├── .circleci └── config.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .husky ├── _ │ └── husky.sh ├── post-commit ├── pre-commit └── validate-circleci-config.sh ├── .idea ├── aws-lambda-libreoffice.iml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── .npmrc ├── .prettierignore ├── changelog.md ├── license ├── package.json ├── readme.md ├── renovate.json ├── src ├── cleanup.ts ├── convert.ts ├── index.ts ├── logs.test.ts ├── logs.ts ├── validations.test.ts └── validations.ts ├── test ├── Dockerfile ├── test.js └── test.sh ├── tsconfig.json └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | orbs: 2 | node: circleci/node@5.1.0 3 | 4 | version: 2.1 5 | 6 | parameters: 7 | node_version: 8 | type: string 9 | default: '16.15.1' 10 | 11 | commands: 12 | install_deps: 13 | steps: 14 | - node/install-packages: 15 | pkg-manager: yarn 16 | cache-version: v1-all 17 | cache-only-lockfile: true 18 | app-dir: ~/repo 19 | override-ci-command: yarn install --pure-lockfile --no-progress 20 | 21 | jobs: 22 | build: 23 | executor: 24 | name: node/default 25 | tag: << pipeline.parameters.node_version >> 26 | working_directory: ~/repo 27 | steps: 28 | - checkout 29 | - install_deps 30 | - run: yarn test 31 | - run: yarn type-check 32 | - run: yarn lint:ci 33 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 2 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | lib/ 3 | renovate.json 4 | tsconfig.json 5 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": [ 4 | "@shelf/eslint-config/typescript" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.js text eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .serverless/ 3 | coverage/ 4 | lib/ 5 | node_modules/ 6 | 7 | *.log 8 | junit.xml 9 | draft.js 10 | *.draft.js 11 | yarn.lock 12 | 13 | .env 14 | 15 | # User-specific stuff 16 | .idea/**/workspace.xml 17 | .idea/**/tasks.xml 18 | .idea/**/usage.statistics.xml 19 | .idea/**/shelf 20 | 21 | # File-based project format 22 | *.iws 23 | 24 | .idea/$CACHE_FILE$ 25 | .idea/$PRODUCT_WORKSPACE_FILE$ 26 | .idea/.gitignore 27 | !.husky/_/husky.sh 28 | 29 | ./test/cid 30 | ./test/lib 31 | ./test/node_modules 32 | -------------------------------------------------------------------------------- /.husky/_/husky.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ -z "$husky_skip_init" ]; then 3 | debug () { 4 | if [ "$HUSKY_DEBUG" = "1" ]; then 5 | echo "husky (debug) - $1" 6 | fi 7 | } 8 | 9 | readonly hook_name="$(basename "$0")" 10 | debug "starting $hook_name..." 11 | 12 | if [ "$HUSKY" = "0" ]; then 13 | debug "HUSKY env variable is set to 0, skipping hook" 14 | exit 0 15 | fi 16 | 17 | if [ -f ~/.huskyrc ]; then 18 | debug "sourcing ~/.huskyrc" 19 | . ~/.huskyrc 20 | fi 21 | 22 | export readonly husky_skip_init=1 23 | sh -e "$0" "$@" 24 | exitCode="$?" 25 | 26 | if [ $exitCode != 0 ]; then 27 | echo "husky - $hook_name hook exited with code $exitCode (error)" 28 | fi 29 | 30 | exit $exitCode 31 | fi 32 | -------------------------------------------------------------------------------- /.husky/post-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | git update-index --again 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | yarn lint-staged 4 | -------------------------------------------------------------------------------- /.husky/validate-circleci-config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if ! command -v circleci > /dev/null 2>&1; then 4 | echo "\033[0;31m" \ 5 | "Please, install CircleCI CLI to validate config:" \ 6 | "https://circleci.com/docs/2.0/local-cli/" 7 | 8 | exit 0 9 | fi 10 | 11 | circleci config validate 12 | -------------------------------------------------------------------------------- /.idea/aws-lambda-libreoffice.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 19 | 20 | 22 | 23 | 35 | 36 | 37 | 39 | 40 | 41 | 48 | 49 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # v5.0.0 2 | 3 | - Requires LibreOffice 7.4, instead of 7.3 previously 4 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Gemshelf Inc. (shelf.io) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@shelf/aws-lambda-libreoffice", 3 | "version": "7.2.0", 4 | "description": "Utility to work with Docker version of LibreOffice in Lambda", 5 | "keywords": [ 6 | "aws lambda", 7 | "libreoffice", 8 | "serverless", 9 | "pdf" 10 | ], 11 | "repository": "shelfio/aws-lambda-libreoffice", 12 | "license": "MIT", 13 | "author": { 14 | "name": "Vlad Holubiev", 15 | "email": "vlad@shelf.io", 16 | "url": "https://shelf.io" 17 | }, 18 | "files": [ 19 | "lib" 20 | ], 21 | "main": "lib", 22 | "types": "lib/index.d.ts", 23 | "scripts": { 24 | "build": "rm -rf lib/ && yarn build:types && yarn build:code", 25 | "build:code": "babel src --out-dir lib --ignore '**/*.test.ts' --extensions '.ts' && find ./lib -name '*.test.d.ts' -delete", 26 | "build:types": "tsc --emitDeclarationOnly --declaration --isolatedModules false --declarationDir lib", 27 | "coverage": "jest --coverage", 28 | "lint": "eslint . --ext .js,.ts,.json --fix", 29 | "lint:ci": "eslint . --ext .js,.ts,.json", 30 | "prepack": "yarn build", 31 | "test": "jest src", 32 | "type-check": "tsc --noEmit", 33 | "type-check:watch": "npm run type-check -- --watch" 34 | }, 35 | "lint-staged": { 36 | "*.{html,json,md,yml}": [ 37 | "prettier --write" 38 | ], 39 | "*.{js,ts}": [ 40 | "eslint --fix" 41 | ], 42 | ".circleci/config.yml": [ 43 | ".husky/validate-circleci-config.sh" 44 | ] 45 | }, 46 | "babel": { 47 | "extends": "@shelf/babel-config/backend" 48 | }, 49 | "prettier": "@shelf/prettier-config", 50 | "jest": { 51 | "testEnvironment": "node" 52 | }, 53 | "dependencies": { 54 | "@shelf/is-audio-filepath": "2.0.0", 55 | "del": "5.1.0", 56 | "is-image": "3.1.0", 57 | "is-video": "1.0.1" 58 | }, 59 | "devDependencies": { 60 | "@babel/cli": "7.27.0", 61 | "@babel/core": "7.26.10", 62 | "@shelf/babel-config": "2.0.1", 63 | "@shelf/eslint-config": "2.29.3", 64 | "@shelf/prettier-config": "1.0.0", 65 | "@types/jest": "29.5.14", 66 | "@types/node": "16", 67 | "babel-jest": "29.7.0", 68 | "eslint": "8.57.1", 69 | "husky": "8.0.3", 70 | "jest": "29.7.0", 71 | "lint-staged": "13.3.0", 72 | "prettier": "2.8.8", 73 | "typescript": "5.8.3" 74 | }, 75 | "engines": { 76 | "node": ">=16" 77 | }, 78 | "publishConfig": { 79 | "access": "public" 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # aws-lambda-libreoffice ![](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) 2 | 3 | > Utility to work with Docker version of LibreOffice in Lambda 4 | 5 | ## Install 6 | 7 | ``` 8 | $ yarn add @shelf/aws-lambda-libreoffice 9 | ``` 10 | 11 | ## Features 12 | 13 | - Includes CJK and X11 fonts bundled in the [base Docker image](https://github.com/shelfio/libreoffice-lambda-base-image)! 14 | - Relies on the latest LibreOffice 7.4 version which is not stripped down from features as a previous layer-based version of this package 15 | - Requires node.js 16x runtime (x86_64) 16 | 17 | ## Requirements 18 | 19 | ### Lambda Docker Image 20 | 21 | First, you need to create a Docker image for your Lambda function. 22 | See the example at [libreoffice-lambda-base-image](https://github.com/shelfio/libreoffice-lambda-base-image) repo. 23 | 24 | Example: 25 | 26 | ```Dockerfile 27 | FROM public.ecr.aws/shelf/lambda-libreoffice-base:7.6-node18-x86_64 28 | 29 | COPY ./ ${LAMBDA_TASK_ROOT}/ 30 | 31 | RUN yarn install 32 | 33 | CMD [ "handler.handler" ] 34 | ``` 35 | 36 | ### Lambda Configuration 37 | 38 | - At least 3008 MB of RAM is recommended 39 | - At least 45 seconds of Lambda timeout is necessary 40 | - For larger files support, you can [extend Lambda's /tmp space](https://aws.amazon.com/blogs/aws/aws-lambda-now-supports-up-to-10-gb-ephemeral-storage/) using the `ephemeral-storage` parameter 41 | - Set environment variable `HOME` to `/tmp` 42 | 43 | ## Usage (For version 4.x; based on a Lambda Docker Image) 44 | 45 | Given you have packaged your Lambda function as a Docker image, you can now use this package: 46 | 47 | ```javascript 48 | const {convertTo, canBeConvertedToPDF} = require('@shelf/aws-lambda-libreoffice'); 49 | 50 | module.exports.handler = async () => { 51 | // assuming there is a document.docx file inside /tmp dir 52 | // original file will be deleted afterwards 53 | 54 | // it is optional to invoke this function, you can skip it if you're sure about file format 55 | if (!canBeConvertedToPDF('document.docx')) { 56 | return false; 57 | } 58 | 59 | return convertTo('document.docx', 'pdf'); // returns /tmp/document.pdf 60 | }; 61 | ``` 62 | 63 | ## Usage (For version 3.x; based on a Lambda Layer) 64 | 65 | This version requires Node 12.x or higher. 66 | 67 | **NOTE:** Since version 2.0.0 npm package no longer ships the 85 MB LibreOffice 68 | but relies upon [libreoffice-lambda-layer](https://github.com/shelfio/libreoffice-lambda-layer) instead. 69 | Follow the instructions on how to add a lambda layer in [that repo](https://github.com/shelfio/libreoffice-lambda-layer). 70 | 71 | ```js 72 | const {convertTo, canBeConvertedToPDF} = require('@shelf/aws-lambda-libreoffice'); 73 | 74 | module.exports.handler = async () => { 75 | // assuming there is a document.docx file inside /tmp dir 76 | // original file will be deleted afterwards 77 | 78 | if (!canBeConvertedToPDF('document.docx')) { 79 | return false; 80 | } 81 | 82 | return convertTo('document.docx', 'pdf'); // returns /tmp/document.pdf 83 | }; 84 | ``` 85 | 86 | Or if you want more control: 87 | 88 | ```js 89 | const {unpack, defaultArgs} = require('@shelf/aws-lambda-libreoffice'); 90 | 91 | await unpack(); // default path /tmp/instdir/program/soffice.bin 92 | 93 | execSync( 94 | `/tmp/instdir/program/soffice.bin ${defaultArgs.join( 95 | ' ' 96 | )} --convert-to pdf file.docx --outdir /tmp` 97 | ); 98 | ``` 99 | 100 | ## Troubleshooting 101 | 102 | - Please allocate at least **3008 MB** of RAM for your Lambda function. 103 | - If some file fails to be converted to PDF, try converting it to PDF on your computer first. This might be an issue with LibreOffice itself 104 | - If you want to include some fonts/plugins to the libreoffice, contribute to the [libreoffice-lambda-base-image](https://github.com/shelfio/libreoffice-lambda-base-image) instead 105 | 106 | ## See Also 107 | 108 | - [libreoffice-lambda-base-image](https://github.com/shelfio/libreoffice-lambda-base-image) - a base Docker image for you Lambdas 109 | - [libreoffice-lambda-layer](https://github.com/shelfio/libreoffice-lambda-layer) - deprecated, not updated anymore, used the Docker image above 110 | - [serverless-libreoffice](https://github.com/vladgolubev/serverless-libreoffice) - original implementation 111 | - [aws-lambda-tesseract](https://github.com/shelfio/aws-lambda-tesseract) 112 | - [aws-lambda-brotli-unpacker](https://github.com/shelfio/aws-lambda-brotli-unpacker) 113 | - [chrome-aws-lambda](https://github.com/alixaxel/chrome-aws-lambda) 114 | 115 | ## Test 116 | 117 | Beside unit tests that could be run via `yarn test`, there are integration tests. 118 | 119 | Smoke test that it works: 120 | 121 | ```sh 122 | cd test 123 | ./test.sh 124 | 125 | # copy converted PDF file from container to the host to see if it's ok 126 | export CID=$(cat ./cid) 127 | docker cp $CID:/tmp/test.pdf ./test.pdf 128 | ``` 129 | 130 | ## Publish 131 | 132 | ```sh 133 | $ git checkout master 134 | $ yarn version 135 | $ yarn publish 136 | $ git push origin master --tags 137 | ``` 138 | 139 | ## License 140 | 141 | MIT © [Shelf](https://shelf.io) 142 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["github>shelfio/renovate-config-public"], 3 | "labels": ["backend"], 4 | "ignoreDeps": ["cimg/node"] 5 | } 6 | -------------------------------------------------------------------------------- /src/cleanup.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs/promises'; 2 | import del from 'del'; 3 | 4 | // Removes temp files generated by LibreOffice 5 | export async function cleanupTempFiles(): Promise { 6 | const files = await fs.readdir(`/tmp`); 7 | for (const file of files) { 8 | if (file.endsWith('.tmp') === true || file.startsWith('OSL_PIPE')) { 9 | try { 10 | await del([`/tmp/${file}`, `/tmp/${file}/*`], {force: true}); 11 | // eslint-disable-next-line no-empty 12 | } catch (error) {} 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/convert.ts: -------------------------------------------------------------------------------- 1 | import childProcess from 'child_process'; 2 | import util from 'util'; 3 | import path from 'node:path'; 4 | import {cleanupTempFiles} from './cleanup'; 5 | import {getConvertedFilePath} from './logs'; 6 | 7 | const exec = util.promisify(childProcess.exec); 8 | 9 | export const DEFAULT_ARGS = [ 10 | '--headless', 11 | '--invisible', 12 | '--nodefault', 13 | '--view', 14 | '--nolockcheck', 15 | '--nologo', 16 | '--norestore', 17 | ]; 18 | const LO_BINARY_PATH = 'libreoffice7.6'; 19 | 20 | export async function convertTo(filename: string, format: string): Promise { 21 | await cleanupTempFiles(); 22 | 23 | const argumentsString = DEFAULT_ARGS.join(' '); 24 | const outputFilename = filename.split(/\\ /).join(' '); 25 | 26 | const cmd = `cd /tmp && ${LO_BINARY_PATH} ${argumentsString} --convert-to ${format} --outdir /tmp '/tmp/${outputFilename}'`; 27 | 28 | let logs; 29 | let err; 30 | 31 | // due to an unknown issue, we need to run command twice 32 | try { 33 | const {stdout, stderr} = await exec(cmd); 34 | logs = stdout; 35 | err = stderr; 36 | } catch (e) { 37 | const {stdout, stderr} = await exec(cmd); 38 | logs = stdout; 39 | err = stderr; 40 | } finally { 41 | await exec(`rm '/tmp/${outputFilename}'`); 42 | await cleanupTempFiles(); 43 | } 44 | 45 | if (err) { 46 | throw new Error(`Cannot generate PDF preview for .${path.extname(outputFilename)} file`, { 47 | cause: logs, 48 | }); 49 | } 50 | 51 | return getConvertedFilePath(logs.toString()); 52 | } 53 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './convert'; 2 | export * from './validations'; 3 | -------------------------------------------------------------------------------- /src/logs.test.ts: -------------------------------------------------------------------------------- 1 | import {getConvertedFilePath} from './logs'; 2 | 3 | describe('getConvertedFilePath', () => { 4 | it('should return converted file path', () => { 5 | const logsString = `\tconvert /tmp/test.txt -> /tmp/test.docx using filter : MS Word 2007 XML`; 6 | 7 | expect(getConvertedFilePath(logsString)).toEqual('/tmp/test.docx'); 8 | }); 9 | 10 | it('should throw extended error message when passed incorrect format string', () => { 11 | const logsString = 'log string that produces error'; 12 | 13 | expect(() => getConvertedFilePath(logsString)).toThrow( 14 | new TypeError( 15 | `TypeError: Cannot read properties of null (reading '1');\tTried to parse string: "log string that produces error"` 16 | ) 17 | ); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/logs.ts: -------------------------------------------------------------------------------- 1 | export function getConvertedFilePath(logs: string): string { 2 | try { 3 | return logs.match(/\/tmp\/.+->\s(\/tmp\/.+) using/)[1]; 4 | } catch (e) { 5 | const ErrorWithExtendedMessage: Error = new Error(e); 6 | ErrorWithExtendedMessage.message += `;\tTried to parse string: "${logs}"`; 7 | 8 | throw ErrorWithExtendedMessage; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/validations.test.ts: -------------------------------------------------------------------------------- 1 | import {canBeConvertedToPDF} from './validations'; 2 | 3 | it.each` 4 | filename 5 | ${'document.docx'} 6 | ${'document.pdf'} 7 | `('should return true for supported filename $filename', ({filename}) => { 8 | expect(canBeConvertedToPDF(filename)).toEqual(true); 9 | }); 10 | 11 | it.each` 12 | filename 13 | ${'table.xlsx'} 14 | ${'book.epub'} 15 | ${'project.mpp'} 16 | ${'email.msg'} 17 | ${'image.jpg'} 18 | ${'video.mp4'} 19 | ${'audio.mp3'} 20 | ${'sound.wav'} 21 | ${'help.chm'} 22 | ${'google-doc.gdoc'} 23 | ${'drawing.dwg'} 24 | `('should return false for unsupported filename $filename', ({filename}) => { 25 | expect(canBeConvertedToPDF(filename)).toEqual(false); 26 | }); 27 | -------------------------------------------------------------------------------- /src/validations.ts: -------------------------------------------------------------------------------- 1 | import isVideo from 'is-video'; 2 | import isImage from 'is-image'; 3 | import isAudio from '@shelf/is-audio-filepath'; 4 | 5 | const UNSUPPORTED_FILE_EXTENSIONS = [ 6 | '.chm', 7 | '.heic', 8 | '.gdoc', 9 | '.gsheet', 10 | '.gslides', 11 | '.zip', 12 | '.dwg', 13 | '.msg', 14 | '.mpp', 15 | '.epub', 16 | '.xlsx', 17 | ]; 18 | 19 | export function canBeConvertedToPDF(filename: string): boolean { 20 | filename = filename.toLowerCase(); 21 | 22 | const isFileExtensionUnsupported = UNSUPPORTED_FILE_EXTENSIONS.some(ext => 23 | filename.endsWith(ext) 24 | ); 25 | 26 | if (isFileExtensionUnsupported) { 27 | return false; 28 | } 29 | 30 | return !isImage(filename) && !isVideo(filename) && !isAudio(filename); 31 | } 32 | -------------------------------------------------------------------------------- /test/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/shelf/lambda-libreoffice-base:7.6-node18-x86_64 2 | 3 | COPY . ${LAMBDA_TASK_ROOT}/ 4 | CMD [ "test.handler" ] 5 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const {writeFileSync} = require('fs'); 3 | const {convertTo} = require('./lib'); 4 | 5 | module.exports.handler = async () => { 6 | writeFileSync('/tmp/test.txt', Buffer.from('Hello World!')); 7 | 8 | const convertedFilePath = await convertTo('test.txt', `pdf`); 9 | 10 | console.log({convertedFilePath}); 11 | }; 12 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cp -r ../lib ./ 4 | cp -r ../node_modules ./ 5 | docker build -t lo-lambda-test . 6 | 7 | (sleep 7; curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}') & 8 | (sleep 30; CID=$(cat ./cid) && docker stop $CID && rm ./cid) & 9 | 10 | docker run -p 9000:8080 --rm --cidfile ./cid lo-lambda-test 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "esModuleInterop": true, 5 | "isolatedModules": true, 6 | "module": "commonjs", 7 | "resolveJsonModule": true, 8 | "skipLibCheck": true, 9 | "sourceMap": false, 10 | "target": "esnext" 11 | }, 12 | "exclude": ["node_modules", "test/test.js"], 13 | "include": ["src"] 14 | } 15 | --------------------------------------------------------------------------------