@reckona/mreact-router 0.0.189 → 0.0.191
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/README.md +17 -4
- package/bin/mreact-router.js +23 -0
- package/dist/adapters/aws-lambda.d.ts +33 -13
- package/dist/adapters/aws-lambda.d.ts.map +1 -1
- package/dist/adapters/aws-lambda.js +128 -20
- package/dist/adapters/aws-lambda.js.map +1 -1
- package/dist/adapters/cloudflare.d.ts +18 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/edge.d.ts +2 -0
- package/dist/adapters/edge.d.ts.map +1 -1
- package/dist/adapters/edge.js.map +1 -1
- package/dist/adapters/node.d.ts +16 -2
- package/dist/adapters/node.d.ts.map +1 -1
- package/dist/adapters/node.js.map +1 -1
- package/dist/build.d.ts +6 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +57 -12
- package/dist/build.js.map +1 -1
- package/dist/cache.d.ts +8 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +34 -13
- package/dist/cache.js.map +1 -1
- package/dist/cli-options.d.ts +4 -1
- package/dist/cli-options.d.ts.map +1 -1
- package/dist/cli-options.js +63 -3
- package/dist/cli-options.js.map +1 -1
- package/dist/cli.js +12 -0
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1 -0
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -2
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +19 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -5
- package/dist/index.js.map +1 -1
- package/dist/link.d.ts +22 -1
- package/dist/link.d.ts.map +1 -1
- package/dist/link.js +130 -5
- package/dist/link.js.map +1 -1
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +514 -517
- package/dist/render.js.map +1 -1
- package/dist/request.d.ts +10 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +6 -0
- package/dist/request.js.map +1 -0
- package/dist/typed-routes.d.ts +4 -5
- package/dist/typed-routes.d.ts.map +1 -1
- package/dist/typed-routes.js.map +1 -1
- package/dist/vite.d.ts +6 -0
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +4 -1
- package/dist/vite.js.map +1 -1
- package/package.json +19 -13
- package/src/adapters/aws-lambda.ts +227 -56
- package/src/adapters/cloudflare.ts +59 -0
- package/src/adapters/edge.ts +14 -0
- package/src/adapters/node.ts +44 -2
- package/src/build.ts +113 -16
- package/src/cache.ts +39 -17
- package/src/cli-options.ts +92 -6
- package/src/cli.ts +12 -0
- package/src/client.ts +2 -1
- package/src/config.ts +10 -2
- package/src/index.ts +57 -10
- package/src/link.ts +205 -10
- package/src/render.ts +5 -7
- package/src/request.ts +35 -0
- package/src/typed-routes.ts +4 -4
- package/src/vite.ts +30 -1
package/src/build.ts
CHANGED
|
@@ -117,10 +117,18 @@ const serverArtifactFilesystemConcurrency = 2;
|
|
|
117
117
|
type ServerTransformOutput = ReturnType<typeof transform>;
|
|
118
118
|
type ServerTransformCache = Map<string, Promise<ServerTransformOutput>>;
|
|
119
119
|
|
|
120
|
+
export type AwsLambdaGeneratedHandlerPreloadMode =
|
|
121
|
+
| "all"
|
|
122
|
+
| "hot-route-requests"
|
|
123
|
+
| "middleware"
|
|
124
|
+
| "none";
|
|
125
|
+
|
|
120
126
|
/**
|
|
121
127
|
* Configures an app-router production build and its deployment targets.
|
|
122
128
|
*/
|
|
123
129
|
export interface BuildAppOptions extends AppRouterProjectOptions {
|
|
130
|
+
awsLambdaPreload?: AwsLambdaGeneratedHandlerPreloadMode | undefined;
|
|
131
|
+
awsLambdaPreloadRoutes?: readonly string[] | undefined;
|
|
124
132
|
onBuildProgress?: ((event: BuildAppProgressEvent) => void) | undefined;
|
|
125
133
|
onBuildPhaseTiming?: ((timing: BuildAppPhaseTiming) => void) | undefined;
|
|
126
134
|
outDir: string;
|
|
@@ -261,6 +269,7 @@ export interface AwsLambdaArtifactManifest {
|
|
|
261
269
|
files: Array<{ bytes: number; path: string }>;
|
|
262
270
|
handler: string;
|
|
263
271
|
runtime: "aws-lambda";
|
|
272
|
+
streamingHandler?: string | undefined;
|
|
264
273
|
totalBytes: number;
|
|
265
274
|
version: 1;
|
|
266
275
|
}
|
|
@@ -280,6 +289,8 @@ export interface CloudflarePagesArtifactManifest {
|
|
|
280
289
|
* Configures packaging of a built app-router output directory for AWS Lambda.
|
|
281
290
|
*/
|
|
282
291
|
export interface PackageAwsLambdaArtifactOptions {
|
|
292
|
+
awsLambdaPreload?: AwsLambdaGeneratedHandlerPreloadMode | undefined;
|
|
293
|
+
awsLambdaPreloadRoutes?: readonly string[] | undefined;
|
|
283
294
|
fromDir: string;
|
|
284
295
|
handlerEntry?: string | undefined;
|
|
285
296
|
outDir: string;
|
|
@@ -810,7 +821,15 @@ async function buildAppWithResolvedProject(
|
|
|
810
821
|
|
|
811
822
|
if (shouldTrackBuildPhases === false) {
|
|
812
823
|
await Promise.all([
|
|
813
|
-
...(shouldBuildAwsLambda
|
|
824
|
+
...(shouldBuildAwsLambda
|
|
825
|
+
? [
|
|
826
|
+
writeAwsLambdaHandlerArtifact(
|
|
827
|
+
options.outDir,
|
|
828
|
+
options.awsLambdaPreload,
|
|
829
|
+
options.awsLambdaPreloadRoutes,
|
|
830
|
+
),
|
|
831
|
+
]
|
|
832
|
+
: []),
|
|
814
833
|
...(shouldBuildCloudflare
|
|
815
834
|
? [
|
|
816
835
|
writeCloudflareWorkerArtifact({
|
|
@@ -825,7 +844,15 @@ async function buildAppWithResolvedProject(
|
|
|
825
844
|
} else {
|
|
826
845
|
await timeBuildPhase(timingSink, progressSink, "adapterArtifacts", async () => {
|
|
827
846
|
await Promise.all([
|
|
828
|
-
...(shouldBuildAwsLambda
|
|
847
|
+
...(shouldBuildAwsLambda
|
|
848
|
+
? [
|
|
849
|
+
writeAwsLambdaHandlerArtifact(
|
|
850
|
+
options.outDir,
|
|
851
|
+
options.awsLambdaPreload,
|
|
852
|
+
options.awsLambdaPreloadRoutes,
|
|
853
|
+
),
|
|
854
|
+
]
|
|
855
|
+
: []),
|
|
829
856
|
...(shouldBuildCloudflare
|
|
830
857
|
? [
|
|
831
858
|
writeCloudflareWorkerArtifact({
|
|
@@ -888,14 +915,18 @@ async function createIncrementalBuildCacheFingerprint(options: {
|
|
|
888
915
|
}))
|
|
889
916
|
.sort((left, right) => left.file.localeCompare(right.file));
|
|
890
917
|
const payload = {
|
|
891
|
-
appDir: normalizeBuildInputPath(
|
|
918
|
+
appDir: normalizeBuildInputPath(
|
|
919
|
+
relative(options.project.projectRoot, options.project.routesDir),
|
|
920
|
+
),
|
|
892
921
|
assetBaseUrl: options.project.assetBaseUrl ?? null,
|
|
893
922
|
clientConsolePureFunctions: options.project.clientConsolePureFunctions ?? [],
|
|
894
923
|
clientSourceMaps: options.project.clientSourceMaps,
|
|
895
924
|
define,
|
|
896
925
|
nodeEnv: process.env.NODE_ENV ?? null,
|
|
897
926
|
publicAssetBaseUrl: options.project.publicAssetBaseUrl ?? null,
|
|
898
|
-
publicDir: normalizeBuildInputPath(
|
|
927
|
+
publicDir: normalizeBuildInputPath(
|
|
928
|
+
relative(options.project.projectRoot, options.project.publicDir),
|
|
929
|
+
),
|
|
899
930
|
routes,
|
|
900
931
|
sourceDirs: options.project.allowedSourceDirs
|
|
901
932
|
.map((directory) => normalizeBuildInputPath(relative(options.project.projectRoot, directory)))
|
|
@@ -1009,10 +1040,7 @@ async function readJsonBuildOutput<T>(file: string): Promise<T | undefined> {
|
|
|
1009
1040
|
try {
|
|
1010
1041
|
return JSON.parse(await readFile(file, "utf8")) as T;
|
|
1011
1042
|
} catch (error) {
|
|
1012
|
-
if (
|
|
1013
|
-
(isNodeError(error) && error.code === "ENOENT") ||
|
|
1014
|
-
error instanceof SyntaxError
|
|
1015
|
-
) {
|
|
1043
|
+
if ((isNodeError(error) && error.code === "ENOENT") || error instanceof SyntaxError) {
|
|
1016
1044
|
return undefined;
|
|
1017
1045
|
}
|
|
1018
1046
|
|
|
@@ -6483,10 +6511,25 @@ async function writeNavigationRuntimeBundle(
|
|
|
6483
6511
|
return script;
|
|
6484
6512
|
}
|
|
6485
6513
|
|
|
6486
|
-
async function writeAwsLambdaHandlerArtifact(
|
|
6514
|
+
async function writeAwsLambdaHandlerArtifact(
|
|
6515
|
+
outDir: string,
|
|
6516
|
+
preload?: AwsLambdaGeneratedHandlerPreloadMode,
|
|
6517
|
+
routes?: readonly string[],
|
|
6518
|
+
): Promise<void> {
|
|
6487
6519
|
const awsLambdaDir = join(outDir, "aws-lambda");
|
|
6488
6520
|
await mkdir(awsLambdaDir, { recursive: true });
|
|
6489
|
-
|
|
6521
|
+
const policy = { mode: preload ?? "middleware", ...(routes === undefined ? {} : { routes }) };
|
|
6522
|
+
await Promise.all([
|
|
6523
|
+
writeFile(
|
|
6524
|
+
join(awsLambdaDir, "mreact-handler.mjs"),
|
|
6525
|
+
awsLambdaHandlerSource("buffered", "..", policy.mode, policy.routes),
|
|
6526
|
+
),
|
|
6527
|
+
writeFile(
|
|
6528
|
+
join(awsLambdaDir, "mreact-streaming-handler.mjs"),
|
|
6529
|
+
awsLambdaHandlerSource("streaming", "..", policy.mode, policy.routes),
|
|
6530
|
+
),
|
|
6531
|
+
writeFile(join(awsLambdaDir, "preload-policy.json"), JSON.stringify(policy, null, 2)),
|
|
6532
|
+
]);
|
|
6490
6533
|
}
|
|
6491
6534
|
|
|
6492
6535
|
async function writeCloudflareWorkerArtifact(options: {
|
|
@@ -6541,7 +6584,17 @@ export async function packageAwsLambdaArtifact(
|
|
|
6541
6584
|
outDir: options.outDir,
|
|
6542
6585
|
});
|
|
6543
6586
|
if (options.handlerEntry === undefined) {
|
|
6544
|
-
await
|
|
6587
|
+
const builtPolicy = await readAwsLambdaGeneratedPreloadPolicy(options.fromDir);
|
|
6588
|
+
const preload = options.awsLambdaPreload ?? builtPolicy.mode;
|
|
6589
|
+
const routes = options.awsLambdaPreloadRoutes ?? builtPolicy.routes;
|
|
6590
|
+
await writeFile(
|
|
6591
|
+
join(options.outDir, "mreact-handler.mjs"),
|
|
6592
|
+
awsLambdaHandlerSource("buffered", ".mreact", preload, routes),
|
|
6593
|
+
);
|
|
6594
|
+
await writeFile(
|
|
6595
|
+
join(options.outDir, "mreact-streaming-handler.mjs"),
|
|
6596
|
+
awsLambdaHandlerSource("streaming", ".mreact", preload, routes),
|
|
6597
|
+
);
|
|
6545
6598
|
} else {
|
|
6546
6599
|
await writeAwsLambdaCustomHandlerArtifact({
|
|
6547
6600
|
entry: options.handlerEntry,
|
|
@@ -6559,6 +6612,9 @@ export async function packageAwsLambdaArtifact(
|
|
|
6559
6612
|
files,
|
|
6560
6613
|
handler: "mreact-handler.handler",
|
|
6561
6614
|
runtime: "aws-lambda",
|
|
6615
|
+
...(options.handlerEntry === undefined
|
|
6616
|
+
? { streamingHandler: "mreact-streaming-handler.handler" }
|
|
6617
|
+
: {}),
|
|
6562
6618
|
totalBytes: files.reduce((total, file) => total + file.bytes, 0),
|
|
6563
6619
|
version: 1,
|
|
6564
6620
|
} satisfies AwsLambdaArtifactManifest;
|
|
@@ -6788,22 +6844,63 @@ async function collectArtifactFiles(
|
|
|
6788
6844
|
);
|
|
6789
6845
|
}
|
|
6790
6846
|
|
|
6791
|
-
function awsLambdaHandlerSource(
|
|
6847
|
+
function awsLambdaHandlerSource(
|
|
6848
|
+
kind: "buffered" | "streaming",
|
|
6849
|
+
outDirRelativeToHandler: string,
|
|
6850
|
+
preload: AwsLambdaGeneratedHandlerPreloadMode = "middleware",
|
|
6851
|
+
routes?: readonly string[],
|
|
6852
|
+
): string {
|
|
6853
|
+
const createHandler =
|
|
6854
|
+
kind === "streaming"
|
|
6855
|
+
? "createAwsLambdaStreamingRequestHandler"
|
|
6856
|
+
: "createAwsLambdaRequestHandler";
|
|
6792
6857
|
return `import { fileURLToPath } from "node:url";
|
|
6793
6858
|
import { dirname, resolve } from "node:path";
|
|
6794
|
-
import {
|
|
6859
|
+
import { ${createHandler}, warmAwsLambdaRuntime } from "@reckona/mreact-router/adapters/aws-lambda";
|
|
6795
6860
|
|
|
6796
6861
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
6797
|
-
|
|
6798
|
-
export const handler = await createPreloadedAwsLambdaRequestHandler({
|
|
6862
|
+
const options = {
|
|
6799
6863
|
importPolicy: "generated",
|
|
6800
6864
|
outDir: resolve(here, ${JSON.stringify(outDirRelativeToHandler)}),
|
|
6801
|
-
preload: { mode: "
|
|
6865
|
+
preload: { mode: ${JSON.stringify(preload)}${routes === undefined ? "" : `, routes: ${JSON.stringify(routes)}`} },
|
|
6802
6866
|
timings: process.env.MREACT_ROUTER_TIMINGS === "1",
|
|
6867
|
+
};
|
|
6868
|
+
|
|
6869
|
+
await warmAwsLambdaRuntime(options);
|
|
6870
|
+
export const handler = ${createHandler}({
|
|
6871
|
+
...options,
|
|
6872
|
+
preload: { mode: "none" },
|
|
6803
6873
|
});
|
|
6804
6874
|
`;
|
|
6805
6875
|
}
|
|
6806
6876
|
|
|
6877
|
+
async function readAwsLambdaGeneratedPreloadPolicy(outDir: string): Promise<{
|
|
6878
|
+
mode: AwsLambdaGeneratedHandlerPreloadMode;
|
|
6879
|
+
routes?: readonly string[] | undefined;
|
|
6880
|
+
}> {
|
|
6881
|
+
const path = join(outDir, "aws-lambda", "preload-policy.json");
|
|
6882
|
+
try {
|
|
6883
|
+
return JSON.parse(await readFile(path, "utf8")) as {
|
|
6884
|
+
mode: AwsLambdaGeneratedHandlerPreloadMode;
|
|
6885
|
+
routes?: readonly string[] | undefined;
|
|
6886
|
+
};
|
|
6887
|
+
} catch (error) {
|
|
6888
|
+
if (isNodeErrorCode(error, "ENOENT")) {
|
|
6889
|
+
return { mode: "middleware" };
|
|
6890
|
+
}
|
|
6891
|
+
throw error;
|
|
6892
|
+
}
|
|
6893
|
+
}
|
|
6894
|
+
|
|
6895
|
+
function isNodeErrorCode(error: unknown, code: string): boolean {
|
|
6896
|
+
return (
|
|
6897
|
+
typeof error === "object" &&
|
|
6898
|
+
error !== null &&
|
|
6899
|
+
"code" in error &&
|
|
6900
|
+
(error as { code?: unknown }).code === code
|
|
6901
|
+
);
|
|
6902
|
+
}
|
|
6903
|
+
|
|
6807
6904
|
async function validateProductionRoutes(options: {
|
|
6808
6905
|
clientRouteInferenceCache: ClientRouteInferenceCache;
|
|
6809
6906
|
files: Record<string, string>;
|
package/src/cache.ts
CHANGED
|
@@ -58,6 +58,7 @@ interface AppRouterCacheState {
|
|
|
58
58
|
interface RouteCacheContext {
|
|
59
59
|
cache: AppRouterCache;
|
|
60
60
|
cachePolicy?: RouteCachePolicy | undefined;
|
|
61
|
+
closed?: boolean | undefined;
|
|
61
62
|
revalidatedPaths: Set<string>;
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -472,15 +473,20 @@ export async function withRouteCacheContext<T>(
|
|
|
472
473
|
};
|
|
473
474
|
|
|
474
475
|
return cacheState.storage.run(context, async () => {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
476
|
+
try {
|
|
477
|
+
const value = await fn();
|
|
478
|
+
context.closed = true;
|
|
479
|
+
const cachePolicy = context.cachePolicy;
|
|
480
|
+
const revalidatedPaths = Array.from(context.revalidatedPaths);
|
|
478
481
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
+
for (const path of revalidatedPaths) {
|
|
483
|
+
await context.cache.deleteByPath(path);
|
|
484
|
+
}
|
|
482
485
|
|
|
483
|
-
|
|
486
|
+
return { cachePolicy, revalidatedPaths, value };
|
|
487
|
+
} finally {
|
|
488
|
+
context.closed = true;
|
|
489
|
+
}
|
|
484
490
|
});
|
|
485
491
|
}
|
|
486
492
|
|
|
@@ -500,15 +506,17 @@ export function beginRouteCacheContext(cache: AppRouterCache | undefined): {
|
|
|
500
506
|
return context.cachePolicy;
|
|
501
507
|
},
|
|
502
508
|
async dispose() {
|
|
509
|
+
context.closed = true;
|
|
503
510
|
const revalidatedPaths = Array.from(context.revalidatedPaths);
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
511
|
+
try {
|
|
512
|
+
for (const path of revalidatedPaths) {
|
|
513
|
+
await context.cache.deleteByPath(path);
|
|
514
|
+
}
|
|
515
|
+
} finally {
|
|
516
|
+
const index = cacheState.activeContexts.lastIndexOf(context);
|
|
517
|
+
if (index !== -1) {
|
|
518
|
+
cacheState.activeContexts.splice(index, 1);
|
|
519
|
+
}
|
|
512
520
|
}
|
|
513
521
|
|
|
514
522
|
return { revalidatedPaths };
|
|
@@ -516,8 +524,22 @@ export function beginRouteCacheContext(cache: AppRouterCache | undefined): {
|
|
|
516
524
|
};
|
|
517
525
|
}
|
|
518
526
|
|
|
519
|
-
function activeRouteCacheContext(): RouteCacheContext | undefined {
|
|
520
|
-
|
|
527
|
+
export function activeRouteCacheContext(): RouteCacheContext | undefined {
|
|
528
|
+
const asyncContext = cacheState.storage.getStore();
|
|
529
|
+
|
|
530
|
+
if (asyncContext !== undefined) {
|
|
531
|
+
return asyncContext.closed === true ? undefined : asyncContext;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
for (let index = cacheState.activeContexts.length - 1; index >= 0; index -= 1) {
|
|
535
|
+
const context = cacheState.activeContexts[index];
|
|
536
|
+
|
|
537
|
+
if (context?.closed !== true) {
|
|
538
|
+
return context;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
return undefined;
|
|
521
543
|
}
|
|
522
544
|
|
|
523
545
|
// Host is excluded from the cache key to prevent attacker-supplied Host
|
package/src/cli-options.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import type { AppRouterLogger, AppRouterLogEvent } from "./logger.js";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import {
|
|
3
|
+
appRouterBuildTargetMetadata,
|
|
4
|
+
type AppRouterBuildTarget,
|
|
5
|
+
type AppRouterClientSourceMapMode,
|
|
5
6
|
} from "./config.js";
|
|
6
7
|
import type { RequestHostPolicy } from "./serve.js";
|
|
8
|
+
import type { AwsLambdaGeneratedHandlerPreloadMode } from "./build.js";
|
|
7
9
|
|
|
8
10
|
export type CliRequestLogMode = "requests";
|
|
9
11
|
export type CliBuildTarget = AppRouterBuildTarget | "all";
|
|
10
12
|
|
|
11
13
|
export interface ParsedCliArguments {
|
|
14
|
+
awsLambdaPreload?: AwsLambdaGeneratedHandlerPreloadMode | undefined;
|
|
15
|
+
awsLambdaPreloadRoutes?: readonly string[] | undefined;
|
|
12
16
|
clientSourceMaps?: AppRouterClientSourceMapMode | undefined;
|
|
13
17
|
command: string;
|
|
14
18
|
allowedHosts?: readonly string[] | undefined;
|
|
@@ -156,6 +160,36 @@ export function parseCliArguments(argv: readonly string[]): ParsedCliArguments {
|
|
|
156
160
|
continue;
|
|
157
161
|
}
|
|
158
162
|
|
|
163
|
+
if (value === "--aws-lambda-preload") {
|
|
164
|
+
parsed.awsLambdaPreload = parseCliAwsLambdaPreloadMode(
|
|
165
|
+
readOptionValue(argv, index, "aws-lambda-preload"),
|
|
166
|
+
);
|
|
167
|
+
index += 1;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (value.startsWith("--aws-lambda-preload=")) {
|
|
172
|
+
parsed.awsLambdaPreload = parseCliAwsLambdaPreloadMode(
|
|
173
|
+
value.slice("--aws-lambda-preload=".length),
|
|
174
|
+
);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (value === "--aws-lambda-preload-routes") {
|
|
179
|
+
parsed.awsLambdaPreloadRoutes = parseCliAwsLambdaPreloadRoutes(
|
|
180
|
+
readOptionValue(argv, index, "aws-lambda-preload-routes"),
|
|
181
|
+
);
|
|
182
|
+
index += 1;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (value.startsWith("--aws-lambda-preload-routes=")) {
|
|
187
|
+
parsed.awsLambdaPreloadRoutes = parseCliAwsLambdaPreloadRoutes(
|
|
188
|
+
value.slice("--aws-lambda-preload-routes=".length),
|
|
189
|
+
);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
159
193
|
if (value.startsWith("--client-source-maps=")) {
|
|
160
194
|
parsed.clientSourceMaps = parseCliClientSourceMapMode(
|
|
161
195
|
value.slice("--client-source-maps=".length),
|
|
@@ -178,6 +212,11 @@ export function parseCliArguments(argv: readonly string[]): ParsedCliArguments {
|
|
|
178
212
|
}
|
|
179
213
|
|
|
180
214
|
export function formatCliHelp(command?: string | undefined): string {
|
|
215
|
+
const defaultTargetLabel = formatBuildTargetDisplayList(
|
|
216
|
+
appRouterBuildTargetMetadata.defaultTargets,
|
|
217
|
+
);
|
|
218
|
+
const allTargetValues = formatBuildTargetValueList(appRouterBuildTargetMetadata.allTargets);
|
|
219
|
+
|
|
181
220
|
if (command === "build") {
|
|
182
221
|
return [
|
|
183
222
|
"Usage: mreact-router build [appDir] [options]",
|
|
@@ -186,9 +225,13 @@ export function formatCliHelp(command?: string | undefined): string {
|
|
|
186
225
|
"",
|
|
187
226
|
"Options:",
|
|
188
227
|
" --target=node|cloudflare|aws-lambda|all",
|
|
189
|
-
|
|
228
|
+
` Select build artifacts. Defaults to ${defaultTargetLabel.toLowerCase()}. all selects ${allTargetValues}. aws-lambda writes .mreact/aws-lambda/mreact-handler.mjs and .mreact/server/import-policy.json.`,
|
|
190
229
|
" --client-source-maps=none|hidden",
|
|
191
230
|
" Control production client source map output.",
|
|
231
|
+
" --aws-lambda-preload=middleware|hot-route-requests|all|none",
|
|
232
|
+
" Select generated Lambda initialization preload. Defaults to middleware.",
|
|
233
|
+
" --aws-lambda-preload-routes=/,/login",
|
|
234
|
+
" Select routes for hot-route-requests initialization preload.",
|
|
192
235
|
" -h, --help",
|
|
193
236
|
" Show this help message.",
|
|
194
237
|
"",
|
|
@@ -196,6 +239,7 @@ export function formatCliHelp(command?: string | undefined): string {
|
|
|
196
239
|
" mreact-router build --target=node",
|
|
197
240
|
" mreact-router build --target=cloudflare",
|
|
198
241
|
" mreact-router build --target=aws-lambda",
|
|
242
|
+
" mreact-router build --target=all",
|
|
199
243
|
].join("\n");
|
|
200
244
|
}
|
|
201
245
|
|
|
@@ -216,6 +260,10 @@ export function formatCliHelp(command?: string | undefined): string {
|
|
|
216
260
|
" For aws-lambda only, skip the production node_modules check when a later deploy step installs dependencies into the package directory.",
|
|
217
261
|
" --handler <entry>",
|
|
218
262
|
" For aws-lambda only, bundle a custom handler entry into mreact-handler.mjs. App-local extensionless TypeScript imports are bundled; package imports stay external.",
|
|
263
|
+
" --aws-lambda-preload=middleware|hot-route-requests|all|none",
|
|
264
|
+
" Override generated Lambda initialization preload. Omission preserves the build policy; legacy output without policy metadata falls back to middleware.",
|
|
265
|
+
" --aws-lambda-preload-routes=/,/login",
|
|
266
|
+
" Select routes for hot-route-requests initialization preload.",
|
|
219
267
|
" -h, --help Show this help message.",
|
|
220
268
|
"",
|
|
221
269
|
"Examples:",
|
|
@@ -272,7 +320,7 @@ export function formatCliHelp(command?: string | undefined): string {
|
|
|
272
320
|
"",
|
|
273
321
|
"Commands:",
|
|
274
322
|
" dev [appDir] Start the development server.",
|
|
275
|
-
|
|
323
|
+
` build [appDir] Build ${defaultTargetLabel} artifacts by default.`,
|
|
276
324
|
" build --target=aws-lambda Build Lambda artifacts including generated handler and import policy.",
|
|
277
325
|
" start [outDir] Serve built Node output.",
|
|
278
326
|
" package aws-lambda --from .mreact --out .lambda",
|
|
@@ -290,6 +338,7 @@ export function formatCliHelp(command?: string | undefined): string {
|
|
|
290
338
|
"Examples:",
|
|
291
339
|
" mreact-router build --target=cloudflare",
|
|
292
340
|
" mreact-router build --target=aws-lambda",
|
|
341
|
+
" mreact-router build --target=all",
|
|
293
342
|
" mreact-router package aws-lambda --from .mreact --out .lambda",
|
|
294
343
|
" mreact-router build --help",
|
|
295
344
|
].join("\n");
|
|
@@ -302,7 +351,21 @@ export function buildTargetsFromCliTarget(
|
|
|
302
351
|
return undefined;
|
|
303
352
|
}
|
|
304
353
|
|
|
305
|
-
return target === "all" ?
|
|
354
|
+
return target === "all" ? appRouterBuildTargetMetadata.allTargets : [target];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function formatBuildTargetDisplayList(targets: readonly AppRouterBuildTarget[]): string {
|
|
358
|
+
return targets.map(formatBuildTargetDisplayName).join(", ");
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function formatBuildTargetDisplayName(target: AppRouterBuildTarget): string {
|
|
362
|
+
if (target === "aws-lambda") return "AWS Lambda";
|
|
363
|
+
return target[0]?.toUpperCase() + target.slice(1);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function formatBuildTargetValueList(targets: readonly AppRouterBuildTarget[]): string {
|
|
367
|
+
if (targets.length < 2) return targets[0] ?? "";
|
|
368
|
+
return `${targets.slice(0, -1).join(", ")}, and ${targets.at(-1)}`;
|
|
306
369
|
}
|
|
307
370
|
|
|
308
371
|
export function resolveCliRequestLogMode(
|
|
@@ -440,6 +503,29 @@ function parseCliClientSourceMapMode(value: string): AppRouterClientSourceMapMod
|
|
|
440
503
|
);
|
|
441
504
|
}
|
|
442
505
|
|
|
506
|
+
function parseCliAwsLambdaPreloadMode(value: string): AwsLambdaGeneratedHandlerPreloadMode {
|
|
507
|
+
if (
|
|
508
|
+
value === "all" ||
|
|
509
|
+
value === "hot-route-requests" ||
|
|
510
|
+
value === "middleware" ||
|
|
511
|
+
value === "none"
|
|
512
|
+
) {
|
|
513
|
+
return value;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
throw new Error(
|
|
517
|
+
`Unsupported aws-lambda-preload ${JSON.stringify(value)}. Expected "middleware", "hot-route-requests", "all", or "none".`,
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function parseCliAwsLambdaPreloadRoutes(value: string): readonly string[] {
|
|
522
|
+
const routes = value.split(",").filter((route) => route.startsWith("/"));
|
|
523
|
+
if (routes.length === 0 || routes.join(",") !== value) {
|
|
524
|
+
throw new Error("aws-lambda-preload-routes must be a comma-separated list of absolute routes.");
|
|
525
|
+
}
|
|
526
|
+
return routes;
|
|
527
|
+
}
|
|
528
|
+
|
|
443
529
|
function readOptionValue(values: readonly string[], index: number, name: string): string {
|
|
444
530
|
const value = values[index + 1];
|
|
445
531
|
|
package/src/cli.ts
CHANGED
|
@@ -61,6 +61,12 @@ if (parsed !== undefined) {
|
|
|
61
61
|
try {
|
|
62
62
|
const result = await buildApp({
|
|
63
63
|
...loaded.project,
|
|
64
|
+
...(parsed.awsLambdaPreload === undefined
|
|
65
|
+
? {}
|
|
66
|
+
: { awsLambdaPreload: parsed.awsLambdaPreload }),
|
|
67
|
+
...(parsed.awsLambdaPreloadRoutes === undefined
|
|
68
|
+
? {}
|
|
69
|
+
: { awsLambdaPreloadRoutes: parsed.awsLambdaPreloadRoutes }),
|
|
64
70
|
...(parsed.clientSourceMaps === undefined
|
|
65
71
|
? {}
|
|
66
72
|
: { clientSourceMaps: parsed.clientSourceMaps }),
|
|
@@ -87,6 +93,12 @@ if (parsed !== undefined) {
|
|
|
87
93
|
} else if (command === "package") {
|
|
88
94
|
if (routeArg === "aws-lambda") {
|
|
89
95
|
const manifest = await packageAwsLambdaArtifact({
|
|
96
|
+
...(parsed.awsLambdaPreload === undefined
|
|
97
|
+
? {}
|
|
98
|
+
: { awsLambdaPreload: parsed.awsLambdaPreload }),
|
|
99
|
+
...(parsed.awsLambdaPreloadRoutes === undefined
|
|
100
|
+
? {}
|
|
101
|
+
: { awsLambdaPreloadRoutes: parsed.awsLambdaPreloadRoutes }),
|
|
90
102
|
fromDir: resolve(parsed.from ?? ".mreact"),
|
|
91
103
|
...(parsed.handler === undefined ? {} : { handlerEntry: resolve(parsed.handler) }),
|
|
92
104
|
outDir: resolve(parsed.out ?? ".lambda"),
|
package/src/client.ts
CHANGED
|
@@ -103,7 +103,7 @@ export interface ClientRouteInferenceCache {
|
|
|
103
103
|
transformedSourceByFile: Map<string, Promise<CachedClientRouteSource>>;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
interface CachedClientRouteSource {
|
|
106
|
+
export interface CachedClientRouteSource {
|
|
107
107
|
signature: string;
|
|
108
108
|
source: string;
|
|
109
109
|
}
|
|
@@ -3535,6 +3535,7 @@ function __mreactSyncRouteDataScripts(root, currentRouteId, nextRouteId) {
|
|
|
3535
3535
|
|
|
3536
3536
|
function __mreactRouteDataScriptIds(...routeIds) {
|
|
3537
3537
|
const ids = new Set();
|
|
3538
|
+
ids.add("__mreact_auth_session");
|
|
3538
3539
|
|
|
3539
3540
|
for (const routeId of routeIds) {
|
|
3540
3541
|
if (typeof routeId !== "string" || routeId === "") {
|
package/src/config.ts
CHANGED
|
@@ -4,6 +4,14 @@ import { basename, dirname, isAbsolute, relative, resolve } from "node:path";
|
|
|
4
4
|
* Selects the deployment runtime artifacts emitted by an app-router build.
|
|
5
5
|
*/
|
|
6
6
|
export type AppRouterBuildTarget = "node" | "cloudflare" | "aws-lambda";
|
|
7
|
+
|
|
8
|
+
export const appRouterBuildTargetMetadata = {
|
|
9
|
+
allTargets: ["node", "cloudflare", "aws-lambda"],
|
|
10
|
+
defaultTargets: ["node"],
|
|
11
|
+
} as const satisfies {
|
|
12
|
+
allTargets: readonly AppRouterBuildTarget[];
|
|
13
|
+
defaultTargets: readonly AppRouterBuildTarget[];
|
|
14
|
+
};
|
|
7
15
|
/**
|
|
8
16
|
* Names a browser console method that can be stripped from client bundles.
|
|
9
17
|
*/
|
|
@@ -180,7 +188,7 @@ export function resolveBuildTargets(
|
|
|
180
188
|
targets: readonly AppRouterBuildTarget[] | undefined,
|
|
181
189
|
): readonly AppRouterBuildTarget[] {
|
|
182
190
|
if (targets === undefined) {
|
|
183
|
-
return
|
|
191
|
+
return appRouterBuildTargetMetadata.defaultTargets;
|
|
184
192
|
}
|
|
185
193
|
|
|
186
194
|
const uniqueTargets = [...new Set(targets)];
|
|
@@ -190,7 +198,7 @@ export function resolveBuildTargets(
|
|
|
190
198
|
}
|
|
191
199
|
|
|
192
200
|
for (const target of uniqueTargets) {
|
|
193
|
-
if (
|
|
201
|
+
if (!appRouterBuildTargetMetadata.allTargets.some((supported) => supported === target)) {
|
|
194
202
|
throw new Error(
|
|
195
203
|
`Unsupported mreactRouter build target ${JSON.stringify(target)}. Expected "node", "cloudflare", or "aws-lambda".`,
|
|
196
204
|
);
|