@spacefast/common 0.0.26 → 0.2.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.
Files changed (302) hide show
  1. package/dist/agents/connect-targets.d.ts +6 -146
  2. package/dist/agents/connect-targets.js +63 -295
  3. package/dist/agents/private-key-oauth.d.ts +31 -1
  4. package/dist/agents/private-key-oauth.js +124 -33
  5. package/dist/agents/registry/core.d.ts +292 -0
  6. package/dist/agents/registry/core.js +1388 -0
  7. package/dist/agents/registry/deeplink-probes.d.ts +23 -0
  8. package/dist/agents/registry/deeplink-probes.js +18 -0
  9. package/dist/agents/registry/node.d.ts +56 -0
  10. package/dist/agents/registry/node.js +339 -0
  11. package/dist/brand-assets-build.js +1 -2
  12. package/dist/brand-assets.js +4 -7
  13. package/dist/brand.d.ts +17 -0
  14. package/dist/brand.js +24 -4
  15. package/dist/config/domains.d.ts +55 -28
  16. package/dist/config/domains.js +85 -41
  17. package/dist/config/index.js +1 -2
  18. package/dist/contracts/abuse.js +9 -24
  19. package/dist/contracts/access-profiles.d.ts +86 -0
  20. package/dist/contracts/access-profiles.js +89 -0
  21. package/dist/contracts/access.d.ts +21 -27
  22. package/dist/contracts/access.js +33 -64
  23. package/dist/contracts/activity.d.ts +18 -1
  24. package/dist/contracts/activity.js +70 -26
  25. package/dist/contracts/analytics.js +8 -10
  26. package/dist/contracts/api-keys.d.ts +77 -52
  27. package/dist/contracts/api-keys.js +44 -24
  28. package/dist/contracts/application-journal.d.ts +216 -0
  29. package/dist/contracts/application-journal.js +167 -0
  30. package/dist/contracts/auth.d.ts +90 -17
  31. package/dist/contracts/auth.js +86 -17
  32. package/dist/contracts/beta.d.ts +9 -4
  33. package/dist/contracts/beta.js +20 -16
  34. package/dist/contracts/billing.js +7 -11
  35. package/dist/contracts/bootstrap.d.ts +791 -0
  36. package/dist/contracts/bootstrap.js +51 -0
  37. package/dist/contracts/builds.d.ts +192 -7
  38. package/dist/contracts/builds.js +84 -21
  39. package/dist/contracts/channels.d.ts +43 -0
  40. package/dist/contracts/channels.js +25 -9
  41. package/dist/contracts/cli.d.ts +7 -0
  42. package/dist/contracts/cli.js +6 -0
  43. package/dist/contracts/collab-public.d.ts +1 -1
  44. package/dist/contracts/collab-public.js +5 -8
  45. package/dist/contracts/comments.d.ts +45 -35
  46. package/dist/contracts/comments.js +107 -77
  47. package/dist/contracts/commerce.d.ts +165 -0
  48. package/dist/contracts/commerce.js +146 -0
  49. package/dist/contracts/common.d.ts +3 -3
  50. package/dist/contracts/common.js +18 -29
  51. package/dist/contracts/content-contract-verification.d.ts +521 -0
  52. package/dist/contracts/content-contract-verification.js +320 -0
  53. package/dist/contracts/content-platform-fixture.d.ts +1278 -0
  54. package/dist/contracts/content-platform-fixture.js +44 -0
  55. package/dist/contracts/content-program.d.ts +994 -0
  56. package/dist/contracts/content-program.js +658 -0
  57. package/dist/contracts/content-sync.d.ts +290 -0
  58. package/dist/contracts/content-sync.js +167 -0
  59. package/dist/contracts/content.d.ts +432 -0
  60. package/dist/contracts/content.js +303 -0
  61. package/dist/contracts/continuation.d.ts +17 -1
  62. package/dist/contracts/continuation.js +23 -23
  63. package/dist/contracts/countries.js +3 -4
  64. package/dist/contracts/crons.d.ts +17 -0
  65. package/dist/contracts/crons.js +33 -15
  66. package/dist/contracts/dashboard-prefs.d.ts +56 -0
  67. package/dist/contracts/dashboard-prefs.js +51 -0
  68. package/dist/contracts/device-auth.d.ts +234 -37
  69. package/dist/contracts/device-auth.js +267 -53
  70. package/dist/contracts/docs.d.ts +6 -10
  71. package/dist/contracts/docs.js +5 -13
  72. package/dist/contracts/domains.d.ts +499 -102
  73. package/dist/contracts/domains.js +169 -58
  74. package/dist/contracts/email-preferences.d.ts +3 -3
  75. package/dist/contracts/email-preferences.js +6 -7
  76. package/dist/contracts/enums.d.ts +26 -26
  77. package/dist/contracts/enums.js +61 -54
  78. package/dist/contracts/error-code-meta.d.ts +273 -7
  79. package/dist/contracts/error-code-meta.js +81 -5
  80. package/dist/contracts/error-codes.d.ts +5 -5
  81. package/dist/contracts/error-codes.js +79 -16
  82. package/dist/contracts/events.d.ts +100 -20
  83. package/dist/contracts/events.js +107 -20
  84. package/dist/contracts/execution.d.ts +47 -66
  85. package/dist/contracts/execution.js +51 -64
  86. package/dist/contracts/feature-lifecycle.d.ts +70 -14
  87. package/dist/contracts/feature-lifecycle.js +86 -15
  88. package/dist/contracts/features.d.ts +100 -37
  89. package/dist/contracts/features.js +21 -27
  90. package/dist/contracts/fixtures/content-platform-v1.json +1108 -0
  91. package/dist/contracts/frame-session.d.ts +192 -0
  92. package/dist/contracts/frame-session.js +164 -0
  93. package/dist/contracts/functions.d.ts +218 -211
  94. package/dist/contracts/functions.js +273 -260
  95. package/dist/contracts/grant-copy.d.ts +43 -0
  96. package/dist/contracts/grant-copy.js +44 -0
  97. package/dist/contracts/grants.d.ts +64 -56
  98. package/dist/contracts/grants.js +124 -23
  99. package/dist/contracts/ids.d.ts +4 -1
  100. package/dist/contracts/ids.js +4 -1
  101. package/dist/contracts/internal.d.ts +5 -4
  102. package/dist/contracts/internal.js +12 -3
  103. package/dist/contracts/mcp.d.ts +17 -0
  104. package/dist/contracts/mcp.js +23 -0
  105. package/dist/contracts/me.d.ts +6 -1
  106. package/dist/contracts/me.js +12 -6
  107. package/dist/contracts/notifications.d.ts +27 -29
  108. package/dist/contracts/notifications.js +9 -4
  109. package/dist/contracts/oauth-resources.d.ts +121 -10
  110. package/dist/contracts/oauth-resources.js +130 -11
  111. package/dist/contracts/oauth-scope-actions.d.ts +90 -0
  112. package/dist/contracts/oauth-scope-actions.js +126 -0
  113. package/dist/contracts/operations.d.ts +27 -4
  114. package/dist/contracts/operations.js +11 -5
  115. package/dist/contracts/pages.d.ts +29 -5
  116. package/dist/contracts/pages.js +22 -5
  117. package/dist/contracts/partner-notifications.d.ts +3 -0
  118. package/dist/contracts/partner-notifications.js +65 -0
  119. package/dist/contracts/{platform.d.ts → partner.d.ts} +29 -42
  120. package/dist/contracts/{platform.js → partner.js} +27 -40
  121. package/dist/contracts/plan-policy.d.ts +1 -1
  122. package/dist/contracts/principal-assertion.d.ts +43 -0
  123. package/dist/contracts/principal-assertion.js +67 -0
  124. package/dist/contracts/principals.d.ts +73 -0
  125. package/dist/contracts/principals.js +59 -0
  126. package/dist/contracts/privacy.d.ts +11 -0
  127. package/dist/contracts/privacy.js +17 -0
  128. package/dist/contracts/problem-document.js +3 -4
  129. package/dist/contracts/publish-archive.d.ts +116 -18
  130. package/dist/contracts/publish-archive.js +6 -3
  131. package/dist/contracts/push-new.d.ts +4 -4
  132. package/dist/contracts/quotas.js +3 -3
  133. package/dist/contracts/realtime.d.ts +52 -0
  134. package/dist/contracts/realtime.js +54 -0
  135. package/dist/contracts/repository-connections.d.ts +1 -1
  136. package/dist/contracts/repository-connections.js +6 -2
  137. package/dist/contracts/resources.d.ts +105 -14
  138. package/dist/contracts/resources.js +145 -21
  139. package/dist/contracts/route-inventory.d.ts +358 -0
  140. package/dist/contracts/route-inventory.js +141 -0
  141. package/dist/contracts/runtime-api.d.ts +112 -35
  142. package/dist/contracts/runtime-api.js +86 -66
  143. package/dist/contracts/runtime-app.d.ts +11 -21
  144. package/dist/contracts/runtime-app.js +39 -24
  145. package/dist/contracts/runtime-components.d.ts +143 -0
  146. package/dist/contracts/runtime-components.js +199 -0
  147. package/dist/contracts/runtime-db.d.ts +45 -19
  148. package/dist/contracts/runtime-db.js +85 -20
  149. package/dist/contracts/runtime-purge.js +3 -5
  150. package/dist/contracts/runtime-services.d.ts +43 -75
  151. package/dist/contracts/runtime-services.js +29 -49
  152. package/dist/contracts/runtime-storage.d.ts +14 -14
  153. package/dist/contracts/runtime-storage.js +28 -13
  154. package/dist/contracts/sf-config-v1.d.ts +14 -18
  155. package/dist/contracts/slugs.js +13 -4
  156. package/dist/contracts/space-config.d.ts +235 -28
  157. package/dist/contracts/space-config.js +246 -91
  158. package/dist/contracts/spaces.d.ts +360 -255
  159. package/dist/contracts/spaces.js +190 -122
  160. package/dist/contracts/superadmin-activity.d.ts +3 -43
  161. package/dist/contracts/superadmin-activity.js +6 -30
  162. package/dist/contracts/superadmin-emails.d.ts +1 -0
  163. package/dist/contracts/superadmin-emails.js +17 -1
  164. package/dist/contracts/superadmin-runtime.d.ts +199 -0
  165. package/dist/contracts/superadmin-runtime.js +141 -0
  166. package/dist/contracts/superadmin-search.d.ts +22 -2
  167. package/dist/contracts/superadmin-search.js +14 -6
  168. package/dist/contracts/superadmin-spaces.d.ts +435 -186
  169. package/dist/contracts/superadmin-spaces.js +131 -25
  170. package/dist/contracts/superadmin-teams.d.ts +3 -0
  171. package/dist/contracts/superadmin-teams.js +1 -2
  172. package/dist/contracts/superadmin-tenants.d.ts +627 -6
  173. package/dist/contracts/superadmin-tenants.js +32 -7
  174. package/dist/contracts/superadmin.d.ts +98 -16
  175. package/dist/contracts/superadmin.js +63 -10
  176. package/dist/contracts/tags.d.ts +85 -58
  177. package/dist/contracts/tags.js +44 -34
  178. package/dist/contracts/teams.d.ts +72 -9
  179. package/dist/contracts/teams.js +84 -25
  180. package/dist/contracts/tenants.d.ts +135 -0
  181. package/dist/contracts/tenants.js +120 -0
  182. package/dist/contracts/test-triggers.d.ts +70 -0
  183. package/dist/contracts/test-triggers.js +116 -0
  184. package/dist/contracts/theme-json.js +3 -8
  185. package/dist/contracts/transfers.d.ts +1 -0
  186. package/dist/contracts/transfers.js +1 -0
  187. package/dist/contracts/usage.d.ts +209 -0
  188. package/dist/contracts/usage.js +124 -12
  189. package/dist/contracts/variables.d.ts +2 -2
  190. package/dist/contracts/variables.js +9 -13
  191. package/dist/contracts/webhooks.d.ts +13 -5
  192. package/dist/contracts/webhooks.js +3 -1
  193. package/dist/contracts/zero.d.ts +57 -64
  194. package/dist/contracts/zero.js +68 -66
  195. package/dist/dashboard-paths/index.d.ts +24 -21
  196. package/dist/dashboard-paths/index.js +35 -47
  197. package/dist/dashboard-paths/route-reservations.generated.d.ts +2 -0
  198. package/dist/dashboard-paths/route-reservations.generated.js +36 -0
  199. package/dist/docs/agent-arrival.d.ts +92 -0
  200. package/dist/docs/agent-arrival.js +227 -0
  201. package/dist/docs/agent-output-policy.d.ts +6 -0
  202. package/dist/docs/agent-output-policy.js +22 -0
  203. package/dist/docs/agent-prose.d.ts +11 -17
  204. package/dist/docs/agent-prose.js +62 -37
  205. package/dist/docs/agent-setup.d.ts +72 -41
  206. package/dist/docs/agent-setup.js +336 -436
  207. package/dist/docs/catalog.d.ts +147 -89
  208. package/dist/docs/catalog.js +157 -42
  209. package/dist/docs/error-docs.d.ts +2102 -1
  210. package/dist/docs/error-docs.js +285 -16
  211. package/dist/docs/index-build.d.ts +0 -1
  212. package/dist/docs/index-build.js +2 -3
  213. package/dist/docs/page-context-prompt.d.ts +77 -0
  214. package/dist/docs/page-context-prompt.js +131 -0
  215. package/dist/docs/reference-urls.d.ts +46 -0
  216. package/dist/docs/reference-urls.js +79 -0
  217. package/dist/docs/search.d.ts +6 -8
  218. package/dist/docs/search.js +10 -13
  219. package/dist/docs/skill-distribution.d.ts +4 -1
  220. package/dist/docs/skill-distribution.js +10 -5
  221. package/dist/docs/skills.d.ts +117 -117
  222. package/dist/docs/skills.js +120 -72
  223. package/dist/docs/start-prompts.d.ts +45 -0
  224. package/dist/docs/start-prompts.js +62 -0
  225. package/dist/domain-exploration.js +9 -13
  226. package/dist/og-template.d.ts +56 -0
  227. package/dist/og-template.js +56 -0
  228. package/dist/slug-policy/index.js +5 -11
  229. package/dist/utils/browser-credential.d.ts +13 -6
  230. package/dist/utils/browser-credential.js +14 -7
  231. package/dist/utils/build-settings.d.ts +16 -0
  232. package/dist/utils/build-settings.js +63 -17
  233. package/dist/utils/canonical-json.d.ts +3 -5
  234. package/dist/utils/canonical-json.js +3 -5
  235. package/dist/utils/cast-transport.d.ts +5 -17
  236. package/dist/utils/cast-transport.js +6 -19
  237. package/dist/utils/claim-token.js +1 -2
  238. package/dist/utils/comment-avatars.js +4 -6
  239. package/dist/utils/concurrency.js +2 -3
  240. package/dist/utils/content-type.d.ts +7 -6
  241. package/dist/utils/content-type.js +73 -51
  242. package/dist/utils/credential-policy.d.ts +50 -6
  243. package/dist/utils/credential-policy.js +123 -57
  244. package/dist/utils/egress-policy.fixtures.json +1 -1
  245. package/dist/utils/generate-space-name.d.ts +3 -8
  246. package/dist/utils/generate-space-name.js +3 -8
  247. package/dist/utils/grants.d.ts +0 -1
  248. package/dist/utils/grants.js +4 -7
  249. package/dist/utils/gravatar.d.ts +2 -4
  250. package/dist/utils/gravatar.js +6 -12
  251. package/dist/utils/id-hints.js +14 -23
  252. package/dist/utils/idempotency.d.ts +3 -3
  253. package/dist/utils/idempotency.js +6 -7
  254. package/dist/utils/local-space-state.d.ts +15 -15
  255. package/dist/utils/local-space-state.js +34 -23
  256. package/dist/utils/oauth-signed-query.d.ts +3 -5
  257. package/dist/utils/oauth-signed-query.js +6 -9
  258. package/dist/utils/one-shot-replay.d.ts +3 -5
  259. package/dist/utils/one-shot-replay.js +3 -5
  260. package/dist/utils/page-colors.d.ts +4 -10
  261. package/dist/utils/page-colors.js +11 -35
  262. package/dist/utils/page-fonts.js +6 -11
  263. package/dist/utils/page-preview.d.ts +0 -1
  264. package/dist/utils/page-preview.js +0 -1
  265. package/dist/utils/pages.d.ts +22 -11
  266. package/dist/utils/pages.js +70 -30
  267. package/dist/utils/privacy-regions.d.ts +19 -0
  268. package/dist/utils/privacy-regions.js +91 -0
  269. package/dist/utils/publish-form-data.d.ts +4 -5
  270. package/dist/utils/publish-form-data.js +2 -3
  271. package/dist/utils/publish-policy.d.ts +10 -23
  272. package/dist/utils/publish-policy.js +63 -116
  273. package/dist/utils/query-client.d.ts +2 -0
  274. package/dist/utils/query-client.js +10 -1
  275. package/dist/utils/runtime-paths.d.ts +4 -4
  276. package/dist/utils/runtime-paths.js +6 -8
  277. package/dist/utils/runtime-upload.d.ts +4 -0
  278. package/dist/utils/runtime-upload.js +5 -0
  279. package/dist/utils/secure-local-file.d.ts +3 -3
  280. package/dist/utils/secure-local-file.js +18 -24
  281. package/dist/utils/space-config.d.ts +11 -14
  282. package/dist/utils/space-config.js +10 -16
  283. package/dist/utils/static-runtime-policy.d.ts +5 -8
  284. package/dist/utils/static-runtime-policy.generated.d.ts +16 -0
  285. package/dist/utils/static-runtime-policy.generated.js +70 -0
  286. package/dist/utils/static-runtime-policy.js +17 -84
  287. package/dist/utils/storage-policy.js +1 -2
  288. package/dist/utils/upload-session.js +8 -14
  289. package/dist/utils/version-path.js +11 -19
  290. package/dist/utils/wpcom-auth-redirects.d.ts +5 -14
  291. package/dist/utils/wpcom-auth-redirects.js +1 -4
  292. package/dist/vocabulary.d.ts +7 -7
  293. package/dist/vocabulary.js +30 -16
  294. package/package.json +14 -2
  295. package/dist/agents/client-registry.d.ts +0 -22
  296. package/dist/agents/client-registry.js +0 -41
  297. package/dist/docs/agent-handoff-document.d.ts +0 -15
  298. package/dist/docs/agent-handoff-document.js +0 -180
  299. package/dist/docs/agent-solutions.d.ts +0 -110
  300. package/dist/docs/agent-solutions.js +0 -183
  301. package/dist/utils/query-keys.d.ts +0 -84
  302. package/dist/utils/query-keys.js +0 -108
@@ -1,6 +1,8 @@
1
1
  import { z } from "zod";
2
2
  import { serviceOrigin } from "../config/domains.js";
3
- import { GRANT_RESOURCE_PATTERN_LIMIT, normalizeGrantResourcePattern } from "./grants.js";
3
+ import { normalizeSlug } from "../utils/slug.js";
4
+ import { defaultPlanNameSchema, planCatalogSchema } from "./commerce.js";
5
+ import { GRANT_RESOURCE_PATTERN_LIMIT, identityConnectionPublicKeySchema, normalizeGrantResourcePattern, } from "./grants.js";
4
6
  export const SPACE_CONFIG_CANONICAL_FILE = "sf.jsonc";
5
7
  export const SPACE_CONFIG_ALIAS_FILES = [
6
8
  "spacefast.jsonc",
@@ -15,18 +17,15 @@ export const SPACE_CONFIG_ACCEPTED_FILES = [
15
17
  ...SPACE_CONFIG_ALIAS_FILES,
16
18
  ];
17
19
  /**
18
- * Accepted config filenames in read precedence order, highest first. Kept in
19
- * step with the finalizer's `CONFIG_ACCEPTED_FILES` (crates/stattic-runtime-core
20
- * protocol.rs) the runtime compile is the selection authority, and a local
21
- * read choosing a different file than the publish serves is a split brain.
20
+ * Accepted config filenames in read precedence order, highest first. Must stay
21
+ * in step with the finalizer's `CONFIG_ACCEPTED_FILES`
22
+ * (crates/stattic-runtime-core protocol.rs), which is the selection authority.
22
23
  */
23
24
  export const SPACE_CONFIG_PRECEDENCE = SPACE_CONFIG_ACCEPTED_FILES;
24
25
  export const SPACE_CONFIG_PRIVATE_FILES = [...SPACE_CONFIG_ACCEPTED_FILES];
25
- // Config compiler parser-safety caps (the platform spec "Config
26
- // compiler scale targets"): hard from launch, enforced by ONE shared validator
27
- // at every intake seam finalize for the `sf.jsonc` file, request
28
- // validation for the API `config` overlay. Plan policy may LOWER these caps,
29
- // never raise them.
26
+ // Parser-safety caps, enforced by ONE shared validator at every intake seam:
27
+ // finalize for the `sf.jsonc` file, request validation for the API `config`
28
+ // overlay. Plan policy may LOWER these caps, never raise them.
30
29
  export const SPACE_CONFIG_CAPS = {
31
30
  /** Max raw `sf.jsonc` size in bytes. */
32
31
  fileBytes: 256 * 1024,
@@ -56,13 +55,48 @@ export const SPACE_CONFIG_CAPS = {
56
55
  crons: 8,
57
56
  /** Max `crons[].path` length. */
58
57
  cronPathChars: 512,
58
+ // `system` manifest (Partner API): the control-plane-only section a tenant's
59
+ // designated system space publishes. Every string is bounded and every URL is
60
+ // https; these caps are the enforcing authority (the Rust crate only passes
61
+ // the section through — it never validates it).
62
+ /** Max `system.presentation.name` display-name length. */
63
+ systemNameChars: 255,
64
+ /** Max length of any https URL or origin in the `system` manifest. */
65
+ systemUrlChars: 2048,
66
+ /** Max `system.hostnames.apex` length (a DNS name never exceeds 253). */
67
+ systemHostnameChars: 253,
68
+ /** Max `system.presentation.contacts` entries. */
69
+ systemContacts: 32,
70
+ /** Max length of a `system.presentation.contacts` key. */
71
+ systemContactKeyChars: 64,
72
+ /** Max length of a `system.presentation.contacts` value. */
73
+ systemContactValueChars: 2048,
74
+ /** Max `system.api.allowedOrigins` entries. */
75
+ systemApiAllowedOrigins: 32,
76
+ /** Max `system.tokenIssuers` entries. */
77
+ systemTokenIssuers: 16,
78
+ /** Max `system.tokenIssuers[].issuer` length. */
79
+ systemIssuerChars: 512,
80
+ /** Max `system.tokenIssuers[].keys` entries. */
81
+ systemIssuerKeys: 16,
82
+ /** Max `system.tokenIssuers[].keys[].kid` length. */
83
+ systemKeyIdChars: 64,
84
+ /** Exact raw Ed25519 public-key length after base64url encoding. */
85
+ systemPublicKeyChars: 43,
86
+ /** Max `system.tokenIssuers[].proof` length. */
87
+ systemProofChars: 4096,
88
+ /** Max `system.subscriptions` entries. */
89
+ systemSubscriptions: 32,
90
+ /** Max `system.subscriptions[].events` entries. */
91
+ systemSubscriptionEvents: 64,
92
+ /** Max length of a `system.subscriptions[].events` name. */
93
+ systemEventChars: 128,
59
94
  };
60
95
  /** Published JSON Schema URL for `sf.jsonc` ($schema autocomplete). */
61
96
  export const SPACE_CONFIG_SCHEMA_URL = `${serviceOrigin("www", "prod")}/schemas/sf.json`;
62
- // Pages theme tokens: visual values consumed by publish-rendered site pages.
63
- // Presentation only never layout, behavior, or protocol.
64
- // Color grammar accepts hex/rgb(a)/hsl(a)/
65
- // named), categorically rejecting anything that could escape a style context.
97
+ // Pages theme tokens: presentation only, never layout, behavior, or protocol.
98
+ // The color grammar accepts hex, rgb(a), hsl(a), and named CSS colors, and
99
+ // rejects anything that could escape a style context.
66
100
  const PAGES_COLOR_PATTERN = new RegExp([
67
101
  "^(?:",
68
102
  "#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})",
@@ -117,10 +151,7 @@ export const spacePageThemeSchema = z
117
151
  .describe("Theme tokens for Spacefast-authored pages.");
118
152
  // WordPress-compatible `theme.json` is an inference input, not configuration.
119
153
  // Only `settings.color.palette` and `settings.typography.fontFamilies` infer
120
- // Pages tokens; every other
121
- // WP theme.json key is accepted-and-ignored (this is not a full WP_Theme_JSON
122
- // reimplementation, just the safe subset that reaches presentation-only gate
123
- // pages.
154
+ // Pages tokens; every other WP key is accepted and ignored.
124
155
  export const THEME_JSON_FILE = "theme.json";
125
156
  export const spaceBuildSettingsSchema = z
126
157
  .object({
@@ -138,9 +169,8 @@ export const spaceBuildSettingsSchema = z
138
169
  .strict()
139
170
  .describe("Remote build settings used by repository builds.");
140
171
  // Every space gets its own site, so there is nothing to place between: no mode,
141
- // no region knob. `burstable` is the one real provider knob left — whether the
142
- // space's site may burst provider PHP workers. Data location is chosen once, at
143
- // creation, and never changes.
172
+ // no region knob. `burstable` says whether the space's site may burst provider
173
+ // PHP workers. Data location is chosen once, at creation, and never changes.
144
174
  export const spacePlacementConfigSchema = z
145
175
  .object({
146
176
  burstable: z.boolean().optional(),
@@ -354,11 +384,9 @@ function refineDefaultDataSource(config, ctx) {
354
384
  });
355
385
  }
356
386
  }
357
- // Shared SpaceConfig fields (the platform spec "SpaceConfig"): the
358
- // declarative serving config also accepted by `sf.jsonc`. Cloud-only overlay
359
- // fields such as pre-build data sources are added to `spaceConfigSchema` below.
360
- // Meta caps are the spec parser-safety numbers (title 300, description 1000,
361
- // image 2000); plan policy may lower them but never raise them.
387
+ // Shared SpaceConfig fields: the declarative serving config also accepted by
388
+ // `sf.jsonc`. Cloud-only overlay fields such as pre-build data sources are
389
+ // added to `spaceConfigSchema` below.
362
390
  const spaceConfigBaseSchema = z.object({
363
391
  index: z
364
392
  .union([z.string().min(1), z.literal(false)])
@@ -456,13 +484,12 @@ const spaceConfigBaseSchema = z.object({
456
484
  .boolean()
457
485
  .optional()
458
486
  .describe("Accepted serving flag; runtime enforcement ships separately."),
459
- // Intentionally undescribed (hidden, experimental): enables the finalize-time
460
- // build pipeline (the build-pipeline plan). Accepted without
461
- // diagnostics; absent/false keeps today's behavior byte-for-byte.
487
+ // Undescribed on purpose (hidden, experimental): enables the finalize-time
488
+ // build pipeline. Accepted without diagnostics.
462
489
  experimental_gutenberg: z.boolean().optional(),
463
- // Intentionally minimally described (hidden, experimental): static HTML
464
- // snippets, honored only when `experimental_gutenberg` is true. Byte caps are
465
- // enforced by the shared validator (inject_snippet_too_large / inject_invalid).
490
+ // Hidden, experimental: static HTML snippets, honored only when
491
+ // `experimental_gutenberg` is true. Byte caps are enforced by the shared
492
+ // validator (inject_snippet_too_large / inject_invalid).
466
493
  inject: z
467
494
  .object({
468
495
  head: z.array(z.string()).max(SPACE_CONFIG_CAPS.injectSnippets).optional(),
@@ -497,12 +524,10 @@ export function spaceSuperpowersEnabled(config) {
497
524
  const superpowers = config?.superpowers;
498
525
  return superpowers?.enabled !== false && superpowers?.disable_all_injection !== true;
499
526
  }
500
- // The `sf.jsonc` FILE shape (the platform spec "Space
501
- // Configuration Files"): SpaceConfig plus the editor `$schema` pointer and the
502
- // optional `space` link (slug or `spc_` id) resolved by CLI/publish flows.
503
- // Routing rules (`redirects`/`rewrites`/`headers`) are sf.jsonc keys too, but they belong
504
- // to the routing compiler, not to this shape: it resolves serving, they compile
505
- // into the canonical rules and merge behind `_redirects`/`_headers`.
527
+ // The `sf.jsonc` FILE shape: SpaceConfig plus the editor `$schema` pointer and
528
+ // the optional `space` link (slug or `spc_` id). Routing rules
529
+ // (`redirects`/`rewrites`/`headers`) are sf.jsonc keys too, but they belong to
530
+ // the routing compiler and merge behind `_redirects`/`_headers`.
506
531
  const spaceConfigPublicPatternSchema = z
507
532
  .string()
508
533
  .min(1)
@@ -564,10 +589,10 @@ export const spaceConfigFileAccessSchema = z
564
589
  /**
565
590
  * Zero: a transactional app with its own database.
566
591
  *
567
- * Both entries are required because Zero is never inferred. A runtime that owns
568
- * a database must not spring into existence from a directory shape, so the only
569
- * way to get one is to say so — and once said, a server or client that cannot
570
- * be resolved fails the publish rather than degrading to static files.
592
+ * Both entries are required because Zero is never inferred: a runtime that owns
593
+ * a database must not spring into existence from a directory shape. Once
594
+ * declared, a server or client that cannot be resolved fails the publish rather
595
+ * than degrading to static files.
571
596
  */
572
597
  export const spaceRuntimeZeroSchema = z
573
598
  .object({
@@ -588,10 +613,8 @@ export const spaceRuntimeZeroSchema = z
588
613
  * Functions: the worker `sf publish` compiles.
589
614
  *
590
615
  * Every field beyond `kind` is optional because the normal case is detection: a
591
- * project with `handler.ts` or an OpenNext build needs no configuration at all.
592
- * These exist for the layouts detection cannot guess — a worker somewhere
593
- * unusual, or a compatibility date the author wants pinned rather than
594
- * defaulted.
616
+ * project with `handler.ts` or an OpenNext build needs no configuration. These
617
+ * exist for the layouts detection cannot guess.
595
618
  */
596
619
  export const spaceRuntimeFunctionsSchema = z
597
620
  .object({
@@ -605,37 +628,33 @@ export const spaceRuntimeFunctionsSchema = z
605
628
  .boolean()
606
629
  .default(false)
607
630
  .describe("Give the worker `env.DB`, a D1-shaped binding to this space's database. " +
608
- "This capability is declared, not detected. A capability an author did not request is authority they cannot see. Reading it from minified build output is a guess. Defaults to off, so a worker reaches nothing until it says so."),
631
+ "Declared, not detected: a capability an author did not request is authority they cannot see. Defaults to off."),
609
632
  fetch: z
610
633
  .boolean()
611
634
  .optional()
612
635
  .describe("Give the worker `ctx.fetch`, brokered outbound HTTP through the relay. " +
613
- "Declared, not detected, for the same reason as `database`. No schema default, because the right one depends on what was published: a Next build gets egress unless this says false SSR fetches while rendering, so denying it breaks the build rather than narrowing it — while a hand-written worker reaches nothing until it says so."),
636
+ "Declared, not detected, like `database`. There is no schema default: a Next build gets egress unless this says false, because SSR fetches while rendering, while a hand-written worker reaches nothing until it says so."),
614
637
  compatibilityDate: z
615
638
  .string()
616
639
  .regex(/^\d{4}-\d{2}-\d{2}$/)
617
640
  .optional()
618
- .describe("Runtime compatibility date this worker was written against. Pinning it makes rollback honest. Promoting an old version restores the semantics it was built with."),
641
+ .describe("Runtime compatibility date this worker was written against. Pinning it means promoting an old version restores the semantics it was built with."),
619
642
  })
620
643
  .describe("Functions: a worker compiled at publish time.");
621
644
  /**
622
- * The one runtime declaration, discriminated on `kind`.
645
+ * The one runtime declaration, discriminated on `kind`. A version cannot
646
+ * express two runtimes at once.
623
647
  *
624
- * One block, one kind a version cannot express two runtimes at once, so the
625
- * ambiguity never has to be resolved downstream. File-only on purpose: a
626
- * runtime is a fact about the content of a version, so it rolls forward and
627
- * back with the version instead of being set through the API config overlay.
648
+ * File-only on purpose: a runtime is a fact about the content of a version, so
649
+ * it rolls forward and back with the version instead of being set through the
650
+ * API config overlay.
628
651
  */
629
652
  export const spaceRuntimeSchema = z
630
653
  .discriminatedUnion("kind", [spaceRuntimeZeroSchema, spaceRuntimeFunctionsSchema])
631
654
  .describe("Runtime this version's code runs on. Omit it when the space does not run code. Functions is also detected from the published directory when it is not stated.");
632
655
  /**
633
656
  * Scheduled requests: the provider crontab asks this space for these paths on
634
- * these schedules.
635
- *
636
- * File-only for the same reason `runtime` is: what runs on a schedule is a fact
637
- * about the content of a version, so it rolls forward and back with the version
638
- * instead of being set through the API config overlay.
657
+ * these schedules. File-only for the same reason `runtime` is.
639
658
  *
640
659
  * The Rust config compiler is the selection authority for both fields; this
641
660
  * schema exists so an editor and an agent get the same answer before publish.
@@ -704,8 +723,8 @@ function cronFieldIsValid(field, [min, max]) {
704
723
  }
705
724
  /**
706
725
  * The wp.cloud schedule grammar: a named interval, an `Nh`/`Nd`/`Nw` count, or
707
- * a five-field crontab expression. No `@daily` macros and no month/day names
708
- * the provider does not accept them either.
726
+ * a five-field crontab expression. No `@daily` macros and no month/day names.
727
+ * The provider does not accept them either.
709
728
  */
710
729
  export function isSpaceCronSchedule(schedule) {
711
730
  if (SPACE_CRON_NAMED_SCHEDULES.some((named) => named === schedule))
@@ -724,16 +743,12 @@ export function isSpaceCronSchedule(schedule) {
724
743
  }));
725
744
  }
726
745
  /**
727
- * The artifact key for a cron path: lowercase, leading `/` stripped, every run
728
- * of non-alphanumerics collapsed to one `-`, trimmed. Two paths that produce
729
- * one key are rejected, so a key names exactly one schedule.
746
+ * The artifact key for a cron path the shared slug normalizer, so an accented
747
+ * path folds the same way it does everywhere else. Two paths that produce one
748
+ * key are rejected, so a key names exactly one schedule.
730
749
  */
731
750
  export function spaceCronKey(path) {
732
- return path
733
- .replace(/^\/+/, "")
734
- .toLowerCase()
735
- .replace(/[^a-z0-9]+/g, "-")
736
- .replace(/^-+|-+$/g, "");
751
+ return normalizeSlug(path);
737
752
  }
738
753
  /** Generated runtime file the serving engine reads, written only when a version declares a cron. */
739
754
  export const SPACE_CRONS_ARTIFACT_PATH = "__spacefast/crons.json";
@@ -754,9 +769,8 @@ export const spaceCronsSchema = z
754
769
  .array(spaceCronSchema)
755
770
  .max(SPACE_CONFIG_CAPS.crons)
756
771
  .superRefine((entries, context) => {
757
- // Identical paths always slug to one key, so keying on the key alone
758
- // catches both defects: a path written twice, and two paths that slug to
759
- // one key — which would give two schedules one identity downstream.
772
+ // Keying on the slug catches both defects: a path written twice, and two
773
+ // paths that slug to one key.
760
774
  const seenByKey = new Map();
761
775
  entries.forEach((entry, index) => {
762
776
  const key = spaceCronKey(entry.path);
@@ -776,6 +790,146 @@ export const spaceCronsSchema = z
776
790
  });
777
791
  })
778
792
  .describe(`Scheduled requests Spacefast issues against this space's own paths; at most ${SPACE_CONFIG_CAPS.crons} entries.`);
793
+ /**
794
+ * The `system` manifest: the control-plane-only section a tenant's designated
795
+ * system space publishes to declare its partner-facing surface (presentation,
796
+ * white-label hostnames, API origins, trusted token issuers, event
797
+ * subscriptions).
798
+ *
799
+ * No serving behavior derives from it. The control plane freezes it at finalize
800
+ * and reconciles it into materialized state; other spaces' manifests are
801
+ * ignored. File-only, like `runtime` and `crons`: what a partner exposes is a
802
+ * fact about the live version, so it rolls forward and back with the version
803
+ * instead of living in the mutable API overlay.
804
+ *
805
+ * This zod contract is the validation authority: every string is bounded and
806
+ * every URL is https, with no HTML/CSS anywhere. The Rust config crate only
807
+ * recognizes the key and passes the section through verbatim — it never
808
+ * validates it and it never reaches the runtime effective-config lane.
809
+ */
810
+ // `*` is excluded deliberately, not for hygiene: `system.api.allowedOrigins`
811
+ // feeds the CORS allow-list, whose matcher treats `*` as a wildcard. A partner
812
+ // could otherwise publish `https://*` and have the control plane reflect any
813
+ // requesting origin back with credentials.
814
+ const SYSTEM_HTTPS_URL_PATTERN = /^https:\/\/[^\s"'<>\\*]+$/;
815
+ const SYSTEM_HOSTNAME_PATTERN = /^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?)+$/;
816
+ const systemHttpsUrlSchema = z
817
+ .string()
818
+ .trim()
819
+ .min(1)
820
+ .max(SPACE_CONFIG_CAPS.systemUrlChars)
821
+ .regex(SYSTEM_HTTPS_URL_PATTERN, "must be an https:// URL");
822
+ export const systemPresentationSchema = z
823
+ .object({
824
+ name: z.string().trim().min(1).max(SPACE_CONFIG_CAPS.systemNameChars).optional(),
825
+ logo: systemHttpsUrlSchema.optional(),
826
+ supportUrl: systemHttpsUrlSchema.optional(),
827
+ claimOrigin: systemHttpsUrlSchema.optional(),
828
+ accessHandoffOrigin: systemHttpsUrlSchema.optional(),
829
+ problemDocsBaseUrl: systemHttpsUrlSchema.optional(),
830
+ contacts: z
831
+ .record(z.string().trim().min(1).max(SPACE_CONFIG_CAPS.systemContactKeyChars), z.string().trim().min(1).max(SPACE_CONFIG_CAPS.systemContactValueChars))
832
+ .refine((contacts) => Object.keys(contacts).length <= SPACE_CONFIG_CAPS.systemContacts, `at most ${SPACE_CONFIG_CAPS.systemContacts} contacts`)
833
+ .optional()
834
+ .describe("Named contact URLs or addresses shown to claimants and partners."),
835
+ })
836
+ .strict()
837
+ .describe("Partner-facing branding and links for the white-label surface.");
838
+ export const systemHostnamesSchema = z
839
+ .object({
840
+ apex: z
841
+ .string()
842
+ .trim()
843
+ .min(1)
844
+ .max(SPACE_CONFIG_CAPS.systemHostnameChars)
845
+ .regex(SYSTEM_HOSTNAME_PATTERN, "must be a bare hostname (no scheme or path)")
846
+ .optional()
847
+ .describe("Apex hostname for the white-label surface."),
848
+ })
849
+ .strict();
850
+ export const systemApiSchema = z
851
+ .object({
852
+ origin: systemHttpsUrlSchema
853
+ .optional()
854
+ .describe("https origin the partner API is served from."),
855
+ allowedOrigins: z
856
+ .array(systemHttpsUrlSchema)
857
+ .max(SPACE_CONFIG_CAPS.systemApiAllowedOrigins)
858
+ .optional()
859
+ .describe("https origins permitted to call the partner API (CORS)."),
860
+ })
861
+ .strict();
862
+ export const systemTokenIssuerSchema = z
863
+ .object({
864
+ issuer: z
865
+ .string()
866
+ .trim()
867
+ .min(1)
868
+ .max(SPACE_CONFIG_CAPS.systemIssuerChars)
869
+ .describe("Issuer identifier (the iss claim tokens must carry)."),
870
+ keys: z
871
+ .array(identityConnectionPublicKeySchema)
872
+ .min(1)
873
+ .max(SPACE_CONFIG_CAPS.systemIssuerKeys)
874
+ .describe("Public verification keys, addressed by key id."),
875
+ proof: z
876
+ .string()
877
+ .trim()
878
+ .min(1)
879
+ .max(SPACE_CONFIG_CAPS.systemProofChars)
880
+ .optional()
881
+ .describe("Ownership proof that completes the two-publish issuer activation."),
882
+ })
883
+ .strict();
884
+ export const systemSubscriptionSchema = z
885
+ .object({
886
+ url: systemHttpsUrlSchema.describe("https endpoint events are delivered to."),
887
+ events: z
888
+ .array(z.string().trim().min(1).max(SPACE_CONFIG_CAPS.systemEventChars))
889
+ .min(1)
890
+ .max(SPACE_CONFIG_CAPS.systemSubscriptionEvents)
891
+ .describe("Event names delivered to this subscription."),
892
+ })
893
+ .strict();
894
+ export const spaceSystemManifestSchema = z
895
+ .object({
896
+ presentation: systemPresentationSchema.optional(),
897
+ hostnames: systemHostnamesSchema.optional(),
898
+ api: systemApiSchema.optional(),
899
+ tokenIssuers: z
900
+ .array(systemTokenIssuerSchema)
901
+ .max(SPACE_CONFIG_CAPS.systemTokenIssuers)
902
+ .optional()
903
+ .describe("Trusted token issuers registered for the tenant."),
904
+ subscriptions: z
905
+ .array(systemSubscriptionSchema)
906
+ .max(SPACE_CONFIG_CAPS.systemSubscriptions)
907
+ .optional()
908
+ .describe("Event subscriptions (webhooks) the tenant declares."),
909
+ plans: planCatalogSchema
910
+ .optional()
911
+ .describe("Per-tenant plan catalog: plan name → { features, quotas.spaces, quotaPolicy }. Feature keys validated against the live vocabulary; plan names are arbitrary."),
912
+ defaultPlan: defaultPlanNameSchema
913
+ .optional()
914
+ .describe("Plan unassigned principals fall back to. Must be a key in `plans`."),
915
+ })
916
+ .strict()
917
+ .superRefine((manifest, ctx) => {
918
+ if (manifest.defaultPlan === undefined) {
919
+ return;
920
+ }
921
+ // A defaultPlan is only meaningful against a declared catalog: it must name a
922
+ // plan the same manifest declares, or gate resolution would fall back to a
923
+ // plan that does not exist.
924
+ if (manifest.plans === undefined || !(manifest.defaultPlan in manifest.plans)) {
925
+ ctx.addIssue({
926
+ code: z.ZodIssueCode.custom,
927
+ path: ["defaultPlan"],
928
+ message: "defaultPlan must be one of the plan names declared in `plans`.",
929
+ });
930
+ }
931
+ })
932
+ .describe("Control-plane manifest for a tenant's designated system space. Parsed and reconciled by the control plane; ignored by other spaces.");
779
933
  export const spaceConfigFileSchema = spaceConfigBaseSchema.extend({
780
934
  $schema: z
781
935
  .string()
@@ -798,6 +952,9 @@ export const spaceConfigFileSchema = spaceConfigBaseSchema.extend({
798
952
  access: spaceConfigFileAccessSchema.optional(),
799
953
  runtime: spaceRuntimeSchema.optional(),
800
954
  crons: spaceCronsSchema.optional(),
955
+ system: spaceSystemManifestSchema
956
+ .optional()
957
+ .describe("Control-plane system-space manifest. Honored only for a tenant's designated system space; other spaces' declarations are ignored."),
801
958
  });
802
959
  /**
803
960
  * The published JSON Schema artifact for `sf.jsonc`, generated from the
@@ -810,11 +967,10 @@ export function spaceConfigJsonSchema() {
810
967
  $id: SPACE_CONFIG_SCHEMA_URL,
811
968
  title: "Spacefast space configuration (sf.jsonc)",
812
969
  });
813
- // `redirects`, `rewrites` and `headers` are real sf.jsonc keys, owned by the routing
814
- // compiler rather than by the serving shape above which is why they are
815
- // described here instead of in the zod schema that resolves serving. An editor
816
- // reading this file still has to know they exist, or the documented routing
817
- // examples read as unknown keys.
970
+ // `redirects`, `rewrites` and `headers` are real sf.jsonc keys owned by the
971
+ // routing compiler, not by the serving shape above, so they are described
972
+ // here. Without them an editor reads the documented routing examples as
973
+ // unknown keys.
818
974
  return {
819
975
  ...schema,
820
976
  properties: {
@@ -824,11 +980,11 @@ export function spaceConfigJsonSchema() {
824
980
  };
825
981
  }
826
982
  // The `!` and `name=:capture` of a `_redirects` line, shared by both rule
827
- // sections the same shapes `config::strict::public_json_schema` publishes.
983
+ // sections and by `config::strict::public_json_schema`.
828
984
  const SPACE_CONFIG_ROUTING_FORCE_SCHEMA = {
829
985
  type: "boolean",
830
986
  default: false,
831
- description: "Answer even when the request path resolves to a committed file the ! of a _redirects rule.",
987
+ description: "Answer even when the request path resolves to a committed file, the ! of a _redirects rule.",
832
988
  };
833
989
  const SPACE_CONFIG_ROUTING_QUERY_SCHEMA = {
834
990
  type: "object",
@@ -890,7 +1046,7 @@ const SPACE_CONFIG_ROUTING_SCHEMA_PROPERTIES = {
890
1046
  notFound: {
891
1047
  type: "boolean",
892
1048
  default: false,
893
- description: "Serve the destination with status 404 the 404 of a _redirects rule. The destination must be a path.",
1049
+ description: "Serve the destination with status 404, the 404 of a _redirects rule. The destination must be a path.",
894
1050
  },
895
1051
  },
896
1052
  required: ["source", "destination"],
@@ -924,7 +1080,7 @@ const SPACE_CONFIG_ROUTING_SCHEMA_PROPERTIES = {
924
1080
  key: { type: "string", minLength: 1 },
925
1081
  remove: {
926
1082
  const: true,
927
- description: "Remove this header instead of setting it the !Name line of a _headers block.",
1083
+ description: "Remove this header instead of setting it, the !Name line of a _headers block.",
928
1084
  },
929
1085
  },
930
1086
  required: ["key", "remove"],
@@ -940,16 +1096,15 @@ const SPACE_CONFIG_ROUTING_SCHEMA_PROPERTIES = {
940
1096
  },
941
1097
  };
942
1098
  /*
943
- * Hidden-feature discipline (the build-pipeline plan): the
944
- * `experimental_gutenberg` flag and its `inject` companion are ACCEPTED by the
945
- * parser but never published the bare key names alone would document the
946
- * feature to every editor/agent reading a schema artifact. Every generator
947
- * that derives a public artifact from the SpaceConfig zod shape (the
948
- * sf.jsonc JSON Schema, the www publish-spec, the SDK OpenAPI documents)
949
- * must run it through this stripper. The published schemas set no
950
- * additionalProperties constraint, so configs that use the hidden keys still
951
- * validate cleanly. `inject` is removed only when it carries the SpaceConfig
952
- * static-placement shape so unrelated properties of the same name survive.
1099
+ * `experimental_gutenberg` and its `inject` companion are ACCEPTED by the parser
1100
+ * but never published: the bare key names alone would document the feature to
1101
+ * every editor and agent reading a schema artifact. Every generator that derives
1102
+ * a public artifact from the SpaceConfig zod shape (the sf.jsonc JSON Schema,
1103
+ * the www publish-spec, the SDK OpenAPI documents) must run it through this
1104
+ * stripper. The published schemas set no additionalProperties constraint, so
1105
+ * configs using the hidden keys still validate. `inject` is removed only when it
1106
+ * carries the SpaceConfig static-placement shape, so unrelated properties of the
1107
+ * same name survive.
953
1108
  */
954
1109
  export function stripHiddenSpaceConfigKeys(schema) {
955
1110
  if (Array.isArray(schema)) {