@chidchanun/bcp 0.1.9 → 0.1.11
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/CHANGELOG.md +83 -1
- package/README.md +263 -8
- package/docs/form-actions.md +314 -0
- package/docs/releasing.md +34 -19
- package/docs/route-guards.md +240 -0
- package/docs/updating.md +130 -0
- package/package.json +1 -1
- package/packages/bundler/src/server-production-actions.ts +523 -0
- package/packages/bundler/src/server-production-guards.ts +497 -0
- package/packages/bundler/src/server-production-middleware.ts +50 -8
- package/packages/cli/src/args.ts +58 -0
- package/packages/cli/src/index.ts +41 -13
- package/packages/cli/src/update.ts +860 -0
- package/packages/client/src/form.tsx +548 -0
- package/packages/client/src/index.tsx +11 -0
- package/packages/client/src/loader-data.tsx +171 -41
- package/packages/client/src/server.ts +6 -0
- package/packages/server/src/form-action-dev-proxy.ts +601 -0
- package/packages/server/src/form-action-transport.ts +271 -0
- package/packages/server/src/form-action.ts +493 -0
- package/packages/server/src/middleware-dev-server.ts +56 -2
- package/packages/server/src/page-guard.ts +529 -0
- package/packages/server/src/page-loader.ts +317 -20
- package/packages/server/src/standalone-production-runtime-v2-action.ts +765 -0
- package/packages/server/src/standalone-production-runtime-v2-guard.ts +815 -0
- package/packages/server/src/standalone-production-runtime-v3.ts +1 -1
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
fileURLToPath,
|
|
5
|
+
} from "node:url";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
build,
|
|
9
|
+
} from "esbuild";
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
createServerEnvironmentDefines,
|
|
13
|
+
} from "../../env/src/index.js";
|
|
14
|
+
|
|
15
|
+
import type {
|
|
16
|
+
Route,
|
|
17
|
+
} from "../../router/src/index.js";
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
findPageGuardFiles,
|
|
21
|
+
} from "../../server/src/page-guard.js";
|
|
22
|
+
|
|
23
|
+
export async function buildProductionGuards(
|
|
24
|
+
pageRoutes: Route[],
|
|
25
|
+
rootDirectory: string,
|
|
26
|
+
serverDirectory: string
|
|
27
|
+
): Promise<void> {
|
|
28
|
+
const outputFile =
|
|
29
|
+
path.join(
|
|
30
|
+
serverDirectory,
|
|
31
|
+
"guards.mjs"
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
fs.rmSync(
|
|
35
|
+
outputFile,
|
|
36
|
+
{
|
|
37
|
+
force: true,
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const appDirectory =
|
|
42
|
+
path.join(
|
|
43
|
+
rootDirectory,
|
|
44
|
+
"app"
|
|
45
|
+
);
|
|
46
|
+
const guardedRoutes =
|
|
47
|
+
pageRoutes
|
|
48
|
+
.map(
|
|
49
|
+
(route) => ({
|
|
50
|
+
route,
|
|
51
|
+
guardFiles:
|
|
52
|
+
findPageGuardFiles(
|
|
53
|
+
appDirectory,
|
|
54
|
+
route.filePath
|
|
55
|
+
),
|
|
56
|
+
})
|
|
57
|
+
)
|
|
58
|
+
.filter(
|
|
59
|
+
(entry) =>
|
|
60
|
+
entry.guardFiles.length > 0
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (
|
|
64
|
+
guardedRoutes.length ===
|
|
65
|
+
0
|
|
66
|
+
) {
|
|
67
|
+
console.log(
|
|
68
|
+
"[BCP Build] Guards: none"
|
|
69
|
+
);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const entryDirectory =
|
|
74
|
+
path.join(
|
|
75
|
+
rootDirectory,
|
|
76
|
+
".bcp-framework",
|
|
77
|
+
"build",
|
|
78
|
+
".guard-entry"
|
|
79
|
+
);
|
|
80
|
+
const entryFile =
|
|
81
|
+
path.join(
|
|
82
|
+
entryDirectory,
|
|
83
|
+
"guards-entry.mjs"
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
fs.rmSync(
|
|
87
|
+
entryDirectory,
|
|
88
|
+
{
|
|
89
|
+
recursive: true,
|
|
90
|
+
force: true,
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
fs.mkdirSync(
|
|
94
|
+
entryDirectory,
|
|
95
|
+
{
|
|
96
|
+
recursive: true,
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
fs.writeFileSync(
|
|
101
|
+
entryFile,
|
|
102
|
+
createGuardEntry(
|
|
103
|
+
guardedRoutes,
|
|
104
|
+
rootDirectory,
|
|
105
|
+
entryDirectory
|
|
106
|
+
),
|
|
107
|
+
"utf8"
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const frameworkDirectory =
|
|
111
|
+
path.dirname(
|
|
112
|
+
fileURLToPath(
|
|
113
|
+
import.meta.url
|
|
114
|
+
)
|
|
115
|
+
);
|
|
116
|
+
const frameworkServerEntry =
|
|
117
|
+
path.resolve(
|
|
118
|
+
frameworkDirectory,
|
|
119
|
+
"../../client/src/server.ts"
|
|
120
|
+
);
|
|
121
|
+
const frameworkServerOnlyEntry =
|
|
122
|
+
path.resolve(
|
|
123
|
+
frameworkDirectory,
|
|
124
|
+
"../../client/src/server-only.mjs"
|
|
125
|
+
);
|
|
126
|
+
const frameworkCacheEntry =
|
|
127
|
+
path.resolve(
|
|
128
|
+
frameworkDirectory,
|
|
129
|
+
"../../cache/src/index.ts"
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
await build({
|
|
134
|
+
absWorkingDir:
|
|
135
|
+
rootDirectory,
|
|
136
|
+
entryPoints: [
|
|
137
|
+
entryFile,
|
|
138
|
+
],
|
|
139
|
+
outfile:
|
|
140
|
+
outputFile,
|
|
141
|
+
bundle:
|
|
142
|
+
true,
|
|
143
|
+
platform:
|
|
144
|
+
"node",
|
|
145
|
+
format:
|
|
146
|
+
"esm",
|
|
147
|
+
target: [
|
|
148
|
+
"node24",
|
|
149
|
+
],
|
|
150
|
+
minify:
|
|
151
|
+
process.env
|
|
152
|
+
.BCP_BUILD_MINIFY !==
|
|
153
|
+
"0",
|
|
154
|
+
sourcemap:
|
|
155
|
+
process.env
|
|
156
|
+
.BCP_BUILD_SOURCE_MAPS ===
|
|
157
|
+
"1",
|
|
158
|
+
treeShaking:
|
|
159
|
+
true,
|
|
160
|
+
packages:
|
|
161
|
+
"external",
|
|
162
|
+
plugins: [
|
|
163
|
+
{
|
|
164
|
+
name:
|
|
165
|
+
"bcp-guard-runtime",
|
|
166
|
+
setup(buildApi) {
|
|
167
|
+
buildApi.onResolve(
|
|
168
|
+
{
|
|
169
|
+
filter:
|
|
170
|
+
/^bcp\/server$/,
|
|
171
|
+
},
|
|
172
|
+
() => ({
|
|
173
|
+
path:
|
|
174
|
+
frameworkServerEntry,
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
buildApi.onResolve(
|
|
178
|
+
{
|
|
179
|
+
filter:
|
|
180
|
+
/^bcp\/server-only$/,
|
|
181
|
+
},
|
|
182
|
+
() => ({
|
|
183
|
+
path:
|
|
184
|
+
frameworkServerOnlyEntry,
|
|
185
|
+
})
|
|
186
|
+
);
|
|
187
|
+
buildApi.onResolve(
|
|
188
|
+
{
|
|
189
|
+
filter:
|
|
190
|
+
/^bcp\/cache$/,
|
|
191
|
+
},
|
|
192
|
+
() => ({
|
|
193
|
+
path:
|
|
194
|
+
frameworkCacheEntry,
|
|
195
|
+
})
|
|
196
|
+
);
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
define:
|
|
201
|
+
createServerEnvironmentDefines(
|
|
202
|
+
"production"
|
|
203
|
+
),
|
|
204
|
+
legalComments:
|
|
205
|
+
"none",
|
|
206
|
+
logLevel:
|
|
207
|
+
"silent",
|
|
208
|
+
});
|
|
209
|
+
} finally {
|
|
210
|
+
fs.rmSync(
|
|
211
|
+
entryDirectory,
|
|
212
|
+
{
|
|
213
|
+
recursive: true,
|
|
214
|
+
force: true,
|
|
215
|
+
}
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.log(
|
|
220
|
+
`[BCP Build] Guards: ${guardedRoutes.length} protected route(s) -> ${path.relative(rootDirectory, outputFile).replace(/\\/g, "/")}`
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function createGuardEntry(
|
|
225
|
+
guardedRoutes: Array<{
|
|
226
|
+
route: Route;
|
|
227
|
+
guardFiles: string[];
|
|
228
|
+
}>,
|
|
229
|
+
rootDirectory: string,
|
|
230
|
+
entryDirectory: string
|
|
231
|
+
): string {
|
|
232
|
+
const frameworkDirectory =
|
|
233
|
+
path.dirname(
|
|
234
|
+
fileURLToPath(
|
|
235
|
+
import.meta.url
|
|
236
|
+
)
|
|
237
|
+
);
|
|
238
|
+
const pageGuardRuntime =
|
|
239
|
+
path.resolve(
|
|
240
|
+
frameworkDirectory,
|
|
241
|
+
"../../server/src/page-guard.ts"
|
|
242
|
+
);
|
|
243
|
+
const requestContextRuntime =
|
|
244
|
+
path.resolve(
|
|
245
|
+
frameworkDirectory,
|
|
246
|
+
"../../server/src/request-context.ts"
|
|
247
|
+
);
|
|
248
|
+
const routerRuntime =
|
|
249
|
+
path.resolve(
|
|
250
|
+
frameworkDirectory,
|
|
251
|
+
"../../router/src/index.ts"
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const imports: string[] = [
|
|
255
|
+
`import { executePageGuardFunctions } from ${JSON.stringify(
|
|
256
|
+
toImportSpecifier(
|
|
257
|
+
entryDirectory,
|
|
258
|
+
pageGuardRuntime
|
|
259
|
+
)
|
|
260
|
+
)};`,
|
|
261
|
+
`import { applyResponseCookies, runWithRequestContext } from ${JSON.stringify(
|
|
262
|
+
toImportSpecifier(
|
|
263
|
+
entryDirectory,
|
|
264
|
+
requestContextRuntime
|
|
265
|
+
)
|
|
266
|
+
)};`,
|
|
267
|
+
`import { matchRoute } from ${JSON.stringify(
|
|
268
|
+
toImportSpecifier(
|
|
269
|
+
entryDirectory,
|
|
270
|
+
routerRuntime
|
|
271
|
+
)
|
|
272
|
+
)};`,
|
|
273
|
+
];
|
|
274
|
+
const guardNameByFile =
|
|
275
|
+
new Map<string, string>();
|
|
276
|
+
let guardIndex =
|
|
277
|
+
0;
|
|
278
|
+
|
|
279
|
+
for (const entry of guardedRoutes) {
|
|
280
|
+
for (const guardFile of entry.guardFiles) {
|
|
281
|
+
if (
|
|
282
|
+
guardNameByFile.has(
|
|
283
|
+
guardFile
|
|
284
|
+
)
|
|
285
|
+
) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const guardName =
|
|
290
|
+
`Guard${guardIndex++}`;
|
|
291
|
+
guardNameByFile.set(
|
|
292
|
+
guardFile,
|
|
293
|
+
guardName
|
|
294
|
+
);
|
|
295
|
+
imports.push(
|
|
296
|
+
`import { guard as ${guardName} } from ${JSON.stringify(
|
|
297
|
+
toImportSpecifier(
|
|
298
|
+
entryDirectory,
|
|
299
|
+
guardFile
|
|
300
|
+
)
|
|
301
|
+
)};`
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const definitions =
|
|
307
|
+
guardedRoutes.map(
|
|
308
|
+
({
|
|
309
|
+
route,
|
|
310
|
+
guardFiles,
|
|
311
|
+
}) => {
|
|
312
|
+
const guards =
|
|
313
|
+
guardFiles.map(
|
|
314
|
+
(guardFile) => {
|
|
315
|
+
const guardName =
|
|
316
|
+
guardNameByFile.get(
|
|
317
|
+
guardFile
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
if (!guardName) {
|
|
321
|
+
throw new Error(
|
|
322
|
+
`BCP Framework: guard import was not generated for "${guardFile}".`
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const label =
|
|
327
|
+
path.relative(
|
|
328
|
+
rootDirectory,
|
|
329
|
+
guardFile
|
|
330
|
+
)
|
|
331
|
+
.replace(
|
|
332
|
+
/\\/g,
|
|
333
|
+
"/"
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
return `{
|
|
337
|
+
filePath: ${JSON.stringify(label)},
|
|
338
|
+
guard: ${guardName}
|
|
339
|
+
}`;
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
return `{
|
|
344
|
+
pathname: ${JSON.stringify(route.pathname)},
|
|
345
|
+
segments: ${JSON.stringify(route.segments)},
|
|
346
|
+
guards: [${guards.join(", ")}]
|
|
347
|
+
}`;
|
|
348
|
+
}
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
return `${imports.join("\n")}
|
|
352
|
+
|
|
353
|
+
const definitions = [
|
|
354
|
+
${definitions.join(",\n ")}
|
|
355
|
+
];
|
|
356
|
+
|
|
357
|
+
const routePatterns =
|
|
358
|
+
definitions.map(
|
|
359
|
+
(definition) => ({
|
|
360
|
+
pathname:
|
|
361
|
+
definition.pathname,
|
|
362
|
+
segments:
|
|
363
|
+
definition.segments,
|
|
364
|
+
filePath:
|
|
365
|
+
definition.pathname,
|
|
366
|
+
layouts: []
|
|
367
|
+
})
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
const definitionByPathname =
|
|
371
|
+
new Map(
|
|
372
|
+
definitions.map(
|
|
373
|
+
(definition) => [
|
|
374
|
+
definition.pathname,
|
|
375
|
+
definition
|
|
376
|
+
]
|
|
377
|
+
)
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
export const guardedPathnames =
|
|
381
|
+
definitions.map(
|
|
382
|
+
(definition) =>
|
|
383
|
+
definition.pathname
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
export async function evaluateRouteGuards(input) {
|
|
387
|
+
const target =
|
|
388
|
+
new URL(
|
|
389
|
+
input.url
|
|
390
|
+
);
|
|
391
|
+
const match =
|
|
392
|
+
matchRoute(
|
|
393
|
+
routePatterns,
|
|
394
|
+
target.pathname
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
if (!match) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const definition =
|
|
402
|
+
definitionByPathname.get(
|
|
403
|
+
match.route.pathname
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
if (!definition) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const request =
|
|
411
|
+
new Request(
|
|
412
|
+
target,
|
|
413
|
+
{
|
|
414
|
+
method:
|
|
415
|
+
input.method ||
|
|
416
|
+
"GET",
|
|
417
|
+
headers:
|
|
418
|
+
new Headers(
|
|
419
|
+
input.headers ||
|
|
420
|
+
[]
|
|
421
|
+
)
|
|
422
|
+
}
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
return runWithRequestContext(
|
|
426
|
+
request,
|
|
427
|
+
async () => {
|
|
428
|
+
const execution =
|
|
429
|
+
await executePageGuardFunctions(
|
|
430
|
+
definition.guards,
|
|
431
|
+
match.params,
|
|
432
|
+
target
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
if (execution.response) {
|
|
436
|
+
return {
|
|
437
|
+
kind:
|
|
438
|
+
"response",
|
|
439
|
+
response:
|
|
440
|
+
applyResponseCookies(
|
|
441
|
+
execution.response
|
|
442
|
+
)
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const cookieCarrier =
|
|
447
|
+
applyResponseCookies(
|
|
448
|
+
new Response(
|
|
449
|
+
null,
|
|
450
|
+
{
|
|
451
|
+
status: 204
|
|
452
|
+
}
|
|
453
|
+
)
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
return {
|
|
457
|
+
kind:
|
|
458
|
+
"allow",
|
|
459
|
+
data:
|
|
460
|
+
execution.data,
|
|
461
|
+
setCookies:
|
|
462
|
+
cookieCarrier.headers.getSetCookie()
|
|
463
|
+
};
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
remoteAddress:
|
|
467
|
+
input.remoteAddress ||
|
|
468
|
+
null
|
|
469
|
+
}
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
`;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function toImportSpecifier(
|
|
476
|
+
fromDirectory: string,
|
|
477
|
+
filePath: string
|
|
478
|
+
): string {
|
|
479
|
+
let relative =
|
|
480
|
+
path.relative(
|
|
481
|
+
fromDirectory,
|
|
482
|
+
filePath
|
|
483
|
+
)
|
|
484
|
+
.replace(
|
|
485
|
+
/\\/g,
|
|
486
|
+
"/"
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
if (
|
|
490
|
+
!relative.startsWith(".")
|
|
491
|
+
) {
|
|
492
|
+
relative =
|
|
493
|
+
`./${relative}`;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return relative;
|
|
497
|
+
}
|
|
@@ -12,10 +12,18 @@ import {
|
|
|
12
12
|
createServerEnvironmentDefines,
|
|
13
13
|
} from "../../env/src/index.js";
|
|
14
14
|
|
|
15
|
+
import {
|
|
16
|
+
routeHasPageActions,
|
|
17
|
+
} from "../../server/src/form-action.js";
|
|
18
|
+
|
|
15
19
|
import {
|
|
16
20
|
findProjectMiddlewareFile,
|
|
17
21
|
} from "../../server/src/middleware-loader.js";
|
|
18
22
|
|
|
23
|
+
import {
|
|
24
|
+
routeHasPageGuard,
|
|
25
|
+
} from "../../server/src/page-guard.js";
|
|
26
|
+
|
|
19
27
|
import type {
|
|
20
28
|
ApiRoute,
|
|
21
29
|
Route,
|
|
@@ -29,6 +37,14 @@ import type {
|
|
|
29
37
|
PartialHydrationBuildManifest,
|
|
30
38
|
} from "./partial-hydration.js";
|
|
31
39
|
|
|
40
|
+
import {
|
|
41
|
+
buildProductionActions,
|
|
42
|
+
} from "./server-production-actions.js";
|
|
43
|
+
|
|
44
|
+
import {
|
|
45
|
+
buildProductionGuards,
|
|
46
|
+
} from "./server-production-guards.js";
|
|
47
|
+
|
|
32
48
|
import {
|
|
33
49
|
buildProductionServer as buildBaseProductionServer,
|
|
34
50
|
type ProductionServerBuildResult,
|
|
@@ -73,7 +89,8 @@ export async function buildProductionServer(
|
|
|
73
89
|
writeCacheManifest(
|
|
74
90
|
pageRoutes,
|
|
75
91
|
apiRoutes,
|
|
76
|
-
serverDirectory
|
|
92
|
+
serverDirectory,
|
|
93
|
+
rootDirectory
|
|
77
94
|
);
|
|
78
95
|
|
|
79
96
|
await buildProductionMiddleware(
|
|
@@ -81,6 +98,18 @@ export async function buildProductionServer(
|
|
|
81
98
|
serverDirectory
|
|
82
99
|
);
|
|
83
100
|
|
|
101
|
+
await buildProductionGuards(
|
|
102
|
+
pageRoutes,
|
|
103
|
+
rootDirectory,
|
|
104
|
+
serverDirectory
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
await buildProductionActions(
|
|
108
|
+
pageRoutes,
|
|
109
|
+
rootDirectory,
|
|
110
|
+
serverDirectory
|
|
111
|
+
);
|
|
112
|
+
|
|
84
113
|
return {
|
|
85
114
|
...baseResult,
|
|
86
115
|
size:
|
|
@@ -174,11 +203,6 @@ async function bundleServerCacheRuntime(
|
|
|
174
203
|
serverFile
|
|
175
204
|
);
|
|
176
205
|
|
|
177
|
-
/*
|
|
178
|
-
* The base server build may have emitted an external map. The final
|
|
179
|
-
* cache-runtime rebundle uses an inline map so a stale server.mjs.map
|
|
180
|
-
* must not be shipped next to the rewritten bundle.
|
|
181
|
-
*/
|
|
182
206
|
fs.rmSync(
|
|
183
207
|
`${serverFile}.map`,
|
|
184
208
|
{
|
|
@@ -204,14 +228,32 @@ async function bundleServerCacheRuntime(
|
|
|
204
228
|
function writeCacheManifest(
|
|
205
229
|
pageRoutes: Route[],
|
|
206
230
|
apiRoutes: ApiRoute[],
|
|
207
|
-
serverDirectory: string
|
|
231
|
+
serverDirectory: string,
|
|
232
|
+
rootDirectory: string
|
|
208
233
|
): void {
|
|
234
|
+
const appDirectory =
|
|
235
|
+
path.join(
|
|
236
|
+
rootDirectory,
|
|
237
|
+
"app"
|
|
238
|
+
);
|
|
239
|
+
const cacheablePages =
|
|
240
|
+
pageRoutes.filter(
|
|
241
|
+
(route) =>
|
|
242
|
+
!routeHasPageGuard(
|
|
243
|
+
appDirectory,
|
|
244
|
+
route.filePath
|
|
245
|
+
) &&
|
|
246
|
+
!routeHasPageActions(
|
|
247
|
+
route.filePath
|
|
248
|
+
)
|
|
249
|
+
);
|
|
250
|
+
|
|
209
251
|
const manifest:
|
|
210
252
|
CacheManifest = {
|
|
211
253
|
version: 1,
|
|
212
254
|
pages:
|
|
213
255
|
collectCacheRoutes(
|
|
214
|
-
|
|
256
|
+
cacheablePages
|
|
215
257
|
),
|
|
216
258
|
apiRoutes:
|
|
217
259
|
collectCacheRoutes(
|
package/packages/cli/src/args.ts
CHANGED
|
@@ -6,6 +6,7 @@ export type CliCommand =
|
|
|
6
6
|
| "build"
|
|
7
7
|
| "start"
|
|
8
8
|
| "routes"
|
|
9
|
+
| "update"
|
|
9
10
|
| "help"
|
|
10
11
|
| "version";
|
|
11
12
|
|
|
@@ -17,6 +18,12 @@ export interface CliOptions {
|
|
|
17
18
|
port?: number;
|
|
18
19
|
|
|
19
20
|
hostname?: string;
|
|
21
|
+
|
|
22
|
+
updateTarget?: string;
|
|
23
|
+
|
|
24
|
+
updateCheck?: boolean;
|
|
25
|
+
|
|
26
|
+
updateDryRun?: boolean;
|
|
20
27
|
}
|
|
21
28
|
|
|
22
29
|
export function parseCliArgs(
|
|
@@ -33,6 +40,15 @@ export function parseCliArgs(
|
|
|
33
40
|
let hostname:
|
|
34
41
|
string | undefined;
|
|
35
42
|
|
|
43
|
+
let updateTarget:
|
|
44
|
+
string | undefined;
|
|
45
|
+
|
|
46
|
+
let updateCheck =
|
|
47
|
+
false;
|
|
48
|
+
|
|
49
|
+
let updateDryRun =
|
|
50
|
+
false;
|
|
51
|
+
|
|
36
52
|
let commandSet = false;
|
|
37
53
|
|
|
38
54
|
for (
|
|
@@ -152,6 +168,22 @@ export function parseCliArgs(
|
|
|
152
168
|
continue;
|
|
153
169
|
}
|
|
154
170
|
|
|
171
|
+
if (
|
|
172
|
+
argument === "--check"
|
|
173
|
+
) {
|
|
174
|
+
updateCheck =
|
|
175
|
+
true;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (
|
|
180
|
+
argument === "--dry-run"
|
|
181
|
+
) {
|
|
182
|
+
updateDryRun =
|
|
183
|
+
true;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
155
187
|
if (
|
|
156
188
|
argument.startsWith("-")
|
|
157
189
|
) {
|
|
@@ -179,6 +211,16 @@ export function parseCliArgs(
|
|
|
179
211
|
continue;
|
|
180
212
|
}
|
|
181
213
|
|
|
214
|
+
if (
|
|
215
|
+
commandSet &&
|
|
216
|
+
command === "update" &&
|
|
217
|
+
updateTarget === undefined
|
|
218
|
+
) {
|
|
219
|
+
updateTarget =
|
|
220
|
+
argument;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
182
224
|
if (commandSet) {
|
|
183
225
|
throw new Error(
|
|
184
226
|
`Unexpected argument: ${argument}`
|
|
@@ -190,6 +232,7 @@ export function parseCliArgs(
|
|
|
190
232
|
argument === "build" ||
|
|
191
233
|
argument === "start" ||
|
|
192
234
|
argument === "routes" ||
|
|
235
|
+
argument === "update" ||
|
|
193
236
|
argument === "help" ||
|
|
194
237
|
argument === "version"
|
|
195
238
|
) {
|
|
@@ -203,11 +246,26 @@ export function parseCliArgs(
|
|
|
203
246
|
);
|
|
204
247
|
}
|
|
205
248
|
|
|
249
|
+
if (
|
|
250
|
+
command !== "update" &&
|
|
251
|
+
(
|
|
252
|
+
updateCheck ||
|
|
253
|
+
updateDryRun
|
|
254
|
+
)
|
|
255
|
+
) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
"Options --check and --dry-run are only valid with `bcp update`."
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
206
261
|
return {
|
|
207
262
|
command,
|
|
208
263
|
rootDirectory,
|
|
209
264
|
port,
|
|
210
265
|
hostname,
|
|
266
|
+
updateTarget,
|
|
267
|
+
updateCheck,
|
|
268
|
+
updateDryRun,
|
|
211
269
|
};
|
|
212
270
|
}
|
|
213
271
|
|