@spacefast/common 0.0.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 +42 -0
- package/dist/brand.d.ts +15 -0
- package/dist/brand.js +24 -0
- package/dist/config/domains.d.ts +30 -0
- package/dist/config/domains.js +75 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.js +3 -0
- package/dist/contracts/abuse.d.ts +93 -0
- package/dist/contracts/abuse.js +50 -0
- package/dist/contracts/access.d.ts +409 -0
- package/dist/contracts/access.js +396 -0
- package/dist/contracts/account.d.ts +28 -0
- package/dist/contracts/account.js +54 -0
- package/dist/contracts/activity.d.ts +118 -0
- package/dist/contracts/activity.js +180 -0
- package/dist/contracts/analytics.d.ts +56 -0
- package/dist/contracts/analytics.js +91 -0
- package/dist/contracts/annotations.d.ts +327 -0
- package/dist/contracts/annotations.js +234 -0
- package/dist/contracts/api-keys.d.ts +517 -0
- package/dist/contracts/api-keys.js +235 -0
- package/dist/contracts/archives.d.ts +332 -0
- package/dist/contracts/archives.js +120 -0
- package/dist/contracts/auth.d.ts +86 -0
- package/dist/contracts/auth.js +82 -0
- package/dist/contracts/beta.d.ts +106 -0
- package/dist/contracts/beta.js +104 -0
- package/dist/contracts/billing.d.ts +328 -0
- package/dist/contracts/billing.js +203 -0
- package/dist/contracts/builds.d.ts +504 -0
- package/dist/contracts/builds.js +248 -0
- package/dist/contracts/channels.d.ts +49 -0
- package/dist/contracts/channels.js +51 -0
- package/dist/contracts/common.d.ts +238 -0
- package/dist/contracts/common.js +175 -0
- package/dist/contracts/deployments.d.ts +574 -0
- package/dist/contracts/deployments.js +97 -0
- package/dist/contracts/device-auth.d.ts +194 -0
- package/dist/contracts/device-auth.js +162 -0
- package/dist/contracts/domains.d.ts +6115 -0
- package/dist/contracts/domains.js +1435 -0
- package/dist/contracts/enums.d.ts +196 -0
- package/dist/contracts/enums.js +211 -0
- package/dist/contracts/error-code-meta.d.ts +1560 -0
- package/dist/contracts/error-code-meta.js +400 -0
- package/dist/contracts/error-codes.d.ts +13 -0
- package/dist/contracts/error-codes.js +416 -0
- package/dist/contracts/events.d.ts +398 -0
- package/dist/contracts/events.js +320 -0
- package/dist/contracts/fast-domain-search.d.ts +19 -0
- package/dist/contracts/fast-domain-search.js +22 -0
- package/dist/contracts/features.d.ts +240 -0
- package/dist/contracts/features.js +406 -0
- package/dist/contracts/git.d.ts +288 -0
- package/dist/contracts/git.js +116 -0
- package/dist/contracts/ids.d.ts +35 -0
- package/dist/contracts/ids.js +45 -0
- package/dist/contracts/intercom.d.ts +6 -0
- package/dist/contracts/intercom.js +5 -0
- package/dist/contracts/internal.d.ts +103 -0
- package/dist/contracts/internal.js +92 -0
- package/dist/contracts/mcp.d.ts +788 -0
- package/dist/contracts/mcp.js +161 -0
- package/dist/contracts/me.d.ts +81 -0
- package/dist/contracts/me.js +104 -0
- package/dist/contracts/oauth-resources.d.ts +30 -0
- package/dist/contracts/oauth-resources.js +61 -0
- package/dist/contracts/operations.d.ts +54 -0
- package/dist/contracts/operations.js +14 -0
- package/dist/contracts/plan-policy.d.ts +85 -0
- package/dist/contracts/plan-policy.js +75 -0
- package/dist/contracts/platform.d.ts +359 -0
- package/dist/contracts/platform.js +216 -0
- package/dist/contracts/push-new.d.ts +156 -0
- package/dist/contracts/push-new.js +52 -0
- package/dist/contracts/quotas.d.ts +16 -0
- package/dist/contracts/quotas.js +36 -0
- package/dist/contracts/repository-connections.d.ts +231 -0
- package/dist/contracts/repository-connections.js +106 -0
- package/dist/contracts/resources.d.ts +529 -0
- package/dist/contracts/resources.js +209 -0
- package/dist/contracts/routes.d.ts +45 -0
- package/dist/contracts/routes.js +31 -0
- package/dist/contracts/runtime-api.d.ts +449 -0
- package/dist/contracts/runtime-api.js +513 -0
- package/dist/contracts/sites.d.ts +393 -0
- package/dist/contracts/sites.js +121 -0
- package/dist/contracts/slugs.d.ts +31 -0
- package/dist/contracts/slugs.js +47 -0
- package/dist/contracts/space-config.d.ts +216 -0
- package/dist/contracts/space-config.js +237 -0
- package/dist/contracts/space-theme.d.ts +25 -0
- package/dist/contracts/space-theme.js +49 -0
- package/dist/contracts/spaces.d.ts +2760 -0
- package/dist/contracts/spaces.js +589 -0
- package/dist/contracts/superadmin-activity.d.ts +205 -0
- package/dist/contracts/superadmin-activity.js +107 -0
- package/dist/contracts/superadmin-emails.d.ts +212 -0
- package/dist/contracts/superadmin-emails.js +112 -0
- package/dist/contracts/superadmin-queues.d.ts +414 -0
- package/dist/contracts/superadmin-queues.js +202 -0
- package/dist/contracts/superadmin-runtime.d.ts +27 -0
- package/dist/contracts/superadmin-runtime.js +38 -0
- package/dist/contracts/superadmin-spaces.d.ts +429 -0
- package/dist/contracts/superadmin-spaces.js +82 -0
- package/dist/contracts/superadmin-tenants.d.ts +180 -0
- package/dist/contracts/superadmin-tenants.js +117 -0
- package/dist/contracts/superadmin.d.ts +654 -0
- package/dist/contracts/superadmin.js +309 -0
- package/dist/contracts/tags.d.ts +1140 -0
- package/dist/contracts/tags.js +1050 -0
- package/dist/contracts/teams.d.ts +233 -0
- package/dist/contracts/teams.js +174 -0
- package/dist/contracts/telemetry.d.ts +2 -0
- package/dist/contracts/telemetry.js +1 -0
- package/dist/contracts/transfers.d.ts +105 -0
- package/dist/contracts/transfers.js +48 -0
- package/dist/contracts/variables.d.ts +189 -0
- package/dist/contracts/variables.js +82 -0
- package/dist/contracts/webhooks.d.ts +159 -0
- package/dist/contracts/webhooks.js +59 -0
- package/dist/contracts/zero.d.ts +1538 -0
- package/dist/contracts/zero.js +755 -0
- package/dist/docs/agent-prose.d.ts +35 -0
- package/dist/docs/agent-prose.js +153 -0
- package/dist/docs/agent-setup.d.ts +6 -0
- package/dist/docs/agent-setup.js +164 -0
- package/dist/docs/agent-solutions.d.ts +110 -0
- package/dist/docs/agent-solutions.js +181 -0
- package/dist/docs/error-docs.d.ts +12 -0
- package/dist/docs/error-docs.js +1601 -0
- package/dist/docs/skill-distribution.d.ts +12 -0
- package/dist/docs/skill-distribution.js +18 -0
- package/dist/domain-exploration.d.ts +108 -0
- package/dist/domain-exploration.js +488 -0
- package/dist/domain-normalize.d.ts +1 -0
- package/dist/domain-normalize.js +14 -0
- package/dist/domain-zones.d.ts +1 -0
- package/dist/domain-zones.js +5272 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/utils/access-policy.d.ts +39 -0
- package/dist/utils/access-policy.js +232 -0
- package/dist/utils/api.d.ts +4 -0
- package/dist/utils/api.js +13 -0
- package/dist/utils/auth-redirect.d.ts +1 -0
- package/dist/utils/auth-redirect.js +48 -0
- package/dist/utils/auth.d.ts +5 -0
- package/dist/utils/auth.js +13 -0
- package/dist/utils/build-settings.d.ts +49 -0
- package/dist/utils/build-settings.js +366 -0
- package/dist/utils/claim-token.d.ts +1 -0
- package/dist/utils/claim-token.js +9 -0
- package/dist/utils/collections.d.ts +1 -0
- package/dist/utils/collections.js +5 -0
- package/dist/utils/concurrency.d.ts +1 -0
- package/dist/utils/concurrency.js +18 -0
- package/dist/utils/content-type.d.ts +10 -0
- package/dist/utils/content-type.js +145 -0
- package/dist/utils/error-display.d.ts +7 -0
- package/dist/utils/error-display.js +42 -0
- package/dist/utils/error.d.ts +1 -0
- package/dist/utils/error.js +3 -0
- package/dist/utils/generate-space-name.d.ts +14 -0
- package/dist/utils/generate-space-name.js +95 -0
- package/dist/utils/git-repository.d.ts +5 -0
- package/dist/utils/git-repository.js +99 -0
- package/dist/utils/guards.d.ts +1 -0
- package/dist/utils/guards.js +3 -0
- package/dist/utils/publish-detection.d.ts +10 -0
- package/dist/utils/publish-detection.js +118 -0
- package/dist/utils/publish-policy.d.ts +69 -0
- package/dist/utils/publish-policy.js +429 -0
- package/dist/utils/query-client.d.ts +7 -0
- package/dist/utils/query-client.js +21 -0
- package/dist/utils/query-keys.d.ts +75 -0
- package/dist/utils/query-keys.js +78 -0
- package/dist/utils/runtime-paths.d.ts +7 -0
- package/dist/utils/runtime-paths.js +28 -0
- package/dist/utils/runtime-upload.d.ts +19 -0
- package/dist/utils/runtime-upload.js +27 -0
- package/dist/utils/slug.d.ts +5 -0
- package/dist/utils/slug.js +13 -0
- package/dist/utils/space-config.d.ts +75 -0
- package/dist/utils/space-config.js +415 -0
- package/dist/utils/space-theme.d.ts +16 -0
- package/dist/utils/space-theme.js +89 -0
- package/dist/utils/static-runtime-policy.d.ts +17 -0
- package/dist/utils/static-runtime-policy.js +103 -0
- package/dist/utils/upload-session.d.ts +34 -0
- package/dist/utils/upload-session.js +69 -0
- package/dist/utils/urls.d.ts +2 -0
- package/dist/utils/urls.js +7 -0
- package/dist/utils/version-path.d.ts +6 -0
- package/dist/utils/version-path.js +51 -0
- package/dist/utils/wpcom-auth-redirects.d.ts +14 -0
- package/dist/utils/wpcom-auth-redirects.js +49 -0
- package/dist/utils/zero-realtime-signature.d.ts +12 -0
- package/dist/utils/zero-realtime-signature.js +45 -0
- package/dist/vocabulary.d.ts +230 -0
- package/dist/vocabulary.js +218 -0
- package/package.json +58 -0
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { policyDocSchema } from "./access.js";
|
|
3
|
+
import { conventionFilesSchema, manifestFileSchema } from "./internal.js";
|
|
4
|
+
const runtimeConventionFilesSchema = conventionFilesSchema.omit({ routes: true }).strict();
|
|
5
|
+
const hostCanonicalRedirectSchema = z.object({
|
|
6
|
+
from: z.string().min(1),
|
|
7
|
+
to: z.string().min(1),
|
|
8
|
+
status: z.literal(308).default(308),
|
|
9
|
+
});
|
|
10
|
+
// Immutable version hosts carry their own target version: the intent is the
|
|
11
|
+
// COMPLETE declarative hostname map for the space (every retained ready
|
|
12
|
+
// version), so a route update can never orphan an older version URL.
|
|
13
|
+
const versionHostnameEntrySchema = z.object({
|
|
14
|
+
hostname: z.string().min(1),
|
|
15
|
+
version_id: z.string().min(1),
|
|
16
|
+
});
|
|
17
|
+
const proxyHostRouteEntrySchema = z.object({
|
|
18
|
+
hostname: z.string().min(1),
|
|
19
|
+
path_prefix: z.string().min(1).default("/"),
|
|
20
|
+
upstream: z.string().url(),
|
|
21
|
+
noindex: z.boolean().default(false),
|
|
22
|
+
});
|
|
23
|
+
const runtimeRouteIntentSchema = z.object({
|
|
24
|
+
production_hostnames: z.array(z.string().min(1)).default([]),
|
|
25
|
+
noindex_production_hostnames: z.array(z.string().min(1)).default([]),
|
|
26
|
+
version_hostnames: z.array(versionHostnameEntrySchema).default([]),
|
|
27
|
+
host_canonical_redirects: z.array(hostCanonicalRedirectSchema).default([]),
|
|
28
|
+
proxy_host_routes: z.array(proxyHostRouteEntrySchema).default([]),
|
|
29
|
+
});
|
|
30
|
+
// Changed-path purge contract (internal-docs/platform.md "Cache Management"):
|
|
31
|
+
// finalize computes the changed-path set against the previous pointer target
|
|
32
|
+
// — expanded to canonical request paths (leading slash, directory-index
|
|
33
|
+
// variants included) — and carries it through the runtime callback journal;
|
|
34
|
+
// the callback receiver translates journal events into edge purges scoped to
|
|
35
|
+
// changed paths, never a blanket purge when a diff exists. Past this cap (or
|
|
36
|
+
// when no previous pointer target exists) the control plane omits the set and
|
|
37
|
+
// purge handling falls back to one host-wide purge.
|
|
38
|
+
export const RUNTIME_CHANGED_PATHS_MAX = 500;
|
|
39
|
+
const changedPathsSchema = z
|
|
40
|
+
.array(z
|
|
41
|
+
.string()
|
|
42
|
+
.min(1)
|
|
43
|
+
.max(2048)
|
|
44
|
+
.describe("Canonical request path (decoded, leading slash) whose served bytes changed."))
|
|
45
|
+
.max(RUNTIME_CHANGED_PATHS_MAX)
|
|
46
|
+
.optional()
|
|
47
|
+
.describe("Request paths changed vs the previous pointer target; absent = no diff available (host-wide purge fallback). Echoed verbatim into the route_updated journal event.");
|
|
48
|
+
const previousVersionIdSchema = z
|
|
49
|
+
.string()
|
|
50
|
+
.min(1)
|
|
51
|
+
.optional()
|
|
52
|
+
.describe("The pointer target this activation replaces (diff baseline).");
|
|
53
|
+
export const runtimeVersionCreateRequestSchema = z.object({
|
|
54
|
+
version_id: z.string().min(1).optional(),
|
|
55
|
+
files: z.array(manifestFileSchema),
|
|
56
|
+
retained_files: z.array(manifestFileSchema).default([]),
|
|
57
|
+
reusable_version_id: z.string().min(1).optional(),
|
|
58
|
+
// "declared" sessions validate every PUT against the declared manifest.
|
|
59
|
+
// "open" sessions (internal-docs/platform.md "Upload Contract" shape 2) have
|
|
60
|
+
// no manifest: the runtime enforces path policy and the session caps per
|
|
61
|
+
// PUT, computes streaming hashes, and finalize derives the manifest.
|
|
62
|
+
// Plan-policy caps ride in session state, never in the upload JWT, and are
|
|
63
|
+
// valid only on open sessions.
|
|
64
|
+
session_mode: z.enum(["declared", "open"]).default("declared"),
|
|
65
|
+
max_total_bytes: z.number().int().positive().optional(),
|
|
66
|
+
max_file_count: z.number().int().positive().optional(),
|
|
67
|
+
// Session state stores the upload truth (spec "Upload Contract"): the version's
|
|
68
|
+
// manifest hash and the draft expiry so resume answers come from runtime state.
|
|
69
|
+
manifest_hash: z.string().optional(),
|
|
70
|
+
expires_at: z.string().optional(),
|
|
71
|
+
metadata: z.record(z.string(), z.unknown()).default({}),
|
|
72
|
+
convention_files: runtimeConventionFilesSchema.default({}),
|
|
73
|
+
});
|
|
74
|
+
export const runtimeVersionCreateResponseSchema = z.object({
|
|
75
|
+
space_id: z.string(),
|
|
76
|
+
version_id: z.string(),
|
|
77
|
+
upload_id: z.string(),
|
|
78
|
+
created_at: z.string(),
|
|
79
|
+
});
|
|
80
|
+
// Runtime-truth upload session state (spec "Upload Contract"): the resume flow asks
|
|
81
|
+
// the runtime which declared files/chunks are actually present instead of guessing
|
|
82
|
+
// from control-plane pending-upload state.
|
|
83
|
+
export const runtimeUploadSessionResponseSchema = z.object({
|
|
84
|
+
space_id: z.string(),
|
|
85
|
+
version_id: z.string(),
|
|
86
|
+
upload_id: z.string(),
|
|
87
|
+
session_mode: z.enum(["declared", "open"]),
|
|
88
|
+
created_at: z.string().nullable(),
|
|
89
|
+
expires_at: z.string().nullable(),
|
|
90
|
+
manifest_hash: z.string().nullable(),
|
|
91
|
+
files: z.array(z.object({
|
|
92
|
+
path: z.string(),
|
|
93
|
+
size: z.number().int().nonnegative(),
|
|
94
|
+
sha256: z.string().optional(),
|
|
95
|
+
uploaded: z.boolean(),
|
|
96
|
+
})),
|
|
97
|
+
// Declared paths the runtime has not committed yet (empty for open sessions).
|
|
98
|
+
pending_paths: z.array(z.string()),
|
|
99
|
+
// Staged chunked-upload parts by canonical path (contiguity is checked at complete).
|
|
100
|
+
chunks: z.record(z.string(), z.array(z.number().int().positive())),
|
|
101
|
+
});
|
|
102
|
+
// Route-pointer config is pure serving policy: THE resolved access policy plus
|
|
103
|
+
// the anonymous claim countdown. Space passwords are NOT a separate config
|
|
104
|
+
// channel — they ride inside `policy.rules` as a password challenge rule (one
|
|
105
|
+
// access model, spec "Runtime"). Per-version serving behavior
|
|
106
|
+
// (index/fallback/listing) is a version artifact concern, never route config.
|
|
107
|
+
const runtimeRouteConfigSchema = z.object({
|
|
108
|
+
// THE unified policy lane ({ rules: RuntimeRule[] }) the runtime enforcer
|
|
109
|
+
// (access-rules.php) evaluates first-match-wins for every host entry this
|
|
110
|
+
// space serves — route hosts, custom domains, and immutable version hosts
|
|
111
|
+
// alike. Carries platform + file + cloud rules (platform prepended, always
|
|
112
|
+
// wins). Explicit null clears the stored policy; absence leaves it untouched.
|
|
113
|
+
policy: policyDocSchema.nullable().optional(),
|
|
114
|
+
// Serving-secret map (name -> value) the policy's password rules reference by
|
|
115
|
+
// `auth.password.ref` = "secret:<name>". Carries the space-password bcrypt
|
|
116
|
+
// verifier hash the runtime resolves and `password_verify`s. Explicit null
|
|
117
|
+
// clears stored secrets; absence leaves them untouched.
|
|
118
|
+
secrets: z.record(z.string().min(1), z.string().min(1)).nullable().optional(),
|
|
119
|
+
// Anonymous claim-window countdown (ISO timestamp), compiled into serving
|
|
120
|
+
// state so the runtime can render the expiry-rescue banner for visitors
|
|
121
|
+
// holding the claim-link viewer session. Null/absent once claimed.
|
|
122
|
+
anonymous_expires_at: z.string().nullable().optional(),
|
|
123
|
+
});
|
|
124
|
+
// Compiled SpaceConfig serving primitives (spec "Serving resolution"): the finalize
|
|
125
|
+
// compiler resolves content defaults -> sf.jsonc -> space overlay into this shape;
|
|
126
|
+
// the runtime stores it on the version's serving artifact and never re-infers. When
|
|
127
|
+
// absent, the runtime infers content defaults (root index.html => website-style,
|
|
128
|
+
// otherwise artifact-style listing + viewer).
|
|
129
|
+
const runtimeServingConfigSchema = z.object({
|
|
130
|
+
index: z
|
|
131
|
+
.union([z.string().min(1), z.literal(false)])
|
|
132
|
+
.optional()
|
|
133
|
+
.describe("Directory index file name, or false to disable directory index resolution."),
|
|
134
|
+
fallback: z
|
|
135
|
+
.object({
|
|
136
|
+
path: z.string().min(1).describe("Committed file served when no exact route matches."),
|
|
137
|
+
status: z
|
|
138
|
+
.union([z.literal(200), z.literal(404)])
|
|
139
|
+
.describe("Response status for the fallback; 200 with /index.html is the SPA shape."),
|
|
140
|
+
})
|
|
141
|
+
.nullable()
|
|
142
|
+
.optional(),
|
|
143
|
+
listing: z
|
|
144
|
+
.boolean()
|
|
145
|
+
.optional()
|
|
146
|
+
.describe("Generate directory-listing pages for directories without an index file."),
|
|
147
|
+
viewer: z
|
|
148
|
+
.boolean()
|
|
149
|
+
.optional()
|
|
150
|
+
.describe("Generate the single-file viewer page when a version has exactly one public file."),
|
|
151
|
+
meta: z
|
|
152
|
+
.object({
|
|
153
|
+
title: z.string().max(300).optional().describe("Listing/viewer/OG title."),
|
|
154
|
+
description: z.string().max(1000).optional().describe("Listing/viewer/OG description."),
|
|
155
|
+
image: z.string().max(2000).optional().describe("OG image path."),
|
|
156
|
+
})
|
|
157
|
+
.nullable()
|
|
158
|
+
.optional()
|
|
159
|
+
.describe("Finalize-resolved listing/viewer/OG metadata (effective SpaceConfig meta); wins over session metadata."),
|
|
160
|
+
// Hidden experimental build-pipeline flag: absent on every version finalized
|
|
161
|
+
// without it (byte-identical payload to today). Only ever sent as true.
|
|
162
|
+
experimental_gutenberg: z.boolean().optional(),
|
|
163
|
+
// Platform-owned head metadata injection for normal HTML finalization. This is
|
|
164
|
+
// distinct from the hidden user build-pipeline flag: it only enables missing
|
|
165
|
+
// title/description/OG/Twitter tags derived from finalized SpaceConfig meta.
|
|
166
|
+
platform_meta: z.boolean().optional(),
|
|
167
|
+
// Platform-owned same-host SDK bootstrap metadata. The public Cast base is
|
|
168
|
+
// finalized with the version so locally-created remote runtimes do not guess
|
|
169
|
+
// between local/prod; resource identity is also per-version because one
|
|
170
|
+
// runtime/Atomic can serve many spaces.
|
|
171
|
+
spacefast_sdk: z
|
|
172
|
+
.object({
|
|
173
|
+
cast_api_base: z.string().url().max(2000).nullable().optional(),
|
|
174
|
+
cast_ws_url: z.string().url().max(2000).nullable().optional(),
|
|
175
|
+
cast_resource_key: z.string().min(1).max(256).nullable().optional(),
|
|
176
|
+
})
|
|
177
|
+
.optional(),
|
|
178
|
+
// CP-validated inject snippets (<= 8 KB each, <= 16 per array); sent only
|
|
179
|
+
// when experimental_gutenberg is true. Char caps here are a sanity bound —
|
|
180
|
+
// the byte caps are enforced by the shared SpaceConfig validator.
|
|
181
|
+
inject: z
|
|
182
|
+
.object({
|
|
183
|
+
head: z.array(z.string().max(8192)).max(16).optional(),
|
|
184
|
+
bodyStart: z.array(z.string().max(8192)).max(16).optional(),
|
|
185
|
+
bodyEnd: z.array(z.string().max(8192)).max(16).optional(),
|
|
186
|
+
noscript: z.array(z.string().max(8192)).max(16).optional(),
|
|
187
|
+
})
|
|
188
|
+
.optional(),
|
|
189
|
+
});
|
|
190
|
+
const runtimeZeroEndpointCapabilitiesSchema = z
|
|
191
|
+
.object({
|
|
192
|
+
db: z.boolean().optional(),
|
|
193
|
+
fetch: z.boolean().optional(),
|
|
194
|
+
auth: z.boolean().optional(),
|
|
195
|
+
env: z.boolean().optional(),
|
|
196
|
+
realtime: z.boolean().optional(),
|
|
197
|
+
})
|
|
198
|
+
.default({});
|
|
199
|
+
const runtimeZeroEndpointSchema = z.object({
|
|
200
|
+
method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]),
|
|
201
|
+
path: z.string().min(1).max(2048),
|
|
202
|
+
source: z
|
|
203
|
+
.string()
|
|
204
|
+
.min(1)
|
|
205
|
+
.max(2 * 1024 * 1024),
|
|
206
|
+
endpoint_id: z.string().min(1).max(256).optional(),
|
|
207
|
+
schema_hash: z.string().min(1).max(256).optional(),
|
|
208
|
+
capabilities: runtimeZeroEndpointCapabilitiesSchema.optional(),
|
|
209
|
+
db: z.record(z.string(), z.unknown()).optional(),
|
|
210
|
+
});
|
|
211
|
+
const runtimeZeroRunSchema = z.object({
|
|
212
|
+
run_id: z.string().min(1).max(256),
|
|
213
|
+
source: z
|
|
214
|
+
.string()
|
|
215
|
+
.min(1)
|
|
216
|
+
.max(2 * 1024 * 1024),
|
|
217
|
+
schema_hash: z.string().min(1).max(256).optional(),
|
|
218
|
+
capabilities: runtimeZeroEndpointCapabilitiesSchema.optional(),
|
|
219
|
+
db: z.record(z.string(), z.unknown()).optional(),
|
|
220
|
+
});
|
|
221
|
+
export const runtimeVersionFinalizeRequestSchema = z.object({
|
|
222
|
+
upload_id: z.string().min(1),
|
|
223
|
+
// The version's authoritative ready timestamp (epoch seconds), passed by the
|
|
224
|
+
// control plane when the version already reached ready (re-finalize, import
|
|
225
|
+
// re-materialization, provider migration). The engine stamps it ONCE into the
|
|
226
|
+
// version metadata; access-window rules (windowDays) compare against this
|
|
227
|
+
// stored value — never a filesystem mtime that resets on rebuilds.
|
|
228
|
+
ready_at: z.number().int().positive().optional(),
|
|
229
|
+
convention_files: runtimeConventionFilesSchema.optional(),
|
|
230
|
+
// Finalize-time `{{ vars.NAME }}` substitution output (spec "Variable
|
|
231
|
+
// rules"): substituted bytes replace the served files; the engine keeps the
|
|
232
|
+
// pre-substitution bytes in `files-original/` so declared-sha dedup still
|
|
233
|
+
// verifies upload identity. Keyed by canonical version-relative path.
|
|
234
|
+
template_files: z
|
|
235
|
+
.record(z.string().min(1).describe("Canonical committed path declared in `templates`."), z
|
|
236
|
+
.string()
|
|
237
|
+
.max(2 * 1024 * 1024)
|
|
238
|
+
.describe("Substituted file contents (secret values never reach this payload)."))
|
|
239
|
+
.refine((files) => Object.keys(files).length <= 100, {
|
|
240
|
+
message: "template_files supports up to 100 entries.",
|
|
241
|
+
})
|
|
242
|
+
.optional()
|
|
243
|
+
.describe("Substituted template contents applied over the committed tree at finalize."),
|
|
244
|
+
// Per-channel template variants (spec "Per-channel values"): channelValues
|
|
245
|
+
// overrides compile channel-specific contents of declared template files as
|
|
246
|
+
// channel-scoped serving artifacts. Keyed by RUNTIME ROUTE NAME (route names
|
|
247
|
+
// are runtime-only vocabulary; the live channel serves via `production`).
|
|
248
|
+
// Variants serve only on the route's hosts — permanent Version URLs always
|
|
249
|
+
// serve the version's own finalize-resolved values.
|
|
250
|
+
template_variants: z
|
|
251
|
+
.record(z
|
|
252
|
+
.string()
|
|
253
|
+
.min(1)
|
|
254
|
+
.max(128)
|
|
255
|
+
.regex(/^[A-Za-z0-9._-]+$/)
|
|
256
|
+
.describe("Runtime route name this variant set serves."), z
|
|
257
|
+
.record(z.string().min(1).describe("Canonical committed path declared in `templates`."), z
|
|
258
|
+
.string()
|
|
259
|
+
.max(2 * 1024 * 1024)
|
|
260
|
+
.describe("Variant file contents (secret values never reach this payload)."))
|
|
261
|
+
.refine((files) => Object.keys(files).length <= 100, {
|
|
262
|
+
message: "template_variants supports up to 100 entries per route.",
|
|
263
|
+
}))
|
|
264
|
+
.refine((routes) => Object.keys(routes).length <= 8, {
|
|
265
|
+
message: "template_variants supports up to 8 routes.",
|
|
266
|
+
})
|
|
267
|
+
.optional()
|
|
268
|
+
.describe("Channel-variant template contents, keyed by runtime route name."),
|
|
269
|
+
serving: z
|
|
270
|
+
.object({
|
|
271
|
+
headers_exact: z.record(z.string(), z.array(z.record(z.string(), z.unknown()))).default({}),
|
|
272
|
+
headers_pattern: z.array(z.record(z.string(), z.unknown())).default([]),
|
|
273
|
+
redirects_exact: z.record(z.string(), z.array(z.record(z.string(), z.unknown()))).default({}),
|
|
274
|
+
redirects_pattern: z.array(z.record(z.string(), z.unknown())).default([]),
|
|
275
|
+
config: runtimeServingConfigSchema.optional(),
|
|
276
|
+
// Compiled SpaceTheme custom-property declarations consumed by themeable pages
|
|
277
|
+
// (directory listings, single-file viewers, platform pages). The finalize
|
|
278
|
+
// compiler validates the token grammar; the runtime re-rejects anything that
|
|
279
|
+
// could escape a <style> element or reach the network.
|
|
280
|
+
theme_css: z.string().max(16384).optional(),
|
|
281
|
+
// Trusted Zero endpoint source compiled by the runtime into private
|
|
282
|
+
// endpoint-specific JS, QuickJS bytecode, and PHP manifest invoke actions.
|
|
283
|
+
zero_endpoints: z.array(runtimeZeroEndpointSchema).max(128).optional(),
|
|
284
|
+
// Trusted Zero run-handler source compiled into private artifacts for
|
|
285
|
+
// non-HTTP Zero execution surfaces. These are not PHP route actions.
|
|
286
|
+
zero_runs: z.array(runtimeZeroRunSchema).max(128).optional(),
|
|
287
|
+
})
|
|
288
|
+
.optional(),
|
|
289
|
+
activate: z
|
|
290
|
+
.object({
|
|
291
|
+
route_name: z
|
|
292
|
+
.string()
|
|
293
|
+
.min(1)
|
|
294
|
+
.default("production")
|
|
295
|
+
.describe("Runtime route-pointer to activate; route names are runtime-only vocabulary."),
|
|
296
|
+
config: runtimeRouteConfigSchema.optional(),
|
|
297
|
+
changed_paths: changedPathsSchema,
|
|
298
|
+
previous_version_id: previousVersionIdSchema,
|
|
299
|
+
production_hostnames: runtimeRouteIntentSchema.shape.production_hostnames,
|
|
300
|
+
noindex_production_hostnames: runtimeRouteIntentSchema.shape.noindex_production_hostnames,
|
|
301
|
+
version_hostnames: runtimeRouteIntentSchema.shape.version_hostnames,
|
|
302
|
+
host_canonical_redirects: runtimeRouteIntentSchema.shape.host_canonical_redirects,
|
|
303
|
+
proxy_host_routes: runtimeRouteIntentSchema.shape.proxy_host_routes,
|
|
304
|
+
})
|
|
305
|
+
.optional(),
|
|
306
|
+
});
|
|
307
|
+
export const runtimeVersionFinalizeResponseSchema = z.object({
|
|
308
|
+
space_id: z.string(),
|
|
309
|
+
version_id: z.string(),
|
|
310
|
+
status: z.literal("ready"),
|
|
311
|
+
// Open sessions: the manifest derived from what was actually uploaded
|
|
312
|
+
// (path, size, streaming sha256). Absent for declared sessions.
|
|
313
|
+
manifest: z.array(manifestFileSchema).optional(),
|
|
314
|
+
});
|
|
315
|
+
export const runtimeRouteUpdateRequestSchema = z.object({
|
|
316
|
+
version_id: z.string().min(1),
|
|
317
|
+
config: runtimeRouteConfigSchema.optional(),
|
|
318
|
+
changed_paths: changedPathsSchema,
|
|
319
|
+
previous_version_id: previousVersionIdSchema,
|
|
320
|
+
production_hostnames: runtimeRouteIntentSchema.shape.production_hostnames,
|
|
321
|
+
noindex_production_hostnames: runtimeRouteIntentSchema.shape.noindex_production_hostnames,
|
|
322
|
+
version_hostnames: runtimeRouteIntentSchema.shape.version_hostnames,
|
|
323
|
+
host_canonical_redirects: runtimeRouteIntentSchema.shape.host_canonical_redirects,
|
|
324
|
+
proxy_host_routes: runtimeRouteIntentSchema.shape.proxy_host_routes,
|
|
325
|
+
});
|
|
326
|
+
export const runtimeRouteUpdateResponseSchema = z.object({
|
|
327
|
+
space_id: z.string(),
|
|
328
|
+
route_name: z.string(),
|
|
329
|
+
version_id: z.string(),
|
|
330
|
+
});
|
|
331
|
+
export const runtimeTombstonesUpdateRequestSchema = z.object({
|
|
332
|
+
hostnames: runtimeRouteIntentSchema.shape.production_hostnames,
|
|
333
|
+
mode: z.enum(["replace", "add", "remove"]).default("replace"),
|
|
334
|
+
// Optional reason/category drive a differentiated tombstone variant on the
|
|
335
|
+
// runtime (e.g. csam -> bare 404, copyright -> 451, suspension -> 402). The
|
|
336
|
+
// runtime falls back to a generic 404 when both are absent, so these are
|
|
337
|
+
// additive and back-compatible.
|
|
338
|
+
reason: z.string().optional(),
|
|
339
|
+
category: z.string().optional(),
|
|
340
|
+
});
|
|
341
|
+
export const runtimeTombstonesUpdateResponseSchema = z.object({
|
|
342
|
+
space_id: z.string(),
|
|
343
|
+
tombstone_count: z.number().int().nonnegative(),
|
|
344
|
+
});
|
|
345
|
+
export const runtimeSpaceDeleteResponseSchema = z.object({
|
|
346
|
+
space_id: z.string(),
|
|
347
|
+
status: z.literal("deleted"),
|
|
348
|
+
});
|
|
349
|
+
export const runtimeVersionDeleteResponseSchema = z.object({
|
|
350
|
+
space_id: z.string(),
|
|
351
|
+
version_id: z.string(),
|
|
352
|
+
status: z.literal("deleted"),
|
|
353
|
+
});
|
|
354
|
+
export const runtimeSpaceRepairResponseSchema = z.object({
|
|
355
|
+
space_id: z.string(),
|
|
356
|
+
status: z.literal("repaired"),
|
|
357
|
+
});
|
|
358
|
+
const runtimeExportImportStatusSchema = z.enum([
|
|
359
|
+
"waiting_for_archive",
|
|
360
|
+
"pending",
|
|
361
|
+
"running",
|
|
362
|
+
"complete",
|
|
363
|
+
]);
|
|
364
|
+
export const runtimeSpaceExportStartRequestSchema = z
|
|
365
|
+
.object({
|
|
366
|
+
version_ids: z.array(z.string().min(1)).min(1).optional(),
|
|
367
|
+
// Honest export options (spec SpaceExportRequest): include_files=false
|
|
368
|
+
// produces a config-only archive; include_explicit_config=false skips the
|
|
369
|
+
// space access policy entry. Recorded in stattic.json `includes`.
|
|
370
|
+
include_files: z.boolean().optional(),
|
|
371
|
+
include_explicit_config: z.boolean().optional(),
|
|
372
|
+
})
|
|
373
|
+
.strict();
|
|
374
|
+
export const runtimeSpaceExportResponseSchema = z.object({
|
|
375
|
+
type: z.literal("space_export"),
|
|
376
|
+
export_id: z.string(),
|
|
377
|
+
space_id: z.string(),
|
|
378
|
+
status: runtimeExportImportStatusSchema,
|
|
379
|
+
cursor: z.number().int().nonnegative(),
|
|
380
|
+
processed_files: z.number().int().nonnegative(),
|
|
381
|
+
total_files: z.number().int().nonnegative(),
|
|
382
|
+
version_ids: z.array(z.string()),
|
|
383
|
+
archive_size: z.number().int().nonnegative().optional(),
|
|
384
|
+
// SHA-256 of the finished archive (64 lowercase hex), computed once at
|
|
385
|
+
// completion so the control plane can expose SpaceExport.archive.sha256.
|
|
386
|
+
archive_sha256: z.string().optional(),
|
|
387
|
+
created_at: z.string(),
|
|
388
|
+
updated_at: z.string(),
|
|
389
|
+
completed_at: z.string().optional(),
|
|
390
|
+
});
|
|
391
|
+
export const runtimeSpaceImportStartRequestSchema = z
|
|
392
|
+
.object({
|
|
393
|
+
version_id_map: z.record(z.string(), z.string()).optional(),
|
|
394
|
+
})
|
|
395
|
+
.strict();
|
|
396
|
+
// Deferred version-id mapping: control-plane-driven uploads land on the
|
|
397
|
+
// runtime before the control plane has read the archive, so the freshly
|
|
398
|
+
// minted target ids are supplied here before the first step.
|
|
399
|
+
export const runtimeSpaceImportMapRequestSchema = z
|
|
400
|
+
.object({
|
|
401
|
+
version_id_map: z.record(z.string(), z.string()),
|
|
402
|
+
})
|
|
403
|
+
.strict();
|
|
404
|
+
export const runtimeSpaceImportResponseSchema = z.object({
|
|
405
|
+
type: z.literal("space_import"),
|
|
406
|
+
import_id: z.string(),
|
|
407
|
+
space_id: z.string(),
|
|
408
|
+
status: runtimeExportImportStatusSchema,
|
|
409
|
+
cursor: z.number().int().nonnegative(),
|
|
410
|
+
processed_files: z.number().int().nonnegative(),
|
|
411
|
+
total_files: z.number().int().nonnegative(),
|
|
412
|
+
version_ids: z.array(z.string()),
|
|
413
|
+
created_at: z.string(),
|
|
414
|
+
updated_at: z.string(),
|
|
415
|
+
completed_at: z.string().optional(),
|
|
416
|
+
});
|
|
417
|
+
// Per-space generation state reported by the authed state endpoint. The
|
|
418
|
+
// reconciliation sweep compares this against control-plane expectations
|
|
419
|
+
// (space liveVersionId vs the runtime's route pointers) and repairs targeted
|
|
420
|
+
// mismatches — never a blanket re-sync (internal-docs/platform.md "Cache
|
|
421
|
+
// Management": missed callbacks degrade to bounded staleness).
|
|
422
|
+
export const runtimeSpaceStateSchema = z.object({
|
|
423
|
+
space_id: z.string().min(1).describe("Space whose runtime route pointers follow."),
|
|
424
|
+
routes: z
|
|
425
|
+
.record(z.string(), z.string())
|
|
426
|
+
.describe("Route pointer map: route name -> version id currently compiled for serving."),
|
|
427
|
+
tombstone_count: z
|
|
428
|
+
.number()
|
|
429
|
+
.int()
|
|
430
|
+
.nonnegative()
|
|
431
|
+
.describe("Hostnames the runtime serves a tombstone page for on this space."),
|
|
432
|
+
});
|
|
433
|
+
export const runtimeHealthResponseSchema = z.object({
|
|
434
|
+
ok: z.literal(true),
|
|
435
|
+
runtime: z.literal("stattic-php"),
|
|
436
|
+
schema: z.string().min(1).optional(),
|
|
437
|
+
engine_version: z.string().min(1).optional(),
|
|
438
|
+
engine_revision: z
|
|
439
|
+
.string()
|
|
440
|
+
.min(1)
|
|
441
|
+
.optional()
|
|
442
|
+
.describe("Runtime engine bundle revision. Missing means the engine predates revision health."),
|
|
443
|
+
site_state: z.string().min(1).optional(),
|
|
444
|
+
request_hostname: z.string().optional(),
|
|
445
|
+
});
|
|
446
|
+
export const runtimeStateResponseSchema = z.object({
|
|
447
|
+
ok: z.literal(true),
|
|
448
|
+
runtime: z.literal("stattic-php"),
|
|
449
|
+
engine_revision: z
|
|
450
|
+
.string()
|
|
451
|
+
.min(1)
|
|
452
|
+
.optional()
|
|
453
|
+
.describe("Runtime engine bundle revision. Missing means the engine predates revision state."),
|
|
454
|
+
// Optional generation-state fields (absent on engines predating the reconcile
|
|
455
|
+
// handshake; the sweep treats absence as "cannot compare").
|
|
456
|
+
routes_generation: z
|
|
457
|
+
.string()
|
|
458
|
+
.nullable()
|
|
459
|
+
.optional()
|
|
460
|
+
.describe("Active route-index generation id (routes/current.php pointer)."),
|
|
461
|
+
spaces: z
|
|
462
|
+
.array(runtimeSpaceStateSchema)
|
|
463
|
+
.optional()
|
|
464
|
+
.describe("Per-space route-pointer state for reconcile comparison."),
|
|
465
|
+
});
|
|
466
|
+
// Runtime callback journal event (internal-docs/platform.md "Cache
|
|
467
|
+
// Management"): the engine journals every management mutation and delivers it
|
|
468
|
+
// at-least-once to the control-plane callback receiver, which translates
|
|
469
|
+
// serving-affecting events into provider edge purges. `event_id` is the stable
|
|
470
|
+
// journal id — purge enqueues are idempotent on (event_id, hostname) so
|
|
471
|
+
// replays are no-ops. The object is intentionally loose: engines may journal
|
|
472
|
+
// extra diagnostic fields without breaking older control planes.
|
|
473
|
+
export const runtimeCallbackEventSchema = z.looseObject({
|
|
474
|
+
event: z.string().min(1).describe("Journal event name (e.g. route_updated, space_deleted)."),
|
|
475
|
+
event_id: z
|
|
476
|
+
.string()
|
|
477
|
+
.min(1)
|
|
478
|
+
.optional()
|
|
479
|
+
.describe("Stable journal/callback id; purge handling replays as no-ops on this id."),
|
|
480
|
+
operation_id: z
|
|
481
|
+
.string()
|
|
482
|
+
.optional()
|
|
483
|
+
.describe("Control-plane operation the management call ran under."),
|
|
484
|
+
space_id: z.string().optional().describe("Space the event applies to, when space-scoped."),
|
|
485
|
+
version_id: z.string().optional().describe("Version the event applies to, when version-scoped."),
|
|
486
|
+
route_name: z.string().optional().describe("Route pointer the event updated, when route-scoped."),
|
|
487
|
+
hostnames: z
|
|
488
|
+
.array(z.string().min(1))
|
|
489
|
+
.optional()
|
|
490
|
+
.describe("Hostnames whose serving output this event changed; purge targets."),
|
|
491
|
+
changed_paths: changedPathsSchema,
|
|
492
|
+
previous_version_id: previousVersionIdSchema,
|
|
493
|
+
});
|
|
494
|
+
export const runtimeEventsDrainResponseSchema = z.object({
|
|
495
|
+
delivered_count: z.number().int().nonnegative(),
|
|
496
|
+
failed_count: z.number().int().nonnegative(),
|
|
497
|
+
expired_count: z
|
|
498
|
+
.number()
|
|
499
|
+
.int()
|
|
500
|
+
.nonnegative()
|
|
501
|
+
.optional()
|
|
502
|
+
.describe("Undeliverable callbacks dropped after exceeding the attempt cap."),
|
|
503
|
+
returned_count: z.number().int().nonnegative().optional(),
|
|
504
|
+
// Pull fallback: events whose push origin was unreachable are handed back to
|
|
505
|
+
// the drain caller (the control plane) instead of rotting in the journal.
|
|
506
|
+
// Processing replays are no-ops on (event_id, hostname).
|
|
507
|
+
events: z
|
|
508
|
+
.array(z.object({
|
|
509
|
+
operation_id: z.string().optional(),
|
|
510
|
+
event: runtimeCallbackEventSchema,
|
|
511
|
+
}))
|
|
512
|
+
.optional(),
|
|
513
|
+
});
|