@cloudflare/vitest-plugin 1.1.6 → 1.1.8

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-V6JSHOVJ.mjs
328
+ //#region ../workers-utils/dist/chunk-R5MIV2EH.mjs
329
329
  function hasKnownExportType(entry) {
330
330
  const type = entry?.type;
331
331
  return type === "durable-object" || type === "worker";
@@ -352,6 +352,15 @@ function hasDurableObjectExports(exports$1) {
352
352
  return Object.keys(getDurableObjectExports(exports$1)).length > 0;
353
353
  }
354
354
  __name$3(hasDurableObjectExports, "hasDurableObjectExports");
355
+ var CONTAINER_IMAGES_BINDING = "EXPERIMENTAL_CLOUDFLARE_CONTAINER_IMAGES";
356
+ function isDurableObjectContainerApp(container) {
357
+ return container.scheduling_policy === "durable_object";
358
+ }
359
+ __name$3(isDurableObjectContainerApp, "isDurableObjectContainerApp");
360
+ function getDurableObjectContainerApps(containers) {
361
+ return Array.isArray(containers) ? containers.filter(isDurableObjectContainerApp) : [];
362
+ }
363
+ __name$3(getDurableObjectContainerApps, "getDurableObjectContainerApps");
355
364
  function getContainerNameToClassNameMap(exports$1) {
356
365
  const containerNameToClassName = /* @__PURE__ */ new Map();
357
366
  for (const [className, entry] of Object.entries(getDurableObjectExports(exports$1))) if ("container" in entry && typeof entry.container === "string" && !containerNameToClassName.has(entry.container)) containerNameToClassName.set(entry.container, className);
@@ -373,6 +382,48 @@ function getContainerDurableObjectClassNames(containers, exports$1) {
373
382
  return classNames;
374
383
  }
375
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) {
417
+ const allDOs = getDurableObjectClassNameToUseSQLiteMap(config$1.migrations, config$1.exports);
418
+ for (const container of getDurableObjectContainerApps(config$1.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");
376
427
  function createScanner(text, ignoreTrivia = false) {
377
428
  const len = text.length;
378
429
  let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
@@ -2736,8 +2787,8 @@ function formatConfigSnippet(snippet, configPath, formatted = true) {
2736
2787
  __name$3(formatConfigSnippet, "formatConfigSnippet");
2737
2788
 
2738
2789
  //#endregion
2739
- //#region ../workers-utils/dist/chunk-CDB2RWUW.mjs
2740
- var DEFAULT_COMPAT_DATE = "2026-09-08";
2790
+ //#region ../workers-utils/dist/chunk-KBTXSRPS.mjs
2791
+ var DEFAULT_COMPAT_DATE = "2026-09-11";
2741
2792
  function assertNever(_value) {}
2742
2793
  __name$3(assertNever, "assertNever");
2743
2794
  function mapWorkerMetadataBindings(bindings) {
@@ -3268,7 +3319,7 @@ function getGlobalWranglerCachePath() {
3268
3319
  __name$3(getGlobalWranglerCachePath, "getGlobalWranglerCachePath");
3269
3320
 
3270
3321
  //#endregion
3271
- //#region ../workers-utils/dist/chunk-XUGGRRBO.mjs
3322
+ //#region ../workers-utils/dist/chunk-IYSONYTF.mjs
3272
3323
  var getC3CommandFromEnv = getEnvironmentVariableFactory({
3273
3324
  variableName: "WRANGLER_C3_COMMAND",
3274
3325
  defaultValue: /* @__PURE__ */ __name$3(() => "create cloudflare", "defaultValue")
@@ -3296,6 +3347,7 @@ var getCloudflareApiEnvironmentFromEnv = getEnvironmentVariableFactory({
3296
3347
  choices: ["production", "staging"]
3297
3348
  });
3298
3349
  var COMPLIANCE_REGION_CONFIG_PUBLIC = { compliance_region: "public" };
3350
+ var COMPLIANCE_REGION_CONFIG_UNKNOWN = { compliance_region: void 0 };
3299
3351
  var getCloudflareComplianceRegionFromEnv = getEnvironmentVariableFactory({
3300
3352
  variableName: "CLOUDFLARE_COMPLIANCE_REGION",
3301
3353
  choices: ["public", "fedramp_high"]
@@ -3318,6 +3370,11 @@ function getComplianceRegionSubdomain(complianceConfig) {
3318
3370
  return getCloudflareComplianceRegion(complianceConfig) === "fedramp_high" ? ".fed" : "";
3319
3371
  }
3320
3372
  __name$3(getComplianceRegionSubdomain, "getComplianceRegionSubdomain");
3373
+ function getCloudflareContainerRegistry(complianceConfig = COMPLIANCE_REGION_CONFIG_UNKNOWN) {
3374
+ if (process.env.CLOUDFLARE_CONTAINER_REGISTRY) return process.env.CLOUDFLARE_CONTAINER_REGISTRY;
3375
+ return `${process.env.WRANGLER_API_ENVIRONMENT === "staging" ? "staging." : ""}registry${getComplianceRegionSubdomain(complianceConfig)}.cloudflare.com`;
3376
+ }
3377
+ __name$3(getCloudflareContainerRegistry, "getCloudflareContainerRegistry");
3321
3378
  function getStagingSubdomain() {
3322
3379
  return getCloudflareApiEnvironmentFromEnv() === "staging" ? ".staging" : "";
3323
3380
  }
@@ -42054,7 +42111,7 @@ function normalizeAndValidateEnvironment(diagnostics, configPath, rawEnv, isDisp
42054
42111
  exports: inheritable(diagnostics, topLevelEnv, rawEnv, "exports", validateExports, {}),
42055
42112
  kv_namespaces: notInheritable(diagnostics, topLevelEnv, rawConfig, rawEnv, envName, "kv_namespaces", validateBindingArray(envName, validateKVBinding), []),
42056
42113
  cloudchamber: notInheritable(diagnostics, topLevelEnv, rawConfig, rawEnv, envName, "cloudchamber", validateCloudchamberConfig, {}),
42057
- containers: notInheritable(diagnostics, topLevelEnv, rawConfig, rawEnv, envName, "containers", validateContainerApp(envName, rawEnv.name ?? rawConfig?.name, configPath), void 0),
42114
+ containers: notInheritable(diagnostics, topLevelEnv, rawConfig, rawEnv, envName, "containers", validateContainerApp(envName, rawEnv.name ?? rawConfig?.name, configPath, { complianceConfig: { compliance_region: rawEnv.compliance_region ?? topLevelEnv?.compliance_region } }), void 0),
42058
42115
  send_email: notInheritable(diagnostics, topLevelEnv, rawConfig, rawEnv, envName, "send_email", validateBindingArray(envName, validateSendEmailBinding), []),
42059
42116
  queues: notInheritable(diagnostics, topLevelEnv, rawConfig, rawEnv, envName, "queues", validateQueues(envName), {
42060
42117
  producers: [],
@@ -42675,6 +42732,11 @@ function validatePreviewsContainers(envName, configPath) {
42675
42732
  const innerValidator = validateContainerApp(envName, void 0, configPath, { generateDefaultName: false });
42676
42733
  return (diagnostics, field, value, config2) => {
42677
42734
  if (Array.isArray(value)) {
42735
+ const durableObjectPolicyFields = [...value.entries()].filter(([, entry]) => entry && typeof entry === "object" && entry.scheduling_policy === "durable_object").map(([index]) => `"${field}[${index}].scheduling_policy"`);
42736
+ if (durableObjectPolicyFields.length > 0) {
42737
+ diagnostics.errors.push(`${durableObjectPolicyFields.join(", ")} cannot be "durable_object". Durable Object-managed Containers are configured only in the top-level "containers" array.`);
42738
+ return false;
42739
+ }
42678
42740
  const nameFields = [...value.entries()].filter(([, entry]) => entry && typeof entry === "object" && "name" in entry).map(([index]) => `"${field}[${index}].name"`);
42679
42741
  if (nameFields.length > 0) {
42680
42742
  diagnostics.errors.push(`${nameFields.join(", ")} cannot be set. A preview container's application name is generated from the worker name, preview slug, and Durable Object class name, so that separate previews of the same Worker do not collide. Remove it and identify the container with "class_name".`);
@@ -42699,6 +42761,63 @@ function validatePreviewsContainers(envName, configPath) {
42699
42761
  };
42700
42762
  }
42701
42763
  __name$3(validatePreviewsContainers, "validatePreviewsContainers");
42764
+ function validateDurableObjectContainerImages(diagnostics, field, images, complianceConfig) {
42765
+ if (images === void 0) return true;
42766
+ if (typeof images !== "object" || images === null || Array.isArray(images) || Object.keys(images).length === 0) {
42767
+ diagnostics.errors.push(`"${field}" must be a non-empty object when present.`);
42768
+ return false;
42769
+ }
42770
+ let valid = true;
42771
+ const entries = Object.entries(images);
42772
+ if (entries.length > 100) {
42773
+ diagnostics.errors.push(`"${field}" must contain at most 100 images.`);
42774
+ valid = false;
42775
+ }
42776
+ for (const [imageName, imageValue] of entries) {
42777
+ const imageField = `${field}.${imageName}`;
42778
+ if (imageName.length === 0 || imageName.length > 128) {
42779
+ diagnostics.errors.push(`"${field}" image names must be between 1 and 128 characters.`);
42780
+ valid = false;
42781
+ }
42782
+ if (typeof imageValue !== "object" || imageValue === null || Array.isArray(imageValue)) {
42783
+ diagnostics.errors.push(`"${imageField}" must be an object with either a "dockerfile" or "image" field.`);
42784
+ valid = false;
42785
+ continue;
42786
+ }
42787
+ const image = imageValue;
42788
+ const hasDockerfile = image.dockerfile !== void 0;
42789
+ const hasImage = image.image !== void 0;
42790
+ if (hasDockerfile === hasImage) {
42791
+ diagnostics.errors.push(`"${imageField}" must specify exactly one of "dockerfile" or "image".`);
42792
+ valid = false;
42793
+ }
42794
+ if (hasDockerfile && (typeof image.dockerfile !== "string" || image.dockerfile.length === 0)) {
42795
+ diagnostics.errors.push(`"${imageField}.dockerfile" must be a non-empty string.`);
42796
+ valid = false;
42797
+ }
42798
+ if (hasImage && (typeof image.image !== "string" || image.image.length === 0)) {
42799
+ diagnostics.errors.push(`"${imageField}.image" must be a non-empty string.`);
42800
+ valid = false;
42801
+ }
42802
+ if (typeof image.image === "string" && image.image.length > 0) {
42803
+ const registry2 = getCloudflareContainerRegistry(complianceConfig);
42804
+ const prefix = `${registry2}/`;
42805
+ const reference = image.image.slice(prefix.length);
42806
+ const digestReference = reference.match(/^[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*(?:\/[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*)+@sha256:[a-f0-9]{64}$/);
42807
+ if (!image.image.startsWith(prefix) || digestReference?.[0] !== reference) {
42808
+ diagnostics.errors.push(`"${imageField}.image" must be a digest-pinned image in the managed registry, in the form "${registry2}/<account-id>/<repository>@sha256:<64 lowercase hex characters>".`);
42809
+ valid = false;
42810
+ }
42811
+ }
42812
+ const unsupportedFields = Object.keys(image).filter((property) => property !== "dockerfile" && property !== "image");
42813
+ if (unsupportedFields.length > 0) {
42814
+ diagnostics.errors.push(`Unexpected fields found in ${imageField} field: ${unsupportedFields.map((property) => `"${property}"`).join(", ")}`);
42815
+ valid = false;
42816
+ }
42817
+ }
42818
+ return valid;
42819
+ }
42820
+ __name$3(validateDurableObjectContainerImages, "validateDurableObjectContainerImages");
42702
42821
  function validateContainerApp(envName, topLevelName, configPath, options = {}) {
42703
42822
  const { generateDefaultName = true } = options;
42704
42823
  return (diagnostics, field, value, config2) => {
@@ -42708,15 +42827,30 @@ function validateContainerApp(envName, topLevelName, configPath, options = {}) {
42708
42827
  return false;
42709
42828
  }
42710
42829
  for (const containerAppOptional of value) {
42711
- validateOptionalProperty(diagnostics, field, "class_name", containerAppOptional.class_name, "string");
42830
+ const isDurableObjectManaged = containerAppOptional.scheduling_policy === "durable_object";
42831
+ const hasValidDurableObjectClassName = typeof containerAppOptional.class_name === "string" && containerAppOptional.class_name.length > 0;
42832
+ if (isDurableObjectManaged) {
42833
+ if (!hasValidDurableObjectClassName) diagnostics.errors.push(`"containers.class_name" must be a non-empty string when "containers.scheduling_policy" is "durable_object".`);
42834
+ } else validateOptionalProperty(diagnostics, field, "class_name", containerAppOptional.class_name, "string");
42712
42835
  validateOptionalProperty(diagnostics, field, "name", containerAppOptional.name, "string");
42713
- if (generateDefaultName && !containerAppOptional.name) if (containerAppOptional.class_name === void 0) diagnostics.errors.push(`"containers.name" is required when "containers.class_name" is not defined, because there is no class name to derive a default name from. Either name this container and reference it from a Durable Object's \`exports\` entry, or set "containers.class_name".`);
42836
+ if (generateDefaultName && !containerAppOptional.name && (!isDurableObjectManaged || hasValidDurableObjectClassName)) if (containerAppOptional.class_name === void 0) diagnostics.errors.push(`"containers.name" is required when "containers.class_name" is not defined, because there is no class name to derive a default name from. Either name this container and reference it from a Durable Object's \`exports\` entry, or set "containers.class_name".`);
42714
42837
  else if (!topLevelName) diagnostics.errors.push(`Must have either a top level "name" and "containers.class_name" field defined, or have field "containers.name" defined.`);
42715
42838
  else {
42716
42839
  let name = `${topLevelName}-${containerAppOptional.class_name}`;
42717
42840
  name += config2 === void 0 ? "" : `-${envName}`;
42718
42841
  containerAppOptional.name = name.toLowerCase().replace(/ /g, "-");
42719
42842
  }
42843
+ if (isDurableObjectManaged) {
42844
+ validateDurableObjectContainerImages(diagnostics, `${field}.images`, containerAppOptional.images, options.complianceConfig);
42845
+ const unsupportedFields = Object.keys(containerAppOptional).filter((key) => ![
42846
+ "name",
42847
+ "class_name",
42848
+ "scheduling_policy",
42849
+ "images"
42850
+ ].includes(key));
42851
+ if (unsupportedFields.length > 0) diagnostics.errors.push(`Unsupported fields for Durable Object-managed Containers in ${field}: ${unsupportedFields.map((key) => `"${key}"`).join(",")}. Only "name", "class_name", "scheduling_policy", and "images" are supported.`);
42852
+ continue;
42853
+ }
42720
42854
  if (!containerAppOptional.configuration?.image && !containerAppOptional.image) diagnostics.errors.push(`"containers.image" field must be defined for each container app. This should be the path to your Dockerfile or an image URI pointing to the Cloudflare registry.`);
42721
42855
  if ("configuration" in containerAppOptional) {
42722
42856
  diagnostics.warnings.push(`"containers.configuration" is deprecated. Use top level "containers" fields instead. "configuration.image" should be "image", limits should be set via "instance_type".`);
@@ -43291,6 +43425,7 @@ var validateBindingsHaveUniqueNames = /* @__PURE__ */ __name$3((diagnostics, con
43291
43425
  const bindingNamesArray = Object.entries(friendlyBindingNames);
43292
43426
  const bindingsGroupedByType = Object.fromEntries(bindingNamesArray.map(([bindingType, binding]) => [binding, getBindingNames(bindingType === "queues" ? config2[bindingType]?.producers : config2[bindingType])]));
43293
43427
  bindingsGroupedByType["Secret"] = config2.secrets?.required ?? [];
43428
+ bindingsGroupedByType["Container images"] = [CONTAINER_IMAGES_BINDING];
43294
43429
  const bindingsGroupedByName = {};
43295
43430
  for (const bindingType in bindingsGroupedByType) {
43296
43431
  const bindingNames = bindingsGroupedByType[bindingType];
@@ -45327,7 +45462,7 @@ ${allTailConsumers.map(({ service, streaming }) => {
45327
45462
  let containersTitle = "The following containers are available:";
45328
45463
  if (context.name && isMultiWorker) containersTitle = `The following containers are available from ${source_default.blue(context.name)}:`;
45329
45464
  log$2(`${containersTitle}
45330
- ${containers.map((c$1) => `- ${c$1.name} (${c$1.image})`).join("\n")}`);
45465
+ ${containers.map((container) => container.scheduling_policy === "durable_object" ? `- ${container.class_name} (durable_object)` : `- ${container.name} (${container.image})`).join("\n")}`);
45331
45466
  log$2("");
45332
45467
  }
45333
45468
  if (context.unsafeMetadata) {
@@ -59847,7 +59982,7 @@ var require_command_exists = /* @__PURE__ */ __commonJS$2({ "../../node_modules/
59847
59982
  }) });
59848
59983
 
59849
59984
  //#endregion
59850
- //#region ../deploy-helpers/dist/chunk-PXVCTRCA.mjs
59985
+ //#region ../deploy-helpers/dist/chunk-3G6JZQDH.mjs
59851
59986
  var import_undici$1 = require_undici();
59852
59987
  var import_command_exists = require_command_exists();
59853
59988
  function handleUnsafeCapnp(capnp) {
@@ -60371,7 +60506,8 @@ function createWorkerUploadForm(worker, bindings, options) {
60371
60506
  bindings: metadataBindings,
60372
60507
  containers: worker.containers === void 0 ? void 0 : worker.containers.map((c$1) => ({
60373
60508
  ...c$1.name !== void 0 && { name: c$1.name },
60374
- ...c$1.class_name !== void 0 && { class_name: c$1.class_name }
60509
+ ...c$1.class_name !== void 0 && { class_name: c$1.class_name },
60510
+ ...c$1.images !== void 0 && { images: c$1.images }
60375
60511
  })),
60376
60512
  ...compatibility_date && { compatibility_date },
60377
60513
  ...compatibility_flags && { compatibility_flags },
@@ -60406,7 +60542,7 @@ __name$1(createWorkerUploadForm, "createWorkerUploadForm");
60406
60542
  //#endregion
60407
60543
  //#region ../remote-bindings/dist/index.mjs
60408
60544
  var import_undici = require_undici();
60409
- var version = "0.0.21";
60545
+ var version = "0.0.23";
60410
60546
  var NoDefaultValueProvided = class extends UserError$1 {
60411
60547
  constructor() {
60412
60548
  super("This command cannot be run in a non-interactive context", { telemetryMessage: "remote bindings prompt default missing" });