@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.
- package/brand-assets/LICENSE-Haskoy.txt +93 -0
- package/brand-assets/haskoy-latin-variable.woff2 +0 -0
- package/brand-assets/spacefast-favicon.svg +4 -4
- package/brand-assets/spacefast-sf-full-bleed.svg +3 -3
- package/brand-assets/spacefast-wordmark.svg +2 -4
- package/dist/agents/connect-targets.js +1 -1
- package/dist/agents/private-key-oauth.d.ts +0 -1
- package/dist/agents/private-key-oauth.js +46 -63
- package/dist/brand-assets-build.js +4 -6
- package/dist/brand-assets.d.ts +5 -15
- package/dist/brand-assets.js +15 -14
- package/dist/config/domains.d.ts +47 -7
- package/dist/config/domains.js +66 -10
- package/dist/config/index.d.ts +0 -1
- package/dist/config/index.js +0 -1
- package/dist/contracts/abuse.d.ts +2 -0
- package/dist/contracts/abuse.js +12 -0
- package/dist/contracts/access.d.ts +124 -12
- package/dist/contracts/access.js +73 -9
- package/dist/contracts/activity.d.ts +1 -1
- package/dist/contracts/activity.js +5 -12
- package/dist/contracts/api-keys.d.ts +21 -21
- package/dist/contracts/api-keys.js +2 -2
- package/dist/contracts/beta.js +1 -1
- package/dist/contracts/billing.d.ts +3 -35
- package/dist/contracts/billing.js +33 -52
- package/dist/contracts/builds.d.ts +30 -18
- package/dist/contracts/builds.js +28 -9
- package/dist/contracts/channels.js +1 -1
- package/dist/contracts/cli.d.ts +10 -0
- package/dist/contracts/cli.js +10 -0
- package/dist/contracts/collab-public.d.ts +63 -0
- package/dist/contracts/collab-public.js +46 -0
- package/dist/contracts/comments.d.ts +282 -53
- package/dist/contracts/comments.js +173 -52
- package/dist/contracts/common.d.ts +3 -3
- package/dist/contracts/common.js +5 -5
- package/dist/contracts/crons.d.ts +35 -0
- package/dist/contracts/crons.js +42 -0
- package/dist/contracts/device-auth.d.ts +6 -6
- package/dist/contracts/device-auth.js +2 -2
- package/dist/contracts/docs.js +2 -2
- package/dist/contracts/domains.d.ts +38 -27
- package/dist/contracts/domains.js +29 -2
- package/dist/contracts/enums.d.ts +34 -30
- package/dist/contracts/enums.js +62 -48
- package/dist/contracts/error-code-meta.d.ts +50 -125
- package/dist/contracts/error-code-meta.js +29 -41
- package/dist/contracts/error-codes.d.ts +1 -1
- package/dist/contracts/error-codes.js +14 -33
- package/dist/contracts/execution.d.ts +47 -66
- package/dist/contracts/execution.js +53 -49
- package/dist/contracts/feature-lifecycle-core.d.ts +0 -6
- package/dist/contracts/feature-lifecycle-core.js +2 -31
- package/dist/contracts/feature-lifecycle.d.ts +12 -52
- package/dist/contracts/feature-lifecycle.js +16 -59
- package/dist/contracts/features.d.ts +48 -60
- package/dist/contracts/features.js +59 -51
- package/dist/contracts/functions.d.ts +266 -72
- package/dist/contracts/functions.js +260 -37
- package/dist/contracts/git.d.ts +28 -34
- package/dist/contracts/git.js +10 -11
- package/dist/contracts/grants.d.ts +9 -5
- package/dist/contracts/grants.js +18 -9
- package/dist/contracts/ids.js +2 -2
- package/dist/contracts/internal.d.ts +8 -6
- package/dist/contracts/internal.js +12 -12
- package/dist/contracts/mcp.d.ts +11 -0
- package/dist/contracts/mcp.js +5 -0
- package/dist/contracts/me.js +1 -1
- package/dist/contracts/oauth-resources.d.ts +4 -3
- package/dist/contracts/oauth-resources.js +12 -3
- package/dist/contracts/operations.d.ts +90 -5
- package/dist/contracts/operations.js +77 -3
- package/dist/contracts/pages.d.ts +12 -7
- package/dist/contracts/pages.js +24 -1
- package/dist/contracts/plan-policy.d.ts +0 -2
- package/dist/contracts/plan-policy.js +2 -3
- package/dist/contracts/platform.d.ts +61 -148
- package/dist/contracts/platform.js +70 -126
- package/dist/contracts/publish-archive.d.ts +508 -0
- package/dist/contracts/publish-archive.js +32 -0
- package/dist/contracts/push-new.d.ts +4 -4
- package/dist/contracts/quotas.js +2 -2
- package/dist/contracts/repository-connections.d.ts +43 -30
- package/dist/contracts/repository-connections.js +11 -3
- package/dist/contracts/resources.d.ts +12 -24
- package/dist/contracts/resources.js +36 -16
- package/dist/contracts/runtime-api.d.ts +433 -192
- package/dist/contracts/runtime-api.js +421 -356
- package/dist/contracts/runtime-app.d.ts +127 -120
- package/dist/contracts/runtime-app.js +19 -10
- package/dist/contracts/runtime-db.d.ts +5 -5
- package/dist/contracts/runtime-db.js +2 -2
- package/dist/contracts/runtime-purge.d.ts +8 -0
- package/dist/contracts/runtime-purge.js +7 -0
- package/dist/contracts/runtime-services.d.ts +219 -0
- package/dist/contracts/runtime-services.js +437 -0
- package/dist/contracts/runtime-storage.d.ts +46 -32
- package/dist/contracts/runtime-storage.js +31 -8
- package/dist/contracts/sf-config-v1.d.ts +48 -10
- package/dist/contracts/space-config.d.ts +69 -18
- package/dist/contracts/space-config.js +226 -27
- package/dist/contracts/spaces.d.ts +236 -450
- package/dist/contracts/spaces.js +131 -151
- package/dist/contracts/superadmin-activity.d.ts +57 -4
- package/dist/contracts/superadmin-activity.js +48 -2
- package/dist/contracts/superadmin-search.d.ts +126 -0
- package/dist/contracts/superadmin-search.js +61 -0
- package/dist/contracts/superadmin-spaces.d.ts +361 -92
- package/dist/contracts/superadmin-spaces.js +97 -24
- package/dist/contracts/superadmin-teams.d.ts +28 -10
- package/dist/contracts/superadmin-teams.js +5 -8
- package/dist/contracts/superadmin-tenants.d.ts +0 -6
- package/dist/contracts/superadmin-tenants.js +1 -7
- package/dist/contracts/superadmin.d.ts +135 -54
- package/dist/contracts/superadmin.js +46 -23
- package/dist/contracts/tags.d.ts +12 -12
- package/dist/contracts/tags.js +3 -3
- package/dist/contracts/teams.d.ts +49 -14
- package/dist/contracts/teams.js +40 -22
- package/dist/contracts/transfers.d.ts +0 -49
- package/dist/contracts/transfers.js +4 -8
- package/dist/contracts/usage.d.ts +61 -0
- package/dist/contracts/usage.js +64 -0
- package/dist/contracts/variables.d.ts +2 -7
- package/dist/contracts/variables.js +9 -8
- package/dist/contracts/webhooks.d.ts +2 -2
- package/dist/contracts/zero.d.ts +102 -73
- package/dist/contracts/zero.js +94 -32
- package/dist/dashboard-paths/index.d.ts +1 -1
- package/dist/dashboard-paths/index.js +1 -0
- package/dist/docs/agent-prose.d.ts +2 -2
- package/dist/docs/agent-prose.js +63 -70
- package/dist/docs/agent-setup.js +45 -15
- package/dist/docs/catalog.d.ts +24 -24
- package/dist/docs/catalog.js +35 -24
- package/dist/docs/error-docs.js +194 -270
- package/dist/docs/skills.d.ts +12 -12
- package/dist/docs/skills.js +4 -4
- package/dist/test-helpers/fetch-stub.d.ts +16 -0
- package/dist/test-helpers/fetch-stub.js +25 -0
- package/dist/utils/build-settings.d.ts +5 -1
- package/dist/utils/build-settings.js +91 -13
- package/dist/utils/canonical-json.d.ts +10 -0
- package/dist/utils/canonical-json.js +22 -0
- package/dist/utils/cast-transport.d.ts +28 -0
- package/dist/utils/cast-transport.js +52 -0
- package/dist/utils/claim-token.d.ts +0 -8
- package/dist/utils/claim-token.js +3 -15
- package/dist/utils/concurrency.js +1 -0
- package/dist/utils/credential-policy.d.ts +1 -1
- package/dist/utils/credential-policy.js +4 -3
- package/dist/utils/dns-instructions.js +9 -9
- package/dist/utils/env-file.d.ts +17 -0
- package/dist/utils/env-file.js +96 -0
- package/dist/utils/error-code.d.ts +2 -0
- package/dist/utils/error-code.js +8 -0
- package/dist/utils/generate-space-name.d.ts +8 -10
- package/dist/utils/generate-space-name.js +206 -21
- package/dist/utils/grant-decision.fixtures.json +2938 -0
- package/dist/utils/grants.d.ts +2 -0
- package/dist/utils/grants.js +26 -1
- package/dist/utils/gravatar.d.ts +9 -0
- package/dist/utils/gravatar.js +31 -0
- package/dist/utils/idempotency.d.ts +6 -0
- package/dist/utils/idempotency.js +28 -0
- package/dist/utils/local-space-state.d.ts +9 -16
- package/dist/utils/local-space-state.js +20 -50
- package/dist/utils/one-shot-replay.d.ts +4 -1
- package/dist/utils/page-colors.d.ts +14 -12
- package/dist/utils/page-colors.js +15 -13
- package/dist/utils/page-fonts.d.ts +2 -2
- package/dist/utils/page-fonts.js +15 -4
- package/dist/utils/pages.d.ts +21 -3
- package/dist/utils/pages.js +42 -13
- package/dist/utils/publish-form-data.d.ts +12 -0
- package/dist/utils/publish-form-data.js +10 -0
- package/dist/utils/publish-policy.d.ts +27 -0
- package/dist/utils/publish-policy.fixtures.json +403 -0
- package/dist/utils/publish-policy.js +45 -20
- package/dist/utils/push-new.d.ts +7 -0
- package/dist/utils/push-new.js +7 -0
- package/dist/utils/query-keys.d.ts +4 -5
- package/dist/utils/query-keys.js +2 -3
- package/dist/utils/runtime-paths.d.ts +5 -0
- package/dist/utils/runtime-paths.js +5 -0
- package/dist/utils/runtime-upload-batch.d.ts +0 -5
- package/dist/utils/runtime-upload-batch.js +1 -27
- package/dist/utils/runtime-upload.d.ts +6 -11
- package/dist/utils/runtime-upload.js +10 -13
- package/dist/utils/secure-local-file.js +5 -16
- package/dist/utils/space-config.d.ts +1 -34
- package/dist/utils/space-config.js +8 -326
- package/dist/utils/static-runtime-policy.d.ts +9 -3
- package/dist/utils/static-runtime-policy.fixtures.json +38 -41
- package/dist/utils/static-runtime-policy.js +22 -56
- package/dist/utils/storage-policy.d.ts +1 -1
- package/dist/utils/storage-policy.js +3 -1
- package/dist/utils/structured-error.d.ts +14 -0
- package/dist/utils/structured-error.js +22 -0
- package/dist/utils/upload-session.d.ts +4 -1
- package/dist/utils/upload-session.js +33 -5
- package/dist/utils/version-path.js +13 -4
- package/dist/vocabulary.d.ts +13 -11
- package/dist/vocabulary.js +42 -28
- package/package.json +7 -17
- package/dist/config/postgres-budget.d.ts +0 -129
- package/dist/config/postgres-budget.js +0 -140
- package/dist/config/postgres-budget.json +0 -51
- package/dist/contracts/archives.d.ts +0 -331
- package/dist/contracts/archives.js +0 -120
- package/dist/contracts/deployments.d.ts +0 -574
- package/dist/contracts/deployments.js +0 -97
- package/dist/contracts/sites.d.ts +0 -416
- package/dist/contracts/sites.js +0 -168
- package/dist/contracts/superadmin-queues.d.ts +0 -414
- package/dist/contracts/superadmin-queues.js +0 -202
- package/dist/contracts/superadmin-runtime.d.ts +0 -27
- package/dist/contracts/superadmin-runtime.js +0 -38
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/utils/api.d.ts +0 -4
- 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:
|
|
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
|
-
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
196
|
-
|
|
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
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
|
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
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
|
|
230
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
230
|
+
infra: "infra";
|
|
231
231
|
dns: "dns";
|
|
232
232
|
runtime: "runtime";
|
|
233
233
|
}>>>;
|
package/dist/contracts/common.js
CHANGED
|
@@ -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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
|
40
|
+
.describe("Anonymous Space key. Stored server-side only as a hash."),
|
|
41
41
|
})
|
|
42
42
|
.strict()
|
|
43
43
|
.optional()
|
package/dist/contracts/docs.js
CHANGED
|
@@ -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
|
|
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,
|
|
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,
|