@cloudflare/workers-utils 0.41.2 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  export { MetricsRegistry } from './chunk-Z62CVNHJ.mjs';
2
2
  import { external_exports } from './chunk-OWXQB7GP.mjs';
3
3
  export { formatZodError } from './chunk-OWXQB7GP.mjs';
4
- import { isRedirectedRawConfig, configFileName, formatConfigSnippet, getDurableObjectExports, getContainerNameToClassNameMap, parsePackageJSON, readFileSync, ParseError, parseJSON, APIError, dir, parseTOML, modify, applyEdits, format, dist_default, parseJSONC } from './chunk-IKXB77SR.mjs';
5
- export { APIError, ENVIRONMENT_TAG_PREFIX, INHERIT_SYMBOL, JSON_CONFIG_FORMATS, PATH_TO_DEPLOY_CONFIG, ParseError, SERVICE_TAG_PREFIX, configFileName, configFormat, experimental_readRawConfig, findWranglerConfig, formatConfigSnippet, getContainerDurableObjectClassNames, getContainerNameToClassNameMap, getDurableObjectClassNameToUseSQLiteMap, getDurableObjectContainerApps, getDurableObjectExports, getResolvedDurableObjectContainerApps, hasDurableObjectExports, indexLocation, isDurableObjectContainerApp, isRedirectedConfig, parseByteSize, parseHumanDuration, parseJSON, parseJSONC, parseNonHyphenedUuid, parsePackageJSON, parseTOML, partitionExports, readFileSync, readFileSyncToBuffer, resolveContainerClassName, resolveWranglerConfigPath, searchLocation, validateDurableObjectContainerApplications } from './chunk-IKXB77SR.mjs';
6
- import { assertNever } from './chunk-4PNP2TCS.mjs';
7
- export { DEFAULT_COMPAT_DATE, assertNever, constructWranglerConfig, mapWorkerMetadataBindings } from './chunk-4PNP2TCS.mjs';
4
+ import { isRedirectedRawConfig, configFileName, formatConfigSnippet, partitionExports, getDurableObjectExports, getContainerNameToClassNameMap, parsePackageJSON, readFileSync, ParseError, parseJSON, APIError, isLiveDurableObjectExport, dir, parseTOML, modify, applyEdits, format, stringify, parseJSONC } from './chunk-FLRJ77A6.mjs';
5
+ export { APIError, ENVIRONMENT_TAG_PREFIX, INHERIT_SYMBOL, JSON_CONFIG_FORMATS, PATH_TO_DEPLOY_CONFIG, ParseError, SERVICE_TAG_PREFIX, configFileName, configFormat, experimental_readRawConfig, findWranglerConfig, formatConfigSnippet, getContainerDurableObjectClassNames, getContainerNameToClassNameMap, getDurableObjectClassNameToUseSQLiteMap, getDurableObjectContainerApps, getDurableObjectExports, getResolvedDurableObjectContainerApps, hasDurableObjectExports, indexLocation, isDurableObjectContainerApp, isLiveDurableObjectExport, isRedirectedConfig, parseByteSize, parseHumanDuration, parseJSON, parseJSONC, parseNonHyphenedUuid, parsePackageJSON, parseTOML, partitionExports, readFileSync, readFileSyncToBuffer, resolveContainerClassName, resolveWranglerConfigPath, searchLocation, validateDurableObjectContainerApplications } from './chunk-FLRJ77A6.mjs';
6
+ import { assertNever } from './chunk-DKSA7K25.mjs';
7
+ export { DEFAULT_COMPAT_DATE, assertNever, constructWranglerConfig, mapWorkerMetadataBindings } from './chunk-DKSA7K25.mjs';
8
8
  export { NODEJS_COMPAT_DEFAULT_ON_DATE, NODEJS_COMPAT_V2_SWITCH_OVER_DATE, getTodaysCompatDate, isCompatDate, isNodejsCompatDefaultOn, resolveNodejsCompat, stripRedundantNodejsCompatFlags } from './chunk-C6O4ION7.mjs';
9
9
  import { getCloudflareEnv, getCloudflareContainerRegistry, getCloudflareApiBaseUrl, getTraceHeader, getCloudflaredPathFromEnv, getOutputFilePathFromEnv, getOutputFileDirectoryFromEnv, getCIOverrideName, getWranglerCacheDirFromEnv } from './chunk-IYSONYTF.mjs';
10
10
  export { COMPLIANCE_REGION_CONFIG_PUBLIC, COMPLIANCE_REGION_CONFIG_UNKNOWN, getBrowserRenderingHeadfulFromEnv, getBuildConditionsFromEnv, getBuildPlatformFromEnv, getC3CommandFromEnv, getCIGeneratePreviewAlias, getCIMatchTag, getCIOverrideName, getCIOverrideNetworkModeHost, getCfFetchEnabledFromEnv, getCfFetchPathFromEnv, getCloudflareApiBaseUrl, getCloudflareApiEnvironmentFromEnv, getCloudflareComplianceRegion, getCloudflareContainerRegistry, getCloudflareEnv, getCloudflareIncludeProcessEnvFromEnv, getCloudflareLoadDevVarsFromDotEnv, getCloudflaredPathFromEnv, getComplianceRegionSubdomain, getD1ExtraLocationChoices, getDisableConfigWatching, getLocalExplorerEnabledFromEnv, getLocalObservabilityEnabledFromEnv, getNoSkillsUpdatePromptsFromEnv, getOpenNextDeployFromEnv, getOutputFileDirectoryFromEnv, getOutputFilePathFromEnv, getRegistryPath, getSanitizeLogs, getSubdomainMixedStateCheckDisabled, getTraceHeader, getWorkersCIBranchName, getWranglerCacheDirFromEnv, getWranglerHideBanner, getWranglerSendErrorReportsFromEnv, getWranglerSendMetricsFromEnv, isDoNotTrackEnabled } from './chunk-IYSONYTF.mjs';
@@ -2582,7 +2582,7 @@ var experimental_patchConfig = /* @__PURE__ */ __name((configPath, patch, isArra
2582
2582
  const formatEdit = format(configString, void 0, {});
2583
2583
  configString = applyEdits(configString, formatEdit);
2584
2584
  if (configPath.endsWith(".toml")) {
2585
- configString = dist_default.stringify(parseJSONC(configString));
2585
+ configString = stringify(parseJSONC(configString));
2586
2586
  }
2587
2587
  writeFileSync(configPath, configString);
2588
2588
  return configString;
@@ -4736,6 +4736,7 @@ function normalizeAndValidateEnvironment(diagnostics, configPath, rawEnv, isDisp
4736
4736
  environment.migrations,
4737
4737
  environment.exports
4738
4738
  );
4739
+ validateWorkflowExportConflicts(diagnostics, environment.exports);
4739
4740
  const containersDeclaredElsewhere = rawConfig !== void 0 ? rawConfig.containers !== void 0 : Object.values("env" in rawEnv ? rawEnv.env ?? {} : {}).some(
4740
4741
  (rawNamedEnv) => rawNamedEnv?.containers !== void 0
4741
4742
  );
@@ -5228,20 +5229,170 @@ var validateDurableObjectBinding = /* @__PURE__ */ __name((diagnostics, field, v
5228
5229
  return isValid;
5229
5230
  }, "validateDurableObjectBinding");
5230
5231
  var workflowNameFormatMessage = `Workflow names must be 1-64 characters long, start with a letter, number, or underscore, and may only contain letters, numbers, underscores, or hyphens.`;
5231
- function validateWorkflowRetentionValue(diagnostics, field, key, value) {
5232
+ function validateWorkflowRetentionValue(diagnostics, field, kind, key, value) {
5232
5233
  const isValidNumber = typeof value === "number" && Number.isInteger(value) && value > 0;
5233
5234
  const isValidString = typeof value === "string" && value.length > 0;
5234
5235
  if (isValidNumber || isValidString) {
5235
5236
  return true;
5236
5237
  }
5237
5238
  diagnostics.errors.push(
5238
- `"${field}" bindings "default_retention.${key}" field must be a positive integer of milliseconds or a duration string such as "3 days", but got ${JSON.stringify(
5239
+ `"${field}" ${kind} "default_retention.${key}" field must be a positive integer of milliseconds or a duration string such as "3 days", but got ${JSON.stringify(
5239
5240
  value
5240
5241
  )}.`
5241
5242
  );
5242
5243
  return false;
5243
5244
  }
5244
5245
  __name(validateWorkflowRetentionValue, "validateWorkflowRetentionValue");
5246
+ function validateWorkflowSchedules(diagnostics, field, kind, value) {
5247
+ const { schedules } = value;
5248
+ if (schedules === void 0) {
5249
+ return true;
5250
+ }
5251
+ if (typeof schedules === "string") {
5252
+ if (schedules.length === 0) {
5253
+ diagnostics.errors.push(
5254
+ `"${field}" ${kind} "schedules" field must not be an empty string.`
5255
+ );
5256
+ return false;
5257
+ }
5258
+ return true;
5259
+ }
5260
+ if (Array.isArray(schedules)) {
5261
+ if (schedules.length === 0) {
5262
+ diagnostics.errors.push(
5263
+ `"${field}" ${kind} "schedules" field must not be an empty array.`
5264
+ );
5265
+ return false;
5266
+ }
5267
+ if (!schedules.every((s) => typeof s === "string")) {
5268
+ diagnostics.errors.push(
5269
+ `"${field}" ${kind} should, optionally, have a string or array of strings "schedules" field but got ${JSON.stringify(
5270
+ value
5271
+ )}.`
5272
+ );
5273
+ return false;
5274
+ }
5275
+ if (schedules.some((s) => s === "")) {
5276
+ diagnostics.errors.push(
5277
+ `"${field}" ${kind} "schedules" field must not contain empty strings.`
5278
+ );
5279
+ return false;
5280
+ }
5281
+ return true;
5282
+ }
5283
+ diagnostics.errors.push(
5284
+ `"${field}" ${kind} should, optionally, have a string or array of strings "schedules" field but got ${JSON.stringify(
5285
+ value
5286
+ )}.`
5287
+ );
5288
+ return false;
5289
+ }
5290
+ __name(validateWorkflowSchedules, "validateWorkflowSchedules");
5291
+ function validateWorkflowLimits(diagnostics, field, kind, value) {
5292
+ const { limits } = value;
5293
+ if (limits === void 0) {
5294
+ return true;
5295
+ }
5296
+ if (typeof limits !== "object" || limits === null || Array.isArray(limits)) {
5297
+ diagnostics.errors.push(
5298
+ `"${field}" ${kind} should, optionally, have an object "limits" field but got ${JSON.stringify(
5299
+ value
5300
+ )}.`
5301
+ );
5302
+ return false;
5303
+ }
5304
+ let valid = true;
5305
+ const { steps } = limits;
5306
+ if (steps !== void 0) {
5307
+ if (typeof steps !== "number" || !Number.isInteger(steps) || steps < 1) {
5308
+ diagnostics.errors.push(
5309
+ `"${field}" ${kind} "limits.steps" field must be a positive integer but got ${JSON.stringify(
5310
+ steps
5311
+ )}.`
5312
+ );
5313
+ valid = false;
5314
+ } else if (steps > 25e3) {
5315
+ diagnostics.warnings.push(
5316
+ `"${field}" has a step limit of ${steps}, which exceeds the production maximum of 25,000. This configuration may not work when deployed.`
5317
+ );
5318
+ }
5319
+ }
5320
+ validateAdditionalProperties(
5321
+ diagnostics,
5322
+ `${field}.limits`,
5323
+ Object.keys(limits),
5324
+ ["steps"]
5325
+ );
5326
+ return valid;
5327
+ }
5328
+ __name(validateWorkflowLimits, "validateWorkflowLimits");
5329
+ function validateWorkflowDefaultRetention(diagnostics, field, kind, value) {
5330
+ const { default_retention: defaultRetention } = value;
5331
+ if (defaultRetention === void 0) {
5332
+ return true;
5333
+ }
5334
+ if (typeof defaultRetention !== "object" || defaultRetention === null || Array.isArray(defaultRetention)) {
5335
+ diagnostics.errors.push(
5336
+ `"${field}" ${kind} should, optionally, have an object "default_retention" field but got ${JSON.stringify(
5337
+ value
5338
+ )}.`
5339
+ );
5340
+ return false;
5341
+ }
5342
+ let valid = true;
5343
+ const retention = defaultRetention;
5344
+ for (const key of ["success_retention", "error_retention"]) {
5345
+ if (retention[key] !== void 0 && !validateWorkflowRetentionValue(
5346
+ diagnostics,
5347
+ field,
5348
+ kind,
5349
+ key,
5350
+ retention[key]
5351
+ )) {
5352
+ valid = false;
5353
+ }
5354
+ }
5355
+ validateAdditionalProperties(
5356
+ diagnostics,
5357
+ `${field}.default_retention`,
5358
+ Object.keys(retention),
5359
+ ["success_retention", "error_retention"]
5360
+ );
5361
+ return valid;
5362
+ }
5363
+ __name(validateWorkflowDefaultRetention, "validateWorkflowDefaultRetention");
5364
+ function validateWorkflowConcurrency(diagnostics, field, kind, value) {
5365
+ const { concurrency } = value;
5366
+ if (concurrency === void 0) {
5367
+ return true;
5368
+ }
5369
+ if (typeof concurrency !== "object" || concurrency === null || Array.isArray(concurrency)) {
5370
+ diagnostics.errors.push(
5371
+ `"${field}" ${kind} should, optionally, have an object "concurrency" field but got ${JSON.stringify(
5372
+ value
5373
+ )}.`
5374
+ );
5375
+ return false;
5376
+ }
5377
+ let valid = true;
5378
+ const { limit } = concurrency;
5379
+ if (limit !== void 0 && (typeof limit !== "number" || !Number.isInteger(limit) || limit < 1)) {
5380
+ diagnostics.errors.push(
5381
+ `"${field}" ${kind} "concurrency.limit" field must be a positive integer but got ${JSON.stringify(
5382
+ limit
5383
+ )}.`
5384
+ );
5385
+ valid = false;
5386
+ }
5387
+ validateAdditionalProperties(
5388
+ diagnostics,
5389
+ `${field}.concurrency`,
5390
+ Object.keys(concurrency),
5391
+ ["limit"]
5392
+ );
5393
+ return valid;
5394
+ }
5395
+ __name(validateWorkflowConcurrency, "validateWorkflowConcurrency");
5245
5396
  var validateWorkflowBinding = /* @__PURE__ */ __name((diagnostics, field, value) => {
5246
5397
  if (typeof value !== "object" || value === null) {
5247
5398
  diagnostics.errors.push(
@@ -5287,128 +5438,16 @@ var validateWorkflowBinding = /* @__PURE__ */ __name((diagnostics, field, value)
5287
5438
  );
5288
5439
  isValid = false;
5289
5440
  }
5290
- if (hasProperty(value, "schedules") && value.schedules !== void 0) {
5291
- if (typeof value.schedules === "string") {
5292
- if (value.schedules.length === 0) {
5293
- diagnostics.errors.push(
5294
- `"${field}" bindings "schedules" field must not be an empty string.`
5295
- );
5296
- isValid = false;
5297
- }
5298
- } else if (Array.isArray(value.schedules)) {
5299
- if (value.schedules.length === 0) {
5300
- diagnostics.errors.push(
5301
- `"${field}" bindings "schedules" field must not be an empty array.`
5302
- );
5303
- isValid = false;
5304
- } else if (!value.schedules.every((s) => typeof s === "string")) {
5305
- diagnostics.errors.push(
5306
- `"${field}" bindings should, optionally, have a string or array of strings "schedules" field but got ${JSON.stringify(
5307
- value
5308
- )}.`
5309
- );
5310
- isValid = false;
5311
- } else if (value.schedules.some((s) => s === "")) {
5312
- diagnostics.errors.push(
5313
- `"${field}" bindings "schedules" field must not contain empty strings.`
5314
- );
5315
- isValid = false;
5316
- }
5317
- } else {
5318
- diagnostics.errors.push(
5319
- `"${field}" bindings should, optionally, have a string or array of strings "schedules" field but got ${JSON.stringify(
5320
- value
5321
- )}.`
5322
- );
5323
- isValid = false;
5324
- }
5325
- }
5326
- if (hasProperty(value, "limits") && value.limits !== void 0) {
5327
- if (typeof value.limits !== "object" || value.limits === null || Array.isArray(value.limits)) {
5328
- diagnostics.errors.push(
5329
- `"${field}" bindings should, optionally, have an object "limits" field but got ${JSON.stringify(
5330
- value
5331
- )}.`
5332
- );
5333
- isValid = false;
5334
- } else {
5335
- const limits = value.limits;
5336
- if (limits.steps !== void 0) {
5337
- if (typeof limits.steps !== "number" || !Number.isInteger(limits.steps) || limits.steps < 1) {
5338
- diagnostics.errors.push(
5339
- `"${field}" bindings "limits.steps" field must be a positive integer but got ${JSON.stringify(
5340
- limits.steps
5341
- )}.`
5342
- );
5343
- isValid = false;
5344
- } else if (limits.steps > 25e3) {
5345
- diagnostics.warnings.push(
5346
- `"${field}" has a step limit of ${limits.steps}, which exceeds the production maximum of 25,000. This configuration may not work when deployed.`
5347
- );
5348
- }
5349
- }
5350
- validateAdditionalProperties(
5351
- diagnostics,
5352
- `${field}.limits`,
5353
- Object.keys(limits),
5354
- ["steps"]
5355
- );
5356
- }
5357
- }
5358
- if (hasProperty(value, "default_retention") && value.default_retention !== void 0) {
5359
- if (typeof value.default_retention !== "object" || value.default_retention === null || Array.isArray(value.default_retention)) {
5360
- diagnostics.errors.push(
5361
- `"${field}" bindings should, optionally, have an object "default_retention" field but got ${JSON.stringify(
5362
- value
5363
- )}.`
5364
- );
5365
- isValid = false;
5366
- } else {
5367
- const defaultRetention = value.default_retention;
5368
- for (const key of ["success_retention", "error_retention"]) {
5369
- if (defaultRetention[key] !== void 0 && !validateWorkflowRetentionValue(
5370
- diagnostics,
5371
- field,
5372
- key,
5373
- defaultRetention[key]
5374
- )) {
5375
- isValid = false;
5376
- }
5377
- }
5378
- validateAdditionalProperties(
5379
- diagnostics,
5380
- `${field}.default_retention`,
5381
- Object.keys(defaultRetention),
5382
- ["success_retention", "error_retention"]
5383
- );
5384
- }
5385
- }
5386
- if (hasProperty(value, "concurrency") && value.concurrency !== void 0) {
5387
- if (typeof value.concurrency !== "object" || value.concurrency === null || Array.isArray(value.concurrency)) {
5388
- diagnostics.errors.push(
5389
- `"${field}" bindings should, optionally, have an object "concurrency" field but got ${JSON.stringify(
5390
- value
5391
- )}.`
5392
- );
5393
- isValid = false;
5394
- } else {
5395
- const concurrency = value.concurrency;
5396
- if (concurrency.limit !== void 0 && (typeof concurrency.limit !== "number" || !Number.isInteger(concurrency.limit) || concurrency.limit < 1)) {
5397
- diagnostics.errors.push(
5398
- `"${field}" bindings "concurrency.limit" field must be a positive integer but got ${JSON.stringify(
5399
- concurrency.limit
5400
- )}.`
5401
- );
5402
- isValid = false;
5403
- }
5404
- validateAdditionalProperties(
5405
- diagnostics,
5406
- `${field}.concurrency`,
5407
- Object.keys(concurrency),
5408
- ["limit"]
5409
- );
5410
- }
5411
- }
5441
+ const settings = value;
5442
+ isValid = validateWorkflowSchedules(diagnostics, field, "bindings", settings) && isValid;
5443
+ isValid = validateWorkflowLimits(diagnostics, field, "bindings", settings) && isValid;
5444
+ isValid = validateWorkflowDefaultRetention(
5445
+ diagnostics,
5446
+ field,
5447
+ "bindings",
5448
+ settings
5449
+ ) && isValid;
5450
+ isValid = validateWorkflowConcurrency(diagnostics, field, "bindings", settings) && isValid;
5412
5451
  validateAdditionalProperties(diagnostics, field, Object.keys(value), [
5413
5452
  "binding",
5414
5453
  "name",
@@ -5729,6 +5768,19 @@ function validateSshPublicKeys(diagnostics, field, value, nameRequired) {
5729
5768
  }
5730
5769
  }
5731
5770
  __name(validateSshPublicKeys, "validateSshPublicKeys");
5771
+ function validateContainerSshConfig(diagnostics, field, value) {
5772
+ const sshConfig = typeof value === "object" && value !== null ? value : {};
5773
+ if (!isRequiredProperty(sshConfig, "enabled", "boolean")) {
5774
+ diagnostics.errors.push(`${field}.enabled must be a boolean`);
5775
+ }
5776
+ const port = "port" in sshConfig ? sshConfig.port : void 0;
5777
+ if (!isOptionalProperty(sshConfig, "port", "number") || typeof port === "number" && (!Number.isInteger(port) || port < 1 || port > 65535)) {
5778
+ diagnostics.errors.push(
5779
+ `${field}.port must be a number between 1 and 65535 inclusive`
5780
+ );
5781
+ }
5782
+ }
5783
+ __name(validateContainerSshConfig, "validateContainerSshConfig");
5732
5784
  function validatePreviewsContainers(envName, configPath) {
5733
5785
  const innerValidator = validateContainerApp(envName, void 0, configPath, {
5734
5786
  generateDefaultName: false
@@ -5979,12 +6031,29 @@ function validateContainerApp(envName, topLevelName, configPath, options = {}) {
5979
6031
  "scheduling_policy",
5980
6032
  "images",
5981
6033
  "observability",
6034
+ "ssh",
6035
+ "authorized_keys",
5982
6036
  "unsafe"
5983
6037
  ].includes(key)
5984
6038
  );
5985
6039
  if (unsupportedFields.length > 0) {
5986
6040
  diagnostics.errors.push(
5987
- `Unsupported fields for Durable Object-managed Containers in ${field}: ${unsupportedFields.map((key) => `"${key}"`).join(",")}. Only "name", "class_name", "scheduling_policy", "images", "observability", and restricted "unsafe" settings are supported.`
6041
+ `Unsupported fields for Durable Object-managed Containers in ${field}: ${unsupportedFields.map((key) => `"${key}"`).join(",")}. Only "name", "class_name", "scheduling_policy", "images", "observability", "ssh", "authorized_keys", and restricted "unsafe" settings are supported.`
6042
+ );
6043
+ }
6044
+ if ("ssh" in containerAppOptional) {
6045
+ validateContainerSshConfig(
6046
+ diagnostics,
6047
+ `${field}.ssh`,
6048
+ containerAppOptional.ssh
6049
+ );
6050
+ }
6051
+ if ("authorized_keys" in containerAppOptional) {
6052
+ validateSshPublicKeys(
6053
+ diagnostics,
6054
+ `${field}.authorized_keys`,
6055
+ containerAppOptional.authorized_keys,
6056
+ true
5988
6057
  );
5989
6058
  }
5990
6059
  continue;
@@ -6202,30 +6271,20 @@ function validateContainerApp(envName, topLevelName, configPath, options = {}) {
6202
6271
  ["image", "secrets", "labels", "disk", "vcpu", "memory_mib"]
6203
6272
  );
6204
6273
  }
6205
- let sshField;
6206
- let sshConfig;
6207
6274
  if ("ssh" in containerAppOptional) {
6208
- sshField = "ssh";
6209
- sshConfig = containerAppOptional.ssh;
6275
+ validateContainerSshConfig(
6276
+ diagnostics,
6277
+ `${field}.ssh`,
6278
+ containerAppOptional.ssh
6279
+ );
6210
6280
  containerAppOptional.wrangler_ssh = containerAppOptional.ssh;
6211
6281
  delete containerAppOptional.ssh;
6212
6282
  } else if ("wrangler_ssh" in containerAppOptional) {
6213
- sshField = "wrangler_ssh";
6214
- sshConfig = containerAppOptional.wrangler_ssh;
6215
- }
6216
- if (sshField !== void 0) {
6217
- const sshConfigObject = typeof sshConfig === "object" && sshConfig !== null ? sshConfig : {};
6218
- if (!isRequiredProperty(sshConfigObject, "enabled", "boolean")) {
6219
- diagnostics.errors.push(
6220
- `${field}.${sshField}.enabled must be a boolean`
6221
- );
6222
- }
6223
- const sshPort = "port" in sshConfigObject ? sshConfigObject.port : void 0;
6224
- if (!isOptionalProperty(sshConfigObject, "port", "number") || typeof sshPort === "number" && (sshPort < 1 || sshPort > 65535)) {
6225
- diagnostics.errors.push(
6226
- `${field}.${sshField}.port must be a number between 1 and 65535 inclusive`
6227
- );
6228
- }
6283
+ validateContainerSshConfig(
6284
+ diagnostics,
6285
+ `${field}.wrangler_ssh`,
6286
+ containerAppOptional.wrangler_ssh
6287
+ );
6229
6288
  }
6230
6289
  if ("authorized_keys" in containerAppOptional) {
6231
6290
  validateSshPublicKeys(
@@ -7445,23 +7504,31 @@ var validateConnectHandler = /* @__PURE__ */ __name((diagnostics, field, value)
7445
7504
  return false;
7446
7505
  }
7447
7506
  let isValid = true;
7448
- if (!validateAdditionalProperties(diagnostics, field, Object.keys(value), [
7449
- "protocol",
7450
- "port",
7451
- "address"
7452
- ])) {
7507
+ const connectHandler = value;
7508
+ if (!validateAdditionalProperties(
7509
+ diagnostics,
7510
+ field,
7511
+ Object.keys(value),
7512
+ connectHandler.protocol === "udp" ? [
7513
+ "protocol",
7514
+ "port",
7515
+ "address",
7516
+ "idle_timeout_ms",
7517
+ "max_pending_bytes"
7518
+ ] : ["protocol", "port", "address"]
7519
+ )) {
7453
7520
  isValid = false;
7454
7521
  }
7455
- if ("protocol" in value && value.protocol !== "tcp") {
7522
+ if ("protocol" in value && value.protocol !== "tcp" && value.protocol !== "udp") {
7456
7523
  diagnostics.errors.push(
7457
- `"${field}" should have a "protocol" field of "tcp" but got ${JSON.stringify(
7524
+ `"${field}" should have a "protocol" field of "tcp" or "udp" but got ${JSON.stringify(
7458
7525
  value.protocol
7459
7526
  )}.`
7460
7527
  );
7461
7528
  isValid = false;
7462
7529
  } else if (!("protocol" in value)) {
7463
7530
  diagnostics.errors.push(
7464
- `"${field}" should have a "protocol" field of "tcp" but got ${JSON.stringify(
7531
+ `"${field}" should have a "protocol" field of "tcp" or "udp" but got ${JSON.stringify(
7465
7532
  value
7466
7533
  )}.`
7467
7534
  );
@@ -7490,6 +7557,20 @@ var validateConnectHandler = /* @__PURE__ */ __name((diagnostics, field, value)
7490
7557
  );
7491
7558
  isValid = false;
7492
7559
  }
7560
+ if (connectHandler.protocol === "udp") {
7561
+ for (const option of ["idle_timeout_ms", "max_pending_bytes"]) {
7562
+ if (!(option in connectHandler)) {
7563
+ continue;
7564
+ }
7565
+ const optionValue = connectHandler[option];
7566
+ if (typeof optionValue !== "number" || !Number.isInteger(optionValue) || optionValue < 0 || optionValue > 4294967295) {
7567
+ diagnostics.errors.push(
7568
+ `"${field}" should have an integer "${option}" field between 0 and 4294967295 but got ${JSON.stringify(value)}.`
7569
+ );
7570
+ isValid = false;
7571
+ }
7572
+ }
7573
+ }
7493
7574
  return isValid;
7494
7575
  }, "validateConnectHandler");
7495
7576
  var validateCompatibilityDate = /* @__PURE__ */ __name((diagnostics, field, value) => {
@@ -8402,6 +8483,47 @@ function validateWorkerExportCache(diagnostics, field, value) {
8402
8483
  return valid;
8403
8484
  }
8404
8485
  __name(validateWorkerExportCache, "validateWorkerExportCache");
8486
+ function validateWorkflowExport(diagnostics, exportName, workflowExport) {
8487
+ const field = `exports.${exportName}`;
8488
+ let valid = true;
8489
+ valid = validateRequiredProperty(
8490
+ diagnostics,
8491
+ field,
8492
+ "name",
8493
+ workflowExport.name,
8494
+ "string"
8495
+ ) && valid;
8496
+ if (typeof workflowExport.name === "string" && !isValidWorkflowName(workflowExport.name)) {
8497
+ diagnostics.errors.push(
8498
+ `"${field}.name" is invalid. ${workflowNameFormatMessage}`
8499
+ );
8500
+ valid = false;
8501
+ }
8502
+ valid = validateWorkflowSchedules(diagnostics, field, "export", workflowExport) && valid;
8503
+ valid = validateWorkflowLimits(diagnostics, field, "export", workflowExport) && valid;
8504
+ valid = validateWorkflowDefaultRetention(
8505
+ diagnostics,
8506
+ field,
8507
+ "export",
8508
+ workflowExport
8509
+ ) && valid;
8510
+ valid = validateWorkflowConcurrency(diagnostics, field, "export", workflowExport) && valid;
8511
+ valid = validateAdditionalProperties(
8512
+ diagnostics,
8513
+ field,
8514
+ Object.keys(workflowExport),
8515
+ [
8516
+ "type",
8517
+ "name",
8518
+ "limits",
8519
+ "concurrency",
8520
+ "schedules",
8521
+ "default_retention"
8522
+ ]
8523
+ ) && valid;
8524
+ return valid;
8525
+ }
8526
+ __name(validateWorkflowExport, "validateWorkflowExport");
8405
8527
  var validateExports = /* @__PURE__ */ __name((diagnostics, field, value) => {
8406
8528
  if (value === void 0 || value === null) {
8407
8529
  return true;
@@ -8429,10 +8551,12 @@ var validateExports = /* @__PURE__ */ __name((diagnostics, field, value) => {
8429
8551
  valid = validateDurableObjectExport(diagnostics, exportName, exportConfig) && valid;
8430
8552
  } else if (exportConfig.type === "worker") {
8431
8553
  valid = validateWorkerExport(diagnostics, exportName, exportConfig) && valid;
8554
+ } else if (exportConfig.type === "workflow") {
8555
+ valid = validateWorkflowExport(diagnostics, exportName, exportConfig) && valid;
8432
8556
  } else {
8433
8557
  valid = false;
8434
8558
  diagnostics.errors.push(
8435
- `"exports.${exportName}.type" must be "durable-object" or "worker", but got ${JSON.stringify(exportConfig.type)}.`
8559
+ `"exports.${exportName}.type" must be "durable-object", "worker", or "workflow", but got ${JSON.stringify(exportConfig.type)}.`
8436
8560
  );
8437
8561
  }
8438
8562
  }
@@ -8841,8 +8965,7 @@ function warnIfDurableObjectsHaveNoLifecycleConfig(diagnostics, durableObjects,
8841
8965
  if (entry === void 0 || entry.type !== "durable-object") {
8842
8966
  return false;
8843
8967
  }
8844
- const state = entry.state ?? "created";
8845
- return state === "created" || state === "expecting-transfer";
8968
+ return isLiveDurableObjectExport(entry);
8846
8969
  }, "exportsCovers");
8847
8970
  const uncoveredByExports = exportedDurableObjects.filter(
8848
8971
  (binding) => typeof binding.class_name !== "string" || !exportsCovers(binding.class_name)
@@ -8881,6 +9004,25 @@ function errorIfMigrationsAndExportsBothSet(diagnostics, migrations, exports$1)
8881
9004
  }
8882
9005
  }
8883
9006
  __name(errorIfMigrationsAndExportsBothSet, "errorIfMigrationsAndExportsBothSet");
9007
+ function validateWorkflowExportConflicts(diagnostics, exports$1) {
9008
+ const classNamesByWorkflowName = /* @__PURE__ */ new Map();
9009
+ for (const [className, workflowExport] of Object.entries(
9010
+ partitionExports(exports$1).workflow
9011
+ )) {
9012
+ if (typeof workflowExport.name !== "string") {
9013
+ continue;
9014
+ }
9015
+ const existing = classNamesByWorkflowName.get(workflowExport.name);
9016
+ if (existing !== void 0) {
9017
+ diagnostics.errors.push(
9018
+ `"exports.${existing}" and "exports.${className}" both declare the Workflow "${workflowExport.name}". Workflow names must be unique.`
9019
+ );
9020
+ continue;
9021
+ }
9022
+ classNamesByWorkflowName.set(workflowExport.name, className);
9023
+ }
9024
+ }
9025
+ __name(validateWorkflowExportConflicts, "validateWorkflowExportConflicts");
8884
9026
  function validateContainerExportLinks(diagnostics, containers, exports$1, containersDeclaredElsewhere) {
8885
9027
  if (containers !== void 0 && !Array.isArray(containers)) {
8886
9028
  return;