@void/platform 0.27.0 → 1.0.3

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.
@@ -37,7 +37,8 @@ html[data-theme="dark"] { color-scheme: dark; }
37
37
  .void-auth-page p { margin: 0; font: inherit; color: var(--auth-secondary); overflow-wrap: anywhere; }
38
38
  .void-auth-page strong { font-weight: 600; color: var(--auth-text); }
39
39
  .void-auth-page a:not(.void-auth-button) { color: var(--auth-text); text-underline-offset: 3px; }
40
- .void-auth-page .void-auth-actions { display: grid; gap: 12px; }
40
+ .void-auth-page form { display: grid; gap: 12px; }
41
+ .void-auth-page .void-auth-actions { display: grid; gap: 8px; }
41
42
  .void-auth-page .void-auth-button { display: flex; align-items: center; justify-content: center; width: 100%; min-height: 44px; padding: 10px 16px; border: 1px solid var(--auth-border); border-radius: var(--auth-radius-element); background: var(--auth-body); color: var(--auth-text); font: inherit; font-weight: 550; line-height: 1.4; text-align: center; text-decoration: none; overflow-wrap: anywhere; cursor: pointer; }
42
43
  .void-auth-page .void-auth-button-primary { background: var(--auth-accent); color: var(--auth-on-accent); border-color: var(--auth-accent); }
43
44
  .void-auth-page .void-auth-button:hover { filter: brightness(.92); }
package/dist/index.d.mts CHANGED
@@ -1,6 +1,23 @@
1
1
  import { BUILD_INSTANCE_FREE, BUILD_INSTANCE_LARGE, BuildInstanceType, BuiltinPlanId, EditablePlanLimit, PLAN_EDITABLE_LIMIT_KEYS, PLAN_LIMITS, PlanId, PlanLimits, PlanLimitsPatch, PlatformPlanCatalog, PlatformPlanDefinition, PlatformPlanReconciliation, createDefaultPlanCatalog, parseBuildInstanceType, parsePlanLimitsPatch, parsePlanName, parsePlatformPlanCatalog, parsePlatformPlanId, validatePlanLimits } from "./plans.mjs";
2
+ //#region src/access-policy.d.ts
3
+ /** An exact email domain, such as `example.com`, without wildcards or an `@`. */
4
+ export declare function isPlatformAccessEmailDomain(value: unknown): value is string;
5
+ /** Whether signing in with this Access identity provider proves a company identity. */
6
+ export declare function isPlatformAccessCompanyIdentityProvider(provider: Readonly<Record<string, unknown>>): boolean;
7
+ /**
8
+ * Whether one Access include or require rule restricts people to company
9
+ * identities. The installer checks the policies that protect the platform and
10
+ * the API checks project Zero Trust policies with this same rule list.
11
+ *
12
+ * A `login_method` rule admits everyone who can use the identity provider it
13
+ * names, so it counts only when `companyLoginMethod` accepts that provider ID.
14
+ */
15
+ export declare function isPlatformAccessIdentityRule(rule: Readonly<Record<string, unknown>>, companyLoginMethod: (identityProviderId: string) => boolean): boolean;
16
+ //#endregion
2
17
  //#region src/app-access.d.ts
3
18
  export declare const PLATFORM_APP_ACCESS_SETUP_PROOF_PREFIX = "void-platform-app-access-v1";
19
+ /** Uninstall handoff that turns off installer-managed project Zero Trust before any user exists. */
20
+ export declare const PLATFORM_APP_ACCESS_TURN_OFF_PROOF_PREFIX = "void-platform-app-access-turn-off-v1";
4
21
  /** Installer handoff. Token values belong only in encrypted recovery and request bodies. */
5
22
  type PlatformAppAccessSetup = Readonly<{
6
23
  version: 1;
package/dist/index.mjs CHANGED
@@ -1,6 +1,62 @@
1
+ import { a as isSourceRevision, c as requiredString, i as isSandboxDrainProtocol, n as isPrintableText, o as isUsageProtocolVersion, s as record, t as assertRecord } from "./validate-DbJR7Q0Z.mjs";
1
2
  import { BUILD_INSTANCE_FREE, BUILD_INSTANCE_LARGE, PLAN_EDITABLE_LIMIT_KEYS, PLAN_LIMITS, createDefaultPlanCatalog, parseBuildInstanceType, parsePlanLimitsPatch, parsePlanName, parsePlatformPlanCatalog, parsePlatformPlanId, validatePlanLimits } from "./plans.mjs";
3
+ //#region src/access-policy.ts
4
+ const COMPANY_IDENTITY_RULES = [
5
+ "email_list",
6
+ "gsuite",
7
+ "github-organization",
8
+ "saml",
9
+ "okta",
10
+ "azureAD",
11
+ "auth_context",
12
+ "group"
13
+ ];
14
+ const COMPANY_IDENTITY_PROVIDER_TYPES = /* @__PURE__ */ new Set([
15
+ "azureAD",
16
+ "centrify",
17
+ "google-apps",
18
+ "okta",
19
+ "onelogin",
20
+ "pingone"
21
+ ]);
22
+ function plainObject(value) {
23
+ return !!value && typeof value === "object" && !Array.isArray(value);
24
+ }
25
+ /** An exact email domain, such as `example.com`, without wildcards or an `@`. */
26
+ function isPlatformAccessEmailDomain(value) {
27
+ return typeof value === "string" && /^(?:[a-z0-9-]+\.)+[a-z]{2,63}$/i.test(value);
28
+ }
29
+ /** Whether signing in with this Access identity provider proves a company identity. */
30
+ function isPlatformAccessCompanyIdentityProvider(provider) {
31
+ if (provider.type === "cloudflare") return plainObject(provider.config) && provider.config.restrict_to_account_members === true;
32
+ return COMPANY_IDENTITY_PROVIDER_TYPES.has(provider.type);
33
+ }
34
+ /**
35
+ * Whether one Access include or require rule restricts people to company
36
+ * identities. The installer checks the policies that protect the platform and
37
+ * the API checks project Zero Trust policies with this same rule list.
38
+ *
39
+ * A `login_method` rule admits everyone who can use the identity provider it
40
+ * names, so it counts only when `companyLoginMethod` accepts that provider ID.
41
+ */
42
+ function isPlatformAccessIdentityRule(rule, companyLoginMethod) {
43
+ if (rule.email_domain) return plainObject(rule.email_domain) && isPlatformAccessEmailDomain(rule.email_domain.domain);
44
+ if (rule.email) return plainObject(rule.email) && typeof rule.email.email === "string" && /^[^\s*@]+@[^\s*@]+\.[^\s*@]+$/.test(rule.email.email);
45
+ if (rule.login_method) return plainObject(rule.login_method) && typeof rule.login_method.id === "string" && companyLoginMethod(rule.login_method.id);
46
+ if (rule.cloudflare_account_member) {
47
+ const member = rule.cloudflare_account_member;
48
+ return plainObject(member) && (member.account_id === void 0 || typeof member.account_id === "string" && /^[0-9a-f]{32}$/i.test(member.account_id));
49
+ }
50
+ return COMPANY_IDENTITY_RULES.some((key) => {
51
+ const value = Object.hasOwn(rule, key) ? rule[key] : void 0;
52
+ return plainObject(value) && Object.keys(value).length > 0;
53
+ });
54
+ }
55
+ //#endregion
2
56
  //#region src/app-access.ts
3
57
  const PLATFORM_APP_ACCESS_SETUP_PROOF_PREFIX = "void-platform-app-access-v1";
58
+ /** Uninstall handoff that turns off installer-managed project Zero Trust before any user exists. */
59
+ const PLATFORM_APP_ACCESS_TURN_OFF_PROOF_PREFIX = "void-platform-app-access-turn-off-v1";
4
60
  function parsePlatformAppAccessSetup(value) {
5
61
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid app access setup.");
6
62
  const input = value;
@@ -125,12 +181,8 @@ function parsePlatformAuthenticationSetup(value) {
125
181
  const DEFAULT_PLATFORM_SESSION_SECONDS = 2592e3;
126
182
  const GOOGLE_OIDC_ISSUER = "https://accounts.google.com";
127
183
  const PLATFORM_AUTH_SETUP_PROOF_PREFIX = "void.platform.auth.setup.v1";
128
- function record(value, name) {
129
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${name} must be an object.`);
130
- return value;
131
- }
132
184
  function string(value, name, maximum = 512) {
133
- if (typeof value !== "string" || !value.trim() || value.length > maximum || Array.from(value).some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127)) throw new Error(`${name} must be a nonempty string of at most ${maximum} characters.`);
185
+ if (!isPrintableText(value, maximum)) throw new Error(`${name} must be a nonempty string of at most ${maximum} characters.`);
134
186
  return value.trim();
135
187
  }
136
188
  function strings(value, name, maximum = 100) {
@@ -262,13 +314,6 @@ const CONTROL_PLANE_DEFAULTS = {
262
314
  dashboardHostname: null,
263
315
  proxyHostname: null
264
316
  };
265
- function assertRecord$1(value, label) {
266
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object.`);
267
- }
268
- function requiredString$1(value, label) {
269
- if (typeof value !== "string" || value.trim() === "") throw new Error(`${label} must be a non-empty string.`);
270
- return value;
271
- }
272
317
  function normalizeInstallationSlug(value) {
273
318
  const slug = value.trim().toLowerCase().replaceAll(/[^a-z0-9-]+/g, "-").replaceAll(/^-+|-+$/g, "").replaceAll(/-{2,}/g, "-");
274
319
  if (!slug) throw new Error("The installation name must contain a letter or number.");
@@ -384,7 +429,7 @@ function createPlatformDeploymentManifest(input) {
384
429
  dedicatedZone: input.application.dedicatedZone ?? false,
385
430
  zoneName,
386
431
  ...workersDev ? { workersDev: { ...workersDev } } : {},
387
- ...input.application.zoneId ? { zoneId: requiredString$1(input.application.zoneId, "application.zoneId") } : {}
432
+ ...input.application.zoneId ? { zoneId: requiredString(input.application.zoneId, "application.zoneId") } : {}
388
433
  },
389
434
  authentication: {
390
435
  providers: [...providers],
@@ -392,7 +437,7 @@ function createPlatformDeploymentManifest(input) {
392
437
  ...input.authentication?.accessProtection ? { accessProtection: true } : {}
393
438
  },
394
439
  capabilities,
395
- ...input.emailSharedZoneId !== void 0 ? { emailSharedZoneId: requiredString$1(input.emailSharedZoneId, "emailSharedZoneId") } : {},
440
+ ...input.emailSharedZoneId !== void 0 ? { emailSharedZoneId: requiredString(input.emailSharedZoneId, "emailSharedZoneId") } : {},
396
441
  ...input.emailSenderDomain !== void 0 ? { emailSenderDomain: normalizeApplicationDomain(input.emailSenderDomain) } : {},
397
442
  controlPlane: {
398
443
  ...CONTROL_PLANE_DEFAULTS,
@@ -402,7 +447,7 @@ function createPlatformDeploymentManifest(input) {
402
447
  dashboardHostname: input.controlPlane?.dashboardHostname ?? new URL(dashboardUrl).hostname
403
448
  } : {}
404
449
  },
405
- displayName: requiredString$1(input.displayName, "displayName").trim(),
450
+ displayName: requiredString(input.displayName, "displayName").trim(),
406
451
  installationSlug,
407
452
  resources,
408
453
  schemaVersion: input.appAccess !== void 0 ? 4 : configurable ? 3 : workersDev ? 2 : 1
@@ -416,30 +461,30 @@ function createPlatformDeploymentManifest(input) {
416
461
  const hostname = new URL(manifest.controlPlane.dashboardUrl).hostname;
417
462
  if (manifest.controlPlane.dashboardHostname !== hostname) throw new Error("The dashboard URL and dashboard hostname must agree.");
418
463
  }
419
- for (const [key, value] of Object.entries(manifest.resources)) requiredString$1(value, `resources.${key}`);
464
+ for (const [key, value] of Object.entries(manifest.resources)) requiredString(value, `resources.${key}`);
420
465
  return manifest;
421
466
  }
422
467
  function parsePlatformDeploymentManifest(value) {
423
- assertRecord$1(value, "Platform deployment manifest");
468
+ assertRecord(value, "Platform deployment manifest");
424
469
  if (value.schemaVersion !== 1 && value.schemaVersion !== 2 && value.schemaVersion !== 3 && value.schemaVersion !== 4) throw new Error(`Unsupported platform deployment schema version: ${String(value.schemaVersion)}.`);
425
470
  const application = value.application;
426
471
  const authentication = value.authentication;
427
472
  const rawCapabilities = value.capabilities;
428
473
  const controlPlane = value.controlPlane;
429
474
  const rawResources = value.resources;
430
- assertRecord$1(application, "application");
475
+ assertRecord(application, "application");
431
476
  let workersDev;
432
477
  if (value.schemaVersion === 2 || (value.schemaVersion === 3 || value.schemaVersion === 4) && application.workersDev !== void 0) {
433
- assertRecord$1(application.workersDev, "application.workersDev");
478
+ assertRecord(application.workersDev, "application.workersDev");
434
479
  workersDev = {
435
- subdomain: requiredString$1(application.workersDev.subdomain, "workersDev.subdomain"),
436
- installationId: requiredString$1(application.workersDev.installationId, "workersDev.installationId")
480
+ subdomain: requiredString(application.workersDev.subdomain, "workersDev.subdomain"),
481
+ installationId: requiredString(application.workersDev.installationId, "workersDev.installationId")
437
482
  };
438
483
  } else if (application.workersDev !== void 0) throw new Error("workers.dev requires platform deployment schema version 2.");
439
- assertRecord$1(rawCapabilities, "capabilities");
440
- assertRecord$1(controlPlane, "controlPlane");
441
- assertRecord$1(authentication, "authentication");
442
- assertRecord$1(rawResources, "resources");
484
+ assertRecord(rawCapabilities, "capabilities");
485
+ assertRecord(controlPlane, "controlPlane");
486
+ assertRecord(authentication, "authentication");
487
+ assertRecord(rawResources, "resources");
443
488
  const capabilityKeys = Object.keys(CORE_CAPABILITIES);
444
489
  const capabilities = {};
445
490
  for (const key of capabilityKeys) {
@@ -456,19 +501,19 @@ function parsePlatformDeploymentManifest(value) {
456
501
  "custom"
457
502
  ].includes(String(value.appAccess)) : value.appAccess !== void 0) throw new Error("Guided app access requires deployment schema version 4 and a valid appAccess choice.");
458
503
  if (authentication.configurable !== void 0 && authentication.configurable !== true) throw new Error("Invalid configurable authentication flag.");
459
- const resourceDefaults = createPlatformResourceNames(requiredString$1(value.installationSlug, "installationSlug"));
504
+ const resourceDefaults = createPlatformResourceNames(requiredString(value.installationSlug, "installationSlug"));
460
505
  const resources = {};
461
- for (const key of Object.keys(resourceDefaults)) resources[key] = requiredString$1(rawResources[key] ?? (key === "emailGatewayWorker" || key === "deploymentQueue" ? resourceDefaults[key] : void 0), `resources.${key}`);
506
+ for (const key of Object.keys(resourceDefaults)) resources[key] = requiredString(rawResources[key] ?? (key === "emailGatewayWorker" || key === "deploymentQueue" ? resourceDefaults[key] : void 0), `resources.${key}`);
462
507
  const readHostname = (key) => {
463
508
  const hostname = controlPlane[key];
464
- return hostname === null ? null : requiredString$1(hostname, `controlPlane.${key}`);
509
+ return hostname === null ? null : requiredString(hostname, `controlPlane.${key}`);
465
510
  };
466
511
  return createPlatformDeploymentManifest({
467
512
  ...value.schemaVersion === 4 ? { appAccess: value.appAccess } : {},
468
513
  application: {
469
- baseDomain: requiredString$1(application.baseDomain, "application.baseDomain"),
514
+ baseDomain: requiredString(application.baseDomain, "application.baseDomain"),
470
515
  dedicatedZone: application.dedicatedZone === true,
471
- zoneName: workersDev && application.zoneName === "" ? "" : requiredString$1(application.zoneName, "application.zoneName"),
516
+ zoneName: workersDev && application.zoneName === "" ? "" : requiredString(application.zoneName, "application.zoneName"),
472
517
  ...workersDev ? { workersDev } : {},
473
518
  ...typeof application.zoneId === "string" ? { zoneId: application.zoneId } : {}
474
519
  },
@@ -478,16 +523,16 @@ function parsePlatformDeploymentManifest(value) {
478
523
  ...authentication.accessProtection === true ? { accessProtection: true } : {}
479
524
  },
480
525
  capabilities,
481
- ...value.emailSharedZoneId !== void 0 ? { emailSharedZoneId: requiredString$1(value.emailSharedZoneId, "emailSharedZoneId") } : {},
482
- ...value.emailSenderDomain !== void 0 ? { emailSenderDomain: requiredString$1(value.emailSenderDomain, "emailSenderDomain") } : {},
526
+ ...value.emailSharedZoneId !== void 0 ? { emailSharedZoneId: requiredString(value.emailSharedZoneId, "emailSharedZoneId") } : {},
527
+ ...value.emailSenderDomain !== void 0 ? { emailSenderDomain: requiredString(value.emailSenderDomain, "emailSenderDomain") } : {},
483
528
  controlPlane: {
484
529
  apiHostname: readHostname("apiHostname"),
485
530
  dashboardHostname: readHostname("dashboardHostname"),
486
- ...controlPlane.dashboardUrl !== void 0 ? { dashboardUrl: requiredString$1(controlPlane.dashboardUrl, "controlPlane.dashboardUrl") } : {},
531
+ ...controlPlane.dashboardUrl !== void 0 ? { dashboardUrl: requiredString(controlPlane.dashboardUrl, "controlPlane.dashboardUrl") } : {},
487
532
  proxyHostname: readHostname("proxyHostname")
488
533
  },
489
- displayName: requiredString$1(value.displayName, "displayName"),
490
- installationSlug: requiredString$1(value.installationSlug, "installationSlug"),
534
+ displayName: requiredString(value.displayName, "displayName"),
535
+ installationSlug: requiredString(value.installationSlug, "installationSlug"),
491
536
  resources
492
537
  });
493
538
  }
@@ -609,13 +654,6 @@ const STATUS_TRANSITIONS = {
609
654
  "uninstalling"
610
655
  ]
611
656
  };
612
- function assertRecord(value, label) {
613
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object.`);
614
- }
615
- function requiredString(value, label) {
616
- if (typeof value !== "string" || value.trim() === "") throw new Error(`${label} must be a non-empty string.`);
617
- return value;
618
- }
619
657
  function isInstallationStatus(value) {
620
658
  return typeof value === "string" && Object.hasOwn(STATUS_TRANSITIONS, value);
621
659
  }
@@ -847,15 +885,14 @@ function parseAuthenticationResources(value) {
847
885
  return resources;
848
886
  }
849
887
  function parseUsageProtocolVersion(value) {
850
- if (value === void 0 || value === 0) return 0;
851
- if (value === 1) return 1;
852
- if (value === 2) return 2;
853
- throw new Error("usageProtocolVersion must be 0, 1, or 2.");
888
+ if (value === void 0) return 0;
889
+ if (!isUsageProtocolVersion(value)) throw new Error("usageProtocolVersion must be 0, 1, or 2.");
890
+ return value;
854
891
  }
855
892
  function parseSafetyProtocols(value) {
856
893
  if (value === void 0) return { sandboxDrain: 0 };
857
894
  assertRecord(value, "safetyProtocols");
858
- if (value.sandboxDrain !== 0 && value.sandboxDrain !== 1 && value.sandboxDrain !== 2 && value.sandboxDrain !== 3) throw new Error("safetyProtocols.sandboxDrain must be 0, 1, 2, or 3.");
895
+ if (!isSandboxDrainProtocol(value.sandboxDrain)) throw new Error("safetyProtocols.sandboxDrain must be 0, 1, 2, or 3.");
859
896
  return { sandboxDrain: value.sandboxDrain };
860
897
  }
861
898
  function parsePlatformRuntimeProvenance(value) {
@@ -865,7 +902,7 @@ function parsePlatformRuntimeProvenance(value) {
865
902
  const manifestSha256 = requiredString(value.manifestSha256, "runtime.manifestSha256");
866
903
  if (!/^[0-9a-f]{64}$/.test(manifestSha256)) throw new Error("runtime.manifestSha256 must be a SHA-256 digest.");
867
904
  const sourceRevision = value.sourceRevision === null || value.sourceRevision === void 0 ? null : requiredString(value.sourceRevision, "runtime.sourceRevision");
868
- if (sourceRevision !== null && (sourceRevision.length > 200 || !/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(sourceRevision))) throw new Error("runtime.sourceRevision is invalid.");
905
+ if (sourceRevision !== null && !isSourceRevision(sourceRevision)) throw new Error("runtime.sourceRevision is invalid.");
869
906
  return {
870
907
  manifestSha256,
871
908
  source: value.source,
@@ -890,10 +927,14 @@ function readPlatformApplication(env) {
890
927
  zoneName: baseDomain,
891
928
  dedicatedZone: false
892
929
  };
930
+ return parsePlatformApplication(JSON.parse(env.PLATFORM_APPLICATION));
931
+ }
932
+ /** Applies the deployment manifest's application rules to a parsed value. */
933
+ function parsePlatformApplication(value) {
893
934
  return createPlatformDeploymentManifest({
894
935
  installationSlug: "runtime",
895
936
  displayName: "Runtime",
896
- application: JSON.parse(env.PLATFORM_APPLICATION)
937
+ application: value
897
938
  }).application;
898
939
  }
899
940
  function platformWorkersDevAliasKey(hostname) {
@@ -968,7 +1009,7 @@ function createPlatformDiscoveryDocument(input) {
968
1009
  if (!input.displayName.trim()) throw new Error("displayName must not be empty.");
969
1010
  if (!input.platformVersion.trim()) throw new Error("platformVersion must not be empty.");
970
1011
  if (input.applicationRouting) {
971
- const application = readPlatformApplication({ PLATFORM_APPLICATION: JSON.stringify(input.applicationRouting) });
1012
+ const application = parsePlatformApplication(input.applicationRouting);
972
1013
  if (!application.workersDev || application.baseDomain !== input.applicationDomain || application.workersDev.installationId !== input.installationId) throw new Error("Application routing must match the discovery domain and installation identity.");
973
1014
  }
974
1015
  const usageProtocolVersion = parseUsageProtocolVersion(input.usageProtocolVersion);
@@ -994,13 +1035,12 @@ function createPlatformDiscoveryDocument(input) {
994
1035
  };
995
1036
  }
996
1037
  function parsePlatformDiscoveryDocument(value) {
997
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Platform discovery document must be an object.");
998
- const document = value;
1038
+ const document = record(value, "Platform discovery document");
999
1039
  if (document.schemaVersion !== 1 && document.schemaVersion !== 2 && document.schemaVersion !== 3) throw new Error(`Unsupported platform discovery schema version: ${String(document.schemaVersion)}.`);
1000
1040
  const capabilities = document.capabilities;
1001
1041
  if (document.schemaVersion === 1 && document.applicationRouting !== void 0) throw new Error("Application routing requires discovery schema version 2.");
1002
1042
  if (document.schemaVersion === 2 && document.applicationRouting === void 0) throw new Error("Discovery schema version 2 requires application routing.");
1003
- if (!capabilities || typeof capabilities !== "object" || Array.isArray(capabilities)) throw new Error("capabilities must be an object.");
1043
+ assertRecord(capabilities, "capabilities");
1004
1044
  const capabilityNames = [
1005
1045
  "ai",
1006
1046
  "customDomains",
@@ -1032,7 +1072,7 @@ function parsePlatformDiscoveryDocument(value) {
1032
1072
  return createPlatformDiscoveryDocument({
1033
1073
  apiUrl,
1034
1074
  applicationDomain: string("applicationDomain"),
1035
- ...document.applicationRouting !== void 0 ? { applicationRouting: readPlatformApplication({ PLATFORM_APPLICATION: JSON.stringify(document.applicationRouting) }) } : {},
1075
+ ...document.applicationRouting !== void 0 ? { applicationRouting: parsePlatformApplication(document.applicationRouting) } : {},
1036
1076
  authenticationProviders: providers,
1037
1077
  ...authentication ? { authentication } : {},
1038
1078
  capabilities: parsedCapabilities,
@@ -1045,8 +1085,7 @@ function parsePlatformDiscoveryDocument(value) {
1045
1085
  });
1046
1086
  }
1047
1087
  function parseAuthentication(value) {
1048
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Authentication discovery must be an object.");
1049
- const authentication = value;
1088
+ const authentication = record(value, "Authentication discovery");
1050
1089
  if (!Array.isArray(authentication.methods) || authentication.methods.length > 32 || typeof authentication.protectedByAccess !== "boolean" || authentication.setupPending !== void 0 && typeof authentication.setupPending !== "boolean") throw new Error("Authentication discovery requires login methods and a protection flag.");
1051
1090
  const methods = authentication.methods.map(parsePlatformLoginDescriptor);
1052
1091
  if (new Set(methods.map((method) => method.id)).size !== methods.length) throw new Error("Authentication connection IDs must be unique.");
@@ -1281,7 +1320,6 @@ function createPlatformWorkerConfigs(input) {
1281
1320
  proxy,
1282
1321
  emailGateway: {
1283
1322
  ...common,
1284
- workers_dev: publicEndpoints,
1285
1323
  preview_urls: false,
1286
1324
  name: names.emailGatewayWorker,
1287
1325
  main: runtimeEntrypoints.emailGateway,
@@ -1359,4 +1397,4 @@ function createPlatformWorkerConfigs(input) {
1359
1397
  };
1360
1398
  }
1361
1399
  //#endregion
1362
- export { BUILD_INSTANCE_FREE, BUILD_INSTANCE_LARGE, DEFAULT_PLATFORM_SESSION_SECONDS, GOOGLE_OIDC_ISSUER, PLAN_EDITABLE_LIMIT_KEYS, PLAN_LIMITS, PLATFORM_APPLICATION_KEY, PLATFORM_APP_ACCESS_SETUP_PROOF_PREFIX, PLATFORM_AUTH_SETUP_PROOF_PREFIX, PLATFORM_DEPLOYMENT_SCHEMA_VERSION, PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE, PLATFORM_DISCOVERY_SCHEMA_VERSION, PLATFORM_HEALTH_HOSTNAME_LABEL, PLATFORM_INSTALLATION_SCHEMA_VERSION, PLATFORM_LOGIN_KINDS, PLATFORM_PROJECT_INGRESS_SOURCE, PLATFORM_R2_OWNERSHIP_MARKER_KEY, PLATFORM_REMOTE_INSTALLATION_MANIFEST_KEY, PLATFORM_RESOURCE_OWNERSHIP_SCHEMA_VERSION, PLATFORM_SANDBOX_DRAIN_KEY, PLATFORM_USAGE_PROTOCOL_VERSION, createApplicationRoutes, createDefaultPlanCatalog, createPlatformDeploymentManifest, createPlatformDiscoveryDocument, createPlatformInstallationManifest, createPlatformResourceNames, createPlatformResourceOwnershipMarker, createPlatformWorkerConfigs, isPlatformSignupAllowed, normalizeApplicationDomain, normalizeInstallationSlug, normalizePlatformDashboardUrl, parseBuildInstanceType, parsePlanLimitsPatch, parsePlanName, parsePlatformAccessProtection, parsePlatformAdmissionPolicy, parsePlatformAppAccessSetup, parsePlatformAuthenticationSetup, parsePlatformDeploymentManifest, parsePlatformDiscoveryDocument, parsePlatformIdentityUrl, parsePlatformInstallationManifest, parsePlatformLifecycleOperation, parsePlatformLoginConfiguration, parsePlatformLoginDescriptor, parsePlatformLoginId, parsePlatformPlanCatalog, parsePlatformPlanId, parsePlatformResourceOwnershipMarker, parsePlatformSignupAllowlistEntry, platformAuthenticationRecoveryMessage, platformDashboardUrl, platformHealthHostname, platformProjectHostname, platformProjectHostnames, platformProjectIngressName, platformProjectIngressPrefix, platformProjectWorkersDevHostname, platformProtectionProofMessage, platformWorkersDevAliasKey, readPlatformApplication, recordInstallationResource, recordInstallationStep, resolvePlatformApplicationEnvironment, setInstallationDesiredState, setInstallationEndpoints, transitionInstallation, validatePlanLimits, validatePlatformAdmissionPolicy };
1400
+ export { BUILD_INSTANCE_FREE, BUILD_INSTANCE_LARGE, DEFAULT_PLATFORM_SESSION_SECONDS, GOOGLE_OIDC_ISSUER, PLAN_EDITABLE_LIMIT_KEYS, PLAN_LIMITS, PLATFORM_APPLICATION_KEY, PLATFORM_APP_ACCESS_SETUP_PROOF_PREFIX, PLATFORM_APP_ACCESS_TURN_OFF_PROOF_PREFIX, PLATFORM_AUTH_SETUP_PROOF_PREFIX, PLATFORM_DEPLOYMENT_SCHEMA_VERSION, PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE, PLATFORM_DISCOVERY_SCHEMA_VERSION, PLATFORM_HEALTH_HOSTNAME_LABEL, PLATFORM_INSTALLATION_SCHEMA_VERSION, PLATFORM_LOGIN_KINDS, PLATFORM_PROJECT_INGRESS_SOURCE, PLATFORM_R2_OWNERSHIP_MARKER_KEY, PLATFORM_REMOTE_INSTALLATION_MANIFEST_KEY, PLATFORM_RESOURCE_OWNERSHIP_SCHEMA_VERSION, PLATFORM_SANDBOX_DRAIN_KEY, PLATFORM_USAGE_PROTOCOL_VERSION, createApplicationRoutes, createDefaultPlanCatalog, createPlatformDeploymentManifest, createPlatformDiscoveryDocument, createPlatformInstallationManifest, createPlatformResourceNames, createPlatformResourceOwnershipMarker, createPlatformWorkerConfigs, isPlatformAccessCompanyIdentityProvider, isPlatformAccessEmailDomain, isPlatformAccessIdentityRule, isPlatformSignupAllowed, normalizeApplicationDomain, normalizeInstallationSlug, normalizePlatformDashboardUrl, parseBuildInstanceType, parsePlanLimitsPatch, parsePlanName, parsePlatformAccessProtection, parsePlatformAdmissionPolicy, parsePlatformAppAccessSetup, parsePlatformAuthenticationSetup, parsePlatformDeploymentManifest, parsePlatformDiscoveryDocument, parsePlatformIdentityUrl, parsePlatformInstallationManifest, parsePlatformLifecycleOperation, parsePlatformLoginConfiguration, parsePlatformLoginDescriptor, parsePlatformLoginId, parsePlatformPlanCatalog, parsePlatformPlanId, parsePlatformResourceOwnershipMarker, parsePlatformSignupAllowlistEntry, platformAuthenticationRecoveryMessage, platformDashboardUrl, platformHealthHostname, platformProjectHostname, platformProjectHostnames, platformProjectIngressName, platformProjectIngressPrefix, platformProjectWorkersDevHostname, platformProtectionProofMessage, platformWorkersDevAliasKey, readPlatformApplication, recordInstallationResource, recordInstallationStep, resolvePlatformApplicationEnvironment, setInstallationDesiredState, setInstallationEndpoints, transitionInstallation, validatePlanLimits, validatePlatformAdmissionPolicy };
@@ -1,3 +1,4 @@
1
+ import { a as isSourceRevision, i as isSandboxDrainProtocol, o as isUsageProtocolVersion, r as isRecord } from "./validate-DbJR7Q0Z.mjs";
1
2
  import { createHash } from "node:crypto";
2
3
  import { readFileSync, realpathSync, statSync } from "node:fs";
3
4
  import { fileURLToPath } from "node:url";
@@ -105,26 +106,20 @@ function parsePlatformRuntimeManifest(value) {
105
106
  }
106
107
  function parseSafetyProtocols(value) {
107
108
  if (value === void 0) return { sandboxDrain: 0 };
108
- const protocols = record(value, "runtime manifest safetyProtocols");
109
- if (protocols.sandboxDrain !== 0 && protocols.sandboxDrain !== 1 && protocols.sandboxDrain !== 2 && protocols.sandboxDrain !== 3) throw new Error("runtime manifest safetyProtocols.sandboxDrain must be 0, 1, 2, or 3");
110
- return { sandboxDrain: protocols.sandboxDrain };
109
+ const { sandboxDrain } = record(value, "runtime manifest safetyProtocols");
110
+ if (!isSandboxDrainProtocol(sandboxDrain)) throw new Error("runtime manifest safetyProtocols.sandboxDrain must be 0, 1, 2, or 3");
111
+ return { sandboxDrain };
111
112
  }
112
113
  function usageProtocolVersion(value) {
113
- if (value === void 0 || value === 0) return 0;
114
- if (value === 1) return 1;
115
- if (value === 2) return 2;
116
- throw new Error("runtime manifest usageProtocolVersion must be 0, 1, or 2");
114
+ if (value === void 0) return 0;
115
+ if (!isUsageProtocolVersion(value)) throw new Error("runtime manifest usageProtocolVersion must be 0, 1, or 2");
116
+ return value;
117
117
  }
118
118
  function getPlatformRuntimeDirectory() {
119
119
  return join(dirname(fileURLToPath(import.meta.url)), "runtime");
120
120
  }
121
121
  function readPlatformRuntimeManifest(runtimeDirectory = getPlatformRuntimeDirectory()) {
122
- const path = join(runtimeDirectory, "manifest.json");
123
- try {
124
- return parsePlatformRuntimeManifest(JSON.parse(readFileSync(path, "utf8")));
125
- } catch (error) {
126
- throw new Error(`Void Platform deployment artifacts are missing or invalid at ${path}: ${error instanceof Error ? error.message : String(error)}`);
127
- }
122
+ return readRuntimeManifestFile(join(runtimeDirectory, "manifest.json")).manifest;
128
123
  }
129
124
  function resolvePlatformRuntime(customRuntimeDirectory, baseDirectory = process.cwd()) {
130
125
  const source = customRuntimeDirectory ? "custom" : "package";
@@ -136,22 +131,25 @@ function resolvePlatformRuntime(customRuntimeDirectory, baseDirectory = process.
136
131
  } catch (error) {
137
132
  throw new Error(`Void Platform runtime directory is unavailable at ${requestedDirectory}: ${error instanceof Error ? error.message : String(error)}`);
138
133
  }
139
- const manifestPath = join(directory, "manifest.json");
140
- let manifestContents;
141
- let manifest;
142
- try {
143
- manifestContents = readFileSync(manifestPath);
144
- manifest = parsePlatformRuntimeManifest(JSON.parse(manifestContents.toString("utf8")));
145
- } catch (error) {
146
- throw new Error(`Void Platform deployment artifacts are missing or invalid at ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`);
147
- }
134
+ const { contents, manifest } = readRuntimeManifestFile(join(directory, "manifest.json"));
148
135
  return {
149
136
  directory,
150
137
  manifest,
151
- manifestSha256: createHash("sha256").update(manifestContents).digest("hex"),
138
+ manifestSha256: createHash("sha256").update(contents).digest("hex"),
152
139
  source
153
140
  };
154
141
  }
142
+ function readRuntimeManifestFile(path) {
143
+ try {
144
+ const contents = readFileSync(path);
145
+ return {
146
+ contents,
147
+ manifest: parsePlatformRuntimeManifest(JSON.parse(contents.toString("utf8")))
148
+ };
149
+ } catch (error) {
150
+ throw new Error(`Void Platform deployment artifacts are missing or invalid at ${path}: ${error instanceof Error ? error.message : String(error)}`);
151
+ }
152
+ }
155
153
  function parseArtifact(value, name) {
156
154
  const artifact = record(value, `runtime manifest artifact ${name}`);
157
155
  const path = nonemptyString(artifact.path, `runtime manifest artifact ${name} path`);
@@ -179,7 +177,7 @@ function parseMigration(value, position) {
179
177
  };
180
178
  }
181
179
  function record(value, name) {
182
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${name} must be an object`);
180
+ if (!isRecord(value)) throw new Error(`${name} must be an object`);
183
181
  return value;
184
182
  }
185
183
  function array(value, name) {
@@ -192,7 +190,7 @@ function nonemptyString(value, name) {
192
190
  }
193
191
  function sourceRevision(value) {
194
192
  const revision = nonemptyString(value, "runtime manifest sourceRevision");
195
- if (revision.length > 200 || !/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(revision)) throw new Error("runtime manifest sourceRevision is invalid");
193
+ if (!isSourceRevision(revision)) throw new Error("runtime manifest sourceRevision is invalid");
196
194
  return revision;
197
195
  }
198
196
  function safeInteger(value, name) {
package/dist/plans.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { n as isPrintableText, s as record } from "./validate-DbJR7Q0Z.mjs";
1
2
  //#region src/plans.ts
2
3
  const GB = 1073741824;
3
4
  const PLAN_LIMITS = {
@@ -119,15 +120,11 @@ function parsePlatformPlanId(value) {
119
120
  return value;
120
121
  }
121
122
  function parsePlanName(value) {
122
- if (typeof value !== "string" || !value.trim() || value.length > 80 || Array.from(value).some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127)) throw new Error("Plan names must contain 1 to 80 printable characters.");
123
+ if (!isPrintableText(value, 80)) throw new Error("Plan names must contain 1 to 80 printable characters.");
123
124
  return value.trim();
124
125
  }
125
- function object(value, label) {
126
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(label + " must be an object.");
127
- return value;
128
- }
129
126
  function parsePlanLimitsPatch(value) {
130
- const input = object(value, "Plan limits");
127
+ const input = record(value, "Plan limits");
131
128
  for (const [key, limit] of Object.entries(input)) {
132
129
  if (!PLAN_EDITABLE_LIMIT_KEYS.includes(key)) throw new Error("Unknown or unenforced plan limit: " + key + ".");
133
130
  if (!Number.isSafeInteger(limit) || limit < 0) throw new Error(key + " must be a nonnegative safe integer; 0 means unlimited.");
@@ -146,18 +143,18 @@ function parseBuildInstanceType(value) {
146
143
  }
147
144
  /** Strict saved-state validation: invalid configuration must not silently lift quotas. */
148
145
  function parsePlatformPlanCatalog(value) {
149
- const input = object(value, "Plan catalog");
146
+ const input = record(value, "Plan catalog");
150
147
  if (!Number.isSafeInteger(input.revision) || input.revision < 0) throw new Error("Invalid plan catalog revision.");
151
148
  if (!Array.isArray(input.plans) || input.plans.length === 0 || input.plans.length > 100) throw new Error("A plan catalog must contain between 1 and 100 plans.");
152
149
  const ids = /* @__PURE__ */ new Set();
153
150
  const plans = input.plans.map((value) => {
154
- const plan = object(value, "Plan");
151
+ const plan = record(value, "Plan");
155
152
  const id = parsePlatformPlanId(plan.id);
156
153
  if (ids.has(id)) throw new Error("Duplicate plan ID: " + id + ".");
157
154
  ids.add(id);
158
155
  if (typeof plan.archived !== "boolean") throw new Error("archived must be a boolean.");
159
156
  if (typeof plan.allowShortSlugs !== "boolean") throw new Error("allowShortSlugs must be a boolean.");
160
- const limits = object(plan.limits, "Plan limits");
157
+ const limits = record(plan.limits, "Plan limits");
161
158
  const keys = Object.keys(PLAN_LIMITS.free);
162
159
  if (Object.keys(limits).length !== keys.length || keys.some((key) => !Object.hasOwn(limits, key))) throw new Error("Plan limits must contain all supported fields.");
163
160
  validatePlanLimits(limits);
@@ -174,13 +171,13 @@ function parsePlatformPlanCatalog(value) {
174
171
  if (!plans.some((plan) => plan.id === defaultPlanId && !plan.archived)) throw new Error("The default plan must exist and be active.");
175
172
  let reconciliation = null;
176
173
  if (input.reconciliation !== null) {
177
- const operation = object(input.reconciliation, "Plan reconciliation");
174
+ const operation = record(input.reconciliation, "Plan reconciliation");
178
175
  if (operation.revision !== input.revision || typeof operation.complete !== "boolean" || !(operation.cursor === null || typeof operation.cursor === "string") || !Array.isArray(operation.planIds) || operation.planIds.length > 100) throw new Error("Invalid plan reconciliation state.");
179
176
  const planIds = operation.planIds.map(parsePlatformPlanId);
180
177
  if (planIds.some((id) => !ids.has(id))) throw new Error("A reconciliation plan is missing.");
181
178
  let error;
182
179
  if (operation.error !== void 0) {
183
- const failure = object(operation.error, "Plan reconciliation failure");
180
+ const failure = record(operation.error, "Plan reconciliation failure");
184
181
  if (typeof failure.accountId !== "string" || typeof failure.message !== "string" || failure.message.length > 1e3) throw new Error("Invalid plan reconciliation failure.");
185
182
  error = {
186
183
  accountId: failure.accountId,