@cloudflare/config 0.10.0 → 0.12.0
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/index.d.mts +234 -179
- package/dist/index.mjs +424 -19
- package/dist/{public-BwQqexwo.mjs → public-BYCVISMH.mjs} +31 -50
- package/dist/{public-DZgNmLyp.d.mts → public-CxIWEZqM.d.mts} +1509 -1384
- package/dist/public.d.mts +2 -2
- package/dist/public.mjs +2 -2
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as triggers, i as exports$1, n as defineWorker, o as bindings, r as
|
|
1
|
+
import { a as triggers, i as exports$1, n as defineWorker, o as bindings, r as defineContainer, t as defineSettings } from "./public-BYCVISMH.mjs";
|
|
2
2
|
import * as nodeModule from "node:module";
|
|
3
3
|
import * as z from "zod";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -263,6 +263,136 @@ function validateSingletonBindings(env, ctx) {
|
|
|
263
263
|
});
|
|
264
264
|
}
|
|
265
265
|
const EnvSchema = z.record(z.string(), BindingSchema).superRefine(validateSingletonBindings).optional();
|
|
266
|
+
const ContainerImageDockerfileSchema = z.strictObject({
|
|
267
|
+
dockerfile: z.string().min(1),
|
|
268
|
+
buildContext: z.string().optional(),
|
|
269
|
+
buildVars: z.record(z.string(), z.string()).optional()
|
|
270
|
+
});
|
|
271
|
+
const ContainerImageReferenceSchema = z.strictObject({ reference: z.string().min(1) });
|
|
272
|
+
const ContainerImageLocalReferenceSchema = z.strictObject({ localReference: z.string().min(1) });
|
|
273
|
+
const InputContainerImageSchema = z.union([ContainerImageDockerfileSchema, ContainerImageReferenceSchema]);
|
|
274
|
+
const OutputContainerImageSchema = z.union([ContainerImageReferenceSchema, ContainerImageLocalReferenceSchema]);
|
|
275
|
+
const VALID_ROLLOUT_STEP_PERCENTAGES = new Set([
|
|
276
|
+
5,
|
|
277
|
+
10,
|
|
278
|
+
20,
|
|
279
|
+
25,
|
|
280
|
+
50,
|
|
281
|
+
100
|
|
282
|
+
]);
|
|
283
|
+
const ContainerRolloutStepPercentageSchema = z.union([z.number(), z.array(z.number())]).superRefine((stepPercentage, ctx) => {
|
|
284
|
+
if (typeof stepPercentage === "number") {
|
|
285
|
+
if (!VALID_ROLLOUT_STEP_PERCENTAGES.has(stepPercentage)) ctx.addIssue({
|
|
286
|
+
code: "custom",
|
|
287
|
+
message: "A rollout step percentage must be one of 5, 10, 20, 25, 50, or 100"
|
|
288
|
+
});
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (stepPercentage.length === 0) {
|
|
292
|
+
ctx.addIssue({
|
|
293
|
+
code: "custom",
|
|
294
|
+
message: "A rollout must contain at least one step percentage"
|
|
295
|
+
});
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
for (const [index, step] of stepPercentage.entries()) {
|
|
299
|
+
if (step < 10 || step > 100) ctx.addIssue({
|
|
300
|
+
code: "custom",
|
|
301
|
+
path: [index],
|
|
302
|
+
message: "Rollout step percentages must be between 10 and 100"
|
|
303
|
+
});
|
|
304
|
+
const previousStep = stepPercentage[index - 1];
|
|
305
|
+
if (previousStep !== void 0 && step < previousStep) ctx.addIssue({
|
|
306
|
+
code: "custom",
|
|
307
|
+
path: [index],
|
|
308
|
+
message: "Rollout step percentages must be in ascending order"
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
const lastIndex = stepPercentage.length - 1;
|
|
312
|
+
if (stepPercentage[lastIndex] !== 100) ctx.addIssue({
|
|
313
|
+
code: "custom",
|
|
314
|
+
path: [lastIndex],
|
|
315
|
+
message: "The final rollout step percentage must be 100"
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
function validateContainerRelationships(container, ctx) {
|
|
319
|
+
const stepPercentage = container.rollout?.stepPercentage;
|
|
320
|
+
if (Array.isArray(stepPercentage) && container.maxInstances !== void 0 && stepPercentage.length > container.maxInstances) ctx.addIssue({
|
|
321
|
+
code: "custom",
|
|
322
|
+
path: ["rollout", "stepPercentage"],
|
|
323
|
+
message: "A rollout cannot contain more steps than the maximum number of instances"
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
const ContainerObservabilityBaseSchema = z.strictObject({
|
|
327
|
+
enabled: z.boolean().optional(),
|
|
328
|
+
logs: z.strictObject({ enabled: z.boolean().optional() }).optional()
|
|
329
|
+
});
|
|
330
|
+
const ContainerObservabilitySchema = z.union([ContainerObservabilityBaseSchema.extend({ targetInstancePercentage: z.number().min(0).max(100).optional() }), ContainerObservabilityBaseSchema.extend({ targetInstanceCount: z.number().int().nonnegative().optional() })]);
|
|
331
|
+
const BaseContainerSchema = z.strictObject({
|
|
332
|
+
type: z.literal("container"),
|
|
333
|
+
name: z.string().min(1),
|
|
334
|
+
observability: ContainerObservabilitySchema.optional(),
|
|
335
|
+
unsafe: z.record(z.string(), z.unknown()).optional()
|
|
336
|
+
});
|
|
337
|
+
const StandardContainerBaseSchema = BaseContainerSchema.extend({
|
|
338
|
+
maxInstances: z.number().int().nonnegative().default(20),
|
|
339
|
+
instanceType: z.union([z.enum([
|
|
340
|
+
"basic",
|
|
341
|
+
"lite",
|
|
342
|
+
"standard-1",
|
|
343
|
+
"standard-2",
|
|
344
|
+
"standard-3",
|
|
345
|
+
"standard-4"
|
|
346
|
+
]), z.strictObject({
|
|
347
|
+
vcpu: z.number().min(.0625).optional(),
|
|
348
|
+
memoryMib: z.number().nonnegative().optional(),
|
|
349
|
+
diskMb: z.number().nonnegative().optional()
|
|
350
|
+
})]).optional(),
|
|
351
|
+
schedulingPolicy: z.enum(["default", "regional"]).optional(),
|
|
352
|
+
ssh: z.strictObject({
|
|
353
|
+
enabled: z.boolean(),
|
|
354
|
+
port: z.number().int().min(1).max(65535).optional()
|
|
355
|
+
}).optional(),
|
|
356
|
+
authorizedKeys: z.array(z.strictObject({
|
|
357
|
+
name: z.string(),
|
|
358
|
+
publicKey: z.string()
|
|
359
|
+
})).optional(),
|
|
360
|
+
constraints: z.strictObject({
|
|
361
|
+
regions: z.array(z.enum([
|
|
362
|
+
"ENAM",
|
|
363
|
+
"WNAM",
|
|
364
|
+
"EEUR",
|
|
365
|
+
"WEUR",
|
|
366
|
+
"APAC",
|
|
367
|
+
"SAM",
|
|
368
|
+
"ME",
|
|
369
|
+
"OC",
|
|
370
|
+
"AFR"
|
|
371
|
+
])).optional(),
|
|
372
|
+
jurisdiction: z.enum(["eu", "fedramp"]).optional()
|
|
373
|
+
}).optional(),
|
|
374
|
+
rollout: z.strictObject({
|
|
375
|
+
kind: z.enum([
|
|
376
|
+
"full-auto",
|
|
377
|
+
"none",
|
|
378
|
+
"full-manual"
|
|
379
|
+
]).optional(),
|
|
380
|
+
stepPercentage: ContainerRolloutStepPercentageSchema.optional(),
|
|
381
|
+
activeGracePeriod: z.number().nonnegative().optional()
|
|
382
|
+
}).optional()
|
|
383
|
+
});
|
|
384
|
+
const DurableObjectContainerBaseSchema = BaseContainerSchema.extend({ schedulingPolicy: z.literal("durable-object") });
|
|
385
|
+
/**
|
|
386
|
+
* Input Container schema — validates user-authored `cloudflare.config.ts`
|
|
387
|
+
* Container exports. Dockerfiles are built by the consuming build tool.
|
|
388
|
+
*/
|
|
389
|
+
const InputContainerSchema = z.union([StandardContainerBaseSchema.extend({ image: InputContainerImageSchema }).superRefine(validateContainerRelationships), DurableObjectContainerBaseSchema.extend({ images: z.record(z.string(), InputContainerImageSchema).optional() })]);
|
|
390
|
+
/**
|
|
391
|
+
* Output Container schema — validates Container configs in the Build Output
|
|
392
|
+
* Specification, after any Dockerfile has been built into a local or remote
|
|
393
|
+
* image reference.
|
|
394
|
+
*/
|
|
395
|
+
const OutputContainerSchema = z.union([StandardContainerBaseSchema.extend({ image: OutputContainerImageSchema }).superRefine(validateContainerRelationships), DurableObjectContainerBaseSchema.extend({ images: z.record(z.string(), OutputContainerImageSchema).optional() })]);
|
|
266
396
|
const DurableObjectCreatedExportSchema = z.strictObject({
|
|
267
397
|
type: z.literal("durable-object"),
|
|
268
398
|
state: z.literal("created").optional(),
|
|
@@ -441,8 +571,13 @@ const InputSettingsSchema = z.strictObject({
|
|
|
441
571
|
* Build Output Specification. Adds the `mode` the build was produced in.
|
|
442
572
|
*/
|
|
443
573
|
const OutputSettingsSchema = InputSettingsSchema.extend({ mode: z.string().optional() });
|
|
574
|
+
const DEFAULT_EXPORT_NAME = "default";
|
|
444
575
|
const SETTINGS_EXPORT_NAME = "settings";
|
|
445
|
-
const SUPPORTED_EXPORT_TYPES = new Set([
|
|
576
|
+
const SUPPORTED_EXPORT_TYPES = new Set([
|
|
577
|
+
"container",
|
|
578
|
+
"worker",
|
|
579
|
+
"settings"
|
|
580
|
+
]);
|
|
446
581
|
function invalidConfigExportMessage(exportName) {
|
|
447
582
|
return `The \`${exportName}\` export is not a supported export type. Move constants, helper functions, and other unsupported exports to a separate module.`;
|
|
448
583
|
}
|
|
@@ -459,6 +594,15 @@ const ConfigExportsTypeSchema = z.record(z.string(), z.unknown()).check((ctx) =>
|
|
|
459
594
|
});
|
|
460
595
|
continue;
|
|
461
596
|
}
|
|
597
|
+
if (key === DEFAULT_EXPORT_NAME && type !== "worker") {
|
|
598
|
+
ctx.issues.push({
|
|
599
|
+
code: "custom",
|
|
600
|
+
input: value,
|
|
601
|
+
path: [key],
|
|
602
|
+
message: `The \`${DEFAULT_EXPORT_NAME}\` export is reserved for a \`worker\` config; found a \`${type}\` config.`
|
|
603
|
+
});
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
462
606
|
const isSettingsName = key === SETTINGS_EXPORT_NAME;
|
|
463
607
|
const isSettingsType = type === "settings";
|
|
464
608
|
if (isSettingsType && !isSettingsName) ctx.issues.push({
|
|
@@ -475,15 +619,6 @@ const ConfigExportsTypeSchema = z.record(z.string(), z.unknown()).check((ctx) =>
|
|
|
475
619
|
});
|
|
476
620
|
}
|
|
477
621
|
});
|
|
478
|
-
const ConfigExportsObjectSchema = z.object({ settings: InputSettingsSchema.optional() }).catchall(InputWorkerSchema);
|
|
479
|
-
/**
|
|
480
|
-
* Schema for the resolved config exports, keyed by export
|
|
481
|
-
* name. Each value is discriminated on its `type` field. Reserves the
|
|
482
|
-
* `settings` export name exclusively for settings configs: a `settings`
|
|
483
|
-
* config must live on the `settings` export, and the `settings` export
|
|
484
|
-
* may only hold a `settings` config.
|
|
485
|
-
*/
|
|
486
|
-
const ConfigExportsSchema = ConfigExportsTypeSchema.pipe(ConfigExportsObjectSchema);
|
|
487
622
|
const ModuleTypeSchema = z.enum([
|
|
488
623
|
"esm",
|
|
489
624
|
"cjs",
|
|
@@ -665,18 +800,26 @@ __name(createFatalError, "createFatalError");
|
|
|
665
800
|
|
|
666
801
|
//#endregion
|
|
667
802
|
//#region src/convert.ts
|
|
803
|
+
const ROLLOUT_KIND_MAP = {
|
|
804
|
+
"full-auto": "full_auto",
|
|
805
|
+
"full-manual": "full_manual",
|
|
806
|
+
none: "none"
|
|
807
|
+
};
|
|
668
808
|
/**
|
|
669
809
|
* Convert a parsed `@cloudflare/config` config into a Wrangler `RawConfig`.
|
|
670
810
|
*
|
|
671
|
-
* The caller is responsible for unwrapping any function/promise
|
|
672
|
-
* the
|
|
811
|
+
* The caller is responsible for unwrapping any function/promise wrappers and
|
|
812
|
+
* validating the configs against their corresponding input schemas before
|
|
813
|
+
* passing them in.
|
|
673
814
|
*
|
|
674
815
|
* @param workerConfig The parsed (post-validation) Worker config.
|
|
675
816
|
* @param settingsConfig The optional parsed settings config, whose fields
|
|
676
817
|
* are merged onto the result.
|
|
818
|
+
* @param containerExports The parsed Container exports to include in the
|
|
819
|
+
* result.
|
|
677
820
|
* @returns The corresponding Wrangler `RawConfig`.
|
|
678
821
|
*/
|
|
679
|
-
function convertToWranglerConfig(workerConfig, settingsConfig) {
|
|
822
|
+
function convertToWranglerConfig(workerConfig, settingsConfig, containerExports = []) {
|
|
680
823
|
const result = {};
|
|
681
824
|
convertTopLevel(workerConfig, result);
|
|
682
825
|
convertBindingsAndAssets(workerConfig, result);
|
|
@@ -685,8 +828,50 @@ function convertToWranglerConfig(workerConfig, settingsConfig) {
|
|
|
685
828
|
convertTriggers(workerConfig, result);
|
|
686
829
|
convertTailConsumers(workerConfig, result);
|
|
687
830
|
if (settingsConfig !== void 0) convertSettings(settingsConfig, result);
|
|
831
|
+
if (containerExports.length > 0) result.containers = containerExports.map((container) => convertContainer(container));
|
|
688
832
|
return result;
|
|
689
833
|
}
|
|
834
|
+
function convertContainer(container) {
|
|
835
|
+
if (container.schedulingPolicy === "durable-object") throw new UserError("Durable Object-managed Containers are not currently supported by `convertToWranglerConfig()`.", { telemetryMessage: false });
|
|
836
|
+
const converted = { name: container.name };
|
|
837
|
+
if (container.observability !== void 0) converted.observability = convertContainerObservability(container.observability);
|
|
838
|
+
if (container.unsafe !== void 0) converted.unsafe = container.unsafe;
|
|
839
|
+
converted.image = "dockerfile" in container.image ? container.image.dockerfile : container.image.reference;
|
|
840
|
+
converted.max_instances = container.maxInstances;
|
|
841
|
+
if ("dockerfile" in container.image) {
|
|
842
|
+
if (container.image.buildContext !== void 0) converted.image_build_context = container.image.buildContext;
|
|
843
|
+
if (container.image.buildVars !== void 0) converted.image_vars = container.image.buildVars;
|
|
844
|
+
}
|
|
845
|
+
if (container.instanceType !== void 0) if (typeof container.instanceType === "string") converted.instance_type = container.instanceType;
|
|
846
|
+
else {
|
|
847
|
+
const instanceType = {};
|
|
848
|
+
if (container.instanceType.vcpu !== void 0) instanceType.vcpu = container.instanceType.vcpu;
|
|
849
|
+
if (container.instanceType.memoryMib !== void 0) instanceType.memory_mib = container.instanceType.memoryMib;
|
|
850
|
+
if (container.instanceType.diskMb !== void 0) instanceType.disk_mb = container.instanceType.diskMb;
|
|
851
|
+
converted.instance_type = instanceType;
|
|
852
|
+
}
|
|
853
|
+
if (container.schedulingPolicy !== void 0) converted.scheduling_policy = container.schedulingPolicy;
|
|
854
|
+
if (container.ssh !== void 0) converted.ssh = container.ssh;
|
|
855
|
+
if (container.authorizedKeys !== void 0) converted.authorized_keys = container.authorizedKeys.map(({ name, publicKey }) => ({
|
|
856
|
+
name,
|
|
857
|
+
public_key: publicKey
|
|
858
|
+
}));
|
|
859
|
+
if (container.constraints !== void 0) converted.constraints = container.constraints;
|
|
860
|
+
if (container.rollout !== void 0) {
|
|
861
|
+
if (container.rollout.kind !== void 0) converted.rollout_kind = ROLLOUT_KIND_MAP[container.rollout.kind];
|
|
862
|
+
if (container.rollout.stepPercentage !== void 0) converted.rollout_step_percentage = container.rollout.stepPercentage;
|
|
863
|
+
if (container.rollout.activeGracePeriod !== void 0) converted.rollout_active_grace_period = container.rollout.activeGracePeriod;
|
|
864
|
+
}
|
|
865
|
+
return converted;
|
|
866
|
+
}
|
|
867
|
+
function convertContainerObservability(observability) {
|
|
868
|
+
const converted = {};
|
|
869
|
+
if (observability.enabled !== void 0) converted.enabled = observability.enabled;
|
|
870
|
+
if (observability.logs !== void 0) converted.logs = observability.logs;
|
|
871
|
+
if ("targetInstancePercentage" in observability && observability.targetInstancePercentage !== void 0) converted.target_instance_percentage = observability.targetInstancePercentage;
|
|
872
|
+
if ("targetInstanceCount" in observability && observability.targetInstanceCount !== void 0) converted.target_instance_count = observability.targetInstanceCount;
|
|
873
|
+
return converted;
|
|
874
|
+
}
|
|
690
875
|
/**
|
|
691
876
|
* Merge a parsed settings config's fields (`account_id`, `compliance_region`)
|
|
692
877
|
* onto an existing Wrangler `RawConfig`.
|
|
@@ -1349,18 +1534,238 @@ function cleanupImportAttributes(context) {
|
|
|
1349
1534
|
|
|
1350
1535
|
//#endregion
|
|
1351
1536
|
//#region src/config-loader.ts
|
|
1537
|
+
const CROSS_WORKER_BINDING_TYPES = new Set([
|
|
1538
|
+
"durable-object",
|
|
1539
|
+
"worker",
|
|
1540
|
+
"workflow"
|
|
1541
|
+
]);
|
|
1542
|
+
function isRecord(value) {
|
|
1543
|
+
return typeof value === "object" && value !== null;
|
|
1544
|
+
}
|
|
1545
|
+
function isConfigReference(value) {
|
|
1546
|
+
return typeof value === "function" || isRecord(value);
|
|
1547
|
+
}
|
|
1548
|
+
function normalizeConfigReference(reference, resolved, expectedType) {
|
|
1549
|
+
return isRecord(resolved) && resolved.type === expectedType && typeof resolved.name === "string" ? resolved.name : reference;
|
|
1550
|
+
}
|
|
1551
|
+
function createDefinitionResolver(ctx) {
|
|
1552
|
+
const resolvedDefinitions = /* @__PURE__ */ new Map();
|
|
1553
|
+
return (input) => {
|
|
1554
|
+
const cached = resolvedDefinitions.get(input);
|
|
1555
|
+
if (cached) return cached;
|
|
1556
|
+
const resolved = (async () => {
|
|
1557
|
+
return await (typeof input === "function" ? input(ctx) : input);
|
|
1558
|
+
})();
|
|
1559
|
+
resolvedDefinitions.set(input, resolved);
|
|
1560
|
+
return resolved;
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
async function normalizeWorkerReferences(resolved, resolveDefinition) {
|
|
1564
|
+
if (!isRecord(resolved) || !isRecord(resolved.env)) return resolved;
|
|
1565
|
+
const env = { ...resolved.env };
|
|
1566
|
+
for (const [bindingName, binding] of Object.entries(env)) {
|
|
1567
|
+
if (!isRecord(binding) || typeof binding.type !== "string" || !CROSS_WORKER_BINDING_TYPES.has(binding.type) || !isConfigReference(binding.worker)) continue;
|
|
1568
|
+
const target = await resolveDefinition(binding.worker);
|
|
1569
|
+
env[bindingName] = {
|
|
1570
|
+
...binding,
|
|
1571
|
+
worker: normalizeConfigReference(binding.worker, target, "worker")
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
return {
|
|
1575
|
+
...resolved,
|
|
1576
|
+
env
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
async function normalizeContainerReferences(resolved, resolveDefinition, resolvedExports) {
|
|
1580
|
+
const issues = [];
|
|
1581
|
+
if (!isRecord(resolved) || !isRecord(resolved.exports)) return {
|
|
1582
|
+
value: resolved,
|
|
1583
|
+
issues
|
|
1584
|
+
};
|
|
1585
|
+
const workerExports = { ...resolved.exports };
|
|
1586
|
+
for (const [exportName, workerExport] of Object.entries(workerExports)) {
|
|
1587
|
+
if (!isRecord(workerExport) || workerExport.type !== "durable-object" || workerExport.container === void 0) continue;
|
|
1588
|
+
const reference = workerExport.container;
|
|
1589
|
+
if (typeof reference === "string") {
|
|
1590
|
+
issues.push({
|
|
1591
|
+
code: "custom",
|
|
1592
|
+
input: reference,
|
|
1593
|
+
path: [
|
|
1594
|
+
"exports",
|
|
1595
|
+
exportName,
|
|
1596
|
+
"container"
|
|
1597
|
+
],
|
|
1598
|
+
message: "Container provided as a string. Reference an exported Container definition instead."
|
|
1599
|
+
});
|
|
1600
|
+
workerExports[exportName] = {
|
|
1601
|
+
...workerExport,
|
|
1602
|
+
container: void 0
|
|
1603
|
+
};
|
|
1604
|
+
continue;
|
|
1605
|
+
}
|
|
1606
|
+
const target = await resolveDefinition(reference);
|
|
1607
|
+
if (isRecord(target) && target.type === "container" && typeof target.name === "string" && !Object.values(resolvedExports).includes(target)) {
|
|
1608
|
+
issues.push({
|
|
1609
|
+
code: "custom",
|
|
1610
|
+
input: reference,
|
|
1611
|
+
path: [
|
|
1612
|
+
"exports",
|
|
1613
|
+
exportName,
|
|
1614
|
+
"container"
|
|
1615
|
+
],
|
|
1616
|
+
message: `The referenced Container "${target.name}" is not exported.`
|
|
1617
|
+
});
|
|
1618
|
+
workerExports[exportName] = {
|
|
1619
|
+
...workerExport,
|
|
1620
|
+
container: void 0
|
|
1621
|
+
};
|
|
1622
|
+
continue;
|
|
1623
|
+
}
|
|
1624
|
+
workerExports[exportName] = {
|
|
1625
|
+
...workerExport,
|
|
1626
|
+
container: normalizeConfigReference(reference, target, "container")
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
return {
|
|
1630
|
+
value: {
|
|
1631
|
+
...resolved,
|
|
1632
|
+
exports: workerExports
|
|
1633
|
+
},
|
|
1634
|
+
issues
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
async function normalizeConfigReferences(resolved, resolveDefinition, resolvedExports) {
|
|
1638
|
+
return normalizeContainerReferences(await normalizeWorkerReferences(resolved, resolveDefinition), resolveDefinition, resolvedExports);
|
|
1639
|
+
}
|
|
1640
|
+
function prefixIssues(issues, prefix) {
|
|
1641
|
+
return issues.map((issue) => ({
|
|
1642
|
+
...issue,
|
|
1643
|
+
path: [prefix, ...issue.path]
|
|
1644
|
+
}));
|
|
1645
|
+
}
|
|
1646
|
+
function validateUniqueResourceNames(configExports) {
|
|
1647
|
+
const issues = [];
|
|
1648
|
+
const exportNameByResourceName = {
|
|
1649
|
+
container: /* @__PURE__ */ new Map(),
|
|
1650
|
+
worker: /* @__PURE__ */ new Map()
|
|
1651
|
+
};
|
|
1652
|
+
for (const [exportName, config] of Object.entries(configExports)) {
|
|
1653
|
+
if (config.type !== "container" && config.type !== "worker") continue;
|
|
1654
|
+
const resourceType = config.type === "container" ? "Container" : "Worker";
|
|
1655
|
+
const exportNames = exportNameByResourceName[config.type];
|
|
1656
|
+
const previousExportName = exportNames.get(config.name);
|
|
1657
|
+
if (previousExportName !== void 0) {
|
|
1658
|
+
issues.push({
|
|
1659
|
+
code: "custom",
|
|
1660
|
+
input: config.name,
|
|
1661
|
+
path: [exportName, "name"],
|
|
1662
|
+
message: `The ${resourceType} name "${config.name}" is also used by the "${previousExportName}" export. ${resourceType} names must be unique.`
|
|
1663
|
+
});
|
|
1664
|
+
continue;
|
|
1665
|
+
}
|
|
1666
|
+
exportNames.set(config.name, exportName);
|
|
1667
|
+
}
|
|
1668
|
+
return issues;
|
|
1669
|
+
}
|
|
1670
|
+
function validateContainerExportLinks(configExports) {
|
|
1671
|
+
const issues = [];
|
|
1672
|
+
const containerNames = /* @__PURE__ */ new Set();
|
|
1673
|
+
for (const config of Object.values(configExports)) if (config.type === "container") containerNames.add(config.name);
|
|
1674
|
+
const firstReferenceByContainerName = /* @__PURE__ */ new Map();
|
|
1675
|
+
for (const [workerExportName, config] of Object.entries(configExports)) {
|
|
1676
|
+
if (config.type !== "worker") continue;
|
|
1677
|
+
for (const [durableObjectExportName, workerExport] of Object.entries(config.exports ?? {})) {
|
|
1678
|
+
if (workerExport.type !== "durable-object" || !("container" in workerExport) || workerExport.container === void 0) continue;
|
|
1679
|
+
const containerName = workerExport.container;
|
|
1680
|
+
const path = [
|
|
1681
|
+
workerExportName,
|
|
1682
|
+
"exports",
|
|
1683
|
+
durableObjectExportName,
|
|
1684
|
+
"container"
|
|
1685
|
+
];
|
|
1686
|
+
if (!containerNames.has(containerName)) {
|
|
1687
|
+
issues.push({
|
|
1688
|
+
code: "custom",
|
|
1689
|
+
input: containerName,
|
|
1690
|
+
path,
|
|
1691
|
+
message: `The Container "${containerName}" is not exported from this configuration.`
|
|
1692
|
+
});
|
|
1693
|
+
continue;
|
|
1694
|
+
}
|
|
1695
|
+
const firstReference = firstReferenceByContainerName.get(containerName);
|
|
1696
|
+
if (firstReference !== void 0) {
|
|
1697
|
+
issues.push({
|
|
1698
|
+
code: "custom",
|
|
1699
|
+
input: containerName,
|
|
1700
|
+
path,
|
|
1701
|
+
message: `The Container "${containerName}" is already referenced by "${firstReference.workerExportName}.exports.${firstReference.durableObjectExportName}". A Container can only be linked to one Durable Object.`
|
|
1702
|
+
});
|
|
1703
|
+
continue;
|
|
1704
|
+
}
|
|
1705
|
+
firstReferenceByContainerName.set(containerName, {
|
|
1706
|
+
workerExportName,
|
|
1707
|
+
durableObjectExportName
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
return issues;
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Resolve and validate loaded `cloudflare.config.ts` exports.
|
|
1715
|
+
*
|
|
1716
|
+
* Config inputs are resolved once by identity. Top-level Worker and Container
|
|
1717
|
+
* exports are also parsed once by identity. References are resolved only far
|
|
1718
|
+
* enough to replace them with resource names, then Container links are
|
|
1719
|
+
* validated across the exported resources.
|
|
1720
|
+
*/
|
|
1721
|
+
async function resolveAndValidateConfigExports(exports$2, ctx) {
|
|
1722
|
+
const resolveDefinition = createDefinitionResolver(ctx);
|
|
1723
|
+
const parsedResources = /* @__PURE__ */ new Map();
|
|
1724
|
+
const resolvedExports = {};
|
|
1725
|
+
for (const [name, input] of Object.entries(exports$2)) resolvedExports[name] = await resolveDefinition(input);
|
|
1726
|
+
const typeResult = ConfigExportsTypeSchema.safeParse(resolvedExports);
|
|
1727
|
+
if (!typeResult.success) return typeResult;
|
|
1728
|
+
const issues = [];
|
|
1729
|
+
const data = {};
|
|
1730
|
+
const resolvedSettings = resolvedExports.settings;
|
|
1731
|
+
const settingsResult = resolvedSettings ? InputSettingsSchema.safeParse(resolvedSettings) : void 0;
|
|
1732
|
+
if (settingsResult) if (settingsResult.success) data.settings = settingsResult.data;
|
|
1733
|
+
else issues.push(...prefixIssues(settingsResult.error.issues, "settings"));
|
|
1734
|
+
for (const [name, input] of Object.entries(exports$2)) {
|
|
1735
|
+
const resolved = resolvedExports[name];
|
|
1736
|
+
if (!isRecord(resolved)) continue;
|
|
1737
|
+
if (resolved.type !== "worker" && resolved.type !== "container") continue;
|
|
1738
|
+
let result = parsedResources.get(input);
|
|
1739
|
+
if (!result) {
|
|
1740
|
+
if (resolved.type === "worker") {
|
|
1741
|
+
const normalized = await normalizeConfigReferences(resolved, resolveDefinition, resolvedExports);
|
|
1742
|
+
issues.push(...prefixIssues(normalized.issues, name));
|
|
1743
|
+
result = InputWorkerSchema.safeParse(normalized.value);
|
|
1744
|
+
} else result = InputContainerSchema.safeParse(resolved);
|
|
1745
|
+
parsedResources.set(input, result);
|
|
1746
|
+
if (!result.success) issues.push(...prefixIssues(result.error.issues, name));
|
|
1747
|
+
}
|
|
1748
|
+
if (result.success) data[name] = result.data;
|
|
1749
|
+
}
|
|
1750
|
+
issues.push(...validateUniqueResourceNames(data), ...validateContainerExportLinks(data));
|
|
1751
|
+
return issues.length > 0 ? {
|
|
1752
|
+
success: false,
|
|
1753
|
+
error: new z.ZodError(issues)
|
|
1754
|
+
} : {
|
|
1755
|
+
success: true,
|
|
1756
|
+
data
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1352
1759
|
/**
|
|
1353
|
-
* Load a `cloudflare.config.ts`, resolve all exports, and validate
|
|
1760
|
+
* Load a `cloudflare.config.ts`, resolve all exports, and validate them.
|
|
1354
1761
|
*/
|
|
1355
1762
|
async function loadAndValidateConfig(configPath, ctx, options) {
|
|
1356
1763
|
const { exports: exports$2, dependencies } = await loadConfig(configPath, options);
|
|
1357
|
-
const resolved = {};
|
|
1358
|
-
for (const [name, value] of Object.entries(exports$2)) resolved[name] = await resolveExportDefinition(value, ctx);
|
|
1359
1764
|
return {
|
|
1360
|
-
result:
|
|
1765
|
+
result: await resolveAndValidateConfigExports(exports$2, ctx),
|
|
1361
1766
|
dependencies
|
|
1362
1767
|
};
|
|
1363
1768
|
}
|
|
1364
1769
|
|
|
1365
1770
|
//#endregion
|
|
1366
|
-
export { AnalyticsEngineDatasetBindingSchema, AssetsSchema, BindingSchema, BrowserBindingSchema,
|
|
1771
|
+
export { AnalyticsEngineDatasetBindingSchema, AssetsSchema, BindingSchema, BrowserBindingSchema, D1BindingSchema, DurableObjectCreatedExportSchema, DurableObjectDeletedExportSchema, DurableObjectExpectingTransferExportSchema, DurableObjectRenamedExportSchema, DurableObjectTransferredExportSchema, ExportSchema, FlagshipBindingSchema, HyperdriveBindingSchema, InputContainerSchema, InputSettingsSchema, InputWorkerSchema, KVBindingSchema, KnownBindingSchema, ModuleTypeSchema, OutputContainerSchema, OutputSettingsSchema, OutputWorkerSchema, QueueBindingSchema, R2BindingSchema, TailConsumerSchema, UnsafeBindingSchema, WorkerBindingSchema, WorkerEntrypointExportSchema, bindings, convertToWranglerConfig, defineContainer, defineSettings, defineWorker, exports$1 as exports, generateTypes, loadAndValidateConfig, loadConfig, registerConfigHooks, resolveAndValidateConfigExports, triggers, validateSingletonBindings };
|
|
@@ -193,12 +193,17 @@ function worker(options = {}) {
|
|
|
193
193
|
*
|
|
194
194
|
* @example
|
|
195
195
|
* ```typescript
|
|
196
|
-
* import { defineWorker, exports } from "@cloudflare/config";
|
|
196
|
+
* import { defineContainer, defineWorker, exports } from "@cloudflare/config";
|
|
197
|
+
*
|
|
198
|
+
* const myContainer = defineContainer({
|
|
199
|
+
* name: "my-container",
|
|
200
|
+
* image: { dockerfile: "./Dockerfile" },
|
|
201
|
+
* });
|
|
197
202
|
*
|
|
198
203
|
* export default defineWorker({
|
|
199
204
|
* exports: {
|
|
200
205
|
* MyDurableObject: exports.durableObject({ storage: "sqlite" }),
|
|
201
|
-
* MyContainerDO: exports.durableObject({ storage: "sqlite", container:
|
|
206
|
+
* MyContainerDO: exports.durableObject({ storage: "sqlite", container: myContainer }),
|
|
202
207
|
* OldClass: exports.durableObject({ state: "deleted" }),
|
|
203
208
|
* OldName: exports.durableObject({ state: "renamed", renamedTo: "NewName" }),
|
|
204
209
|
* Outgoing: exports.durableObject({ state: "transferred", transferredTo: "target-worker" }),
|
|
@@ -214,55 +219,36 @@ const exports = {
|
|
|
214
219
|
|
|
215
220
|
//#endregion
|
|
216
221
|
//#region src/definition.ts
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
* the result. A function config is invoked with {@link ConfigContext}.
|
|
221
|
-
*/
|
|
222
|
-
async function unwrap(config, ctx) {
|
|
223
|
-
return typeof config === "function" ? await config(ctx) : await config;
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Resolve any `cloudflare.config.ts` export to its plain config value.
|
|
227
|
-
*
|
|
228
|
-
* A `define*` helper stores its authored config plus `type` under the
|
|
229
|
-
* {@link DEFINITION} symbol; here we unwrap the config and stamp `type` back on.
|
|
230
|
-
* Every other export — a raw object/promise/function — is unwrapped as-is and
|
|
231
|
-
* already carries its own `type`. Discrimination happens afterwards via `type`.
|
|
232
|
-
*/
|
|
233
|
-
async function resolveExportDefinition(def, ctx) {
|
|
234
|
-
if (typeof def === "object" && def !== null && DEFINITION in def) {
|
|
235
|
-
const { config, type } = def[DEFINITION];
|
|
222
|
+
/** Add a config type while preserving its value, promise, or function shape. */
|
|
223
|
+
function addConfigType(config, type) {
|
|
224
|
+
function addType(value) {
|
|
236
225
|
return {
|
|
237
|
-
...
|
|
226
|
+
...value,
|
|
238
227
|
type
|
|
239
228
|
};
|
|
240
229
|
}
|
|
241
|
-
return
|
|
230
|
+
if (typeof config === "function") return (ctx) => {
|
|
231
|
+
const result = config(ctx);
|
|
232
|
+
return result instanceof Promise ? result.then(addType) : addType(result);
|
|
233
|
+
};
|
|
234
|
+
return config instanceof Promise ? config.then(addType) : addType(config);
|
|
242
235
|
}
|
|
236
|
+
/** Create a type-safe config helper for a particular export type. */
|
|
237
|
+
function createConfigDefiner(type) {
|
|
238
|
+
function define(config) {
|
|
239
|
+
return addConfigType(config, type);
|
|
240
|
+
}
|
|
241
|
+
return define;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/container-definition.ts
|
|
246
|
+
/** Declare a Container application. */
|
|
247
|
+
const defineContainer = createConfigDefiner("container");
|
|
243
248
|
|
|
244
249
|
//#endregion
|
|
245
250
|
//#region src/worker-definition.ts
|
|
246
|
-
|
|
247
|
-
return {
|
|
248
|
-
[DEFINITION]: {
|
|
249
|
-
config,
|
|
250
|
-
type: "worker"
|
|
251
|
-
},
|
|
252
|
-
durableObject(options) {
|
|
253
|
-
return {
|
|
254
|
-
type: "durable-object",
|
|
255
|
-
...options
|
|
256
|
-
};
|
|
257
|
-
},
|
|
258
|
-
worker(options) {
|
|
259
|
-
return {
|
|
260
|
-
type: "worker",
|
|
261
|
-
...options
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
}
|
|
251
|
+
const defineWorker = createConfigDefiner("worker");
|
|
266
252
|
|
|
267
253
|
//#endregion
|
|
268
254
|
//#region src/settings-definition.ts
|
|
@@ -270,12 +256,7 @@ function defineWorker(config) {
|
|
|
270
256
|
* Declare shared settings.
|
|
271
257
|
* Authored as a named `settings` export.
|
|
272
258
|
*/
|
|
273
|
-
|
|
274
|
-
return { [DEFINITION]: {
|
|
275
|
-
config,
|
|
276
|
-
type: "settings"
|
|
277
|
-
} };
|
|
278
|
-
}
|
|
259
|
+
const defineSettings = createConfigDefiner("settings");
|
|
279
260
|
|
|
280
261
|
//#endregion
|
|
281
|
-
export { triggers as a, exports as i, defineWorker as n, bindings as o,
|
|
262
|
+
export { triggers as a, exports as i, defineWorker as n, bindings as o, defineContainer as r, defineSettings as t };
|