@void/platform 0.20.1 → 0.20.2
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/README.md +10 -1
- package/dist/email-protocol.d.mts +48 -0
- package/dist/email-protocol.mjs +278 -0
- package/dist/index.d.mts +152 -13
- package/dist/index.mjs +346 -20
- package/dist/installer.d.mts +4 -2
- package/dist/installer.mjs +13 -4
- package/dist/runtime/api/README.md +1 -1
- package/dist/runtime/api/index.js +67382 -54178
- package/dist/runtime/api/index.js.map +4 -4
- package/dist/runtime/dispatch/README.md +1 -1
- package/dist/runtime/dispatch/index.js +26 -8
- package/dist/runtime/dispatch/index.js.map +2 -2
- package/dist/runtime/drizzle/0041_military_beyonder.sql +119 -0
- package/dist/runtime/drizzle/0042_dark_the_anarchist.sql +1 -0
- package/dist/runtime/drizzle/0043_nostalgic_meggan.sql +21 -0
- package/dist/runtime/drizzle/0044_smart_mentor.sql +15 -0
- package/dist/runtime/drizzle/0045_platform_settings.sql +5 -0
- package/dist/runtime/drizzle/0046_email_domains_platform_credential.sql +8 -0
- package/dist/runtime/drizzle/0047_email_gateway.sql +226 -0
- package/dist/runtime/drizzle/0048_project_teams.sql +133 -0
- package/dist/runtime/drizzle/compatibility.json +4 -0
- package/dist/runtime/drizzle/meta/_journal.json +56 -0
- package/dist/runtime/emailGateway/README.md +1 -0
- package/dist/runtime/emailGateway/index.js +5893 -0
- package/dist/runtime/emailGateway/index.js.map +8 -0
- package/dist/runtime/manifest.json +70 -11
- package/dist/runtime/proxy/README.md +1 -1
- package/dist/runtime/proxy/index.js +1629 -2242
- package/dist/runtime/proxy/index.js.map +4 -4
- package/dist/runtime/tail/README.md +1 -1
- package/package.json +5 -1
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,222 @@
|
|
|
1
|
+
//#region src/authentication-recovery.ts
|
|
2
|
+
function platformAuthenticationRecoveryMessage(value) {
|
|
3
|
+
return JSON.stringify([
|
|
4
|
+
"void-platform-auth-recovery-v1",
|
|
5
|
+
value.installationId,
|
|
6
|
+
value.administratorUserId,
|
|
7
|
+
value.connectionId,
|
|
8
|
+
value.revision,
|
|
9
|
+
value.generation,
|
|
10
|
+
value.testId,
|
|
11
|
+
value.expiresAt
|
|
12
|
+
]);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/authentication.ts
|
|
16
|
+
/** Platform login and perimeter configuration are independent of app authentication. */
|
|
17
|
+
const PLATFORM_LOGIN_KINDS = [
|
|
18
|
+
"github",
|
|
19
|
+
"google",
|
|
20
|
+
"oidc",
|
|
21
|
+
"cloudflare-access"
|
|
22
|
+
];
|
|
23
|
+
/** Operator-side coverage verification, bound to one administrator and settings revision. */
|
|
24
|
+
function platformProtectionProofMessage(input) {
|
|
25
|
+
return `void-platform-protection-v1\n${JSON.stringify({
|
|
26
|
+
installationId: input.installationId,
|
|
27
|
+
origin: input.origin,
|
|
28
|
+
userId: input.userId,
|
|
29
|
+
sessionId: input.sessionId,
|
|
30
|
+
revision: input.revision,
|
|
31
|
+
lifecycleVersion: input.lifecycleVersion,
|
|
32
|
+
protection: parsePlatformAccessProtection(input.protection),
|
|
33
|
+
expiresAt: input.expiresAt
|
|
34
|
+
})}`;
|
|
35
|
+
}
|
|
36
|
+
function parsePlatformSignupAllowlistEntry(value) {
|
|
37
|
+
const entry = record(value, "Signup allowlist entry");
|
|
38
|
+
const note = entry.note;
|
|
39
|
+
if (note !== void 0 && (typeof note !== "string" || note.length > 1e3)) throw new Error("Signup allowlist notes must be strings of at most 1000 characters.");
|
|
40
|
+
const optionalNote = note === void 0 ? {} : { note };
|
|
41
|
+
if (entry.type === "identity") {
|
|
42
|
+
const connectionId = parsePlatformLoginId(entry.connectionId);
|
|
43
|
+
if (typeof entry.subject !== "string" || entry.subject.length === 0 || entry.subject.length > 255) throw new Error("Identity subjects must be nonempty strings of at most 255 characters.");
|
|
44
|
+
return {
|
|
45
|
+
type: "identity",
|
|
46
|
+
connectionId,
|
|
47
|
+
subject: entry.subject,
|
|
48
|
+
...optionalNote
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (entry.type !== "github" && entry.type !== "email") throw new Error("Signup allowlist entry type must be github, email, or identity.");
|
|
52
|
+
if (typeof entry.pattern !== "string" || !entry.pattern || entry.pattern.length > 320 || /[\s,]/.test(entry.pattern)) throw new Error("Signup allowlist patterns must be nonempty strings of at most 320 characters.");
|
|
53
|
+
return {
|
|
54
|
+
type: entry.type,
|
|
55
|
+
pattern: entry.pattern,
|
|
56
|
+
...optionalNote
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** Match one verified login identity against persisted signup grants. */
|
|
60
|
+
function isPlatformSignupAllowed(identity, entries) {
|
|
61
|
+
return entries.some((entry) => {
|
|
62
|
+
if (entry.type === "identity") return entry.connectionId === identity.connectionId && entry.subject === identity.subject;
|
|
63
|
+
if (entry.type === "github") return identity.provider === "github" && entry.pattern.toLowerCase() === identity.login.toLowerCase();
|
|
64
|
+
if (!identity.email) return false;
|
|
65
|
+
if (entry.pattern.startsWith("*@")) return identity.email.toLowerCase().endsWith(entry.pattern.slice(1).toLowerCase());
|
|
66
|
+
return entry.pattern.toLowerCase() === identity.email.toLowerCase();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function parsePlatformAuthenticationSetup(value) {
|
|
70
|
+
const input = record(value, "Authentication setup");
|
|
71
|
+
if (!Array.isArray(input.connections) || input.connections.length === 0 || input.connections.length > 32) throw new Error("Authentication setup requires between 1 and 32 connections.");
|
|
72
|
+
const connections = input.connections.map((value) => {
|
|
73
|
+
const entry = record(value, "Login connection");
|
|
74
|
+
string(entry.clientSecret, "Client secret", 8192);
|
|
75
|
+
return {
|
|
76
|
+
configuration: parsePlatformLoginConfiguration(entry.configuration),
|
|
77
|
+
clientSecret: entry.clientSecret
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
if (new Set(connections.map((entry) => entry.configuration.id)).size !== connections.length) throw new Error("Authentication setup connection IDs must be unique.");
|
|
81
|
+
const administratorConnectionId = parsePlatformLoginId(input.administratorConnectionId);
|
|
82
|
+
if (!connections.some((entry) => entry.configuration.id === administratorConnectionId)) throw new Error("The administrator login method must be included in setup.");
|
|
83
|
+
if (typeof input.bootstrapCredentialHash !== "string" || !/^[a-f0-9]{64}$/.test(input.bootstrapCredentialHash)) throw new Error("A SHA-256 bootstrap credential hash is required.");
|
|
84
|
+
const admission = parsePlatformAdmissionPolicy(input.admission);
|
|
85
|
+
const protection = parsePlatformAccessProtection(input.protection ?? null);
|
|
86
|
+
validatePlatformAdmissionPolicy(admission, connections.map((entry) => entry.configuration), protection);
|
|
87
|
+
if (input.resetPending !== void 0 && typeof input.resetPending !== "boolean") throw new Error("resetPending must be a boolean.");
|
|
88
|
+
return {
|
|
89
|
+
connections,
|
|
90
|
+
administratorConnectionId,
|
|
91
|
+
bootstrapCredentialHash: input.bootstrapCredentialHash,
|
|
92
|
+
admission,
|
|
93
|
+
protection,
|
|
94
|
+
...input.resetPending === true ? { resetPending: true } : {}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const DEFAULT_PLATFORM_SESSION_SECONDS = 2592e3;
|
|
98
|
+
const GOOGLE_OIDC_ISSUER = "https://accounts.google.com";
|
|
99
|
+
const PLATFORM_AUTH_SETUP_PROOF_PREFIX = "void.platform.auth.setup.v1";
|
|
100
|
+
function record(value, name) {
|
|
101
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${name} must be an object.`);
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
function string(value, name, maximum = 512) {
|
|
105
|
+
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.`);
|
|
106
|
+
return value.trim();
|
|
107
|
+
}
|
|
108
|
+
function strings(value, name, maximum = 100) {
|
|
109
|
+
if (!Array.isArray(value) || value.length > maximum) throw new Error(`${name} must be an array of at most ${maximum} strings.`);
|
|
110
|
+
const result = value.map((entry) => string(entry, name));
|
|
111
|
+
if (new Set(result).size !== result.length) throw new Error(`${name} must not contain duplicates.`);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
function parsePlatformLoginId(value) {
|
|
115
|
+
if (typeof value !== "string" || !/^[a-z][a-z0-9-]{0,63}$/.test(value)) throw new Error("Login connection IDs must start with a letter and use 1–64 lowercase letters, digits, or hyphens.");
|
|
116
|
+
return value;
|
|
117
|
+
}
|
|
118
|
+
/** HTTPS syntax validation; outbound network policy must additionally validate resolved endpoints. */
|
|
119
|
+
function parsePlatformIdentityUrl(value, name, originOnly = false) {
|
|
120
|
+
const input = string(value, name, 2048);
|
|
121
|
+
let url;
|
|
122
|
+
try {
|
|
123
|
+
url = new URL(input);
|
|
124
|
+
} catch {
|
|
125
|
+
throw new Error(`${name} must be a credential-free HTTPS URL.`);
|
|
126
|
+
}
|
|
127
|
+
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash || originOnly && url.pathname !== "/") throw new Error(`${name} must be a credential-free HTTPS ${originOnly ? "origin" : "URL"} without query or fragment.`);
|
|
128
|
+
return originOnly ? url.origin : input;
|
|
129
|
+
}
|
|
130
|
+
function parsePlatformLoginDescriptor(value) {
|
|
131
|
+
const entry = record(value, "Login connection");
|
|
132
|
+
const id = parsePlatformLoginId(entry.id);
|
|
133
|
+
if (!PLATFORM_LOGIN_KINDS.includes(entry.kind)) throw new Error("Login kind must be github, google, oidc, or cloudflare-access.");
|
|
134
|
+
const kind = entry.kind;
|
|
135
|
+
if ((id === "github" || id === "google") && id !== kind) throw new Error(`Connection ID ${id} is reserved for ${id} login.`);
|
|
136
|
+
if ((kind === "github" || kind === "google") && id !== kind) throw new Error(`${kind} uses the fixed connection ID ${kind}.`);
|
|
137
|
+
return {
|
|
138
|
+
id,
|
|
139
|
+
kind,
|
|
140
|
+
label: string(entry.label, "Login label", 100)
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function parsePlatformLoginConfiguration(value) {
|
|
144
|
+
const entry = record(value, "Login configuration");
|
|
145
|
+
const descriptor = parsePlatformLoginDescriptor(entry);
|
|
146
|
+
const clientId = string(entry.clientId, "Client ID");
|
|
147
|
+
const allowedDomains = strings(entry.allowedDomains ?? [], "Allowed domains").map((domain) => {
|
|
148
|
+
const normalized = domain.toLowerCase();
|
|
149
|
+
if (!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/.test(normalized)) throw new Error("Allowed domains must be exact domain names, without wildcards.");
|
|
150
|
+
return normalized;
|
|
151
|
+
});
|
|
152
|
+
if (new Set(allowedDomains).size !== allowedDomains.length) throw new Error("Allowed domains must not contain duplicates.");
|
|
153
|
+
const requiredGroups = strings(entry.requiredGroups ?? [], "Required groups");
|
|
154
|
+
if (descriptor.kind !== "google" && allowedDomains.length > 0) throw new Error("Workspace domain restrictions are only supported by Google login.");
|
|
155
|
+
if ((descriptor.kind === "github" || descriptor.kind === "google") && requiredGroups.length > 0) throw new Error("Group restrictions require an OIDC or Cloudflare Access connection.");
|
|
156
|
+
let issuer;
|
|
157
|
+
if (descriptor.kind === "google") {
|
|
158
|
+
if (entry.issuer !== void 0 && entry.issuer !== "https://accounts.google.com") throw new Error("Google login uses the Google issuer.");
|
|
159
|
+
issuer = GOOGLE_OIDC_ISSUER;
|
|
160
|
+
} else if (descriptor.kind === "github") {
|
|
161
|
+
if (entry.issuer !== void 0) throw new Error("GitHub login does not accept an OIDC issuer.");
|
|
162
|
+
} else {
|
|
163
|
+
issuer = parsePlatformIdentityUrl(entry.issuer, "OIDC issuer");
|
|
164
|
+
if (descriptor.kind === "cloudflare-access") {
|
|
165
|
+
const url = new URL(issuer);
|
|
166
|
+
if (!/^[a-z0-9-]+\.cloudflareaccess\.com$/.test(url.hostname) || url.port || !url.pathname.startsWith("/cdn-cgi/access/sso/oidc/") || decodeURIComponent(url.pathname.slice(25).replace(/\/$/, "")) !== clientId) throw new Error("Cloudflare Access login requires its application issuer URL and matching client ID. Use generic OIDC for another issuer.");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
...descriptor,
|
|
171
|
+
clientId,
|
|
172
|
+
...issuer ? { issuer } : {},
|
|
173
|
+
allowedDomains,
|
|
174
|
+
requiredGroups
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function parsePlatformAccessProtection(value) {
|
|
178
|
+
if (value === null) return null;
|
|
179
|
+
const entry = record(value, "Access protection");
|
|
180
|
+
const teamDomain = parsePlatformIdentityUrl(entry.teamDomain, "Access team domain", true);
|
|
181
|
+
const host = new URL(teamDomain).hostname;
|
|
182
|
+
if (!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.cloudflareaccess\.com$/.test(host) || new URL(teamDomain).port) throw new Error("Access team domain must be an HTTPS cloudflareaccess.com team origin.");
|
|
183
|
+
if (!Array.isArray(entry.applications) || entry.applications.length === 0 || entry.applications.length > 20) throw new Error("Access protection requires between 1 and 20 protected origins.");
|
|
184
|
+
const applications = entry.applications.map((value) => {
|
|
185
|
+
const application = record(value, "Access application");
|
|
186
|
+
return {
|
|
187
|
+
origin: parsePlatformIdentityUrl(application.origin, "Protected origin", true),
|
|
188
|
+
audience: string(application.audience, "Access application audience")
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
if (new Set(applications.map((app) => app.origin)).size !== applications.length) throw new Error("Each protected origin must have exactly one Access application.");
|
|
192
|
+
return {
|
|
193
|
+
teamDomain,
|
|
194
|
+
applications
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function parsePlatformAdmissionPolicy(value) {
|
|
198
|
+
const entry = record(value, "Admission policy");
|
|
199
|
+
if (entry.mode === "restricted" || entry.mode === "public") return { mode: entry.mode };
|
|
200
|
+
if (entry.mode !== "company" || typeof entry.access !== "boolean") throw new Error("Admission policy must select restricted, company, or public signup.");
|
|
201
|
+
const connections = strings(entry.connections, "Company connections").map(parsePlatformLoginId);
|
|
202
|
+
if (!entry.access && connections.length === 0) throw new Error("Company admission requires a trusted connection or Access protection.");
|
|
203
|
+
return {
|
|
204
|
+
mode: "company",
|
|
205
|
+
connections,
|
|
206
|
+
access: entry.access
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/** Run inside the settings mutation transaction, using the resulting enabled connections. */
|
|
210
|
+
function validatePlatformAdmissionPolicy(policy, enabledConnections, protection) {
|
|
211
|
+
if (policy.mode !== "company") return;
|
|
212
|
+
if (policy.access && !protection) throw new Error("Company admission through Access requires enabled protection.");
|
|
213
|
+
for (const id of policy.connections) {
|
|
214
|
+
const connection = enabledConnections.find((entry) => entry.id === id);
|
|
215
|
+
if (!connection) throw new Error(`Company admission requires enabled connection ${id}.`);
|
|
216
|
+
if (connection.kind === "github" || connection.kind === "google" && connection.allowedDomains.length === 0) throw new Error("Unrestricted social login does not establish company membership.");
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//#endregion
|
|
1
220
|
//#region src/manifest.ts
|
|
2
221
|
const PLATFORM_DEPLOYMENT_SCHEMA_VERSION = 1;
|
|
3
222
|
const CORE_CAPABILITIES = {
|
|
@@ -45,6 +264,7 @@ function createPlatformResourceNames(installationSlug) {
|
|
|
45
264
|
dashboardWorker: `${prefix}-dashboard`,
|
|
46
265
|
dispatchNamespace: `${prefix}-users`,
|
|
47
266
|
dispatchWorker: `${prefix}-dispatch`,
|
|
267
|
+
emailGatewayWorker: `${prefix}-email-gateway`,
|
|
48
268
|
hyperdrive: `${prefix}-database`,
|
|
49
269
|
isrCacheKv: `${prefix}-isr-cache`,
|
|
50
270
|
legacyAssetsKv: `${prefix}-legacy-assets`,
|
|
@@ -84,6 +304,7 @@ function createApplicationRoutes(application) {
|
|
|
84
304
|
return routes;
|
|
85
305
|
}
|
|
86
306
|
function createPlatformDeploymentManifest(input) {
|
|
307
|
+
if (input.emailSharedZoneId === void 0 !== (input.emailSenderDomain === void 0)) throw new Error("Shared email configuration requires both emailSenderDomain and emailSharedZoneId.");
|
|
87
308
|
const installationSlug = normalizeInstallationSlug(input.installationSlug);
|
|
88
309
|
const baseDomain = normalizeApplicationDomain(input.application.baseDomain);
|
|
89
310
|
const workersDev = input.application.workersDev;
|
|
@@ -100,6 +321,8 @@ function createPlatformDeploymentManifest(input) {
|
|
|
100
321
|
};
|
|
101
322
|
if (capabilities.managedBuilds && !capabilities.githubActions) throw new Error("Managed builds require the GitHub Actions capability.");
|
|
102
323
|
const providers = input.authentication?.providers ?? ["github"];
|
|
324
|
+
if (providers.some((provider) => !PLATFORM_LOGIN_KINDS.includes(provider)) || new Set(providers).size !== providers.length) throw new Error("Authentication providers must be unique supported login kinds.");
|
|
325
|
+
const configurable = input.authentication?.configurable === true || input.authentication?.accessProtection === true || providers.some((provider) => provider === "oidc" || provider === "cloudflare-access");
|
|
103
326
|
if (providers.length === 0) throw new Error("At least one authentication provider is required.");
|
|
104
327
|
if (providers.includes("github") !== capabilities.githubOAuth) throw new Error("The GitHub provider and githubOAuth capability must agree.");
|
|
105
328
|
if (providers.includes("google") !== capabilities.googleOAuth) throw new Error("The Google provider and googleOAuth capability must agree.");
|
|
@@ -111,8 +334,14 @@ function createPlatformDeploymentManifest(input) {
|
|
|
111
334
|
...workersDev ? { workersDev: { ...workersDev } } : {},
|
|
112
335
|
...input.application.zoneId ? { zoneId: requiredString$1(input.application.zoneId, "application.zoneId") } : {}
|
|
113
336
|
},
|
|
114
|
-
authentication: {
|
|
337
|
+
authentication: {
|
|
338
|
+
providers: [...providers],
|
|
339
|
+
...configurable ? { configurable: true } : {},
|
|
340
|
+
...input.authentication?.accessProtection ? { accessProtection: true } : {}
|
|
341
|
+
},
|
|
115
342
|
capabilities,
|
|
343
|
+
...input.emailSharedZoneId !== void 0 ? { emailSharedZoneId: requiredString$1(input.emailSharedZoneId, "emailSharedZoneId") } : {},
|
|
344
|
+
...input.emailSenderDomain !== void 0 ? { emailSenderDomain: normalizeApplicationDomain(input.emailSenderDomain) } : {},
|
|
116
345
|
controlPlane: {
|
|
117
346
|
...CONTROL_PLANE_DEFAULTS,
|
|
118
347
|
...input.controlPlane
|
|
@@ -120,7 +349,7 @@ function createPlatformDeploymentManifest(input) {
|
|
|
120
349
|
displayName: requiredString$1(input.displayName, "displayName").trim(),
|
|
121
350
|
installationSlug,
|
|
122
351
|
resources,
|
|
123
|
-
schemaVersion: workersDev ? 2 : 1
|
|
352
|
+
schemaVersion: configurable ? 3 : workersDev ? 2 : 1
|
|
124
353
|
};
|
|
125
354
|
createApplicationRoutes(manifest.application);
|
|
126
355
|
for (const [key, value] of Object.entries(manifest.controlPlane)) {
|
|
@@ -132,7 +361,7 @@ function createPlatformDeploymentManifest(input) {
|
|
|
132
361
|
}
|
|
133
362
|
function parsePlatformDeploymentManifest(value) {
|
|
134
363
|
assertRecord$1(value, "Platform deployment manifest");
|
|
135
|
-
if (value.schemaVersion !== 1 && value.schemaVersion !== 2) throw new Error(`Unsupported platform deployment schema version: ${String(value.schemaVersion)}.`);
|
|
364
|
+
if (value.schemaVersion !== 1 && value.schemaVersion !== 2 && value.schemaVersion !== 3) throw new Error(`Unsupported platform deployment schema version: ${String(value.schemaVersion)}.`);
|
|
136
365
|
const application = value.application;
|
|
137
366
|
const authentication = value.authentication;
|
|
138
367
|
const rawCapabilities = value.capabilities;
|
|
@@ -140,7 +369,7 @@ function parsePlatformDeploymentManifest(value) {
|
|
|
140
369
|
const rawResources = value.resources;
|
|
141
370
|
assertRecord$1(application, "application");
|
|
142
371
|
let workersDev;
|
|
143
|
-
if (value.schemaVersion === 2) {
|
|
372
|
+
if (value.schemaVersion === 2 || value.schemaVersion === 3 && application.workersDev !== void 0) {
|
|
144
373
|
assertRecord$1(application.workersDev, "application.workersDev");
|
|
145
374
|
workersDev = {
|
|
146
375
|
subdomain: requiredString$1(application.workersDev.subdomain, "workersDev.subdomain"),
|
|
@@ -159,10 +388,11 @@ function parsePlatformDeploymentManifest(value) {
|
|
|
159
388
|
capabilities[key] = entry;
|
|
160
389
|
}
|
|
161
390
|
const providers = authentication.providers;
|
|
162
|
-
if (!Array.isArray(providers) || providers.some((provider) => provider !== "github" && provider !== "google")) throw new Error("authentication.providers must contain only github or google.");
|
|
391
|
+
if (!Array.isArray(providers) || providers.some((provider) => !PLATFORM_LOGIN_KINDS.includes(provider) || value.schemaVersion !== 3 && provider !== "github" && provider !== "google")) throw new Error("authentication.providers must contain only github or google.");
|
|
392
|
+
if (value.schemaVersion === 3 && authentication.configurable !== true || value.schemaVersion !== 3 && (authentication.configurable !== void 0 || authentication.accessProtection !== void 0) || authentication.accessProtection !== void 0 && authentication.accessProtection !== true) throw new Error("Configurable authentication requires deployment schema version 3.");
|
|
163
393
|
const resourceDefaults = createPlatformResourceNames(requiredString$1(value.installationSlug, "installationSlug"));
|
|
164
394
|
const resources = {};
|
|
165
|
-
for (const key of Object.keys(resourceDefaults)) resources[key] = requiredString$1(rawResources[key], `resources.${key}`);
|
|
395
|
+
for (const key of Object.keys(resourceDefaults)) resources[key] = requiredString$1(rawResources[key] ?? (key === "emailGatewayWorker" ? resourceDefaults[key] : void 0), `resources.${key}`);
|
|
166
396
|
const readHostname = (key) => {
|
|
167
397
|
const hostname = controlPlane[key];
|
|
168
398
|
return hostname === null ? null : requiredString$1(hostname, `controlPlane.${key}`);
|
|
@@ -175,8 +405,14 @@ function parsePlatformDeploymentManifest(value) {
|
|
|
175
405
|
...workersDev ? { workersDev } : {},
|
|
176
406
|
...typeof application.zoneId === "string" ? { zoneId: application.zoneId } : {}
|
|
177
407
|
},
|
|
178
|
-
authentication: {
|
|
408
|
+
authentication: {
|
|
409
|
+
providers,
|
|
410
|
+
...authentication.configurable === true ? { configurable: true } : {},
|
|
411
|
+
...authentication.accessProtection === true ? { accessProtection: true } : {}
|
|
412
|
+
},
|
|
179
413
|
capabilities,
|
|
414
|
+
...value.emailSharedZoneId !== void 0 ? { emailSharedZoneId: requiredString$1(value.emailSharedZoneId, "emailSharedZoneId") } : {},
|
|
415
|
+
...value.emailSenderDomain !== void 0 ? { emailSenderDomain: normalizeApplicationDomain(requiredString$1(value.emailSenderDomain, "emailSenderDomain")) } : {},
|
|
180
416
|
controlPlane: {
|
|
181
417
|
apiHostname: readHostname("apiHostname"),
|
|
182
418
|
dashboardHostname: readHostname("dashboardHostname"),
|
|
@@ -196,7 +432,7 @@ const PLATFORM_REMOTE_INSTALLATION_MANIFEST_KEY = "__void/platform/installation/
|
|
|
196
432
|
const PLATFORM_SANDBOX_DRAIN_KEY = "__void/platform/sandbox-drain/v1";
|
|
197
433
|
const PLATFORM_R2_OWNERSHIP_MARKER_KEY = "__void/platform/ownership/v1";
|
|
198
434
|
const PLATFORM_RESOURCE_OWNERSHIP_SCHEMA_VERSION = 1;
|
|
199
|
-
const PLATFORM_USAGE_PROTOCOL_VERSION =
|
|
435
|
+
const PLATFORM_USAGE_PROTOCOL_VERSION = 2;
|
|
200
436
|
const STATUS_TRANSITIONS = {
|
|
201
437
|
draft: [
|
|
202
438
|
"planned",
|
|
@@ -459,6 +695,7 @@ function parsePlatformInstallationManifest(value) {
|
|
|
459
695
|
status: value.status,
|
|
460
696
|
runtime,
|
|
461
697
|
...pendingDomain ? { pendingDomain } : {},
|
|
698
|
+
...value.authenticationResources !== void 0 ? { authenticationResources: parseAuthenticationResources(value.authenticationResources) } : {},
|
|
462
699
|
updatedAt
|
|
463
700
|
}, {
|
|
464
701
|
apiUrl: endpoints.apiUrl === null ? null : requiredString(endpoints.apiUrl, "endpoints.apiUrl"),
|
|
@@ -495,10 +732,28 @@ function parsePlatformInstallationManifest(value) {
|
|
|
495
732
|
updatedAt
|
|
496
733
|
};
|
|
497
734
|
}
|
|
735
|
+
function parseAuthenticationResources(value) {
|
|
736
|
+
if (!Array.isArray(value) || value.length > 100) throw new Error("Invalid authentication resource inventory.");
|
|
737
|
+
const resources = value.map((entry) => {
|
|
738
|
+
assertRecord(entry, "Authentication resource");
|
|
739
|
+
if (entry.kind !== "application" && entry.kind !== "service-token" || entry.ownership !== "created" && entry.ownership !== "adopted") throw new Error("Invalid authentication resource kind or ownership.");
|
|
740
|
+
return {
|
|
741
|
+
key: requiredString(entry.key, "authentication resource key"),
|
|
742
|
+
kind: entry.kind,
|
|
743
|
+
accountId: requiredString(entry.accountId, "authentication resource account"),
|
|
744
|
+
id: requiredString(entry.id, "authentication resource ID"),
|
|
745
|
+
name: requiredString(entry.name, "authentication resource name"),
|
|
746
|
+
ownership: entry.ownership
|
|
747
|
+
};
|
|
748
|
+
});
|
|
749
|
+
if (new Set(resources.map((resource) => `${resource.accountId}:${resource.kind}:${resource.id}`)).size !== resources.length) throw new Error("Duplicate authentication resource identity.");
|
|
750
|
+
return resources;
|
|
751
|
+
}
|
|
498
752
|
function parseUsageProtocolVersion$1(value) {
|
|
499
753
|
if (value === void 0 || value === 0) return 0;
|
|
500
754
|
if (value === 1) return 1;
|
|
501
|
-
|
|
755
|
+
if (value === 2) return 2;
|
|
756
|
+
throw new Error("usageProtocolVersion must be 0, 1, or 2.");
|
|
502
757
|
}
|
|
503
758
|
function parseSafetyProtocols(value) {
|
|
504
759
|
if (value === void 0) return { sandboxDrain: 0 };
|
|
@@ -600,28 +855,34 @@ function createPlatformDiscoveryDocument(input) {
|
|
|
600
855
|
const application = readPlatformApplication({ PLATFORM_APPLICATION: JSON.stringify(input.applicationRouting) });
|
|
601
856
|
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.");
|
|
602
857
|
}
|
|
603
|
-
if (input.usageProtocolVersion !== void 0 && input.usageProtocolVersion !== 0 && input.usageProtocolVersion !== 1) throw new Error("usageProtocolVersion must be 0 or
|
|
604
|
-
|
|
858
|
+
if (input.usageProtocolVersion !== void 0 && input.usageProtocolVersion !== 0 && input.usageProtocolVersion !== 1 && input.usageProtocolVersion !== 2) throw new Error("usageProtocolVersion must be 0, 1, or 2.");
|
|
859
|
+
const authentication = input.authentication ? parseAuthentication(input.authentication) : void 0;
|
|
860
|
+
if (!authentication && input.authenticationProviders.some((provider) => provider !== "github" && provider !== "google")) throw new Error("Named login methods require authentication discovery descriptors.");
|
|
861
|
+
if (new Set(input.authenticationProviders).size !== input.authenticationProviders.length) throw new Error("Authentication provider IDs must be unique.");
|
|
862
|
+
if (input.authenticationProviders.length === 0 && !authentication?.setupPending) throw new Error("At least one authentication provider is required.");
|
|
863
|
+
if (authentication && (authentication.methods.length !== input.authenticationProviders.length || authentication.methods.some((method, index) => method.id !== input.authenticationProviders[index]))) throw new Error("Authentication method descriptors must match the advertised provider IDs.");
|
|
605
864
|
if (input.authenticationProviders.includes("github") !== input.capabilities.githubOAuth || input.authenticationProviders.includes("google") !== input.capabilities.googleOAuth) throw new Error("Authentication providers and capabilities must agree.");
|
|
606
865
|
return {
|
|
607
866
|
...input,
|
|
608
867
|
apiUrl: normalizeOrigin(input.apiUrl, "apiUrl"),
|
|
609
868
|
applicationDomain: normalizeApplicationDomain(input.applicationDomain),
|
|
610
869
|
authenticationProviders: [...input.authenticationProviders],
|
|
870
|
+
...authentication ? { authentication } : {},
|
|
611
871
|
displayName: input.displayName.trim(),
|
|
612
872
|
installationId: input.installationId?.trim() || null,
|
|
613
873
|
platformVersion: input.platformVersion.trim(),
|
|
614
874
|
proxyUrl: normalizeOrigin(input.proxyUrl, "proxyUrl"),
|
|
615
|
-
schemaVersion: input.applicationRouting?.workersDev ? 2 : 1,
|
|
875
|
+
schemaVersion: authentication ? 3 : input.applicationRouting?.workersDev ? 2 : 1,
|
|
616
876
|
usageProtocolVersion: input.usageProtocolVersion ?? 0
|
|
617
877
|
};
|
|
618
878
|
}
|
|
619
879
|
function parsePlatformDiscoveryDocument(value) {
|
|
620
880
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Platform discovery document must be an object.");
|
|
621
881
|
const document = value;
|
|
622
|
-
if (document.schemaVersion !== 1 && document.schemaVersion !== 2) throw new Error(`Unsupported platform discovery schema version: ${String(document.schemaVersion)}.`);
|
|
882
|
+
if (document.schemaVersion !== 1 && document.schemaVersion !== 2 && document.schemaVersion !== 3) throw new Error(`Unsupported platform discovery schema version: ${String(document.schemaVersion)}.`);
|
|
623
883
|
const capabilities = document.capabilities;
|
|
624
884
|
if (document.schemaVersion === 1 && document.applicationRouting !== void 0) throw new Error("Application routing requires discovery schema version 2.");
|
|
885
|
+
if (document.schemaVersion === 2 && document.applicationRouting === void 0) throw new Error("Discovery schema version 2 requires application routing.");
|
|
625
886
|
if (!capabilities || typeof capabilities !== "object" || Array.isArray(capabilities)) throw new Error("capabilities must be an object.");
|
|
626
887
|
const capabilityNames = [
|
|
627
888
|
"ai",
|
|
@@ -640,7 +901,10 @@ function parsePlatformDiscoveryDocument(value) {
|
|
|
640
901
|
parsedCapabilities[name] = enabled;
|
|
641
902
|
}
|
|
642
903
|
const providers = document.authenticationProviders;
|
|
643
|
-
if (!Array.isArray(providers) || providers.some((provider) => provider !== "github" && provider !== "google")) throw new Error("authenticationProviders must contain only github or google.");
|
|
904
|
+
if (!Array.isArray(providers) || providers.some((provider) => typeof provider !== "string" || document.schemaVersion !== 3 && provider !== "github" && provider !== "google")) throw new Error("authenticationProviders must contain only github or google.");
|
|
905
|
+
if (document.schemaVersion !== 3 && document.authentication !== void 0) throw new Error("Configurable authentication requires discovery schema version 3.");
|
|
906
|
+
const authentication = document.schemaVersion === 3 ? parseAuthentication(document.authentication) : void 0;
|
|
907
|
+
if (authentication) providers.forEach(parsePlatformLoginId);
|
|
644
908
|
const string = (name) => {
|
|
645
909
|
const entry = document[name];
|
|
646
910
|
if (typeof entry !== "string" || !entry.trim()) throw new Error(`${name} must be a non-empty string.`);
|
|
@@ -651,8 +915,9 @@ function parsePlatformDiscoveryDocument(value) {
|
|
|
651
915
|
return createPlatformDiscoveryDocument({
|
|
652
916
|
apiUrl,
|
|
653
917
|
applicationDomain: string("applicationDomain"),
|
|
654
|
-
...document.
|
|
918
|
+
...document.applicationRouting !== void 0 ? { applicationRouting: readPlatformApplication({ PLATFORM_APPLICATION: JSON.stringify(document.applicationRouting ?? null) }) } : {},
|
|
655
919
|
authenticationProviders: providers,
|
|
920
|
+
...authentication ? { authentication } : {},
|
|
656
921
|
capabilities: parsedCapabilities,
|
|
657
922
|
displayName: string("displayName"),
|
|
658
923
|
installationId: document.installationId === null ? null : string("installationId"),
|
|
@@ -661,18 +926,37 @@ function parsePlatformDiscoveryDocument(value) {
|
|
|
661
926
|
usageProtocolVersion: parseUsageProtocolVersion(document.usageProtocolVersion)
|
|
662
927
|
});
|
|
663
928
|
}
|
|
929
|
+
function parseAuthentication(value) {
|
|
930
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Authentication discovery must be an object.");
|
|
931
|
+
const authentication = value;
|
|
932
|
+
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.");
|
|
933
|
+
const methods = authentication.methods.map(parsePlatformLoginDescriptor);
|
|
934
|
+
if (new Set(methods.map((method) => method.id)).size !== methods.length) throw new Error("Authentication connection IDs must be unique.");
|
|
935
|
+
return {
|
|
936
|
+
methods,
|
|
937
|
+
protectedByAccess: authentication.protectedByAccess,
|
|
938
|
+
...authentication.setupPending === true ? { setupPending: true } : {}
|
|
939
|
+
};
|
|
940
|
+
}
|
|
664
941
|
function parseUsageProtocolVersion(value) {
|
|
665
942
|
if (value === void 0 || value === 0) return 0;
|
|
666
943
|
if (value === 1) return 1;
|
|
667
|
-
|
|
944
|
+
if (value === 2) return 2;
|
|
945
|
+
throw new Error("usageProtocolVersion must be 0, 1, or 2.");
|
|
668
946
|
}
|
|
669
947
|
//#endregion
|
|
670
948
|
//#region src/worker-config.ts
|
|
671
949
|
function createPlatformWorkerConfigs(input) {
|
|
672
|
-
const { accountId, apiUrl, deployment, healthProbeToken, installationId, ownershipNonce, platformVersion, proxyUrl, resources, runtimeEntrypoints } = input;
|
|
950
|
+
const { accountId, apiUrl, deployment, healthProbeToken, installationId, ownershipNonce, platformVersion, proxyUrl, emailGatewayUrl, resources, runtimeEntrypoints } = input;
|
|
673
951
|
const publicEndpoints = input.publicEndpoints ?? true;
|
|
674
952
|
const trafficState = input.trafficState ?? "enabled";
|
|
675
953
|
const names = deployment.resources;
|
|
954
|
+
const sharedEmailIngress = deployment.emailSharedZoneId ? {
|
|
955
|
+
EMAIL_SHARED_ACCOUNT_ID: accountId,
|
|
956
|
+
EMAIL_SHARED_ZONE_ID: deployment.emailSharedZoneId,
|
|
957
|
+
EMAIL_SHARED_INGRESS_NAME: names.emailGatewayWorker
|
|
958
|
+
} : {};
|
|
959
|
+
const senderDomain = deployment.emailSenderDomain ? { EMAIL_SENDER_DOMAIN: deployment.emailSenderDomain } : {};
|
|
676
960
|
const ownershipVars = (resourceKey, resourceName) => ({ PLATFORM_OWNERSHIP_MARKER: JSON.stringify(createPlatformResourceOwnershipMarker({
|
|
677
961
|
accountId,
|
|
678
962
|
installationId,
|
|
@@ -686,7 +970,7 @@ function createPlatformWorkerConfigs(input) {
|
|
|
686
970
|
account_id: accountId,
|
|
687
971
|
compatibility_date: "2026-02-24",
|
|
688
972
|
observability: { enabled: true },
|
|
689
|
-
preview_urls: publicEndpoints,
|
|
973
|
+
preview_urls: publicEndpoints && !deployment.authentication.accessProtection,
|
|
690
974
|
workers_dev: publicEndpoints
|
|
691
975
|
};
|
|
692
976
|
const kv = [
|
|
@@ -711,9 +995,15 @@ function createPlatformWorkerConfigs(input) {
|
|
|
711
995
|
binding: "STATIC_ASSETS_R2",
|
|
712
996
|
bucket_name: names.assetsBucket
|
|
713
997
|
}];
|
|
714
|
-
const fetchWorkersDev = Boolean(deployment.application.workersDev) || [
|
|
998
|
+
const fetchWorkersDev = Boolean(deployment.application.workersDev) || [
|
|
999
|
+
apiUrl,
|
|
1000
|
+
proxyUrl,
|
|
1001
|
+
...deployment.capabilities.email ? [emailGatewayUrl] : []
|
|
1002
|
+
].some((url) => new URL(url).hostname.endsWith(".workers.dev"));
|
|
715
1003
|
const api = {
|
|
716
1004
|
...common,
|
|
1005
|
+
version_metadata: { binding: "VERSION_METADATA" },
|
|
1006
|
+
workers_dev: publicEndpoints && (!deployment.authentication.accessProtection || new URL(apiUrl).hostname.endsWith(".workers.dev")),
|
|
717
1007
|
name: names.apiWorker,
|
|
718
1008
|
main: runtimeEntrypoints.api,
|
|
719
1009
|
no_bundle: true,
|
|
@@ -724,6 +1014,7 @@ function createPlatformWorkerConfigs(input) {
|
|
|
724
1014
|
id: resources.hyperdrive
|
|
725
1015
|
}],
|
|
726
1016
|
kv_namespaces: kv,
|
|
1017
|
+
...deployment.capabilities.email ? { send_email: [{ name: "EMAIL" }] } : {},
|
|
727
1018
|
r2_buckets: r2,
|
|
728
1019
|
dispatch_namespaces: dispatchNamespace,
|
|
729
1020
|
durable_objects: { bindings: [
|
|
@@ -790,6 +1081,7 @@ function createPlatformWorkerConfigs(input) {
|
|
|
790
1081
|
DISPATCH_WORKER_NAME: names.dispatchWorker,
|
|
791
1082
|
LOGS_DATASET: names.logsDataset,
|
|
792
1083
|
PLATFORM_CAPABILITIES: JSON.stringify(deployment.capabilities),
|
|
1084
|
+
...input.authenticationDatabaseUncached ? { PLATFORM_AUTH_DATABASE_UNCACHED: "true" } : {},
|
|
793
1085
|
PLATFORM_DISPLAY_NAME: deployment.displayName,
|
|
794
1086
|
PLATFORM_ENV: "production",
|
|
795
1087
|
PLATFORM_HEALTH_PROBE_TOKEN: healthProbeToken,
|
|
@@ -798,6 +1090,9 @@ function createPlatformWorkerConfigs(input) {
|
|
|
798
1090
|
...ownershipVars("api-worker", names.apiWorker),
|
|
799
1091
|
PLATFORM_VERSION: platformVersion,
|
|
800
1092
|
PROXY_URL: proxyUrl,
|
|
1093
|
+
EMAIL_GATEWAY_ORIGIN: emailGatewayUrl,
|
|
1094
|
+
...sharedEmailIngress,
|
|
1095
|
+
...senderDomain,
|
|
801
1096
|
R2_STATIC_ASSETS_BUCKET: names.assetsBucket,
|
|
802
1097
|
REQUESTS_DATASET: names.requestsDataset,
|
|
803
1098
|
SITE_DOMAIN: deployment.application.baseDomain,
|
|
@@ -812,6 +1107,7 @@ function createPlatformWorkerConfigs(input) {
|
|
|
812
1107
|
}];
|
|
813
1108
|
const proxy = {
|
|
814
1109
|
...common,
|
|
1110
|
+
workers_dev: publicEndpoints && (!deployment.authentication.accessProtection || new URL(proxyUrl).hostname.endsWith(".workers.dev")),
|
|
815
1111
|
name: names.proxyWorker,
|
|
816
1112
|
main: runtimeEntrypoints.proxy,
|
|
817
1113
|
no_bundle: true,
|
|
@@ -826,12 +1122,14 @@ function createPlatformWorkerConfigs(input) {
|
|
|
826
1122
|
service: names.apiWorker
|
|
827
1123
|
}],
|
|
828
1124
|
dispatch_namespaces: dispatchNamespace,
|
|
1125
|
+
...deployment.capabilities.email ? { send_email: [{ name: "SEND_EMAIL" }] } : {},
|
|
829
1126
|
vars: {
|
|
830
1127
|
AI_GATEWAY_ID: names.aiGateway,
|
|
831
1128
|
PLATFORM_CAPABILITIES: JSON.stringify(deployment.capabilities),
|
|
832
1129
|
PLATFORM_HEALTH_PROBE_TOKEN: healthProbeToken,
|
|
833
1130
|
PLATFORM_INSTALLATION_ID: installationId,
|
|
834
1131
|
PLATFORM_TRAFFIC_STATE: trafficState,
|
|
1132
|
+
...senderDomain,
|
|
835
1133
|
...ownershipVars("proxy-worker", names.proxyWorker)
|
|
836
1134
|
}
|
|
837
1135
|
};
|
|
@@ -842,6 +1140,34 @@ function createPlatformWorkerConfigs(input) {
|
|
|
842
1140
|
return {
|
|
843
1141
|
api,
|
|
844
1142
|
proxy,
|
|
1143
|
+
emailGateway: {
|
|
1144
|
+
...common,
|
|
1145
|
+
workers_dev: publicEndpoints,
|
|
1146
|
+
preview_urls: false,
|
|
1147
|
+
name: names.emailGatewayWorker,
|
|
1148
|
+
main: runtimeEntrypoints.emailGateway,
|
|
1149
|
+
no_bundle: true,
|
|
1150
|
+
compatibility_flags: ["nodejs_compat"],
|
|
1151
|
+
kv_namespaces: [{
|
|
1152
|
+
binding: "ROUTING",
|
|
1153
|
+
id: resources.routingKv
|
|
1154
|
+
}],
|
|
1155
|
+
services: [{
|
|
1156
|
+
binding: "API",
|
|
1157
|
+
service: names.apiWorker
|
|
1158
|
+
}],
|
|
1159
|
+
dispatch_namespaces: dispatchNamespace,
|
|
1160
|
+
...deployment.capabilities.email ? { send_email: [{ name: "SEND_EMAIL" }] } : {},
|
|
1161
|
+
vars: {
|
|
1162
|
+
PLATFORM_CAPABILITIES: JSON.stringify(deployment.capabilities),
|
|
1163
|
+
PLATFORM_INSTALLATION_ID: installationId,
|
|
1164
|
+
PLATFORM_VERSION: platformVersion,
|
|
1165
|
+
PLATFORM_TRAFFIC_STATE: trafficState,
|
|
1166
|
+
...sharedEmailIngress,
|
|
1167
|
+
...senderDomain,
|
|
1168
|
+
...ownershipVars("email-gateway-worker", names.emailGatewayWorker)
|
|
1169
|
+
}
|
|
1170
|
+
},
|
|
845
1171
|
tail: {
|
|
846
1172
|
...common,
|
|
847
1173
|
name: names.tailWorker,
|
|
@@ -892,4 +1218,4 @@ function createPlatformWorkerConfigs(input) {
|
|
|
892
1218
|
};
|
|
893
1219
|
}
|
|
894
1220
|
//#endregion
|
|
895
|
-
export { PLATFORM_APPLICATION_KEY, PLATFORM_DEPLOYMENT_SCHEMA_VERSION, PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE, PLATFORM_DISCOVERY_SCHEMA_VERSION, PLATFORM_INSTALLATION_SCHEMA_VERSION, 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, createPlatformDeploymentManifest, createPlatformDiscoveryDocument, createPlatformInstallationManifest, createPlatformResourceNames, createPlatformResourceOwnershipMarker, createPlatformWorkerConfigs, normalizeApplicationDomain, normalizeInstallationSlug, parsePlatformDeploymentManifest, parsePlatformDiscoveryDocument, parsePlatformInstallationManifest, parsePlatformResourceOwnershipMarker, platformProjectHostname, platformProjectHostnames, platformProjectIngressName, platformProjectWorkersDevHostname, platformWorkersDevAliasKey, readPlatformApplication, recordInstallationResource, recordInstallationStep, resolvePlatformApplicationEnvironment, setInstallationDesiredState, setInstallationEndpoints, transitionInstallation };
|
|
1221
|
+
export { DEFAULT_PLATFORM_SESSION_SECONDS, GOOGLE_OIDC_ISSUER, PLATFORM_APPLICATION_KEY, PLATFORM_AUTH_SETUP_PROOF_PREFIX, PLATFORM_DEPLOYMENT_SCHEMA_VERSION, PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE, PLATFORM_DISCOVERY_SCHEMA_VERSION, 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, createPlatformDeploymentManifest, createPlatformDiscoveryDocument, createPlatformInstallationManifest, createPlatformResourceNames, createPlatformResourceOwnershipMarker, createPlatformWorkerConfigs, isPlatformSignupAllowed, normalizeApplicationDomain, normalizeInstallationSlug, parsePlatformAccessProtection, parsePlatformAdmissionPolicy, parsePlatformAuthenticationSetup, parsePlatformDeploymentManifest, parsePlatformDiscoveryDocument, parsePlatformIdentityUrl, parsePlatformInstallationManifest, parsePlatformLoginConfiguration, parsePlatformLoginDescriptor, parsePlatformLoginId, parsePlatformResourceOwnershipMarker, parsePlatformSignupAllowlistEntry, platformAuthenticationRecoveryMessage, platformProjectHostname, platformProjectHostnames, platformProjectIngressName, platformProjectWorkersDevHostname, platformProtectionProofMessage, platformWorkersDevAliasKey, readPlatformApplication, recordInstallationResource, recordInstallationStep, resolvePlatformApplicationEnvironment, setInstallationDesiredState, setInstallationEndpoints, transitionInstallation, validatePlatformAdmissionPolicy };
|
package/dist/installer.d.mts
CHANGED
|
@@ -23,8 +23,10 @@ export type PlatformRuntimeDatabaseManifest = Readonly<{
|
|
|
23
23
|
schemaDigest: string;
|
|
24
24
|
}>;
|
|
25
25
|
export type PlatformRuntimeManifest = Readonly<{
|
|
26
|
+
authenticationProtocolVersion?: 1;
|
|
26
27
|
applicationRoutingVersion?: 1;
|
|
27
|
-
artifacts: Readonly<Record<"api" | "dispatch" | "proxy" | "tail", PlatformRuntimeArtifact
|
|
28
|
+
artifacts: Readonly<Record<"api" | "dispatch" | "proxy" | "tail", PlatformRuntimeArtifact> & Partial<Record<"emailGateway", PlatformRuntimeArtifact>>>;
|
|
29
|
+
emailProtocolVersion?: 1;
|
|
28
30
|
database: PlatformRuntimeDatabaseManifest;
|
|
29
31
|
platformVersion: string;
|
|
30
32
|
safetyProtocols: Readonly<{
|
|
@@ -33,7 +35,7 @@ export type PlatformRuntimeManifest = Readonly<{
|
|
|
33
35
|
schemaVersion: 2;
|
|
34
36
|
sourceRevision: string | null;
|
|
35
37
|
/** Queue payload contract shared by the API consumer and trusted producers. */
|
|
36
|
-
usageProtocolVersion: 0 | 1;
|
|
38
|
+
usageProtocolVersion: 0 | 1 | 2;
|
|
37
39
|
}>;
|
|
38
40
|
export type PlatformRuntime = Readonly<{
|
|
39
41
|
directory: string;
|
package/dist/installer.mjs
CHANGED
|
@@ -19,13 +19,19 @@ function platformDatabaseSchemaDigest(lineage, migrations) {
|
|
|
19
19
|
function parsePlatformRuntimeManifest(value) {
|
|
20
20
|
const root = record(value, "runtime manifest");
|
|
21
21
|
if (root.schemaVersion !== 2) throw new Error("runtime manifest schemaVersion must be 2");
|
|
22
|
+
if (root.authenticationProtocolVersion !== void 0 && root.authenticationProtocolVersion !== 1) throw new Error("Unsupported authentication protocol version.");
|
|
23
|
+
if (root.emailProtocolVersion !== void 0 && root.emailProtocolVersion !== 1) throw new Error("Unsupported email protocol version.");
|
|
22
24
|
const artifactsValue = record(root.artifacts, "runtime manifest artifacts");
|
|
23
|
-
|
|
25
|
+
if (root.emailProtocolVersion === 1 && artifactsValue.emailGateway === void 0) throw new Error("Email protocol version 1 requires an emailGateway runtime artifact.");
|
|
26
|
+
if (artifactsValue.emailGateway !== void 0 && root.emailProtocolVersion !== 1) throw new Error("An emailGateway runtime artifact requires email protocol version 1.");
|
|
27
|
+
const artifactNames = [
|
|
24
28
|
"api",
|
|
25
29
|
"dispatch",
|
|
26
30
|
"proxy",
|
|
27
|
-
"tail"
|
|
28
|
-
|
|
31
|
+
"tail",
|
|
32
|
+
...artifactsValue.emailGateway === void 0 ? [] : ["emailGateway"]
|
|
33
|
+
];
|
|
34
|
+
const artifacts = Object.fromEntries(artifactNames.map((name) => [name, parseArtifact(artifactsValue[name], name)]));
|
|
29
35
|
const databaseValue = record(root.database, "runtime manifest database");
|
|
30
36
|
if (databaseValue.protocolVersion !== 1) throw new Error("runtime manifest database protocolVersion must be 1");
|
|
31
37
|
const lineage = nonemptyString(databaseValue.lineage, "database lineage");
|
|
@@ -59,6 +65,8 @@ function parsePlatformRuntimeManifest(value) {
|
|
|
59
65
|
if (rollbackSafeFrom.some((entry) => !prefixDigests.has(entry.schemaDigest))) throw new Error("runtime manifest database rollback compatibility must reference this migration lineage");
|
|
60
66
|
return {
|
|
61
67
|
artifacts,
|
|
68
|
+
...root.authenticationProtocolVersion === 1 ? { authenticationProtocolVersion: 1 } : {},
|
|
69
|
+
...root.emailProtocolVersion === 1 ? { emailProtocolVersion: 1 } : {},
|
|
62
70
|
...root.applicationRoutingVersion === 1 ? { applicationRoutingVersion: 1 } : {},
|
|
63
71
|
database: {
|
|
64
72
|
journalSha256: sha256(databaseValue.journalSha256, "database journal digest"),
|
|
@@ -84,7 +92,8 @@ function parseSafetyProtocols(value) {
|
|
|
84
92
|
function usageProtocolVersion(value) {
|
|
85
93
|
if (value === void 0 || value === 0) return 0;
|
|
86
94
|
if (value === 1) return 1;
|
|
87
|
-
|
|
95
|
+
if (value === 2) return 2;
|
|
96
|
+
throw new Error("runtime manifest usageProtocolVersion must be 0, 1, or 2");
|
|
88
97
|
}
|
|
89
98
|
function getPlatformRuntimeDirectory() {
|
|
90
99
|
return join(dirname(fileURLToPath(import.meta.url)), "runtime");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
This folder contains the built output assets for the worker "void-runtime-build-api" generated at 2026-09-
|
|
1
|
+
This folder contains the built output assets for the worker "void-runtime-build-api" generated at 2026-09-22T17:31:12.516Z.
|