lambda-reactor 1.0.0 → 1.0.2

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.
Files changed (69) hide show
  1. package/{src/build-handlers.ts → dist/build-handlers.d.ts} +3 -16
  2. package/dist/build-handlers.js +13 -0
  3. package/dist/build-handlers.js.map +10 -0
  4. package/dist/dispatch.d.ts +21 -0
  5. package/dist/dispatch.js +55 -0
  6. package/dist/dispatch.js.map +10 -0
  7. package/dist/env.d.ts +6 -0
  8. package/dist/env.js +13 -0
  9. package/dist/env.js.map +10 -0
  10. package/dist/handler.d.ts +26 -0
  11. package/dist/handler.js +29 -0
  12. package/dist/handler.js.map +10 -0
  13. package/dist/logger.d.ts +8 -0
  14. package/dist/logger.js +19 -0
  15. package/dist/logger.js.map +10 -0
  16. package/dist/method.d.ts +53 -0
  17. package/dist/method.js +57 -0
  18. package/dist/method.js.map +10 -0
  19. package/{src/middleware.ts → dist/middleware.d.ts} +5 -22
  20. package/dist/middleware.js +19 -0
  21. package/dist/middleware.js.map +10 -0
  22. package/dist/response.d.ts +48 -0
  23. package/dist/response.js +46 -0
  24. package/dist/response.js.map +10 -0
  25. package/{src/route-handler.ts → dist/route-handler.d.ts} +12 -14
  26. package/dist/route-handler.js +2 -0
  27. package/dist/route-handler.js.map +9 -0
  28. package/dist/router-class.d.ts +54 -0
  29. package/dist/router-class.js +46 -0
  30. package/dist/router-class.js.map +10 -0
  31. package/{src/router.ts → dist/router.d.ts} +4 -16
  32. package/dist/router.js +18 -0
  33. package/dist/router.js.map +10 -0
  34. package/package.json +12 -2
  35. package/.prettierrc +0 -8
  36. package/AGENTS.md +0 -7
  37. package/bun.lock +0 -477
  38. package/eslint.config.ts +0 -31
  39. package/examples/cdk-stack.ts +0 -20
  40. package/examples/health.ts +0 -7
  41. package/examples/items.ts +0 -25
  42. package/examples/users-get.ts +0 -20
  43. package/examples/users-post.ts +0 -26
  44. package/lefthook.yml +0 -16
  45. package/src/dispatch.ts +0 -91
  46. package/src/env.ts +0 -23
  47. package/src/handler.ts +0 -58
  48. package/src/logger.ts +0 -19
  49. package/src/method.ts +0 -92
  50. package/src/response.ts +0 -86
  51. package/src/router-class.ts +0 -98
  52. package/tests/api-get-methods.test.ts +0 -14
  53. package/tests/api-router-factory.test.ts +0 -46
  54. package/tests/api-router.test.ts +0 -72
  55. package/tests/config-cors.test.ts +0 -50
  56. package/tests/config.test.ts +0 -79
  57. package/tests/dispatch-error-logging.test.ts +0 -61
  58. package/tests/env.test.ts +0 -38
  59. package/tests/handler-error-logging.test.ts +0 -61
  60. package/tests/handler-routing-validation.test.ts +0 -86
  61. package/tests/handler-routing.test.ts +0 -37
  62. package/tests/handler.test.ts +0 -48
  63. package/tests/method.test.ts +0 -40
  64. package/tests/response.test.ts +0 -29
  65. package/tsconfig.build.json +0 -26
  66. package/tsconfig.json +0 -3
  67. package/tsconfig.node.json +0 -24
  68. package/vitest.config.ts +0 -21
  69. package/vitest.setup.ts +0 -2
@@ -1,72 +0,0 @@
1
- import {join} from "path"
2
-
3
- import type {IRestApi} from "aws-cdk-lib/aws-apigateway"
4
- import type {IFunction} from "aws-cdk-lib/aws-lambda"
5
- import {beforeEach, describe, expect, it, vi} from "vitest"
6
-
7
- vi.mock("fs", () => ({readFileSync: vi.fn()}))
8
-
9
- vi.mock("aws-cdk-lib/aws-apigateway", () => ({
10
- LambdaIntegration: vi.fn((handler: unknown) => ({handler})),
11
- }))
12
-
13
- class FakeResource {
14
- children = new Map<string, FakeResource>()
15
- methods: {method: string; integration: unknown}[] = []
16
- getResource(part: string) {
17
- return this.children.get(part)
18
- }
19
- addResource(part: string) {
20
- const child = new FakeResource()
21
- this.children.set(part, child)
22
- return child
23
- }
24
- addMethod(method: string, value: unknown) {
25
- this.methods.push({method, integration: value})
26
- return this
27
- }
28
- }
29
-
30
- describe("router defineRestApi", () => {
31
- beforeEach(async () => {
32
- const {LambdaIntegration} = await import("aws-cdk-lib/aws-apigateway")
33
- ;(LambdaIntegration as ReturnType<typeof vi.fn>).mockClear()
34
- const {readFileSync} = await import("fs")
35
- ;(readFileSync as ReturnType<typeof vi.fn>).mockReturnValue(
36
- `export const handler = createHandler({GET, POST})`,
37
- )
38
- })
39
-
40
- it("defines nested rest resources on an existing api instance", async () => {
41
- const {router} = await import("#src/router")
42
- const root = new FakeResource()
43
- const api = {root} as unknown as IRestApi
44
- const getUser = {name: "getUser"} as unknown as IFunction
45
- const createPost = {name: "createPost"} as unknown as IFunction
46
- const factory = vi.fn((_entry: string, id: string) => {
47
- if (id === "/user/{user_id}") return getUser
48
- return createPost
49
- })
50
- router().route("/user/{user_id}").route("/posts").defineRestApi(api, factory)
51
- expect(factory).toHaveBeenCalledWith(
52
- join(process.cwd(), "src", "/user/{user_id}.ts"),
53
- "/user/{user_id}",
54
- )
55
- expect(factory).toHaveBeenCalledWith(
56
- join(process.cwd(), "src", "/posts.ts"),
57
- "/posts",
58
- )
59
- const {LambdaIntegration} = await import("aws-cdk-lib/aws-apigateway")
60
- expect(LambdaIntegration).toHaveBeenCalledWith(getUser)
61
- expect(LambdaIntegration).toHaveBeenCalledWith(createPost)
62
- const user = root.getResource("user")
63
- expect(user?.getResource("{user_id}")?.methods).toEqual([
64
- {method: "GET", integration: {handler: getUser}},
65
- {method: "POST", integration: {handler: getUser}},
66
- ])
67
- expect(root.getResource("posts")?.methods).toEqual([
68
- {method: "GET", integration: {handler: createPost}},
69
- {method: "POST", integration: {handler: createPost}},
70
- ])
71
- })
72
- })
@@ -1,50 +0,0 @@
1
- import {dispatch} from "#src/dispatch"
2
- import {method} from "#src/method"
3
- import {cors} from "#src/middleware"
4
- import type {APIGatewayProxyEvent, Context} from "aws-lambda"
5
- import {describe, expect, it} from "vitest"
6
-
7
- const context = {} as Context
8
-
9
- const event = {
10
- body: null,
11
- headers: {},
12
- multiValueHeaders: {},
13
- httpMethod: "GET",
14
- isBase64Encoded: false,
15
- path: "/",
16
- pathParameters: null,
17
- queryStringParameters: null,
18
- multiValueQueryStringParameters: null,
19
- stageVariables: null,
20
- resource: "/",
21
- requestContext: {} as APIGatewayProxyEvent["requestContext"],
22
- } satisfies APIGatewayProxyEvent
23
-
24
- describe("cors middleware", () => {
25
- it("adds Access-Control headers to response", async () => {
26
- const route = method()
27
- .use(cors({"Allow-Origin": "*", "Allow-Methods": "GET,POST"}))
28
- .handle(async () => "ok")
29
- const result = await dispatch(route, event, context)
30
- expect(result.headers?.["Access-Control-Allow-Origin"]).toBe("*")
31
- expect(result.headers?.["Access-Control-Allow-Methods"]).toBe("GET,POST")
32
- })
33
-
34
- it("does not add cors headers when no middleware used", async () => {
35
- const route = method().handle(async () => "ok")
36
- const result = await dispatch(route, event, context)
37
- const keys = Object.keys(result.headers ?? {})
38
- expect(keys.some((k) => k.startsWith("Access-Control"))).toBe(false)
39
- })
40
-
41
- it("applies multiple cors middlewares in order", async () => {
42
- const route = method()
43
- .use(cors({"Allow-Origin": "*"}))
44
- .use(cors({"Allow-Methods": "GET"}))
45
- .handle(async () => "ok")
46
- const result = await dispatch(route, event, context)
47
- expect(result.headers?.["Access-Control-Allow-Origin"]).toBe("*")
48
- expect(result.headers?.["Access-Control-Allow-Methods"]).toBe("GET")
49
- })
50
- })
@@ -1,79 +0,0 @@
1
- import {method} from "#src/method"
2
- import {cors} from "#src/middleware"
3
- import {router} from "#src/router"
4
- import {describe, expect, it} from "vitest"
5
- import {z} from "zod"
6
-
7
- describe("method middlewares", () => {
8
- it("has empty middlewares by default", () => {
9
- expect(method().middlewares).toEqual([])
10
- })
11
-
12
- it("adds middleware via .use()", () => {
13
- const m = cors({"Allow-Origin": "*"})
14
- expect(method().use(m).middlewares).toHaveLength(1)
15
- })
16
-
17
- it("accumulates multiple middlewares", () => {
18
- const m1 = cors({"Allow-Origin": "*"})
19
- const m2 = cors({"Allow-Methods": "GET"})
20
- expect(method().use(m1).use(m2).middlewares).toHaveLength(2)
21
- })
22
-
23
- it("propagates middlewares through input chain", () => {
24
- const m = cors({"Allow-Origin": "*"})
25
- expect(
26
- method()
27
- .use(m)
28
- .input(z.object({x: z.string()})).middlewares,
29
- ).toHaveLength(1)
30
- })
31
-
32
- it("propagates middlewares through output chain", () => {
33
- const m = cors({"Allow-Origin": "*"})
34
- expect(
35
- method()
36
- .use(m)
37
- .output(z.object({x: z.string()})).middlewares,
38
- ).toHaveLength(1)
39
- })
40
-
41
- it("propagates middlewares through handle chain", () => {
42
- const m = cors({"Allow-Origin": "*"})
43
- expect(
44
- method()
45
- .use(m)
46
- .handle(async () => "ok").middlewares,
47
- ).toHaveLength(1)
48
- })
49
- })
50
-
51
- describe("router srcDir", () => {
52
- it("defaults srcDir to src", () => {
53
- expect(router().srcDir).toBe("src")
54
- })
55
-
56
- it("accepts custom srcDir", () => {
57
- expect(router("src/api").srcDir).toBe("src/api")
58
- })
59
-
60
- it("propagates srcDir through route chain", () => {
61
- expect(router("src/api").route("/health").srcDir).toBe("src/api")
62
- })
63
- })
64
-
65
- describe("router cors", () => {
66
- it("stores corsOptions via .cors()", () => {
67
- const options = {allowOrigins: ["*"], allowMethods: ["GET"]}
68
- expect(router().cors(options).corsOptions).toEqual(options)
69
- })
70
-
71
- it("propagates corsOptions through route chain", () => {
72
- const options = {allowOrigins: ["*"], allowMethods: ["GET"]}
73
- expect(router().cors(options).route("/health").corsOptions).toEqual(options)
74
- })
75
-
76
- it("has no corsOptions by default", () => {
77
- expect(router().corsOptions).toBeUndefined()
78
- })
79
- })
@@ -1,61 +0,0 @@
1
- import {dispatch} from "#src/dispatch"
2
- import * as logger from "#src/logger"
3
- import {method} from "#src/method"
4
- import type {APIGatewayProxyEvent, Context} from "aws-lambda"
5
- import {describe, expect, it, vi} from "vitest"
6
- import {z} from "zod"
7
-
8
- const context = {} as Context
9
-
10
- const event = {
11
- body: null,
12
- headers: {},
13
- multiValueHeaders: {},
14
- httpMethod: "GET",
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
- } satisfies APIGatewayProxyEvent
24
-
25
- describe("dispatch error logging", () => {
26
- it("logs error when route has no callback", async () => {
27
- const logError = vi.spyOn(logger, "logError").mockImplementation(() => "")
28
- const route = method()
29
- await expect(dispatch(route, event, context)).resolves.toMatchObject({
30
- statusCode: 500,
31
- })
32
- expect(logError).toHaveBeenCalledWith(expect.any(Error))
33
- logError.mockRestore()
34
- })
35
-
36
- it("logs error when output schema validation fails on Response body", async () => {
37
- const logError = vi.spyOn(logger, "logError").mockImplementation(() => "")
38
- const route = method()
39
- .output(z.object({n: z.number()}))
40
- .handle(() => ({n: "not-a-number"}) as unknown as {n: number})
41
- await expect(dispatch(route, event, context)).resolves.toMatchObject({
42
- statusCode: 500,
43
- })
44
- expect(logError).toHaveBeenCalled()
45
- logError.mockRestore()
46
- })
47
-
48
- it("logs error when output schema validation fails on plain result", async () => {
49
- const logError = vi.spyOn(logger, "logError").mockImplementation(() => "")
50
- const route = method()
51
- .output(z.object({n: z.number()}))
52
- .handle(() =>
53
- Promise.resolve({n: "not-a-number"} as unknown as {n: number}),
54
- )
55
- await expect(dispatch(route, event, context)).resolves.toMatchObject({
56
- statusCode: 500,
57
- })
58
- expect(logError).toHaveBeenCalled()
59
- logError.mockRestore()
60
- })
61
- })
package/tests/env.test.ts DELETED
@@ -1,38 +0,0 @@
1
- import {isProduction} from "#src/env"
2
- import {afterEach, describe, expect, it} from "vitest"
3
-
4
- const ENV_KEYS = ["NODE_ENV", "STAGE", "ENV", "ENVIRONMENT"] as const
5
-
6
- describe("isProduction", () => {
7
- afterEach(() => {
8
- for (const key of ENV_KEYS) {
9
- delete process.env[key]
10
- }
11
- })
12
-
13
- it("returns false when no env vars are set", () => {
14
- expect(isProduction()).toBe(false)
15
- })
16
-
17
- for (const key of ENV_KEYS) {
18
- it(`returns true when ${key}=production`, () => {
19
- process.env[key] = "production"
20
- expect(isProduction()).toBe(true)
21
- })
22
-
23
- it(`returns true when ${key}=prod`, () => {
24
- process.env[key] = "prod"
25
- expect(isProduction()).toBe(true)
26
- })
27
-
28
- it(`returns true when ${key}=PRODUCTION (case-insensitive)`, () => {
29
- process.env[key] = "PRODUCTION"
30
- expect(isProduction()).toBe(true)
31
- })
32
-
33
- it(`returns false when ${key}=development`, () => {
34
- process.env[key] = "development"
35
- expect(isProduction()).toBe(false)
36
- })
37
- }
38
- })
@@ -1,61 +0,0 @@
1
- import {createHandler} from "#src/handler"
2
- import {method} from "#src/method"
3
- import type {APIGatewayProxyEvent, Context} from "aws-lambda"
4
- import {afterEach, describe, expect, it, vi} from "vitest"
5
-
6
- vi.mock("source-map-support", () => ({install: vi.fn()}))
7
-
8
- const context = {} as Context
9
-
10
- function event(httpMethod: string): APIGatewayProxyEvent {
11
- return {
12
- body: null,
13
- headers: {},
14
- multiValueHeaders: {},
15
- httpMethod,
16
- isBase64Encoded: false,
17
- path: "/",
18
- pathParameters: null,
19
- queryStringParameters: null,
20
- multiValueQueryStringParameters: null,
21
- stageVariables: null,
22
- resource: "/",
23
- requestContext: {} as APIGatewayProxyEvent["requestContext"],
24
- }
25
- }
26
-
27
- describe("createHandler error logging", () => {
28
- afterEach(() => {
29
- delete process.env["NODE_ENV"]
30
- })
31
-
32
- it("logs the error message and returns it in the body outside production", async () => {
33
- const consoleError = vi.spyOn(console, "error").mockImplementation(() => {})
34
- const boom = new Error("boom")
35
- const handler = createHandler({
36
- GET: method().handle(() => {
37
- throw boom
38
- }),
39
- })
40
- const result = await handler(event("GET"), context)
41
- expect(result.statusCode).toBe(500)
42
- expect(result.body).toContain("boom")
43
- expect(consoleError).toHaveBeenCalledWith(expect.stringContaining("boom"))
44
- consoleError.mockRestore()
45
- })
46
-
47
- it("returns generic message in production", async () => {
48
- process.env["NODE_ENV"] = "production"
49
- const consoleError = vi.spyOn(console, "error").mockImplementation(() => {})
50
- const handler = createHandler({
51
- GET: method().handle(() => {
52
- throw new Error("secret details")
53
- }),
54
- })
55
- const result = await handler(event("GET"), context)
56
- expect(result.statusCode).toBe(500)
57
- expect(result.body).toBe("Internal Server Error")
58
- expect(result.body).not.toContain("secret details")
59
- consoleError.mockRestore()
60
- })
61
- })
@@ -1,86 +0,0 @@
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} from "vitest"
6
- import {z} from "zod"
7
-
8
- function event(httpMethod: string, body: unknown = undefined): APIGatewayProxyEvent {
9
- return {
10
- body:
11
- body === undefined ? null
12
- : typeof body === "string" ? body
13
- : JSON.stringify(body),
14
- headers: {},
15
- multiValueHeaders: {},
16
- httpMethod,
17
- isBase64Encoded: false,
18
- path: "/",
19
- pathParameters: null,
20
- queryStringParameters: null,
21
- multiValueQueryStringParameters: null,
22
- stageVariables: null,
23
- resource: "/",
24
- requestContext: {} as APIGatewayProxyEvent["requestContext"],
25
- }
26
- }
27
-
28
- const context = {} as Context
29
-
30
- describe("createHandler validation", () => {
31
- it("validates input and returns 400 on bad input", async () => {
32
- const handler = createHandler({
33
- POST: method()
34
- .input(z.object({username: z.string()}))
35
- .handle(({body}) => ({username: body.username})),
36
- })
37
- const invalid = await handler(event("POST", {username: 7}), context)
38
- expect(invalid).toMatchObject({
39
- statusCode: 400,
40
- headers: {"Content-Type": "text/plain; charset=utf-8"},
41
- })
42
- })
43
-
44
- it("validates output schema and returns json on success", async () => {
45
- const handler = createHandler({
46
- POST: method()
47
- .input(z.object({username: z.string()}))
48
- .output(z.object({username: z.string()}))
49
- .handle(({body}) => ({username: body.username})),
50
- })
51
- await expect(
52
- handler(event("POST", {username: "neo"}), context),
53
- ).resolves.toEqual({
54
- statusCode: 200,
55
- body: JSON.stringify({username: "neo"}),
56
- headers: {"Content-Type": "application/json; charset=utf-8"},
57
- })
58
- })
59
-
60
- it("validates output schema against raw Response body and returns 500 on mismatch", async () => {
61
- const handler = createHandler({
62
- POST: method()
63
- .output(z.object({username: z.string()}))
64
- .handle(() => Response.json(200, {username: 42})),
65
- })
66
- const result = await handler(event("POST"), context)
67
- expect(result).toMatchObject({
68
- statusCode: 500,
69
- headers: {"Content-Type": "text/plain; charset=utf-8"},
70
- })
71
- })
72
-
73
- it("validates output schema against raw Response body and passes on match", async () => {
74
- const handler = createHandler({
75
- POST: method()
76
- .output(z.object({username: z.string()}))
77
- .handle(() => Response.json(201, {username: "neo"})),
78
- })
79
- const result = await handler(event("POST"), context)
80
- expect(result).toEqual({
81
- statusCode: 201,
82
- body: JSON.stringify({username: "neo"}),
83
- headers: {"Content-Type": "application/json; charset=utf-8"},
84
- })
85
- })
86
- })
@@ -1,37 +0,0 @@
1
- import {createHandler} from "#src/handler"
2
- import {method} from "#src/method"
3
- import type {APIGatewayProxyEvent, Context} from "aws-lambda"
4
- import {describe, expect, it} from "vitest"
5
-
6
- function event(httpMethod: string, body: unknown = undefined): APIGatewayProxyEvent {
7
- return {
8
- body:
9
- body === undefined ? null
10
- : typeof body === "string" ? body
11
- : JSON.stringify(body),
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 routing", () => {
29
- it("returns 405 with allow header for unsupported methods", async () => {
30
- const handler = createHandler({GET: method().handle(() => ({ok: true}))})
31
- await expect(handler(event("POST"), context)).resolves.toEqual({
32
- statusCode: 405,
33
- body: "Method Not Allowed",
34
- headers: {"Content-Type": "text/plain; charset=utf-8", Allow: "GET"},
35
- })
36
- })
37
- })
@@ -1,48 +0,0 @@
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
- })
@@ -1,40 +0,0 @@
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
- })
@@ -1,29 +0,0 @@
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
- })
@@ -1,26 +0,0 @@
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 DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "extends": ["./tsconfig.build.json", "./tsconfig.node.json"]
3
- }
@@ -1,24 +0,0 @@
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
- }