@certik/serverless-api 1.0.12 → 2.1.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.
Files changed (58) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +0 -1
  3. package/dist/deploy.d.ts +20 -0
  4. package/dist/deploy.d.ts.map +1 -0
  5. package/dist/deploy.js +17 -0
  6. package/dist/dev.d.ts +8 -0
  7. package/dist/dev.d.ts.map +1 -0
  8. package/dist/dev.js +8 -0
  9. package/dist/entrypoint.d.ts +26 -0
  10. package/dist/entrypoint.d.ts.map +1 -0
  11. package/dist/entrypoint.js +78 -0
  12. package/dist/handler.d.ts +2 -0
  13. package/dist/handler.d.ts.map +1 -0
  14. package/{index.js → dist/handler.js} +1 -0
  15. package/dist/index.d.ts +14 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +13 -0
  18. package/dist/lib/app.d.ts +39 -0
  19. package/dist/lib/app.d.ts.map +1 -0
  20. package/dist/lib/app.js +139 -0
  21. package/dist/lib/const.d.ts +12 -0
  22. package/dist/lib/const.d.ts.map +1 -0
  23. package/dist/lib/const.js +12 -0
  24. package/dist/lib/cors.d.ts +19 -0
  25. package/dist/lib/cors.d.ts.map +1 -0
  26. package/dist/lib/cors.js +38 -0
  27. package/dist/lib/dev.d.ts +38 -0
  28. package/dist/lib/dev.d.ts.map +1 -0
  29. package/dist/lib/dev.js +78 -0
  30. package/dist/lib/domain.d.ts +16 -0
  31. package/dist/lib/domain.d.ts.map +1 -0
  32. package/dist/lib/domain.js +19 -0
  33. package/dist/lib/env.d.ts +14 -0
  34. package/dist/lib/env.d.ts.map +1 -0
  35. package/dist/lib/env.js +37 -0
  36. package/dist/lib/pack.d.ts +29 -0
  37. package/dist/lib/pack.d.ts.map +1 -0
  38. package/dist/lib/pack.js +93 -0
  39. package/dist/lib/path.d.ts +22 -0
  40. package/dist/lib/path.d.ts.map +1 -0
  41. package/dist/lib/path.js +26 -0
  42. package/dist/lib/routes.d.ts +32 -0
  43. package/dist/lib/routes.d.ts.map +1 -0
  44. package/dist/lib/routes.js +76 -0
  45. package/dist/lib/types.d.ts +125 -0
  46. package/dist/lib/types.d.ts.map +1 -0
  47. package/dist/lib/types.js +7 -0
  48. package/package.json +58 -44
  49. package/dev.js +0 -4
  50. package/entrypoint.js +0 -68
  51. package/lib/app.js +0 -162
  52. package/lib/const.js +0 -4
  53. package/lib/cors.js +0 -21
  54. package/lib/dev.js +0 -54
  55. package/lib/env.js +0 -24
  56. package/lib/pack.js +0 -83
  57. package/lib/path.js +0 -6
  58. package/lib/routes.js +0 -39
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 2.1.0
2
+
3
+ - added exports field to package.json mapping subpaths to dist/ counterparts
4
+
5
+ # 2.0.0
6
+
7
+ - Migrate the whole repo to typescript
8
+
1
9
  # 1.0.12
2
10
 
3
11
  - fixed incorrect parsing of empty request body in startLocalApp
package/README.md CHANGED
@@ -59,7 +59,6 @@ export default async function handler(event) {
59
59
  }
60
60
  ```
61
61
 
62
-
63
62
  **Local Development Workflow**
64
63
 
65
64
  ```bash
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Pulumi program entry point.
3
+ *
4
+ * Loads routes from the local `routes/` directory and deploys
5
+ * the full serverless API stack via {@link createPulumiAPIApp}.
6
+ */
7
+ export default function main(): Promise<{
8
+ zipFileName: string;
9
+ zipFileHash: string;
10
+ routes: Record<string, {
11
+ method: string;
12
+ timeout: number;
13
+ url: string;
14
+ }>;
15
+ runtime: import("@pulumi/aws/lambda/index.js").Runtime;
16
+ hostedZone: string;
17
+ domainName: string;
18
+ readme: string;
19
+ }>;
20
+ //# sourceMappingURL=deploy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,wBAA8B,IAAI;;;;;;;;;;;;GAOjC"}
package/dist/deploy.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Pulumi program entry point.
3
+ *
4
+ * Loads routes from the local `routes/` directory and deploys
5
+ * the full serverless API stack via {@link createPulumiAPIApp}.
6
+ */
7
+ import pathModule from "node:path";
8
+ import { createPulumiAPIApp } from "./lib/app.js";
9
+ import { dirname } from "./lib/path.js";
10
+ import { getRoutes } from "./lib/routes.js";
11
+ export default async function main() {
12
+ return createPulumiAPIApp({
13
+ routes: await getRoutes(pathModule.join(dirname(import.meta.url), "routes")),
14
+ bundleDevDependencies: true,
15
+ });
16
+ }
17
+ //# sourceMappingURL=deploy.js.map
package/dist/dev.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Re-export of {@link startLocalApp} for consumer convenience.
3
+ *
4
+ * Consumers can `import { startLocalApp } from "@certik/serverless-api/dev"`
5
+ * without pulling in the full library.
6
+ */
7
+ export { startLocalApp } from "./lib/dev.js";
8
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
package/dist/dev.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Re-export of {@link startLocalApp} for consumer convenience.
3
+ *
4
+ * Consumers can `import { startLocalApp } from "@certik/serverless-api/dev"`
5
+ * without pulling in the full library.
6
+ */
7
+ export { startLocalApp } from "./lib/dev.js";
8
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Shared Lambda entrypoint.
3
+ *
4
+ * All Lambda functions deployed by this library share this single
5
+ * entrypoint. It discovers routes once on cold start, then matches
6
+ * each incoming API Gateway event to the correct handler, applying
7
+ * timeout enforcement and CORS headers.
8
+ *
9
+ * @module entrypoint
10
+ */
11
+ import type { LambdaEvent, LambdaContext, LambdaResponse } from "./lib/types.js";
12
+ /**
13
+ * The Lambda handler invoked by API Gateway.
14
+ *
15
+ * On the first invocation (cold start), routes are loaded from the
16
+ * `routes/` directory and cached for subsequent warm invocations.
17
+ * The handler matches the request path and HTTP method to a route,
18
+ * applies the configured timeout, and injects CORS headers when
19
+ * the route defines a `corsOrigin`.
20
+ *
21
+ * @param event - The API Gateway proxy integration event.
22
+ * @param context - The Lambda execution context.
23
+ * @returns The HTTP response to send back through API Gateway.
24
+ */
25
+ export declare const handler: (event: LambdaEvent, context: LambdaContext) => Promise<LambdaResponse>;
26
+ //# sourceMappingURL=entrypoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entrypoint.d.ts","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAEV,WAAW,EACX,aAAa,EACb,cAAc,EACf,MAAM,gBAAgB,CAAC;AAOxB;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,OAAO,GAClB,OAAO,WAAW,EAClB,SAAS,aAAa,KACrB,OAAO,CAAC,cAAc,CAiExB,CAAC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Shared Lambda entrypoint.
3
+ *
4
+ * All Lambda functions deployed by this library share this single
5
+ * entrypoint. It discovers routes once on cold start, then matches
6
+ * each incoming API Gateway event to the correct handler, applying
7
+ * timeout enforcement and CORS headers.
8
+ *
9
+ * @module entrypoint
10
+ */
11
+ import pathModule from "node:path";
12
+ import { getRoutes } from "./lib/routes.js";
13
+ /** Cached routes — resolved once on cold start. */
14
+ let cachedRoutes = null;
15
+ /**
16
+ * The Lambda handler invoked by API Gateway.
17
+ *
18
+ * On the first invocation (cold start), routes are loaded from the
19
+ * `routes/` directory and cached for subsequent warm invocations.
20
+ * The handler matches the request path and HTTP method to a route,
21
+ * applies the configured timeout, and injects CORS headers when
22
+ * the route defines a `corsOrigin`.
23
+ *
24
+ * @param event - The API Gateway proxy integration event.
25
+ * @param context - The Lambda execution context.
26
+ * @returns The HTTP response to send back through API Gateway.
27
+ */
28
+ export const handler = async (event, context) => {
29
+ if (!cachedRoutes) {
30
+ cachedRoutes = await getRoutes(pathModule.resolve("routes"));
31
+ }
32
+ const currentRoute = cachedRoutes.find((route) => {
33
+ return (route.path === event.path &&
34
+ route.method.toLowerCase() === event.httpMethod.toLowerCase());
35
+ });
36
+ if (!currentRoute) {
37
+ return {
38
+ statusCode: 404,
39
+ body: "Not Found",
40
+ };
41
+ }
42
+ const extraHeaders = {};
43
+ if (currentRoute.corsOrigin) {
44
+ extraHeaders["Access-Control-Allow-Origin"] = currentRoute.corsOrigin;
45
+ }
46
+ let timeoutId;
47
+ const response = await Promise.race([
48
+ (async () => {
49
+ let body = event.body ? event.body : null;
50
+ if (event.isBase64Encoded && body) {
51
+ body = Buffer.from(body, "base64").toString("utf-8");
52
+ }
53
+ const rp = await currentRoute.handler({
54
+ ...event,
55
+ body,
56
+ isBase64Encoded: false,
57
+ }, context);
58
+ return rp;
59
+ })(),
60
+ new Promise(function timeoutResponse(resolve) {
61
+ timeoutId = setTimeout(() => {
62
+ resolve({
63
+ statusCode: 408,
64
+ body: `Request Timeout after ${currentRoute.timeout} seconds`,
65
+ });
66
+ }, currentRoute.timeout * 1000);
67
+ }),
68
+ ]);
69
+ clearTimeout(timeoutId);
70
+ return {
71
+ ...response,
72
+ headers: {
73
+ ...response.headers,
74
+ ...extraHeaders,
75
+ },
76
+ };
77
+ };
78
+ //# sourceMappingURL=entrypoint.js.map
@@ -0,0 +1,2 @@
1
+ export { handler } from "./entrypoint.js";
2
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC"}
@@ -1 +1,2 @@
1
1
  export { handler } from "./entrypoint.js";
2
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Public API surface of `@certik/serverless-api`.
3
+ *
4
+ * Re-exports the key utilities consumers need to build and
5
+ * deploy their own serverless APIs.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ export { dirname } from "./lib/path.js";
10
+ export { startLocalApp } from "./lib/dev.js";
11
+ export { createPulumiAPIApp } from "./lib/app.js";
12
+ export { getRoutes } from "./lib/routes.js";
13
+ export type { Route, RouteHandler, RouteModule, LambdaEvent, LambdaContext, LambdaResponse, PulumiAPIAppOptions, LocalAppOptions, PackOptions, PackResult, } from "./lib/types.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EACV,KAAK,EACL,YAAY,EACZ,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,UAAU,GACX,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Public API surface of `@certik/serverless-api`.
3
+ *
4
+ * Re-exports the key utilities consumers need to build and
5
+ * deploy their own serverless APIs.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ export { dirname } from "./lib/path.js";
10
+ export { startLocalApp } from "./lib/dev.js";
11
+ export { createPulumiAPIApp } from "./lib/app.js";
12
+ export { getRoutes } from "./lib/routes.js";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Pulumi deployment logic for the serverless API.
3
+ *
4
+ * Creates the full AWS infrastructure stack: Lambda functions,
5
+ * API Gateway, custom domain, ACM certificate, and Route 53
6
+ * DNS records. Each route gets its own Lambda function, all
7
+ * sharing the same source zip and entrypoint.
8
+ *
9
+ * @module app
10
+ */
11
+ import * as aws from "@pulumi/aws";
12
+ import type { PulumiAPIAppOptions } from "./types.js";
13
+ export { getWildcardCertificateName } from "./domain.js";
14
+ /**
15
+ * Create and deploy the full Pulumi serverless API stack.
16
+ *
17
+ * This provisions:
18
+ * - An S3 bucket object containing the zipped source code.
19
+ * - One Lambda function per route.
20
+ * - An API Gateway REST API wiring routes to Lambdas.
21
+ * - A custom domain with ACM certificate and Route 53 alias record.
22
+ *
23
+ * @param options - Deployment options including routes and bundling flags.
24
+ * @returns Deployment metadata: zip info, route URLs, runtime, and README.
25
+ */
26
+ export declare function createPulumiAPIApp({ routes, bundleDevDependencies, }: PulumiAPIAppOptions): Promise<{
27
+ zipFileName: string;
28
+ zipFileHash: string;
29
+ routes: Record<string, {
30
+ method: string;
31
+ timeout: number;
32
+ url: string;
33
+ }>;
34
+ runtime: aws.lambda.Runtime;
35
+ hostedZone: string;
36
+ domainName: string;
37
+ readme: string;
38
+ }>;
39
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/lib/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;AAKnC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAMtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAEzD;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CAAC,EACvC,MAAM,EACN,qBAA6B,GAC9B,EAAE,mBAAmB;;;;gBAkHc,MAAM;iBAAW,MAAM;aAAO,MAAM;;;;;;GAwBvE"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Pulumi deployment logic for the serverless API.
3
+ *
4
+ * Creates the full AWS infrastructure stack: Lambda functions,
5
+ * API Gateway, custom domain, ACM certificate, and Route 53
6
+ * DNS records. Each route gets its own Lambda function, all
7
+ * sharing the same source zip and entrypoint.
8
+ *
9
+ * @module app
10
+ */
11
+ import * as aws from "@pulumi/aws";
12
+ import * as apigateway from "@pulumi/aws-apigateway";
13
+ import * as pulumi from "@pulumi/pulumi";
14
+ import { readFile } from "node:fs/promises";
15
+ import { getWildcardCertificateName } from "./domain.js";
16
+ import { isReservedEnvName } from "./env.js";
17
+ import { packAndZip } from "./pack.js";
18
+ export { getWildcardCertificateName } from "./domain.js";
19
+ /**
20
+ * Create and deploy the full Pulumi serverless API stack.
21
+ *
22
+ * This provisions:
23
+ * - An S3 bucket object containing the zipped source code.
24
+ * - One Lambda function per route.
25
+ * - An API Gateway REST API wiring routes to Lambdas.
26
+ * - A custom domain with ACM certificate and Route 53 alias record.
27
+ *
28
+ * @param options - Deployment options including routes and bundling flags.
29
+ * @returns Deployment metadata: zip info, route URLs, runtime, and README.
30
+ */
31
+ export async function createPulumiAPIApp({ routes, bundleDevDependencies = false, }) {
32
+ const { zipFileName, zipFileHash } = await packAndZip({
33
+ bundleDevDependencies,
34
+ });
35
+ const projectName = pulumi.getProject();
36
+ const stackName = pulumi.getStack();
37
+ const namespace = `wf-${stackName}-${projectName}-${stackName}`;
38
+ const config = new pulumi.Config();
39
+ const sourceBucketName = config.require("sourceBucket");
40
+ const hostedZone = config.require("hostedZone");
41
+ const runtime = config.require("runtime");
42
+ let subdomain = config.get("subdomain");
43
+ if (!subdomain) {
44
+ subdomain = projectName.startsWith("api-")
45
+ ? projectName.slice(4)
46
+ : projectName;
47
+ }
48
+ const domainName = `${subdomain}.${hostedZone}`;
49
+ const wildcardCertificateName = getWildcardCertificateName(domainName);
50
+ const lambdaRoleName = config.get("lambdaRole");
51
+ const role = aws.iam.getRole({ name: lambdaRoleName });
52
+ const sourceBucket = aws.s3.getBucket({ bucket: sourceBucketName });
53
+ const sourceKey = `${namespace}/sourcecode.zip`;
54
+ const sourceS3File = new aws.s3.BucketObject(`${namespace}-s3-sourcecode`, {
55
+ bucket: sourceBucket.then((b) => b.id),
56
+ key: sourceKey,
57
+ source: new pulumi.asset.FileArchive(zipFileName),
58
+ sourceHash: zipFileHash,
59
+ });
60
+ const site = new apigateway.RestAPI(namespace, {
61
+ routes: routes.map(({ name, path, method, timeout, memorySize, environmentVariables }) => {
62
+ const variables = environmentVariables
63
+ ? environmentVariables.reduce((acc, envName) => {
64
+ if (isReservedEnvName(envName)) {
65
+ return acc;
66
+ }
67
+ if (process.env[envName]) {
68
+ acc[envName] = process.env[envName];
69
+ }
70
+ else {
71
+ console.warn(`Environment variable not set: process.env.${envName}`);
72
+ }
73
+ return acc;
74
+ }, {})
75
+ : {};
76
+ return {
77
+ path,
78
+ method: method,
79
+ eventHandler: new aws.lambda.Function(`${namespace}-${name}`.slice(0, 56), {
80
+ name: `${namespace}-${name}`.slice(0, 56),
81
+ role: role.then((r) => r.arn),
82
+ runtime,
83
+ s3Bucket: sourceBucketName,
84
+ s3Key: sourceS3File.key,
85
+ handler: "entrypoint.handler",
86
+ sourceCodeHash: zipFileHash,
87
+ timeout: timeout + 10,
88
+ memorySize,
89
+ environment: { variables },
90
+ }),
91
+ };
92
+ }),
93
+ });
94
+ const certificate = await aws.acm.getCertificate({
95
+ domain: wildcardCertificateName,
96
+ statuses: ["ISSUED"],
97
+ });
98
+ const zone = await aws.route53.getZone({ name: hostedZone }, { async: true });
99
+ const domain = new aws.apigateway.DomainName(namespace, {
100
+ certificateArn: certificate.arn,
101
+ domainName,
102
+ });
103
+ const _basePathMapping = new aws.apigateway.BasePathMapping(namespace, {
104
+ restApi: site.api,
105
+ stageName: site.stage.stageName,
106
+ domainName: domain.domainName,
107
+ });
108
+ const _dnsRecord = new aws.route53.Record(namespace, {
109
+ type: "A",
110
+ zoneId: zone.zoneId,
111
+ name: domainName,
112
+ aliases: [
113
+ {
114
+ name: domain.cloudfrontDomainName,
115
+ zoneId: domain.cloudfrontZoneId,
116
+ evaluateTargetHealth: false,
117
+ },
118
+ ],
119
+ });
120
+ const routesInfo = routes.reduce((acc, { name, method, timeout, path }) => {
121
+ acc[name] = {
122
+ method,
123
+ timeout,
124
+ url: `https://${domainName}${path}`,
125
+ };
126
+ return acc;
127
+ }, {});
128
+ const readme = (await readFile("./README.md")).toString();
129
+ return {
130
+ zipFileName,
131
+ zipFileHash,
132
+ routes: routesInfo,
133
+ runtime,
134
+ hostedZone,
135
+ domainName,
136
+ readme,
137
+ };
138
+ }
139
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Default and maximum configuration constants for Lambda functions.
3
+ *
4
+ * @module const
5
+ */
6
+ /** Default Lambda timeout in seconds. */
7
+ export declare const DEFAULT_TIMEOUT = 30;
8
+ /** Maximum allowed Lambda timeout in seconds. */
9
+ export declare const MAX_TIMEOUT = 90;
10
+ /** Default Lambda memory allocation in megabytes. */
11
+ export declare const DEFAULT_MEMORY_SIZE = 128;
12
+ //# sourceMappingURL=const.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../src/lib/const.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yCAAyC;AACzC,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,iDAAiD;AACjD,eAAO,MAAM,WAAW,KAAK,CAAC;AAE9B,qDAAqD;AACrD,eAAO,MAAM,mBAAmB,MAAM,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Default and maximum configuration constants for Lambda functions.
3
+ *
4
+ * @module const
5
+ */
6
+ /** Default Lambda timeout in seconds. */
7
+ export const DEFAULT_TIMEOUT = 30;
8
+ /** Maximum allowed Lambda timeout in seconds. */
9
+ export const MAX_TIMEOUT = 90;
10
+ /** Default Lambda memory allocation in megabytes. */
11
+ export const DEFAULT_MEMORY_SIZE = 128;
12
+ //# sourceMappingURL=const.js.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * CORS preflight route generation.
3
+ *
4
+ * @module cors
5
+ */
6
+ import type { Route } from "./types.js";
7
+ /**
8
+ * Create an `OPTIONS` preflight route that responds with permissive
9
+ * CORS headers.
10
+ *
11
+ * The generated route allows all origins (`*`), all standard HTTP
12
+ * methods, and all request headers.
13
+ *
14
+ * @param name - A unique name for the preflight route.
15
+ * @param path - The URL path this preflight route handles.
16
+ * @returns A fully configured {@link Route} for the OPTIONS method.
17
+ */
18
+ export declare function corsPreflight(name: string, path: string): Route;
19
+ //# sourceMappingURL=cors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/lib/cors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,CAqB/D"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * CORS preflight route generation.
3
+ *
4
+ * @module cors
5
+ */
6
+ /**
7
+ * Create an `OPTIONS` preflight route that responds with permissive
8
+ * CORS headers.
9
+ *
10
+ * The generated route allows all origins (`*`), all standard HTTP
11
+ * methods, and all request headers.
12
+ *
13
+ * @param name - A unique name for the preflight route.
14
+ * @param path - The URL path this preflight route handles.
15
+ * @returns A fully configured {@link Route} for the OPTIONS method.
16
+ */
17
+ export function corsPreflight(name, path) {
18
+ return {
19
+ name,
20
+ path,
21
+ method: "OPTIONS",
22
+ timeout: 30,
23
+ memorySize: 128,
24
+ environmentVariables: [],
25
+ handler: async () => {
26
+ return {
27
+ body: "",
28
+ statusCode: 200,
29
+ headers: {
30
+ "Access-Control-Allow-Origin": "*",
31
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS, PUT, PATCH, DELETE",
32
+ "Access-Control-Allow-Headers": "*",
33
+ },
34
+ };
35
+ },
36
+ };
37
+ }
38
+ //# sourceMappingURL=cors.js.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Local development server powered by Express.
3
+ *
4
+ * Translates incoming HTTP requests into the AWS API Gateway
5
+ * proxy event format so route handlers can run identically
6
+ * in local development and in Lambda.
7
+ *
8
+ * @module dev
9
+ */
10
+ import { type Request } from "express";
11
+ import type { LambdaEvent, LocalAppOptions } from "./types.js";
12
+ /**
13
+ * Map an Express {@link Request} to an API Gateway
14
+ * {@link LambdaEvent} proxy integration event.
15
+ *
16
+ * The request body is base64-encoded when it is a `Buffer`
17
+ * (as produced by `express.raw()`), matching how API Gateway
18
+ * delivers binary payloads.
19
+ *
20
+ * @param req - The incoming Express request.
21
+ * @returns A synthetic Lambda event object.
22
+ */
23
+ export declare function mapRequestToEvent(req: Request): LambdaEvent;
24
+ /**
25
+ * Start a local Express server that serves the given routes using
26
+ * the shared Lambda handler.
27
+ *
28
+ * Each route is registered at both `/{path}` and `/dev/{path}`
29
+ * for backward compatibility with the serverless-offline convention.
30
+ * The server listens on the port specified by the `PORT` environment
31
+ * variable, defaulting to `4000`.
32
+ *
33
+ * @param options - The routes and handler to serve.
34
+ * @param options.routes - Resolved route definitions.
35
+ * @param options.handler - The shared Lambda entrypoint handler.
36
+ */
37
+ export declare function startLocalApp({ routes, handler, }: LocalAppOptions): Promise<void>;
38
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/lib/dev.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAgB,EAAE,KAAK,OAAO,EAAiB,MAAM,SAAS,CAAC;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/D;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,CAgB3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAAC,EAClC,MAAM,EACN,OAAO,GACR,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCjC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Local development server powered by Express.
3
+ *
4
+ * Translates incoming HTTP requests into the AWS API Gateway
5
+ * proxy event format so route handlers can run identically
6
+ * in local development and in Lambda.
7
+ *
8
+ * @module dev
9
+ */
10
+ import express from "express";
11
+ /**
12
+ * Map an Express {@link Request} to an API Gateway
13
+ * {@link LambdaEvent} proxy integration event.
14
+ *
15
+ * The request body is base64-encoded when it is a `Buffer`
16
+ * (as produced by `express.raw()`), matching how API Gateway
17
+ * delivers binary payloads.
18
+ *
19
+ * @param req - The incoming Express request.
20
+ * @returns A synthetic Lambda event object.
21
+ */
22
+ export function mapRequestToEvent(req) {
23
+ return {
24
+ resource: req.path,
25
+ path: req.path,
26
+ httpMethod: req.method,
27
+ requestContext: {
28
+ resourcePath: req.path,
29
+ httpMethod: req.method,
30
+ path: req.path,
31
+ },
32
+ headers: req.headers,
33
+ multiValueHeaders: {},
34
+ queryStringParameters: req.query,
35
+ body: Buffer.isBuffer(req.body) ? req.body.toString("base64") : "",
36
+ isBase64Encoded: true,
37
+ };
38
+ }
39
+ /**
40
+ * Start a local Express server that serves the given routes using
41
+ * the shared Lambda handler.
42
+ *
43
+ * Each route is registered at both `/{path}` and `/dev/{path}`
44
+ * for backward compatibility with the serverless-offline convention.
45
+ * The server listens on the port specified by the `PORT` environment
46
+ * variable, defaulting to `4000`.
47
+ *
48
+ * @param options - The routes and handler to serve.
49
+ * @param options.routes - Resolved route definitions.
50
+ * @param options.handler - The shared Lambda entrypoint handler.
51
+ */
52
+ export async function startLocalApp({ routes, handler, }) {
53
+ const app = express();
54
+ app.use(express.raw({
55
+ inflate: true,
56
+ limit: "10mb",
57
+ type: () => true,
58
+ }));
59
+ const port = Number(process.env["PORT"] ?? 4000);
60
+ routes.forEach(({ path, method }) => {
61
+ const m = method || "GET";
62
+ console.log(`registering ${m} ${path}`);
63
+ const callback = async (req, res) => {
64
+ const context = {};
65
+ const result = await handler(mapRequestToEvent(req), context);
66
+ for (const [key, value] of Object.entries(result.headers ?? {})) {
67
+ res.set(key, value);
68
+ }
69
+ res.status(result.statusCode);
70
+ res.send(result.body);
71
+ };
72
+ app[m.toLowerCase()](path, callback);
73
+ app[m.toLowerCase()](`/dev${path}`, callback);
74
+ });
75
+ console.log(`listening on http://localhost:${port}`);
76
+ app.listen(port);
77
+ }
78
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Domain name utilities.
3
+ *
4
+ * @module domain
5
+ */
6
+ /**
7
+ * Derive a wildcard certificate name from a fully-qualified domain.
8
+ *
9
+ * Replaces the leftmost label with `*` so the result matches an
10
+ * ACM wildcard certificate (e.g. `data.example.com` → `*.example.com`).
11
+ *
12
+ * @param domainName - The fully-qualified domain name.
13
+ * @returns The wildcard domain (e.g. `*.example.com`).
14
+ */
15
+ export declare function getWildcardCertificateName(domainName: string): string;
16
+ //# sourceMappingURL=domain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../../src/lib/domain.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAGrE"}