@bleedingdev/modern-js-app-tools-extensions 3.9.0-ultramodern.22 → 3.9.0-ultramodern.23
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/cloudflare/worker-manifest.js +8 -6
- package/dist/cjs/cloudflare/wrangler-config.js +175 -6
- package/dist/cjs/cloudflare-output-contract.js +2 -1
- package/dist/esm/cloudflare/worker-manifest.mjs +9 -7
- package/dist/esm/cloudflare/wrangler-config.mjs +168 -5
- package/dist/esm/cloudflare-output-contract.mjs +2 -1
- package/dist/esm-node/cloudflare/worker-manifest.mjs +9 -7
- package/dist/esm-node/cloudflare/wrangler-config.mjs +168 -5
- package/dist/esm-node/cloudflare-output-contract.mjs +2 -1
- package/dist/types/cloudflare/worker-manifest.d.ts +7 -2
- package/dist/types/cloudflare/wrangler-config.d.ts +52 -5
- package/dist/types/cloudflare-output-contract.d.ts +1 -1
- package/dist/types/config.d.ts +69 -12
- package/package.json +15 -15
- package/src/cloudflare/worker-manifest.ts +19 -6
- package/src/cloudflare/wrangler-config.ts +305 -5
- package/src/cloudflare-output-contract.ts +3 -0
- package/src/config.ts +71 -12
|
@@ -128,6 +128,129 @@ const createWorkerServiceBindings = (modernConfig, configuredWranglerServices)=>
|
|
|
128
128
|
if (!Array.isArray(services)) throw new Error('deploy.worker.services must be an array.');
|
|
129
129
|
return services.map(normalizeServiceBinding);
|
|
130
130
|
};
|
|
131
|
+
const normalizeVpcService = (vpcService, index)=>{
|
|
132
|
+
const binding = assertNonEmptyString(vpcService.binding, `deploy.worker.vpcServices[${index}].binding`);
|
|
133
|
+
const serviceId = assertNonEmptyString(vpcService.serviceId, `deploy.worker.vpcServices[${index}].serviceId`);
|
|
134
|
+
const prefix = void 0 === vpcService.prefix ? void 0 : assertNonEmptyString(vpcService.prefix, `deploy.worker.vpcServices[${index}].prefix`);
|
|
135
|
+
return {
|
|
136
|
+
binding,
|
|
137
|
+
serviceId,
|
|
138
|
+
...void 0 === prefix ? {} : {
|
|
139
|
+
prefix
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
const decodeRoutePrefix = (prefix)=>{
|
|
144
|
+
let decoded = prefix;
|
|
145
|
+
for(let round = 0; round < 4; round += 1){
|
|
146
|
+
let next;
|
|
147
|
+
try {
|
|
148
|
+
next = decodeURIComponent(decoded);
|
|
149
|
+
} catch {
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
if (next === decoded) break;
|
|
153
|
+
decoded = next;
|
|
154
|
+
}
|
|
155
|
+
return decoded;
|
|
156
|
+
};
|
|
157
|
+
const normalizeRoutePrefix = (prefix)=>{
|
|
158
|
+
const decoded = decodeRoutePrefix(prefix);
|
|
159
|
+
return '/' === decoded ? decoded : decoded.replace(/\/+$/u, '');
|
|
160
|
+
};
|
|
161
|
+
const isCanonicalRoutePrefix = (prefix)=>prefix.startsWith('/') && !prefix.includes('\\') && decodeRoutePrefix(prefix) === prefix && new URL(prefix, 'https://route.invalid').pathname === prefix;
|
|
162
|
+
const collectWorkerBindingNames = (config)=>{
|
|
163
|
+
const names = new Set();
|
|
164
|
+
const visit = (value, inArray)=>{
|
|
165
|
+
if (Array.isArray(value)) {
|
|
166
|
+
for (const item of value)visit(item, true);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (!isJsonRecord(value)) return;
|
|
170
|
+
for (const field of inArray ? [
|
|
171
|
+
'binding',
|
|
172
|
+
'name'
|
|
173
|
+
] : [
|
|
174
|
+
'binding'
|
|
175
|
+
]){
|
|
176
|
+
const name = value[field];
|
|
177
|
+
if ('string' == typeof name) names.add(name.trim());
|
|
178
|
+
}
|
|
179
|
+
for (const child of Object.values(value))visit(child, false);
|
|
180
|
+
};
|
|
181
|
+
for (const [key, value] of Object.entries(config))if ('env' !== key && 'services' !== key && 'vpc_services' !== key) {
|
|
182
|
+
if ('vars' === key && isJsonRecord(value)) {
|
|
183
|
+
for (const name of Object.keys(value))names.add(name);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
visit(value, false);
|
|
187
|
+
}
|
|
188
|
+
return names;
|
|
189
|
+
};
|
|
190
|
+
const prefixesOverlap = (left, right)=>{
|
|
191
|
+
const [first, second] = [
|
|
192
|
+
normalizeRoutePrefix(left),
|
|
193
|
+
normalizeRoutePrefix(right)
|
|
194
|
+
];
|
|
195
|
+
return '/' === first || '/' === second || first === second || first.startsWith(`${second}/`) || second.startsWith(`${first}/`);
|
|
196
|
+
};
|
|
197
|
+
const getWorkerEffectBffPrefix = (modernConfig)=>{
|
|
198
|
+
const bffPrefix = modernConfig.bff?.prefix;
|
|
199
|
+
const primaryBffPrefix = Array.isArray(bffPrefix) ? bffPrefix[0] : bffPrefix;
|
|
200
|
+
const isEffectApi = Boolean(modernConfig.bff) && modernConfig.bff?.runtimeFramework !== 'hono';
|
|
201
|
+
return isEffectApi && primaryBffPrefix ? primaryBffPrefix : void 0;
|
|
202
|
+
};
|
|
203
|
+
const effectiveServiceBindings = (serviceBindings)=>{
|
|
204
|
+
const bindings = Array.isArray(serviceBindings) ? serviceBindings : [];
|
|
205
|
+
return bindings.flatMap((service)=>isJsonRecord(service) && 'string' == typeof service.binding ? [
|
|
206
|
+
{
|
|
207
|
+
binding: service.binding.trim(),
|
|
208
|
+
prefix: 'string' == typeof service.prefix ? service.prefix : void 0
|
|
209
|
+
}
|
|
210
|
+
] : []);
|
|
211
|
+
};
|
|
212
|
+
const createWorkerVpcServiceBindings = (modernConfig, configuredWranglerVpcServices, serviceBindings, workerBindingNames)=>{
|
|
213
|
+
const vpcServices = modernConfig.deploy?.worker?.vpcServices;
|
|
214
|
+
if (void 0 === vpcServices) return;
|
|
215
|
+
if (void 0 !== configuredWranglerVpcServices) throw new Error('Use deploy.worker.vpcServices or deploy.worker.wrangler.vpc_services, not both.');
|
|
216
|
+
if (!Array.isArray(vpcServices)) throw new Error('deploy.worker.vpcServices must be an array.');
|
|
217
|
+
const services = effectiveServiceBindings(serviceBindings);
|
|
218
|
+
const serviceBindingNames = new Set(services.map(({ binding })=>binding));
|
|
219
|
+
const effectBffPrefix = getWorkerEffectBffPrefix(modernConfig);
|
|
220
|
+
const routes = [
|
|
221
|
+
...void 0 === effectBffPrefix ? [] : [
|
|
222
|
+
{
|
|
223
|
+
owner: 'the Effect BFF',
|
|
224
|
+
prefix: effectBffPrefix
|
|
225
|
+
}
|
|
226
|
+
],
|
|
227
|
+
...services.flatMap(({ binding, prefix })=>void 0 === prefix ? [] : [
|
|
228
|
+
{
|
|
229
|
+
owner: `binding "${binding}"`,
|
|
230
|
+
prefix
|
|
231
|
+
}
|
|
232
|
+
])
|
|
233
|
+
];
|
|
234
|
+
const vpcBindingNames = new Set();
|
|
235
|
+
return vpcServices.map((vpcService, index)=>{
|
|
236
|
+
const normalized = normalizeVpcService(vpcService, index);
|
|
237
|
+
if (serviceBindingNames.has(normalized.binding)) throw new Error(`deploy.worker.vpcServices[${index}].binding "${normalized.binding}" is already declared by deploy.worker.services.`);
|
|
238
|
+
if (workerBindingNames.has(normalized.binding)) throw new Error(`deploy.worker.vpcServices[${index}].binding "${normalized.binding}" is already a binding of this Worker.`);
|
|
239
|
+
if (vpcBindingNames.has(normalized.binding)) throw new Error(`deploy.worker.vpcServices[${index}].binding "${normalized.binding}" is declared more than once.`);
|
|
240
|
+
vpcBindingNames.add(normalized.binding);
|
|
241
|
+
if (void 0 !== normalized.prefix) {
|
|
242
|
+
const { prefix } = normalized;
|
|
243
|
+
if (!isCanonicalRoutePrefix(prefix)) throw new Error(`deploy.worker.vpcServices[${index}].prefix "${prefix}" must be a decoded URL path that starts with "/" (no query, fragment, "." or ".." segments).`);
|
|
244
|
+
const shadow = routes.find((route)=>prefixesOverlap(route.prefix, prefix));
|
|
245
|
+
if (void 0 !== shadow) throw new Error(`deploy.worker.vpcServices[${index}].prefix "${prefix}" overlaps the prefix "${shadow.prefix}" of ${shadow.owner}; the worker dispatcher would route one of them ambiguously.`);
|
|
246
|
+
routes.push({
|
|
247
|
+
owner: `binding "${normalized.binding}"`,
|
|
248
|
+
prefix
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
return normalized;
|
|
252
|
+
});
|
|
253
|
+
};
|
|
131
254
|
const createWranglerServices = (serviceBindings)=>{
|
|
132
255
|
if (!Array.isArray(serviceBindings)) return serviceBindings;
|
|
133
256
|
if (!serviceBindings.every(isJsonRecord)) return serviceBindings;
|
|
@@ -136,8 +259,16 @@ const createWranglerServices = (serviceBindings)=>{
|
|
|
136
259
|
return wranglerService;
|
|
137
260
|
});
|
|
138
261
|
};
|
|
139
|
-
const createWorkerManifestServiceBindings = (serviceBindings)=>{
|
|
140
|
-
|
|
262
|
+
const createWorkerManifestServiceBindings = (serviceBindings, vpcServiceBindings)=>{
|
|
263
|
+
const vpcManifestBindings = (vpcServiceBindings ?? []).flatMap(({ binding, prefix, serviceId })=>void 0 === prefix ? [] : [
|
|
264
|
+
{
|
|
265
|
+
binding,
|
|
266
|
+
interface: 'fetch',
|
|
267
|
+
prefix,
|
|
268
|
+
vpcServiceId: serviceId
|
|
269
|
+
}
|
|
270
|
+
]);
|
|
271
|
+
if (!Array.isArray(serviceBindings)) return vpcManifestBindings.length > 0 ? vpcManifestBindings : void 0;
|
|
141
272
|
const bindings = serviceBindings;
|
|
142
273
|
const manifestBindings = bindings.filter((service)=>isJsonRecord(service) && 'string' == typeof service.binding && 'string' == typeof service.service && ('string' == typeof service.prefix || Array.isArray(service.fragments) && service.fragments.length > 0)).map((service)=>({
|
|
143
274
|
binding: service.binding,
|
|
@@ -150,7 +281,11 @@ const createWorkerManifestServiceBindings = (serviceBindings)=>{
|
|
|
150
281
|
fragments: service.fragments
|
|
151
282
|
}
|
|
152
283
|
}));
|
|
153
|
-
|
|
284
|
+
const allBindings = [
|
|
285
|
+
...manifestBindings,
|
|
286
|
+
...vpcManifestBindings
|
|
287
|
+
];
|
|
288
|
+
return allBindings.length > 0 ? allBindings : void 0;
|
|
154
289
|
};
|
|
155
290
|
const createWranglerConfig = (appDirectory, modernConfig)=>{
|
|
156
291
|
const wrangler = getConfiguredWrangler(modernConfig);
|
|
@@ -158,7 +293,7 @@ const createWranglerConfig = (appDirectory, modernConfig)=>{
|
|
|
158
293
|
const d1Databases = createWranglerD1Databases(modernConfig, wrangler.d1_databases);
|
|
159
294
|
const serviceBindings = createWorkerServiceBindings(modernConfig, wrangler.services);
|
|
160
295
|
const wranglerServices = createWranglerServices(serviceBindings);
|
|
161
|
-
|
|
296
|
+
const workerConfig = {
|
|
162
297
|
$schema: 'node_modules/wrangler/config-schema.json',
|
|
163
298
|
name: getConfiguredWorkerName(appDirectory, modernConfig),
|
|
164
299
|
...wrangler,
|
|
@@ -176,5 +311,33 @@ const createWranglerConfig = (appDirectory, modernConfig)=>{
|
|
|
176
311
|
services: wranglerServices
|
|
177
312
|
}
|
|
178
313
|
};
|
|
314
|
+
const vpcServiceBindings = createWorkerVpcServiceBindings(modernConfig, wrangler.vpc_services, serviceBindings, collectWorkerBindingNames(workerConfig));
|
|
315
|
+
if (void 0 === vpcServiceBindings) return workerConfig;
|
|
316
|
+
const vpcServicesConfig = vpcServiceBindings.map(({ binding, serviceId })=>({
|
|
317
|
+
binding,
|
|
318
|
+
service_id: serviceId
|
|
319
|
+
}));
|
|
320
|
+
return {
|
|
321
|
+
...workerConfig,
|
|
322
|
+
...void 0 === environments ? {} : {
|
|
323
|
+
env: Object.fromEntries(Object.entries(environments).map(([name, environment])=>{
|
|
324
|
+
if (void 0 !== environment.vpc_services) throw new Error(`Use deploy.worker.vpcServices or deploy.worker.wrangler.env.${name}.vpc_services, not both.`);
|
|
325
|
+
const environmentBindingNames = new Set([
|
|
326
|
+
...collectWorkerBindingNames(environment),
|
|
327
|
+
...effectiveServiceBindings(environment.services).map(({ binding })=>binding)
|
|
328
|
+
]);
|
|
329
|
+
const collision = vpcServiceBindings.find(({ binding })=>environmentBindingNames.has(binding));
|
|
330
|
+
if (void 0 !== collision) throw new Error(`deploy.worker.vpcServices binding "${collision.binding}" is already a binding of deploy.worker.wrangler.env.${name}.`);
|
|
331
|
+
return [
|
|
332
|
+
name,
|
|
333
|
+
{
|
|
334
|
+
...environment,
|
|
335
|
+
vpc_services: vpcServicesConfig
|
|
336
|
+
}
|
|
337
|
+
];
|
|
338
|
+
}))
|
|
339
|
+
},
|
|
340
|
+
vpc_services: vpcServicesConfig
|
|
341
|
+
};
|
|
179
342
|
};
|
|
180
|
-
export { createWorkerManifestServiceBindings, createWorkerServiceBindings, createWranglerConfig };
|
|
343
|
+
export { createWorkerManifestServiceBindings, createWorkerServiceBindings, createWorkerVpcServiceBindings, createWranglerConfig, getWorkerEffectBffPrefix };
|
|
@@ -130,7 +130,12 @@ export declare const createWorkerManifest: (outputDirectory: string, modernConfi
|
|
|
130
130
|
};
|
|
131
131
|
} | undefined;
|
|
132
132
|
} | undefined;
|
|
133
|
-
serviceBindings?: {
|
|
133
|
+
serviceBindings?: ({
|
|
134
|
+
binding: string;
|
|
135
|
+
interface: string;
|
|
136
|
+
prefix: string;
|
|
137
|
+
vpcServiceId: string;
|
|
138
|
+
} | {
|
|
134
139
|
binding: string;
|
|
135
140
|
service: string;
|
|
136
141
|
interface: string;
|
|
@@ -141,7 +146,7 @@ export declare const createWorkerManifest: (outputDirectory: string, modernConfi
|
|
|
141
146
|
boundaryId: string;
|
|
142
147
|
path: string;
|
|
143
148
|
}[] | undefined;
|
|
144
|
-
}[] | undefined;
|
|
149
|
+
})[] | undefined;
|
|
145
150
|
}>;
|
|
146
151
|
export declare const createWorkerModuleLoaders: (manifest: any) => string;
|
|
147
152
|
export declare const getPublicAssetExcludes: (appDirectory: string, modernConfig: CloudflareModernConfig) => string[];
|
|
@@ -11,7 +11,22 @@ export declare const createWorkerServiceBindings: (modernConfig: CloudflareModer
|
|
|
11
11
|
path: string;
|
|
12
12
|
}[] | undefined;
|
|
13
13
|
}[] | JsonValue | undefined;
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The prefix the worker's Effect BFF dispatcher owns. It runs before any
|
|
16
|
+
* service binding, so it takes part in route-overlap checks.
|
|
17
|
+
*/
|
|
18
|
+
export declare const getWorkerEffectBffPrefix: (modernConfig: CloudflareModernConfig) => string | undefined;
|
|
19
|
+
export declare const createWorkerVpcServiceBindings: (modernConfig: CloudflareModernConfig, configuredWranglerVpcServices: JsonValue | undefined, serviceBindings: ReturnType<typeof createWorkerServiceBindings>, workerBindingNames: ReadonlySet<string>) => {
|
|
20
|
+
binding: string;
|
|
21
|
+
serviceId: string;
|
|
22
|
+
prefix?: string | undefined;
|
|
23
|
+
}[] | undefined;
|
|
24
|
+
export declare const createWorkerManifestServiceBindings: (serviceBindings: ReturnType<typeof createWorkerServiceBindings>, vpcServiceBindings: ReturnType<typeof createWorkerVpcServiceBindings>) => ({
|
|
25
|
+
binding: string;
|
|
26
|
+
interface: string;
|
|
27
|
+
prefix: string;
|
|
28
|
+
vpcServiceId: string;
|
|
29
|
+
} | {
|
|
15
30
|
binding: string;
|
|
16
31
|
service: string;
|
|
17
32
|
interface: string;
|
|
@@ -22,7 +37,7 @@ export declare const createWorkerManifestServiceBindings: (serviceBindings: Retu
|
|
|
22
37
|
boundaryId: string;
|
|
23
38
|
path: string;
|
|
24
39
|
}[] | undefined;
|
|
25
|
-
}[] | undefined;
|
|
40
|
+
})[] | undefined;
|
|
26
41
|
export declare const createWranglerConfig: (appDirectory: string, modernConfig: CloudflareModernConfig) => {
|
|
27
42
|
$schema: string;
|
|
28
43
|
name: string;
|
|
@@ -34,10 +49,38 @@ export declare const createWranglerConfig: (appDirectory: string, modernConfig:
|
|
|
34
49
|
binding: string;
|
|
35
50
|
run_worker_first: boolean;
|
|
36
51
|
};
|
|
37
|
-
env?:
|
|
52
|
+
env?: Record<string, Record<string, JsonValue>> | undefined;
|
|
53
|
+
d1_databases?: {
|
|
54
|
+
binding: string;
|
|
55
|
+
database_name: string;
|
|
56
|
+
database_id: string;
|
|
57
|
+
migrations_dir?: string | undefined;
|
|
58
|
+
preview_database_id?: string | undefined;
|
|
59
|
+
remote?: boolean | undefined;
|
|
60
|
+
}[] | JsonValue | undefined;
|
|
61
|
+
services?: string | number | boolean | JsonValue[] | {
|
|
62
|
+
binding: string;
|
|
63
|
+
service: string;
|
|
64
|
+
}[] | {
|
|
65
|
+
[key: string]: JsonValue;
|
|
66
|
+
} | null | undefined;
|
|
67
|
+
} | {
|
|
68
|
+
$schema: string;
|
|
69
|
+
name: string;
|
|
70
|
+
compatibility_date: string;
|
|
71
|
+
main: string;
|
|
72
|
+
compatibility_flags: JsonValue[];
|
|
73
|
+
assets: {
|
|
74
|
+
directory: string;
|
|
75
|
+
binding: string;
|
|
76
|
+
run_worker_first: boolean;
|
|
77
|
+
};
|
|
78
|
+
env?: Record<string, Record<string, JsonValue>> | {
|
|
38
79
|
[k: string]: {
|
|
39
|
-
|
|
40
|
-
|
|
80
|
+
vpc_services: {
|
|
81
|
+
binding: string;
|
|
82
|
+
service_id: string;
|
|
83
|
+
}[];
|
|
41
84
|
};
|
|
42
85
|
} | undefined;
|
|
43
86
|
d1_databases?: {
|
|
@@ -54,4 +97,8 @@ export declare const createWranglerConfig: (appDirectory: string, modernConfig:
|
|
|
54
97
|
}[] | {
|
|
55
98
|
[key: string]: JsonValue;
|
|
56
99
|
} | null | undefined;
|
|
100
|
+
vpc_services: {
|
|
101
|
+
binding: string;
|
|
102
|
+
service_id: string;
|
|
103
|
+
}[];
|
|
57
104
|
};
|
|
@@ -13,5 +13,5 @@ export declare const CLOUDFLARE_WORKER_BUNDLE_FORMAT = "commonjs";
|
|
|
13
13
|
export declare const CLOUDFLARE_ROUTE_DATA_HANDLER_EXPORT = "handleRouteDataRequest";
|
|
14
14
|
export declare const getCloudflareWorkerRouteDataEntryName: (entryName: string) => string;
|
|
15
15
|
export declare const CLOUDFLARE_WORKER_NODE_BUILTINS: readonly ['_http_agent', '_http_client', '_http_common', '_http_incoming', '_http_outgoing', '_http_server', '_tls_common', '_tls_wrap', 'assert', 'assert/strict', 'async_hooks', 'buffer', 'child_process', 'cluster', 'console', 'constants', 'crypto', 'dgram', 'diagnostics_channel', 'dns', 'dns/promises', 'domain', 'events', 'fs', 'fs/promises', 'http', 'http2', 'https', 'inspector', 'inspector/promises', 'module', 'net', 'os', 'path', 'path/posix', 'path/win32', 'perf_hooks', 'process', 'punycode', 'querystring', 'readline', 'readline/promises', 'repl', 'sqlite', 'stream', 'stream/consumers', 'stream/promises', 'stream/web', 'string_decoder', 'sys', 'test', 'timers', 'timers/promises', 'tls', 'trace_events', 'tty', 'url', 'util', 'util/types', 'v8', 'vm', 'wasi', 'worker_threads', 'zlib'];
|
|
16
|
-
export declare const CLOUDFLARE_WORKER_PLATFORM_MODULES: readonly ['cloudflare:sockets'];
|
|
16
|
+
export declare const CLOUDFLARE_WORKER_PLATFORM_MODULES: readonly ['cloudflare:sockets', 'cloudflare:workers'];
|
|
17
17
|
export declare const CLOUDFLARE_REQUIRED_COMPATIBILITY_FLAGS: readonly ['nodejs_compat', 'global_fetch_strictly_public'];
|
package/dist/types/config.d.ts
CHANGED
|
@@ -84,6 +84,18 @@ export interface CloudflareWorkerServiceBindingConfig {
|
|
|
84
84
|
*/
|
|
85
85
|
fragments?: CloudflareWorkerServiceBindingFragmentConfig[];
|
|
86
86
|
}
|
|
87
|
+
export interface CloudflareWorkerVpcServiceConfig {
|
|
88
|
+
/** Worker binding name exposed on the module worker `env` object. */
|
|
89
|
+
binding: string;
|
|
90
|
+
/** Workers VPC service id (`wrangler vpc service create`). */
|
|
91
|
+
serviceId: string;
|
|
92
|
+
/**
|
|
93
|
+
* Optional application path prefix that Modern.js should dispatch to this
|
|
94
|
+
* private origin with `env[binding].fetch(request)`, exactly like a
|
|
95
|
+
* prefixed Worker service binding.
|
|
96
|
+
*/
|
|
97
|
+
prefix?: string;
|
|
98
|
+
}
|
|
87
99
|
export interface CloudflareWorkerServiceBindingFragmentConfig {
|
|
88
100
|
/** Stable remote id used by the shell's composition contract. */
|
|
89
101
|
remote: string;
|
|
@@ -174,19 +186,64 @@ export interface CloudflareWorkerSecurityConfig {
|
|
|
174
186
|
};
|
|
175
187
|
reason?: string;
|
|
176
188
|
}
|
|
189
|
+
export interface CloudflareWorkerDeployConfig {
|
|
190
|
+
name?: string;
|
|
191
|
+
/**
|
|
192
|
+
* Cloudflare Workers compatibility date for generated wrangler config.
|
|
193
|
+
* Use YYYY-MM-DD. Defaults to the date validated against the bundled
|
|
194
|
+
* Wrangler version used by UltraModern generated workspaces.
|
|
195
|
+
*/
|
|
196
|
+
compatibilityDate?: string;
|
|
197
|
+
ssr?: boolean;
|
|
198
|
+
security?: CloudflareWorkerSecurityConfig;
|
|
199
|
+
/**
|
|
200
|
+
* Raw Wrangler-compatible config merged into `.output/wrangler.json`.
|
|
201
|
+
* Framework-owned worker invariants still win for `main`, the assets
|
|
202
|
+
* binding/directory/run mode, and required compatibility flags.
|
|
203
|
+
*/
|
|
204
|
+
wrangler?: Record<string, JsonValue>;
|
|
205
|
+
/**
|
|
206
|
+
* Additional app-root files or directories to stage under `.output`.
|
|
207
|
+
* Use this for provider resources such as migrations or generated config.
|
|
208
|
+
*/
|
|
209
|
+
artifacts?: CloudflareWorkerArtifactConfig[];
|
|
210
|
+
/**
|
|
211
|
+
* Additional app-root files or directories to serve as Cloudflare Worker
|
|
212
|
+
* Static Assets under `.output/public`. Use `to: '.'` to copy a
|
|
213
|
+
* source directory's contents into the public asset root.
|
|
214
|
+
*/
|
|
215
|
+
publicAssets?: CloudflareWorkerPublicAssetConfig[];
|
|
216
|
+
/**
|
|
217
|
+
* First-class Cloudflare D1 bindings. Modern.js writes these to
|
|
218
|
+
* `wrangler.json` as `d1_databases` and stages configured migration
|
|
219
|
+
* directories into `.output`.
|
|
220
|
+
*/
|
|
221
|
+
d1Databases?: CloudflareWorkerD1DatabaseConfig[];
|
|
222
|
+
/**
|
|
223
|
+
* First-class Cloudflare service bindings. Modern.js writes these to
|
|
224
|
+
* `wrangler.json` as `services`; when a binding also has `prefix`,
|
|
225
|
+
* the generated Worker dispatches matching requests through
|
|
226
|
+
* `env[binding].fetch(request)`.
|
|
227
|
+
*/
|
|
228
|
+
services?: CloudflareWorkerServiceBindingConfig[];
|
|
229
|
+
/**
|
|
230
|
+
* First-class Workers VPC service bindings to private origins reached
|
|
231
|
+
* through a Cloudflare Tunnel. Modern.js writes these to `wrangler.json`
|
|
232
|
+
* as `vpc_services`; a binding with `prefix` joins the prefix dispatch of
|
|
233
|
+
* `services`.
|
|
234
|
+
*/
|
|
235
|
+
vpcServices?: CloudflareWorkerVpcServiceConfig[];
|
|
236
|
+
/**
|
|
237
|
+
* Dist output paths that must not be copied into Cloudflare public assets.
|
|
238
|
+
* Entries are slash-normalized path prefixes relative to the app dist root.
|
|
239
|
+
* Top-level `api` and `shared` dist directories are excluded when matching
|
|
240
|
+
* source directories exist in the app root because they conventionally
|
|
241
|
+
* contain server-only implementation code.
|
|
242
|
+
*/
|
|
243
|
+
publicAssetExcludes?: string[];
|
|
244
|
+
}
|
|
177
245
|
export interface CloudflareDeployConfig {
|
|
178
|
-
worker?:
|
|
179
|
-
name?: string;
|
|
180
|
-
compatibilityDate?: string;
|
|
181
|
-
ssr?: boolean;
|
|
182
|
-
security?: CloudflareWorkerSecurityConfig;
|
|
183
|
-
wrangler?: Record<string, JsonValue>;
|
|
184
|
-
artifacts?: CloudflareWorkerArtifactConfig[];
|
|
185
|
-
publicAssets?: CloudflareWorkerPublicAssetConfig[];
|
|
186
|
-
d1Databases?: CloudflareWorkerD1DatabaseConfig[];
|
|
187
|
-
services?: CloudflareWorkerServiceBindingConfig[];
|
|
188
|
-
publicAssetExcludes?: string[];
|
|
189
|
-
};
|
|
246
|
+
worker?: CloudflareWorkerDeployConfig;
|
|
190
247
|
}
|
|
191
248
|
export interface NodeDeployConfig {
|
|
192
249
|
node?: {
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"directory": "packages/solutions/app-tools-extensions"
|
|
12
12
|
},
|
|
13
13
|
"license": "MIT",
|
|
14
|
-
"version": "3.9.0-ultramodern.
|
|
14
|
+
"version": "3.9.0-ultramodern.23",
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
17
|
"src"
|
|
@@ -153,16 +153,16 @@
|
|
|
153
153
|
"@babel/parser": "^8.0.6",
|
|
154
154
|
"@babel/traverse": "^8.0.6",
|
|
155
155
|
"@loadable/component": "5.16.7",
|
|
156
|
-
"@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.0-ultramodern.
|
|
157
|
-
"@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.0-ultramodern.
|
|
158
|
-
"@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.9.0-ultramodern.
|
|
159
|
-
"@modern-js/runtime-renderer-extensions": "npm:@bleedingdev/modern-js-runtime-renderer-extensions@3.9.0-ultramodern.
|
|
160
|
-
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.9.0-ultramodern.
|
|
161
|
-
"@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.
|
|
162
|
-
"@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.
|
|
163
|
-
"@modern-js/surface-resolution": "npm:@bleedingdev/modern-js-surface-resolution@3.9.0-ultramodern.
|
|
164
|
-
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.
|
|
165
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.
|
|
156
|
+
"@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.0-ultramodern.23",
|
|
157
|
+
"@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.0-ultramodern.23",
|
|
158
|
+
"@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.9.0-ultramodern.23",
|
|
159
|
+
"@modern-js/runtime-renderer-extensions": "npm:@bleedingdev/modern-js-runtime-renderer-extensions@3.9.0-ultramodern.23",
|
|
160
|
+
"@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.9.0-ultramodern.23",
|
|
161
|
+
"@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.0-ultramodern.23",
|
|
162
|
+
"@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.0-ultramodern.23",
|
|
163
|
+
"@modern-js/surface-resolution": "npm:@bleedingdev/modern-js-surface-resolution@3.9.0-ultramodern.23",
|
|
164
|
+
"@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.0-ultramodern.23",
|
|
165
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.0-ultramodern.23",
|
|
166
166
|
"@swc/helpers": "^0.5.23",
|
|
167
167
|
"@vercel/nft": "^1.11.0",
|
|
168
168
|
"compression-webpack-plugin": "^12.0.0",
|
|
@@ -179,10 +179,10 @@
|
|
|
179
179
|
}
|
|
180
180
|
},
|
|
181
181
|
"devDependencies": {
|
|
182
|
-
"@modern-js/bff-effect": "npm:@bleedingdev/modern-js-bff-effect@3.9.0-ultramodern.
|
|
183
|
-
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.0-ultramodern.
|
|
184
|
-
"@modern-js/plugin-bff-extensions": "npm:@bleedingdev/modern-js-plugin-bff-extensions@3.9.0-ultramodern.
|
|
185
|
-
"@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.9.0-ultramodern.
|
|
182
|
+
"@modern-js/bff-effect": "npm:@bleedingdev/modern-js-bff-effect@3.9.0-ultramodern.23",
|
|
183
|
+
"@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.0-ultramodern.23",
|
|
184
|
+
"@modern-js/plugin-bff-extensions": "npm:@bleedingdev/modern-js-plugin-bff-extensions@3.9.0-ultramodern.23",
|
|
185
|
+
"@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.9.0-ultramodern.23",
|
|
186
186
|
"@module-federation/modern-js-v3": "2.9.2",
|
|
187
187
|
"@module-federation/runtime-tools": "2.9.2",
|
|
188
188
|
"@rsbuild/core": "2.2.10",
|
|
@@ -28,6 +28,8 @@ import { isRecord, normalizeRelativePath } from './utils';
|
|
|
28
28
|
import {
|
|
29
29
|
createWorkerManifestServiceBindings,
|
|
30
30
|
createWorkerServiceBindings,
|
|
31
|
+
createWorkerVpcServiceBindings,
|
|
32
|
+
getWorkerEffectBffPrefix,
|
|
31
33
|
} from './wrangler-config';
|
|
32
34
|
|
|
33
35
|
const createMissingEffectBffWorkerError = (
|
|
@@ -157,20 +159,31 @@ export const createWorkerManifest = async (
|
|
|
157
159
|
}),
|
|
158
160
|
);
|
|
159
161
|
|
|
160
|
-
const bffPrefix = modernConfig.bff?.prefix;
|
|
161
|
-
const primaryBffPrefix = Array.isArray(bffPrefix) ? bffPrefix[0] : bffPrefix;
|
|
162
162
|
const isEffectApi =
|
|
163
163
|
Boolean(modernConfig.bff) && modernConfig.bff?.runtimeFramework !== 'hono';
|
|
164
|
+
const effectBffPrefix = getWorkerEffectBffPrefix(modernConfig);
|
|
164
165
|
const effectApiWorkerExists = await fse.pathExists(
|
|
165
166
|
path.join(outputDirectory, BFF_EFFECT_WORKER_ENTRY),
|
|
166
167
|
);
|
|
168
|
+
const typedServiceBindings = createWorkerServiceBindings(
|
|
169
|
+
modernConfig,
|
|
170
|
+
undefined,
|
|
171
|
+
);
|
|
167
172
|
const serviceBindings = createWorkerManifestServiceBindings(
|
|
168
|
-
|
|
173
|
+
typedServiceBindings,
|
|
174
|
+
// The wrangler config checks VPC names against every Worker binding; the
|
|
175
|
+
// manifest only needs the framework-owned assets binding reserved.
|
|
176
|
+
createWorkerVpcServiceBindings(
|
|
177
|
+
modernConfig,
|
|
178
|
+
undefined,
|
|
179
|
+
typedServiceBindings,
|
|
180
|
+
new Set([ASSETS_BINDING]),
|
|
181
|
+
),
|
|
169
182
|
);
|
|
170
183
|
const moduleFederation =
|
|
171
184
|
await createModuleFederationWorkerManifest(outputDirectory);
|
|
172
185
|
|
|
173
|
-
if (
|
|
186
|
+
if (effectBffPrefix !== undefined && !effectApiWorkerExists) {
|
|
174
187
|
throw createMissingEffectBffWorkerError(
|
|
175
188
|
outputDirectory,
|
|
176
189
|
BFF_EFFECT_WORKER_ENTRY,
|
|
@@ -212,11 +225,11 @@ export const createWorkerManifest = async (
|
|
|
212
225
|
...(deliveryUnitStamp ? { deliveryUnit: deliveryUnitStamp } : {}),
|
|
213
226
|
i18n: createI18nWorkerManifest(routeSpec, appContext),
|
|
214
227
|
bff:
|
|
215
|
-
|
|
228
|
+
effectBffPrefix !== undefined && effectApiWorkerExists
|
|
216
229
|
? {
|
|
217
230
|
dispatcherExport: BFF_EFFECT_WORKER_DISPATCHER_EXPORT,
|
|
218
231
|
runtimeFramework: 'effect',
|
|
219
|
-
prefix:
|
|
232
|
+
prefix: effectBffPrefix,
|
|
220
233
|
worker: BFF_EFFECT_WORKER_ENTRY,
|
|
221
234
|
effect: effectBffManifest,
|
|
222
235
|
}
|