@spacefast/common 0.0.23 → 0.0.26

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 (224) 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.js +1 -1
  7. package/dist/agents/private-key-oauth.d.ts +0 -1
  8. package/dist/agents/private-key-oauth.js +46 -63
  9. package/dist/brand-assets-build.js +4 -6
  10. package/dist/brand-assets.d.ts +5 -15
  11. package/dist/brand-assets.js +15 -14
  12. package/dist/config/domains.d.ts +47 -7
  13. package/dist/config/domains.js +66 -10
  14. package/dist/config/index.d.ts +0 -1
  15. package/dist/config/index.js +0 -1
  16. package/dist/contracts/abuse.d.ts +2 -0
  17. package/dist/contracts/abuse.js +12 -0
  18. package/dist/contracts/access.d.ts +124 -12
  19. package/dist/contracts/access.js +73 -9
  20. package/dist/contracts/activity.d.ts +1 -1
  21. package/dist/contracts/activity.js +5 -12
  22. package/dist/contracts/api-keys.d.ts +21 -21
  23. package/dist/contracts/api-keys.js +2 -2
  24. package/dist/contracts/beta.js +1 -1
  25. package/dist/contracts/billing.d.ts +3 -35
  26. package/dist/contracts/billing.js +33 -52
  27. package/dist/contracts/builds.d.ts +30 -18
  28. package/dist/contracts/builds.js +28 -9
  29. package/dist/contracts/channels.js +1 -1
  30. package/dist/contracts/cli.d.ts +10 -0
  31. package/dist/contracts/cli.js +10 -0
  32. package/dist/contracts/collab-public.d.ts +63 -0
  33. package/dist/contracts/collab-public.js +46 -0
  34. package/dist/contracts/comments.d.ts +282 -53
  35. package/dist/contracts/comments.js +173 -52
  36. package/dist/contracts/common.d.ts +3 -3
  37. package/dist/contracts/common.js +5 -5
  38. package/dist/contracts/crons.d.ts +35 -0
  39. package/dist/contracts/crons.js +42 -0
  40. package/dist/contracts/device-auth.d.ts +6 -6
  41. package/dist/contracts/device-auth.js +2 -2
  42. package/dist/contracts/docs.js +2 -2
  43. package/dist/contracts/domains.d.ts +38 -27
  44. package/dist/contracts/domains.js +29 -2
  45. package/dist/contracts/enums.d.ts +34 -30
  46. package/dist/contracts/enums.js +62 -48
  47. package/dist/contracts/error-code-meta.d.ts +50 -125
  48. package/dist/contracts/error-code-meta.js +29 -41
  49. package/dist/contracts/error-codes.d.ts +1 -1
  50. package/dist/contracts/error-codes.js +14 -33
  51. package/dist/contracts/execution.d.ts +47 -66
  52. package/dist/contracts/execution.js +53 -49
  53. package/dist/contracts/feature-lifecycle-core.d.ts +0 -6
  54. package/dist/contracts/feature-lifecycle-core.js +2 -31
  55. package/dist/contracts/feature-lifecycle.d.ts +12 -52
  56. package/dist/contracts/feature-lifecycle.js +16 -59
  57. package/dist/contracts/features.d.ts +48 -60
  58. package/dist/contracts/features.js +59 -51
  59. package/dist/contracts/functions.d.ts +266 -72
  60. package/dist/contracts/functions.js +260 -37
  61. package/dist/contracts/git.d.ts +28 -34
  62. package/dist/contracts/git.js +10 -11
  63. package/dist/contracts/grants.d.ts +9 -5
  64. package/dist/contracts/grants.js +18 -9
  65. package/dist/contracts/ids.js +2 -2
  66. package/dist/contracts/internal.d.ts +8 -6
  67. package/dist/contracts/internal.js +12 -12
  68. package/dist/contracts/mcp.d.ts +11 -0
  69. package/dist/contracts/mcp.js +5 -0
  70. package/dist/contracts/me.js +1 -1
  71. package/dist/contracts/oauth-resources.d.ts +4 -3
  72. package/dist/contracts/oauth-resources.js +12 -3
  73. package/dist/contracts/operations.d.ts +90 -5
  74. package/dist/contracts/operations.js +77 -3
  75. package/dist/contracts/pages.d.ts +12 -7
  76. package/dist/contracts/pages.js +24 -1
  77. package/dist/contracts/plan-policy.d.ts +0 -2
  78. package/dist/contracts/plan-policy.js +2 -3
  79. package/dist/contracts/platform.d.ts +61 -148
  80. package/dist/contracts/platform.js +70 -126
  81. package/dist/contracts/publish-archive.d.ts +508 -0
  82. package/dist/contracts/publish-archive.js +32 -0
  83. package/dist/contracts/push-new.d.ts +4 -4
  84. package/dist/contracts/quotas.js +2 -2
  85. package/dist/contracts/repository-connections.d.ts +43 -30
  86. package/dist/contracts/repository-connections.js +11 -3
  87. package/dist/contracts/resources.d.ts +12 -24
  88. package/dist/contracts/resources.js +36 -16
  89. package/dist/contracts/runtime-api.d.ts +433 -192
  90. package/dist/contracts/runtime-api.js +421 -356
  91. package/dist/contracts/runtime-app.d.ts +127 -120
  92. package/dist/contracts/runtime-app.js +19 -10
  93. package/dist/contracts/runtime-db.d.ts +5 -5
  94. package/dist/contracts/runtime-db.js +2 -2
  95. package/dist/contracts/runtime-purge.d.ts +8 -0
  96. package/dist/contracts/runtime-purge.js +7 -0
  97. package/dist/contracts/runtime-services.d.ts +219 -0
  98. package/dist/contracts/runtime-services.js +437 -0
  99. package/dist/contracts/runtime-storage.d.ts +46 -32
  100. package/dist/contracts/runtime-storage.js +31 -8
  101. package/dist/contracts/sf-config-v1.d.ts +48 -10
  102. package/dist/contracts/space-config.d.ts +69 -18
  103. package/dist/contracts/space-config.js +226 -27
  104. package/dist/contracts/spaces.d.ts +236 -450
  105. package/dist/contracts/spaces.js +131 -151
  106. package/dist/contracts/superadmin-activity.d.ts +57 -4
  107. package/dist/contracts/superadmin-activity.js +48 -2
  108. package/dist/contracts/superadmin-search.d.ts +126 -0
  109. package/dist/contracts/superadmin-search.js +61 -0
  110. package/dist/contracts/superadmin-spaces.d.ts +361 -92
  111. package/dist/contracts/superadmin-spaces.js +97 -24
  112. package/dist/contracts/superadmin-teams.d.ts +28 -10
  113. package/dist/contracts/superadmin-teams.js +5 -8
  114. package/dist/contracts/superadmin-tenants.d.ts +0 -6
  115. package/dist/contracts/superadmin-tenants.js +1 -7
  116. package/dist/contracts/superadmin.d.ts +135 -54
  117. package/dist/contracts/superadmin.js +46 -23
  118. package/dist/contracts/tags.d.ts +12 -12
  119. package/dist/contracts/tags.js +3 -3
  120. package/dist/contracts/teams.d.ts +49 -14
  121. package/dist/contracts/teams.js +40 -22
  122. package/dist/contracts/transfers.d.ts +0 -49
  123. package/dist/contracts/transfers.js +4 -8
  124. package/dist/contracts/usage.d.ts +61 -0
  125. package/dist/contracts/usage.js +64 -0
  126. package/dist/contracts/variables.d.ts +2 -7
  127. package/dist/contracts/variables.js +9 -8
  128. package/dist/contracts/webhooks.d.ts +2 -2
  129. package/dist/contracts/zero.d.ts +102 -73
  130. package/dist/contracts/zero.js +94 -32
  131. package/dist/dashboard-paths/index.d.ts +1 -1
  132. package/dist/dashboard-paths/index.js +1 -0
  133. package/dist/docs/agent-prose.d.ts +2 -2
  134. package/dist/docs/agent-prose.js +63 -70
  135. package/dist/docs/agent-setup.js +45 -15
  136. package/dist/docs/catalog.d.ts +24 -24
  137. package/dist/docs/catalog.js +35 -24
  138. package/dist/docs/error-docs.js +194 -270
  139. package/dist/docs/skills.d.ts +12 -12
  140. package/dist/docs/skills.js +4 -4
  141. package/dist/test-helpers/fetch-stub.d.ts +16 -0
  142. package/dist/test-helpers/fetch-stub.js +25 -0
  143. package/dist/utils/build-settings.d.ts +5 -1
  144. package/dist/utils/build-settings.js +91 -13
  145. package/dist/utils/canonical-json.d.ts +10 -0
  146. package/dist/utils/canonical-json.js +22 -0
  147. package/dist/utils/cast-transport.d.ts +28 -0
  148. package/dist/utils/cast-transport.js +52 -0
  149. package/dist/utils/claim-token.d.ts +0 -8
  150. package/dist/utils/claim-token.js +3 -15
  151. package/dist/utils/concurrency.js +1 -0
  152. package/dist/utils/credential-policy.d.ts +1 -1
  153. package/dist/utils/credential-policy.js +4 -3
  154. package/dist/utils/dns-instructions.js +9 -9
  155. package/dist/utils/env-file.d.ts +17 -0
  156. package/dist/utils/env-file.js +96 -0
  157. package/dist/utils/error-code.d.ts +2 -0
  158. package/dist/utils/error-code.js +8 -0
  159. package/dist/utils/generate-space-name.d.ts +8 -10
  160. package/dist/utils/generate-space-name.js +206 -21
  161. package/dist/utils/grant-decision.fixtures.json +2938 -0
  162. package/dist/utils/grants.d.ts +2 -0
  163. package/dist/utils/grants.js +26 -1
  164. package/dist/utils/gravatar.d.ts +9 -0
  165. package/dist/utils/gravatar.js +31 -0
  166. package/dist/utils/idempotency.d.ts +6 -0
  167. package/dist/utils/idempotency.js +28 -0
  168. package/dist/utils/local-space-state.d.ts +9 -16
  169. package/dist/utils/local-space-state.js +20 -50
  170. package/dist/utils/one-shot-replay.d.ts +4 -1
  171. package/dist/utils/page-colors.d.ts +14 -12
  172. package/dist/utils/page-colors.js +15 -13
  173. package/dist/utils/page-fonts.d.ts +2 -2
  174. package/dist/utils/page-fonts.js +15 -4
  175. package/dist/utils/pages.d.ts +21 -3
  176. package/dist/utils/pages.js +42 -13
  177. package/dist/utils/publish-form-data.d.ts +12 -0
  178. package/dist/utils/publish-form-data.js +10 -0
  179. package/dist/utils/publish-policy.d.ts +27 -0
  180. package/dist/utils/publish-policy.fixtures.json +403 -0
  181. package/dist/utils/publish-policy.js +45 -20
  182. package/dist/utils/push-new.d.ts +7 -0
  183. package/dist/utils/push-new.js +7 -0
  184. package/dist/utils/query-keys.d.ts +4 -5
  185. package/dist/utils/query-keys.js +2 -3
  186. package/dist/utils/runtime-paths.d.ts +5 -0
  187. package/dist/utils/runtime-paths.js +5 -0
  188. package/dist/utils/runtime-upload-batch.d.ts +0 -5
  189. package/dist/utils/runtime-upload-batch.js +1 -27
  190. package/dist/utils/runtime-upload.d.ts +6 -11
  191. package/dist/utils/runtime-upload.js +10 -13
  192. package/dist/utils/secure-local-file.js +5 -16
  193. package/dist/utils/space-config.d.ts +1 -34
  194. package/dist/utils/space-config.js +8 -326
  195. package/dist/utils/static-runtime-policy.d.ts +9 -3
  196. package/dist/utils/static-runtime-policy.fixtures.json +38 -41
  197. package/dist/utils/static-runtime-policy.js +22 -56
  198. package/dist/utils/storage-policy.d.ts +1 -1
  199. package/dist/utils/storage-policy.js +3 -1
  200. package/dist/utils/structured-error.d.ts +14 -0
  201. package/dist/utils/structured-error.js +22 -0
  202. package/dist/utils/upload-session.d.ts +4 -1
  203. package/dist/utils/upload-session.js +33 -5
  204. package/dist/utils/version-path.js +13 -4
  205. package/dist/vocabulary.d.ts +13 -11
  206. package/dist/vocabulary.js +42 -28
  207. package/package.json +7 -17
  208. package/dist/config/postgres-budget.d.ts +0 -129
  209. package/dist/config/postgres-budget.js +0 -140
  210. package/dist/config/postgres-budget.json +0 -51
  211. package/dist/contracts/archives.d.ts +0 -331
  212. package/dist/contracts/archives.js +0 -120
  213. package/dist/contracts/deployments.d.ts +0 -574
  214. package/dist/contracts/deployments.js +0 -97
  215. package/dist/contracts/sites.d.ts +0 -416
  216. package/dist/contracts/sites.js +0 -168
  217. package/dist/contracts/superadmin-queues.d.ts +0 -414
  218. package/dist/contracts/superadmin-queues.js +0 -202
  219. package/dist/contracts/superadmin-runtime.d.ts +0 -27
  220. package/dist/contracts/superadmin-runtime.js +0 -38
  221. package/dist/index.d.ts +0 -1
  222. package/dist/index.js +0 -1
  223. package/dist/utils/api.d.ts +0 -4
  224. package/dist/utils/api.js +0 -13
@@ -72,6 +72,15 @@ export const collaborationPublicProfileSchema = z
72
72
  .nullable(),
73
73
  })
74
74
  .strict();
75
+ /**
76
+ * Where the browser holding this ticket is.
77
+ *
78
+ * "embed" is a third-party site the owner allowlisted, and it is its own state
79
+ * precisely so nothing pretends a foreign origin is a published Spacefast host:
80
+ * the room an embed ticket names is origin-scoped, and both the mint and Cast
81
+ * refuse the pairing in either direction.
82
+ */
83
+ export const collaborationSurfaceSchema = z.enum(["published", "preview", "embed"]);
75
84
  export const collaborationTicketClaimsSchema = z
76
85
  .object({
77
86
  sub: z.string().min(1),
@@ -96,7 +105,7 @@ export const collaborationTicketClaimsSchema = z
96
105
  emailVerified: z.boolean().optional(),
97
106
  room: z.string().min(1).max(4_096),
98
107
  scope: z.string().min(1).max(COMMENT_PAGE_PATH_MAX_LENGTH),
99
- surface: z.enum(["published", "preview"]),
108
+ surface: collaborationSurfaceSchema,
100
109
  nonce: z.string().min(1).max(160),
101
110
  iat: z.number().int(),
102
111
  nbf: z.number().int(),
@@ -140,15 +149,43 @@ export const collaborationTicketClaimsSchema = z
140
149
  }
141
150
  }
142
151
  });
152
+ // Where comments are reachable. One escalating axis, not two booleans: "off"
153
+ // means nowhere, "previews" means the immutable Version hosts only, and
154
+ // "everywhere" adds the published Space. Moving between them never requires a
155
+ // republish — the always-injected inert tag re-reads the surface through the
156
+ // runtime's same-origin Comments config exchange on every load.
157
+ export const commentsSurfaceSchema = z.enum(["off", "previews", "everywhere"]);
158
+ export const COMMENTS_EMBED_ORIGINS_MAX = 20;
159
+ /**
160
+ * A site the Space owner allows the one-line Collab insert to run on.
161
+ *
162
+ * Exactly one https origin — scheme, host, and port, nothing else. No
163
+ * wildcards: on a foreign site this list IS the entitlement, and `*.example.com`
164
+ * hands it to every subdomain the site ever loses control of. An off-shape
165
+ * value is refused rather than normalized, so what the owner typed and what the
166
+ * server matches are the same string.
167
+ */
168
+ export const commentsEmbedOriginSchema = z
169
+ .string()
170
+ .max(255)
171
+ .refine((value) => {
172
+ let url;
173
+ try {
174
+ url = new URL(value);
175
+ }
176
+ catch {
177
+ return false;
178
+ }
179
+ return url.protocol === "https:" && url.origin === value && !url.hostname.includes("*");
180
+ }, "must be an exact https origin, e.g. https://docs.example.com");
143
181
  export const collaborationSettingsSchema = z
144
182
  .object({
145
183
  spamFilterEnabled: z.boolean().optional(),
146
- // Whether comments are surfaced on the live/published host (vs preview-only).
147
- // The published loader (SPACEFAST-CAST-PLAN §4.2) mounts the orb on a live
148
- // host only when this is true; toggling it never requires a republish — the
149
- // always-injected inert tag re-reads it through the runtime's same-origin
150
- // Comments config exchange on every load.
151
- publishedComments: z.boolean().optional(),
184
+ surface: commentsSurfaceSchema.default("previews"),
185
+ // Non-empty is the embed toggle there is no fourth `surface` state. An
186
+ // embed origin sees the Space at its "previews" tier and never the
187
+ // published Space itself.
188
+ embedOrigins: z.array(commentsEmbedOriginSchema).max(COMMENTS_EMBED_ORIGINS_MAX).default([]),
152
189
  notificationPreferences: z
153
190
  .object({
154
191
  newThreads: z.boolean().default(true),
@@ -162,7 +199,8 @@ export const collaborationSettingsSchema = z
162
199
  const collaborationSettingsPatchSchema = z
163
200
  .object({
164
201
  spamFilterEnabled: z.boolean().optional(),
165
- publishedComments: z.boolean().optional(),
202
+ surface: commentsSurfaceSchema.optional(),
203
+ embedOrigins: z.array(commentsEmbedOriginSchema).max(COMMENTS_EMBED_ORIGINS_MAX).optional(),
166
204
  notificationPreferences: z
167
205
  .object({
168
206
  newThreads: z.boolean().optional(),
@@ -176,40 +214,92 @@ const collaborationSettingsPatchSchema = z
176
214
  export const collaborationSchema = z.object({
177
215
  spaceId: z.string(),
178
216
  revision: z.number().int().nonnegative(),
179
- enabled: z.boolean(),
180
217
  castResourceId: z.string().nullable(),
181
218
  castResourceKey: z.string().nullable(),
182
219
  settings: collaborationSettingsSchema,
183
220
  createdAt: z.string().datetime().nullable(),
184
221
  updatedAt: z.string().datetime().nullable(),
185
222
  });
186
- export const collaborationUpdateSchema = z
187
- .object({
223
+ export const collaborationUpdateSchema = z.object({
188
224
  expectedRevision: z.number().int().nonnegative(),
189
- enabled: z.boolean().optional(),
190
- settings: collaborationSettingsPatchSchema.optional(),
191
- })
192
- .refine((update) => update.enabled !== undefined || update.settings !== undefined, {
193
- message: "At least one collaboration field is required",
225
+ settings: collaborationSettingsPatchSchema,
194
226
  });
195
- export const commentsTicketRequestSchema = z.object({
196
- spaceId: z.string().min(1),
227
+ /**
228
+ * The overlay's whole configuration, in one shape.
229
+ *
230
+ * Both lanes carry this: the Space's own origins get it from the runtime's
231
+ * same-origin exchange, a third-party site fetches it over CORS keyed by
232
+ * `data-space`. Only the transport differs — the SDK parses one shape.
233
+ */
234
+ export const collabOverlayConfigSchema = z.object({
235
+ enabled: z.boolean(),
236
+ resource_key: z.string().nullable(),
237
+ room_key: z.string().nullable(),
238
+ version: z.object({
239
+ id: z.string().nullable(),
240
+ current: z.string().nullable(),
241
+ url: z.string().nullable(),
242
+ }),
243
+ space: z.object({ live_url: z.string().nullable() }),
244
+ theme: z.object({ accent: z.string().nullable(), hide_branding: z.boolean() }),
245
+ ws_url: z.string().nullable(),
246
+ endpoints: z.object({ ticket: z.string() }),
247
+ features: z.object({
248
+ picker: z.boolean().optional(),
249
+ drawing: z.boolean(),
250
+ capture: z.boolean(),
251
+ attachments: z.boolean(),
252
+ notices: z.boolean(),
253
+ }),
254
+ });
255
+ // What a third-party page may assert about itself. The display name only — the
256
+ // anonymous id is the server's to own, and a browser that could choose one
257
+ // could wear another visitor's identity.
258
+ export const commentsEmbedIdentitySchema = collaborationGuestProjectionSchema.pick({
259
+ name: true,
260
+ namedByUser: true,
261
+ });
262
+ export const commentsEmbedTicketRequestSchema = z.object({
197
263
  pagePath: z.string().min(1).max(COMMENT_PAGE_PATH_MAX_LENGTH).default("/"),
198
- origin: z.string().url(),
199
- versionId: z.string().min(1).optional(),
200
- identity: commentsGuestIdentitySchema.optional(),
264
+ identity: commentsEmbedIdentitySchema,
265
+ /**
266
+ * The opaque capability a previous mint on this Space + embed origin handed
267
+ * back. It carries the returning visitor's server-owned anonymous id; an
268
+ * absent, expired, or foreign one simply mints a new identity.
269
+ */
270
+ visitorToken: z.string().min(1).max(2_048).optional(),
201
271
  });
202
- export const commentsTicketResponseSchema = z.object({
272
+ export const commentsEmbedTicketResponseSchema = z.object({
203
273
  token: z.string(),
204
274
  expiresAt: z.string().datetime(),
205
275
  cast: z.object({
206
276
  resource: z.string(),
207
277
  room: z.string(),
208
278
  }),
279
+ visitorToken: z.string(),
280
+ visitorExpiresAt: z.string().datetime(),
209
281
  });
210
- export const realtimeTokenRequestSchema = z.object({
211
- versionId: z.string().optional(),
212
- scope: z.enum(["space", "version"]).default("space"),
282
+ export const commentsTicketResponseSchema = z.object({
283
+ token: z.string(),
284
+ expiresAt: z.string().datetime(),
285
+ cast: z.object({
286
+ resource: z.string(),
287
+ room: z.string(),
288
+ /** Where to open the socket. The client never assembles this itself. */
289
+ wsUrl: z.string().nullable(),
290
+ }),
291
+ /**
292
+ * The same session, bound to the Space's notice room. Cast binds a ticket to
293
+ * exactly one room, so an overlay that also wants Space-level notices needs
294
+ * a second ticket — never a second access decision. Null when this Space has
295
+ * notices switched off.
296
+ */
297
+ notice: z
298
+ .object({
299
+ token: z.string(),
300
+ room: z.string(),
301
+ })
302
+ .nullable(),
213
303
  });
214
304
  export const realtimeTokenResponseSchema = z.object({
215
305
  token: z.string(),
@@ -217,8 +307,16 @@ export const realtimeTokenResponseSchema = z.object({
217
307
  cast: z.object({
218
308
  resource: z.string(),
219
309
  room: z.string(),
310
+ wsUrl: z.string().nullable(),
220
311
  }),
221
312
  });
313
+ /**
314
+ * A Space-level fact worth interrupting someone for. It travels as a `notice`
315
+ * on the Space's notice room — never as an event in a page room — because it
316
+ * is not conversation content: every open surface needs it regardless of which
317
+ * page it happens to be sitting on, including surfaces (the dashboard) that
318
+ * are in no page room at all.
319
+ */
222
320
  export const noticePublishSchema = z.object({
223
321
  versionId: z.string().optional(),
224
322
  kind: z.string().min(1).max(80).default("version.ready"),
@@ -226,13 +324,15 @@ export const noticePublishSchema = z.object({
226
324
  message: z.string().min(1).max(2_000),
227
325
  level: z.enum(["info", "success", "warning", "error"]).default("info"),
228
326
  payload: z.record(z.string(), z.unknown()).optional(),
229
- durable: z.boolean().default(true),
230
- idempotencyKey: z.string().min(1).max(320).optional(),
327
+ });
328
+ /** The wire shape of one notice, shared by the platform and comment lanes. */
329
+ export const spaceNoticeSchema = z.looseObject({
330
+ kind: z.string().min(1),
331
+ version_id: z.string().nullable(),
231
332
  });
232
333
  export const noticePublishResponseSchema = z.object({
233
334
  status: z.string(),
234
- event: z.record(z.string(), z.unknown()).nullable(),
235
- broadcast: z.record(z.string(), z.unknown()).nullable(),
335
+ notice: spaceNoticeSchema,
236
336
  });
237
337
  // Cross-version navigation directory: the Comments overlay asks for the
238
338
  // immutable URLs of version ids present in a room's threads.
@@ -258,6 +358,40 @@ export const commentAuthorSchema = z.object({
258
358
  color: z.string().max(64).nullable(),
259
359
  });
260
360
  export const commentTargetSchema = z.record(z.string(), z.unknown()).nullable();
361
+ /**
362
+ * How many attachments one thread or reply may carry. Mirrors Cast's own
363
+ * `@attachment_limit`: Cast is the authority that enforces it on write, this
364
+ * bound is what REST readers can rely on.
365
+ */
366
+ export const COMMENT_ATTACHMENT_MAX_COUNT = 10;
367
+ /**
368
+ * A pointer to a storage object on the Space's own runtime plus the descriptor
369
+ * needed to render it — never a URL. Cast stores exactly this (snake_case) under
370
+ * `metadata.attachments`; the id is a bare 32-hex object id.
371
+ */
372
+ export const commentAttachmentSchema = z.object({
373
+ id: z.string().regex(/^[a-f0-9]{32}$/),
374
+ name: z.string().min(1).max(160),
375
+ contentType: z.string().min(1).max(255),
376
+ size: z
377
+ .number()
378
+ .int()
379
+ .min(1)
380
+ .max(5 * 1024 * 1024),
381
+ kind: z.enum(["screenshot", "image", "file"]),
382
+ // Document-normalized evidence rectangle. Screenshots only.
383
+ crop: z
384
+ .object({ x: z.number(), y: z.number(), width: z.number(), height: z.number() })
385
+ .optional(),
386
+ });
387
+ /**
388
+ * What a REST reader gets: the stored attachment plus a freshly composed read
389
+ * URL. `url` is null when the runtime's revocable read key cannot be resolved —
390
+ * an honest degraded read rather than a dead link or a dropped attachment.
391
+ */
392
+ export const commentAttachmentViewSchema = commentAttachmentSchema.extend({
393
+ url: z.string().nullable(),
394
+ });
261
395
  export const commentReactionActorSchema = z.object({
262
396
  name: z.string().nullable(),
263
397
  });
@@ -270,6 +404,14 @@ export const commentReactionUpdateSchema = z.object({
270
404
  emoji: z.enum(COMMENT_REACTION_EMOJIS),
271
405
  op: z.enum(["add", "remove"]),
272
406
  });
407
+ /**
408
+ * A reply keeps Cast's own free-form shape; `attachments` is the one field the
409
+ * API composes rather than passes through (Cast carries it in the reply's
410
+ * `metadata`, without URLs).
411
+ */
412
+ export const commentReplyViewSchema = z.looseObject({
413
+ attachments: z.array(commentAttachmentViewSchema),
414
+ });
273
415
  export const commentThreadSchema = z.object({
274
416
  id: z.string(),
275
417
  castThreadId: z.string(),
@@ -287,7 +429,8 @@ export const commentThreadSchema = z.object({
287
429
  author: commentAuthorSchema.nullable(),
288
430
  target: commentTargetSchema,
289
431
  reactions: z.record(z.string(), commentReactionEntrySchema),
290
- comments: z.array(z.record(z.string(), z.unknown())),
432
+ attachments: z.array(commentAttachmentViewSchema),
433
+ comments: z.array(commentReplyViewSchema),
291
434
  permalink: z.string().nullable(),
292
435
  updatedAt: z.string().datetime().nullable(),
293
436
  });
@@ -311,28 +454,6 @@ export const commentCreateSchema = z.object({
311
454
  target: commentTargetSchema.optional(),
312
455
  idempotencyKey: z.string().min(1).max(320).optional(),
313
456
  });
314
- export const commentScreenshotCreateSchema = z.object({
315
- versionId: z.string().min(1),
316
- pagePath: z.string().min(1).max(COMMENT_PAGE_PATH_MAX_LENGTH).default("/"),
317
- contentType: z.enum(["image/png", "image/jpeg", "image/webp"]),
318
- contentBase64: z.string().min(1),
319
- });
320
- export const commentScreenshotSchema = z.object({
321
- id: z.string(),
322
- key: z.string(),
323
- url: z.string().url(),
324
- expiresAt: z.string().datetime(),
325
- });
326
- export const commentScreenshotRefreshSchema = z.object({
327
- versionId: z.string().min(1),
328
- pagePath: z.string().min(1).max(COMMENT_PAGE_PATH_MAX_LENGTH).default("/"),
329
- key: z.string().min(1).max(2_048),
330
- });
331
- export const commentScreenshotRefreshResponseSchema = z.object({
332
- key: z.string(),
333
- url: z.string().url(),
334
- expiresAt: z.string().datetime(),
335
- });
336
457
  export const commentReplySchema = z.object({
337
458
  body: z.string().min(1).max(16_000),
338
459
  idempotencyKey: z.string().min(1).max(320).optional(),
@@ -16,7 +16,7 @@ export declare const baseDiagnosticSchema: z.ZodObject<{
16
16
  path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
17
17
  provider: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
18
18
  registrar: "registrar";
19
- wpcloud: "wpcloud";
19
+ infra: "infra";
20
20
  dns: "dns";
21
21
  runtime: "runtime";
22
22
  }>>>;
@@ -183,7 +183,7 @@ export declare const AsyncOperationSchema: z.ZodObject<{
183
183
  path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
184
184
  provider: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
185
185
  registrar: "registrar";
186
- wpcloud: "wpcloud";
186
+ infra: "infra";
187
187
  dns: "dns";
188
188
  runtime: "runtime";
189
189
  }>>>;
@@ -227,7 +227,7 @@ export declare function mutationEnvelope<T extends z.ZodType>(data: T): z.ZodObj
227
227
  path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
228
228
  provider: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
229
229
  registrar: "registrar";
230
- wpcloud: "wpcloud";
230
+ infra: "infra";
231
231
  dns: "dns";
232
232
  runtime: "runtime";
233
233
  }>>>;
@@ -6,7 +6,7 @@ export const SpaceViewerSchema = z.object({
6
6
  description: z.string().nullable(),
7
7
  ogImagePath: z.string().nullable(),
8
8
  });
9
- // The ONE Diagnostic shape (internal-docs/platform.md L1616-1623). Every lifecycle
9
+ // The ONE Diagnostic shape (the platform spec). Every lifecycle
10
10
  // resource (versions, builds, bindings, assignments, exports, imports, transfers)
11
11
  // carries `diagnostics: Diagnostic[]` using exactly this vocabulary.
12
12
  export const baseDiagnosticSchema = z.object({
@@ -32,7 +32,7 @@ export const baseDiagnosticSchema = z.object({
32
32
  .nullish()
33
33
  .describe("Whether retrying the same operation can resolve this diagnostic without the caller changing anything."),
34
34
  });
35
- // Canonical DnsInstruction (internal-docs/platform.md L2500-2506): provider vocabulary
35
+ // Canonical DnsInstruction (the platform spec): provider vocabulary
36
36
  // never leaks into `purpose`.
37
37
  export const DnsInstructionSchema = z.object({
38
38
  type: z.enum(["A", "AAAA", "CNAME", "TXT", "ALIAS"]),
@@ -41,7 +41,7 @@ export const DnsInstructionSchema = z.object({
41
41
  ttl: z.number().int().optional(),
42
42
  purpose: z.enum(["verification", "routing", "ssl"]).describe("Why this record is needed."),
43
43
  });
44
- // One shared requiredActions vocabulary (internal-docs/platform.md L2512-2517 + L1807-1811):
44
+ // One shared requiredActions vocabulary (the platform spec):
45
45
  // lifecycle resources expose the concrete user steps that unblock them. New action types are
46
46
  // added HERE, never as per-resource variants.
47
47
  export const requiredActionSchema = z.discriminatedUnion("type", [
@@ -64,7 +64,7 @@ export const requiredActionSchema = z.discriminatedUnion("type", [
64
64
  export const requiredActionsSchema = z
65
65
  .array(requiredActionSchema)
66
66
  .describe("Concrete user steps that unblock this resource, using the one shared vocabulary.");
67
- // The error shape (internal-docs/platform.md "Global API Conventions"): every 4xx/5xx body
67
+ // The error shape (the platform spec "Global API Conventions"): every 4xx/5xx body
68
68
  // is one RFC 9457 problem details document served as `application/problem+json`. `type` and
69
69
  // `title` are derived mechanically from `code` (see contracts/error-codes.ts); `code`,
70
70
  // `pointer` (RFC 6901), `details`, `suggestions`, `next`, and `requestId` are extension members.
@@ -93,7 +93,7 @@ export const ProblemDetailsSchema = z.object({
93
93
  .describe("Copy-pasteable commands or API requests an agent can run next."),
94
94
  requestId: z.string().describe("The request id to quote when contacting support."),
95
95
  });
96
- // Success envelope (internal-docs/platform.md "Global API Conventions"): `{ data: T }` for
96
+ // Success envelope (the platform spec "Global API Conventions"): `{ data: T }` for
97
97
  // single resources and mutations, `{ data: T[], pagination }` for lists. Mutations whose work
98
98
  // outlives the request also carry `operation` — wrap with `.extend({ operation: ... })`.
99
99
  export function dataEnvelope(data) {
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ export declare const spaceCronFailureSchema: z.ZodObject<{
3
+ id: z.ZodString;
4
+ occurredAt: z.ZodString;
5
+ }, z.core.$strip>;
6
+ export type SpaceCronFailure = z.infer<typeof spaceCronFailureSchema>;
7
+ export declare const spaceCronListItemSchema: z.ZodObject<{
8
+ key: z.ZodString;
9
+ path: z.ZodString;
10
+ schedule: z.ZodString;
11
+ recentFailures: z.ZodArray<z.ZodObject<{
12
+ id: z.ZodString;
13
+ occurredAt: z.ZodString;
14
+ }, z.core.$strip>>;
15
+ }, z.core.$strip>;
16
+ export type SpaceCronListItem = z.infer<typeof spaceCronListItemSchema>;
17
+ export declare const spaceCronsResponseSchema: z.ZodObject<{
18
+ data: z.ZodObject<{
19
+ versionId: z.ZodNullable<z.ZodString>;
20
+ crons: z.ZodArray<z.ZodObject<{
21
+ key: z.ZodString;
22
+ path: z.ZodString;
23
+ schedule: z.ZodString;
24
+ recentFailures: z.ZodArray<z.ZodObject<{
25
+ id: z.ZodString;
26
+ occurredAt: z.ZodString;
27
+ }, z.core.$strip>>;
28
+ }, z.core.$strip>>;
29
+ unattributedFailures: z.ZodArray<z.ZodObject<{
30
+ id: z.ZodString;
31
+ occurredAt: z.ZodString;
32
+ }, z.core.$strip>>;
33
+ }, z.core.$strip>;
34
+ }, z.core.$strip>;
35
+ export type SpaceCronsResponse = z.infer<typeof spaceCronsResponseSchema>;
@@ -0,0 +1,42 @@
1
+ import { z } from "zod";
2
+ // Crons READ surface: what the live version declares, plus what has failed.
3
+ //
4
+ // There is no write side and there will not be one. `crons` is an sf.jsonc key,
5
+ // so the config file is the only writer and a publish is the only edit — which
6
+ // is what makes a rollback restore the previous schedules for free. This
7
+ // projection exists so a human or an agent can ask what is actually scheduled
8
+ // right now without re-reading the file they think they published.
9
+ // One reported failure. Deliberately just an identity and an instant: the
10
+ // platform's own report of a failed run carries a payload whose shape is not
11
+ // pinned yet, and guessing fields into a public contract now would freeze the
12
+ // wrong ones. A timestamp is what both the CLI table and "did my cron break?"
13
+ // actually need; the space's activity feed carries the narrative.
14
+ export const spaceCronFailureSchema = z.object({
15
+ id: z.string().describe("Identifier of this failure report."),
16
+ occurredAt: z.string().datetime().describe("Instant the failure was reported."),
17
+ });
18
+ // One scheduled entry, exactly as the live version declared it. `key` is the
19
+ // path's slug and is what names this entry everywhere else — the CLI argument,
20
+ // the failure reports, the platform's own bookkeeping.
21
+ export const spaceCronListItemSchema = z.object({
22
+ key: z.string().describe("Stable identifier for this entry, derived from its path."),
23
+ path: z.string().describe("Path on this space that gets requested."),
24
+ schedule: z
25
+ .string()
26
+ .describe("Schedule as declared, verbatim: named, an Nh/Nd/Nw interval, or a five-field crontab expression."),
27
+ recentFailures: z
28
+ .array(spaceCronFailureSchema)
29
+ .describe("Most recent failures reported for this entry, newest first. Empty when it has not failed."),
30
+ });
31
+ export const spaceCronsResponseSchema = z.object({
32
+ data: z.object({
33
+ versionId: z
34
+ .string()
35
+ .nullable()
36
+ .describe("Live version these declarations come from, or null before the first publish."),
37
+ crons: z.array(spaceCronListItemSchema),
38
+ unattributedFailures: z
39
+ .array(spaceCronFailureSchema)
40
+ .describe("Failures that could not be tied to one entry, newest first. A cron removed from the config can still have failed while it was live."),
41
+ }),
42
+ });
@@ -81,6 +81,8 @@ export declare const DeviceAuthorizationPollResponseSchema: z.ZodObject<{
81
81
  "spaces:write": "spaces:write";
82
82
  "spaces:rename": "spaces:rename";
83
83
  "domains:read": "domains:read";
84
+ "spaces:publish": "spaces:publish";
85
+ "builds:trigger": "builds:trigger";
84
86
  "mcp:tools": "mcp:tools";
85
87
  "*": "*";
86
88
  "sites:read": "sites:read";
@@ -90,7 +92,6 @@ export declare const DeviceAuthorizationPollResponseSchema: z.ZodObject<{
90
92
  "sites:policy.write": "sites:policy.write";
91
93
  "spaces:create": "spaces:create";
92
94
  "spaces:delete": "spaces:delete";
93
- "spaces:publish": "spaces:publish";
94
95
  "spaces:transfer": "spaces:transfer";
95
96
  "spaces:export": "spaces:export";
96
97
  "spaces:import": "spaces:import";
@@ -109,7 +110,6 @@ export declare const DeviceAuthorizationPollResponseSchema: z.ZodObject<{
109
110
  "webhooks:read": "webhooks:read";
110
111
  "webhooks:write": "webhooks:write";
111
112
  "builds:read": "builds:read";
112
- "builds:trigger": "builds:trigger";
113
113
  "builds:create": "builds:create";
114
114
  "teams:write": "teams:write";
115
115
  "teams:members.write": "teams:members.write";
@@ -125,8 +125,8 @@ export declare const DeviceAuthorizationPollResponseSchema: z.ZodObject<{
125
125
  "request.client": z.ZodOptional<z.ZodEnum<{
126
126
  api: "api";
127
127
  dashboard: "dashboard";
128
- worker: "worker";
129
128
  cli: "cli";
129
+ worker: "worker";
130
130
  }>>;
131
131
  }, z.core.$strict>>;
132
132
  }, z.core.$strict>>;
@@ -276,6 +276,8 @@ export declare const AgentHandoffRedeemResponseSchema: z.ZodObject<{
276
276
  "spaces:write": "spaces:write";
277
277
  "spaces:rename": "spaces:rename";
278
278
  "domains:read": "domains:read";
279
+ "spaces:publish": "spaces:publish";
280
+ "builds:trigger": "builds:trigger";
279
281
  "mcp:tools": "mcp:tools";
280
282
  "*": "*";
281
283
  "sites:read": "sites:read";
@@ -285,7 +287,6 @@ export declare const AgentHandoffRedeemResponseSchema: z.ZodObject<{
285
287
  "sites:policy.write": "sites:policy.write";
286
288
  "spaces:create": "spaces:create";
287
289
  "spaces:delete": "spaces:delete";
288
- "spaces:publish": "spaces:publish";
289
290
  "spaces:transfer": "spaces:transfer";
290
291
  "spaces:export": "spaces:export";
291
292
  "spaces:import": "spaces:import";
@@ -304,7 +305,6 @@ export declare const AgentHandoffRedeemResponseSchema: z.ZodObject<{
304
305
  "webhooks:read": "webhooks:read";
305
306
  "webhooks:write": "webhooks:write";
306
307
  "builds:read": "builds:read";
307
- "builds:trigger": "builds:trigger";
308
308
  "builds:create": "builds:create";
309
309
  "teams:write": "teams:write";
310
310
  "teams:members.write": "teams:members.write";
@@ -320,8 +320,8 @@ export declare const AgentHandoffRedeemResponseSchema: z.ZodObject<{
320
320
  "request.client": z.ZodOptional<z.ZodEnum<{
321
321
  api: "api";
322
322
  dashboard: "dashboard";
323
- worker: "worker";
324
323
  cli: "cli";
324
+ worker: "worker";
325
325
  }>>;
326
326
  }, z.core.$strict>>;
327
327
  }, z.core.$strict>>;
@@ -3,7 +3,7 @@ import { AGENT_HANDOFF_DECLINE_REASONS } from "../docs/agent-setup.js";
3
3
  import { ApiKeyPresetSchema, ApiKeySchema } from "./api-keys.js";
4
4
  import { DeviceTeamScopeSchema } from "./device-team-scope.js";
5
5
  export { DeviceTeamScopeSchema } from "./device-team-scope.js";
6
- // Device authorization flow (internal-docs/platform.md Credential Bootstrap):
6
+ // Device authorization flow (the platform spec Credential Bootstrap):
7
7
  // `POST /v1/auth/device` starts the flow, `POST /v1/auth/device/poll` redeems
8
8
  // it. Device codes are bearer capabilities: they ride POST bodies only, are
9
9
  // never logged, and redeem exactly once. User codes are short display codes the
@@ -37,7 +37,7 @@ export const DeviceAuthorizationStartRequestSchema = z
37
37
  .trim()
38
38
  .min(1)
39
39
  .max(512)
40
- .describe("Anonymous-space claim token. Stored server-side only as a hash."),
40
+ .describe("Anonymous Space key. Stored server-side only as a hash."),
41
41
  })
42
42
  .strict()
43
43
  .optional()
@@ -19,7 +19,7 @@ export const docsIndexQuerySchema = z.object({
19
19
  .describe("Disclosure tier to list. `essential` (default) shows the core pages; `full` adds advanced pages; `reference` returns everything."),
20
20
  category: docCategoryEnum
21
21
  .optional()
22
- .describe("Restrict to one docs area: guide, cli, api, recipe, workflow, or error."),
22
+ .describe("Restrict to one docs area: `guide`, `cli`, `api`, `recipe`, `workflow`, or `error`."),
23
23
  });
24
24
  /** Links carried by every docs entry. */
25
25
  export const DocsLinksSchema = z.object({
@@ -28,7 +28,7 @@ export const DocsLinksSchema = z.object({
28
28
  });
29
29
  /** One entry in the docs index. */
30
30
  export const DocsEntrySchema = z.object({
31
- slug: z.string().describe("Stable topic id, e.g. `publishing` or `api/spaces`."),
31
+ slug: z.string().describe("Stable topic id, for example `publishing` or `api/spaces`."),
32
32
  title: z.string(),
33
33
  summary: z.string(),
34
34
  category: docCategoryEnum,