lambda-reactor 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +8 -0
- package/AGENTS.md +7 -0
- package/bun.lock +477 -0
- package/eslint.config.ts +31 -0
- package/examples/cdk-stack.ts +20 -0
- package/examples/health.ts +7 -0
- package/examples/items.ts +25 -0
- package/examples/users-get.ts +20 -0
- package/examples/users-post.ts +26 -0
- package/lefthook.yml +16 -0
- package/package.json +35 -0
- package/src/build-handlers.ts +30 -0
- package/src/dispatch.ts +91 -0
- package/src/env.ts +23 -0
- package/src/handler.ts +58 -0
- package/src/logger.ts +19 -0
- package/src/method.ts +92 -0
- package/src/middleware.ts +41 -0
- package/src/response.ts +86 -0
- package/src/route-handler.ts +28 -0
- package/src/router-class.ts +98 -0
- package/src/router.ts +30 -0
- package/tests/api-get-methods.test.ts +14 -0
- package/tests/api-router-factory.test.ts +46 -0
- package/tests/api-router.test.ts +72 -0
- package/tests/config-cors.test.ts +50 -0
- package/tests/config.test.ts +79 -0
- package/tests/dispatch-error-logging.test.ts +61 -0
- package/tests/env.test.ts +38 -0
- package/tests/handler-error-logging.test.ts +61 -0
- package/tests/handler-routing-validation.test.ts +86 -0
- package/tests/handler-routing.test.ts +37 -0
- package/tests/handler.test.ts +48 -0
- package/tests/method.test.ts +40 -0
- package/tests/response.test.ts +29 -0
- package/tsconfig.build.json +26 -0
- package/tsconfig.json +3 -0
- package/tsconfig.node.json +24 -0
- package/vitest.config.ts +21 -0
- package/vitest.setup.ts +2 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {createHandler} from "#src/handler"
|
|
2
|
+
import {method} from "#src/method"
|
|
3
|
+
import {Response} from "#src/response"
|
|
4
|
+
import type {APIGatewayProxyEvent, Context} from "aws-lambda"
|
|
5
|
+
import {describe, expect, it, vi} from "vitest"
|
|
6
|
+
|
|
7
|
+
vi.mock("source-map-support", () => ({install: vi.fn()}))
|
|
8
|
+
|
|
9
|
+
function event(httpMethod: string): APIGatewayProxyEvent {
|
|
10
|
+
return {
|
|
11
|
+
body: null,
|
|
12
|
+
headers: {},
|
|
13
|
+
multiValueHeaders: {},
|
|
14
|
+
httpMethod,
|
|
15
|
+
isBase64Encoded: false,
|
|
16
|
+
path: "/",
|
|
17
|
+
pathParameters: null,
|
|
18
|
+
queryStringParameters: null,
|
|
19
|
+
multiValueQueryStringParameters: null,
|
|
20
|
+
stageVariables: null,
|
|
21
|
+
resource: "/",
|
|
22
|
+
requestContext: {} as APIGatewayProxyEvent["requestContext"],
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const context = {} as Context
|
|
27
|
+
|
|
28
|
+
describe("createHandler", () => {
|
|
29
|
+
it("passes through Response instances", async () => {
|
|
30
|
+
const callback = vi.fn(() => Response.text(204, ""))
|
|
31
|
+
const handler = createHandler({GET: method().handle(callback)})
|
|
32
|
+
await expect(handler(event("GET"), context)).resolves.toEqual({
|
|
33
|
+
statusCode: 204,
|
|
34
|
+
body: "",
|
|
35
|
+
headers: {"Content-Type": "text/plain; charset=utf-8"},
|
|
36
|
+
})
|
|
37
|
+
expect(callback).toHaveBeenCalledOnce()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it("returns 500 when callback is not defined", async () => {
|
|
41
|
+
const handler = createHandler({GET: method()})
|
|
42
|
+
await expect(handler(event("GET"), context)).resolves.toEqual({
|
|
43
|
+
statusCode: 500,
|
|
44
|
+
body: "Route has no handler defined",
|
|
45
|
+
headers: {"Content-Type": "text/plain; charset=utf-8"},
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {method} from "#src/method"
|
|
2
|
+
import {describe, expect, it} from "vitest"
|
|
3
|
+
import {z} from "zod"
|
|
4
|
+
|
|
5
|
+
describe("method", () => {
|
|
6
|
+
it("creates a method with no schema", () => {
|
|
7
|
+
const m = method()
|
|
8
|
+
expect(m.bodySchema).toBeUndefined()
|
|
9
|
+
expect(m.outputSchema).toBeUndefined()
|
|
10
|
+
expect(m.callback).toBeUndefined()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it("chains input schema", () => {
|
|
14
|
+
const schema = z.object({name: z.string()})
|
|
15
|
+
const m = method().input(schema)
|
|
16
|
+
expect(m.bodySchema).toBe(schema)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it("chains output schema", () => {
|
|
20
|
+
const schema = z.object({id: z.number()})
|
|
21
|
+
const m = method().output(schema)
|
|
22
|
+
expect(m.outputSchema).toBe(schema)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it("chains handle callback", () => {
|
|
26
|
+
const cb = async () => ({ok: true})
|
|
27
|
+
const m = method().handle(cb)
|
|
28
|
+
expect(m.callback).toBe(cb)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it("preserves schemas through handle chain", () => {
|
|
32
|
+
const input = z.object({x: z.string()})
|
|
33
|
+
const output = z.object({y: z.number()})
|
|
34
|
+
const cb = async () => ({y: 1})
|
|
35
|
+
const m = method().input(input).output(output).handle(cb)
|
|
36
|
+
expect(m.bodySchema).toBe(input)
|
|
37
|
+
expect(m.outputSchema).toBe(output)
|
|
38
|
+
expect(m.callback).toBe(cb)
|
|
39
|
+
})
|
|
40
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {Response} from "#src/response"
|
|
2
|
+
import {describe, expect, it} from "vitest"
|
|
3
|
+
|
|
4
|
+
describe("Response", () => {
|
|
5
|
+
it("serializes json bodies", () => {
|
|
6
|
+
expect(
|
|
7
|
+
Response.json(201, {ok: true})
|
|
8
|
+
.header("X-Test", "1")
|
|
9
|
+
.toAPIGatewayProxyResult(),
|
|
10
|
+
).toEqual({
|
|
11
|
+
statusCode: 201,
|
|
12
|
+
body: JSON.stringify({ok: true}),
|
|
13
|
+
headers: {
|
|
14
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
15
|
+
"X-Test": "1",
|
|
16
|
+
},
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it("serializes text bodies", () => {
|
|
21
|
+
expect(Response.text(400, "nope").toAPIGatewayProxyResult()).toEqual({
|
|
22
|
+
statusCode: 400,
|
|
23
|
+
body: "nope",
|
|
24
|
+
headers: {
|
|
25
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["esnext"],
|
|
7
|
+
"types": ["node"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"noUncheckedIndexedAccess": true,
|
|
11
|
+
"noImplicitOverride": true,
|
|
12
|
+
"noImplicitAny": true,
|
|
13
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
14
|
+
"exactOptionalPropertyTypes": true,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
"noImplicitReturns": true,
|
|
17
|
+
"noUnusedLocals": true,
|
|
18
|
+
"noUnusedParameters": true,
|
|
19
|
+
"declaration": true,
|
|
20
|
+
"emitDeclarationOnly": true,
|
|
21
|
+
"sourceMap": true,
|
|
22
|
+
"rootDir": "./src/",
|
|
23
|
+
"outDir": "./dist/"
|
|
24
|
+
},
|
|
25
|
+
"include": ["./src/"]
|
|
26
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["esnext"],
|
|
7
|
+
"types": ["node", "vitest/globals"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"noUncheckedIndexedAccess": true,
|
|
11
|
+
"noImplicitOverride": true,
|
|
12
|
+
"noImplicitAny": true,
|
|
13
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
14
|
+
"exactOptionalPropertyTypes": false,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
"noImplicitReturns": true,
|
|
17
|
+
"noUnusedLocals": true,
|
|
18
|
+
"noUnusedParameters": true,
|
|
19
|
+
"noEmit": true,
|
|
20
|
+
"rootDir": "."
|
|
21
|
+
},
|
|
22
|
+
"include": ["."],
|
|
23
|
+
"exclude": ["./src/", "./dist/"]
|
|
24
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {fileURLToPath, URL} from "node:url"
|
|
2
|
+
|
|
3
|
+
import {defineConfig} from "vitest/config"
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
resolve: {
|
|
7
|
+
alias: {
|
|
8
|
+
"#src": fileURLToPath(new URL("./src", import.meta.url)),
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
test: {
|
|
12
|
+
globals: true,
|
|
13
|
+
environment: "node",
|
|
14
|
+
include: ["tests/**/*.test.{ts,tsx}"],
|
|
15
|
+
setupFiles: ["./vitest.setup.ts"],
|
|
16
|
+
coverage: {
|
|
17
|
+
provider: "v8",
|
|
18
|
+
include: ["src/**/*.ts"],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
})
|
package/vitest.setup.ts
ADDED