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