@spacefast/common 0.0.24 → 0.2.1

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 (320) hide show
  1. package/brand-assets/LICENSE-Haskoy.txt +93 -0
  2. package/brand-assets/haskoy-latin-variable.woff2 +0 -0
  3. package/brand-assets/spacefast-favicon.svg +4 -4
  4. package/brand-assets/spacefast-sf-full-bleed.svg +3 -3
  5. package/brand-assets/spacefast-wordmark.svg +2 -4
  6. package/dist/agents/connect-targets.d.ts +6 -146
  7. package/dist/agents/connect-targets.js +63 -295
  8. package/dist/agents/private-key-oauth.d.ts +31 -2
  9. package/dist/agents/private-key-oauth.js +166 -92
  10. package/dist/agents/registry/core.d.ts +292 -0
  11. package/dist/agents/registry/core.js +1388 -0
  12. package/dist/agents/registry/deeplink-probes.d.ts +23 -0
  13. package/dist/agents/registry/deeplink-probes.js +18 -0
  14. package/dist/agents/registry/node.d.ts +56 -0
  15. package/dist/agents/registry/node.js +339 -0
  16. package/dist/brand-assets-build.js +3 -6
  17. package/dist/brand-assets.d.ts +5 -15
  18. package/dist/brand-assets.js +12 -14
  19. package/dist/brand.d.ts +17 -0
  20. package/dist/brand.js +24 -4
  21. package/dist/config/domains.d.ts +79 -12
  22. package/dist/config/domains.js +128 -29
  23. package/dist/config/index.js +1 -2
  24. package/dist/contracts/abuse.js +9 -24
  25. package/dist/contracts/access-profiles.d.ts +86 -0
  26. package/dist/contracts/access-profiles.js +89 -0
  27. package/dist/contracts/access.d.ts +24 -30
  28. package/dist/contracts/access.js +33 -64
  29. package/dist/contracts/activity.d.ts +18 -1
  30. package/dist/contracts/activity.js +72 -26
  31. package/dist/contracts/analytics.js +8 -10
  32. package/dist/contracts/api-keys.d.ts +77 -52
  33. package/dist/contracts/api-keys.js +44 -24
  34. package/dist/contracts/application-journal.d.ts +216 -0
  35. package/dist/contracts/application-journal.js +167 -0
  36. package/dist/contracts/auth.d.ts +90 -17
  37. package/dist/contracts/auth.js +86 -17
  38. package/dist/contracts/beta.d.ts +9 -4
  39. package/dist/contracts/beta.js +20 -16
  40. package/dist/contracts/billing.d.ts +2 -1
  41. package/dist/contracts/billing.js +37 -11
  42. package/dist/contracts/bootstrap.d.ts +791 -0
  43. package/dist/contracts/bootstrap.js +51 -0
  44. package/dist/contracts/builds.d.ts +209 -18
  45. package/dist/contracts/builds.js +93 -27
  46. package/dist/contracts/channels.d.ts +43 -0
  47. package/dist/contracts/channels.js +25 -9
  48. package/dist/contracts/cli.d.ts +7 -0
  49. package/dist/contracts/cli.js +6 -0
  50. package/dist/contracts/collab-public.d.ts +1 -1
  51. package/dist/contracts/collab-public.js +5 -8
  52. package/dist/contracts/comments.d.ts +44 -34
  53. package/dist/contracts/comments.js +107 -77
  54. package/dist/contracts/commerce.d.ts +165 -0
  55. package/dist/contracts/commerce.js +146 -0
  56. package/dist/contracts/common.d.ts +3 -3
  57. package/dist/contracts/common.js +20 -31
  58. package/dist/contracts/content-contract-verification.d.ts +521 -0
  59. package/dist/contracts/content-contract-verification.js +320 -0
  60. package/dist/contracts/content-platform-fixture.d.ts +1278 -0
  61. package/dist/contracts/content-platform-fixture.js +44 -0
  62. package/dist/contracts/content-program.d.ts +994 -0
  63. package/dist/contracts/content-program.js +658 -0
  64. package/dist/contracts/content-sync.d.ts +290 -0
  65. package/dist/contracts/content-sync.js +167 -0
  66. package/dist/contracts/content.d.ts +432 -0
  67. package/dist/contracts/content.js +303 -0
  68. package/dist/contracts/continuation.d.ts +17 -1
  69. package/dist/contracts/continuation.js +23 -23
  70. package/dist/contracts/countries.js +3 -4
  71. package/dist/contracts/crons.d.ts +52 -0
  72. package/dist/contracts/crons.js +60 -0
  73. package/dist/contracts/dashboard-prefs.d.ts +56 -0
  74. package/dist/contracts/dashboard-prefs.js +51 -0
  75. package/dist/contracts/device-auth.d.ts +234 -37
  76. package/dist/contracts/device-auth.js +267 -53
  77. package/dist/contracts/docs.d.ts +1 -5
  78. package/dist/contracts/docs.js +7 -15
  79. package/dist/contracts/domains.d.ts +501 -93
  80. package/dist/contracts/domains.js +193 -55
  81. package/dist/contracts/email-preferences.d.ts +3 -3
  82. package/dist/contracts/email-preferences.js +6 -7
  83. package/dist/contracts/enums.d.ts +27 -26
  84. package/dist/contracts/enums.js +68 -61
  85. package/dist/contracts/error-code-meta.d.ts +283 -7
  86. package/dist/contracts/error-code-meta.js +97 -5
  87. package/dist/contracts/error-codes.d.ts +5 -5
  88. package/dist/contracts/error-codes.js +82 -17
  89. package/dist/contracts/events.d.ts +100 -20
  90. package/dist/contracts/events.js +107 -20
  91. package/dist/contracts/execution.d.ts +48 -64
  92. package/dist/contracts/execution.js +52 -62
  93. package/dist/contracts/feature-lifecycle.d.ts +73 -27
  94. package/dist/contracts/feature-lifecycle.js +86 -26
  95. package/dist/contracts/features.d.ts +68 -19
  96. package/dist/contracts/features.js +42 -41
  97. package/dist/contracts/fixtures/content-platform-v1.json +1108 -0
  98. package/dist/contracts/frame-session.d.ts +192 -0
  99. package/dist/contracts/frame-session.js +164 -0
  100. package/dist/contracts/functions.d.ts +338 -164
  101. package/dist/contracts/functions.js +367 -198
  102. package/dist/contracts/git.d.ts +27 -33
  103. package/dist/contracts/git.js +10 -11
  104. package/dist/contracts/grant-copy.d.ts +43 -0
  105. package/dist/contracts/grant-copy.js +44 -0
  106. package/dist/contracts/grants.d.ts +62 -54
  107. package/dist/contracts/grants.js +124 -23
  108. package/dist/contracts/ids.d.ts +4 -1
  109. package/dist/contracts/ids.js +6 -3
  110. package/dist/contracts/internal.d.ts +8 -18
  111. package/dist/contracts/internal.js +13 -14
  112. package/dist/contracts/mcp.d.ts +28 -0
  113. package/dist/contracts/mcp.js +28 -0
  114. package/dist/contracts/me.d.ts +6 -1
  115. package/dist/contracts/me.js +12 -6
  116. package/dist/contracts/notifications.d.ts +27 -29
  117. package/dist/contracts/notifications.js +9 -4
  118. package/dist/contracts/oauth-resources.d.ts +112 -10
  119. package/dist/contracts/oauth-resources.js +116 -11
  120. package/dist/contracts/oauth-scope-actions.d.ts +90 -0
  121. package/dist/contracts/oauth-scope-actions.js +126 -0
  122. package/dist/contracts/operations.d.ts +27 -4
  123. package/dist/contracts/operations.js +12 -6
  124. package/dist/contracts/pages.d.ts +31 -7
  125. package/dist/contracts/pages.js +22 -5
  126. package/dist/contracts/partner-notifications.d.ts +3 -0
  127. package/dist/contracts/partner-notifications.js +65 -0
  128. package/dist/contracts/{platform.d.ts → partner.d.ts} +29 -42
  129. package/dist/contracts/{platform.js → partner.js} +27 -40
  130. package/dist/contracts/plan-policy.js +1 -1
  131. package/dist/contracts/principal-assertion.d.ts +43 -0
  132. package/dist/contracts/principal-assertion.js +67 -0
  133. package/dist/contracts/principals.d.ts +73 -0
  134. package/dist/contracts/principals.js +59 -0
  135. package/dist/contracts/privacy.d.ts +11 -0
  136. package/dist/contracts/privacy.js +17 -0
  137. package/dist/contracts/problem-document.js +3 -4
  138. package/dist/contracts/publish-archive.d.ts +269 -161
  139. package/dist/contracts/publish-archive.js +11 -1
  140. package/dist/contracts/push-new.d.ts +8 -8
  141. package/dist/contracts/quotas.js +5 -5
  142. package/dist/contracts/realtime.d.ts +52 -0
  143. package/dist/contracts/realtime.js +54 -0
  144. package/dist/contracts/repository-connections.d.ts +44 -31
  145. package/dist/contracts/repository-connections.js +17 -5
  146. package/dist/contracts/resources.d.ts +105 -14
  147. package/dist/contracts/resources.js +150 -26
  148. package/dist/contracts/route-inventory.d.ts +358 -0
  149. package/dist/contracts/route-inventory.js +141 -0
  150. package/dist/contracts/runtime-api.d.ts +206 -82
  151. package/dist/contracts/runtime-api.js +131 -70
  152. package/dist/contracts/runtime-app.d.ts +13 -23
  153. package/dist/contracts/runtime-app.js +39 -24
  154. package/dist/contracts/runtime-components.d.ts +143 -0
  155. package/dist/contracts/runtime-components.js +199 -0
  156. package/dist/contracts/runtime-db.d.ts +49 -23
  157. package/dist/contracts/runtime-db.js +87 -22
  158. package/dist/contracts/runtime-purge.d.ts +8 -0
  159. package/dist/contracts/runtime-purge.js +5 -0
  160. package/dist/contracts/runtime-services.d.ts +43 -75
  161. package/dist/contracts/runtime-services.js +29 -49
  162. package/dist/contracts/runtime-storage.d.ts +15 -14
  163. package/dist/contracts/runtime-storage.js +30 -14
  164. package/dist/contracts/sf-config-v1.d.ts +48 -14
  165. package/dist/contracts/slugs.js +13 -4
  166. package/dist/contracts/space-config.d.ts +283 -19
  167. package/dist/contracts/space-config.js +430 -80
  168. package/dist/contracts/spaces.d.ts +376 -290
  169. package/dist/contracts/spaces.js +200 -135
  170. package/dist/contracts/superadmin-activity.d.ts +3 -43
  171. package/dist/contracts/superadmin-activity.js +6 -30
  172. package/dist/contracts/superadmin-emails.d.ts +1 -0
  173. package/dist/contracts/superadmin-emails.js +17 -1
  174. package/dist/contracts/superadmin-runtime.d.ts +199 -0
  175. package/dist/contracts/superadmin-runtime.js +141 -0
  176. package/dist/contracts/superadmin-search.d.ts +22 -2
  177. package/dist/contracts/superadmin-search.js +14 -6
  178. package/dist/contracts/superadmin-spaces.d.ts +438 -189
  179. package/dist/contracts/superadmin-spaces.js +131 -25
  180. package/dist/contracts/superadmin-teams.d.ts +5 -2
  181. package/dist/contracts/superadmin-teams.js +1 -2
  182. package/dist/contracts/superadmin-tenants.d.ts +627 -12
  183. package/dist/contracts/superadmin-tenants.js +32 -13
  184. package/dist/contracts/superadmin.d.ts +232 -37
  185. package/dist/contracts/superadmin.js +106 -22
  186. package/dist/contracts/tags.d.ts +85 -58
  187. package/dist/contracts/tags.js +47 -37
  188. package/dist/contracts/teams.d.ts +86 -26
  189. package/dist/contracts/teams.js +90 -31
  190. package/dist/contracts/tenants.d.ts +135 -0
  191. package/dist/contracts/tenants.js +120 -0
  192. package/dist/contracts/test-triggers.d.ts +70 -0
  193. package/dist/contracts/test-triggers.js +116 -0
  194. package/dist/contracts/theme-json.js +3 -8
  195. package/dist/contracts/transfers.d.ts +1 -0
  196. package/dist/contracts/transfers.js +3 -2
  197. package/dist/contracts/usage.d.ts +209 -0
  198. package/dist/contracts/usage.js +124 -12
  199. package/dist/contracts/variables.d.ts +2 -2
  200. package/dist/contracts/variables.js +9 -13
  201. package/dist/contracts/webhooks.d.ts +13 -5
  202. package/dist/contracts/webhooks.js +3 -1
  203. package/dist/contracts/zero.d.ts +72 -81
  204. package/dist/contracts/zero.js +80 -78
  205. package/dist/dashboard-paths/index.d.ts +24 -21
  206. package/dist/dashboard-paths/index.js +35 -47
  207. package/dist/dashboard-paths/route-reservations.generated.d.ts +2 -0
  208. package/dist/dashboard-paths/route-reservations.generated.js +36 -0
  209. package/dist/docs/agent-arrival.d.ts +92 -0
  210. package/dist/docs/agent-arrival.js +227 -0
  211. package/dist/docs/agent-output-policy.d.ts +6 -0
  212. package/dist/docs/agent-output-policy.js +22 -0
  213. package/dist/docs/agent-prose.d.ts +12 -18
  214. package/dist/docs/agent-prose.js +73 -51
  215. package/dist/docs/agent-setup.d.ts +72 -41
  216. package/dist/docs/agent-setup.js +339 -436
  217. package/dist/docs/catalog.d.ts +153 -95
  218. package/dist/docs/catalog.js +163 -48
  219. package/dist/docs/error-docs.d.ts +2098 -1
  220. package/dist/docs/error-docs.js +421 -144
  221. package/dist/docs/index-build.d.ts +0 -1
  222. package/dist/docs/index-build.js +2 -3
  223. package/dist/docs/page-context-prompt.d.ts +77 -0
  224. package/dist/docs/page-context-prompt.js +131 -0
  225. package/dist/docs/reference-urls.d.ts +46 -0
  226. package/dist/docs/reference-urls.js +79 -0
  227. package/dist/docs/search.d.ts +6 -8
  228. package/dist/docs/search.js +10 -13
  229. package/dist/docs/skill-distribution.d.ts +4 -1
  230. package/dist/docs/skill-distribution.js +10 -5
  231. package/dist/docs/skills.d.ts +120 -120
  232. package/dist/docs/skills.js +121 -73
  233. package/dist/docs/start-prompts.d.ts +45 -0
  234. package/dist/docs/start-prompts.js +62 -0
  235. package/dist/domain-exploration.js +9 -13
  236. package/dist/og-template.d.ts +56 -0
  237. package/dist/og-template.js +56 -0
  238. package/dist/slug-policy/index.js +5 -11
  239. package/dist/test-helpers/fetch-stub.js +1 -0
  240. package/dist/utils/browser-credential.d.ts +13 -6
  241. package/dist/utils/browser-credential.js +14 -7
  242. package/dist/utils/build-settings.d.ts +21 -1
  243. package/dist/utils/build-settings.js +133 -15
  244. package/dist/utils/canonical-json.d.ts +3 -5
  245. package/dist/utils/canonical-json.js +4 -5
  246. package/dist/utils/cast-transport.d.ts +5 -17
  247. package/dist/utils/cast-transport.js +6 -19
  248. package/dist/utils/claim-token.js +1 -2
  249. package/dist/utils/comment-avatars.js +4 -6
  250. package/dist/utils/concurrency.js +3 -3
  251. package/dist/utils/content-type.d.ts +7 -6
  252. package/dist/utils/content-type.js +73 -51
  253. package/dist/utils/credential-policy.d.ts +50 -6
  254. package/dist/utils/credential-policy.js +126 -59
  255. package/dist/utils/dns-instructions.js +9 -9
  256. package/dist/utils/egress-policy.fixtures.json +1 -1
  257. package/dist/utils/error-code.js +1 -0
  258. package/dist/utils/generate-space-name.d.ts +3 -8
  259. package/dist/utils/generate-space-name.js +3 -8
  260. package/dist/utils/grant-decision.fixtures.json +2 -2
  261. package/dist/utils/grants.d.ts +0 -1
  262. package/dist/utils/grants.js +7 -8
  263. package/dist/utils/gravatar.d.ts +2 -4
  264. package/dist/utils/gravatar.js +6 -12
  265. package/dist/utils/id-hints.js +14 -23
  266. package/dist/utils/idempotency.d.ts +3 -3
  267. package/dist/utils/idempotency.js +6 -7
  268. package/dist/utils/local-space-state.d.ts +23 -26
  269. package/dist/utils/local-space-state.js +46 -46
  270. package/dist/utils/oauth-signed-query.d.ts +3 -5
  271. package/dist/utils/oauth-signed-query.js +6 -9
  272. package/dist/utils/one-shot-replay.d.ts +7 -6
  273. package/dist/utils/one-shot-replay.js +3 -5
  274. package/dist/utils/page-colors.d.ts +15 -19
  275. package/dist/utils/page-colors.js +23 -45
  276. package/dist/utils/page-fonts.d.ts +1 -1
  277. package/dist/utils/page-fonts.js +8 -20
  278. package/dist/utils/page-preview.d.ts +0 -1
  279. package/dist/utils/page-preview.js +0 -1
  280. package/dist/utils/pages.d.ts +33 -3
  281. package/dist/utils/pages.js +83 -30
  282. package/dist/utils/privacy-regions.d.ts +19 -0
  283. package/dist/utils/privacy-regions.js +91 -0
  284. package/dist/utils/publish-form-data.d.ts +4 -5
  285. package/dist/utils/publish-form-data.js +2 -3
  286. package/dist/utils/publish-policy.d.ts +11 -17
  287. package/dist/utils/publish-policy.fixtures.json +11 -5
  288. package/dist/utils/publish-policy.js +65 -110
  289. package/dist/utils/query-client.d.ts +2 -0
  290. package/dist/utils/query-client.js +10 -1
  291. package/dist/utils/runtime-paths.d.ts +4 -4
  292. package/dist/utils/runtime-paths.js +6 -8
  293. package/dist/utils/runtime-upload.d.ts +9 -0
  294. package/dist/utils/runtime-upload.js +12 -0
  295. package/dist/utils/secure-local-file.d.ts +3 -3
  296. package/dist/utils/secure-local-file.js +23 -40
  297. package/dist/utils/space-config.d.ts +12 -15
  298. package/dist/utils/space-config.js +13 -16
  299. package/dist/utils/static-runtime-policy.d.ts +10 -7
  300. package/dist/utils/static-runtime-policy.fixtures.json +38 -41
  301. package/dist/utils/static-runtime-policy.generated.d.ts +16 -0
  302. package/dist/utils/static-runtime-policy.generated.js +70 -0
  303. package/dist/utils/static-runtime-policy.js +31 -132
  304. package/dist/utils/storage-policy.js +1 -2
  305. package/dist/utils/upload-session.d.ts +4 -1
  306. package/dist/utils/upload-session.js +41 -19
  307. package/dist/utils/version-path.js +11 -19
  308. package/dist/utils/wpcom-auth-redirects.d.ts +5 -14
  309. package/dist/utils/wpcom-auth-redirects.js +1 -4
  310. package/dist/vocabulary.d.ts +13 -13
  311. package/dist/vocabulary.js +52 -27
  312. package/package.json +15 -18
  313. package/dist/agents/client-registry.d.ts +0 -22
  314. package/dist/agents/client-registry.js +0 -41
  315. package/dist/docs/agent-handoff-document.d.ts +0 -15
  316. package/dist/docs/agent-handoff-document.js +0 -180
  317. package/dist/docs/agent-solutions.d.ts +0 -110
  318. package/dist/docs/agent-solutions.js +0 -183
  319. package/dist/utils/query-keys.d.ts +0 -84
  320. package/dist/utils/query-keys.js +0 -108
@@ -1,38 +1,28 @@
1
1
  import { z } from "zod";
2
2
  /**
3
3
  * The platform execution layer: everything true of running tenant code on
4
- * Spacefast regardless of which product is running it.
4
+ * Spacefast, regardless of which product runs it.
5
5
  *
6
- * Two products sit on top of this file, and they are genuinely different
7
- * things rather than two configurations of one thing:
8
- *
9
- * - **Zero** (`./zero.js`) runs capsules — schema, queries, mutations and
10
- * endpoints that share one parent-owned transaction — in the native runner
11
- * on a dedicated wp.cloud site, next to that site's MySQL.
6
+ * - **Zero** (`./zero.js`) runs capsules in the native runner on a dedicated
7
+ * wp.cloud site, next to that site's MySQL. A capsule is a schema, queries,
8
+ * mutations and endpoints sharing one parent-owned transaction.
12
9
  * - **Functions** (`./functions.js`) runs workers on Cloudflare Workers for
13
- * Platforms, carrying npm and framework output that we could never sandbox
14
- * as well ourselves.
10
+ * Platforms, carrying npm and framework output we could not sandbox as well
11
+ * ourselves.
15
12
  *
16
- * The only surface both can host is an endpoint that touches neither the
17
- * database nor the caller's identity see `endpointIsPortable`. That is the
18
- * portable seam, and it is deliberately narrow: a capsule handler's semantics
19
- * depend on the transaction wrapped around it, which does not exist on an
20
- * isolate a continent away from the database.
13
+ * The only surface both can host is an endpoint touching neither the database,
14
+ * the caller's identity, nor realtime. See `endpointIsPortable`.
21
15
  *
22
- * Neither is a "kind" a space declares. Every space owns a site, so what runs
23
- * is a routing decision derived from what the published tree carries: static
24
- * files, a worker, a capsule, or any mix of the three in one publish. There is
25
- * no enum here to disagree with the tree.
16
+ * Neither is a "kind" a space declares. What runs is a routing decision derived
17
+ * from what the published tree carries, so there is no enum here to disagree
18
+ * with the tree.
26
19
  */
27
20
  /**
28
- * How a live runtime delivers realtime invalidations.
29
- *
30
- * One vocabulary end to end: the finalize payload, the client config a serving
31
- * runtime hands the browser, and every API response all name the transport
32
- * with these three values. `central` is the hosted relay, `cast` is the
33
- * collaboration service, and `local` is a dev machine serving its own socket —
34
- * a distinction a customer can act on, unlike the component names the transports
35
- * used to be called after.
21
+ * How a live runtime delivers realtime invalidations. One vocabulary end to
22
+ * end: the finalize payload, the client config handed to the browser, and every
23
+ * API response name the transport with these three values. `central` is the
24
+ * hosted relay, `cast` is the collaboration service, `local` is a dev machine
25
+ * serving its own socket.
36
26
  */
37
27
  export const RUNTIME_REALTIME_MODES = ["central", "cast", "local"];
38
28
  export const runtimeRealtimeModeSchema = z.enum(RUNTIME_REALTIME_MODES);
@@ -57,13 +47,19 @@ export const SERVER_ENV_FILES = [SERVER_ENV_FILE, LAKEBED_SERVER_ENV_FILE];
57
47
  export const EXECUTION_ENV_RESERVED_PREFIXES = ["SPACEFAST_", "ZERO_"];
58
48
  /** Paths the platform owns on every space, whatever the product. */
59
49
  export const PLATFORM_ROUTE_PREFIX = "/__spacefast";
50
+ /** Runtime-owned files that travel inside a version but are never tenant files. */
51
+ export function runtimeInternalArtifactPath(path) {
52
+ const foldedPlatformPath = path.toLowerCase();
53
+ return (path === "zero" ||
54
+ path.startsWith("zero/") ||
55
+ foldedPlatformPath === "__spacefast" ||
56
+ foldedPlatformPath.startsWith("__spacefast/"));
57
+ }
60
58
  /**
61
- * First path segments the platform claims. Matched as segment prefixes rather
62
- * than whole segments because the runtime already reserves the whole family —
63
- * `/__stattic_probe` is a live serving path, and `upload-policy.php` refuses
64
- * any first segment starting with either of these. Encoding it the same way
65
- * here keeps a capsule or worker from declaring a route the origin would
66
- * intercept before it ever reached them.
59
+ * First path segments the platform claims. Matched as segment prefixes, not
60
+ * whole segments: `/__stattic_probe` is a live serving path, and
61
+ * `upload-policy.php` refuses any first segment starting with one of these. A
62
+ * capsule or worker must not declare a route the origin would intercept first.
67
63
  */
68
64
  export const PLATFORM_RESERVED_ROUTE_SEGMENT_PREFIXES = [
69
65
  "__spacefast",
@@ -116,11 +112,11 @@ function hasNoAsciiControlCharacters(value) {
116
112
  return true;
117
113
  }
118
114
  /**
119
- * Builds the route-path schema for a product. Structural rules — normalization,
120
- * traversal, wildcards, the platform's own prefixes are identical everywhere
121
- * and live here. Each product passes the extra paths and prefixes its own app
122
- * shell claims, because those differ: Zero's client router owns `/auth/*`,
123
- * a Functions worker owns nothing beyond what the platform reserves.
115
+ * Builds the route-path schema for a product. The structural rules are
116
+ * identical everywhere and live here: normalization, traversal, wildcards, and
117
+ * the platform's own prefixes. Each product passes the extra paths and prefixes
118
+ * its own app shell claims, because those differ: Zero's client router owns
119
+ * `/auth/*`, a Functions worker owns nothing beyond what the platform reserves.
124
120
  */
125
121
  export function appRoutePathSchema(options) {
126
122
  const reservedPaths = options.reservedPaths ?? [];
@@ -145,9 +141,8 @@ export function appRoutePathSchema(options) {
145
141
  !path.includes("?") &&
146
142
  !path.includes("#") &&
147
143
  !path.includes("%") &&
148
- // The root is the one path allowed to end in a slash. Zero reserves it
149
- // for its app shell anyway, but a Functions worker serving a framework
150
- // app needs to claim "/" as its index route.
144
+ // The root is the one path allowed to end in a slash: a Functions
145
+ // worker serving a framework app claims "/" as its index route.
151
146
  (path === "/" || !path.endsWith("/")) &&
152
147
  path
153
148
  .split("/")
@@ -190,14 +185,14 @@ export const executionCapabilitiesSchema = z
190
185
  gravatar: z.boolean().default(false),
191
186
  spam: z.boolean().default(false),
192
187
  email: z.boolean().default(false),
188
+ content: z.boolean().default(false),
193
189
  })
194
190
  .partial()
195
191
  .default({});
196
192
  /**
197
193
  * The order every surface renders a capability list in. Fixed rather than
198
194
  * derived from a response body, so two spaces never list their capabilities
199
- * differently because JSON came back reshuffled — and declared here, beside the
200
- * schema, so adding a capability cannot leave a renderer silently omitting it.
195
+ * differently because JSON came back reshuffled.
201
196
  */
202
197
  export const EXECUTION_CAPABILITY_ORDER = [
203
198
  "db",
@@ -209,32 +204,28 @@ export const EXECUTION_CAPABILITY_ORDER = [
209
204
  "gravatar",
210
205
  "spam",
211
206
  "email",
207
+ "content",
212
208
  ];
213
209
  // A capability added to executionCapabilitiesSchema must also be added to the order above.
214
210
  true;
215
211
  /**
216
- * The portable seam, stated as one predicate.
217
- *
218
- * `db` and `auth` are the two capabilities that bind a handler to the local
219
- * tier. `db` because Zero's store guarantees every handler runs inside one
220
- * parent-owned transaction, which an isolate reaching the database over a
221
- * relay cannot offer. `auth` because capsule identity is resolved against that
222
- * same transaction's view. Everything else — fetch, env, realtime, logging, and
223
- * the three platform services — is brokered identically on both tiers and does
224
- * not constrain placement.
212
+ * The portable seam. `db`, `auth` and `realtime` bind a handler to the local
213
+ * tier: `db` because Zero guarantees one parent-owned transaction that an
214
+ * isolate over a relay cannot offer, `auth` because capsule identity resolves
215
+ * against that transaction's view, `realtime` because the Functions grant
216
+ * vocabulary has no counterpart for invalidations. Everything else is brokered
217
+ * identically on both tiers.
225
218
  *
226
- * `email` is the one worth stating explicitly, because it looks like it should
227
- * bind: a Zero mutation's send is atomic with its database writes, and a
228
- * Function's is not. That is a difference in the *guarantee* either tier can
229
- * offer, not in what the handler is allowed to reach, and placement follows
230
- * what code reaches. An author who needs that atomicity writes a capsule.
219
+ * `email` looks like it should bind but does not: a Zero mutation's send is
220
+ * atomic with its writes and a Function's is not, which is a difference in
221
+ * guarantee, not in what the handler reaches. An author who needs that
222
+ * atomicity writes a capsule.
231
223
  *
232
- * Nothing here decides placement automatically: the product a version deploys
233
- * to is a property of what its author wrote, and this predicate only reports
234
- * whether the code could also have run on the other tier.
224
+ * This predicate reports only whether code could also have run on the other
225
+ * tier. It does not decide placement.
235
226
  */
236
227
  export function endpointIsPortable(capabilities) {
237
- return capabilities.db !== true && capabilities.auth !== true;
228
+ return capabilities.db !== true && capabilities.auth !== true && capabilities.realtime !== true;
238
229
  }
239
230
  /**
240
231
  * A source-carrying handler, before it is compiled to whichever tier will run
@@ -304,7 +295,6 @@ export function executionStaticFileSchema(options) {
304
295
  }
305
296
  /**
306
297
  * Whether a version's execution surface may be read by anyone or only by the
307
- * space's own members. Both products expose an inspect route; the policy is
308
- * the same question on each.
298
+ * space's own members. Both products expose an inspect route.
309
299
  */
310
300
  export const executionInspectPolicySchema = z.enum(["private", "public"]);
@@ -7,7 +7,7 @@ type RuntimeFeaturePolicy = {
7
7
  readonly enabledForA8c: boolean;
8
8
  readonly planDefaults: Readonly<Partial<Record<PlanCode, boolean>>>;
9
9
  };
10
- type RuntimeFeatureDefinitionShape<K extends string> = {
10
+ type RuntimeFeatureDefinitionFields<K extends string> = {
11
11
  readonly key: K;
12
12
  readonly name: string;
13
13
  readonly description: string;
@@ -17,7 +17,7 @@ declare const featureEntries: readonly [{
17
17
  readonly cohort: "launch";
18
18
  readonly key: "plans.paid.available";
19
19
  readonly name: "Paid plans available";
20
- readonly description: "Controls whether paid plan upgrade and management surfaces are available.";
20
+ readonly description: "Enables paid plan upgrade and management surfaces.";
21
21
  readonly stage: "internal";
22
22
  readonly surface: false;
23
23
  readonly defaultEnabled: false;
@@ -50,7 +50,7 @@ declare const featureEntries: readonly [{
50
50
  };
51
51
  readonly docs: {
52
52
  readonly channel: "public";
53
- readonly slug: "/docs/publishing/anonymous";
53
+ readonly slug: "/docs/publish/anonymous";
54
54
  readonly feedbackUrl: null;
55
55
  };
56
56
  readonly owner: "team:publishing";
@@ -86,7 +86,7 @@ declare const featureEntries: readonly [{
86
86
  readonly cohort: "launch";
87
87
  readonly key: "domains.catalog";
88
88
  readonly name: "Domain catalog";
89
- readonly description: "Controls authenticated domain product/catalog operations; public suggestions, availability and WHOIS remain unflagged.";
89
+ readonly description: "Enables authenticated domain catalog operations. Public suggestions, availability and WHOIS stay unflagged.";
90
90
  readonly stage: "internal";
91
91
  readonly surface: true;
92
92
  readonly defaultEnabled: false;
@@ -232,7 +232,7 @@ declare const featureEntries: readonly [{
232
232
  };
233
233
  readonly docs: {
234
234
  readonly channel: "public";
235
- readonly slug: "/docs/spaces/proxy-routes";
235
+ readonly slug: "/docs/serve/redirects";
236
236
  readonly feedbackUrl: null;
237
237
  };
238
238
  readonly owner: "team:domains";
@@ -249,7 +249,7 @@ declare const featureEntries: readonly [{
249
249
  readonly cohort: "launch";
250
250
  readonly key: "collab.notices";
251
251
  readonly name: "Realtime notices";
252
- readonly description: "Live: the Space notice room. Turns on the dashboard's realtime comment feed and the overlay's notice chips. Not an authorization who may watch a Space's feed is decided by its Grants.";
252
+ readonly description: "Turns on the Space notice room: the dashboard's realtime comment feed and the overlay's notice chips. Not an authorization; Grants decide who may watch a feed.";
253
253
  readonly stage: "internal";
254
254
  readonly surface: false;
255
255
  readonly defaultEnabled: false;
@@ -268,6 +268,44 @@ declare const featureEntries: readonly [{
268
268
  readonly code: "notices_stop";
269
269
  readonly summary: "Stop mint/publish; service/operator revoke and cleanup continue.";
270
270
  };
271
+ }, {
272
+ readonly key: "collab.comments";
273
+ readonly name: "Comments";
274
+ readonly description: "Enables the Comments feature for a team: comment threads on spaces/versions, collaboration settings, and the third-party embed surface.";
275
+ readonly defaultEnabled: false;
276
+ readonly runtime: {
277
+ readonly enabledInDevelopment: true;
278
+ readonly enabledForA8c: true;
279
+ readonly planDefaults: {};
280
+ };
281
+ }, {
282
+ readonly cohort: "launch";
283
+ readonly key: "content.managed";
284
+ readonly name: "Managed content";
285
+ readonly description: "Enables the managed WordPress content API and dashboard editor after the compatible runtime fleet is promoted.";
286
+ readonly stage: "internal";
287
+ readonly surface: true;
288
+ readonly defaultEnabled: false;
289
+ readonly runtime: {
290
+ readonly enabledInDevelopment: true;
291
+ readonly enabledForA8c: true;
292
+ readonly planDefaults: {};
293
+ };
294
+ readonly docs: {
295
+ readonly channel: "handbook";
296
+ readonly slug: "/features/content";
297
+ readonly feedbackUrl: null;
298
+ };
299
+ readonly owner: "team:runtime";
300
+ readonly requires: readonly ["sites.dedicated_runtime"];
301
+ readonly lifecycleAdoptedAt: "2026-08-28";
302
+ readonly reviewAfter: "2026-09-11";
303
+ readonly removeAfter: "2026-10-31";
304
+ readonly gaAt: null;
305
+ readonly downRamp: {
306
+ readonly code: "managed_content_stop";
307
+ readonly summary: "Deny customer Content API calls and new editor-session launches, let already-minted editor sessions expire within one hour, stop compiling and activating content releases, and leave existing WordPress data and static serving intact for recovery or export.";
308
+ };
271
309
  }, {
272
310
  readonly key: "collab.drawing";
273
311
  readonly name: "Collab drawing";
@@ -293,7 +331,7 @@ declare const featureEntries: readonly [{
293
331
  };
294
332
  readonly docs: {
295
333
  readonly channel: "public";
296
- readonly slug: "/docs/apps";
334
+ readonly slug: "/docs/account/plans";
297
335
  readonly feedbackUrl: null;
298
336
  };
299
337
  readonly owner: "team:runtime";
@@ -306,21 +344,11 @@ declare const featureEntries: readonly [{
306
344
  readonly code: "dedicated_runtime_stop";
307
345
  readonly summary: "Deny customer mutation and new placement/materialization immediately; serve-time revocation of already-materialized output lands with the deferred runtime-proof slice; operator recovery/export/delete remain; downloaded bytes cannot be recalled.";
308
346
  };
309
- }, {
310
- readonly key: "shelf";
311
- readonly name: "Shelf";
312
- readonly description: "Exposes the per-user artifact shelf: dashboard curation and public /shelf/{handle} pages.";
313
- readonly defaultEnabled: false;
314
- readonly runtime: {
315
- readonly enabledInDevelopment: true;
316
- readonly enabledForA8c: true;
317
- readonly planDefaults: {};
318
- };
319
347
  }, {
320
348
  readonly cohort: "launch";
321
349
  readonly key: "build.content_pipeline";
322
350
  readonly name: "Content pipeline";
323
- readonly description: "Controls publish/finalize use of the content transformation pipeline.";
351
+ readonly description: "Enables the content transformation pipeline at publish and finalize.";
324
352
  readonly stage: "internal";
325
353
  readonly surface: true;
326
354
  readonly defaultEnabled: false;
@@ -355,7 +383,7 @@ declare const featureEntries: readonly [{
355
383
  };
356
384
  readonly docs: {
357
385
  readonly channel: "public";
358
- readonly slug: "/docs/tags";
386
+ readonly slug: "/docs/guides/tag-manager";
359
387
  readonly feedbackUrl: null;
360
388
  };
361
389
  readonly owner: "team:tag-manager";
@@ -382,7 +410,7 @@ declare const featureEntries: readonly [{
382
410
  };
383
411
  readonly docs: {
384
412
  readonly channel: "public";
385
- readonly slug: "/docs/apps/zero";
413
+ readonly slug: "/docs/zero-runtime";
386
414
  readonly feedbackUrl: null;
387
415
  };
388
416
  readonly owner: "team:zero";
@@ -409,7 +437,7 @@ declare const featureEntries: readonly [{
409
437
  };
410
438
  readonly docs: {
411
439
  readonly channel: "public";
412
- readonly slug: "/docs/apps/functions";
440
+ readonly slug: "/docs/functions";
413
441
  readonly feedbackUrl: null;
414
442
  };
415
443
  readonly owner: "team:zero";
@@ -426,7 +454,7 @@ declare const featureEntries: readonly [{
426
454
  readonly cohort: "launch";
427
455
  readonly key: "spaces.slug_rename";
428
456
  readonly name: "Space slug rename";
429
- readonly description: "Renames a space and its managed hostname while retained former hostnames temporarily redirect to the current address.";
457
+ readonly description: "Renames a space and its managed hostname. Retained former hostnames temporarily redirect to the current address.";
430
458
  readonly stage: "ga";
431
459
  readonly surface: true;
432
460
  readonly defaultEnabled: true;
@@ -437,7 +465,7 @@ declare const featureEntries: readonly [{
437
465
  };
438
466
  readonly docs: {
439
467
  readonly channel: "public";
440
- readonly slug: "/docs/spaces/rename";
468
+ readonly slug: "/docs/operate/spaces";
441
469
  readonly feedbackUrl: null;
442
470
  };
443
471
  readonly owner: "team:spaces";
@@ -448,7 +476,25 @@ declare const featureEntries: readonly [{
448
476
  readonly gaAt: "2026-07-27";
449
477
  readonly downRamp: {
450
478
  readonly code: "slug_rename_stop";
451
- readonly summary: "Deny new slug renames while already-committed hostname redirects and runtime convergence continue.";
479
+ readonly summary: "Block new slug renames while earlier hostname and runtime updates continue.";
480
+ };
481
+ }, {
482
+ readonly key: "pages.templates";
483
+ readonly name: "Custom page templates";
484
+ readonly description: "Allows _pages/*.html full-page takeovers to compile for spaces owned by a principal on a plan that grants it.";
485
+ readonly defaultEnabled: false;
486
+ readonly runtime: {
487
+ readonly enabledForA8c: false;
488
+ readonly planDefaults: {};
489
+ };
490
+ }, {
491
+ readonly key: "branding.hide";
492
+ readonly name: "Hide Spacefast branding";
493
+ readonly description: "Allows theme.hideSpacefastBranding to remove the Spacefast badge for spaces owned by a principal on a plan that grants it.";
494
+ readonly defaultEnabled: false;
495
+ readonly runtime: {
496
+ readonly enabledForA8c: false;
497
+ readonly planDefaults: {};
452
498
  };
453
499
  }];
454
500
  type FeatureEntry = (typeof featureEntries)[number];
@@ -460,11 +506,11 @@ type RuntimeFeatureEntry = Extract<FeatureEntry, {
460
506
  }>;
461
507
  export type LifecycleFeatureKey = LifecycleFeatureEntry["key"];
462
508
  export type RuntimeFeatureKey = RuntimeFeatureEntry["key"];
463
- export type RuntimeFeatureDefinition<K extends RuntimeFeatureKey = RuntimeFeatureKey> = RuntimeFeatureDefinitionShape<K>;
509
+ export type RuntimeFeatureDefinition<K extends RuntimeFeatureKey = RuntimeFeatureKey> = RuntimeFeatureDefinitionFields<K>;
464
510
  export declare const FEATURE_LIFECYCLE_REGISTRY: readonly FeatureRegistryEntry<LifecycleFeatureKey>[];
465
511
  type RuntimeDefinitionRecord<K extends string> = {
466
- readonly [Key in K]: RuntimeFeatureDefinitionShape<Key>;
512
+ readonly [Key in K]: RuntimeFeatureDefinitionFields<Key>;
467
513
  };
468
514
  export declare const FEATURE_RUNTIME_KEYS: readonly RuntimeFeatureKey[];
469
- export declare const FEATURE_RUNTIME_DEFINITIONS: Readonly<RuntimeDefinitionRecord<"zero" | "plans.paid.available" | "anonymous.publishing" | "beta.enrollment_gate" | "domains.search" | "domains.registration" | "domains.dns_management" | "domains.wpcom_dns" | "domains.domain_connect" | "domains.proxy_bindings" | "collab.notices" | "collab.drawing" | "sites.dedicated_runtime" | "shelf" | "tags" | "functions" | "spaces.slug_rename">>;
515
+ export declare const FEATURE_RUNTIME_DEFINITIONS: Readonly<RuntimeDefinitionRecord<"zero" | "plans.paid.available" | "anonymous.publishing" | "beta.enrollment_gate" | "domains.search" | "domains.registration" | "domains.dns_management" | "domains.wpcom_dns" | "domains.domain_connect" | "domains.proxy_bindings" | "collab.notices" | "collab.comments" | "content.managed" | "sites.dedicated_runtime" | "collab.drawing" | "tags" | "functions" | "spaces.slug_rename" | "pages.templates" | "branding.hide">>;
470
516
  export declare const FEATURE_LIFECYCLE_BY_KEY: ReadonlyMap<LifecycleFeatureKey, FeatureRegistryEntry<LifecycleFeatureKey>>;
@@ -1,11 +1,16 @@
1
1
  import { freezeFeatureRegistryEntry } from "./feature-lifecycle-core.js";
2
2
  export { FEATURE_OWNER_IDS, FEATURE_STAGES, freezeFeatureRegistryEntry, validateFeatureLifecycleRegistry, } from "./feature-lifecycle-core.js";
3
+ // A `public` docs slug is a live path on the published documentation site, and
4
+ // the sidebar in that site's `blume.config.ts` is its route manifest. Nothing
5
+ // here can check that a slug resolves, because the docs live in another
6
+ // repository; `hasCanonicalDocsSlug` only checks the path's shape. Confirm a
7
+ // slug against that sidebar when you add or move one.
3
8
  const featureEntries = Object.freeze([
4
9
  {
5
10
  cohort: "launch",
6
11
  key: "plans.paid.available",
7
12
  name: "Paid plans available",
8
- description: "Controls whether paid plan upgrade and management surfaces are available.",
13
+ description: "Enables paid plan upgrade and management surfaces.",
9
14
  stage: "internal",
10
15
  surface: false,
11
16
  defaultEnabled: false,
@@ -39,7 +44,7 @@ const featureEntries = Object.freeze([
39
44
  },
40
45
  docs: {
41
46
  channel: "public",
42
- slug: "/docs/publishing/anonymous",
47
+ slug: "/docs/publish/anonymous",
43
48
  feedbackUrl: null,
44
49
  },
45
50
  owner: "team:publishing",
@@ -78,7 +83,7 @@ const featureEntries = Object.freeze([
78
83
  cohort: "launch",
79
84
  key: "domains.catalog",
80
85
  name: "Domain catalog",
81
- description: "Controls authenticated domain product/catalog operations; public suggestions, availability and WHOIS remain unflagged.",
86
+ description: "Enables authenticated domain catalog operations. Public suggestions, availability and WHOIS stay unflagged.",
82
87
  stage: "internal",
83
88
  surface: true,
84
89
  defaultEnabled: false,
@@ -229,7 +234,7 @@ const featureEntries = Object.freeze([
229
234
  },
230
235
  docs: {
231
236
  channel: "public",
232
- slug: "/docs/spaces/proxy-routes",
237
+ slug: "/docs/serve/redirects",
233
238
  feedbackUrl: null,
234
239
  },
235
240
  owner: "team:domains",
@@ -247,7 +252,7 @@ const featureEntries = Object.freeze([
247
252
  cohort: "launch",
248
253
  key: "collab.notices",
249
254
  name: "Realtime notices",
250
- description: "Live: the Space notice room. Turns on the dashboard's realtime comment feed and the overlay's notice chips. Not an authorization who may watch a Space's feed is decided by its Grants.",
255
+ description: "Turns on the Space notice room: the dashboard's realtime comment feed and the overlay's notice chips. Not an authorization; Grants decide who may watch a feed.",
251
256
  stage: "internal",
252
257
  surface: false,
253
258
  defaultEnabled: false,
@@ -267,6 +272,46 @@ const featureEntries = Object.freeze([
267
272
  summary: "Stop mint/publish; service/operator revoke and cleanup continue.",
268
273
  },
269
274
  },
275
+ {
276
+ key: "collab.comments",
277
+ name: "Comments",
278
+ description: "Enables the Comments feature for a team: comment threads on spaces/versions, collaboration settings, and the third-party embed surface.",
279
+ defaultEnabled: false,
280
+ runtime: {
281
+ enabledInDevelopment: true,
282
+ enabledForA8c: true,
283
+ planDefaults: {},
284
+ },
285
+ },
286
+ {
287
+ cohort: "launch",
288
+ key: "content.managed",
289
+ name: "Managed content",
290
+ description: "Enables the managed WordPress content API and dashboard editor after the compatible runtime fleet is promoted.",
291
+ stage: "internal",
292
+ surface: true,
293
+ defaultEnabled: false,
294
+ runtime: {
295
+ enabledInDevelopment: true,
296
+ enabledForA8c: true,
297
+ planDefaults: {},
298
+ },
299
+ docs: {
300
+ channel: "handbook",
301
+ slug: "/features/content",
302
+ feedbackUrl: null,
303
+ },
304
+ owner: "team:runtime",
305
+ requires: ["sites.dedicated_runtime"],
306
+ lifecycleAdoptedAt: "2026-08-28",
307
+ reviewAfter: "2026-09-11",
308
+ removeAfter: "2026-10-31",
309
+ gaAt: null,
310
+ downRamp: {
311
+ code: "managed_content_stop",
312
+ summary: "Deny customer Content API calls and new editor-session launches, let already-minted editor sessions expire within one hour, stop compiling and activating content releases, and leave existing WordPress data and static serving intact for recovery or export.",
313
+ },
314
+ },
270
315
  {
271
316
  key: "collab.drawing",
272
317
  name: "Collab drawing",
@@ -295,7 +340,7 @@ const featureEntries = Object.freeze([
295
340
  },
296
341
  docs: {
297
342
  channel: "public",
298
- slug: "/docs/apps",
343
+ slug: "/docs/account/plans",
299
344
  feedbackUrl: null,
300
345
  },
301
346
  owner: "team:runtime",
@@ -309,22 +354,11 @@ const featureEntries = Object.freeze([
309
354
  summary: "Deny customer mutation and new placement/materialization immediately; serve-time revocation of already-materialized output lands with the deferred runtime-proof slice; operator recovery/export/delete remain; downloaded bytes cannot be recalled.",
310
355
  },
311
356
  },
312
- {
313
- key: "shelf",
314
- name: "Shelf",
315
- description: "Exposes the per-user artifact shelf: dashboard curation and public /shelf/{handle} pages.",
316
- defaultEnabled: false,
317
- runtime: {
318
- enabledInDevelopment: true,
319
- enabledForA8c: true,
320
- planDefaults: {},
321
- },
322
- },
323
357
  {
324
358
  cohort: "launch",
325
359
  key: "build.content_pipeline",
326
360
  name: "Content pipeline",
327
- description: "Controls publish/finalize use of the content transformation pipeline.",
361
+ description: "Enables the content transformation pipeline at publish and finalize.",
328
362
  stage: "internal",
329
363
  surface: true,
330
364
  defaultEnabled: false,
@@ -360,7 +394,7 @@ const featureEntries = Object.freeze([
360
394
  },
361
395
  docs: {
362
396
  channel: "public",
363
- slug: "/docs/tags",
397
+ slug: "/docs/guides/tag-manager",
364
398
  feedbackUrl: null,
365
399
  },
366
400
  owner: "team:tag-manager",
@@ -390,7 +424,7 @@ const featureEntries = Object.freeze([
390
424
  },
391
425
  docs: {
392
426
  channel: "public",
393
- slug: "/docs/apps/zero",
427
+ slug: "/docs/zero-runtime",
394
428
  feedbackUrl: null,
395
429
  },
396
430
  owner: "team:zero",
@@ -421,7 +455,7 @@ const featureEntries = Object.freeze([
421
455
  },
422
456
  docs: {
423
457
  channel: "public",
424
- slug: "/docs/apps/functions",
458
+ slug: "/docs/functions",
425
459
  feedbackUrl: null,
426
460
  },
427
461
  owner: "team:zero",
@@ -436,15 +470,15 @@ const featureEntries = Object.freeze([
436
470
  downRamp: {
437
471
  code: "functions_stop",
438
472
  summary: "Stop emitting dispatch configuration at finalize; published bundles stay on disk as inert content and the " +
439
- "version serves statically. Versions already carrying a config keep dispatching until they are replaced " +
440
- "unsetting the runtime's dispatch token is the immediate kill.",
473
+ "version serves statically. Versions already carrying a config keep dispatching until they are replaced. " +
474
+ "Unsetting the runtime's dispatch token is the immediate kill.",
441
475
  },
442
476
  },
443
477
  {
444
478
  cohort: "launch",
445
479
  key: "spaces.slug_rename",
446
480
  name: "Space slug rename",
447
- description: "Renames a space and its managed hostname while retained former hostnames temporarily redirect to the current address.",
481
+ description: "Renames a space and its managed hostname. Retained former hostnames temporarily redirect to the current address.",
448
482
  stage: "ga",
449
483
  surface: true,
450
484
  defaultEnabled: true,
@@ -455,7 +489,7 @@ const featureEntries = Object.freeze([
455
489
  },
456
490
  docs: {
457
491
  channel: "public",
458
- slug: "/docs/spaces/rename",
492
+ slug: "/docs/operate/spaces",
459
493
  feedbackUrl: null,
460
494
  },
461
495
  owner: "team:spaces",
@@ -466,7 +500,33 @@ const featureEntries = Object.freeze([
466
500
  gaAt: "2026-07-27",
467
501
  downRamp: {
468
502
  code: "slug_rename_stop",
469
- summary: "Deny new slug renames while already-committed hostname redirects and runtime convergence continue.",
503
+ summary: "Block new slug renames while earlier hostname and runtime updates continue.",
504
+ },
505
+ },
506
+ {
507
+ // Partner plan-catalog entitlement dial: a partner plan that grants this key
508
+ // lets its principals' spaces compile `_pages/*.html` full-page takeovers.
509
+ // First-party plans express the same capability through PlanDefinition, not
510
+ // this flag; entitlement resolution maps this key onto the entitlement shape.
511
+ key: "pages.templates",
512
+ name: "Custom page templates",
513
+ description: "Allows _pages/*.html full-page takeovers to compile for spaces owned by a principal on a plan that grants it.",
514
+ defaultEnabled: false,
515
+ runtime: {
516
+ enabledForA8c: false,
517
+ planDefaults: {},
518
+ },
519
+ },
520
+ {
521
+ // Partner plan-catalog entitlement dial: a partner plan that grants this key
522
+ // lets its principals hide the Spacefast badge via theme.hideSpacefastBranding.
523
+ key: "branding.hide",
524
+ name: "Hide Spacefast branding",
525
+ description: "Allows theme.hideSpacefastBranding to remove the Spacefast badge for spaces owned by a principal on a plan that grants it.",
526
+ defaultEnabled: false,
527
+ runtime: {
528
+ enabledForA8c: false,
529
+ planDefaults: {},
470
530
  },
471
531
  },
472
532
  ]);