@cloudflare/vite-plugin 1.54.8 → 1.54.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.
package/dist/index.mjs CHANGED
@@ -137,7 +137,7 @@ function createFatalError$1(message, isJson, options) {
137
137
  __name$6(createFatalError$1, "createFatalError");
138
138
 
139
139
  //#endregion
140
- //#region ../workers-utils/dist/chunk-R5MIV2EH.mjs
140
+ //#region ../workers-utils/dist/chunk-T5JQYOMX.mjs
141
141
  function hasKnownExportType(entry) {
142
142
  const type = entry?.type;
143
143
  return type === "durable-object" || type === "worker";
@@ -225,9 +225,9 @@ function getDurableObjectClassNameToUseSQLiteMap(migrations, exports$1) {
225
225
  return durableObjectClassNameToUseSQLiteMap;
226
226
  }
227
227
  __name$6(getDurableObjectClassNameToUseSQLiteMap, "getDurableObjectClassNameToUseSQLiteMap");
228
- function validateDurableObjectContainerApplications(config$2) {
228
+ function validateDurableObjectContainerApplications(config$2, containers = getDurableObjectContainerApps(config$2.containers)) {
229
229
  const allDOs = getDurableObjectClassNameToUseSQLiteMap(config$2.migrations, config$2.exports);
230
- for (const container of getDurableObjectContainerApps(config$2.containers)) {
230
+ for (const container of containers) {
231
231
  const maybeBoundDO = config$2.durable_objects.bindings.find((durableObject) => durableObject.class_name === container.class_name);
232
232
  const useSQLite = allDOs.get(container.class_name);
233
233
  if (useSQLite === void 0 && maybeBoundDO === void 0) throw new UserError(`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" });
@@ -41939,7 +41939,7 @@ function normalizeAndValidateEnvironment(diagnostics, configPath, rawEnv, isDisp
41939
41939
  warnIfDurableObjectsHaveNoLifecycleConfig(diagnostics, environment.durable_objects, environment.migrations, environment.exports, configPath);
41940
41940
  errorIfMigrationsAndExportsBothSet(diagnostics, environment.migrations, environment.exports);
41941
41941
  const containersDeclaredElsewhere = rawConfig !== void 0 ? rawConfig.containers !== void 0 : Object.values("env" in rawEnv ? rawEnv.env ?? {} : {}).some((rawNamedEnv) => rawNamedEnv?.containers !== void 0);
41942
- validateContainerExportLinks(diagnostics, environment.containers, environment.exports, containersDeclaredElsewhere);
41942
+ validateContainerExportLinks$1(diagnostics, environment.containers, environment.exports, containersDeclaredElsewhere);
41943
41943
  if (envName !== "top level") validateAdditionalProperties(diagnostics, "env." + envName, Object.keys(rawEnv), Object.keys(environment));
41944
41944
  return environment;
41945
41945
  }
@@ -44149,7 +44149,7 @@ function errorIfMigrationsAndExportsBothSet(diagnostics, migrations, exports$1)
44149
44149
  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.`);
44150
44150
  }
44151
44151
  __name$6(errorIfMigrationsAndExportsBothSet, "errorIfMigrationsAndExportsBothSet");
44152
- function validateContainerExportLinks(diagnostics, containers, exports$1, containersDeclaredElsewhere) {
44152
+ function validateContainerExportLinks$1(diagnostics, containers, exports$1, containersDeclaredElsewhere) {
44153
44153
  if (containers !== void 0 && !Array.isArray(containers)) return;
44154
44154
  if (containers === void 0 && containersDeclaredElsewhere) return;
44155
44155
  const containersByName = /* @__PURE__ */ new Map();
@@ -44209,7 +44209,7 @@ function validateContainerExportLinks(diagnostics, containers, exports$1, contai
44209
44209
  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.`);
44210
44210
  }
44211
44211
  }
44212
- __name$6(validateContainerExportLinks, "validateContainerExportLinks");
44212
+ __name$6(validateContainerExportLinks$1, "validateContainerExportLinks");
44213
44213
  var validatePythonModules = /* @__PURE__ */ __name$6((diagnostics, field, value, topLevelEnv) => {
44214
44214
  if (value === void 0) return true;
44215
44215
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
@@ -55504,6 +55504,136 @@ function validateSingletonBindings(env$3, ctx) {
55504
55504
  });
55505
55505
  }
55506
55506
  const EnvSchema = record(string(), BindingSchema).superRefine(validateSingletonBindings).optional();
55507
+ const ContainerImageDockerfileSchema = strictObject({
55508
+ dockerfile: string().min(1),
55509
+ buildContext: string().optional(),
55510
+ buildVars: record(string(), string()).optional()
55511
+ });
55512
+ const ContainerImageReferenceSchema = strictObject({ reference: string().min(1) });
55513
+ const ContainerImageLocalReferenceSchema = strictObject({ localReference: string().min(1) });
55514
+ const InputContainerImageSchema = union([ContainerImageDockerfileSchema, ContainerImageReferenceSchema]);
55515
+ const OutputContainerImageSchema = union([ContainerImageReferenceSchema, ContainerImageLocalReferenceSchema]);
55516
+ const VALID_ROLLOUT_STEP_PERCENTAGES = new Set([
55517
+ 5,
55518
+ 10,
55519
+ 20,
55520
+ 25,
55521
+ 50,
55522
+ 100
55523
+ ]);
55524
+ const ContainerRolloutStepPercentageSchema = union([number(), array(number())]).superRefine((stepPercentage, ctx) => {
55525
+ if (typeof stepPercentage === "number") {
55526
+ if (!VALID_ROLLOUT_STEP_PERCENTAGES.has(stepPercentage)) ctx.addIssue({
55527
+ code: "custom",
55528
+ message: "A rollout step percentage must be one of 5, 10, 20, 25, 50, or 100"
55529
+ });
55530
+ return;
55531
+ }
55532
+ if (stepPercentage.length === 0) {
55533
+ ctx.addIssue({
55534
+ code: "custom",
55535
+ message: "A rollout must contain at least one step percentage"
55536
+ });
55537
+ return;
55538
+ }
55539
+ for (const [index, step] of stepPercentage.entries()) {
55540
+ if (step < 10 || step > 100) ctx.addIssue({
55541
+ code: "custom",
55542
+ path: [index],
55543
+ message: "Rollout step percentages must be between 10 and 100"
55544
+ });
55545
+ const previousStep = stepPercentage[index - 1];
55546
+ if (previousStep !== void 0 && step < previousStep) ctx.addIssue({
55547
+ code: "custom",
55548
+ path: [index],
55549
+ message: "Rollout step percentages must be in ascending order"
55550
+ });
55551
+ }
55552
+ const lastIndex = stepPercentage.length - 1;
55553
+ if (stepPercentage[lastIndex] !== 100) ctx.addIssue({
55554
+ code: "custom",
55555
+ path: [lastIndex],
55556
+ message: "The final rollout step percentage must be 100"
55557
+ });
55558
+ });
55559
+ function validateContainerRelationships(container, ctx) {
55560
+ const stepPercentage = container.rollout?.stepPercentage;
55561
+ if (Array.isArray(stepPercentage) && container.maxInstances !== void 0 && stepPercentage.length > container.maxInstances) ctx.addIssue({
55562
+ code: "custom",
55563
+ path: ["rollout", "stepPercentage"],
55564
+ message: "A rollout cannot contain more steps than the maximum number of instances"
55565
+ });
55566
+ }
55567
+ const ContainerObservabilityBaseSchema = strictObject({
55568
+ enabled: boolean().optional(),
55569
+ logs: strictObject({ enabled: boolean().optional() }).optional()
55570
+ });
55571
+ const ContainerObservabilitySchema = union([ContainerObservabilityBaseSchema.extend({ targetInstancePercentage: number().min(0).max(100).optional() }), ContainerObservabilityBaseSchema.extend({ targetInstanceCount: number().int().nonnegative().optional() })]);
55572
+ const BaseContainerSchema = strictObject({
55573
+ type: literal$1("container"),
55574
+ name: string().min(1),
55575
+ observability: ContainerObservabilitySchema.optional(),
55576
+ unsafe: record(string(), unknown()).optional()
55577
+ });
55578
+ const StandardContainerBaseSchema = BaseContainerSchema.extend({
55579
+ maxInstances: number().int().nonnegative().default(20),
55580
+ instanceType: union([_enum([
55581
+ "basic",
55582
+ "lite",
55583
+ "standard-1",
55584
+ "standard-2",
55585
+ "standard-3",
55586
+ "standard-4"
55587
+ ]), strictObject({
55588
+ vcpu: number().min(.0625).optional(),
55589
+ memoryMib: number().nonnegative().optional(),
55590
+ diskMb: number().nonnegative().optional()
55591
+ })]).optional(),
55592
+ schedulingPolicy: _enum(["default", "regional"]).optional(),
55593
+ ssh: strictObject({
55594
+ enabled: boolean(),
55595
+ port: number().int().min(1).max(65535).optional()
55596
+ }).optional(),
55597
+ authorizedKeys: array(strictObject({
55598
+ name: string(),
55599
+ publicKey: string()
55600
+ })).optional(),
55601
+ constraints: strictObject({
55602
+ regions: array(_enum([
55603
+ "ENAM",
55604
+ "WNAM",
55605
+ "EEUR",
55606
+ "WEUR",
55607
+ "APAC",
55608
+ "SAM",
55609
+ "ME",
55610
+ "OC",
55611
+ "AFR"
55612
+ ])).optional(),
55613
+ jurisdiction: _enum(["eu", "fedramp"]).optional()
55614
+ }).optional(),
55615
+ rollout: strictObject({
55616
+ kind: _enum([
55617
+ "full-auto",
55618
+ "none",
55619
+ "full-manual"
55620
+ ]).optional(),
55621
+ stepPercentage: ContainerRolloutStepPercentageSchema.optional(),
55622
+ activeGracePeriod: number().nonnegative().optional()
55623
+ }).optional()
55624
+ });
55625
+ const DurableObjectContainerBaseSchema = BaseContainerSchema.extend({ schedulingPolicy: literal$1("durable-object") });
55626
+ /**
55627
+ * Input Container schema — validates user-authored `cloudflare.config.ts`
55628
+ * Container exports. Dockerfiles are built by the consuming build tool.
55629
+ */
55630
+ const InputContainerSchema = union([StandardContainerBaseSchema.extend({ image: InputContainerImageSchema }).superRefine(validateContainerRelationships), DurableObjectContainerBaseSchema.extend({ images: record(string(), InputContainerImageSchema).optional() })]);
55631
+ /**
55632
+ * Output Container schema — validates Container configs in the Build Output
55633
+ * Specification, after any Dockerfile has been built into a local or remote
55634
+ * image reference.
55635
+ */
55636
+ const OutputContainerSchema = union([StandardContainerBaseSchema.extend({ image: OutputContainerImageSchema }).superRefine(validateContainerRelationships), DurableObjectContainerBaseSchema.extend({ images: record(string(), OutputContainerImageSchema).optional() })]);
55507
55637
  const DurableObjectCreatedExportSchema = strictObject({
55508
55638
  type: literal$1("durable-object"),
55509
55639
  state: literal$1("created").optional(),
@@ -55682,8 +55812,13 @@ const InputSettingsSchema = strictObject({
55682
55812
  * Build Output Specification. Adds the `mode` the build was produced in.
55683
55813
  */
55684
55814
  const OutputSettingsSchema = InputSettingsSchema.extend({ mode: string().optional() });
55815
+ const DEFAULT_EXPORT_NAME = "default";
55685
55816
  const SETTINGS_EXPORT_NAME = "settings";
55686
- const SUPPORTED_EXPORT_TYPES = new Set(["worker", "settings"]);
55817
+ const SUPPORTED_EXPORT_TYPES = new Set([
55818
+ "container",
55819
+ "worker",
55820
+ "settings"
55821
+ ]);
55687
55822
  function invalidConfigExportMessage(exportName) {
55688
55823
  return `The \`${exportName}\` export is not a supported export type. Move constants, helper functions, and other unsupported exports to a separate module.`;
55689
55824
  }
@@ -55700,6 +55835,15 @@ const ConfigExportsTypeSchema = record(string(), unknown()).check((ctx) => {
55700
55835
  });
55701
55836
  continue;
55702
55837
  }
55838
+ if (key === DEFAULT_EXPORT_NAME && type !== "worker") {
55839
+ ctx.issues.push({
55840
+ code: "custom",
55841
+ input: value,
55842
+ path: [key],
55843
+ message: `The \`${DEFAULT_EXPORT_NAME}\` export is reserved for a \`worker\` config; found a \`${type}\` config.`
55844
+ });
55845
+ continue;
55846
+ }
55703
55847
  const isSettingsName = key === SETTINGS_EXPORT_NAME;
55704
55848
  const isSettingsType = type === "settings";
55705
55849
  if (isSettingsType && !isSettingsName) ctx.issues.push({
@@ -55881,18 +56025,26 @@ function createFatalError(message, isJson, options) {
55881
56025
  return new FatalError$1(`${message}`, options);
55882
56026
  }
55883
56027
  __name$5(createFatalError, "createFatalError");
56028
+ const ROLLOUT_KIND_MAP = {
56029
+ "full-auto": "full_auto",
56030
+ "full-manual": "full_manual",
56031
+ none: "none"
56032
+ };
55884
56033
  /**
55885
56034
  * Convert a parsed `@cloudflare/config` config into a Wrangler `RawConfig`.
55886
56035
  *
55887
- * The caller is responsible for unwrapping any function/promise wrapper around
55888
- * the config and validating it against `InputWorkerSchema` before passing it in.
56036
+ * The caller is responsible for unwrapping any function/promise wrappers and
56037
+ * validating the configs against their corresponding input schemas before
56038
+ * passing them in.
55889
56039
  *
55890
56040
  * @param workerConfig The parsed (post-validation) Worker config.
55891
56041
  * @param settingsConfig The optional parsed settings config, whose fields
55892
56042
  * are merged onto the result.
56043
+ * @param containerExports The parsed Container exports to include in the
56044
+ * result.
55893
56045
  * @returns The corresponding Wrangler `RawConfig`.
55894
56046
  */
55895
- function convertToWranglerConfig(workerConfig, settingsConfig) {
56047
+ function convertToWranglerConfig(workerConfig, settingsConfig, containerExports = []) {
55896
56048
  const result = {};
55897
56049
  convertTopLevel(workerConfig, result);
55898
56050
  convertBindingsAndAssets(workerConfig, result);
@@ -55901,8 +56053,50 @@ function convertToWranglerConfig(workerConfig, settingsConfig) {
55901
56053
  convertTriggers(workerConfig, result);
55902
56054
  convertTailConsumers(workerConfig, result);
55903
56055
  if (settingsConfig !== void 0) convertSettings(settingsConfig, result);
56056
+ if (containerExports.length > 0) result.containers = containerExports.map((container) => convertContainer(container));
55904
56057
  return result;
55905
56058
  }
56059
+ function convertContainer(container) {
56060
+ if (container.schedulingPolicy === "durable-object") throw new UserError$1("Durable Object-managed Containers are not currently supported by `convertToWranglerConfig()`.", { telemetryMessage: false });
56061
+ const converted = { name: container.name };
56062
+ if (container.observability !== void 0) converted.observability = convertContainerObservability(container.observability);
56063
+ if (container.unsafe !== void 0) converted.unsafe = container.unsafe;
56064
+ converted.image = "dockerfile" in container.image ? container.image.dockerfile : container.image.reference;
56065
+ converted.max_instances = container.maxInstances;
56066
+ if ("dockerfile" in container.image) {
56067
+ if (container.image.buildContext !== void 0) converted.image_build_context = container.image.buildContext;
56068
+ if (container.image.buildVars !== void 0) converted.image_vars = container.image.buildVars;
56069
+ }
56070
+ if (container.instanceType !== void 0) if (typeof container.instanceType === "string") converted.instance_type = container.instanceType;
56071
+ else {
56072
+ const instanceType = {};
56073
+ if (container.instanceType.vcpu !== void 0) instanceType.vcpu = container.instanceType.vcpu;
56074
+ if (container.instanceType.memoryMib !== void 0) instanceType.memory_mib = container.instanceType.memoryMib;
56075
+ if (container.instanceType.diskMb !== void 0) instanceType.disk_mb = container.instanceType.diskMb;
56076
+ converted.instance_type = instanceType;
56077
+ }
56078
+ if (container.schedulingPolicy !== void 0) converted.scheduling_policy = container.schedulingPolicy;
56079
+ if (container.ssh !== void 0) converted.ssh = container.ssh;
56080
+ if (container.authorizedKeys !== void 0) converted.authorized_keys = container.authorizedKeys.map(({ name, publicKey }) => ({
56081
+ name,
56082
+ public_key: publicKey
56083
+ }));
56084
+ if (container.constraints !== void 0) converted.constraints = container.constraints;
56085
+ if (container.rollout !== void 0) {
56086
+ if (container.rollout.kind !== void 0) converted.rollout_kind = ROLLOUT_KIND_MAP[container.rollout.kind];
56087
+ if (container.rollout.stepPercentage !== void 0) converted.rollout_step_percentage = container.rollout.stepPercentage;
56088
+ if (container.rollout.activeGracePeriod !== void 0) converted.rollout_active_grace_period = container.rollout.activeGracePeriod;
56089
+ }
56090
+ return converted;
56091
+ }
56092
+ function convertContainerObservability(observability) {
56093
+ const converted = {};
56094
+ if (observability.enabled !== void 0) converted.enabled = observability.enabled;
56095
+ if (observability.logs !== void 0) converted.logs = observability.logs;
56096
+ if ("targetInstancePercentage" in observability && observability.targetInstancePercentage !== void 0) converted.target_instance_percentage = observability.targetInstancePercentage;
56097
+ if ("targetInstanceCount" in observability && observability.targetInstanceCount !== void 0) converted.target_instance_count = observability.targetInstanceCount;
56098
+ return converted;
56099
+ }
55906
56100
  /**
55907
56101
  * Merge a parsed settings config's fields (`account_id`, `compliance_region`)
55908
56102
  * onto an existing Wrangler `RawConfig`.
@@ -56570,6 +56764,9 @@ function isRecord(value) {
56570
56764
  function isConfigReference(value) {
56571
56765
  return typeof value === "function" || isRecord(value);
56572
56766
  }
56767
+ function normalizeConfigReference(reference, resolved, expectedType) {
56768
+ return isRecord(resolved) && resolved.type === expectedType && typeof resolved.name === "string" ? resolved.name : reference;
56769
+ }
56573
56770
  function createDefinitionResolver(ctx) {
56574
56771
  const resolvedDefinitions = /* @__PURE__ */ new Map();
56575
56772
  return (input) => {
@@ -56590,7 +56787,7 @@ async function normalizeWorkerReferences(resolved, resolveDefinition) {
56590
56787
  const target$1 = await resolveDefinition(binding.worker);
56591
56788
  env$3[bindingName] = {
56592
56789
  ...binding,
56593
- worker: isRecord(target$1) ? target$1.name : void 0
56790
+ worker: normalizeConfigReference(binding.worker, target$1, "worker")
56594
56791
  };
56595
56792
  }
56596
56793
  return {
@@ -56598,22 +56795,151 @@ async function normalizeWorkerReferences(resolved, resolveDefinition) {
56598
56795
  env: env$3
56599
56796
  };
56600
56797
  }
56798
+ async function normalizeContainerReferences(resolved, resolveDefinition, resolvedExports) {
56799
+ const issues = [];
56800
+ if (!isRecord(resolved) || !isRecord(resolved.exports)) return {
56801
+ value: resolved,
56802
+ issues
56803
+ };
56804
+ const workerExports = { ...resolved.exports };
56805
+ for (const [exportName, workerExport] of Object.entries(workerExports)) {
56806
+ if (!isRecord(workerExport) || workerExport.type !== "durable-object" || workerExport.container === void 0) continue;
56807
+ const reference = workerExport.container;
56808
+ if (typeof reference === "string") {
56809
+ issues.push({
56810
+ code: "custom",
56811
+ input: reference,
56812
+ path: [
56813
+ "exports",
56814
+ exportName,
56815
+ "container"
56816
+ ],
56817
+ message: "Container provided as a string. Reference an exported Container definition instead."
56818
+ });
56819
+ workerExports[exportName] = {
56820
+ ...workerExport,
56821
+ container: void 0
56822
+ };
56823
+ continue;
56824
+ }
56825
+ const target$1 = await resolveDefinition(reference);
56826
+ if (isRecord(target$1) && target$1.type === "container" && typeof target$1.name === "string" && !Object.values(resolvedExports).includes(target$1)) {
56827
+ issues.push({
56828
+ code: "custom",
56829
+ input: reference,
56830
+ path: [
56831
+ "exports",
56832
+ exportName,
56833
+ "container"
56834
+ ],
56835
+ message: `The referenced Container "${target$1.name}" is not exported.`
56836
+ });
56837
+ workerExports[exportName] = {
56838
+ ...workerExport,
56839
+ container: void 0
56840
+ };
56841
+ continue;
56842
+ }
56843
+ workerExports[exportName] = {
56844
+ ...workerExport,
56845
+ container: normalizeConfigReference(reference, target$1, "container")
56846
+ };
56847
+ }
56848
+ return {
56849
+ value: {
56850
+ ...resolved,
56851
+ exports: workerExports
56852
+ },
56853
+ issues
56854
+ };
56855
+ }
56856
+ async function normalizeConfigReferences(resolved, resolveDefinition, resolvedExports) {
56857
+ return normalizeContainerReferences(await normalizeWorkerReferences(resolved, resolveDefinition), resolveDefinition, resolvedExports);
56858
+ }
56601
56859
  function prefixIssues(issues, prefix) {
56602
56860
  return issues.map((issue$2) => ({
56603
56861
  ...issue$2,
56604
56862
  path: [prefix, ...issue$2.path]
56605
56863
  }));
56606
56864
  }
56865
+ function validateUniqueResourceNames(configExports) {
56866
+ const issues = [];
56867
+ const exportNameByResourceName = {
56868
+ container: /* @__PURE__ */ new Map(),
56869
+ worker: /* @__PURE__ */ new Map()
56870
+ };
56871
+ for (const [exportName, config$2] of Object.entries(configExports)) {
56872
+ if (config$2.type !== "container" && config$2.type !== "worker") continue;
56873
+ const resourceType = config$2.type === "container" ? "Container" : "Worker";
56874
+ const exportNames = exportNameByResourceName[config$2.type];
56875
+ const previousExportName = exportNames.get(config$2.name);
56876
+ if (previousExportName !== void 0) {
56877
+ issues.push({
56878
+ code: "custom",
56879
+ input: config$2.name,
56880
+ path: [exportName, "name"],
56881
+ message: `The ${resourceType} name "${config$2.name}" is also used by the "${previousExportName}" export. ${resourceType} names must be unique.`
56882
+ });
56883
+ continue;
56884
+ }
56885
+ exportNames.set(config$2.name, exportName);
56886
+ }
56887
+ return issues;
56888
+ }
56889
+ function validateContainerExportLinks(configExports) {
56890
+ const issues = [];
56891
+ const containerNames = /* @__PURE__ */ new Set();
56892
+ for (const config$2 of Object.values(configExports)) if (config$2.type === "container") containerNames.add(config$2.name);
56893
+ const firstReferenceByContainerName = /* @__PURE__ */ new Map();
56894
+ for (const [workerExportName, config$2] of Object.entries(configExports)) {
56895
+ if (config$2.type !== "worker") continue;
56896
+ for (const [durableObjectExportName, workerExport] of Object.entries(config$2.exports ?? {})) {
56897
+ if (workerExport.type !== "durable-object" || !("container" in workerExport) || workerExport.container === void 0) continue;
56898
+ const containerName = workerExport.container;
56899
+ const path$2 = [
56900
+ workerExportName,
56901
+ "exports",
56902
+ durableObjectExportName,
56903
+ "container"
56904
+ ];
56905
+ if (!containerNames.has(containerName)) {
56906
+ issues.push({
56907
+ code: "custom",
56908
+ input: containerName,
56909
+ path: path$2,
56910
+ message: `The Container "${containerName}" is not exported from this configuration.`
56911
+ });
56912
+ continue;
56913
+ }
56914
+ const firstReference = firstReferenceByContainerName.get(containerName);
56915
+ if (firstReference !== void 0) {
56916
+ issues.push({
56917
+ code: "custom",
56918
+ input: containerName,
56919
+ path: path$2,
56920
+ message: `The Container "${containerName}" is already referenced by "${firstReference.workerExportName}.exports.${firstReference.durableObjectExportName}". A Container can only be linked to one Durable Object.`
56921
+ });
56922
+ continue;
56923
+ }
56924
+ firstReferenceByContainerName.set(containerName, {
56925
+ workerExportName,
56926
+ durableObjectExportName
56927
+ });
56928
+ }
56929
+ }
56930
+ return issues;
56931
+ }
56607
56932
  /**
56608
56933
  * Resolve and validate loaded `cloudflare.config.ts` exports.
56609
56934
  *
56610
- * Config inputs are resolved once by identity. Top-level Worker exports are
56611
- * also parsed once by identity; unexported references are resolved only far
56612
- * enough to replace the reference with the Worker's name.
56935
+ * Config inputs are resolved once by identity. Top-level Worker and Container
56936
+ * exports are also parsed once by identity. References are resolved only far
56937
+ * enough to replace them with resource names, then Container links are
56938
+ * validated across the exported resources.
56613
56939
  */
56614
56940
  async function resolveAndValidateConfigExports(exports$2, ctx) {
56615
56941
  const resolveDefinition = createDefinitionResolver(ctx);
56616
- const parsedWorkers = /* @__PURE__ */ new Map();
56942
+ const parsedResources = /* @__PURE__ */ new Map();
56617
56943
  const resolvedExports = {};
56618
56944
  for (const [name, input] of Object.entries(exports$2)) resolvedExports[name] = await resolveDefinition(input);
56619
56945
  const typeResult = ConfigExportsTypeSchema.safeParse(resolvedExports);
@@ -56627,17 +56953,20 @@ async function resolveAndValidateConfigExports(exports$2, ctx) {
56627
56953
  for (const [name, input] of Object.entries(exports$2)) {
56628
56954
  const resolved = resolvedExports[name];
56629
56955
  if (!isRecord(resolved)) continue;
56630
- if (resolved.type === "worker") {
56631
- let result = parsedWorkers.get(input);
56632
- if (!result) {
56633
- result = InputWorkerSchema.safeParse(await normalizeWorkerReferences(resolved, resolveDefinition));
56634
- parsedWorkers.set(input, result);
56635
- if (!result.success) issues.push(...prefixIssues(result.error.issues, name));
56636
- }
56637
- if (result.success) data$1[name] = result.data;
56638
- continue;
56639
- }
56640
- }
56956
+ if (resolved.type !== "worker" && resolved.type !== "container") continue;
56957
+ let result = parsedResources.get(input);
56958
+ if (!result) {
56959
+ if (resolved.type === "worker") {
56960
+ const normalized = await normalizeConfigReferences(resolved, resolveDefinition, resolvedExports);
56961
+ issues.push(...prefixIssues(normalized.issues, name));
56962
+ result = InputWorkerSchema.safeParse(normalized.value);
56963
+ } else result = InputContainerSchema.safeParse(resolved);
56964
+ parsedResources.set(input, result);
56965
+ if (!result.success) issues.push(...prefixIssues(result.error.issues, name));
56966
+ }
56967
+ if (result.success) data$1[name] = result.data;
56968
+ }
56969
+ issues.push(...validateUniqueResourceNames(data$1), ...validateContainerExportLinks(data$1));
56641
56970
  return issues.length > 0 ? {
56642
56971
  success: false,
56643
56972
  error: new ZodError(issues)
@@ -56946,13 +57275,36 @@ function getWorkersDir(root) {
56946
57275
  return path.join(getBuildOutputDir(root), BUILD_OUTPUT_VERSION, "workers");
56947
57276
  }
56948
57277
  /**
57278
+ * Absolute path to the Containers output directory.
57279
+ */
57280
+ function getContainersDir(root) {
57281
+ return path.join(getBuildOutputDir(root), BUILD_OUTPUT_VERSION, "containers");
57282
+ }
57283
+ function validateDirectoryName(name, resourceName) {
57284
+ if (name.length === 0 || name === "." || name === ".." || name.includes("/") || name.includes("\\") || name.includes("\0")) throw new Error(`${resourceName} directory names must be non-empty, single path segments. Received ${JSON.stringify(name)}.`);
57285
+ }
57286
+ /**
56949
57287
  * Absolute path to a Worker's directory (`workers/<worker-directory-name>`).
56950
57288
  */
56951
57289
  function getWorkerDir(root, workerDirectoryName = DEFAULT_WORKER_DIRECTORY_NAME) {
56952
- if (workerDirectoryName.length === 0 || workerDirectoryName === "." || workerDirectoryName === ".." || workerDirectoryName.includes("/") || workerDirectoryName.includes("\\") || workerDirectoryName.includes("\0")) throw new Error("Worker directory names must be non-empty, single path segments.");
57290
+ validateDirectoryName(workerDirectoryName, "Worker");
56953
57291
  return path.join(getWorkersDir(root), workerDirectoryName);
56954
57292
  }
56955
57293
  /**
57294
+ * Absolute path to a Container's directory
57295
+ * (`containers/<container-directory-name>`).
57296
+ */
57297
+ function getContainerDir(root, containerDirectoryName) {
57298
+ validateDirectoryName(containerDirectoryName, "Container");
57299
+ return path.join(getContainersDir(root), containerDirectoryName);
57300
+ }
57301
+ /**
57302
+ * Absolute path to the Container's config file.
57303
+ */
57304
+ function getContainerConfigPath(root, containerDirectoryName) {
57305
+ return path.join(getContainerDir(root, containerDirectoryName), CONFIG_FILENAME);
57306
+ }
57307
+ /**
56956
57308
  * Absolute path to the Worker's config file.
56957
57309
  */
56958
57310
  function getWorkerConfigPath(root, workerDirectoryName = DEFAULT_WORKER_DIRECTORY_NAME) {
@@ -57011,14 +57363,14 @@ async function cleanBuildOutputDir(root) {
57011
57363
  * - Workers mode: `manifest` is provided (bundle/ present on disk).
57012
57364
  * - Assets-only mode: `manifest` is omitted (no bundle/ directory).
57013
57365
  */
57014
- async function writeWorkerConfig({ root, config: config$2, manifest, workerDirectoryName = DEFAULT_WORKER_DIRECTORY_NAME }) {
57366
+ async function writeWorkerConfig({ root, config: config$2, manifest, directoryName = DEFAULT_WORKER_DIRECTORY_NAME }) {
57015
57367
  const { entrypoint: _entrypoint,...rest } = config$2;
57016
57368
  const outputConfig = {
57017
57369
  ...rest,
57018
57370
  manifest
57019
57371
  };
57020
- await fsp.mkdir(getWorkerDir(root, workerDirectoryName), { recursive: true });
57021
- await fsp.writeFile(getWorkerConfigPath(root, workerDirectoryName), JSON.stringify(outputConfig));
57372
+ await fsp.mkdir(getWorkerDir(root, directoryName), { recursive: true });
57373
+ await fsp.writeFile(getWorkerConfigPath(root, directoryName), JSON.stringify(outputConfig));
57022
57374
  }
57023
57375
  /**
57024
57376
  * Write the top-level `config.json` to the Build Output Specification tree.
@@ -57057,12 +57409,13 @@ var BuildOutputError = class extends Error {
57057
57409
  * `<root>/.cloudflare/output/v0/`.
57058
57410
  *
57059
57411
  * Reads the optional top-level settings `config.json`, then reads and
57060
- * schema-validates the Worker's `config.json` and resolves its
57061
- * `bundle/` / `assets/` directories. Partial manifests are resolved into
57062
- * complete manifests using the files in `bundle/`.
57412
+ * schema-validates each Worker and Container `config.json`, and resolves each
57413
+ * Worker's `bundle/` / `assets/` directories. Partial manifests are resolved
57414
+ * into complete manifests using the files in `bundle/`.
57063
57415
  *
57064
57416
  * @throws {BuildOutputError} if the top-level `config.json` is invalid, or if
57065
- * the Worker config is missing, is not valid JSON, or fails schema validation.
57417
+ * a Worker or Container config is missing, is not valid JSON, or fails schema
57418
+ * validation.
57066
57419
  */
57067
57420
  async function readBuildOutput(root) {
57068
57421
  const settings = await readSettings(root);
@@ -57076,7 +57429,28 @@ async function readBuildOutput(root) {
57076
57429
  workers: {
57077
57430
  default: defaultWorker,
57078
57431
  ...Object.fromEntries(additionalWorkers)
57079
- }
57432
+ },
57433
+ containers: await readContainers(root)
57434
+ };
57435
+ }
57436
+ /** Read and schema-validate all Container configs, if any. */
57437
+ async function readContainers(root) {
57438
+ const containersDir = getContainersDir(root);
57439
+ if (!fs$1.existsSync(containersDir)) return {};
57440
+ const containerDirectoryNames = (await fsp.readdir(containersDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
57441
+ const containers = await Promise.all(containerDirectoryNames.map(async (containerDirectoryName) => [containerDirectoryName, await readContainer(root, containerDirectoryName)]));
57442
+ return Object.fromEntries(containers);
57443
+ }
57444
+ /** Read and schema-validate one Container config. */
57445
+ async function readContainer(root, containerDirectoryName) {
57446
+ const configPath = getContainerConfigPath(root, containerDirectoryName);
57447
+ if (!fs$1.existsSync(configPath)) throw new BuildOutputError(`no Container config found at ${configPath}.`);
57448
+ const contents = await fsp.readFile(configPath, "utf-8");
57449
+ const result = OutputContainerSchema.safeParse(parseJson(contents, configPath));
57450
+ if (!result.success) throw new BuildOutputError(`invalid Container config at ${configPath}.\n${result.error.message}`);
57451
+ return {
57452
+ configPath,
57453
+ config: result.data
57080
57454
  };
57081
57455
  }
57082
57456
  /**
@@ -68562,6 +68936,39 @@ function validateWorkerEnvironmentOptions(resolvedPluginConfig, resolvedViteConf
68562
68936
  }
68563
68937
  }
68564
68938
 
68939
+ //#endregion
68940
+ //#region src/plugins/wrangler-watch-ignore.ts
68941
+ const WRANGLER_STATE_WATCH_IGNORE = "**/.wrangler/**";
68942
+ /**
68943
+ * Keep Miniflare persistence writes out of Vite's file watcher without
68944
+ * replacing any ignore patterns the user already configured.
68945
+ *
68946
+ * @param userIgnored - Existing `server.watch.ignored` patterns, if any
68947
+ * @returns Ignore patterns that always include `.wrangler` directories
68948
+ */
68949
+ function withWranglerStateIgnored(userIgnored) {
68950
+ if (userIgnored == null) return WRANGLER_STATE_WATCH_IGNORE;
68951
+ if (Array.isArray(userIgnored)) return [...userIgnored, WRANGLER_STATE_WATCH_IGNORE];
68952
+ return [userIgnored, WRANGLER_STATE_WATCH_IGNORE];
68953
+ }
68954
+ /**
68955
+ * Merge `.wrangler` into Vite's `server.watch` config.
68956
+ *
68957
+ * Returns `null` when the user disabled watching with `server.watch: null`,
68958
+ * so this plugin does not turn the watcher back on.
68959
+ *
68960
+ * @param userWatch - The user's `server.watch` value from Vite config
68961
+ * @returns `null` when watching is disabled, otherwise a watch object whose
68962
+ * `ignored` list includes `.wrangler` directories
68963
+ */
68964
+ function getServerWatchConfig(userWatch) {
68965
+ if (userWatch === null) return null;
68966
+ return {
68967
+ ...userWatch,
68968
+ ignored: withWranglerStateIgnored(userWatch?.ignored)
68969
+ };
68970
+ }
68971
+
68565
68972
  //#endregion
68566
68973
  //#region src/plugins/config.ts
68567
68974
  /**
@@ -68580,6 +68987,7 @@ const configPlugin = createPlugin("config", (ctx) => {
68580
68987
  appType: "custom",
68581
68988
  server: {
68582
68989
  allowedHosts: getAllowedHosts(ctx.getTunnelHostnames(), userConfig.server?.allowedHosts),
68990
+ watch: getServerWatchConfig(userConfig.server?.watch),
68583
68991
  fs: { deny: [...[
68584
68992
  ".env",
68585
68993
  ".env.*",
@@ -74143,7 +74551,7 @@ async function buildContainerImage(containerConfig, pathToDocker, verifyDockerIs
74143
74551
  }
74144
74552
  })).ready;
74145
74553
  return {
74146
- containerConfig,
74554
+ container: containerConfig,
74147
74555
  localTag
74148
74556
  };
74149
74557
  } catch (error$2) {
@@ -74156,12 +74564,14 @@ async function buildContainerImage(containerConfig, pathToDocker, verifyDockerIs
74156
74564
  }
74157
74565
  __name$2(buildContainerImage, "buildContainerImage");
74158
74566
  async function buildContainerImages(containers, pathToDocker, verifyDockerIsRunning) {
74159
- const builtContainerDeployments = [];
74160
- for (const container of containers.filter(isDockerfileContainerConfig)) builtContainerDeployments.push({
74161
- container,
74162
- builtImage: await buildContainerImage(container, pathToDocker, verifyDockerIsRunning)
74163
- });
74164
- return builtContainerDeployments;
74567
+ const builtImages = [];
74568
+ try {
74569
+ for (const container of containers.filter(isDockerfileContainerConfig)) builtImages.push(await buildContainerImage(container, pathToDocker, verifyDockerIsRunning));
74570
+ } catch (error$2) {
74571
+ await cleanupBuiltImages(builtImages, pathToDocker);
74572
+ throw error$2;
74573
+ }
74574
+ return builtImages;
74165
74575
  }
74166
74576
  __name$2(buildContainerImages, "buildContainerImages");
74167
74577
  async function pushBuiltContainerImage(builtImage, versionId, pathToDocker, accountId, complianceConfig) {
@@ -74169,8 +74579,8 @@ async function pushBuiltContainerImage(builtImage, versionId, pathToDocker, acco
74169
74579
  const imageRef = await pushImageIfChanged({
74170
74580
  pathToDocker,
74171
74581
  sourceTag: builtImage.localTag,
74172
- targetTag: getContainerImageTag(builtImage.containerConfig, versionId),
74173
- containerConfig: builtImage.containerConfig,
74582
+ targetTag: getContainerImageTag(builtImage.container, versionId),
74583
+ containerConfig: builtImage.container,
74174
74584
  accountId,
74175
74585
  complianceConfig,
74176
74586
  cleanupSourceTag: true
@@ -74186,8 +74596,8 @@ async function pushBuiltContainerImage(builtImage, versionId, pathToDocker, acco
74186
74596
  }
74187
74597
  }
74188
74598
  __name$2(pushBuiltContainerImage, "pushBuiltContainerImage");
74189
- async function cleanupBuiltContainerImages(builtContainerDeployments, pathToDocker) {
74190
- for (const { builtImage } of builtContainerDeployments) {
74599
+ async function cleanupBuiltImages(builtImages, pathToDocker) {
74600
+ for (const builtImage of builtImages) {
74191
74601
  if (builtImage.localTagCleaned) continue;
74192
74602
  try {
74193
74603
  logger$1.debug(`Untagging built image: ${builtImage.localTag}.`);
@@ -74202,7 +74612,7 @@ async function cleanupBuiltContainerImages(builtContainerDeployments, pathToDock
74202
74612
  }
74203
74613
  }
74204
74614
  }
74205
- __name$2(cleanupBuiltContainerImages, "cleanupBuiltContainerImages");
74615
+ __name$2(cleanupBuiltImages, "cleanupBuiltImages");
74206
74616
  function getContainerImageTag(containerConfig, imageTag) {
74207
74617
  return `${getContainerImageRepositoryName(containerConfig)}:${imageTag.split("-")[0]}`;
74208
74618
  }
@@ -80117,7 +80527,7 @@ __name(createWorkerUploadForm, "createWorkerUploadForm");
80117
80527
  //#endregion
80118
80528
  //#region ../remote-bindings/dist/index.mjs
80119
80529
  var import_undici = require_undici();
80120
- var version$2 = "0.0.23";
80530
+ var version$2 = "0.0.24";
80121
80531
  var NoDefaultValueProvided = class extends UserError {
80122
80532
  constructor() {
80123
80533
  super("This command cannot be run in a non-interactive context", { telemetryMessage: "remote bindings prompt default missing" });