Skip to main content
Module

x/lambda/bootstrap

A deno runtime for AWS Lambda. Deploy deno via docker, SAM, serverless, or bundle it yourself.
Very Popular
Go to Latest
File
#!/bin/shset -euo pipefail
SCRIPT_DIR=$(cd $(dirname $0); pwd)HANDLER_NAME=$(echo "$_HANDLER" | cut -d. -f2)HANDLER_FILE=$(echo "$_HANDLER" | cut -d. -f1)
API_ROOT=http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/
# If this ENV variable is set then copy that directory as DENO_DIR (default = .deno_dir).# Note: For permissions reasons we need the actual DENO_DIR to be somewhere in /tmp.DENO_DIR=${DENO_DIR-.deno_dir}if [[ -z "$DENO_DIR" ]]; then DENO_DIR=.deno_dirfi
# whether to use ts, js, bundle.js, etc.HANDLER_EXT=${HANDLER_EXT-'ts'}HANDLER_FILE=${HANDLER_FILE}.${HANDLER_EXT}
# If we fail prior to the handler loop we post an init error.function error { echo "error:" $1 ERROR="{\"errorMessage\" : \"$1\", \"errorType\" : \"InitException\"}" curl -s -X POST "${API_ROOT}init/error" \ -d "$ERROR" \ --header "Lambda-Runtime-Function-Error-Type: Unhandled" \ --output /tmp/init.out # expect it to be {"status":"OK"} grep -q OK /tmp/init.out \ || echo "Unexpected bootstrap error when calling AWS_LAMBDA_RUNTIME_API /init/error:" $(cat /tmp/init.out) exit 1}
# If the script fails we try and determine why.function investigate { [ -f $SCRIPT_DIR/amz-deno ] \ || error "missing amz-deno executable" $SCRIPT_DIR/amz-deno eval 'Deno.version.deno' \ || error "bad amz-deno executable" [ -f $LAMBDA_TASK_ROOT/$HANDLER_FILE ] \ || error "missing expected handler file '$HANDLER_FILE'" DENO_DIR=/tmp/deno_dir NO_COLOR=true $SCRIPT_DIR/amz-deno fetch $LAMBDA_TASK_ROOT/$HANDLER_FILE \ || error "unable to compile $HANDLER_FILE" echo "import { $HANDLER_NAME } from '$LAMBDA_TASK_ROOT/$HANDLER_FILE';" > /tmp/runtime-test.js DENO_DIR=/tmp/deno_dir NO_COLOR=true $SCRIPT_DIR/amz-deno fetch /tmp/runtime-test.js 2> /dev/null \ || error "$HANDLER_FILE must export a function named '$HANDLER_NAME'"; # perhaps a bug in bootstrap? Should we always exit 1?}
# Note: This is a js file to avoid a runtime compilation step.# Hopefully $HANDLER_FILE's compilation is cached in DENO_DIR.echo "import { $HANDLER_NAME } from '$LAMBDA_TASK_ROOT/$HANDLER_FILE';const INVOCATION = '${API_ROOT}invocation/';while (true) { const next = await fetch(INVOCATION + 'next'); const headers = next.headers; const reqId = headers.get('Lambda-Runtime-Aws-Request-Id'); const context = { functionName: '$AWS_LAMBDA_FUNCTION_NAME', functionVersion: '$AWS_LAMBDA_FUNCTION_VERSION', invokedFunctionArn: headers.get('lambda-runtime-invoked-function-arn'), memoryLimitInMB: $AWS_LAMBDA_FUNCTION_MEMORY_SIZE, awsRequestId: headers.get('lambda-runtime-aws-request-id'), logGroupName: '$AWS_LAMBDA_LOG_GROUP_NAME', logStreamName: '$AWS_LAMBDA_LOG_STREAM_NAME', identity: undefined, clientContext: undefined, getRemainingTimeInMillis: function() { return Number(headers.get('lambda-runtime-deadline-ms')) - Date.now(); } } let res; try { const event = await next.json(); const body = await $HANDLER_NAME(event, context); res = await fetch(INVOCATION + reqId + '/response', { method: 'POST', body: JSON.stringify(body) }); } catch(e) { console.error(e); // If it's an Error we can pull these out cleanly... // BUT it's javascript so it could be anything! // If there's a better way, very happy to take suggestions. let name, message; try { name = e.name || 'Error' } catch (_) { name = 'Error' } try { message = e.message || e } catch (_) { message = e } if (typeof(name) !== 'string') { name = JSON.stringify(name) } if (typeof(message) !== 'string') { const s = JSON.stringify(message) message = s === undefined ? '' + message : s } res = await fetch(INVOCATION + reqId + '/error', { method: 'POST', body: JSON.stringify({ errorMessage: message, errorType: name }) }); } await res.blob();}" > /tmp/runtime.js
# We copy DENO_DIR into a writable directory (/tmp/deno_dir)# and expand DENO_DIR/LAMBDA_TASK_ROOT to match the new location ($LAMBDA_TASK_ROOT).
mkdir -p /tmp/deno_dir/gen/file$LAMBDA_TASK_ROOT# We cp first from the deno-lambda-layer.cp -R /opt/.deno_dir/gen/. /tmp/deno_dir/gen &> /dev/null \ && cp -R /opt/.deno_dir/deps/. /tmp/deno_dir/deps &> /dev/null \ && cp -R /opt/.deno_dir/LAMBDA_TASK_ROOT/. /tmp/deno_dir/gen/file$LAMBDA_TASK_ROOT &> /dev/null \ || true# Then we overwrite with from the DENO_DIR in the function code.cp -R $LAMBDA_TASK_ROOT/$DENO_DIR/gen/. /tmp/deno_dir/gen &> /dev/null \ && cp -R $LAMBDA_TASK_ROOT/$DENO_DIR/deps/. /tmp/deno_dir/deps &> /dev/null \ && cp -R $LAMBDA_TASK_ROOT/$DENO_DIR/gen/. /tmp/deno_dir/gen &> /dev/null \ && cp -R $LAMBDA_TASK_ROOT/$DENO_DIR/LAMBDA_TASK_ROOT/. /tmp/deno_dir/gen/file$LAMBDA_TASK_ROOT &> /dev/null \ || echo "warn: unable to import '$DENO_DIR/' as DENO_DIR"DENO_DIR=/tmp/deno_dir NO_COLOR=true $SCRIPT_DIR/amz-deno run --allow-net --allow-read --allow-env /tmp/runtime.js \ || investigate;