@bleedingdev/modern-js-app-tools 3.5.0-ultramodern.3 → 3.5.0-ultramodern.30
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/dist/cjs/builder/generator/getBuilderEnvironments.js +1 -0
- package/dist/cjs/index.js +50 -44
- package/dist/cjs/plugins/backendFederationBuild.js +347 -0
- package/dist/cjs/plugins/deploy/platforms/cloudflare-output-contract.js +91 -0
- package/dist/cjs/plugins/deploy/platforms/cloudflare-output-plan.js +93 -0
- package/dist/cjs/plugins/deploy/platforms/cloudflare-output-verifier.js +402 -0
- package/dist/cjs/plugins/deploy/platforms/cloudflare.js +272 -29
- package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-entry.mjs +346 -43
- package/dist/esm/builder/generator/getBuilderEnvironments.mjs +1 -0
- package/dist/esm/index.mjs +2 -0
- package/dist/esm/plugins/backendFederationBuild.mjs +296 -0
- package/dist/esm/plugins/deploy/platforms/cloudflare-output-contract.mjs +17 -0
- package/dist/esm/plugins/deploy/platforms/cloudflare-output-plan.mjs +45 -0
- package/dist/esm/plugins/deploy/platforms/cloudflare-output-verifier.mjs +347 -0
- package/dist/esm/plugins/deploy/platforms/cloudflare.mjs +272 -29
- package/dist/esm/plugins/deploy/platforms/templates/cloudflare-entry.mjs +346 -43
- package/dist/esm-node/builder/generator/getBuilderEnvironments.mjs +1 -0
- package/dist/esm-node/index.mjs +2 -0
- package/dist/esm-node/plugins/backendFederationBuild.mjs +297 -0
- package/dist/esm-node/plugins/deploy/platforms/cloudflare-output-contract.mjs +18 -0
- package/dist/esm-node/plugins/deploy/platforms/cloudflare-output-plan.mjs +46 -0
- package/dist/esm-node/plugins/deploy/platforms/cloudflare-output-verifier.mjs +348 -0
- package/dist/esm-node/plugins/deploy/platforms/cloudflare.mjs +272 -29
- package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-entry.mjs +346 -43
- package/dist/types/plugins/backendFederationBuild.d.ts +11 -0
- package/dist/types/plugins/deploy/platforms/cloudflare-output-contract.d.ts +13 -0
- package/dist/types/plugins/deploy/platforms/cloudflare-output-plan.d.ts +33 -0
- package/dist/types/plugins/deploy/platforms/cloudflare-output-verifier.d.ts +32 -0
- package/dist/types/types/config/cloudflareDeploy.d.ts +22 -0
- package/dist/types/types/config/deploy.d.ts +15 -2
- package/lib/types.d.ts +2 -3
- package/package.json +17 -11
|
@@ -43,17 +43,19 @@ const external_node_path_namespaceObject = require("node:path");
|
|
|
43
43
|
var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
|
|
44
44
|
const utils_namespaceObject = require("@modern-js/utils");
|
|
45
45
|
const index_js_namespaceObject = require("../utils/index.js");
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const
|
|
46
|
+
const external_cloudflare_output_contract_js_namespaceObject = require("./cloudflare-output-contract.js");
|
|
47
|
+
const external_cloudflare_output_plan_js_namespaceObject = require("./cloudflare-output-plan.js");
|
|
48
|
+
const external_cloudflare_output_verifier_js_namespaceObject = require("./cloudflare-output-verifier.js");
|
|
49
|
+
const WORKER_ENTRY = external_cloudflare_output_contract_js_namespaceObject.CLOUDFLARE_WORKER_ENTRY;
|
|
50
|
+
const WRANGLER_CONFIG_FILE = external_cloudflare_output_contract_js_namespaceObject.CLOUDFLARE_WRANGLER_CONFIG_FILE;
|
|
51
|
+
const OUTPUT_PACKAGE_FILE = external_cloudflare_output_contract_js_namespaceObject.CLOUDFLARE_OUTPUT_PACKAGE_FILE;
|
|
52
|
+
const ASSETS_BINDING = external_cloudflare_output_contract_js_namespaceObject.CLOUDFLARE_ASSETS_BINDING;
|
|
51
53
|
const ROUTE_SPEC_FILE = 'route.json';
|
|
52
54
|
const ROUTE_SPEC_OUTPUT = `server/${ROUTE_SPEC_FILE}`;
|
|
53
55
|
const LOADABLE_STATS_FILE = 'loadable-stats.json';
|
|
54
56
|
const ROUTE_MANIFEST_FILE = 'routes-manifest.json';
|
|
55
|
-
const PUBLIC_ASSETS_DIRECTORY =
|
|
56
|
-
const WORKER_BUNDLE_DIRECTORY =
|
|
57
|
+
const PUBLIC_ASSETS_DIRECTORY = external_cloudflare_output_contract_js_namespaceObject.CLOUDFLARE_PUBLIC_ASSETS_DIRECTORY;
|
|
58
|
+
const WORKER_BUNDLE_DIRECTORY = external_cloudflare_output_contract_js_namespaceObject.CLOUDFLARE_WORKER_BUNDLE_DIRECTORY;
|
|
57
59
|
const SERVER_BUNDLE_DIRECTORY = 'bundles';
|
|
58
60
|
const SERVER_OUTPUT_DIRECTORY = 'server';
|
|
59
61
|
const DEFAULT_SERVER_ONLY_PUBLIC_ASSET_EXCLUDES = [
|
|
@@ -64,10 +66,7 @@ const BFF_EFFECT_WORKER_ENTRY = `${WORKER_BUNDLE_DIRECTORY}/__modern_bff_effect.
|
|
|
64
66
|
const EFFECT_BFF_CLOUDFLARE_IMPORT_GUIDANCE = 'Ensure the Effect API entry exists at api/index.ts or bff.effect.entry, and import Cloudflare edge handlers from @modern-js/plugin-bff/effect-edge instead of lambda/Hono server helpers.';
|
|
65
67
|
const DEFAULT_COMPATIBILITY_DATE = '2026-06-02';
|
|
66
68
|
const COMPATIBILITY_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/u;
|
|
67
|
-
const REQUIRED_COMPATIBILITY_FLAGS =
|
|
68
|
-
'nodejs_compat',
|
|
69
|
-
'global_fetch_strictly_public'
|
|
70
|
-
];
|
|
69
|
+
const REQUIRED_COMPATIBILITY_FLAGS = external_cloudflare_output_contract_js_namespaceObject.CLOUDFLARE_REQUIRED_COMPATIBILITY_FLAGS;
|
|
71
70
|
const RESERVED_ARTIFACT_DESTINATION_FILES = new Set([
|
|
72
71
|
WRANGLER_CONFIG_FILE,
|
|
73
72
|
OUTPUT_PACKAGE_FILE
|
|
@@ -151,6 +150,102 @@ const DEFAULT_CSP_DIRECTIVES = {
|
|
|
151
150
|
'blob:'
|
|
152
151
|
]
|
|
153
152
|
};
|
|
153
|
+
const I18N_SERVER_PLUGIN_NAME = 'plugin-i18n/server';
|
|
154
|
+
const DEFAULT_I18NEXT_DETECTION_OPTIONS = {
|
|
155
|
+
order: [
|
|
156
|
+
'querystring',
|
|
157
|
+
'cookie',
|
|
158
|
+
'localStorage',
|
|
159
|
+
'header',
|
|
160
|
+
'navigator',
|
|
161
|
+
'htmlTag',
|
|
162
|
+
'path',
|
|
163
|
+
'subdomain'
|
|
164
|
+
],
|
|
165
|
+
lookupQuerystring: 'lng',
|
|
166
|
+
lookupCookie: 'i18next',
|
|
167
|
+
lookupHeader: 'accept-language'
|
|
168
|
+
};
|
|
169
|
+
const SERVER_SIDE_I18N_DETECTORS = new Set([
|
|
170
|
+
'querystring',
|
|
171
|
+
'cookie',
|
|
172
|
+
'header'
|
|
173
|
+
]);
|
|
174
|
+
const isRecord = (value)=>null !== value && 'object' == typeof value && !Array.isArray(value);
|
|
175
|
+
const toStringArray = (value)=>Array.isArray(value) ? value.filter((entry)=>'string' == typeof entry) : [];
|
|
176
|
+
const getI18nServerPlugin = (appContext)=>appContext.serverPlugins?.find((plugin)=>plugin.name.includes(I18N_SERVER_PLUGIN_NAME));
|
|
177
|
+
const removeLocaleDetectionByEntry = (config)=>{
|
|
178
|
+
const { localeDetectionByEntry: _localeDetectionByEntry, ...rest } = config;
|
|
179
|
+
return rest;
|
|
180
|
+
};
|
|
181
|
+
const getEntryLocaleDetection = (entryName, localeDetection)=>{
|
|
182
|
+
const byEntry = isRecord(localeDetection.localeDetectionByEntry) ? localeDetection.localeDetectionByEntry : void 0;
|
|
183
|
+
const entryConfig = byEntry?.[entryName];
|
|
184
|
+
const globalConfig = removeLocaleDetectionByEntry(localeDetection);
|
|
185
|
+
return isRecord(entryConfig) ? {
|
|
186
|
+
...globalConfig,
|
|
187
|
+
...entryConfig
|
|
188
|
+
} : globalConfig;
|
|
189
|
+
};
|
|
190
|
+
const normalizeI18nDetection = (detection)=>{
|
|
191
|
+
const configured = isRecord(detection) ? detection : {};
|
|
192
|
+
const rawOrder = Array.isArray(configured.order) ? configured.order : DEFAULT_I18NEXT_DETECTION_OPTIONS.order;
|
|
193
|
+
const order = rawOrder.filter((entry)=>'string' == typeof entry && SERVER_SIDE_I18N_DETECTORS.has(entry));
|
|
194
|
+
return {
|
|
195
|
+
order: order.length > 0 ? order : [
|
|
196
|
+
'querystring',
|
|
197
|
+
'cookie',
|
|
198
|
+
'header'
|
|
199
|
+
],
|
|
200
|
+
lookupQuerystring: 'string' == typeof configured.lookupQuerystring && configured.lookupQuerystring ? configured.lookupQuerystring : DEFAULT_I18NEXT_DETECTION_OPTIONS.lookupQuerystring,
|
|
201
|
+
lookupCookie: 'string' == typeof configured.lookupCookie && configured.lookupCookie ? configured.lookupCookie : DEFAULT_I18NEXT_DETECTION_OPTIONS.lookupCookie,
|
|
202
|
+
lookupHeader: 'string' == typeof configured.lookupHeader && configured.lookupHeader ? configured.lookupHeader : DEFAULT_I18NEXT_DETECTION_OPTIONS.lookupHeader
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
const normalizeLocalisedUrls = (localisedUrls)=>{
|
|
206
|
+
if (!isRecord(localisedUrls) || 0 === Object.keys(localisedUrls).length) return;
|
|
207
|
+
const normalized = {};
|
|
208
|
+
for (const [canonicalPath, languageMap] of Object.entries(localisedUrls)){
|
|
209
|
+
if (!isRecord(languageMap)) continue;
|
|
210
|
+
const normalizedLanguageMap = Object.fromEntries(Object.entries(languageMap).filter((entry)=>'string' == typeof entry[1] && entry[1].length > 0));
|
|
211
|
+
if (Object.keys(normalizedLanguageMap).length > 0) normalized[canonicalPath] = normalizedLanguageMap;
|
|
212
|
+
}
|
|
213
|
+
return Object.keys(normalized).length > 0 ? normalized : void 0;
|
|
214
|
+
};
|
|
215
|
+
const normalizeWorkerI18nEntry = (entryName, localeDetection, staticRoutePrefixes)=>{
|
|
216
|
+
const entryConfig = getEntryLocaleDetection(entryName, localeDetection);
|
|
217
|
+
const languages = toStringArray(entryConfig.languages);
|
|
218
|
+
if (true !== entryConfig.localePathRedirect || 0 === languages.length) return;
|
|
219
|
+
const fallbackLanguage = 'string' == typeof entryConfig.fallbackLanguage && entryConfig.fallbackLanguage ? entryConfig.fallbackLanguage : 'en';
|
|
220
|
+
const ignoreRedirectRoutes = Array.isArray(entryConfig.ignoreRedirectRoutes) ? toStringArray(entryConfig.ignoreRedirectRoutes) : [];
|
|
221
|
+
const localisedUrls = normalizeLocalisedUrls(entryConfig.localisedUrls);
|
|
222
|
+
return {
|
|
223
|
+
i18nextDetector: false !== entryConfig.i18nextDetector,
|
|
224
|
+
languages,
|
|
225
|
+
fallbackLanguage,
|
|
226
|
+
detection: normalizeI18nDetection(entryConfig.detection),
|
|
227
|
+
ignoreRedirectRoutes,
|
|
228
|
+
staticRoutePrefixes,
|
|
229
|
+
...localisedUrls ? {
|
|
230
|
+
localisedUrls
|
|
231
|
+
} : {}
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
const createI18nWorkerManifest = (routeSpec, appContext)=>{
|
|
235
|
+
const i18nServerPlugin = getI18nServerPlugin(appContext);
|
|
236
|
+
const localeDetection = i18nServerPlugin?.options?.localeDetection;
|
|
237
|
+
if (!isRecord(localeDetection)) return;
|
|
238
|
+
const staticRoutePrefixes = toStringArray(i18nServerPlugin?.options?.staticRoutePrefixes);
|
|
239
|
+
const entries = {};
|
|
240
|
+
for (const route of routeSpec.routes){
|
|
241
|
+
if ('string' != typeof route.entryName || entries[route.entryName]) continue;
|
|
242
|
+
const entry = normalizeWorkerI18nEntry(route.entryName, localeDetection, staticRoutePrefixes);
|
|
243
|
+
if (entry) entries[route.entryName] = entry;
|
|
244
|
+
}
|
|
245
|
+
return Object.keys(entries).length > 0 ? {
|
|
246
|
+
entries
|
|
247
|
+
} : void 0;
|
|
248
|
+
};
|
|
154
249
|
const getCompatibilityDate = (modernConfig)=>{
|
|
155
250
|
const configuredDate = modernConfig.deploy?.worker?.compatibilityDate?.trim();
|
|
156
251
|
const compatibilityDate = configuredDate || DEFAULT_COMPATIBILITY_DATE;
|
|
@@ -165,11 +260,12 @@ const getConfiguredWorkerName = (appDirectory, modernConfig)=>{
|
|
|
165
260
|
const configuredName = modernConfig.deploy?.worker?.name?.trim();
|
|
166
261
|
return configuredName || getWorkerName(appDirectory);
|
|
167
262
|
};
|
|
168
|
-
const normalizeRelativePath = (value, label, scope = 'app output')=>{
|
|
263
|
+
const normalizeRelativePath = (value, label, scope = 'app output', options = {})=>{
|
|
169
264
|
if ('string' != typeof value) throw new Error(`${label} must be a relative path inside the ${scope}.`);
|
|
170
265
|
const normalized = value.trim().replace(/\\/g, '/').replace(/^\.\/+/u, '').replace(/\/+$/u, '');
|
|
171
266
|
const segments = normalized.split('/');
|
|
172
|
-
|
|
267
|
+
const isRootDestination = '.' === normalized;
|
|
268
|
+
if (!normalized || external_node_path_default().isAbsolute(normalized) || !options.allowRoot && isRootDestination || segments.includes('..')) throw new Error(`${label} must be a relative path inside the ${scope}.`);
|
|
173
269
|
return normalized;
|
|
174
270
|
};
|
|
175
271
|
const normalizeDirectiveValues = (value)=>{
|
|
@@ -324,9 +420,48 @@ const createWranglerD1Databases = (modernConfig, configuredWranglerD1)=>{
|
|
|
324
420
|
if (!Array.isArray(d1Databases)) throw new Error('deploy.worker.d1Databases must be an array.');
|
|
325
421
|
return d1Databases.map(normalizeD1Database);
|
|
326
422
|
};
|
|
423
|
+
const normalizeServiceBinding = (service, index)=>{
|
|
424
|
+
const binding = assertNonEmptyString(service.binding, `deploy.worker.services[${index}].binding`);
|
|
425
|
+
const serviceName = assertNonEmptyString(service.service, `deploy.worker.services[${index}].service`);
|
|
426
|
+
const prefix = void 0 === service.prefix ? void 0 : assertNonEmptyString(service.prefix, `deploy.worker.services[${index}].prefix`);
|
|
427
|
+
return {
|
|
428
|
+
binding,
|
|
429
|
+
service: serviceName,
|
|
430
|
+
...void 0 === prefix ? {} : {
|
|
431
|
+
prefix
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
};
|
|
435
|
+
const createWorkerServiceBindings = (modernConfig, configuredWranglerServices)=>{
|
|
436
|
+
const services = modernConfig.deploy?.worker?.services;
|
|
437
|
+
if (void 0 === services) return configuredWranglerServices;
|
|
438
|
+
if (void 0 !== configuredWranglerServices) throw new Error('Use deploy.worker.services or deploy.worker.wrangler.services, not both.');
|
|
439
|
+
if (!Array.isArray(services)) throw new Error('deploy.worker.services must be an array.');
|
|
440
|
+
return services.map(normalizeServiceBinding);
|
|
441
|
+
};
|
|
442
|
+
const createWranglerServices = (serviceBindings)=>{
|
|
443
|
+
if (!Array.isArray(serviceBindings)) return serviceBindings;
|
|
444
|
+
if (!serviceBindings.every(isJsonRecord)) return serviceBindings;
|
|
445
|
+
return serviceBindings.map((service)=>{
|
|
446
|
+
const { prefix, ...wranglerService } = service;
|
|
447
|
+
return wranglerService;
|
|
448
|
+
});
|
|
449
|
+
};
|
|
450
|
+
const createWorkerManifestServiceBindings = (serviceBindings)=>{
|
|
451
|
+
if (!Array.isArray(serviceBindings)) return;
|
|
452
|
+
const dispatchBindings = serviceBindings.filter((service)=>isJsonRecord(service) && 'string' == typeof service.binding && 'string' == typeof service.service && 'string' == typeof service.prefix).map((service)=>({
|
|
453
|
+
binding: service.binding,
|
|
454
|
+
service: service.service,
|
|
455
|
+
prefix: service.prefix,
|
|
456
|
+
interface: 'fetch'
|
|
457
|
+
}));
|
|
458
|
+
return dispatchBindings.length > 0 ? dispatchBindings : void 0;
|
|
459
|
+
};
|
|
327
460
|
const createWranglerConfig = (appDirectory, modernConfig)=>{
|
|
328
461
|
const wrangler = getConfiguredWrangler(modernConfig);
|
|
329
462
|
const d1Databases = createWranglerD1Databases(modernConfig, wrangler.d1_databases);
|
|
463
|
+
const serviceBindings = createWorkerServiceBindings(modernConfig, wrangler.services);
|
|
464
|
+
const wranglerServices = createWranglerServices(serviceBindings);
|
|
330
465
|
return {
|
|
331
466
|
$schema: 'node_modules/wrangler/config-schema.json',
|
|
332
467
|
name: getConfiguredWorkerName(appDirectory, modernConfig),
|
|
@@ -337,6 +472,9 @@ const createWranglerConfig = (appDirectory, modernConfig)=>{
|
|
|
337
472
|
assets: createWranglerAssetsConfig(wrangler.assets),
|
|
338
473
|
...void 0 === d1Databases ? {} : {
|
|
339
474
|
d1_databases: d1Databases
|
|
475
|
+
},
|
|
476
|
+
...void 0 === wranglerServices ? {} : {
|
|
477
|
+
services: wranglerServices
|
|
340
478
|
}
|
|
341
479
|
};
|
|
342
480
|
};
|
|
@@ -353,6 +491,18 @@ const normalizeCloudflareArtifact = (artifact, index)=>{
|
|
|
353
491
|
};
|
|
354
492
|
};
|
|
355
493
|
const getCloudflareArtifacts = (modernConfig)=>(modernConfig.deploy?.worker?.artifacts ?? []).map(normalizeCloudflareArtifact);
|
|
494
|
+
const normalizeCloudflarePublicAsset = (asset, index)=>{
|
|
495
|
+
const from = normalizeRelativePath(asset.from, `deploy.worker.publicAssets[${index}].from`, 'app root');
|
|
496
|
+
const to = normalizeRelativePath(asset.to, `deploy.worker.publicAssets[${index}].to`, 'Cloudflare public output', {
|
|
497
|
+
allowRoot: true
|
|
498
|
+
});
|
|
499
|
+
return {
|
|
500
|
+
from,
|
|
501
|
+
to,
|
|
502
|
+
index
|
|
503
|
+
};
|
|
504
|
+
};
|
|
505
|
+
const getCloudflarePublicAssets = (modernConfig)=>(modernConfig.deploy?.worker?.publicAssets ?? []).map(normalizeCloudflarePublicAsset);
|
|
356
506
|
const copyCloudflareArtifacts = async (appDirectory, outputDirectory, artifacts)=>{
|
|
357
507
|
for (const artifact of artifacts){
|
|
358
508
|
const sourcePath = external_node_path_default().join(appDirectory, artifact.from);
|
|
@@ -360,6 +510,13 @@ const copyCloudflareArtifacts = async (appDirectory, outputDirectory, artifacts)
|
|
|
360
510
|
await utils_namespaceObject.fs.copy(sourcePath, external_node_path_default().join(outputDirectory, artifact.to));
|
|
361
511
|
}
|
|
362
512
|
};
|
|
513
|
+
const copyCloudflarePublicAssets = async (appDirectory, publicDirectory, publicAssets)=>{
|
|
514
|
+
for (const asset of publicAssets){
|
|
515
|
+
const sourcePath = external_node_path_default().join(appDirectory, asset.from);
|
|
516
|
+
if (!await utils_namespaceObject.fs.pathExists(sourcePath)) throw new Error(`deploy.worker.publicAssets[${asset.index}].from does not exist: ${asset.from}`);
|
|
517
|
+
await utils_namespaceObject.fs.copy(sourcePath, external_node_path_default().join(publicDirectory, asset.to));
|
|
518
|
+
}
|
|
519
|
+
};
|
|
363
520
|
const copyCloudflareD1Migrations = async (appDirectory, outputDirectory, modernConfig)=>{
|
|
364
521
|
for (const [index, database] of (modernConfig.deploy?.worker?.d1Databases ?? []).entries()){
|
|
365
522
|
if (!database.migrationsDir) continue;
|
|
@@ -380,8 +537,79 @@ const readRouteSpec = async (outputDirectory)=>{
|
|
|
380
537
|
routes: Array.isArray(routeSpec.routes) ? routeSpec.routes : []
|
|
381
538
|
};
|
|
382
539
|
};
|
|
540
|
+
const COMPACT_CONFIG_PATH = '.modernjs/ultramodern.json';
|
|
541
|
+
const ULTRAMODERN_BUILD_MODULE = 'shared/ultramodern-build.ts';
|
|
542
|
+
const nonEmptyString = (value)=>'string' == typeof value && value.length > 0 ? value : void 0;
|
|
543
|
+
const toDeliveryUnitIdentity = (value)=>{
|
|
544
|
+
if (!isRecord(value)) return;
|
|
545
|
+
const unitId = nonEmptyString(value.unitId);
|
|
546
|
+
const buildMarker = nonEmptyString(value.buildMarker);
|
|
547
|
+
const sourceRevision = nonEmptyString(value.sourceRevision);
|
|
548
|
+
if (!unitId || !buildMarker || !sourceRevision) return;
|
|
549
|
+
return {
|
|
550
|
+
unitId,
|
|
551
|
+
buildMarker,
|
|
552
|
+
sourceRevision
|
|
553
|
+
};
|
|
554
|
+
};
|
|
555
|
+
const findWorkspaceRoot = async (appDirectory)=>{
|
|
556
|
+
let current = external_node_path_default().resolve(appDirectory);
|
|
557
|
+
for(;;){
|
|
558
|
+
if (await utils_namespaceObject.fs.pathExists(external_node_path_default().join(current, COMPACT_CONFIG_PATH))) return current;
|
|
559
|
+
const parent = external_node_path_default().dirname(current);
|
|
560
|
+
if (parent === current) return;
|
|
561
|
+
current = parent;
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
const resolveTopologyDeliveryUnit = async (appDirectory)=>{
|
|
565
|
+
const workspaceRoot = await findWorkspaceRoot(appDirectory);
|
|
566
|
+
if (!workspaceRoot) return;
|
|
567
|
+
let compactConfig;
|
|
568
|
+
try {
|
|
569
|
+
compactConfig = await utils_namespaceObject.fs.readJSON(external_node_path_default().join(workspaceRoot, COMPACT_CONFIG_PATH));
|
|
570
|
+
} catch {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (!isRecord(compactConfig)) return;
|
|
574
|
+
const topology = isRecord(compactConfig.topology) ? compactConfig.topology : void 0;
|
|
575
|
+
const apps = Array.isArray(topology?.apps) ? topology.apps : [];
|
|
576
|
+
const resolvedAppDirectory = external_node_path_default().resolve(appDirectory);
|
|
577
|
+
for (const app of apps){
|
|
578
|
+
if (!isRecord(app)) continue;
|
|
579
|
+
const appPath = nonEmptyString(app.path);
|
|
580
|
+
if (appPath && external_node_path_default().resolve(workspaceRoot, appPath.replace(/^\.\/+/u, '')) === resolvedAppDirectory) return toDeliveryUnitIdentity(app.deliveryUnit);
|
|
581
|
+
}
|
|
582
|
+
return toDeliveryUnitIdentity(compactConfig.deliveryUnit);
|
|
583
|
+
};
|
|
584
|
+
const resolveWorkerDeliveryUnitStamp = async (appDirectory)=>{
|
|
585
|
+
const buildModulePath = external_node_path_default().join(appDirectory, ULTRAMODERN_BUILD_MODULE);
|
|
586
|
+
if (!await utils_namespaceObject.fs.pathExists(buildModulePath)) return;
|
|
587
|
+
const source = await utils_namespaceObject.fs.readFile(buildModulePath, 'utf8');
|
|
588
|
+
const buildMarker = source.match(/\bbuild:\s*['"]([^'"]+)['"]/u)?.[1];
|
|
589
|
+
const unitId = source.match(/\bunitId:\s*['"]([^'"]+)['"]/u)?.[1];
|
|
590
|
+
const sourceRevision = source.match(/\bsourceRevision:\s*['"]([^'"]+)['"]/u)?.[1];
|
|
591
|
+
if (!buildMarker || !unitId || !sourceRevision) return;
|
|
592
|
+
const identity = {
|
|
593
|
+
unitId,
|
|
594
|
+
buildMarker,
|
|
595
|
+
sourceRevision
|
|
596
|
+
};
|
|
597
|
+
return {
|
|
598
|
+
...identity,
|
|
599
|
+
surfaces: {
|
|
600
|
+
ui: {
|
|
601
|
+
...identity,
|
|
602
|
+
surface: 'ui'
|
|
603
|
+
},
|
|
604
|
+
api: {
|
|
605
|
+
...identity,
|
|
606
|
+
surface: 'api'
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
};
|
|
383
611
|
const createMissingEffectBffWorkerError = (outputDirectory, worker)=>new Error(`Cloudflare Effect API runtime is configured, but the BFF worker bundle is missing: ${external_node_path_default().join(outputDirectory, worker)}. ${EFFECT_BFF_CLOUDFLARE_IMPORT_GUIDANCE}`);
|
|
384
|
-
const createWorkerManifest = async (outputDirectory, modernConfig)=>{
|
|
612
|
+
const createWorkerManifest = async (outputDirectory, modernConfig, appContext, deliveryUnitStamp)=>{
|
|
385
613
|
const routeSpec = await readRouteSpec(outputDirectory);
|
|
386
614
|
const routes = await Promise.all(routeSpec.routes.map(async (route)=>{
|
|
387
615
|
const worker = 'string' == typeof route.worker ? route.worker : void 0;
|
|
@@ -398,11 +626,12 @@ const createWorkerManifest = async (outputDirectory, modernConfig)=>{
|
|
|
398
626
|
const primaryBffPrefix = Array.isArray(bffPrefix) ? bffPrefix[0] : bffPrefix;
|
|
399
627
|
const isEffectApi = Boolean(modernConfig.bff) && modernConfig.bff?.runtimeFramework !== 'hono';
|
|
400
628
|
const effectApiWorkerExists = await utils_namespaceObject.fs.pathExists(external_node_path_default().join(outputDirectory, BFF_EFFECT_WORKER_ENTRY));
|
|
629
|
+
const serviceBindings = createWorkerManifestServiceBindings(createWorkerServiceBindings(modernConfig, void 0));
|
|
401
630
|
if (isEffectApi && primaryBffPrefix && !effectApiWorkerExists) throw createMissingEffectBffWorkerError(outputDirectory, BFF_EFFECT_WORKER_ENTRY);
|
|
402
631
|
return {
|
|
403
632
|
version: 1,
|
|
404
633
|
runtime: {
|
|
405
|
-
type:
|
|
634
|
+
type: external_cloudflare_output_contract_js_namespaceObject.CLOUDFLARE_RUNTIME_TYPE,
|
|
406
635
|
entry: WORKER_ENTRY,
|
|
407
636
|
fetchExport: true,
|
|
408
637
|
nodeListen: false
|
|
@@ -418,7 +647,7 @@ const createWorkerManifest = async (outputDirectory, modernConfig)=>{
|
|
|
418
647
|
},
|
|
419
648
|
workerBundles: {
|
|
420
649
|
directory: WORKER_BUNDLE_DIRECTORY,
|
|
421
|
-
format:
|
|
650
|
+
format: external_cloudflare_output_contract_js_namespaceObject.CLOUDFLARE_WORKER_BUNDLE_FORMAT,
|
|
422
651
|
importableFromModuleWorker: true,
|
|
423
652
|
requestHandlerExport: 'requestHandler'
|
|
424
653
|
},
|
|
@@ -427,11 +656,18 @@ const createWorkerManifest = async (outputDirectory, modernConfig)=>{
|
|
|
427
656
|
routeManifest: ROUTE_MANIFEST_FILE
|
|
428
657
|
},
|
|
429
658
|
security: createCloudflareWorkerSecurityPolicy(modernConfig),
|
|
659
|
+
...deliveryUnitStamp ? {
|
|
660
|
+
deliveryUnit: deliveryUnitStamp
|
|
661
|
+
} : {},
|
|
662
|
+
i18n: createI18nWorkerManifest(routeSpec, appContext),
|
|
430
663
|
bff: isEffectApi && primaryBffPrefix && effectApiWorkerExists ? {
|
|
431
664
|
runtimeFramework: 'effect',
|
|
432
665
|
prefix: primaryBffPrefix,
|
|
433
666
|
worker: BFF_EFFECT_WORKER_ENTRY
|
|
434
|
-
} : void 0
|
|
667
|
+
} : void 0,
|
|
668
|
+
...void 0 === serviceBindings ? {} : {
|
|
669
|
+
serviceBindings
|
|
670
|
+
}
|
|
435
671
|
};
|
|
436
672
|
};
|
|
437
673
|
const createWorkerModuleLoaders = (manifest)=>{
|
|
@@ -483,11 +719,12 @@ const shouldCopyToWorkerBundle = (src, workerBundleDirectory)=>{
|
|
|
483
719
|
const createCloudflarePreset = ({ appContext, modernConfig })=>{
|
|
484
720
|
const { appDirectory, distDirectory } = appContext;
|
|
485
721
|
const outputDirectory = external_node_path_default().join(appDirectory, '.output');
|
|
486
|
-
const
|
|
487
|
-
const
|
|
488
|
-
const
|
|
722
|
+
const outputPlan = (0, external_cloudflare_output_plan_js_namespaceObject.createCloudflareOutputPlan)(outputDirectory);
|
|
723
|
+
const publicDirectory = outputPlan.paths.publicAssets;
|
|
724
|
+
const workerEntryPath = outputPlan.paths.workerEntry;
|
|
725
|
+
const workerManifestPath = outputPlan.paths.workerManifest;
|
|
489
726
|
const routeSpecOutputPath = external_node_path_default().join(outputDirectory, ROUTE_SPEC_OUTPUT);
|
|
490
|
-
const wranglerConfigPath =
|
|
727
|
+
const wranglerConfigPath = outputPlan.paths.wranglerConfig;
|
|
491
728
|
const cloudflareArtifacts = getCloudflareArtifacts(modernConfig);
|
|
492
729
|
const publicAssetExcludes = getPublicAssetExcludes(appDirectory, modernConfig);
|
|
493
730
|
return {
|
|
@@ -503,31 +740,37 @@ const createCloudflarePreset = ({ appContext, modernConfig })=>{
|
|
|
503
740
|
const routeSpecSourcePath = external_node_path_default().join(distDirectory, ROUTE_SPEC_FILE);
|
|
504
741
|
if (await utils_namespaceObject.fs.pathExists(routeSpecSourcePath)) await utils_namespaceObject.fs.copy(routeSpecSourcePath, routeSpecOutputPath);
|
|
505
742
|
const workerBundleSourceDirectory = external_node_path_default().join(distDirectory, WORKER_BUNDLE_DIRECTORY);
|
|
506
|
-
const workerBundleOutputDirectory =
|
|
743
|
+
const workerBundleOutputDirectory = outputPlan.paths.workerBundle;
|
|
507
744
|
if (await utils_namespaceObject.fs.pathExists(workerBundleSourceDirectory)) {
|
|
508
745
|
await utils_namespaceObject.fs.copy(workerBundleSourceDirectory, workerBundleOutputDirectory, {
|
|
509
746
|
filter: (src)=>shouldCopyToWorkerBundle(src, workerBundleSourceDirectory)
|
|
510
747
|
});
|
|
511
|
-
await utils_namespaceObject.fs.writeJSON(
|
|
512
|
-
type: 'commonjs'
|
|
513
|
-
});
|
|
748
|
+
await utils_namespaceObject.fs.writeJSON(outputPlan.paths.workerPackage, outputPlan.packages.worker);
|
|
514
749
|
}
|
|
515
750
|
await copyCloudflareArtifacts(appDirectory, outputDirectory, cloudflareArtifacts);
|
|
751
|
+
await copyCloudflarePublicAssets(appDirectory, publicDirectory, getCloudflarePublicAssets(modernConfig));
|
|
516
752
|
await copyCloudflareD1Migrations(appDirectory, outputDirectory, modernConfig);
|
|
517
753
|
await utils_namespaceObject.fs.writeJSON(wranglerConfigPath, createWranglerConfig(appDirectory, modernConfig), {
|
|
518
754
|
spaces: 2
|
|
519
755
|
});
|
|
520
|
-
|
|
756
|
+
const deliveryUnitStamp = await resolveWorkerDeliveryUnitStamp(appDirectory);
|
|
757
|
+
await utils_namespaceObject.fs.writeJSON(workerManifestPath, await createWorkerManifest(outputDirectory, modernConfig, appContext, deliveryUnitStamp), {
|
|
521
758
|
spaces: 2
|
|
522
759
|
});
|
|
523
|
-
await utils_namespaceObject.fs.writeJSON(
|
|
524
|
-
type: 'module'
|
|
525
|
-
});
|
|
760
|
+
await utils_namespaceObject.fs.writeJSON(outputPlan.paths.outputPackage, outputPlan.packages.output);
|
|
526
761
|
},
|
|
527
762
|
async genEntry () {
|
|
528
763
|
const template = await (0, index_js_namespaceObject.readTemplate)('cloudflare-entry.mjs');
|
|
529
764
|
const manifest = await utils_namespaceObject.fs.readJSON(workerManifestPath);
|
|
530
765
|
await utils_namespaceObject.fs.writeFile(workerEntryPath, template.replace('p_workerManifest', JSON.stringify(manifest, null, 2)).replace('p_workerModuleLoaders', createWorkerModuleLoaders(manifest)));
|
|
766
|
+
const topologyDeliveryUnit = await resolveTopologyDeliveryUnit(appDirectory);
|
|
767
|
+
await (0, external_cloudflare_output_verifier_js_namespaceObject.assertCloudflareOutput)({
|
|
768
|
+
outputDirectory,
|
|
769
|
+
importWorker: false,
|
|
770
|
+
...topologyDeliveryUnit ? {
|
|
771
|
+
deliveryUnit: topologyDeliveryUnit
|
|
772
|
+
} : {}
|
|
773
|
+
});
|
|
531
774
|
}
|
|
532
775
|
};
|
|
533
776
|
};
|