@bleedingdev/modern-js-app-tools 3.5.0-ultramodern.28 → 3.5.0-ultramodern.29
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/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 +152 -27
- package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-entry.mjs +30 -19
- 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 +152 -27
- package/dist/esm/plugins/deploy/platforms/templates/cloudflare-entry.mjs +30 -19
- 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 +152 -27
- package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-entry.mjs +30 -19
- 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 +11 -0
- package/dist/types/types/config/deploy.d.ts +9 -2
- 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
|
|
@@ -421,9 +420,48 @@ const createWranglerD1Databases = (modernConfig, configuredWranglerD1)=>{
|
|
|
421
420
|
if (!Array.isArray(d1Databases)) throw new Error('deploy.worker.d1Databases must be an array.');
|
|
422
421
|
return d1Databases.map(normalizeD1Database);
|
|
423
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
|
+
};
|
|
424
460
|
const createWranglerConfig = (appDirectory, modernConfig)=>{
|
|
425
461
|
const wrangler = getConfiguredWrangler(modernConfig);
|
|
426
462
|
const d1Databases = createWranglerD1Databases(modernConfig, wrangler.d1_databases);
|
|
463
|
+
const serviceBindings = createWorkerServiceBindings(modernConfig, wrangler.services);
|
|
464
|
+
const wranglerServices = createWranglerServices(serviceBindings);
|
|
427
465
|
return {
|
|
428
466
|
$schema: 'node_modules/wrangler/config-schema.json',
|
|
429
467
|
name: getConfiguredWorkerName(appDirectory, modernConfig),
|
|
@@ -434,6 +472,9 @@ const createWranglerConfig = (appDirectory, modernConfig)=>{
|
|
|
434
472
|
assets: createWranglerAssetsConfig(wrangler.assets),
|
|
435
473
|
...void 0 === d1Databases ? {} : {
|
|
436
474
|
d1_databases: d1Databases
|
|
475
|
+
},
|
|
476
|
+
...void 0 === wranglerServices ? {} : {
|
|
477
|
+
services: wranglerServices
|
|
437
478
|
}
|
|
438
479
|
};
|
|
439
480
|
};
|
|
@@ -496,8 +537,79 @@ const readRouteSpec = async (outputDirectory)=>{
|
|
|
496
537
|
routes: Array.isArray(routeSpec.routes) ? routeSpec.routes : []
|
|
497
538
|
};
|
|
498
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
|
+
};
|
|
499
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}`);
|
|
500
|
-
const createWorkerManifest = async (outputDirectory, modernConfig, appContext)=>{
|
|
612
|
+
const createWorkerManifest = async (outputDirectory, modernConfig, appContext, deliveryUnitStamp)=>{
|
|
501
613
|
const routeSpec = await readRouteSpec(outputDirectory);
|
|
502
614
|
const routes = await Promise.all(routeSpec.routes.map(async (route)=>{
|
|
503
615
|
const worker = 'string' == typeof route.worker ? route.worker : void 0;
|
|
@@ -514,11 +626,12 @@ const createWorkerManifest = async (outputDirectory, modernConfig, appContext)=>
|
|
|
514
626
|
const primaryBffPrefix = Array.isArray(bffPrefix) ? bffPrefix[0] : bffPrefix;
|
|
515
627
|
const isEffectApi = Boolean(modernConfig.bff) && modernConfig.bff?.runtimeFramework !== 'hono';
|
|
516
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));
|
|
517
630
|
if (isEffectApi && primaryBffPrefix && !effectApiWorkerExists) throw createMissingEffectBffWorkerError(outputDirectory, BFF_EFFECT_WORKER_ENTRY);
|
|
518
631
|
return {
|
|
519
632
|
version: 1,
|
|
520
633
|
runtime: {
|
|
521
|
-
type:
|
|
634
|
+
type: external_cloudflare_output_contract_js_namespaceObject.CLOUDFLARE_RUNTIME_TYPE,
|
|
522
635
|
entry: WORKER_ENTRY,
|
|
523
636
|
fetchExport: true,
|
|
524
637
|
nodeListen: false
|
|
@@ -534,7 +647,7 @@ const createWorkerManifest = async (outputDirectory, modernConfig, appContext)=>
|
|
|
534
647
|
},
|
|
535
648
|
workerBundles: {
|
|
536
649
|
directory: WORKER_BUNDLE_DIRECTORY,
|
|
537
|
-
format:
|
|
650
|
+
format: external_cloudflare_output_contract_js_namespaceObject.CLOUDFLARE_WORKER_BUNDLE_FORMAT,
|
|
538
651
|
importableFromModuleWorker: true,
|
|
539
652
|
requestHandlerExport: 'requestHandler'
|
|
540
653
|
},
|
|
@@ -543,12 +656,18 @@ const createWorkerManifest = async (outputDirectory, modernConfig, appContext)=>
|
|
|
543
656
|
routeManifest: ROUTE_MANIFEST_FILE
|
|
544
657
|
},
|
|
545
658
|
security: createCloudflareWorkerSecurityPolicy(modernConfig),
|
|
659
|
+
...deliveryUnitStamp ? {
|
|
660
|
+
deliveryUnit: deliveryUnitStamp
|
|
661
|
+
} : {},
|
|
546
662
|
i18n: createI18nWorkerManifest(routeSpec, appContext),
|
|
547
663
|
bff: isEffectApi && primaryBffPrefix && effectApiWorkerExists ? {
|
|
548
664
|
runtimeFramework: 'effect',
|
|
549
665
|
prefix: primaryBffPrefix,
|
|
550
666
|
worker: BFF_EFFECT_WORKER_ENTRY
|
|
551
|
-
} : void 0
|
|
667
|
+
} : void 0,
|
|
668
|
+
...void 0 === serviceBindings ? {} : {
|
|
669
|
+
serviceBindings
|
|
670
|
+
}
|
|
552
671
|
};
|
|
553
672
|
};
|
|
554
673
|
const createWorkerModuleLoaders = (manifest)=>{
|
|
@@ -600,11 +719,12 @@ const shouldCopyToWorkerBundle = (src, workerBundleDirectory)=>{
|
|
|
600
719
|
const createCloudflarePreset = ({ appContext, modernConfig })=>{
|
|
601
720
|
const { appDirectory, distDirectory } = appContext;
|
|
602
721
|
const outputDirectory = external_node_path_default().join(appDirectory, '.output');
|
|
603
|
-
const
|
|
604
|
-
const
|
|
605
|
-
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;
|
|
606
726
|
const routeSpecOutputPath = external_node_path_default().join(outputDirectory, ROUTE_SPEC_OUTPUT);
|
|
607
|
-
const wranglerConfigPath =
|
|
727
|
+
const wranglerConfigPath = outputPlan.paths.wranglerConfig;
|
|
608
728
|
const cloudflareArtifacts = getCloudflareArtifacts(modernConfig);
|
|
609
729
|
const publicAssetExcludes = getPublicAssetExcludes(appDirectory, modernConfig);
|
|
610
730
|
return {
|
|
@@ -620,14 +740,12 @@ const createCloudflarePreset = ({ appContext, modernConfig })=>{
|
|
|
620
740
|
const routeSpecSourcePath = external_node_path_default().join(distDirectory, ROUTE_SPEC_FILE);
|
|
621
741
|
if (await utils_namespaceObject.fs.pathExists(routeSpecSourcePath)) await utils_namespaceObject.fs.copy(routeSpecSourcePath, routeSpecOutputPath);
|
|
622
742
|
const workerBundleSourceDirectory = external_node_path_default().join(distDirectory, WORKER_BUNDLE_DIRECTORY);
|
|
623
|
-
const workerBundleOutputDirectory =
|
|
743
|
+
const workerBundleOutputDirectory = outputPlan.paths.workerBundle;
|
|
624
744
|
if (await utils_namespaceObject.fs.pathExists(workerBundleSourceDirectory)) {
|
|
625
745
|
await utils_namespaceObject.fs.copy(workerBundleSourceDirectory, workerBundleOutputDirectory, {
|
|
626
746
|
filter: (src)=>shouldCopyToWorkerBundle(src, workerBundleSourceDirectory)
|
|
627
747
|
});
|
|
628
|
-
await utils_namespaceObject.fs.writeJSON(
|
|
629
|
-
type: 'commonjs'
|
|
630
|
-
});
|
|
748
|
+
await utils_namespaceObject.fs.writeJSON(outputPlan.paths.workerPackage, outputPlan.packages.worker);
|
|
631
749
|
}
|
|
632
750
|
await copyCloudflareArtifacts(appDirectory, outputDirectory, cloudflareArtifacts);
|
|
633
751
|
await copyCloudflarePublicAssets(appDirectory, publicDirectory, getCloudflarePublicAssets(modernConfig));
|
|
@@ -635,17 +753,24 @@ const createCloudflarePreset = ({ appContext, modernConfig })=>{
|
|
|
635
753
|
await utils_namespaceObject.fs.writeJSON(wranglerConfigPath, createWranglerConfig(appDirectory, modernConfig), {
|
|
636
754
|
spaces: 2
|
|
637
755
|
});
|
|
638
|
-
|
|
756
|
+
const deliveryUnitStamp = await resolveWorkerDeliveryUnitStamp(appDirectory);
|
|
757
|
+
await utils_namespaceObject.fs.writeJSON(workerManifestPath, await createWorkerManifest(outputDirectory, modernConfig, appContext, deliveryUnitStamp), {
|
|
639
758
|
spaces: 2
|
|
640
759
|
});
|
|
641
|
-
await utils_namespaceObject.fs.writeJSON(
|
|
642
|
-
type: 'module'
|
|
643
|
-
});
|
|
760
|
+
await utils_namespaceObject.fs.writeJSON(outputPlan.paths.outputPackage, outputPlan.packages.output);
|
|
644
761
|
},
|
|
645
762
|
async genEntry () {
|
|
646
763
|
const template = await (0, index_js_namespaceObject.readTemplate)('cloudflare-entry.mjs');
|
|
647
764
|
const manifest = await utils_namespaceObject.fs.readJSON(workerManifestPath);
|
|
648
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
|
+
});
|
|
649
774
|
}
|
|
650
775
|
};
|
|
651
776
|
};
|
|
@@ -2,7 +2,7 @@ const ASSETS_BINDING = 'ASSETS';
|
|
|
2
2
|
const MODERN_WORKER_MANIFEST = p_workerManifest;
|
|
3
3
|
const WORKER_MODULE_LOADERS = p_workerModuleLoaders;
|
|
4
4
|
const workerModulePromises = new Map();
|
|
5
|
-
const
|
|
5
|
+
const effectBffDispatcherPromises = new Map();
|
|
6
6
|
let effectEdgeRuntimePromise;
|
|
7
7
|
const remoteJsonPromises = new Map();
|
|
8
8
|
const CORS_POLICY = MODERN_WORKER_MANIFEST.security?.cors || {};
|
|
@@ -152,17 +152,7 @@ async function createCorsPreflightResponse(request, env) {
|
|
|
152
152
|
status: 204
|
|
153
153
|
});
|
|
154
154
|
}
|
|
155
|
-
|
|
156
|
-
const assets = env?.[ASSETS_BINDING];
|
|
157
|
-
if (!assets || 'function' != typeof assets.fetch) return null;
|
|
158
|
-
const assetResponse = await assets.fetch(new Request(request.url, {
|
|
159
|
-
method: 'HEAD'
|
|
160
|
-
}));
|
|
161
|
-
if (!assetResponse || 404 === assetResponse.status) return null;
|
|
162
|
-
return new Response(null, {
|
|
163
|
-
headers: ASSET_CORS_HEADERS,
|
|
164
|
-
status: 204
|
|
165
|
-
});
|
|
155
|
+
return null;
|
|
166
156
|
}
|
|
167
157
|
async function fetchAsset(request, env) {
|
|
168
158
|
if ('GET' !== request.method && 'HEAD' !== request.method) return null;
|
|
@@ -798,17 +788,17 @@ async function dispatchBffRequest(request, env) {
|
|
|
798
788
|
const defaultExport = workerModule.default;
|
|
799
789
|
const runtime = getRuntimeModule(workerModule);
|
|
800
790
|
if ('effect' === bff.runtimeFramework) {
|
|
801
|
-
let
|
|
802
|
-
if (!
|
|
803
|
-
const {
|
|
804
|
-
|
|
791
|
+
let effectDispatcherPromise = effectBffDispatcherPromises.get(bff.worker);
|
|
792
|
+
if (!effectDispatcherPromise) {
|
|
793
|
+
const { createEffectBffEdgeDispatcher } = await loadEffectEdgeRuntime();
|
|
794
|
+
effectDispatcherPromise = createEffectBffEdgeDispatcher({
|
|
805
795
|
module: runtime,
|
|
806
796
|
prefix: bff.prefix
|
|
807
797
|
});
|
|
808
|
-
|
|
798
|
+
effectBffDispatcherPromises.set(bff.worker, effectDispatcherPromise);
|
|
809
799
|
}
|
|
810
|
-
const
|
|
811
|
-
return
|
|
800
|
+
const effectDispatcher = await effectDispatcherPromise;
|
|
801
|
+
return effectDispatcher.dispatch(request, {
|
|
812
802
|
env
|
|
813
803
|
});
|
|
814
804
|
}
|
|
@@ -836,12 +826,33 @@ async function dispatchBffRequest(request, env) {
|
|
|
836
826
|
};
|
|
837
827
|
return handler(mountedRequest, effectContext);
|
|
838
828
|
}
|
|
829
|
+
async function dispatchServiceBindingRequest(request, env) {
|
|
830
|
+
const serviceBindings = MODERN_WORKER_MANIFEST.serviceBindings;
|
|
831
|
+
if (!Array.isArray(serviceBindings) || 0 === serviceBindings.length) return null;
|
|
832
|
+
const pathname = new URL(request.url).pathname;
|
|
833
|
+
for (const binding of serviceBindings){
|
|
834
|
+
if (!binding?.binding || !binding?.prefix) continue;
|
|
835
|
+
if (!matchesPrefix(pathname, binding.prefix)) continue;
|
|
836
|
+
const service = env?.[binding.binding];
|
|
837
|
+
if (!service || 'function' != typeof service.fetch) return new Response(`Cloudflare service binding not available: ${binding.binding}`, {
|
|
838
|
+
status: 502,
|
|
839
|
+
headers: {
|
|
840
|
+
'content-type': 'text/plain; charset=utf-8',
|
|
841
|
+
'x-modern-js-service-binding': binding.binding
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
return service.fetch(request);
|
|
845
|
+
}
|
|
846
|
+
return null;
|
|
847
|
+
}
|
|
839
848
|
export default {
|
|
840
849
|
async fetch (request, env, ctx) {
|
|
841
850
|
const corsPreflightResponse = await createCorsPreflightResponse(request, env);
|
|
842
851
|
if (corsPreflightResponse) return finalizeResponseForRequest(corsPreflightResponse, request);
|
|
843
852
|
const bffResponse = await dispatchBffRequest(request, env);
|
|
844
853
|
if (bffResponse) return finalizeResponseForRequest(withAppCorsHeaders(bffResponse, request), request);
|
|
854
|
+
const serviceBindingResponse = await dispatchServiceBindingRequest(request, env);
|
|
855
|
+
if (serviceBindingResponse) return finalizeResponseForRequest(withAppCorsHeaders(serviceBindingResponse, request), request);
|
|
845
856
|
const route = findRoute(request);
|
|
846
857
|
const { pathname } = new URL(request.url);
|
|
847
858
|
if (isAssetLikePathname(pathname) && !routeMatchesExactly(route, pathname)) {
|
package/dist/esm/index.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { compatPlugin } from "./compat/index.mjs";
|
|
|
8
8
|
import { DEFAULT_RUNTIME_CONFIG_FILE } from "./constants.mjs";
|
|
9
9
|
import { i18n } from "./locale/index.mjs";
|
|
10
10
|
import analyze from "./plugins/analyze/index.mjs";
|
|
11
|
+
import backendFederationBuild from "./plugins/backendFederationBuild.mjs";
|
|
11
12
|
import deploy from "./plugins/deploy/index.mjs";
|
|
12
13
|
import initialize from "./plugins/initialize/index.mjs";
|
|
13
14
|
import serverBuild from "./plugins/serverBuild.mjs";
|
|
@@ -28,6 +29,7 @@ const appTools = ()=>({
|
|
|
28
29
|
initialize(),
|
|
29
30
|
analyze(),
|
|
30
31
|
serverBuild(),
|
|
32
|
+
backendFederationBuild(),
|
|
31
33
|
deploy()
|
|
32
34
|
],
|
|
33
35
|
post: [
|