serverless-offline-reasint
Version:
Emulate AWS λ and API Gateway locally when developing your Serverless project
107 lines (84 loc) • 2.48 kB
JavaScript
import { EOL, platform } from "node:os"
import { relative } from "node:path"
import { cwd } from "node:process"
import { log } from "@serverless/utils/log.js"
import { join } from "desm"
import { execa } from "execa"
import { splitHandlerPathAndName } from "../../../utils/index.js"
const { parse, stringify } = JSON
const { hasOwn } = Object
export default class RubyRunner {
static #payloadIdentifier = "__offline_payload__"
#env = null
#handlerName = null
#handlerPath = null
constructor(funOptions, env) {
const [handlerPath, handlerName] = splitHandlerPathAndName(
funOptions.handler,
)
this.#env = env
this.#handlerName = handlerName
this.#handlerPath = handlerPath
}
// no-op
// () => void
cleanup() {}
#parsePayload(value) {
let payload
for (const item of value.split(EOL)) {
let json
// first check if it's JSON
try {
json = parse(item)
// nope, it's not JSON
} catch {
// no-op
}
// now let's see if we have a property __offline_payload__
if (
json &&
typeof json === "object" &&
hasOwn(json, RubyRunner.#payloadIdentifier)
) {
payload = json[RubyRunner.#payloadIdentifier]
} else {
log.notice(item)
}
}
return payload
}
// invokeLocalRuby, loosely based on:
// https://github.com/serverless/serverless/blob/v1.50.0/lib/plugins/aws/invokeLocal/index.js#L556
// invoke.rb, copy/pasted entirely as is:
// https://github.com/serverless/serverless/blob/v1.50.0/lib/plugins/aws/invokeLocal/invoke.rb
async run(event, context) {
const runtime = platform() === "win32" ? "ruby.exe" : "ruby"
// https://docs.aws.amazon.com/lambda/latest/dg/ruby-context.html
// https://docs.aws.amazon.com/lambda/latest/dg/ruby-context.html
// exclude callbackWaitsForEmptyEventLoop, don't mutate context
const { callbackWaitsForEmptyEventLoop, ..._context } = context
const input = stringify({
context: _context,
event,
})
// console.log(input)
const { stderr, stdout } = await execa(
runtime,
[
join(import.meta.url, "invoke.rb"),
relative(cwd(), this.#handlerPath),
this.#handlerName,
],
{
env: this.#env,
input,
// shell: true,
},
)
if (stderr) {
// TODO
log.notice(stderr)
}
return this.#parsePayload(stdout)
}
}