@buildinternet/releases-api-types 0.58.3 → 0.60.0

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 (125) hide show
  1. package/README.md +14 -6
  2. package/dist/api-types.d.ts +1168 -0
  3. package/dist/api-types.d.ts.map +1 -0
  4. package/dist/api-types.js +134 -0
  5. package/dist/schemas/account-profile.d.ts +29 -0
  6. package/dist/schemas/account-profile.d.ts.map +1 -0
  7. package/dist/schemas/account-profile.js +24 -0
  8. package/dist/schemas/ai-models.d.ts +67 -0
  9. package/dist/schemas/ai-models.d.ts.map +1 -0
  10. package/{src/schemas/ai-models.ts → dist/schemas/ai-models.js} +25 -31
  11. package/dist/schemas/api-keys.d.ts +71 -0
  12. package/dist/schemas/api-keys.d.ts.map +1 -0
  13. package/dist/schemas/api-keys.js +32 -0
  14. package/dist/schemas/classifications.d.ts +134 -0
  15. package/dist/schemas/classifications.d.ts.map +1 -0
  16. package/dist/schemas/classifications.js +96 -0
  17. package/dist/schemas/collections.d.ts +605 -0
  18. package/dist/schemas/collections.d.ts.map +1 -0
  19. package/dist/schemas/collections.js +320 -0
  20. package/dist/schemas/datasets.d.ts +34 -0
  21. package/dist/schemas/datasets.d.ts.map +1 -0
  22. package/dist/schemas/datasets.js +11 -0
  23. package/dist/schemas/errors.d.ts +43 -0
  24. package/dist/schemas/errors.d.ts.map +1 -0
  25. package/dist/schemas/errors.js +61 -0
  26. package/dist/schemas/feedback.d.ts +134 -0
  27. package/dist/schemas/feedback.d.ts.map +1 -0
  28. package/dist/schemas/feedback.js +76 -0
  29. package/dist/schemas/follows.d.ts +154 -0
  30. package/dist/schemas/follows.d.ts.map +1 -0
  31. package/dist/schemas/follows.js +42 -0
  32. package/dist/schemas/listing.d.ts +374 -0
  33. package/dist/schemas/listing.d.ts.map +1 -0
  34. package/dist/schemas/listing.js +175 -0
  35. package/dist/schemas/lookups.d.ts +285 -0
  36. package/dist/schemas/lookups.d.ts.map +1 -0
  37. package/{src/schemas/lookups.ts → dist/schemas/lookups.js} +67 -80
  38. package/dist/schemas/marketing-classifier.d.ts +32 -0
  39. package/dist/schemas/marketing-classifier.d.ts.map +1 -0
  40. package/{src/schemas/marketing-classifier.ts → dist/schemas/marketing-classifier.js} +14 -18
  41. package/dist/schemas/orgs.d.ts +950 -0
  42. package/dist/schemas/orgs.d.ts.map +1 -0
  43. package/dist/schemas/orgs.js +473 -0
  44. package/dist/schemas/overviews.d.ts +205 -0
  45. package/dist/schemas/overviews.d.ts.map +1 -0
  46. package/{src/schemas/overviews.ts → dist/schemas/overviews.js} +41 -54
  47. package/dist/schemas/products.d.ts +595 -0
  48. package/dist/schemas/products.d.ts.map +1 -0
  49. package/{src/schemas/products.ts → dist/schemas/products.js} +113 -136
  50. package/dist/schemas/publish-tokens.d.ts +55 -0
  51. package/dist/schemas/publish-tokens.d.ts.map +1 -0
  52. package/{src/schemas/publish-tokens.ts → dist/schemas/publish-tokens.js} +18 -29
  53. package/dist/schemas/recommendations.d.ts +52 -0
  54. package/dist/schemas/recommendations.d.ts.map +1 -0
  55. package/dist/schemas/recommendations.js +58 -0
  56. package/dist/schemas/related.d.ts +331 -0
  57. package/dist/schemas/related.d.ts.map +1 -0
  58. package/dist/schemas/related.js +115 -0
  59. package/dist/schemas/releases.d.ts +623 -0
  60. package/dist/schemas/releases.d.ts.map +1 -0
  61. package/dist/schemas/releases.js +414 -0
  62. package/dist/schemas/resolve.d.ts +259 -0
  63. package/dist/schemas/resolve.d.ts.map +1 -0
  64. package/{src/schemas/resolve.ts → dist/schemas/resolve.js} +2 -5
  65. package/dist/schemas/search.d.ts +475 -0
  66. package/dist/schemas/search.d.ts.map +1 -0
  67. package/dist/schemas/search.js +258 -0
  68. package/dist/schemas/semantic-alert-summary.d.ts +54 -0
  69. package/dist/schemas/semantic-alert-summary.d.ts.map +1 -0
  70. package/dist/schemas/semantic-alert-summary.js +57 -0
  71. package/dist/schemas/semantic-alerts.d.ts +41 -0
  72. package/dist/schemas/semantic-alerts.d.ts.map +1 -0
  73. package/dist/schemas/semantic-alerts.js +42 -0
  74. package/dist/schemas/shared.d.ts +247 -0
  75. package/dist/schemas/shared.d.ts.map +1 -0
  76. package/dist/schemas/shared.js +248 -0
  77. package/dist/schemas/site-notice.d.ts +35 -0
  78. package/dist/schemas/site-notice.d.ts.map +1 -0
  79. package/{src/schemas/site-notice.ts → dist/schemas/site-notice.js} +14 -18
  80. package/dist/schemas/sitemap.d.ts +97 -0
  81. package/dist/schemas/sitemap.d.ts.map +1 -0
  82. package/dist/schemas/sitemap.js +107 -0
  83. package/dist/schemas/sources.d.ts +1145 -0
  84. package/dist/schemas/sources.d.ts.map +1 -0
  85. package/dist/schemas/sources.js +645 -0
  86. package/dist/schemas/stats.d.ts +82 -0
  87. package/dist/schemas/stats.d.ts.map +1 -0
  88. package/dist/schemas/stats.js +59 -0
  89. package/dist/schemas/taxonomy.d.ts +344 -0
  90. package/dist/schemas/taxonomy.d.ts.map +1 -0
  91. package/{src/schemas/taxonomy.ts → dist/schemas/taxonomy.js} +47 -58
  92. package/dist/schemas/webhooks.d.ts +618 -0
  93. package/dist/schemas/webhooks.d.ts.map +1 -0
  94. package/dist/schemas/webhooks.js +191 -0
  95. package/dist/schemas/well-known.d.ts +302 -0
  96. package/dist/schemas/well-known.d.ts.map +1 -0
  97. package/dist/schemas/well-known.js +192 -0
  98. package/dist/schemas/workspace-integrations.d.ts +27 -0
  99. package/dist/schemas/workspace-integrations.d.ts.map +1 -0
  100. package/dist/schemas/workspace-integrations.js +22 -0
  101. package/package.json +16 -4
  102. package/src/api-types.ts +0 -2223
  103. package/src/schemas/account-profile.ts +0 -28
  104. package/src/schemas/ai-models.test.ts +0 -29
  105. package/src/schemas/classifications.ts +0 -109
  106. package/src/schemas/collections.ts +0 -346
  107. package/src/schemas/errors.test.ts +0 -55
  108. package/src/schemas/errors.ts +0 -81
  109. package/src/schemas/feedback.ts +0 -56
  110. package/src/schemas/listing.ts +0 -226
  111. package/src/schemas/orgs.ts +0 -533
  112. package/src/schemas/recommendations.ts +0 -39
  113. package/src/schemas/related.ts +0 -126
  114. package/src/schemas/releases.ts +0 -436
  115. package/src/schemas/search.ts +0 -274
  116. package/src/schemas/semantic-alert-summary.ts +0 -65
  117. package/src/schemas/shared.notice.test.ts +0 -36
  118. package/src/schemas/shared.ts +0 -267
  119. package/src/schemas/site-notice.test.ts +0 -67
  120. package/src/schemas/sitemap.ts +0 -114
  121. package/src/schemas/sources.ts +0 -674
  122. package/src/schemas/stats.ts +0 -62
  123. package/src/schemas/well-known.test.ts +0 -264
  124. package/src/schemas/well-known.ts +0 -252
  125. package/src/schemas/workspace-integrations.ts +0 -26
@@ -1,436 +0,0 @@
1
- import { z } from "zod";
2
- import { SOURCE_TYPES } from "@buildinternet/releases-core/source-enums";
3
- import { BREAKING_LEVELS } from "@buildinternet/releases-core/breaking";
4
- import { KIND_VALUES } from "@buildinternet/releases-core/kinds";
5
- import {
6
- AppStoreSourceInfoSchema,
7
- ImportanceScoreSchema,
8
- MediaItemSchema,
9
- ReleaseCompositionSchema,
10
- ReleaseThumbnailSchema,
11
- ReleaseTypeSchema,
12
- VideoSourceInfoSchema,
13
- } from "./shared.js";
14
-
15
- // ReleaseCompositionSchema lives in ./shared.js (single source of truth) — both
16
- // this file and ReleaseItemSchema reference it from there.
17
-
18
- /**
19
- * Per-row shape returned by `GET /v1/releases/latest`. Distinct from the
20
- * shared `ReleaseItemSchema` because the latest-feed handler joins the
21
- * source row in and exposes it as a nested `source` object instead of
22
- * leaving the caller to do a second lookup.
23
- *
24
- * `type` is required here — the latest handler reads it directly from
25
- * `releases.type` (NOT NULL with DB-default `'feature'`), so mid-deploy
26
- * degrade-gracefully nullability doesn't apply on this path.
27
- */
28
- export const ReleaseLatestSourceSchema = z.object({
29
- slug: z.string(),
30
- name: z.string(),
31
- type: z.enum(SOURCE_TYPES),
32
- orgSlug: z.string().nullable(),
33
- /** Owning org's display name (e.g. "Cloudflare"), distinct from the source
34
- * name. Null when the source has no org. Additive — older responses omit it. */
35
- orgName: z.string().nullable().optional(),
36
- /** Owning org's explicit avatar URL (`organizations.avatar_url`), when set.
37
- * Null/absent when the org has no stored avatar — clients fall back to the
38
- * GitHub handle below, then an initial. Additive — older responses omit it. */
39
- orgAvatarUrl: z.string().nullable().optional(),
40
- /** Owning org's GitHub handle, used to derive `github.com/<handle>.png` as the
41
- * avatar fallback when `orgAvatarUrl` is unset. Additive — older responses omit it. */
42
- orgGithubHandle: z.string().nullable().optional(),
43
- /** Source classification (`sdk`, `platform`, `docs`, …) from `sources.kind`.
44
- * Null when the source has no explicit kind — resolve against the product's
45
- * kind via `resolveSourceKind`. Additive — older responses omit it. Lets read
46
- * surfaces (e.g. the digest email) deprioritize/cluster SDK releases the way
47
- * the web sources table does. */
48
- kind: z.enum(KIND_VALUES).nullable().optional(),
49
- });
50
-
51
- export const ReleaseLatestProductSchema = z.object({
52
- slug: z.string(),
53
- name: z.string(),
54
- /** Product classification from `products.kind`; the fallback `resolveSourceKind`
55
- * consults when the source itself has no kind. Additive — older responses omit it. */
56
- kind: z.enum(KIND_VALUES).nullable().optional(),
57
- });
58
-
59
- export const ReleaseLatestItemSchema = z.object({
60
- id: z.string(),
61
- version: z.string().nullable(),
62
- type: ReleaseTypeSchema,
63
- title: z.string(),
64
- summary: z.string().nullable(),
65
- titleGenerated: z.string().nullable(),
66
- titleShort: z.string().nullable(),
67
- /**
68
- * Machine-readable breaking-change level (#1696, surfaced on read paths in
69
- * #1710). `.optional()` for mid-deploy / pinned-worker tolerance and because
70
- * rows predating the column omit it; absent or `"unknown"` means not
71
- * classified (the fail-open default). List paths carry `breaking` only —
72
- * `migrationNotes` stays detail-route-only to keep list payloads slim.
73
- */
74
- breaking: z.enum(BREAKING_LEVELS).optional(),
75
- importance: ImportanceScoreSchema,
76
- publishedAt: z.string().nullable(),
77
- url: z.string().nullable(),
78
- /**
79
- * Canonical releases.sh detail-page URL (friendly form: ID + current
80
- * title slug). Additive — older servers and the digest-cron path omit it.
81
- */
82
- webUrl: z.string().optional(),
83
- media: z.array(MediaItemSchema),
84
- source: ReleaseLatestSourceSchema,
85
- /**
86
- * Owning product, when the release's source is grouped under a product.
87
- * `null` when the source has no `product_id`. Additive — older API responses
88
- * omit this field; treat `undefined` as `null`. #1217.
89
- */
90
- product: ReleaseLatestProductSchema.nullable().optional(),
91
- /**
92
- * Server-resolved grouping identity — `product.slug ?? source.slug` /
93
- * `product.name ?? source.name`. The web releases feed keys and labels
94
- * SDK/package-cluster rollups on these instead of reconstructing
95
- * `product ?? source` client-side; the digest email mirrors that. Optional on
96
- * the wire: older workers omit them, so clients fall back to deriving from
97
- * `product ?? source`. Never null when present (`source` is always set). #1234
98
- */
99
- groupSlug: z.string().optional(),
100
- groupName: z.string().optional(),
101
- coverageCount: z.number().int().min(0).optional(),
102
- // Cached release-body size hint — see {@link ReleaseItemSchema} for the
103
- // same fields on the org / collection feeds. #958.
104
- contentChars: z.number().int().min(0).nullable().optional(),
105
- contentTokens: z.number().int().min(0).nullable().optional(),
106
- composition: ReleaseCompositionSchema.nullable().optional(),
107
- });
108
-
109
- export const ReleaseLatestResponseSchema = z.object({
110
- releases: z.array(ReleaseLatestItemSchema),
111
- });
112
-
113
- /**
114
- * Display fields for the counterpart release a coverage row points at —
115
- * the canonical for a `coverage`-role response, or each rolled-up coverage
116
- * release for a `canonical`-role response. Lets `GET /releases/:id/coverage`
117
- * render a cluster without a follow-up `GET /releases/:id` per sibling.
118
- * `null` when the counterpart is suppressed or its source was removed.
119
- *
120
- * Coverage-side rows are surfaced here on purpose, even though the
121
- * `releases_visible` view (and thus `GET /releases/:id`) hides them — a
122
- * cluster view's whole job is to show its members.
123
- */
124
- export const ReleaseCoverageSiblingSchema = z.object({
125
- id: z.string(),
126
- version: z.string().nullable(),
127
- title: z.string(),
128
- sourceName: z.string(),
129
- publishedAt: z.string().nullable(),
130
- org: z.object({ slug: z.string(), name: z.string() }).nullable(),
131
- /** First image/gif thumbnail for the counterpart release; null when it has
132
- * none. Optional so an older server that omits it still validates. */
133
- thumbnail: ReleaseThumbnailSchema.nullable().optional(),
134
- });
135
-
136
- /**
137
- * Single row of the `release_coverage` join table. Drives the
138
- * GET /releases/:id/coverage response. `sibling` carries the counterpart
139
- * release's display fields (see {@link ReleaseCoverageSiblingSchema}); it is
140
- * optional so an older server that doesn't populate it still validates.
141
- */
142
- export const ReleaseCoverageRowSchema = z.object({
143
- coverageId: z.string(),
144
- canonicalId: z.string(),
145
- reason: z.string().nullable(),
146
- decidedBy: z.string(),
147
- decidedAt: z.string(),
148
- sibling: ReleaseCoverageSiblingSchema.nullable().optional(),
149
- });
150
-
151
- /**
152
- * Discriminated by `role`:
153
- * - `standalone` — release is neither canonical nor coverage of anything.
154
- * - `coverage` — release is coverage rolling up to `canonical`.
155
- * - `canonical` — release is the canonical row; `covers` enumerates rollups.
156
- */
157
- export const ReleaseCoverageResponseSchema = z.discriminatedUnion("role", [
158
- z.object({
159
- role: z.literal("standalone"),
160
- canonical: z.null(),
161
- covers: z.array(z.never()).length(0),
162
- }),
163
- z.object({
164
- role: z.literal("coverage"),
165
- canonical: ReleaseCoverageRowSchema,
166
- covers: z.array(z.never()).length(0),
167
- }),
168
- z.object({
169
- role: z.literal("canonical"),
170
- canonical: z.null(),
171
- covers: z.array(ReleaseCoverageRowSchema),
172
- }),
173
- ]);
174
-
175
- /**
176
- * Body accepted by `POST /v1/releases/:id/coverage`. `decidedBy` MUST be
177
- * prefixed with `human:` or `agent:` so the audit trail records who linked
178
- * the rows; the handler enforces this with a regex.
179
- */
180
- export const LinkReleaseCoverageBodySchema = z.object({
181
- coverageIds: z.array(z.string()).min(1),
182
- reason: z.string().nullable().optional(),
183
- decidedBy: z.string().regex(/^(human:|agent:)/),
184
- });
185
-
186
- export const LinkReleaseCoverageResponseSchema = z.object({
187
- canonicalId: z.string(),
188
- coverageIds: z.array(z.string()),
189
- linked: z.number().int().min(0),
190
- });
191
-
192
- /**
193
- * Response for `DELETE /v1/releases/:id/coverage`. Idempotent — the handler
194
- * returns `{ unlinked: false }` when the release isn't in a cluster, so the
195
- * remote client can skip a brittle error-message sniff.
196
- */
197
- export const UnlinkReleaseCoverageResponseSchema = z.object({
198
- unlinked: z.boolean(),
199
- });
200
-
201
- /**
202
- * Row returned by `GET /v1/releases?hasMedia=true`. Internal/admin escape
203
- * hatch consumed by the `media backfill` CLI command.
204
- */
205
- export const ReleaseWithMediaRowSchema = z.object({
206
- id: z.string(),
207
- sourceId: z.string(),
208
- media: z.string().nullable(),
209
- });
210
-
211
- export const ReleasesWithMediaResponseSchema = z.array(ReleaseWithMediaRowSchema);
212
-
213
- /**
214
- * Nested org context joined into the `GET /v1/releases/:id` response.
215
- * Both fields are nullable — releases whose source has no org attached
216
- * return `null` for this object entirely.
217
- */
218
- export const ReleaseDetailOrgSchema = z.object({
219
- slug: z.string(),
220
- name: z.string(),
221
- /**
222
- * Resolved org avatar URL (the `organizations.avatar_url` column). `null`
223
- * when the org has no stored avatar. Additive — older servers omit it, so
224
- * treat `undefined` as `null`. Mirrors the `orgAvatarUrl` field on the
225
- * related-rail feed.
226
- */
227
- avatarUrl: z.string().nullable().optional(),
228
- /**
229
- * How the org was created. Additive — older servers omit it; treat
230
- * `undefined` as `"curated"`. Used by the web to emit `noindex` on
231
- * on-demand-materialized org pages.
232
- */
233
- discovery: z.enum(["curated", "agent", "on_demand"]).optional(),
234
- /**
235
- * Whether the org is hidden from public listings. Additive — older servers
236
- * omit it; treat `undefined` as `false`. Used by the web to emit `noindex`.
237
- */
238
- isHidden: z.boolean().optional(),
239
- });
240
-
241
- /**
242
- * Full release detail returned by `GET /v1/releases/:id`. Joins source
243
- * name/slug/type and a nullable org object; media is parsed from the raw
244
- * JSON stored in D1 and typed URLs are rewritten to the CDN origin. The
245
- * route only surfaces non-suppressed, non-coverage rows (filtered via the
246
- * `releases_visible` view).
247
- */
248
- export const ReleaseDetailResponseSchema = z.object({
249
- id: z.string(),
250
- sourceId: z.string(),
251
- version: z.string().nullable(),
252
- type: ReleaseTypeSchema,
253
- title: z.string(),
254
- content: z.string(),
255
- summary: z.string().nullable(),
256
- titleGenerated: z.string().nullable(),
257
- titleShort: z.string().nullable(),
258
- /**
259
- * Machine-readable breaking-change level (#1696, surfaced on read paths in
260
- * #1710). `.optional()` — rows predating the column omit it; absent or
261
- * `"unknown"` means not classified (the fail-open default). Mirrors
262
- * `ReleaseDetail.breaking` in api-types.ts.
263
- */
264
- breaking: z.enum(BREAKING_LEVELS).optional(),
265
- importance: ImportanceScoreSchema,
266
- /**
267
- * Explicit upgrade/migration steps lifted from the body (#1696); omitted
268
- * when the body gives none. Detail-route-only — list paths never carry it.
269
- */
270
- migrationNotes: z.string().nullable().optional(),
271
- url: z.string().nullable(),
272
- /**
273
- * Canonical releases.sh detail-page URL, `https://releases.sh/release/
274
- * rel_<id>-<slug>` (Zendesk-style: immutable ID + current title slug;
275
- * the slug follows title regeneration, the ID keeps old links alive).
276
- * Additive — older servers omit it.
277
- */
278
- webUrl: z.string().optional(),
279
- contentHash: z.string().nullable(),
280
- media: z.array(MediaItemSchema),
281
- publishedAt: z.string().nullable(),
282
- suppressed: z.boolean().nullable(),
283
- suppressedReason: z.string().nullable(),
284
- prerelease: z.boolean().nullable(),
285
- fetchedAt: z.string().nullable(),
286
- sourceName: z.string().nullable(),
287
- sourceSlug: z.string().nullable(),
288
- sourceType: z.enum(SOURCE_TYPES).nullable(),
289
- org: ReleaseDetailOrgSchema.nullable(),
290
- /**
291
- * Owning product, when the release's source is grouped under a product
292
- * (`sources.product_id`). `null` when the source has no product. Additive —
293
- * older servers omit this field; treat `undefined` as `null`. Reuses the
294
- * `{ slug, name }` shape from the latest feed.
295
- */
296
- product: ReleaseLatestProductSchema.nullable().optional(),
297
- composition: ReleaseCompositionSchema.nullable(),
298
- appStore: AppStoreSourceInfoSchema.nullable().optional(),
299
- video: VideoSourceInfoSchema.nullable().optional(),
300
- /**
301
- * Whether the release's source is hidden from public listings. Additive —
302
- * older servers omit it; treat `undefined` as `false`. Used by the web to
303
- * emit `noindex` on pages whose source is an on-demand-materialized stub.
304
- */
305
- sourceIsHidden: z.boolean().optional(),
306
- });
307
-
308
- /**
309
- * Body accepted by `PATCH /v1/releases/:id`. All fields are optional;
310
- * omitted fields are not updated. The nullable string columns (`version`,
311
- * `url`, `publishedAt`, `contentHash`) accept a string or `null`. AI-generated
312
- * fields (`summary`, `titleGenerated`, `titleShort`) accept `null` to
313
- * explicitly clear the stored value. Non-whitelisted fields are rejected
314
- * via `.strict()` — the handler also re-runs the field-set check after
315
- * sanitization so an empty update payload still 400s.
316
- */
317
- export const UpdateReleaseBodySchema = z
318
- .object({
319
- title: z.string().optional(),
320
- content: z.string().optional(),
321
- version: z.string().nullable().optional(),
322
- url: z.string().nullable().optional(),
323
- publishedAt: z.string().nullable().optional(),
324
- contentHash: z.string().nullable().optional(),
325
- summary: z.string().nullable().optional(),
326
- titleGenerated: z.string().nullable().optional(),
327
- titleShort: z.string().nullable().optional(),
328
- // `null` removes `$.composition` from metadata; an object replaces it.
329
- composition: ReleaseCompositionSchema.nullable().optional(),
330
- // Replace the release's stored `media[]` wholesale (curator manual edit).
331
- // Items whose `url` is not already an R2/`media.releases.sh` origin are run
332
- // through the ingest R2 mirror (`processMediaForR2`) so posters/images land
333
- // in `released-media` and get `r2Key`/`r2Url` stamped — same path as ingest.
334
- // Reuses the shared `MediaItemSchema` (type/url/alt/r2Url/r2Key/linkUrl).
335
- media: z.array(MediaItemSchema).optional(),
336
- })
337
- .strict();
338
-
339
- /**
340
- * Response returned by `PATCH /v1/releases/:id`. The handler returns the raw
341
- * Drizzle row from the `releases` table — distinct from the augmented
342
- * `ReleaseDetailResponseSchema` shape served by `GET /v1/releases/:id`, which
343
- * adds joined source/org metadata and parses `media` from raw JSON. Clients
344
- * that need the augmented shape after an edit should re-fetch via GET.
345
- */
346
- export const ReleasePatchResponseSchema = z.object({
347
- id: z.string(),
348
- sourceId: z.string(),
349
- version: z.string().nullable(),
350
- type: ReleaseTypeSchema,
351
- title: z.string(),
352
- content: z.string(),
353
- summary: z.string().nullable(),
354
- titleGenerated: z.string().nullable(),
355
- titleShort: z.string().nullable(),
356
- url: z.string().nullable(),
357
- contentHash: z.string().nullable(),
358
- metadata: z.string().nullable(),
359
- // Raw JSON string of the media array — not parsed at this endpoint.
360
- media: z.string().nullable(),
361
- publishedAt: z.string().nullable(),
362
- prerelease: z.boolean().nullable(),
363
- suppressed: z.boolean().nullable(),
364
- suppressedReason: z.string().nullable(),
365
- fetchedAt: z.string().nullable(),
366
- embeddedAt: z.string().nullable(),
367
- });
368
-
369
- /** Response returned by `DELETE /v1/releases/:id`. */
370
- export const ReleaseDeleteResponseSchema = z.object({
371
- deleted: z.literal(true),
372
- });
373
-
374
- /** Body accepted by `DELETE /v1/releases/batch`. */
375
- export const ReleaseBatchDeleteBodySchema = z.object({
376
- releaseIds: z.array(z.string()).min(1),
377
- });
378
-
379
- /** Response returned by `DELETE /v1/releases/batch`. */
380
- export const ReleaseBatchDeleteResponseSchema = z.object({
381
- deleted: z.number().int().min(0),
382
- });
383
-
384
- /**
385
- * Body accepted by `POST /v1/releases/batch-suppress`. When `suppressed` is
386
- * true the optional `reason` is stored in `suppressed_reason`; when false the
387
- * reason is cleared.
388
- */
389
- export const ReleaseBatchSuppressBodySchema = z.object({
390
- releaseIds: z.array(z.string()).min(1),
391
- suppressed: z.boolean(),
392
- reason: z.string().optional(),
393
- });
394
-
395
- /** Response returned by `POST /v1/releases/batch-suppress`. */
396
- export const ReleaseBatchSuppressResponseSchema = z.object({
397
- updated: z.number().int().min(0),
398
- });
399
-
400
- /** Response returned by `POST /v1/releases/:id/suppress`. */
401
- export const ReleaseSuppressResponseSchema = z.object({
402
- suppressed: z.literal(true),
403
- });
404
-
405
- /** Response returned by `POST /v1/releases/:id/unsuppress`. */
406
- export const ReleaseUnsuppressResponseSchema = z.object({
407
- unsuppressed: z.literal(true),
408
- });
409
-
410
- /**
411
- * Body accepted by `POST /v1/releases/:id/suppress`. The `reason` field
412
- * is optional; when omitted the stored `suppressed_reason` is set to null.
413
- */
414
- export const ReleaseSuppressBodySchema = z.object({
415
- reason: z.string().optional(),
416
- });
417
-
418
- /**
419
- * WebSocket message schema for the `GET /v1/releases/stream` endpoint.
420
- * Each message is a JSON object with one of the following shapes:
421
- * - `{ type: "ready", seq: number }` — sent on connect to give the caller
422
- * the current head sequence number for later resume.
423
- * - `{ type: "release.created", seq: number, release: object }` — a new
424
- * release was indexed; `release` carries the full release row.
425
- * - `{ type: "snapshot_gap" }` — the requested `since` sequence fell
426
- * behind the oldest buffered event; the client must REST-backfill.
427
- */
428
- export const ReleaseStreamMessageSchema = z.discriminatedUnion("type", [
429
- z.object({ type: z.literal("ready"), seq: z.number().int() }),
430
- z.object({
431
- type: z.literal("release.created"),
432
- seq: z.number().int(),
433
- release: z.record(z.string(), z.unknown()),
434
- }),
435
- z.object({ type: z.literal("snapshot_gap") }),
436
- ]);