@cloudflare/vitest-plugin 1.1.7 → 1.1.9

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.
@@ -325,7 +325,7 @@ function createFatalError$1(message, isJson, options) {
325
325
  __name$3(createFatalError$1, "createFatalError");
326
326
 
327
327
  //#endregion
328
- //#region ../workers-utils/dist/chunk-IQDQ5WRD.mjs
328
+ //#region ../workers-utils/dist/chunk-T5JQYOMX.mjs
329
329
  function hasKnownExportType(entry) {
330
330
  const type = entry?.type;
331
331
  return type === "durable-object" || type === "worker";
@@ -382,6 +382,48 @@ function getContainerDurableObjectClassNames(containers, exports$1) {
382
382
  return classNames;
383
383
  }
384
384
  __name$3(getContainerDurableObjectClassNames, "getContainerDurableObjectClassNames");
385
+ function getDurableObjectClassNameToUseSQLiteMap(migrations, exports$1) {
386
+ const durableObjectClassNameToUseSQLiteMap = /* @__PURE__ */ new Map();
387
+ (migrations ?? []).forEach((migration) => {
388
+ migration.deleted_classes?.forEach((deleted_class) => {
389
+ if (!durableObjectClassNameToUseSQLiteMap.delete(deleted_class)) throw new UserError$1(`Cannot apply deleted_classes migration to non-existent class ${deleted_class}`, { telemetryMessage: "durable object deleted class migration missing class" });
390
+ });
391
+ migration.renamed_classes?.forEach(({ from, to }) => {
392
+ const useSQLite = durableObjectClassNameToUseSQLiteMap.get(from);
393
+ if (useSQLite === void 0) throw new UserError$1(`Cannot apply renamed_classes migration to non-existent class ${from}`, { telemetryMessage: "durable object renamed class migration missing class" });
394
+ else {
395
+ durableObjectClassNameToUseSQLiteMap.delete(from);
396
+ durableObjectClassNameToUseSQLiteMap.set(to, useSQLite);
397
+ }
398
+ });
399
+ migration.new_classes?.forEach((new_class) => {
400
+ if (durableObjectClassNameToUseSQLiteMap.has(new_class)) throw new UserError$1(`Cannot apply new_classes migration to existing class ${new_class}`, { telemetryMessage: "durable object new class migration existing class" });
401
+ else durableObjectClassNameToUseSQLiteMap.set(new_class, false);
402
+ });
403
+ migration.new_sqlite_classes?.forEach((new_class) => {
404
+ if (durableObjectClassNameToUseSQLiteMap.has(new_class)) throw new UserError$1(`Cannot apply new_sqlite_classes migration to existing class ${new_class}`, { telemetryMessage: "durable object new sqlite class migration existing class" });
405
+ else durableObjectClassNameToUseSQLiteMap.set(new_class, true);
406
+ });
407
+ });
408
+ const durableObjectExports = getDurableObjectExports(exports$1 ?? {});
409
+ for (const [className, entry] of Object.entries(durableObjectExports)) {
410
+ if (entry.type !== "durable-object") continue;
411
+ if (entry.state === void 0 || entry.state === "created" || entry.state === "expecting-transfer") durableObjectClassNameToUseSQLiteMap.set(className, entry.storage === "sqlite");
412
+ }
413
+ return durableObjectClassNameToUseSQLiteMap;
414
+ }
415
+ __name$3(getDurableObjectClassNameToUseSQLiteMap, "getDurableObjectClassNameToUseSQLiteMap");
416
+ function validateDurableObjectContainerApplications(config$1, containers = getDurableObjectContainerApps(config$1.containers)) {
417
+ const allDOs = getDurableObjectClassNameToUseSQLiteMap(config$1.migrations, config$1.exports);
418
+ for (const container of containers) {
419
+ const maybeBoundDO = config$1.durable_objects.bindings.find((durableObject) => durableObject.class_name === container.class_name);
420
+ const useSQLite = allDOs.get(container.class_name);
421
+ if (useSQLite === void 0 && maybeBoundDO === void 0) throw new UserError$1(`The container class_name ${container.class_name} does not match any durable object class_name defined in your Wrangler config file. Note that the durable object must be defined in the same script as the container.`, { telemetryMessage: "no DO defined that matches container class_name" });
422
+ if (maybeBoundDO?.script_name !== void 0) throw new UserError$1(`The container ${container.name} is referencing the durable object ${container.class_name}, which appears to be defined on the ${maybeBoundDO.script_name} Worker instead (via the 'script_name' field). You cannot configure a container on a Durable Object that is defined in another Worker.`, { telemetryMessage: "container class_name refers to an external durable object" });
423
+ if (useSQLite === false) throw new UserError$1(`The container ${container.name} references Durable Object class ${container.class_name}, which uses the legacy KV storage backend. Durable Object-managed Containers require SQLite-backed Durable Objects.`, { telemetryMessage: "durable object container class uses legacy storage" });
424
+ }
425
+ }
426
+ __name$3(validateDurableObjectContainerApplications, "validateDurableObjectContainerApplications");
385
427
  function createScanner(text, ignoreTrivia = false) {
386
428
  const len = text.length;
387
429
  let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
@@ -2745,8 +2787,8 @@ function formatConfigSnippet(snippet, configPath, formatted = true) {
2745
2787
  __name$3(formatConfigSnippet, "formatConfigSnippet");
2746
2788
 
2747
2789
  //#endregion
2748
- //#region ../workers-utils/dist/chunk-S3ANQ67D.mjs
2749
- var DEFAULT_COMPAT_DATE = "2026-09-10";
2790
+ //#region ../workers-utils/dist/chunk-KBTXSRPS.mjs
2791
+ var DEFAULT_COMPAT_DATE = "2026-09-11";
2750
2792
  function assertNever(_value) {}
2751
2793
  __name$3(assertNever, "assertNever");
2752
2794
  function mapWorkerMetadataBindings(bindings) {
@@ -42123,7 +42165,7 @@ function normalizeAndValidateEnvironment(diagnostics, configPath, rawEnv, isDisp
42123
42165
  warnIfDurableObjectsHaveNoLifecycleConfig(diagnostics, environment.durable_objects, environment.migrations, environment.exports, configPath);
42124
42166
  errorIfMigrationsAndExportsBothSet(diagnostics, environment.migrations, environment.exports);
42125
42167
  const containersDeclaredElsewhere = rawConfig !== void 0 ? rawConfig.containers !== void 0 : Object.values("env" in rawEnv ? rawEnv.env ?? {} : {}).some((rawNamedEnv) => rawNamedEnv?.containers !== void 0);
42126
- validateContainerExportLinks(diagnostics, environment.containers, environment.exports, containersDeclaredElsewhere);
42168
+ validateContainerExportLinks$1(diagnostics, environment.containers, environment.exports, containersDeclaredElsewhere);
42127
42169
  if (envName !== "top level") validateAdditionalProperties(diagnostics, "env." + envName, Object.keys(rawEnv), Object.keys(environment));
42128
42170
  return environment;
42129
42171
  }
@@ -44333,7 +44375,7 @@ function errorIfMigrationsAndExportsBothSet(diagnostics, migrations, exports$1)
44333
44375
  if (migrations.length > 0 && exports$1 !== void 0 && Object.values(exports$1).some((entry) => entry.type === "durable-object")) diagnostics.errors.push(`\`migrations\` and \`exports\` are mutually exclusive. Choose one or the other to declare your Durable Object lifecycle, but not both.`);
44334
44376
  }
44335
44377
  __name$3(errorIfMigrationsAndExportsBothSet, "errorIfMigrationsAndExportsBothSet");
44336
- function validateContainerExportLinks(diagnostics, containers, exports$1, containersDeclaredElsewhere) {
44378
+ function validateContainerExportLinks$1(diagnostics, containers, exports$1, containersDeclaredElsewhere) {
44337
44379
  if (containers !== void 0 && !Array.isArray(containers)) return;
44338
44380
  if (containers === void 0 && containersDeclaredElsewhere) return;
44339
44381
  const containersByName = /* @__PURE__ */ new Map();
@@ -44393,7 +44435,7 @@ function validateContainerExportLinks(diagnostics, containers, exports$1, contai
44393
44435
  if (referencedContainerName === void 0 && exportEntry !== void 0 && "storage" in exportEntry && exportEntry.storage === "legacy-kv") diagnostics.errors.push(`The container "${container.name}" sets "class_name" to "${container.class_name}", but "exports.${container.class_name}.storage" is "legacy-kv". Containers are not supported on Durable Objects using the "legacy-kv" storage backend.`);
44394
44436
  }
44395
44437
  }
44396
- __name$3(validateContainerExportLinks, "validateContainerExportLinks");
44438
+ __name$3(validateContainerExportLinks$1, "validateContainerExportLinks");
44397
44439
  var validatePythonModules = /* @__PURE__ */ __name$3((diagnostics, field, value, topLevelEnv) => {
44398
44440
  if (value === void 0) return true;
44399
44441
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
@@ -60500,7 +60542,7 @@ __name$1(createWorkerUploadForm, "createWorkerUploadForm");
60500
60542
  //#endregion
60501
60543
  //#region ../remote-bindings/dist/index.mjs
60502
60544
  var import_undici = require_undici();
60503
- var version = "0.0.22";
60545
+ var version = "0.0.24";
60504
60546
  var NoDefaultValueProvided = class extends UserError$1 {
60505
60547
  constructor() {
60506
60548
  super("This command cannot be run in a non-interactive context", { telemetryMessage: "remote bindings prompt default missing" });
@@ -61667,6 +61709,136 @@ function validateSingletonBindings(env$2, ctx) {
61667
61709
  });
61668
61710
  }
61669
61711
  const EnvSchema = z$1.record(z$1.string(), BindingSchema).superRefine(validateSingletonBindings).optional();
61712
+ const ContainerImageDockerfileSchema = z$1.strictObject({
61713
+ dockerfile: z$1.string().min(1),
61714
+ buildContext: z$1.string().optional(),
61715
+ buildVars: z$1.record(z$1.string(), z$1.string()).optional()
61716
+ });
61717
+ const ContainerImageReferenceSchema = z$1.strictObject({ reference: z$1.string().min(1) });
61718
+ const ContainerImageLocalReferenceSchema = z$1.strictObject({ localReference: z$1.string().min(1) });
61719
+ const InputContainerImageSchema = z$1.union([ContainerImageDockerfileSchema, ContainerImageReferenceSchema]);
61720
+ const OutputContainerImageSchema = z$1.union([ContainerImageReferenceSchema, ContainerImageLocalReferenceSchema]);
61721
+ const VALID_ROLLOUT_STEP_PERCENTAGES = new Set([
61722
+ 5,
61723
+ 10,
61724
+ 20,
61725
+ 25,
61726
+ 50,
61727
+ 100
61728
+ ]);
61729
+ const ContainerRolloutStepPercentageSchema = z$1.union([z$1.number(), z$1.array(z$1.number())]).superRefine((stepPercentage, ctx) => {
61730
+ if (typeof stepPercentage === "number") {
61731
+ if (!VALID_ROLLOUT_STEP_PERCENTAGES.has(stepPercentage)) ctx.addIssue({
61732
+ code: "custom",
61733
+ message: "A rollout step percentage must be one of 5, 10, 20, 25, 50, or 100"
61734
+ });
61735
+ return;
61736
+ }
61737
+ if (stepPercentage.length === 0) {
61738
+ ctx.addIssue({
61739
+ code: "custom",
61740
+ message: "A rollout must contain at least one step percentage"
61741
+ });
61742
+ return;
61743
+ }
61744
+ for (const [index, step] of stepPercentage.entries()) {
61745
+ if (step < 10 || step > 100) ctx.addIssue({
61746
+ code: "custom",
61747
+ path: [index],
61748
+ message: "Rollout step percentages must be between 10 and 100"
61749
+ });
61750
+ const previousStep = stepPercentage[index - 1];
61751
+ if (previousStep !== void 0 && step < previousStep) ctx.addIssue({
61752
+ code: "custom",
61753
+ path: [index],
61754
+ message: "Rollout step percentages must be in ascending order"
61755
+ });
61756
+ }
61757
+ const lastIndex = stepPercentage.length - 1;
61758
+ if (stepPercentage[lastIndex] !== 100) ctx.addIssue({
61759
+ code: "custom",
61760
+ path: [lastIndex],
61761
+ message: "The final rollout step percentage must be 100"
61762
+ });
61763
+ });
61764
+ function validateContainerRelationships(container, ctx) {
61765
+ const stepPercentage = container.rollout?.stepPercentage;
61766
+ if (Array.isArray(stepPercentage) && container.maxInstances !== void 0 && stepPercentage.length > container.maxInstances) ctx.addIssue({
61767
+ code: "custom",
61768
+ path: ["rollout", "stepPercentage"],
61769
+ message: "A rollout cannot contain more steps than the maximum number of instances"
61770
+ });
61771
+ }
61772
+ const ContainerObservabilityBaseSchema = z$1.strictObject({
61773
+ enabled: z$1.boolean().optional(),
61774
+ logs: z$1.strictObject({ enabled: z$1.boolean().optional() }).optional()
61775
+ });
61776
+ const ContainerObservabilitySchema = z$1.union([ContainerObservabilityBaseSchema.extend({ targetInstancePercentage: z$1.number().min(0).max(100).optional() }), ContainerObservabilityBaseSchema.extend({ targetInstanceCount: z$1.number().int().nonnegative().optional() })]);
61777
+ const BaseContainerSchema = z$1.strictObject({
61778
+ type: z$1.literal("container"),
61779
+ name: z$1.string().min(1),
61780
+ observability: ContainerObservabilitySchema.optional(),
61781
+ unsafe: z$1.record(z$1.string(), z$1.unknown()).optional()
61782
+ });
61783
+ const StandardContainerBaseSchema = BaseContainerSchema.extend({
61784
+ maxInstances: z$1.number().int().nonnegative().default(20),
61785
+ instanceType: z$1.union([z$1.enum([
61786
+ "basic",
61787
+ "lite",
61788
+ "standard-1",
61789
+ "standard-2",
61790
+ "standard-3",
61791
+ "standard-4"
61792
+ ]), z$1.strictObject({
61793
+ vcpu: z$1.number().min(.0625).optional(),
61794
+ memoryMib: z$1.number().nonnegative().optional(),
61795
+ diskMb: z$1.number().nonnegative().optional()
61796
+ })]).optional(),
61797
+ schedulingPolicy: z$1.enum(["default", "regional"]).optional(),
61798
+ ssh: z$1.strictObject({
61799
+ enabled: z$1.boolean(),
61800
+ port: z$1.number().int().min(1).max(65535).optional()
61801
+ }).optional(),
61802
+ authorizedKeys: z$1.array(z$1.strictObject({
61803
+ name: z$1.string(),
61804
+ publicKey: z$1.string()
61805
+ })).optional(),
61806
+ constraints: z$1.strictObject({
61807
+ regions: z$1.array(z$1.enum([
61808
+ "ENAM",
61809
+ "WNAM",
61810
+ "EEUR",
61811
+ "WEUR",
61812
+ "APAC",
61813
+ "SAM",
61814
+ "ME",
61815
+ "OC",
61816
+ "AFR"
61817
+ ])).optional(),
61818
+ jurisdiction: z$1.enum(["eu", "fedramp"]).optional()
61819
+ }).optional(),
61820
+ rollout: z$1.strictObject({
61821
+ kind: z$1.enum([
61822
+ "full-auto",
61823
+ "none",
61824
+ "full-manual"
61825
+ ]).optional(),
61826
+ stepPercentage: ContainerRolloutStepPercentageSchema.optional(),
61827
+ activeGracePeriod: z$1.number().nonnegative().optional()
61828
+ }).optional()
61829
+ });
61830
+ const DurableObjectContainerBaseSchema = BaseContainerSchema.extend({ schedulingPolicy: z$1.literal("durable-object") });
61831
+ /**
61832
+ * Input Container schema — validates user-authored `cloudflare.config.ts`
61833
+ * Container exports. Dockerfiles are built by the consuming build tool.
61834
+ */
61835
+ const InputContainerSchema = z$1.union([StandardContainerBaseSchema.extend({ image: InputContainerImageSchema }).superRefine(validateContainerRelationships), DurableObjectContainerBaseSchema.extend({ images: z$1.record(z$1.string(), InputContainerImageSchema).optional() })]);
61836
+ /**
61837
+ * Output Container schema — validates Container configs in the Build Output
61838
+ * Specification, after any Dockerfile has been built into a local or remote
61839
+ * image reference.
61840
+ */
61841
+ const OutputContainerSchema = z$1.union([StandardContainerBaseSchema.extend({ image: OutputContainerImageSchema }).superRefine(validateContainerRelationships), DurableObjectContainerBaseSchema.extend({ images: z$1.record(z$1.string(), OutputContainerImageSchema).optional() })]);
61670
61842
  const DurableObjectCreatedExportSchema = z$1.strictObject({
61671
61843
  type: z$1.literal("durable-object"),
61672
61844
  state: z$1.literal("created").optional(),
@@ -61845,8 +62017,13 @@ const InputSettingsSchema = z$1.strictObject({
61845
62017
  * Build Output Specification. Adds the `mode` the build was produced in.
61846
62018
  */
61847
62019
  const OutputSettingsSchema = InputSettingsSchema.extend({ mode: z$1.string().optional() });
62020
+ const DEFAULT_EXPORT_NAME = "default";
61848
62021
  const SETTINGS_EXPORT_NAME = "settings";
61849
- const SUPPORTED_EXPORT_TYPES = new Set(["worker", "settings"]);
62022
+ const SUPPORTED_EXPORT_TYPES = new Set([
62023
+ "container",
62024
+ "worker",
62025
+ "settings"
62026
+ ]);
61850
62027
  function invalidConfigExportMessage(exportName) {
61851
62028
  return `The \`${exportName}\` export is not a supported export type. Move constants, helper functions, and other unsupported exports to a separate module.`;
61852
62029
  }
@@ -61863,6 +62040,15 @@ const ConfigExportsTypeSchema = z$1.record(z$1.string(), z$1.unknown()).check((c
61863
62040
  });
61864
62041
  continue;
61865
62042
  }
62043
+ if (key === DEFAULT_EXPORT_NAME && type !== "worker") {
62044
+ ctx.issues.push({
62045
+ code: "custom",
62046
+ input: value,
62047
+ path: [key],
62048
+ message: `The \`${DEFAULT_EXPORT_NAME}\` export is reserved for a \`worker\` config; found a \`${type}\` config.`
62049
+ });
62050
+ continue;
62051
+ }
61866
62052
  const isSettingsName = key === SETTINGS_EXPORT_NAME;
61867
62053
  const isSettingsType = type === "settings";
61868
62054
  if (isSettingsType && !isSettingsName) ctx.issues.push({
@@ -62011,18 +62197,26 @@ function createFatalError(message, isJson, options) {
62011
62197
  return new FatalError(`${message}`, options);
62012
62198
  }
62013
62199
  __name(createFatalError, "createFatalError");
62200
+ const ROLLOUT_KIND_MAP = {
62201
+ "full-auto": "full_auto",
62202
+ "full-manual": "full_manual",
62203
+ none: "none"
62204
+ };
62014
62205
  /**
62015
62206
  * Convert a parsed `@cloudflare/config` config into a Wrangler `RawConfig`.
62016
62207
  *
62017
- * The caller is responsible for unwrapping any function/promise wrapper around
62018
- * the config and validating it against `InputWorkerSchema` before passing it in.
62208
+ * The caller is responsible for unwrapping any function/promise wrappers and
62209
+ * validating the configs against their corresponding input schemas before
62210
+ * passing them in.
62019
62211
  *
62020
62212
  * @param workerConfig The parsed (post-validation) Worker config.
62021
62213
  * @param settingsConfig The optional parsed settings config, whose fields
62022
62214
  * are merged onto the result.
62215
+ * @param containerExports The parsed Container exports to include in the
62216
+ * result.
62023
62217
  * @returns The corresponding Wrangler `RawConfig`.
62024
62218
  */
62025
- function convertToWranglerConfig(workerConfig, settingsConfig) {
62219
+ function convertToWranglerConfig(workerConfig, settingsConfig, containerExports = []) {
62026
62220
  const result = {};
62027
62221
  convertTopLevel(workerConfig, result);
62028
62222
  convertBindingsAndAssets(workerConfig, result);
@@ -62031,8 +62225,50 @@ function convertToWranglerConfig(workerConfig, settingsConfig) {
62031
62225
  convertTriggers(workerConfig, result);
62032
62226
  convertTailConsumers(workerConfig, result);
62033
62227
  if (settingsConfig !== void 0) convertSettings(settingsConfig, result);
62228
+ if (containerExports.length > 0) result.containers = containerExports.map((container) => convertContainer(container));
62034
62229
  return result;
62035
62230
  }
62231
+ function convertContainer(container) {
62232
+ if (container.schedulingPolicy === "durable-object") throw new UserError("Durable Object-managed Containers are not currently supported by `convertToWranglerConfig()`.", { telemetryMessage: false });
62233
+ const converted = { name: container.name };
62234
+ if (container.observability !== void 0) converted.observability = convertContainerObservability(container.observability);
62235
+ if (container.unsafe !== void 0) converted.unsafe = container.unsafe;
62236
+ converted.image = "dockerfile" in container.image ? container.image.dockerfile : container.image.reference;
62237
+ converted.max_instances = container.maxInstances;
62238
+ if ("dockerfile" in container.image) {
62239
+ if (container.image.buildContext !== void 0) converted.image_build_context = container.image.buildContext;
62240
+ if (container.image.buildVars !== void 0) converted.image_vars = container.image.buildVars;
62241
+ }
62242
+ if (container.instanceType !== void 0) if (typeof container.instanceType === "string") converted.instance_type = container.instanceType;
62243
+ else {
62244
+ const instanceType = {};
62245
+ if (container.instanceType.vcpu !== void 0) instanceType.vcpu = container.instanceType.vcpu;
62246
+ if (container.instanceType.memoryMib !== void 0) instanceType.memory_mib = container.instanceType.memoryMib;
62247
+ if (container.instanceType.diskMb !== void 0) instanceType.disk_mb = container.instanceType.diskMb;
62248
+ converted.instance_type = instanceType;
62249
+ }
62250
+ if (container.schedulingPolicy !== void 0) converted.scheduling_policy = container.schedulingPolicy;
62251
+ if (container.ssh !== void 0) converted.ssh = container.ssh;
62252
+ if (container.authorizedKeys !== void 0) converted.authorized_keys = container.authorizedKeys.map(({ name, publicKey }) => ({
62253
+ name,
62254
+ public_key: publicKey
62255
+ }));
62256
+ if (container.constraints !== void 0) converted.constraints = container.constraints;
62257
+ if (container.rollout !== void 0) {
62258
+ if (container.rollout.kind !== void 0) converted.rollout_kind = ROLLOUT_KIND_MAP[container.rollout.kind];
62259
+ if (container.rollout.stepPercentage !== void 0) converted.rollout_step_percentage = container.rollout.stepPercentage;
62260
+ if (container.rollout.activeGracePeriod !== void 0) converted.rollout_active_grace_period = container.rollout.activeGracePeriod;
62261
+ }
62262
+ return converted;
62263
+ }
62264
+ function convertContainerObservability(observability) {
62265
+ const converted = {};
62266
+ if (observability.enabled !== void 0) converted.enabled = observability.enabled;
62267
+ if (observability.logs !== void 0) converted.logs = observability.logs;
62268
+ if ("targetInstancePercentage" in observability && observability.targetInstancePercentage !== void 0) converted.target_instance_percentage = observability.targetInstancePercentage;
62269
+ if ("targetInstanceCount" in observability && observability.targetInstanceCount !== void 0) converted.target_instance_count = observability.targetInstanceCount;
62270
+ return converted;
62271
+ }
62036
62272
  /**
62037
62273
  * Merge a parsed settings config's fields (`account_id`, `compliance_region`)
62038
62274
  * onto an existing Wrangler `RawConfig`.
@@ -62700,6 +62936,9 @@ function isRecord(value) {
62700
62936
  function isConfigReference(value) {
62701
62937
  return typeof value === "function" || isRecord(value);
62702
62938
  }
62939
+ function normalizeConfigReference(reference, resolved, expectedType) {
62940
+ return isRecord(resolved) && resolved.type === expectedType && typeof resolved.name === "string" ? resolved.name : reference;
62941
+ }
62703
62942
  function createDefinitionResolver(ctx) {
62704
62943
  const resolvedDefinitions = /* @__PURE__ */ new Map();
62705
62944
  return (input) => {
@@ -62720,7 +62959,7 @@ async function normalizeWorkerReferences(resolved, resolveDefinition) {
62720
62959
  const target = await resolveDefinition(binding.worker);
62721
62960
  env$2[bindingName] = {
62722
62961
  ...binding,
62723
- worker: isRecord(target) ? target.name : void 0
62962
+ worker: normalizeConfigReference(binding.worker, target, "worker")
62724
62963
  };
62725
62964
  }
62726
62965
  return {
@@ -62728,22 +62967,151 @@ async function normalizeWorkerReferences(resolved, resolveDefinition) {
62728
62967
  env: env$2
62729
62968
  };
62730
62969
  }
62970
+ async function normalizeContainerReferences(resolved, resolveDefinition, resolvedExports) {
62971
+ const issues = [];
62972
+ if (!isRecord(resolved) || !isRecord(resolved.exports)) return {
62973
+ value: resolved,
62974
+ issues
62975
+ };
62976
+ const workerExports = { ...resolved.exports };
62977
+ for (const [exportName, workerExport] of Object.entries(workerExports)) {
62978
+ if (!isRecord(workerExport) || workerExport.type !== "durable-object" || workerExport.container === void 0) continue;
62979
+ const reference = workerExport.container;
62980
+ if (typeof reference === "string") {
62981
+ issues.push({
62982
+ code: "custom",
62983
+ input: reference,
62984
+ path: [
62985
+ "exports",
62986
+ exportName,
62987
+ "container"
62988
+ ],
62989
+ message: "Container provided as a string. Reference an exported Container definition instead."
62990
+ });
62991
+ workerExports[exportName] = {
62992
+ ...workerExport,
62993
+ container: void 0
62994
+ };
62995
+ continue;
62996
+ }
62997
+ const target = await resolveDefinition(reference);
62998
+ if (isRecord(target) && target.type === "container" && typeof target.name === "string" && !Object.values(resolvedExports).includes(target)) {
62999
+ issues.push({
63000
+ code: "custom",
63001
+ input: reference,
63002
+ path: [
63003
+ "exports",
63004
+ exportName,
63005
+ "container"
63006
+ ],
63007
+ message: `The referenced Container "${target.name}" is not exported.`
63008
+ });
63009
+ workerExports[exportName] = {
63010
+ ...workerExport,
63011
+ container: void 0
63012
+ };
63013
+ continue;
63014
+ }
63015
+ workerExports[exportName] = {
63016
+ ...workerExport,
63017
+ container: normalizeConfigReference(reference, target, "container")
63018
+ };
63019
+ }
63020
+ return {
63021
+ value: {
63022
+ ...resolved,
63023
+ exports: workerExports
63024
+ },
63025
+ issues
63026
+ };
63027
+ }
63028
+ async function normalizeConfigReferences(resolved, resolveDefinition, resolvedExports) {
63029
+ return normalizeContainerReferences(await normalizeWorkerReferences(resolved, resolveDefinition), resolveDefinition, resolvedExports);
63030
+ }
62731
63031
  function prefixIssues(issues, prefix) {
62732
63032
  return issues.map((issue$1) => ({
62733
63033
  ...issue$1,
62734
63034
  path: [prefix, ...issue$1.path]
62735
63035
  }));
62736
63036
  }
63037
+ function validateUniqueResourceNames(configExports) {
63038
+ const issues = [];
63039
+ const exportNameByResourceName = {
63040
+ container: /* @__PURE__ */ new Map(),
63041
+ worker: /* @__PURE__ */ new Map()
63042
+ };
63043
+ for (const [exportName, config$1] of Object.entries(configExports)) {
63044
+ if (config$1.type !== "container" && config$1.type !== "worker") continue;
63045
+ const resourceType = config$1.type === "container" ? "Container" : "Worker";
63046
+ const exportNames = exportNameByResourceName[config$1.type];
63047
+ const previousExportName = exportNames.get(config$1.name);
63048
+ if (previousExportName !== void 0) {
63049
+ issues.push({
63050
+ code: "custom",
63051
+ input: config$1.name,
63052
+ path: [exportName, "name"],
63053
+ message: `The ${resourceType} name "${config$1.name}" is also used by the "${previousExportName}" export. ${resourceType} names must be unique.`
63054
+ });
63055
+ continue;
63056
+ }
63057
+ exportNames.set(config$1.name, exportName);
63058
+ }
63059
+ return issues;
63060
+ }
63061
+ function validateContainerExportLinks(configExports) {
63062
+ const issues = [];
63063
+ const containerNames = /* @__PURE__ */ new Set();
63064
+ for (const config$1 of Object.values(configExports)) if (config$1.type === "container") containerNames.add(config$1.name);
63065
+ const firstReferenceByContainerName = /* @__PURE__ */ new Map();
63066
+ for (const [workerExportName, config$1] of Object.entries(configExports)) {
63067
+ if (config$1.type !== "worker") continue;
63068
+ for (const [durableObjectExportName, workerExport] of Object.entries(config$1.exports ?? {})) {
63069
+ if (workerExport.type !== "durable-object" || !("container" in workerExport) || workerExport.container === void 0) continue;
63070
+ const containerName = workerExport.container;
63071
+ const path$3 = [
63072
+ workerExportName,
63073
+ "exports",
63074
+ durableObjectExportName,
63075
+ "container"
63076
+ ];
63077
+ if (!containerNames.has(containerName)) {
63078
+ issues.push({
63079
+ code: "custom",
63080
+ input: containerName,
63081
+ path: path$3,
63082
+ message: `The Container "${containerName}" is not exported from this configuration.`
63083
+ });
63084
+ continue;
63085
+ }
63086
+ const firstReference = firstReferenceByContainerName.get(containerName);
63087
+ if (firstReference !== void 0) {
63088
+ issues.push({
63089
+ code: "custom",
63090
+ input: containerName,
63091
+ path: path$3,
63092
+ message: `The Container "${containerName}" is already referenced by "${firstReference.workerExportName}.exports.${firstReference.durableObjectExportName}". A Container can only be linked to one Durable Object.`
63093
+ });
63094
+ continue;
63095
+ }
63096
+ firstReferenceByContainerName.set(containerName, {
63097
+ workerExportName,
63098
+ durableObjectExportName
63099
+ });
63100
+ }
63101
+ }
63102
+ return issues;
63103
+ }
62737
63104
  /**
62738
63105
  * Resolve and validate loaded `cloudflare.config.ts` exports.
62739
63106
  *
62740
- * Config inputs are resolved once by identity. Top-level Worker exports are
62741
- * also parsed once by identity; unexported references are resolved only far
62742
- * enough to replace the reference with the Worker's name.
63107
+ * Config inputs are resolved once by identity. Top-level Worker and Container
63108
+ * exports are also parsed once by identity. References are resolved only far
63109
+ * enough to replace them with resource names, then Container links are
63110
+ * validated across the exported resources.
62743
63111
  */
62744
63112
  async function resolveAndValidateConfigExports(exports$2, ctx) {
62745
63113
  const resolveDefinition = createDefinitionResolver(ctx);
62746
- const parsedWorkers = /* @__PURE__ */ new Map();
63114
+ const parsedResources = /* @__PURE__ */ new Map();
62747
63115
  const resolvedExports = {};
62748
63116
  for (const [name, input] of Object.entries(exports$2)) resolvedExports[name] = await resolveDefinition(input);
62749
63117
  const typeResult = ConfigExportsTypeSchema.safeParse(resolvedExports);
@@ -62757,17 +63125,20 @@ async function resolveAndValidateConfigExports(exports$2, ctx) {
62757
63125
  for (const [name, input] of Object.entries(exports$2)) {
62758
63126
  const resolved = resolvedExports[name];
62759
63127
  if (!isRecord(resolved)) continue;
62760
- if (resolved.type === "worker") {
62761
- let result = parsedWorkers.get(input);
62762
- if (!result) {
62763
- result = InputWorkerSchema.safeParse(await normalizeWorkerReferences(resolved, resolveDefinition));
62764
- parsedWorkers.set(input, result);
62765
- if (!result.success) issues.push(...prefixIssues(result.error.issues, name));
62766
- }
62767
- if (result.success) data[name] = result.data;
62768
- continue;
62769
- }
62770
- }
63128
+ if (resolved.type !== "worker" && resolved.type !== "container") continue;
63129
+ let result = parsedResources.get(input);
63130
+ if (!result) {
63131
+ if (resolved.type === "worker") {
63132
+ const normalized = await normalizeConfigReferences(resolved, resolveDefinition, resolvedExports);
63133
+ issues.push(...prefixIssues(normalized.issues, name));
63134
+ result = InputWorkerSchema.safeParse(normalized.value);
63135
+ } else result = InputContainerSchema.safeParse(resolved);
63136
+ parsedResources.set(input, result);
63137
+ if (!result.success) issues.push(...prefixIssues(result.error.issues, name));
63138
+ }
63139
+ if (result.success) data[name] = result.data;
63140
+ }
63141
+ issues.push(...validateUniqueResourceNames(data), ...validateContainerExportLinks(data));
62771
63142
  return issues.length > 0 ? {
62772
63143
  success: false,
62773
63144
  error: new z$1.ZodError(issues)