@bleedingdev/modern-js-app-tools-extensions 3.9.0-ultramodern.8 → 3.9.3-ultramodern.1
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 +23 -0
- package/dist/cjs/backend-federation-build/codegen.js +29 -18
- package/dist/cjs/backend-federation-build/config.js +84 -45
- package/dist/cjs/backend-federation-build/emit.js +63 -22
- package/dist/cjs/build-config/build-environment.js +25 -162
- package/dist/cjs/build-config/internal-effect-discovery.js +143 -0
- package/dist/cjs/build-config/public.js +2 -5
- package/dist/cjs/build-config/remote-address.js +58 -0
- package/dist/cjs/cloudflare/artifacts.js +8 -19
- package/dist/cjs/cloudflare/delivery-unit.js +125 -43
- package/dist/cjs/cloudflare/index.js +14 -4
- package/dist/cjs/cloudflare/native-renderer.js +100 -0
- package/dist/cjs/cloudflare/renderer-identity.js +106 -0
- package/dist/cjs/cloudflare/worker-manifest.js +54 -13
- package/dist/cjs/cloudflare/worker-options.js +48 -0
- package/dist/cjs/cloudflare/wrangler-config.js +210 -13
- package/dist/cjs/cloudflare-builder.js +307 -89
- package/dist/cjs/cloudflare-output-contract.js +36 -4
- package/dist/cjs/cloudflare-output-verifier/identity.js +112 -23
- package/dist/cjs/cloudflare-output-verifier/index.js +10 -0
- package/dist/cjs/cloudflare-output-verifier/manifest.js +46 -0
- package/dist/cjs/cloudflare-output-verifier/mutation-policy.js +7 -1
- package/dist/cjs/cloudflare-output-verifier/worker-bundles.js +10 -5
- package/dist/cjs/config.js +10 -5
- package/dist/cjs/deploy-output/npmAliases.js +92 -6
- package/dist/cjs/deploy-output/plugin.js +27 -6
- package/dist/cjs/deploy-output/public-assets.js +146 -0
- package/dist/cjs/deploy-output/target.js +57 -1
- package/dist/cjs/deploy-output/trace-files.js +99 -0
- package/dist/cjs/module-federation-config/exposes.js +70 -0
- package/dist/cjs/module-federation-config/index.js +73 -0
- package/dist/cjs/module-federation-config/inspect.js +103 -0
- package/dist/cjs/module-federation-config/object-literal.js +87 -0
- package/dist/cjs/module-federation-config/syntax.js +151 -0
- package/dist/cjs/module-federation-config/types.js +18 -0
- package/dist/cjs/native-type-checker.js +164 -18
- package/dist/cjs/policy-defaults.js +110 -0
- package/dist/cjs/release-envelope/canonical.js +2 -9
- package/dist/cjs/release-envelope/contract.js +68 -0
- package/dist/cjs/release-envelope/framework-output.js +296 -105
- package/dist/cjs/release-envelope/index.js +150 -36
- package/dist/cjs/release-envelope/plugin.js +24 -15
- package/dist/cjs/release-envelope/renderer-output-stamp.js +170 -0
- package/dist/cjs/release-envelope/types.js +10 -8
- package/dist/cjs/release-identity.js +8 -5
- package/dist/cjs/renderer-build-identity.js +134 -0
- package/dist/cjs/runtime-package-resolution.js +118 -0
- package/dist/cjs/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
- package/dist/cjs/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
- package/dist/cjs/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
- package/dist/cjs/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
- package/dist/cjs/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
- package/dist/cjs/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/dist/cjs/workspace-topology.js +84 -0
- package/dist/esm/backend-federation-build/codegen.mjs +29 -18
- package/dist/esm/backend-federation-build/config.mjs +74 -38
- package/dist/esm/backend-federation-build/emit.mjs +64 -23
- package/dist/esm/build-config/build-environment.mjs +26 -160
- package/dist/esm/build-config/internal-effect-discovery.mjs +102 -0
- package/dist/esm/build-config/public.mjs +1 -1
- package/dist/esm/build-config/remote-address.mjs +20 -0
- package/dist/esm/cloudflare/artifacts.mjs +8 -19
- package/dist/esm/cloudflare/delivery-unit.mjs +124 -45
- package/dist/esm/cloudflare/index.mjs +15 -5
- package/dist/esm/cloudflare/native-renderer.mjs +48 -0
- package/dist/esm/cloudflare/renderer-identity.mjs +57 -0
- package/dist/esm/cloudflare/worker-manifest.mjs +55 -14
- package/dist/esm/cloudflare/worker-options.mjs +10 -0
- package/dist/esm/cloudflare/wrangler-config.mjs +203 -12
- package/dist/esm/cloudflare-builder.mjs +301 -89
- package/dist/esm/cloudflare-output-contract.mjs +29 -3
- package/dist/esm/cloudflare-output-verifier/identity.mjs +113 -24
- package/dist/esm/cloudflare-output-verifier/index.mjs +10 -0
- package/dist/esm/cloudflare-output-verifier/manifest.mjs +46 -0
- package/dist/esm/cloudflare-output-verifier/mutation-policy.mjs +7 -1
- package/dist/esm/cloudflare-output-verifier/worker-bundles.mjs +11 -6
- package/dist/esm/config.mjs +3 -1
- package/dist/esm/deploy-output/npmAliases.mjs +92 -6
- package/dist/esm/deploy-output/plugin.mjs +24 -6
- package/dist/esm/deploy-output/public-assets.mjs +82 -0
- package/dist/esm/deploy-output/target.mjs +50 -3
- package/dist/esm/deploy-output/trace-files.mjs +47 -0
- package/dist/esm/module-federation-config/exposes.mjs +18 -0
- package/dist/esm/module-federation-config/index.mjs +4 -0
- package/dist/esm/module-federation-config/inspect.mjs +65 -0
- package/dist/esm/module-federation-config/object-literal.mjs +43 -0
- package/dist/esm/module-federation-config/syntax.mjs +101 -0
- package/dist/esm/module-federation-config/types.mjs +0 -0
- package/dist/esm/native-type-checker.mjs +158 -18
- package/dist/esm/policy-defaults.mjs +51 -0
- package/dist/esm/release-envelope/canonical.mjs +2 -9
- package/dist/esm/release-envelope/contract.mjs +21 -0
- package/dist/esm/release-envelope/framework-output.mjs +297 -106
- package/dist/esm/release-envelope/index.mjs +149 -38
- package/dist/esm/release-envelope/plugin.mjs +24 -15
- package/dist/esm/release-envelope/renderer-output-stamp.mjs +112 -0
- package/dist/esm/release-envelope/types.mjs +2 -3
- package/dist/esm/release-identity.mjs +8 -5
- package/dist/esm/renderer-build-identity.mjs +82 -0
- package/dist/esm/runtime-package-resolution.mjs +60 -0
- package/dist/esm/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
- package/dist/esm/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
- package/dist/esm/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
- package/dist/esm/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
- package/dist/esm/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
- package/dist/esm/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/dist/esm/workspace-topology.mjs +21 -0
- package/dist/esm-node/backend-federation-build/codegen.mjs +29 -18
- package/dist/esm-node/backend-federation-build/config.mjs +74 -38
- package/dist/esm-node/backend-federation-build/emit.mjs +64 -23
- package/dist/esm-node/build-config/build-environment.mjs +26 -160
- package/dist/esm-node/build-config/internal-effect-discovery.mjs +103 -0
- package/dist/esm-node/build-config/public.mjs +1 -1
- package/dist/esm-node/build-config/remote-address.mjs +21 -0
- package/dist/esm-node/cloudflare/artifacts.mjs +8 -19
- package/dist/esm-node/cloudflare/delivery-unit.mjs +124 -45
- package/dist/esm-node/cloudflare/index.mjs +15 -5
- package/dist/esm-node/cloudflare/native-renderer.mjs +49 -0
- package/dist/esm-node/cloudflare/renderer-identity.mjs +58 -0
- package/dist/esm-node/cloudflare/worker-manifest.mjs +55 -14
- package/dist/esm-node/cloudflare/worker-options.mjs +11 -0
- package/dist/esm-node/cloudflare/wrangler-config.mjs +203 -12
- package/dist/esm-node/cloudflare-builder.mjs +301 -89
- package/dist/esm-node/cloudflare-output-contract.mjs +29 -3
- package/dist/esm-node/cloudflare-output-verifier/identity.mjs +113 -24
- package/dist/esm-node/cloudflare-output-verifier/index.mjs +10 -0
- package/dist/esm-node/cloudflare-output-verifier/manifest.mjs +46 -0
- package/dist/esm-node/cloudflare-output-verifier/mutation-policy.mjs +7 -1
- package/dist/esm-node/cloudflare-output-verifier/worker-bundles.mjs +11 -6
- package/dist/esm-node/config.mjs +3 -1
- package/dist/esm-node/deploy-output/npmAliases.mjs +92 -6
- package/dist/esm-node/deploy-output/plugin.mjs +24 -6
- package/dist/esm-node/deploy-output/public-assets.mjs +83 -0
- package/dist/esm-node/deploy-output/target.mjs +50 -3
- package/dist/esm-node/deploy-output/trace-files.mjs +48 -0
- package/dist/esm-node/module-federation-config/exposes.mjs +19 -0
- package/dist/esm-node/module-federation-config/index.mjs +5 -0
- package/dist/esm-node/module-federation-config/inspect.mjs +66 -0
- package/dist/esm-node/module-federation-config/object-literal.mjs +44 -0
- package/dist/esm-node/module-federation-config/syntax.mjs +102 -0
- package/dist/esm-node/module-federation-config/types.mjs +1 -0
- package/dist/esm-node/native-type-checker.mjs +158 -18
- package/dist/esm-node/policy-defaults.mjs +52 -0
- package/dist/esm-node/release-envelope/canonical.mjs +2 -9
- package/dist/esm-node/release-envelope/contract.mjs +22 -0
- package/dist/esm-node/release-envelope/framework-output.mjs +297 -106
- package/dist/esm-node/release-envelope/index.mjs +149 -38
- package/dist/esm-node/release-envelope/plugin.mjs +24 -15
- package/dist/esm-node/release-envelope/renderer-output-stamp.mjs +113 -0
- package/dist/esm-node/release-envelope/types.mjs +2 -3
- package/dist/esm-node/release-identity.mjs +8 -5
- package/dist/esm-node/renderer-build-identity.mjs +83 -0
- package/dist/esm-node/runtime-package-resolution.mjs +61 -0
- package/dist/esm-node/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
- package/dist/esm-node/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
- package/dist/esm-node/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
- package/dist/esm-node/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
- package/dist/esm-node/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
- package/dist/esm-node/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/dist/esm-node/workspace-topology.mjs +22 -0
- package/dist/types/backend-federation-build/codegen.d.ts +30 -0
- package/dist/types/backend-federation-build/config.d.ts +10 -57
- package/dist/types/backend-federation-build/emit.d.ts +12 -2
- package/dist/types/backend-federation-build/index.d.ts +1 -1
- package/dist/types/build-config/build-environment.d.ts +1 -9
- package/dist/types/build-config/internal-effect-discovery.d.ts +4 -0
- package/dist/types/build-config/public.d.ts +1 -1
- package/dist/types/build-config/remote-address.d.ts +3 -0
- package/dist/types/cloudflare/artifacts.d.ts +7 -6
- package/dist/types/cloudflare/constants.d.ts +1 -1
- package/dist/types/cloudflare/delivery-unit.d.ts +38 -7
- package/dist/types/cloudflare/native-renderer.d.ts +30 -0
- package/dist/types/cloudflare/renderer-identity.d.ts +25 -0
- package/dist/types/cloudflare/worker-manifest.d.ts +17 -2
- package/dist/types/cloudflare/worker-options.d.ts +20 -0
- package/dist/types/cloudflare/wrangler-config.d.ts +55 -2
- package/dist/types/cloudflare-builder.d.ts +51 -8
- package/dist/types/cloudflare-output-contract.d.ts +5 -3
- package/dist/types/cloudflare-output-verifier/identity.d.ts +7 -3
- package/dist/types/cloudflare-output-verifier/worker-bundles.d.ts +2 -2
- package/dist/types/config.d.ts +98 -13
- package/dist/types/deploy-output/plugin.d.ts +29 -9
- package/dist/types/deploy-output/public-assets.d.ts +51 -0
- package/dist/types/deploy-output/target.d.ts +28 -5
- package/dist/types/deploy-output/trace-files.d.ts +17 -0
- package/dist/types/module-federation-config/exposes.d.ts +11 -0
- package/dist/types/module-federation-config/index.d.ts +5 -0
- package/dist/types/module-federation-config/inspect.d.ts +2 -0
- package/dist/types/module-federation-config/object-literal.d.ts +4 -0
- package/dist/types/module-federation-config/syntax.d.ts +7 -0
- package/dist/types/module-federation-config/types.d.ts +20 -0
- package/dist/types/native-type-checker.d.ts +26 -3
- package/dist/types/policy-defaults.d.ts +56 -0
- package/dist/types/release-envelope/canonical.d.ts +5 -5
- package/dist/types/release-envelope/contract.d.mts +8 -0
- package/dist/types/release-envelope/framework-output.d.ts +23 -13
- package/dist/types/release-envelope/index.d.ts +17 -5
- package/dist/types/release-envelope/plugin.d.ts +10 -6
- package/dist/types/release-envelope/renderer-output-stamp.d.ts +34 -0
- package/dist/types/release-envelope/types.d.ts +42 -4
- package/dist/types/release-identity.d.ts +3 -2
- package/dist/types/renderer-build-identity.d.ts +30 -0
- package/dist/types/runtime-package-resolution.d.ts +28 -0
- package/dist/types/templates/cloudflare-worker-route-data.d.mts +14 -0
- package/dist/types/workspace-topology.d.ts +91 -0
- package/package.json +97 -26
- package/src/backend-federation-build/codegen.ts +28 -19
- package/src/backend-federation-build/config.ts +189 -123
- package/src/backend-federation-build/emit.ts +119 -38
- package/src/backend-federation-build/index.ts +4 -1
- package/src/build-config/build-environment.ts +59 -285
- package/src/build-config/internal-effect-discovery.ts +239 -0
- package/src/build-config/public.ts +0 -1
- package/src/build-config/remote-address.ts +33 -0
- package/src/cloudflare/artifacts.ts +22 -43
- package/src/cloudflare/delivery-unit.ts +283 -60
- package/src/cloudflare/index.ts +35 -19
- package/src/cloudflare/native-renderer.ts +117 -0
- package/src/cloudflare/renderer-identity.ts +171 -0
- package/src/cloudflare/worker-manifest.ts +108 -10
- package/src/cloudflare/worker-options.ts +60 -0
- package/src/cloudflare/wrangler-config.ts +390 -14
- package/src/cloudflare-builder.ts +543 -170
- package/src/cloudflare-output-contract.ts +45 -2
- package/src/cloudflare-output-verifier/identity.ts +138 -7
- package/src/cloudflare-output-verifier/index.ts +20 -0
- package/src/cloudflare-output-verifier/manifest.ts +77 -0
- package/src/cloudflare-output-verifier/mutation-policy.ts +11 -1
- package/src/cloudflare-output-verifier/worker-bundles.ts +27 -11
- package/src/config.ts +101 -19
- package/src/deploy-output/npmAliases.ts +141 -4
- package/src/deploy-output/plugin.ts +55 -18
- package/src/deploy-output/public-assets.ts +224 -0
- package/src/deploy-output/target.ts +97 -14
- package/src/deploy-output/trace-files.ts +80 -0
- package/src/module-federation-config/exposes.ts +46 -0
- package/src/module-federation-config/index.ts +22 -0
- package/src/module-federation-config/inspect.ts +157 -0
- package/src/module-federation-config/object-literal.ts +76 -0
- package/src/module-federation-config/syntax.ts +212 -0
- package/src/module-federation-config/types.ts +22 -0
- package/src/native-type-checker.ts +281 -26
- package/src/policy-defaults.ts +157 -0
- package/src/release-envelope/canonical.ts +6 -18
- package/src/release-envelope/contract.mjs +28 -0
- package/src/release-envelope/framework-output.ts +681 -156
- package/src/release-envelope/index.ts +315 -60
- package/src/release-envelope/plugin.ts +54 -38
- package/src/release-envelope/renderer-output-stamp.ts +210 -0
- package/src/release-envelope/types.ts +75 -6
- package/src/release-identity.ts +19 -2
- package/src/renderer-build-identity.ts +168 -0
- package/src/runtime-package-resolution.ts +115 -0
- package/src/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
- package/src/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
- package/src/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
- package/src/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
- package/src/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
- package/src/templates/cloudflare-worker-route-data.mjs +1069 -0
- package/src/workspace-topology.ts +125 -0
- package/dist/cjs/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/dist/cjs/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/dist/cjs/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/dist/cjs/templates/cloudflare-worker-path.mjs +0 -98
- package/dist/esm/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/dist/esm/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/dist/esm/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/dist/esm/templates/cloudflare-worker-path.mjs +0 -98
- package/dist/esm-node/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/dist/esm-node/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/dist/esm-node/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/dist/esm-node/templates/cloudflare-worker-path.mjs +0 -98
- package/dist/types/templates/cloudflare-worker-fs-promises.d.mts +0 -5
- package/dist/types/templates/cloudflare-worker-loadable-server.d.mts +0 -48
- package/dist/types/templates/cloudflare-worker-mf-ssr-runtime-plugin.d.mts +0 -13
- package/dist/types/templates/cloudflare-worker-path.d.mts +0 -21
- package/src/templates/cloudflare-worker-fs-promises.mjs +0 -11
- package/src/templates/cloudflare-worker-loadable-server.mjs +0 -281
- package/src/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
- package/src/templates/cloudflare-worker-path.mjs +0 -98
|
@@ -2,6 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import type {
|
|
3
3
|
CloudflareWorkerD1DatabaseConfig,
|
|
4
4
|
CloudflareWorkerServiceBindingConfig,
|
|
5
|
+
CloudflareWorkerVpcServiceConfig,
|
|
5
6
|
JsonValue,
|
|
6
7
|
} from '../config';
|
|
7
8
|
import {
|
|
@@ -15,21 +16,51 @@ import {
|
|
|
15
16
|
import type { CloudflareModernConfig } from './types';
|
|
16
17
|
import { isJsonRecord, normalizeRelativePath } from './utils';
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
// Workers only add Node.js built-ins at later dates, and the bundler
|
|
20
|
+
// externalizes the set probed at DEFAULT_COMPATIBILITY_DATE; an earlier date
|
|
21
|
+
// could leave an externalized built-in unresolvable at deploy time.
|
|
22
|
+
const assertSupportedCompatibilityDate = (
|
|
23
|
+
compatibilityDate: JsonValue | undefined,
|
|
24
|
+
label: string,
|
|
25
|
+
) => {
|
|
26
|
+
if (typeof compatibilityDate !== 'string') {
|
|
27
|
+
throw new Error(`${label} must be a YYYY-MM-DD string.`);
|
|
28
|
+
}
|
|
22
29
|
if (!COMPATIBILITY_DATE_PATTERN.test(compatibilityDate)) {
|
|
23
30
|
throw new Error(
|
|
24
|
-
|
|
31
|
+
`${label} must use YYYY-MM-DD, received ${JSON.stringify(
|
|
32
|
+
compatibilityDate,
|
|
33
|
+
)}.`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
if (compatibilityDate < DEFAULT_COMPATIBILITY_DATE) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`${label} must be ${DEFAULT_COMPATIBILITY_DATE} or later, the date the Cloudflare worker Node.js built-in contract is verified against; received ${JSON.stringify(
|
|
25
39
|
compatibilityDate,
|
|
26
40
|
)}.`,
|
|
27
41
|
);
|
|
28
42
|
}
|
|
29
|
-
|
|
30
43
|
return compatibilityDate;
|
|
31
44
|
};
|
|
32
45
|
|
|
46
|
+
const getCompatibilityDate = (
|
|
47
|
+
modernConfig: CloudflareModernConfig,
|
|
48
|
+
wranglerCompatibilityDate: JsonValue | undefined,
|
|
49
|
+
) => {
|
|
50
|
+
if (wranglerCompatibilityDate !== undefined) {
|
|
51
|
+
// A raw Wrangler override is the effective date, so it is validated too.
|
|
52
|
+
return assertSupportedCompatibilityDate(
|
|
53
|
+
wranglerCompatibilityDate,
|
|
54
|
+
'deploy.worker.wrangler.compatibility_date',
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return assertSupportedCompatibilityDate(
|
|
58
|
+
modernConfig.deploy?.worker?.compatibilityDate?.trim() ||
|
|
59
|
+
DEFAULT_COMPATIBILITY_DATE,
|
|
60
|
+
'deploy.worker.compatibilityDate',
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
33
64
|
const getWorkerName = (appDirectory: string) => {
|
|
34
65
|
const basename = path.basename(appDirectory);
|
|
35
66
|
return basename.replace(/[^a-zA-Z0-9-_]/g, '-') || 'modern-cloudflare-worker';
|
|
@@ -59,6 +90,7 @@ const getConfiguredWrangler = (modernConfig: CloudflareModernConfig) => {
|
|
|
59
90
|
|
|
60
91
|
const createWranglerCompatibilityFlags = (
|
|
61
92
|
configuredFlags: JsonValue | undefined,
|
|
93
|
+
label = 'deploy.worker.wrangler.compatibility_flags',
|
|
62
94
|
) => {
|
|
63
95
|
if (configuredFlags === undefined) {
|
|
64
96
|
return [...REQUIRED_COMPATIBILITY_FLAGS];
|
|
@@ -68,14 +100,56 @@ const createWranglerCompatibilityFlags = (
|
|
|
68
100
|
!Array.isArray(configuredFlags) ||
|
|
69
101
|
configuredFlags.some(flag => typeof flag !== 'string')
|
|
70
102
|
) {
|
|
71
|
-
throw new Error(
|
|
72
|
-
'deploy.worker.wrangler.compatibility_flags must be an array of strings.',
|
|
73
|
-
);
|
|
103
|
+
throw new Error(`${label} must be an array of strings.`);
|
|
74
104
|
}
|
|
75
105
|
|
|
76
106
|
return [...new Set([...configuredFlags, ...REQUIRED_COMPATIBILITY_FLAGS])];
|
|
77
107
|
};
|
|
78
108
|
|
|
109
|
+
// `wrangler deploy --env <name>` uses an environment's own compatibility_date
|
|
110
|
+
// and compatibility_flags instead of the top-level values, so each override
|
|
111
|
+
// is held to the same verified date floor and required flags.
|
|
112
|
+
const createWranglerEnvironments = (
|
|
113
|
+
wranglerEnv: JsonValue | undefined,
|
|
114
|
+
): Record<string, Record<string, JsonValue>> | undefined => {
|
|
115
|
+
if (wranglerEnv === undefined) {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
if (!isJsonRecord(wranglerEnv)) {
|
|
119
|
+
throw new Error('deploy.worker.wrangler.env must be an object.');
|
|
120
|
+
}
|
|
121
|
+
return Object.fromEntries(
|
|
122
|
+
Object.entries(wranglerEnv).map(([name, environment]) => {
|
|
123
|
+
const label = `deploy.worker.wrangler.env.${name}`;
|
|
124
|
+
if (!isJsonRecord(environment)) {
|
|
125
|
+
throw new Error(`${label} must be an object.`);
|
|
126
|
+
}
|
|
127
|
+
return [
|
|
128
|
+
name,
|
|
129
|
+
{
|
|
130
|
+
...environment,
|
|
131
|
+
...(environment.compatibility_date === undefined
|
|
132
|
+
? {}
|
|
133
|
+
: {
|
|
134
|
+
compatibility_date: assertSupportedCompatibilityDate(
|
|
135
|
+
environment.compatibility_date,
|
|
136
|
+
`${label}.compatibility_date`,
|
|
137
|
+
),
|
|
138
|
+
}),
|
|
139
|
+
...(environment.compatibility_flags === undefined
|
|
140
|
+
? {}
|
|
141
|
+
: {
|
|
142
|
+
compatibility_flags: createWranglerCompatibilityFlags(
|
|
143
|
+
environment.compatibility_flags,
|
|
144
|
+
`${label}.compatibility_flags`,
|
|
145
|
+
),
|
|
146
|
+
}),
|
|
147
|
+
},
|
|
148
|
+
];
|
|
149
|
+
}),
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
|
|
79
153
|
const createWranglerAssetsConfig = (
|
|
80
154
|
configuredAssets: JsonValue | undefined,
|
|
81
155
|
) => {
|
|
@@ -242,6 +316,232 @@ export const createWorkerServiceBindings = (
|
|
|
242
316
|
return services.map(normalizeServiceBinding);
|
|
243
317
|
};
|
|
244
318
|
|
|
319
|
+
const normalizeVpcService = (
|
|
320
|
+
vpcService: CloudflareWorkerVpcServiceConfig,
|
|
321
|
+
index: number,
|
|
322
|
+
) => {
|
|
323
|
+
const binding = assertNonEmptyString(
|
|
324
|
+
vpcService.binding,
|
|
325
|
+
`deploy.worker.vpcServices[${index}].binding`,
|
|
326
|
+
);
|
|
327
|
+
const serviceId = assertNonEmptyString(
|
|
328
|
+
vpcService.serviceId,
|
|
329
|
+
`deploy.worker.vpcServices[${index}].serviceId`,
|
|
330
|
+
);
|
|
331
|
+
const prefix =
|
|
332
|
+
vpcService.prefix === undefined
|
|
333
|
+
? undefined
|
|
334
|
+
: assertNonEmptyString(
|
|
335
|
+
vpcService.prefix,
|
|
336
|
+
`deploy.worker.vpcServices[${index}].prefix`,
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
return { binding, serviceId, ...(prefix === undefined ? {} : { prefix }) };
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// The worker dispatcher percent-decodes a request path (up to four rounds, as
|
|
343
|
+
// `resolvePrefixPathname` does), matches a prefix on path-segment boundaries
|
|
344
|
+
// and takes the first matching binding, so overlapping prefixes, including
|
|
345
|
+
// encoded aliases of one another, route ambiguously.
|
|
346
|
+
const decodeRoutePrefix = (prefix: string) => {
|
|
347
|
+
let decoded = prefix;
|
|
348
|
+
for (let round = 0; round < 4; round += 1) {
|
|
349
|
+
let next: string;
|
|
350
|
+
try {
|
|
351
|
+
next = decodeURIComponent(decoded);
|
|
352
|
+
} catch {
|
|
353
|
+
return decoded;
|
|
354
|
+
}
|
|
355
|
+
if (next === decoded) {
|
|
356
|
+
return decoded;
|
|
357
|
+
}
|
|
358
|
+
decoded = next;
|
|
359
|
+
}
|
|
360
|
+
return decoded;
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const normalizeRoutePrefix = (prefix: string) => {
|
|
364
|
+
const decoded = decodeRoutePrefix(prefix);
|
|
365
|
+
return decoded === '/' ? decoded : decoded.replace(/\/+$/u, '');
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// The dispatcher matches `new URL(request.url).pathname`, so a prefix is
|
|
369
|
+
// routable only if URL parsing keeps it unchanged: no query or fragment, no
|
|
370
|
+
// `.`/`..` segments, nothing URL parsing would re-encode, and no percent-encoding
|
|
371
|
+
// (the dispatcher decodes request paths before matching).
|
|
372
|
+
const isCanonicalRoutePrefix = (prefix: string) =>
|
|
373
|
+
prefix.startsWith('/') &&
|
|
374
|
+
!prefix.includes('\\') &&
|
|
375
|
+
decodeRoutePrefix(prefix) === prefix &&
|
|
376
|
+
new URL(prefix, 'https://route.invalid').pathname === prefix;
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Names the generated Worker may already expose on `env`, collected
|
|
380
|
+
* conservatively so no Wrangler binding shape is missed: every `binding` field
|
|
381
|
+
* at any depth (assets, D1, KV, Hyperdrive, queue producers, …), the `name` of
|
|
382
|
+
* every array entry (Durable Objects, `send_email`, `ratelimits`, `unsafe` and
|
|
383
|
+
* `logfwdr` bindings, …), and `vars` keys. A non-binding array `name` can only
|
|
384
|
+
* make a VPC name collide, never let a real collision through. Service and VPC
|
|
385
|
+
* bindings are checked separately; per-environment overrides live under `env`.
|
|
386
|
+
*/
|
|
387
|
+
const collectWorkerBindingNames = (config: Record<string, JsonValue>) => {
|
|
388
|
+
const names = new Set<string>();
|
|
389
|
+
const visit = (value: JsonValue, inArray: boolean) => {
|
|
390
|
+
if (Array.isArray(value)) {
|
|
391
|
+
for (const item of value) {
|
|
392
|
+
visit(item, true);
|
|
393
|
+
}
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
if (!isJsonRecord(value)) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
for (const field of inArray ? ['binding', 'name'] : ['binding']) {
|
|
400
|
+
const name = value[field];
|
|
401
|
+
if (typeof name === 'string') {
|
|
402
|
+
names.add(name.trim());
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
for (const child of Object.values(value)) {
|
|
406
|
+
visit(child, false);
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
for (const [key, value] of Object.entries(config)) {
|
|
410
|
+
if (key === 'env' || key === 'services' || key === 'vpc_services') {
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
if (key === 'vars' && isJsonRecord(value)) {
|
|
414
|
+
for (const name of Object.keys(value)) {
|
|
415
|
+
names.add(name);
|
|
416
|
+
}
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
visit(value, false);
|
|
420
|
+
}
|
|
421
|
+
return names;
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
const prefixesOverlap = (left: string, right: string) => {
|
|
425
|
+
const [first, second] = [
|
|
426
|
+
normalizeRoutePrefix(left),
|
|
427
|
+
normalizeRoutePrefix(right),
|
|
428
|
+
];
|
|
429
|
+
return (
|
|
430
|
+
first === '/' ||
|
|
431
|
+
second === '/' ||
|
|
432
|
+
first === second ||
|
|
433
|
+
first.startsWith(`${second}/`) ||
|
|
434
|
+
second.startsWith(`${first}/`)
|
|
435
|
+
);
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* The prefix the worker's Effect BFF dispatcher owns. It runs before any
|
|
440
|
+
* service binding, so it takes part in route-overlap checks.
|
|
441
|
+
*/
|
|
442
|
+
export const getWorkerEffectBffPrefix = (
|
|
443
|
+
modernConfig: CloudflareModernConfig,
|
|
444
|
+
) => {
|
|
445
|
+
const bffPrefix = modernConfig.bff?.prefix;
|
|
446
|
+
const primaryBffPrefix = Array.isArray(bffPrefix) ? bffPrefix[0] : bffPrefix;
|
|
447
|
+
const isEffectApi =
|
|
448
|
+
Boolean(modernConfig.bff) && modernConfig.bff?.runtimeFramework !== 'hono';
|
|
449
|
+
return isEffectApi && primaryBffPrefix ? primaryBffPrefix : undefined;
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
const effectiveServiceBindings = (
|
|
453
|
+
serviceBindings: ReturnType<typeof createWorkerServiceBindings>,
|
|
454
|
+
) => {
|
|
455
|
+
const bindings: unknown[] = Array.isArray(serviceBindings)
|
|
456
|
+
? serviceBindings
|
|
457
|
+
: [];
|
|
458
|
+
return bindings.flatMap(service =>
|
|
459
|
+
isJsonRecord(service) && typeof service.binding === 'string'
|
|
460
|
+
? [
|
|
461
|
+
{
|
|
462
|
+
binding: service.binding.trim(),
|
|
463
|
+
prefix:
|
|
464
|
+
typeof service.prefix === 'string' ? service.prefix : undefined,
|
|
465
|
+
},
|
|
466
|
+
]
|
|
467
|
+
: [],
|
|
468
|
+
);
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
export const createWorkerVpcServiceBindings = (
|
|
472
|
+
modernConfig: CloudflareModernConfig,
|
|
473
|
+
configuredWranglerVpcServices: JsonValue | undefined,
|
|
474
|
+
serviceBindings: ReturnType<typeof createWorkerServiceBindings>,
|
|
475
|
+
workerBindingNames: ReadonlySet<string>,
|
|
476
|
+
) => {
|
|
477
|
+
const vpcServices = modernConfig.deploy?.worker?.vpcServices;
|
|
478
|
+
|
|
479
|
+
if (vpcServices === undefined) {
|
|
480
|
+
return undefined;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (configuredWranglerVpcServices !== undefined) {
|
|
484
|
+
throw new Error(
|
|
485
|
+
'Use deploy.worker.vpcServices or deploy.worker.wrangler.vpc_services, not both.',
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
if (!Array.isArray(vpcServices)) {
|
|
490
|
+
throw new Error('deploy.worker.vpcServices must be an array.');
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const services = effectiveServiceBindings(serviceBindings);
|
|
494
|
+
const serviceBindingNames = new Set(services.map(({ binding }) => binding));
|
|
495
|
+
const effectBffPrefix = getWorkerEffectBffPrefix(modernConfig);
|
|
496
|
+
const routes = [
|
|
497
|
+
...(effectBffPrefix === undefined
|
|
498
|
+
? []
|
|
499
|
+
: [{ owner: 'the Effect BFF', prefix: effectBffPrefix }]),
|
|
500
|
+
...services.flatMap(({ binding, prefix }) =>
|
|
501
|
+
prefix === undefined ? [] : [{ owner: `binding "${binding}"`, prefix }],
|
|
502
|
+
),
|
|
503
|
+
];
|
|
504
|
+
const vpcBindingNames = new Set<string>();
|
|
505
|
+
|
|
506
|
+
return vpcServices.map((vpcService, index) => {
|
|
507
|
+
const normalized = normalizeVpcService(vpcService, index);
|
|
508
|
+
if (serviceBindingNames.has(normalized.binding)) {
|
|
509
|
+
throw new Error(
|
|
510
|
+
`deploy.worker.vpcServices[${index}].binding "${normalized.binding}" is already declared by deploy.worker.services.`,
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
if (workerBindingNames.has(normalized.binding)) {
|
|
514
|
+
throw new Error(
|
|
515
|
+
`deploy.worker.vpcServices[${index}].binding "${normalized.binding}" is already a binding of this Worker.`,
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
if (vpcBindingNames.has(normalized.binding)) {
|
|
519
|
+
throw new Error(
|
|
520
|
+
`deploy.worker.vpcServices[${index}].binding "${normalized.binding}" is declared more than once.`,
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
vpcBindingNames.add(normalized.binding);
|
|
524
|
+
if (normalized.prefix !== undefined) {
|
|
525
|
+
const { prefix } = normalized;
|
|
526
|
+
if (!isCanonicalRoutePrefix(prefix)) {
|
|
527
|
+
throw new Error(
|
|
528
|
+
`deploy.worker.vpcServices[${index}].prefix "${prefix}" must be a decoded URL path that starts with "/" (no query, fragment, "." or ".." segments).`,
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
const shadow = routes.find(route =>
|
|
532
|
+
prefixesOverlap(route.prefix, prefix),
|
|
533
|
+
);
|
|
534
|
+
if (shadow !== undefined) {
|
|
535
|
+
throw new Error(
|
|
536
|
+
`deploy.worker.vpcServices[${index}].prefix "${prefix}" overlaps the prefix "${shadow.prefix}" of ${shadow.owner}; the worker dispatcher would route one of them ambiguously.`,
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
routes.push({ owner: `binding "${normalized.binding}"`, prefix });
|
|
540
|
+
}
|
|
541
|
+
return normalized;
|
|
542
|
+
});
|
|
543
|
+
};
|
|
544
|
+
|
|
245
545
|
const createWranglerServices = (
|
|
246
546
|
serviceBindings: ReturnType<typeof createWorkerServiceBindings>,
|
|
247
547
|
) => {
|
|
@@ -267,9 +567,24 @@ const createWranglerServices = (
|
|
|
267
567
|
|
|
268
568
|
export const createWorkerManifestServiceBindings = (
|
|
269
569
|
serviceBindings: ReturnType<typeof createWorkerServiceBindings>,
|
|
570
|
+
vpcServiceBindings: ReturnType<typeof createWorkerVpcServiceBindings>,
|
|
270
571
|
) => {
|
|
572
|
+
const vpcManifestBindings = (vpcServiceBindings ?? []).flatMap(
|
|
573
|
+
({ binding, prefix, serviceId }) =>
|
|
574
|
+
prefix === undefined
|
|
575
|
+
? []
|
|
576
|
+
: [
|
|
577
|
+
{
|
|
578
|
+
binding,
|
|
579
|
+
interface: 'fetch',
|
|
580
|
+
prefix,
|
|
581
|
+
vpcServiceId: serviceId,
|
|
582
|
+
},
|
|
583
|
+
],
|
|
584
|
+
);
|
|
585
|
+
|
|
271
586
|
if (!Array.isArray(serviceBindings)) {
|
|
272
|
-
return undefined;
|
|
587
|
+
return vpcManifestBindings.length > 0 ? vpcManifestBindings : undefined;
|
|
273
588
|
}
|
|
274
589
|
|
|
275
590
|
const bindings: unknown[] = serviceBindings;
|
|
@@ -304,7 +619,9 @@ export const createWorkerManifestServiceBindings = (
|
|
|
304
619
|
: { fragments: service.fragments }),
|
|
305
620
|
}));
|
|
306
621
|
|
|
307
|
-
|
|
622
|
+
const allBindings = [...manifestBindings, ...vpcManifestBindings];
|
|
623
|
+
|
|
624
|
+
return allBindings.length > 0 ? allBindings : undefined;
|
|
308
625
|
};
|
|
309
626
|
|
|
310
627
|
export const createWranglerConfig = (
|
|
@@ -312,6 +629,7 @@ export const createWranglerConfig = (
|
|
|
312
629
|
modernConfig: CloudflareModernConfig,
|
|
313
630
|
) => {
|
|
314
631
|
const wrangler = getConfiguredWrangler(modernConfig);
|
|
632
|
+
const environments = createWranglerEnvironments(wrangler.env);
|
|
315
633
|
const d1Databases = createWranglerD1Databases(
|
|
316
634
|
modernConfig,
|
|
317
635
|
wrangler.d1_databases,
|
|
@@ -321,18 +639,76 @@ export const createWranglerConfig = (
|
|
|
321
639
|
wrangler.services,
|
|
322
640
|
);
|
|
323
641
|
const wranglerServices = createWranglerServices(serviceBindings);
|
|
324
|
-
|
|
325
|
-
return {
|
|
642
|
+
const workerConfig = {
|
|
326
643
|
$schema: 'node_modules/wrangler/config-schema.json',
|
|
327
644
|
name: getConfiguredWorkerName(appDirectory, modernConfig),
|
|
328
|
-
compatibility_date: getCompatibilityDate(modernConfig),
|
|
329
645
|
...wrangler,
|
|
646
|
+
compatibility_date: getCompatibilityDate(
|
|
647
|
+
modernConfig,
|
|
648
|
+
wrangler.compatibility_date,
|
|
649
|
+
),
|
|
330
650
|
main: WORKER_ENTRY,
|
|
331
651
|
compatibility_flags: createWranglerCompatibilityFlags(
|
|
332
652
|
wrangler.compatibility_flags,
|
|
333
653
|
),
|
|
334
654
|
assets: createWranglerAssetsConfig(wrangler.assets),
|
|
655
|
+
...(environments === undefined ? {} : { env: environments }),
|
|
335
656
|
...(d1Databases === undefined ? {} : { d1_databases: d1Databases }),
|
|
336
657
|
...(wranglerServices === undefined ? {} : { services: wranglerServices }),
|
|
337
658
|
};
|
|
659
|
+
const vpcServiceBindings = createWorkerVpcServiceBindings(
|
|
660
|
+
modernConfig,
|
|
661
|
+
wrangler.vpc_services,
|
|
662
|
+
serviceBindings,
|
|
663
|
+
collectWorkerBindingNames(workerConfig),
|
|
664
|
+
);
|
|
665
|
+
|
|
666
|
+
if (vpcServiceBindings === undefined) {
|
|
667
|
+
return workerConfig;
|
|
668
|
+
}
|
|
669
|
+
const vpcServicesConfig = vpcServiceBindings.map(
|
|
670
|
+
({ binding, serviceId }) => ({
|
|
671
|
+
binding,
|
|
672
|
+
service_id: serviceId,
|
|
673
|
+
}),
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
return {
|
|
677
|
+
...workerConfig,
|
|
678
|
+
// Wrangler bindings are not inherited by named environments, so every
|
|
679
|
+
// configured environment receives the typed VPC bindings as well.
|
|
680
|
+
...(environments === undefined
|
|
681
|
+
? {}
|
|
682
|
+
: {
|
|
683
|
+
env: Object.fromEntries(
|
|
684
|
+
Object.entries(environments).map(([name, environment]) => {
|
|
685
|
+
if (environment.vpc_services !== undefined) {
|
|
686
|
+
throw new Error(
|
|
687
|
+
`Use deploy.worker.vpcServices or deploy.worker.wrangler.env.${name}.vpc_services, not both.`,
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
// A named environment declares its own (non-inherited) bindings.
|
|
691
|
+
const environmentBindingNames = new Set([
|
|
692
|
+
...collectWorkerBindingNames(environment),
|
|
693
|
+
...effectiveServiceBindings(environment.services).map(
|
|
694
|
+
({ binding }) => binding,
|
|
695
|
+
),
|
|
696
|
+
]);
|
|
697
|
+
const collision = vpcServiceBindings.find(({ binding }) =>
|
|
698
|
+
environmentBindingNames.has(binding),
|
|
699
|
+
);
|
|
700
|
+
if (collision !== undefined) {
|
|
701
|
+
throw new Error(
|
|
702
|
+
`deploy.worker.vpcServices binding "${collision.binding}" is already a binding of deploy.worker.wrangler.env.${name}.`,
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
return [
|
|
706
|
+
name,
|
|
707
|
+
{ ...environment, vpc_services: vpcServicesConfig },
|
|
708
|
+
];
|
|
709
|
+
}),
|
|
710
|
+
),
|
|
711
|
+
}),
|
|
712
|
+
vpc_services: vpcServicesConfig,
|
|
713
|
+
};
|
|
338
714
|
};
|