@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,674 +0,0 @@
1
- import { z } from "zod";
2
- import {
3
- SOURCE_TYPES,
4
- SOURCE_DISCOVERY,
5
- SOURCE_FETCH_PRIORITIES,
6
- } from "@buildinternet/releases-core/source-enums";
7
- import { KIND_VALUES } from "@buildinternet/releases-core/kinds";
8
- import {
9
- ListResponseSchema,
10
- NoticeSchema,
11
- ReleaseItemSchema,
12
- ReleaseSummaryItemSchema,
13
- } from "./shared.js";
14
-
15
- export const SourceTypeSchema = z.enum(SOURCE_TYPES);
16
- export const SourceDiscoverySchema = z.enum(SOURCE_DISCOVERY);
17
- export const SourceFetchPrioritySchema = z.enum(SOURCE_FETCH_PRIORITIES);
18
-
19
- /**
20
- * Per-source row used in list/embedded contexts (e.g. nested inside OrgDetail).
21
- * Most fields are optional — embedded shapes (org detail) only carry the
22
- * subset needed for that view.
23
- */
24
- export const SourceListItemSchema = z.object({
25
- id: z.string().optional(),
26
- slug: z.string(),
27
- name: z.string(),
28
- type: SourceTypeSchema,
29
- url: z.string().optional(),
30
- // `orgSlug` is populated on the standalone `/v1/sources` list path; the
31
- // `OrgDetail.sources` embedded path omits it (the parent already names the org).
32
- orgSlug: z.string().nullable().optional(),
33
- releaseCount: z.number().int().min(0),
34
- latestVersion: z.string().nullable(),
35
- latestDate: z.string().nullable(),
36
- latestAddedAt: z.string().nullable().optional(),
37
- isPrimary: z.boolean().optional(),
38
- isHidden: z.boolean().optional(),
39
- /**
40
- * How the row was created. Optional on the wire so older API responses
41
- * (mid-deploy or pinned old workers) degrade gracefully — consumers that
42
- * see `undefined` should treat it as `"curated"`.
43
- */
44
- discovery: SourceDiscoverySchema.optional(),
45
- fetchPriority: SourceFetchPrioritySchema.nullable().optional(),
46
- lastFetchedAt: z.string().nullable().optional(),
47
- lastPolledAt: z.string().nullable().optional(),
48
- changeDetectedAt: z.string().nullable().optional(),
49
- consecutiveNoChange: z.number().int().nullable().optional(),
50
- consecutiveErrors: z.number().int().nullable().optional(),
51
- nextFetchAfter: z.string().nullable().optional(),
52
- medianGapDays: z.number().nullable().optional(),
53
- lastRetieredAt: z.string().nullable().optional(),
54
- metadata: z.string().nullable().optional(),
55
- productName: z.string().nullable().optional(),
56
- productSlug: z.string().nullable().optional(),
57
- kind: z.enum(KIND_VALUES).nullable().optional(),
58
- // GitHub stargazer count. `nullable().optional()` (the house idiom for these
59
- // shapes): non-github sources and older responses omit it; a fetched row may
60
- // carry `null`. Consumers treat null/undefined as "unknown".
61
- stars: z.number().int().min(0).nullable().optional(),
62
- starsFetchedAt: z.string().nullable().optional(),
63
- });
64
-
65
- /**
66
- * Canonical row returned by `GET /v1/sources` (list). Superset of
67
- * `SourceListItem` with required `id` / `orgName` / `orgSlug` fields used by
68
- * the CLI `list` command.
69
- */
70
- export const SourceWithOrgSchema = z.object({
71
- id: z.string(),
72
- name: z.string(),
73
- slug: z.string(),
74
- type: SourceTypeSchema,
75
- url: z.string(),
76
- orgName: z.string().nullable(),
77
- orgSlug: z.string().nullable(),
78
- productName: z.string().nullable(),
79
- productSlug: z.string().nullable(),
80
- isPrimary: z.boolean(),
81
- isHidden: z.boolean().nullable(),
82
- discovery: SourceDiscoverySchema.optional(),
83
- metadata: z.string().nullable(),
84
- releaseCount: z.number().int().min(0),
85
- latestVersion: z.string().nullable(),
86
- latestDate: z.string().nullable(),
87
- lastFetchedAt: z.string().nullable(),
88
- lastPolledAt: z.string().nullable(),
89
- fetchPriority: SourceFetchPrioritySchema.nullable(),
90
- changeDetectedAt: z.string().nullable(),
91
- consecutiveNoChange: z.number().int().nullable(),
92
- consecutiveErrors: z.number().int().nullable(),
93
- nextFetchAfter: z.string().nullable(),
94
- medianGapDays: z.number().nullable(),
95
- lastRetieredAt: z.string().nullable(),
96
- kind: z.enum(KIND_VALUES).nullable().optional(),
97
- // GitHub stargazer count. `nullable().optional()` (the house idiom for these
98
- // shapes): non-github sources and older responses omit it; a fetched row may
99
- // carry `null`. Consumers treat null/undefined as "unknown".
100
- stars: z.number().int().min(0).nullable().optional(),
101
- starsFetchedAt: z.string().nullable().optional(),
102
- });
103
-
104
- export const SourceListResponseSchema = ListResponseSchema(SourceWithOrgSchema);
105
-
106
- /**
107
- * `GET /v1/sources` returns a bare array by default and an envelope when
108
- * `?envelope=true` is passed. The OpenAPI spec advertises the union so
109
- * either client expectation is documented.
110
- */
111
- export const SourceListResultSchema = z.union([
112
- z.array(SourceWithOrgSchema),
113
- SourceListResponseSchema,
114
- ]);
115
-
116
- const SourceDetailSummariesSchema = z.object({
117
- rolling: ReleaseSummaryItemSchema.nullable(),
118
- monthly: z.array(ReleaseSummaryItemSchema),
119
- });
120
-
121
- /**
122
- * Cursor pagination shape for the source detail's embedded release feed.
123
- * Mirrors `OrgFeedPaginationSchema` and `CollectionFeedPaginationSchema` —
124
- * release lists are feed-shaped (append-only, mutates between calls), so they
125
- * use cursor pagination per the AGENTS.md convention.
126
- */
127
- export const SourceFeedPaginationSchema = z.object({
128
- nextCursor: z.string().nullable(),
129
- limit: z.number().int().min(1),
130
- });
131
-
132
- /**
133
- * Resolved attribution block returned alongside a source row. `id` is
134
- * additive vs the legacy `{ slug, name }` shape — older clients that ignored
135
- * it still parse cleanly. `productId` / `productSlug` are sibling top-level
136
- * fields on the source response (kept flat to mirror `orgId`), not nested
137
- * inside this block.
138
- */
139
- export const SourceOrgRefSchema = z.object({
140
- id: z.string(),
141
- slug: z.string(),
142
- name: z.string(),
143
- });
144
-
145
- export const SourceDetailSchema = z.object({
146
- id: z.string(),
147
- slug: z.string(),
148
- name: z.string(),
149
- type: SourceTypeSchema,
150
- url: z.string(),
151
- orgId: z.string().nullable(),
152
- productId: z.string().nullable(),
153
- productSlug: z.string().nullable(),
154
- // Hidden sources are reachable by direct URL but excluded from listings,
155
- // sitemap, and AI features. On-demand lookups and admin-suppressed rows
156
- // set this true; canonical curated/agent sources leave it false.
157
- isHidden: z.boolean(),
158
- // Pairs with `isHidden` to distinguish admin-suppressed rows (`curated` /
159
- // `agent` + hidden) from rows materialized by `/v1/lookups` (`on_demand`).
160
- // Optional for graceful degradation against older API responses.
161
- discovery: SourceDiscoverySchema.optional(),
162
- isPrimary: z.boolean(),
163
- metadata: z.string(),
164
- changelogUrl: z.string().nullable().optional(),
165
- hasChangelogFile: z.boolean().optional(),
166
- org: SourceOrgRefSchema.nullable(),
167
- releaseCount: z.number().int().min(0),
168
- releasesLast30Days: z.number().int().min(0),
169
- avgReleasesPerWeek: z.number(),
170
- latestVersion: z.string().nullable(),
171
- latestDate: z.string().nullable(),
172
- lastFetchedAt: z.string().nullable(),
173
- lastPolledAt: z.string().nullable(),
174
- // #1969: additive so pinned old workers/clients degrade gracefully.
175
- changeDetectedAt: z.string().nullable().optional(),
176
- trackingSince: z.string(),
177
- releases: z.array(ReleaseItemSchema),
178
- pagination: SourceFeedPaginationSchema,
179
- summaries: SourceDetailSummariesSchema,
180
- kind: z.enum(KIND_VALUES).nullable().optional(),
181
- // GitHub stargazer count. `nullable().optional()` (the house idiom for these
182
- // shapes): non-github sources and older responses omit it; a fetched row may
183
- // carry `null`. Consumers treat null/undefined as "unknown".
184
- stars: z.number().int().min(0).nullable().optional(),
185
- starsFetchedAt: z.string().nullable().optional(),
186
- notice: NoticeSchema.nullable().optional(),
187
- });
188
-
189
- /**
190
- * Response returned by `POST /v1/sources` and `PATCH /v1/sources/:slug`.
191
- *
192
- * Pre-#794 these endpoints returned the bare drizzle row, leaving callers to
193
- * round-trip a separate `GET` to confirm the resolved org/product attribution.
194
- * Now they return the same source row plus a resolved `org { id, slug, name }`
195
- * block and `productSlug`, so an agent can answer "did the write take?" from
196
- * the response alone.
197
- *
198
- * Wire fields are loosely-typed (`z.unknown()`) for the timestamps/counters
199
- * that aren't load-bearing for callers — the row is large and we don't want
200
- * to hand-mirror every column. Stable, agent-relevant fields are typed.
201
- */
202
- export const SourceMutationResponseSchema = z.looseObject({
203
- id: z.string(),
204
- slug: z.string(),
205
- name: z.string(),
206
- type: SourceTypeSchema,
207
- url: z.string(),
208
- orgId: z.string().nullable(),
209
- productId: z.string().nullable(),
210
- productSlug: z.string().nullable(),
211
- org: SourceOrgRefSchema.nullable(),
212
- metadata: z.string().nullable(),
213
- isPrimary: z.boolean().nullable().optional(),
214
- isHidden: z.boolean().nullable().optional(),
215
- discovery: SourceDiscoverySchema.optional(),
216
- createdAt: z.string().optional(),
217
- kind: z.enum(KIND_VALUES).nullable().optional(),
218
- });
219
-
220
- /**
221
- * Response from `POST /v1/sources/appstore` — materializes an App Store listing
222
- * into a curated Org → Product → Source → first Release (modeled on the GitHub
223
- * coordinate `LookupResponse`).
224
- *
225
- * Unlike `SourceMutationResponse`, the `source` here is the **bare inserted (or
226
- * idempotently looked-up) drizzle row** the materialize handler returns verbatim:
227
- * no resolved `org { id, slug, name }` block and no `productSlug`. `loose` so the
228
- * untyped timestamp/counter columns on the row pass through.
229
- *
230
- * `status: "indexed"` is a brand-new source (HTTP 201); `"existing"` is the
231
- * idempotent hit on a prior materialize of the same trackId (HTTP 200).
232
- */
233
- export const AppStoreMaterializeResponseSchema = z.object({
234
- status: z.enum(["indexed", "existing"]),
235
- source: z.looseObject({
236
- id: z.string(),
237
- slug: z.string(),
238
- name: z.string(),
239
- type: SourceTypeSchema,
240
- url: z.string(),
241
- orgId: z.string().nullable(),
242
- productId: z.string().nullable(),
243
- metadata: z.string().nullable(),
244
- kind: z.enum(KIND_VALUES).nullable().optional(),
245
- discovery: SourceDiscoverySchema.optional(),
246
- isHidden: z.boolean().nullable().optional(),
247
- createdAt: z.string().optional(),
248
- }),
249
- releaseCount: z.number(),
250
- });
251
-
252
- /** Body accepted by `PATCH /v1/sources/:slug`. */
253
- export const SourcePatchInputSchema = z.object({
254
- name: z.string().optional(),
255
- url: z.string().optional(),
256
- type: SourceTypeSchema.optional(),
257
- slug: z.string().optional(),
258
- metadata: z.string().optional(),
259
- orgId: z.string().nullable().optional(),
260
- productId: z.string().nullable().optional(),
261
- lastFetchedAt: z.string().nullable().optional(),
262
- lastContentHash: z.string().nullable().optional(),
263
- fetchPriority: SourceFetchPrioritySchema.optional(),
264
- consecutiveNoChange: z.number().int().optional(),
265
- consecutiveErrors: z.number().int().optional(),
266
- nextFetchAfter: z.string().nullable().optional(),
267
- isPrimary: z.boolean().optional(),
268
- isHidden: z.boolean().optional(),
269
- changeDetectedAt: z.string().nullable().optional(),
270
- lastPolledAt: z.string().nullable().optional(),
271
- kind: z.enum(KIND_VALUES).nullable().optional(),
272
- /** Admin-only: promote or demote the source's discovery status (curated/agent/on_demand). */
273
- discovery: SourceDiscoverySchema.optional(),
274
- notice: NoticeSchema.nullable().optional(),
275
- });
276
-
277
- /** Body accepted by `POST /v1/sources`. */
278
- export const CreateSourceBodySchema = z.object({
279
- name: z.string().min(1),
280
- url: z.string().min(1),
281
- type: SourceTypeSchema.optional(),
282
- slug: z.string().optional(),
283
- orgId: z.string().optional(),
284
- orgSlug: z.string().optional(),
285
- /**
286
- * Either accepted; `productId` wins when both are supplied. `productSlug`
287
- * resolves within the requested org (slug uniqueness is per-org). The
288
- * legacy `productId` ingestion path is preserved for callers that already
289
- * resolve products client-side; new agent flows should pass `productSlug`.
290
- */
291
- productId: z.string().optional(),
292
- productSlug: z.string().optional(),
293
- metadata: z.string().optional(),
294
- isPrimary: z.boolean().optional(),
295
- kind: z.enum(KIND_VALUES).nullable().optional(),
296
- });
297
-
298
- export const ChangelogFileSummarySchema = z.object({
299
- path: z.string(),
300
- filename: z.string(),
301
- url: z.string(),
302
- bytes: z.number().int().min(0),
303
- fetchedAt: z.string(),
304
- });
305
-
306
- export const SourceChangelogResponseSchema = z.object({
307
- path: z.string(),
308
- filename: z.string(),
309
- url: z.string(),
310
- rawUrl: z.string(),
311
- content: z.string(),
312
- bytes: z.number().int().min(0),
313
- fetchedAt: z.string(),
314
- /** Character offset of the first character in `content` within the full file. */
315
- offset: z.number().int().min(0),
316
- /** The limit (in chars) that was applied to produce this slice. */
317
- limit: z.number().int().min(0),
318
- /** Next offset to request for the next slice, or null if `content` is the tail. */
319
- nextOffset: z.number().int().nullable(),
320
- /** Total length of the full file in characters. */
321
- totalChars: z.number().int().min(0),
322
- /** Requested token budget when in token mode (cl100k_base). */
323
- tokens: z.number().int().optional(),
324
- /** Encoded token count of the returned `content`. Set in token mode. */
325
- sliceTokens: z.number().int().optional(),
326
- /** Full-file token count (cl100k_base). Always populated. */
327
- totalTokens: z.number().int().min(0),
328
- /** True when the upstream file exceeded the 1MB cap and content was sliced. */
329
- truncated: z.boolean(),
330
- /** Byte offset where the file was truncated, or null when not truncated. */
331
- truncatedAt: z.number().int().nullable(),
332
- /**
333
- * Index of every changelog file tracked for this source (root plus any
334
- * discovered per-package files). Always present even for single-file
335
- * sources so clients can lazily render a file picker.
336
- */
337
- files: z.array(ChangelogFileSummarySchema),
338
- });
339
-
340
- // ── Source activity (/sources/:slug/activity, /orgs/:orgSlug/sources/:sourceSlug/activity) ──
341
-
342
- const SourceActivityWeeklyBucketSchema = z.object({
343
- weekStart: z.string(),
344
- count: z.number().int().min(0),
345
- earliestVersion: z.string().nullable(),
346
- latestVersion: z.string().nullable(),
347
- });
348
-
349
- /**
350
- * Response shape for `GET /v1/sources/:slug/activity` and the org-scoped twin.
351
- * Returns week-bucketed release counts for the full tracking lifetime of the source.
352
- * Optional `?from=YYYY-MM-DD` and `?to=YYYY-MM-DD` narrow the range.
353
- */
354
- export const SourceActivityResponseSchema = z.object({
355
- source: z.object({
356
- slug: z.string(),
357
- name: z.string(),
358
- orgSlug: z.string().nullable(),
359
- orgName: z.string().nullable(),
360
- }),
361
- range: z.object({ from: z.string(), to: z.string() }),
362
- weeklyBuckets: z.array(SourceActivityWeeklyBucketSchema),
363
- });
364
-
365
- // ── Source heatmap (/sources/:slug/heatmap, /orgs/:orgSlug/sources/:sourceSlug/heatmap) ──
366
-
367
- /**
368
- * Response shape for `GET /v1/sources/:slug/heatmap` and the org-scoped twin.
369
- * Returns daily release counts for the trailing 365 days — contribution-graph
370
- * visualization for the source detail page.
371
- */
372
- export const SourceHeatmapResponseSchema = z.object({
373
- source: z.object({ slug: z.string(), name: z.string() }),
374
- range: z.object({ from: z.string(), to: z.string() }),
375
- dailyCounts: z.array(z.object({ date: z.string(), count: z.number().int().min(0) })),
376
- total: z.number().int().min(0),
377
- });
378
-
379
- // ── Source known releases (/sources/:slug/known-releases, /orgs/:orgSlug/…) ──
380
-
381
- /**
382
- * Single row returned inside `GET /v1/sources/:slug/known-releases`. Minimal
383
- * identifier set used by the incremental parsing agent to skip already-known
384
- * versions without fetching full content.
385
- */
386
- export const SourceKnownReleaseItemSchema = z.object({
387
- version: z.string().nullable(),
388
- title: z.string(),
389
- publishedAt: z.string().nullable(),
390
- });
391
-
392
- /**
393
- * Response shape for `GET /v1/sources/:slug/known-releases`. Returns the
394
- * N most-recent non-suppressed releases (default N=10, max 500), ordered
395
- * by `publishedAt` descending. Accepts `?limit=N`.
396
- */
397
- export const SourceKnownReleasesResponseSchema = z.array(SourceKnownReleaseItemSchema);
398
-
399
- // ── Source recent releases (/sources/:slug/recent-releases, /orgs/:orgSlug/…) ──
400
-
401
- /**
402
- * Response shape for `GET /v1/sources/:slug/recent-releases`. Returns the
403
- * full release rows (non-suppressed, published at or after `?cutoff=`) ordered
404
- * by `publishedAt` descending. Used by the summarization agent to retrieve the
405
- * release window it needs to summarize. `?cutoff=` is required (ISO-8601 date
406
- * string); missing `?cutoff=` returns 400.
407
- */
408
- export const SourceRecentReleasesResponseSchema = z.array(
409
- z.looseObject({
410
- id: z.string(),
411
- sourceId: z.string(),
412
- version: z.string().nullable(),
413
- title: z.string(),
414
- content: z.string(),
415
- url: z.string().nullable(),
416
- publishedAt: z.string().nullable(),
417
- fetchedAt: z.string().optional(),
418
- }),
419
- );
420
-
421
- // ── Source sessions (/sources/:slug/sessions) ──
422
-
423
- /**
424
- * Response shape for `GET /v1/sources/:slug/sessions`. Returns the active
425
- * discovery session (if any) touching this source. The session object is the
426
- * live DO state blob from the `StatusHub` Durable Object. Returns `{ sessions:
427
- * [] }` when no active session references this source.
428
- */
429
- export const SourceSessionsResponseSchema = z.object({
430
- sessions: z.array(z.record(z.string(), z.unknown())),
431
- });
432
-
433
- // ── Source summaries (/sources/:slug/summaries) ──
434
-
435
- /**
436
- * Full summary row as stored in `release_summaries`, returned by
437
- * `GET /v1/sources/:slug/summaries`. Filter by `?type=rolling|monthly`,
438
- * `?year=`, `?month=`.
439
- */
440
- export const SourceSummaryRowSchema = z.object({
441
- id: z.string().optional(),
442
- sourceId: z.string(),
443
- orgId: z.string().nullable(),
444
- type: z.enum(["rolling", "monthly"]),
445
- year: z.number().int().nullable(),
446
- month: z.number().int().nullable(),
447
- windowDays: z.number().int().nullable(),
448
- summary: z.string(),
449
- releaseCount: z.number().int().min(0),
450
- generatedAt: z.string(),
451
- });
452
-
453
- export const SourceSummariesResponseSchema = z.array(SourceSummaryRowSchema);
454
-
455
- /**
456
- * Body accepted by `POST /v1/sources/:slug/summaries`.
457
- *
458
- * `month` is calendar-bounded (1..12) and `windowDays` must be a positive
459
- * integer when present — silently dropping wrong-typed values masks client
460
- * bugs, so the validator rejects them explicitly. `year` is not bound-checked
461
- * (any cutoff would be arbitrary).
462
- */
463
- export const CreateSourceSummaryBodySchema = z.object({
464
- type: z.enum(["rolling", "monthly"]),
465
- year: z.number().int().nullable().optional(),
466
- month: z.number().int().min(1).max(12).nullable().optional(),
467
- windowDays: z.number().int().min(1).nullable().optional(),
468
- summary: z.string().min(1),
469
- releaseCount: z.number().int().min(0),
470
- });
471
-
472
- /** Response for `POST /v1/sources/:slug/summaries` (upsert). */
473
- export const CreateSourceSummaryResponseSchema = z.object({
474
- ok: z.literal(true),
475
- });
476
-
477
- // ── Source fetch trigger (POST /sources/:slug/fetch) ──
478
-
479
- /**
480
- * Response shape for `POST /v1/sources/:slug/fetch`. Three branches:
481
- * - Feed/GitHub/scraped-with-feed sources: `{ fetched: true, releasesInserted, … }`
482
- * - Scrape/agent sources (flagged for CLI pickup): `{ queued: true, type: "flagged" }`
483
- * - Render dry-run probe (`?dryRun=true` on a client-rendered scrape source):
484
- * `{ renderCheck: true, rendered, candidateCount, sampleUrls, … }`
485
- */
486
- export const SourceFetchResponseSchema = z.union([
487
- z.looseObject({ fetched: z.literal(true) }),
488
- z.object({ queued: z.literal(true), type: z.string() }),
489
- // Render dry-run probe (#1528): renders a client-rendered scrape source's
490
- // index once and reports candidate links found, without the managed-agent
491
- // extraction loop.
492
- z.looseObject({
493
- renderCheck: z.literal(true),
494
- status: z.enum(["dry_run", "error"]),
495
- rendered: z.boolean(),
496
- candidateCount: z.number().int(),
497
- sampleUrls: z.array(z.string()),
498
- durationMs: z.number().int(),
499
- error: z.string().optional(),
500
- }),
501
- ]);
502
-
503
- // ── Source content-hash check (POST /sources/:slug/content-hash) ──
504
-
505
- /** Response for `POST /v1/sources/:slug/content-hash`. */
506
- export const SourceContentHashResponseSchema = z.union([
507
- z.object({ unchanged: z.literal(true) }),
508
- z.object({ unchanged: z.literal(false) }),
509
- ]);
510
-
511
- /** Body for `POST /v1/sources/:slug/content-hash`. */
512
- export const SourceContentHashBodySchema = z.object({
513
- contentHash: z.string().min(1),
514
- });
515
-
516
- // ── Changelog token backfill (PATCH /sources/:slug/changelog/tokens) ──
517
-
518
- /** Response for `PATCH /v1/sources/:slug/changelog/tokens`. */
519
- export const ChangelogTokensResponseSchema = z.object({
520
- path: z.string(),
521
- oldTokens: z.number().int().nullable(),
522
- tokens: z.number().int().min(0),
523
- });
524
-
525
- // ── Source metadata merge (PATCH /sources/:slug/metadata) ──
526
-
527
- /** Response for `PATCH /v1/sources/:slug/metadata`. Echoes the merged metadata object. */
528
- export const SourceMetadataResponseSchema = z.object({
529
- metadata: z.record(z.string(), z.unknown()),
530
- });
531
-
532
- // ── Changelog probe (POST /sources/:slug/changelog/probe) ──
533
-
534
- /**
535
- * A discovered CHANGELOG path returned by the probe. Mirrors
536
- * `DiscoveredChangelogPath` from `@releases/adapters/github-discovery`:
537
- * `origin` tags where the path came from (repo root, a workspace package, or
538
- * an explicit `metadata.changelogPaths` override) and `exists` is true when a
539
- * directory listing confirmed the file on HEAD.
540
- */
541
- export const DiscoveredChangelogPathSchema = z.object({
542
- path: z.string(),
543
- origin: z.enum(["root", "workspace", "override"]),
544
- exists: z.boolean(),
545
- });
546
-
547
- /** Response for `POST /v1/sources/:slug/changelog/probe`. */
548
- export const ChangelogProbeResponseSchema = z.object({
549
- sourceId: z.string(),
550
- sourceSlug: z.string(),
551
- url: z.string(),
552
- paths: z.array(DiscoveredChangelogPathSchema),
553
- });
554
-
555
- // ── Delete source (DELETE /sources/:slug) ──
556
-
557
- /**
558
- * Response for `DELETE /v1/sources/:slug`. Two shapes:
559
- * - Soft delete: `{ deleted: true, deletedAt: "<iso>" }`
560
- * - Hard delete (`?hard=true`): `{ deleted: true, hard: true }`
561
- */
562
- export const DeleteSourceResponseSchema = z.union([
563
- z.object({ deleted: z.literal(true), deletedAt: z.string() }),
564
- z.object({ deleted: z.literal(true), hard: z.literal(true) }),
565
- ]);
566
-
567
- // ── Delete source releases (DELETE /sources/:slug/releases) ──
568
-
569
- /**
570
- * Response for `DELETE /v1/sources/:slug/releases`. Two shapes:
571
- * - Soft (`?hard` absent): `{ suppressed: N }` — releases hidden, not deleted
572
- * - Hard (`?hard=true`): `{ deleted: N, hard: true }`
573
- */
574
- export const DeleteSourceReleasesResponseSchema = z.union([
575
- z.object({ suppressed: z.number().int().min(0) }),
576
- z.object({ deleted: z.number().int().min(0), hard: z.literal(true) }),
577
- ]);
578
-
579
- // ── Single release insert (POST /sources/:slug/releases) ──
580
-
581
- /**
582
- * Response for `POST /v1/sources/:slug/releases`. Returns the inserted release
583
- * row (201) or `{ skipped: true }` (200) on URL conflict.
584
- */
585
- export const InsertReleaseResponseSchema = z.union([
586
- z.looseObject({
587
- id: z.string(),
588
- sourceId: z.string(),
589
- title: z.string(),
590
- }),
591
- z.object({ skipped: z.literal(true) }),
592
- ]);
593
-
594
- // ── Batch release insert (POST /sources/:slug/releases/batch) ──
595
-
596
- /** Response for `POST /v1/sources/:slug/releases/batch`. */
597
- export const BatchReleasesResponseSchema = z.object({
598
- inserted: z.number().int().min(0),
599
- total: z.number().int().min(0),
600
- });
601
-
602
- // ── Raw page snapshot (POST /sources/:slug/raw-snapshot) ──
603
-
604
- /**
605
- * Response for `POST /v1/sources/:slug/raw-snapshot` (#1283). On a store or a
606
- * content-hash dedup hit, all fields are present; `stored` is `false` for the
607
- * dedup case. When the `RAW_SNAPSHOTS` bucket is unbound the capture soft-fails
608
- * with `{ stored: false, reason: "no_binding" }` and the snapshot fields are
609
- * omitted — capture is best-effort and never errors ingest.
610
- */
611
- export const RawSnapshotResponseSchema = z.object({
612
- stored: z.boolean(),
613
- r2Key: z.string().optional(),
614
- contentHash: z.string().optional(),
615
- bytes: z.number().int().min(0).optional(),
616
- // Only set on the soft-fail path; bounded so consumers can branch on it.
617
- reason: z.enum(["no_binding"]).optional(),
618
- });
619
-
620
- // ── Oversized changelog files (GET /sources/changelog-files/oversized) ──
621
-
622
- /**
623
- * Row returned by `GET /v1/sources/changelog-files/oversized`. Each row is a
624
- * changelog file whose content length exceeds `?minBytes=` (default 256 KB).
625
- * Used by `scripts/backfill-changelog-tokens.ts` to find rows with estimated
626
- * (not exact) token counts.
627
- */
628
- export const OversizedChangelogFileRowSchema = z.object({
629
- sourceId: z.string(),
630
- sourceSlug: z.string(),
631
- sourceName: z.string(),
632
- orgSlug: z.string(),
633
- path: z.string(),
634
- filename: z.string(),
635
- bytes: z.number().int().min(0),
636
- tokens: z.number().int().nullable(),
637
- fetchedAt: z.string(),
638
- });
639
-
640
- export const OversizedChangelogFilesResponseSchema = z.array(OversizedChangelogFileRowSchema);
641
-
642
- // ── Fetchable sources (GET /sources/fetchable) ──
643
-
644
- /**
645
- * Response for `GET /v1/sources/fetchable`. Returns raw source rows matching
646
- * the requested fetch mode (`?mode=unfetched|stale|retry_errors|all`).
647
- * Accepts `?staleHours=N` when `mode=stale`.
648
- */
649
- export const FetchableSourcesResponseSchema = z.array(
650
- z.looseObject({
651
- id: z.string(),
652
- slug: z.string(),
653
- name: z.string(),
654
- type: SourceTypeSchema,
655
- url: z.string(),
656
- metadata: z.string().nullable(),
657
- }),
658
- );
659
-
660
- // ── Feed sources (GET /sources/feeds) ──
661
-
662
- /**
663
- * Response for `GET /v1/sources/feeds`. Returns visible source rows where
664
- * `metadata.feedUrl` is set and `fetchPriority != 'paused'`.
665
- */
666
- export const FeedSourcesResponseSchema = FetchableSourcesResponseSchema;
667
-
668
- // ── Changed sources (GET /sources/changes) ──
669
-
670
- /**
671
- * Response for `GET /v1/sources/changes`. Returns visible source rows that
672
- * have a non-null `changeDetectedAt` — the set flagged for CLI pickup.
673
- */
674
- export const ChangedSourcesResponseSchema = FetchableSourcesResponseSchema;