@reckona/mreact-router 0.0.189 → 0.0.190

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/README.md +16 -3
  2. package/bin/mreact-router.js +23 -0
  3. package/dist/adapters/aws-lambda.d.ts +33 -13
  4. package/dist/adapters/aws-lambda.d.ts.map +1 -1
  5. package/dist/adapters/aws-lambda.js +128 -20
  6. package/dist/adapters/aws-lambda.js.map +1 -1
  7. package/dist/adapters/cloudflare.d.ts +18 -0
  8. package/dist/adapters/cloudflare.d.ts.map +1 -1
  9. package/dist/adapters/cloudflare.js.map +1 -1
  10. package/dist/adapters/edge.d.ts +2 -0
  11. package/dist/adapters/edge.d.ts.map +1 -1
  12. package/dist/adapters/edge.js.map +1 -1
  13. package/dist/adapters/node.d.ts +16 -2
  14. package/dist/adapters/node.d.ts.map +1 -1
  15. package/dist/adapters/node.js.map +1 -1
  16. package/dist/cache.d.ts +8 -0
  17. package/dist/cache.d.ts.map +1 -1
  18. package/dist/cache.js +34 -13
  19. package/dist/cache.js.map +1 -1
  20. package/dist/cli-options.d.ts +1 -1
  21. package/dist/cli-options.d.ts.map +1 -1
  22. package/dist/cli-options.js +21 -3
  23. package/dist/cli-options.js.map +1 -1
  24. package/dist/cli.js +0 -0
  25. package/dist/client.d.ts +1 -1
  26. package/dist/client.d.ts.map +1 -1
  27. package/dist/client.js +1 -0
  28. package/dist/client.js.map +1 -1
  29. package/dist/config.d.ts +4 -0
  30. package/dist/config.d.ts.map +1 -1
  31. package/dist/config.js +6 -2
  32. package/dist/config.js.map +1 -1
  33. package/dist/index.d.ts +19 -16
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +15 -5
  36. package/dist/index.js.map +1 -1
  37. package/dist/link.d.ts +22 -1
  38. package/dist/link.d.ts.map +1 -1
  39. package/dist/link.js +130 -5
  40. package/dist/link.js.map +1 -1
  41. package/dist/render.d.ts.map +1 -1
  42. package/dist/render.js +514 -517
  43. package/dist/render.js.map +1 -1
  44. package/dist/request.d.ts +10 -0
  45. package/dist/request.d.ts.map +1 -0
  46. package/dist/request.js +6 -0
  47. package/dist/request.js.map +1 -0
  48. package/dist/typed-routes.d.ts +4 -5
  49. package/dist/typed-routes.d.ts.map +1 -1
  50. package/dist/typed-routes.js.map +1 -1
  51. package/dist/vite.d.ts +6 -0
  52. package/dist/vite.d.ts.map +1 -1
  53. package/dist/vite.js +4 -1
  54. package/dist/vite.js.map +1 -1
  55. package/package.json +19 -13
  56. package/src/adapters/aws-lambda.ts +227 -56
  57. package/src/adapters/cloudflare.ts +59 -0
  58. package/src/adapters/edge.ts +14 -0
  59. package/src/adapters/node.ts +44 -2
  60. package/src/cache.ts +39 -17
  61. package/src/cli-options.ts +28 -6
  62. package/src/client.ts +2 -1
  63. package/src/config.ts +10 -2
  64. package/src/index.ts +56 -10
  65. package/src/link.ts +205 -10
  66. package/src/render.ts +5 -7
  67. package/src/request.ts +35 -0
  68. package/src/typed-routes.ts +4 -4
  69. package/src/vite.ts +30 -1
package/README.md CHANGED
@@ -363,7 +363,7 @@ For Cloudflare Pages advanced mode, run `mreact-router package cloudflare-pages
363
363
  User Vite plugins from the project config are forwarded into router bundle builds after the `mreact-router` plugin itself is removed, so MDX-style syntax transforms and custom content loaders can participate in server, client, Cloudflare, and prerender bundles. Vite `define` values are also forwarded into generated Cloudflare server bundles, including `import.meta.env.*` aliases and plain define identifiers used by loaders and route handlers. Client assets, route stylesheet assets imported by pages/layouts/templates or special `error.tsx`/`not-found.tsx` boundaries, and copied public assets are served only when they appear in the generated manifest allow-list. Dynamic routes resolve modules through a build-time registry keyed by `route.file`, not by constructing module ids from request input. Generated Cloudflare route modules preserve app-router layout/template shells and named slots for both string and `stream = true` pages, including route-local `<Await>` boundaries and local server-component imports. Generated Cloudflare server route modules dispatch method exports such as `GET`, `POST`, and `ALL` with decoded dynamic params plus `context.env`, `context.context`, `context.request`, and `context.route`, so handlers can use Worker bindings directly. Cloudflare page rendering installs the per-request query client scope before loader, page, metadata, and document rendering, so server-rendered helpers can call `getQueryClient()` even in runtimes without `AsyncLocalStorage`. The Cloudflare adapter marks streamed HTML with `Cache-Control: no-transform` and `Content-Encoding: identity` so Workers compression does not gzip-buffer the first shell before placeholders can paint. Pass `onResponse` to add cross-cutting response headers to rendered, static, asset, reload, not-found, and error responses. If a generated Cloudflare route module cannot produce the `data-mreact-route-id` marker contract required by client navigation, the adapter returns a reload signal for `x-mreact-navigation: 1` requests so the browser performs a normal document navigation without first buffering the full HTML response.
364
364
 
365
365
  For AWS Lambda, use `createPreloadedAwsLambdaRequestHandler()` with API Gateway
366
- HTTP API v2 or Lambda Function URL payload format 2.0:
366
+ HTTP API v2 or Lambda Function URL payload format 2.0. It validates the event before materializing runtime files or starting preload work:
367
367
 
368
368
  ```ts
369
369
  import { createPreloadedAwsLambdaRequestHandler } from "@reckona/mreact-router/adapters/aws-lambda";
@@ -377,17 +377,30 @@ export const handler = await createPreloadedAwsLambdaRequestHandler({
377
377
  });
378
378
  ```
379
379
 
380
+ When a deployment deliberately trades Lambda initialization time for lower first-valid-request latency, call `warmAwsLambdaRuntime()` explicitly before creating the handler:
381
+
382
+ ```ts
383
+ import {
384
+ createPreloadedAwsLambdaRequestHandler,
385
+ warmAwsLambdaRuntime,
386
+ } from "@reckona/mreact-router/adapters/aws-lambda";
387
+
388
+ const options = { importPolicy: "generated" as const, outDir: ".mreact" };
389
+ await warmAwsLambdaRuntime(options);
390
+ export const handler = await createPreloadedAwsLambdaRequestHandler(options);
391
+ ```
392
+
380
393
  Production adapters enforce the app-router import policy when bundling loaders, middleware, route handlers, metadata, and server actions. `mreact-router build` writes `.mreact/server/import-policy.json` from server-side static imports. The built Node server used by `mreact-router start .mreact`, `renderBuiltAppRequest()`, and `createBuiltRequestRuntime()` reads that generated policy automatically and merges its runtime packages with any explicit policy options. Lambda handlers can use `importPolicy: "generated"`. You can still pass an explicit `importPolicy.allowedPackages` list when you need a hand-audited policy.
381
394
 
382
395
  For Lambda deployments, build with `mreact-router build --target=aws-lambda` or `buildApp({ targets: ["aws-lambda"] })`. The target writes Node-compatible server/client output, `.mreact/server/import-policy.json`, and `.mreact/aws-lambda/mreact-handler.mjs` while skipping `.mreact/cloudflare` route modules, so loaders and server helpers may import Node-only dependencies such as database drivers without being bundled for the Workers runtime.
383
396
 
384
- Package Lambda deployments with `mreact-router package aws-lambda --from .mreact --out .lambda` instead of pointing deployment tooling at the full project checkout. AWS Lambda enforces a 250 MB unzipped deployment package limit, and the runtime only needs `.mreact/`, `mreact-handler.mjs`, `package.json` / lockfiles, and production `node_modules`; `src/`, tests, dev dependencies, build caches, and Vite/Vitest/Playwright tooling are not required. `mreact-router build --target=aws-lambda` keeps compiled server route artifacts in `.mreact/server/server-modules/*.json` instead of embedding them in one large server manifest, writes compiled module bodies as hashed `.mjs` files, and keeps request/control artifacts separate from render artifacts so loader redirects do not read page render bundles. AWS Lambda request/control artifacts bundle the generated import-policy packages they use for loaders, middleware, route handlers, and metadata, reducing first-hit package resolution on sparse Lambda traffic while leaving render-only, server action, custom handler, and adapter dependencies in production `node_modules`. `createAwsLambdaRequestHandler()` treats `outDir` as read-only and materializes generated runtime files under `/tmp/mreact-router/<hash>/runtime` by default, with a `node_modules` symlink back to the deployed package root. Direct `createAwsLambdaRequestHandler()` and `createAwsLambdaStreamingRequestHandler()` handlers start only middleware and shared runtime preload in the background by default, so all-route preload work does not compete with the first user request. If a request arrives before preload finishes, middleware is resolved first, middleware responses or redirects return without loading the matched page artifact, and continuing requests load only the matched route's artifact closure. Static middleware `config.matcher` and `config.id` values are checked before importing the middleware module, so unmatched health checks and route-local middleware skips avoid evaluating heavyweight middleware dependencies. Route request artifacts omit page render exports, and built loader and route metadata artifacts are split, so loader redirects do not evaluate page-only or metadata-only dependencies before render or metadata is needed. Loader redirects settle before page component server transforms and render imports for non-stream routes, stream routes without a loading boundary, and stream loading routes whose loader source contains router control-flow helpers such as `redirect()` or `notFound()`. Prefer `await createPreloadedAwsLambdaRequestHandler()` in Node 24 ESM Lambda handlers when first-request latency matters: it waits for the full preload during Lambda initialization by default, increasing `Init Duration` but making the first handler invocation much closer to warm steady-state. Pass `runtimeDir` only when you need to control that writable cache location. With pnpm, run `pnpm --dir .lambda install --prod --frozen-lockfile --ignore-scripts --config.node-linker=hoisted`. pnpm's default isolated linker is symlink-heavy, so verify the artifact's symlink count with `find .lambda -type l | wc -l` and measure actual file bytes in addition to `du -sh .lambda` before upload. Packages listed in the generated import policy may still be needed by render-only modules, inferred server actions, custom handlers, or adapter code, so keep them installed in that production artifact.
397
+ Package Lambda deployments with `mreact-router package aws-lambda --from .mreact --out .lambda` instead of pointing deployment tooling at the full project checkout. AWS Lambda enforces a 250 MB unzipped deployment package limit, and the runtime only needs `.mreact/`, `mreact-handler.mjs`, `package.json` / lockfiles, and production `node_modules`; `src/`, tests, dev dependencies, build caches, and Vite/Vitest/Playwright tooling are not required. `mreact-router build --target=aws-lambda` keeps compiled server route artifacts in `.mreact/server/server-modules/*.json` instead of embedding them in one large server manifest, writes compiled module bodies as hashed `.mjs` files, and keeps request/control artifacts separate from render artifacts so loader redirects do not read page render bundles. AWS Lambda request/control artifacts bundle the generated import-policy packages they use for loaders, middleware, route handlers, and metadata, reducing first-hit package resolution on sparse Lambda traffic while leaving render-only, server action, custom handler, and adapter dependencies in production `node_modules`. `createAwsLambdaRequestHandler()` treats `outDir` as read-only and materializes generated runtime files under `/tmp/mreact-router/<hash>/runtime` by default, with a `node_modules` symlink back to the deployed package root. Direct `createAwsLambdaRequestHandler()` and `createAwsLambdaStreamingRequestHandler()` handlers start only middleware and shared runtime preload in the background by default, so all-route preload work does not compete with the first user request. If a request arrives before preload finishes, middleware is resolved first, middleware responses or redirects return without loading the matched page artifact, and continuing requests load only the matched route's artifact closure. Static middleware `config.matcher` and `config.id` values are checked before importing the middleware module, so unmatched health checks and route-local middleware skips avoid evaluating heavyweight middleware dependencies. Route request artifacts omit page render exports, and built loader and route metadata artifacts are split, so loader redirects do not evaluate page-only or metadata-only dependencies before render or metadata is needed. Loader redirects settle before page component server transforms and render imports for non-stream routes, stream routes without a loading boundary, and stream loading routes whose loader source contains router control-flow helpers such as `redirect()` or `notFound()`. `createPreloadedAwsLambdaRequestHandler()` validates the first event before it starts full preload. When a deployment intentionally accepts extra Lambda initialization work to reduce first-valid-request latency, call `await warmAwsLambdaRuntime(options)` during controlled initialization before creating the handler. Pass `runtimeDir` only when you need to control that writable cache location. With pnpm, run `pnpm --dir .lambda install --prod --frozen-lockfile --ignore-scripts --config.node-linker=hoisted`. pnpm's default isolated linker is symlink-heavy, so verify the artifact's symlink count with `find .lambda -type l | wc -l` and measure actual file bytes in addition to `du -sh .lambda` before upload. Packages listed in the generated import policy may still be needed by render-only modules, inferred server actions, custom handlers, or adapter code, so keep them installed in that production artifact.
385
398
 
386
399
  When a deployment needs custom adapter options such as `serverActions.authorize`, `onResponse`, `errorHandler`, or `allowedHosts`, create an app handler and package it with `mreact-router package aws-lambda --from .mreact --out .lambda --handler src/lambda.ts`. The package command bundles that handler into `.lambda/mreact-handler.mjs`, resolves app-local TypeScript imports with Vite-style extensionless paths, and keeps package imports external so production `node_modules` remains the runtime dependency boundary. If the handler imports the same app server modules that routes also import, those modules are compiled into the handler bundle separately from the mreact route artifacts; use `getServerRuntimeState()` for state that must be shared through the router runtime instead of relying on module singletons.
387
400
 
388
401
  Configure `allowedHosts` for production Lambda deployments so absolute URLs, redirects, cache keys, and metadata cannot be derived from attacker-controlled Host input. The Lambda adapter uses `Host` by default and only reads `x-forwarded-host` when `hostPolicy: "trusted-proxy"` is set. It also ignores `x-forwarded-proto` unless `trustForwardedProto: true` is configured, deriving the request scheme from the Lambda event protocol when available and otherwise defaulting to HTTPS.
389
402
 
390
- Use the Lambda `preload` option to tune that trade-off. Direct handlers default to `"middleware"` so cold starts do not kick off all route module imports in parallel with the first request. `createPreloadedAwsLambdaRequestHandler()` and `createPreloadedAwsLambdaStreamingRequestHandler()` default to `"all"` because the work is awaited during Lambda initialization instead of racing user traffic. Set `preload: "none"` to disable background preload, `preload: "all"` only when you have measured that all-route background preload helps the deployed function, `preload: { mode: "hot-routes", routes: ["/", "/dashboard"] }` with `createPreloadedAwsLambdaRequestHandler()` to await selected route closures including render modules during Lambda initialization, or `preload: { mode: "hot-route-requests", routes: ["/", "/login"] }` to warm only middleware plus selected route loader/server-route request modules without evaluating page/layout render modules. For direct handlers that cannot use top-level async initialization, add `wait: "before-render"` to an object preload strategy to let page-rendering invocations wait for the already-started preload after loader redirects have had a chance to return; add `wait: "first-request"` only when the first invocation can pay the full preload cost. Lambda request timing reports `first-request` waits as `preloadWaitMs`, and render timing reports `before-render` waits as `preloadWaitMs`.
403
+ Use the Lambda `preload` option to tune that trade-off. Direct handlers default to `"middleware"` so cold starts do not kick off all route module imports in parallel with the first request. `createPreloadedAwsLambdaRequestHandler()` and `createPreloadedAwsLambdaStreamingRequestHandler()` default to `"all"` after event validation. Call `warmAwsLambdaRuntime()` explicitly when initialization-time full preload is an intentional deployment choice. Set `preload: "none"` to disable background preload, `preload: "all"` only when you have measured that all-route background preload helps the deployed function, `preload: { mode: "hot-routes", routes: ["/", "/dashboard"] }` with `warmAwsLambdaRuntime()` to warm selected route closures including render modules before valid traffic, or `preload: { mode: "hot-route-requests", routes: ["/", "/login"] }` to warm only middleware plus selected route loader/server-route request modules without evaluating page/layout render modules. For direct handlers that cannot use top-level async initialization, add `wait: "before-render"` to an object preload strategy to let page-rendering invocations wait for the already-started preload after loader redirects have had a chance to return; add `wait: "first-request"` only when the first invocation can pay the full preload cost. Lambda request timing reports `first-request` waits as `preloadWaitMs`, and render timing reports `before-render` waits as `preloadWaitMs`.
391
404
 
392
405
  Set `timings: true` on `createAwsLambdaRequestHandler()` or `createAwsLambdaStreamingRequestHandler()` when you need low-overhead Lambda phase diagnostics. The adapter emits a `router:request:timing` debug log event with `eventToRequestMs`, `runtimeDirMs`, `renderMs`, and response serialization or streaming time, so production measurements can separate API Gateway event normalization, runtime materialization, route rendering, and Lambda response conversion. It also forwards `router:render:timing` debug events for route-level phases such as route matching, middleware, loader start/wait, source analysis, page module load, page component render, route slot render, layout module load, layout component render, metadata, and response construction. Loader timings split module load/evaluation (`loaderModuleLoadMs`) from user loader execution (`loaderExecutionMs`) inside the existing `loaderWaitMs` envelope, source analysis reports `sourceAnalysisArtifactMs` when a built analysis summary is reused, and middleware timings similarly split `middlewareModuleLoadMs` from `middlewareExecutionMs` inside `middlewareMs`. Buffered handlers report `responseSerializationMs` as the total conversion phase and split it into `streamDrainMs`, `streamReadMs`, `streamConcatMs`, and `bodyEncodeMs`; streaming handlers report `responseStreamingMs` as the total streaming phase and split it into `streamWaitMs` and `streamWriteMs`.
393
406
 
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+
3
+ const builtCliUrl = new URL("../dist/cli.js", import.meta.url);
4
+
5
+ try {
6
+ await import(builtCliUrl.href);
7
+ } catch (error) {
8
+ if (
9
+ error !== null &&
10
+ typeof error === "object" &&
11
+ "code" in error &&
12
+ error.code === "ERR_MODULE_NOT_FOUND" &&
13
+ "url" in error &&
14
+ error.url === builtCliUrl.href
15
+ ) {
16
+ console.error(
17
+ "mreact-router has not been built yet. Run the workspace or package build before invoking the CLI.",
18
+ );
19
+ process.exitCode = 1;
20
+ } else {
21
+ throw error;
22
+ }
23
+ }
@@ -4,11 +4,23 @@ import type { AppRouterImportPolicy } from "../import-policy.js";
4
4
  import { type AppRouterLogger } from "../logger.js";
5
5
  import type { AppRouterResponseHook } from "../render.js";
6
6
  import type { RouterInstrumentation } from "../trace.js";
7
- /** Re-exports router instrumentation hooks for AWS Lambda handlers. */
8
- export type { RouterInstrumentation } from "../trace.js";
7
+ /** Re-exports cache contracts used by AWS Lambda handlers. */
8
+ export type { AppRouterCache, AppRouterCacheEntry } from "../cache.js";
9
+ /** Re-exports server action contracts used by AWS Lambda handlers. */
10
+ export type { AppRouterAllowedServerAction, AppRouterServerActionOptions, } from "../actions.js";
11
+ /** Re-exports logger contracts used by AWS Lambda handlers. */
12
+ export type { AppRouterCspInlineNonceWarningLogEvent, AppRouterLogger, AppRouterLogError, AppRouterLogEvent, AppRouterRenderTimingLogEvent, AppRouterRequestEndLogEvent, AppRouterRequestErrorLogEvent, AppRouterRequestStartLogEvent, AppRouterRequestTimingLogEvent, AppRouterRuntime, } from "../logger.js";
13
+ /** Re-exports response hook contracts used by AWS Lambda handlers. */
14
+ export type { AppRouterResponseHook, AppRouterResponseHookContext } from "../render.js";
15
+ /** Re-exports build contracts referenced by AWS Lambda handler options. */
16
+ export type { BuiltPrerenderedRoute } from "../build.js";
17
+ /** Re-exports router instrumentation hooks and events for AWS Lambda handlers. */
18
+ export type { RouterInstrumentation, RouterMiddlewareEndInstrumentationEvent, RouterMiddlewareInstrumentationEvent, RouterRequestEndInstrumentationEvent, RouterRequestInstrumentationEvent, RouterRouteEndInstrumentationEvent, RouterRouteInstrumentationEvent, RouterTraceContext, } from "../trace.js";
9
19
  /** Re-exports app-router import policy controls for AWS Lambda handlers. */
10
20
  export type { AppRouterImportPolicy } from "../import-policy.js";
11
21
  import { type AppRouterPrerenderStore, type RequestHostPolicy, type ResponseSinkStrategy } from "../serve.js";
22
+ /** Re-exports request and rendering contracts used by AWS Lambda handlers. */
23
+ export type { AppRouterPrerenderStore, RequestHostPolicy, ResponseSinkStrategy, } from "../serve.js";
12
24
  /**
13
25
  * Represents the AWS API Gateway HTTP API v2 event consumed by buffered handlers.
14
26
  */
@@ -17,15 +29,15 @@ export interface AwsLambdaHttpEventV2 {
17
29
  cookies?: string[] | undefined;
18
30
  headers?: Record<string, string | undefined> | undefined;
19
31
  isBase64Encoded?: boolean | undefined;
20
- rawPath?: string | undefined;
21
- rawQueryString?: string | undefined;
22
- requestContext?: {
23
- http?: {
24
- method?: string | undefined;
32
+ rawPath: string;
33
+ rawQueryString: string;
34
+ requestContext: {
35
+ http: {
36
+ method: string;
25
37
  protocol?: string | undefined;
26
- } | undefined;
27
- } | undefined;
28
- version?: "2.0" | string | undefined;
38
+ };
39
+ };
40
+ version: "2.0";
29
41
  }
30
42
  /**
31
43
  * Represents the AWS API Gateway HTTP API v2 result returned by buffered handlers.
@@ -109,11 +121,17 @@ export type AwsLambdaStreamingRequestHandler<TContext = unknown> = (event: AwsLa
109
121
  */
110
122
  export declare function createAwsLambdaRequestHandler(options: AwsLambdaRequestHandlerOptions): AwsLambdaRequestHandler;
111
123
  /**
112
- * Creates a buffered AWS Lambda handler after eagerly preparing and preloading the built runtime.
124
+ * Creates a buffered AWS Lambda handler that starts full runtime preparation after the first valid event.
113
125
  *
114
- * Use this when startup code can await preload work before the first request instead of letting the first invocation share that cost.
126
+ * Invalid events are rejected before runtime materialization or preload work begins.
115
127
  */
116
128
  export declare function createPreloadedAwsLambdaRequestHandler(options: AwsLambdaRequestHandlerOptions): Promise<AwsLambdaRequestHandler>;
129
+ /**
130
+ * Explicitly materializes and preloads a built Lambda runtime before request handling.
131
+ *
132
+ * Call this during controlled Lambda initialization only when the extra startup work is preferable to first-valid-request latency. Request handlers always validate events before they start runtime work.
133
+ */
134
+ export declare function warmAwsLambdaRuntime(options: AwsLambdaRequestHandlerOptions): Promise<void>;
117
135
  /**
118
136
  * Creates an AWS Lambda streaming response handler for built app-router output.
119
137
  *
@@ -121,7 +139,9 @@ export declare function createPreloadedAwsLambdaRequestHandler(options: AwsLambd
121
139
  */
122
140
  export declare function createAwsLambdaStreamingRequestHandler<TContext = unknown>(options: AwsLambdaRequestHandlerOptions): AwsLambdaStreamingRequestHandler<TContext>;
123
141
  /**
124
- * Creates a streaming AWS Lambda handler after eagerly preparing and preloading the built runtime.
142
+ * Creates a streaming AWS Lambda handler that starts full runtime preparation after the first valid event.
143
+ *
144
+ * Invalid events are rejected before runtime materialization or preload work begins.
125
145
  */
126
146
  export declare function createPreloadedAwsLambdaStreamingRequestHandler<TContext = unknown>(options: AwsLambdaRequestHandlerOptions): Promise<AwsLambdaStreamingRequestHandler<TContext>>;
127
147
  //# sourceMappingURL=aws-lambda.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"aws-lambda.d.ts","sourceRoot":"","sources":["../../src/adapters/aws-lambda.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"aws-lambda.d.ts","sourceRoot":"","sources":["../../src/adapters/aws-lambda.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,21 @@ import { dirname, join } from "node:path";
6
6
  import { normalizeBuiltAppRuntimePreloadStrategy, } from "../preload-policy.js";
7
7
  import { emitRouterLog, logDurationMs, logError, logNow, requestLogFields, } from "../logger.js";
8
8
  import { createBuiltRequestRuntime, preloadBuiltAppRuntime, resolveRequestHost, warnIfImplicitHostTrust, } from "../serve.js";
9
+ const invalidAwsLambdaHttpEventV2Diagnostic = 'Expected an AWS Lambda HTTP API payload format 2.0 event with rawPath and requestContext.http.method.';
10
+ function invalidAwsLambdaHttpEventV2Result() {
11
+ return {
12
+ body: invalidAwsLambdaHttpEventV2Diagnostic,
13
+ headers: { "content-type": "text/plain; charset=utf-8" },
14
+ isBase64Encoded: false,
15
+ statusCode: 400,
16
+ };
17
+ }
18
+ function invalidAwsLambdaHttpEventV2Response() {
19
+ return new Response(invalidAwsLambdaHttpEventV2Diagnostic, {
20
+ headers: { "content-type": "text/plain; charset=utf-8" },
21
+ status: 400,
22
+ });
23
+ }
9
24
  /**
10
25
  * Creates a buffered AWS Lambda HTTP API v2 handler for built app-router output.
11
26
  *
@@ -13,24 +28,65 @@ import { createBuiltRequestRuntime, preloadBuiltAppRuntime, resolveRequestHost,
13
28
  */
14
29
  export function createAwsLambdaRequestHandler(options) {
15
30
  warnIfImplicitHostTrust(options);
16
- const runtimeDirPromise = prepareAwsLambdaRuntimeDir(options);
17
- const runtimePreloadPromise = startAwsLambdaRuntimePreload(options, runtimeDirPromise, "middleware");
18
- void runtimePreloadPromise?.catch(() => { });
19
- return createAwsLambdaRequestHandlerFromRuntime(options, runtimeDirPromise, runtimePreloadPromise, "middleware");
31
+ let handler;
32
+ return async (event) => {
33
+ try {
34
+ validateAwsLambdaHttpEventV2(event);
35
+ }
36
+ catch {
37
+ return invalidAwsLambdaHttpEventV2Result();
38
+ }
39
+ handler ??= (() => {
40
+ const runtimeDirPromise = prepareAwsLambdaRuntimeDir(options);
41
+ const runtimePreloadPromise = startAwsLambdaRuntimePreload(options, runtimeDirPromise, "middleware");
42
+ void runtimePreloadPromise?.catch(() => { });
43
+ return createAwsLambdaRequestHandlerFromRuntime(options, runtimeDirPromise, runtimePreloadPromise, "middleware");
44
+ })();
45
+ return await handler(event);
46
+ };
20
47
  }
21
48
  /**
22
- * Creates a buffered AWS Lambda handler after eagerly preparing and preloading the built runtime.
49
+ * Creates a buffered AWS Lambda handler that starts full runtime preparation after the first valid event.
23
50
  *
24
- * Use this when startup code can await preload work before the first request instead of letting the first invocation share that cost.
51
+ * Invalid events are rejected before runtime materialization or preload work begins.
25
52
  */
26
53
  export async function createPreloadedAwsLambdaRequestHandler(options) {
54
+ warnIfImplicitHostTrust(options);
55
+ let handler;
56
+ return async (event) => {
57
+ try {
58
+ validateAwsLambdaHttpEventV2(event);
59
+ }
60
+ catch {
61
+ return invalidAwsLambdaHttpEventV2Result();
62
+ }
63
+ handler ??= (() => {
64
+ const runtimeDirPromise = prepareAwsLambdaRuntimeDir(options);
65
+ const runtimePreloadPromise = startAwsLambdaRuntimePreload(options, runtimeDirPromise, "all");
66
+ void runtimePreloadPromise?.catch(() => { });
67
+ return createAwsLambdaRequestHandlerFromRuntime(options, runtimeDirPromise, runtimePreloadPromise);
68
+ })();
69
+ return await handler(event);
70
+ };
71
+ }
72
+ /**
73
+ * Explicitly materializes and preloads a built Lambda runtime before request handling.
74
+ *
75
+ * Call this during controlled Lambda initialization only when the extra startup work is preferable to first-valid-request latency. Request handlers always validate events before they start runtime work.
76
+ */
77
+ export async function warmAwsLambdaRuntime(options) {
27
78
  warnIfImplicitHostTrust(options);
28
79
  const runtimeDir = await prepareAwsLambdaRuntimeDir(options);
29
80
  await preloadAwsLambdaRuntime(options, runtimeDir);
30
- return createAwsLambdaRequestHandlerFromRuntime(options, Promise.resolve(runtimeDir));
31
81
  }
32
82
  function createAwsLambdaRequestHandlerFromRuntime(options, runtimeDirPromise, runtimePreloadPromise, defaultPreloadMode = "all") {
33
83
  return async (event) => {
84
+ try {
85
+ validateAwsLambdaHttpEventV2(event);
86
+ }
87
+ catch {
88
+ return invalidAwsLambdaHttpEventV2Result();
89
+ }
34
90
  const startedAt = logNow();
35
91
  const phases = createAwsLambdaTimingPhases(options);
36
92
  const eventToRequestStartedAt = phaseStartedAt(phases);
@@ -107,20 +163,49 @@ function createAwsLambdaRequestHandlerFromRuntime(options, runtimeDirPromise, ru
107
163
  export function createAwsLambdaStreamingRequestHandler(options) {
108
164
  warnIfImplicitHostTrust(options);
109
165
  const runtime = awsLambdaRuntime();
110
- const runtimeDirPromise = prepareAwsLambdaRuntimeDir(options);
111
- const runtimePreloadPromise = startAwsLambdaRuntimePreload(options, runtimeDirPromise, "middleware");
112
- void runtimePreloadPromise?.catch(() => { });
113
- return createAwsLambdaStreamingRequestHandlerFromRuntime(options, runtime, runtimeDirPromise, runtimePreloadPromise, "middleware");
166
+ let handler;
167
+ return runtime.streamifyResponse(async (event, responseStream, context) => {
168
+ try {
169
+ validateAwsLambdaHttpEventV2(event);
170
+ }
171
+ catch {
172
+ await streamResponseToLambda(invalidAwsLambdaHttpEventV2Response(), responseStream, runtime);
173
+ return;
174
+ }
175
+ handler ??= (() => {
176
+ const runtimeDirPromise = prepareAwsLambdaRuntimeDir(options);
177
+ const runtimePreloadPromise = startAwsLambdaRuntimePreload(options, runtimeDirPromise, "middleware");
178
+ void runtimePreloadPromise?.catch(() => { });
179
+ return createAwsLambdaStreamingRequestHandlerFromRuntime(options, runtime, runtimeDirPromise, runtimePreloadPromise, "middleware");
180
+ })();
181
+ await handler(event, responseStream, context);
182
+ });
114
183
  }
115
184
  /**
116
- * Creates a streaming AWS Lambda handler after eagerly preparing and preloading the built runtime.
185
+ * Creates a streaming AWS Lambda handler that starts full runtime preparation after the first valid event.
186
+ *
187
+ * Invalid events are rejected before runtime materialization or preload work begins.
117
188
  */
118
189
  export async function createPreloadedAwsLambdaStreamingRequestHandler(options) {
119
190
  warnIfImplicitHostTrust(options);
120
191
  const runtime = awsLambdaRuntime();
121
- const runtimeDir = await prepareAwsLambdaRuntimeDir(options);
122
- await preloadAwsLambdaRuntime(options, runtimeDir);
123
- return createAwsLambdaStreamingRequestHandlerFromRuntime(options, runtime, Promise.resolve(runtimeDir));
192
+ let handler;
193
+ return runtime.streamifyResponse(async (event, responseStream, context) => {
194
+ try {
195
+ validateAwsLambdaHttpEventV2(event);
196
+ }
197
+ catch {
198
+ await streamResponseToLambda(invalidAwsLambdaHttpEventV2Response(), responseStream, runtime);
199
+ return;
200
+ }
201
+ handler ??= (() => {
202
+ const runtimeDirPromise = prepareAwsLambdaRuntimeDir(options);
203
+ const runtimePreloadPromise = startAwsLambdaRuntimePreload(options, runtimeDirPromise, "all");
204
+ void runtimePreloadPromise?.catch(() => { });
205
+ return createAwsLambdaStreamingRequestHandlerFromRuntime(options, runtime, runtimeDirPromise, runtimePreloadPromise);
206
+ })();
207
+ await handler(event, responseStream, context);
208
+ });
124
209
  }
125
210
  function startAwsLambdaRuntimePreload(options, runtimeDirPromise, defaultMode = "all") {
126
211
  const preload = normalizeAwsLambdaPreload(options.preload, defaultMode);
@@ -213,6 +298,13 @@ function normalizeAwsLambdaPreload(strategy, defaultMode = "all") {
213
298
  }
214
299
  function createAwsLambdaStreamingRequestHandlerFromRuntime(options, runtime, runtimeDirPromise, runtimePreloadPromise, defaultPreloadMode = "all") {
215
300
  return runtime.streamifyResponse(async (event, responseStream, _context) => {
301
+ try {
302
+ validateAwsLambdaHttpEventV2(event);
303
+ }
304
+ catch {
305
+ await streamResponseToLambda(invalidAwsLambdaHttpEventV2Response(), responseStream, runtime);
306
+ return;
307
+ }
216
308
  const startedAt = logNow();
217
309
  const phases = createAwsLambdaTimingPhases(options);
218
310
  const eventToRequestStartedAt = phaseStartedAt(phases);
@@ -337,6 +429,7 @@ function isNodeErrorCode(error, code) {
337
429
  error.code === code);
338
430
  }
339
431
  function eventToRequest(event, options) {
432
+ validateAwsLambdaHttpEventV2(event);
340
433
  const headers = eventHeaders(event);
341
434
  const rawHost = lambdaRequestHost(headers, options);
342
435
  const host = resolveRequestHost({
@@ -346,11 +439,9 @@ function eventToRequest(event, options) {
346
439
  rawHost: rawHost ?? undefined,
347
440
  });
348
441
  const protocol = lambdaRequestProtocol(event, headers, options);
349
- const rawPath = event.rawPath === undefined || event.rawPath === "" ? "/" : event.rawPath;
350
- const rawQueryString = event.rawQueryString === undefined || event.rawQueryString === ""
351
- ? ""
352
- : `?${event.rawQueryString}`;
353
- const method = event.requestContext?.http?.method ?? "GET";
442
+ const rawPath = event.rawPath;
443
+ const rawQueryString = event.rawQueryString === "" ? "" : `?${event.rawQueryString}`;
444
+ const method = event.requestContext.http.method;
354
445
  const init = {
355
446
  headers,
356
447
  method,
@@ -361,6 +452,23 @@ function eventToRequest(event, options) {
361
452
  }
362
453
  return new Request(`${protocol}://${host}${rawPath}${rawQueryString}`, init);
363
454
  }
455
+ function validateAwsLambdaHttpEventV2(event) {
456
+ const candidate = event;
457
+ if (typeof candidate !== "object" ||
458
+ candidate === null ||
459
+ candidate.version !== "2.0" ||
460
+ typeof candidate.rawPath !== "string" ||
461
+ !candidate.rawPath.startsWith("/") ||
462
+ typeof candidate.rawQueryString !== "string" ||
463
+ typeof candidate.requestContext !== "object" ||
464
+ candidate.requestContext === null ||
465
+ typeof (candidate.requestContext.http) !== "object" ||
466
+ candidate.requestContext.http === null ||
467
+ typeof (candidate.requestContext.http.method) !== "string" ||
468
+ candidate.requestContext.http.method === "") {
469
+ throw new Error(invalidAwsLambdaHttpEventV2Diagnostic);
470
+ }
471
+ }
364
472
  function lambdaRequestHost(headers, options) {
365
473
  if (options.hostPolicy === "trusted-proxy") {
366
474
  return firstForwardedValue(headers.get("x-forwarded-host")) ?? headers.get("host");