@buildinternet/releases-api-types 0.15.0 → 0.17.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.
package/src/api-types.ts CHANGED
@@ -30,6 +30,28 @@ import type {
30
30
  CreateOrgBodySchema,
31
31
  UpdateOrgBodySchema,
32
32
  OrgDetailSchema,
33
+ OrgCatalogItemSchema,
34
+ OrgCatalogResponseSchema,
35
+ OrgCollectionsResponseSchema,
36
+ AddOrgAccountBodySchema,
37
+ IgnoredUrlItemSchema,
38
+ OrgIgnoredUrlsResponseSchema,
39
+ AddIgnoredUrlBodySchema,
40
+ AddIgnoredUrlResponseSchema,
41
+ DeleteIgnoredUrlResponseSchema,
42
+ OrgTagsBodySchema,
43
+ OrgTagsMutationResponseSchema,
44
+ CreateTagBodySchema,
45
+ TagRowSchema,
46
+ OrgActivityResponseSchema,
47
+ OrgHeatmapResponseSchema,
48
+ OrgSparklinesResponseSchema,
49
+ OrgReleaseItemSchema,
50
+ OrgFeedPaginationSchema,
51
+ OrgReleasesFeedResponseSchema,
52
+ OrgRecentReleaseItemSchema,
53
+ OrgRecentReleasesResponseSchema,
54
+ DeleteOrgAccountResponseSchema,
33
55
  } from "./schemas/orgs.js";
34
56
  import type {
35
57
  SourceListItemSchema,
@@ -43,6 +65,31 @@ import type {
43
65
  CreateSourceBodySchema,
44
66
  ChangelogFileSummarySchema,
45
67
  SourceChangelogResponseSchema,
68
+ SourceActivityResponseSchema,
69
+ SourceHeatmapResponseSchema,
70
+ SourceKnownReleaseItemSchema,
71
+ SourceKnownReleasesResponseSchema,
72
+ SourceRecentReleasesResponseSchema,
73
+ SourceSessionsResponseSchema,
74
+ SourceSummaryRowSchema,
75
+ SourceSummariesResponseSchema,
76
+ CreateSourceSummaryBodySchema,
77
+ CreateSourceSummaryResponseSchema,
78
+ SourceFetchResponseSchema,
79
+ SourceContentHashResponseSchema,
80
+ SourceContentHashBodySchema,
81
+ ChangelogTokensResponseSchema,
82
+ SourceMetadataResponseSchema,
83
+ ChangelogProbeResponseSchema,
84
+ DeleteSourceResponseSchema,
85
+ DeleteSourceReleasesResponseSchema,
86
+ InsertReleaseResponseSchema,
87
+ BatchReleasesResponseSchema,
88
+ OversizedChangelogFileRowSchema,
89
+ OversizedChangelogFilesResponseSchema,
90
+ FetchableSourcesResponseSchema,
91
+ FeedSourcesResponseSchema,
92
+ ChangedSourcesResponseSchema,
46
93
  } from "./schemas/sources.js";
47
94
  import type {
48
95
  ProductRowSchema,
@@ -57,7 +104,115 @@ import type {
57
104
  ProductAdoptDryRunSchema,
58
105
  ProductAdoptResponseSchema,
59
106
  ProductDeleteResponseSchema,
107
+ ProductTagsListResponseSchema,
108
+ ProductTagsBodySchema,
109
+ ProductTagsMutationResponseSchema,
60
110
  } from "./schemas/products.js";
111
+ import type {
112
+ ReleaseLatestSourceSchema,
113
+ ReleaseLatestItemSchema,
114
+ ReleaseLatestResponseSchema,
115
+ ReleaseCoverageRowSchema,
116
+ ReleaseCoverageResponseSchema,
117
+ LinkReleaseCoverageBodySchema,
118
+ LinkReleaseCoverageResponseSchema,
119
+ UnlinkReleaseCoverageResponseSchema,
120
+ ReleaseWithMediaRowSchema,
121
+ ReleasesWithMediaResponseSchema,
122
+ ReleaseDetailOrgSchema,
123
+ ReleaseDetailResponseSchema,
124
+ UpdateReleaseBodySchema,
125
+ ReleasePatchResponseSchema,
126
+ ReleaseDeleteResponseSchema,
127
+ ReleaseSuppressResponseSchema,
128
+ ReleaseUnsuppressResponseSchema,
129
+ ReleaseSuppressBodySchema,
130
+ ReleaseStreamMessageSchema,
131
+ } from "./schemas/releases.js";
132
+ import type {
133
+ LookupStatusSchema,
134
+ LookupBodySchema,
135
+ LookupSourceSchema,
136
+ LookupReleaseSchema,
137
+ LookupRelatedOrgSchema,
138
+ LookupResponseSchema,
139
+ LookupSourceBySlugResponseSchema,
140
+ LookupProductBySlugResponseSchema,
141
+ DomainLookupOrgSchema,
142
+ DomainLookupProductSchema,
143
+ DomainLookupResponseSchema,
144
+ } from "./schemas/lookups.js";
145
+ import type {
146
+ SearchOrgHitSchema,
147
+ SearchCatalogHitSchema,
148
+ SearchSourceHitSchema,
149
+ SearchReleaseHitSchema,
150
+ SearchChunkHitSchema,
151
+ LookupResultPayloadSchema,
152
+ UnifiedSearchResponseSchema,
153
+ } from "./schemas/search.js";
154
+ import type {
155
+ TaxonomyOrgSchema,
156
+ TaxonomyProductSchema,
157
+ CategoryListItemSchema,
158
+ CategoryListResponseSchema,
159
+ CategoryDetailSchema,
160
+ UpdateCategoryRequestSchema,
161
+ UpdateCategoryResponseSchema,
162
+ CategoryFeedPaginationSchema,
163
+ CategoryReleasesResponseSchema,
164
+ TagDetailSchema,
165
+ } from "./schemas/taxonomy.js";
166
+ import type {
167
+ StatsSourceActivitySchema,
168
+ StatsRecentActivitySchema,
169
+ StatsResponseSchema,
170
+ } from "./schemas/stats.js";
171
+ import type { SitemapSourceSchema, SitemapPayloadSchema } from "./schemas/sitemap.js";
172
+ import type {
173
+ RelatedScopeSchema,
174
+ RelatedReleaseThumbnailSchema,
175
+ RelatedReleaseSourceSchema,
176
+ RelatedReleaseItemSchema,
177
+ RelatedSourceItemSchema,
178
+ RelatedReleasesOkResponseSchema,
179
+ RelatedReleasesDegradedResponseSchema,
180
+ RelatedReleasesResponseSchema,
181
+ RelatedSourcesOkResponseSchema,
182
+ RelatedSourcesDegradedResponseSchema,
183
+ RelatedSourcesResponseSchema,
184
+ } from "./schemas/related.js";
185
+ import type {
186
+ CollectionMemberOrgSchema,
187
+ CollectionListItemSchema,
188
+ CollectionListResponseSchema,
189
+ CollectionDetailSchema,
190
+ CollectionReleaseItemSchema,
191
+ CollectionFeedPaginationSchema,
192
+ CollectionReleasesResponseSchema,
193
+ CollectionRowSchema,
194
+ CreateCollectionRequestSchema,
195
+ UpdateCollectionRequestSchema,
196
+ CollectionMemberInputSchema,
197
+ AddCollectionMemberRequestSchema,
198
+ ReplaceCollectionMembersRequestSchema,
199
+ ResolvedCollectionMemberSchema,
200
+ ReplaceCollectionMembersResponseSchema,
201
+ AddCollectionMemberResponseSchema,
202
+ } from "./schemas/collections.js";
203
+ import type {
204
+ OrgOverviewResponseSchema,
205
+ IncomingOverviewCitationSchema,
206
+ RegenerateOverviewBodySchema,
207
+ RegenerateOverviewResponseSchema,
208
+ ProductOverviewResponseSchema,
209
+ OverviewInputsCheckResponseSchema,
210
+ OverviewInputsFullResponseSchema,
211
+ OverviewInputsResponseSchema,
212
+ PlaybookResponseSchema,
213
+ UpdatePlaybookNotesBodySchema,
214
+ UpdatePlaybookNotesResponseSchema,
215
+ } from "./schemas/overviews.js";
61
216
 
62
217
  export {
63
218
  MediaItemSchema,
@@ -81,6 +236,28 @@ export {
81
236
  CreateOrgBodySchema,
82
237
  UpdateOrgBodySchema,
83
238
  OrgDetailSchema,
239
+ OrgCatalogItemSchema,
240
+ OrgCatalogResponseSchema,
241
+ OrgCollectionsResponseSchema,
242
+ AddOrgAccountBodySchema,
243
+ IgnoredUrlItemSchema,
244
+ OrgIgnoredUrlsResponseSchema,
245
+ AddIgnoredUrlBodySchema,
246
+ AddIgnoredUrlResponseSchema,
247
+ DeleteIgnoredUrlResponseSchema,
248
+ OrgTagsBodySchema,
249
+ OrgTagsMutationResponseSchema,
250
+ CreateTagBodySchema,
251
+ TagRowSchema,
252
+ OrgActivityResponseSchema,
253
+ OrgHeatmapResponseSchema,
254
+ OrgSparklinesResponseSchema,
255
+ OrgReleaseItemSchema,
256
+ OrgFeedPaginationSchema,
257
+ OrgReleasesFeedResponseSchema,
258
+ OrgRecentReleaseItemSchema,
259
+ OrgRecentReleasesResponseSchema,
260
+ DeleteOrgAccountResponseSchema,
84
261
  } from "./schemas/orgs.js";
85
262
  export {
86
263
  SourceListItemSchema,
@@ -94,6 +271,31 @@ export {
94
271
  CreateSourceBodySchema,
95
272
  ChangelogFileSummarySchema,
96
273
  SourceChangelogResponseSchema,
274
+ SourceActivityResponseSchema,
275
+ SourceHeatmapResponseSchema,
276
+ SourceKnownReleaseItemSchema,
277
+ SourceKnownReleasesResponseSchema,
278
+ SourceRecentReleasesResponseSchema,
279
+ SourceSessionsResponseSchema,
280
+ SourceSummaryRowSchema,
281
+ SourceSummariesResponseSchema,
282
+ CreateSourceSummaryBodySchema,
283
+ CreateSourceSummaryResponseSchema,
284
+ SourceFetchResponseSchema,
285
+ SourceContentHashResponseSchema,
286
+ SourceContentHashBodySchema,
287
+ ChangelogTokensResponseSchema,
288
+ SourceMetadataResponseSchema,
289
+ ChangelogProbeResponseSchema,
290
+ DeleteSourceResponseSchema,
291
+ DeleteSourceReleasesResponseSchema,
292
+ InsertReleaseResponseSchema,
293
+ BatchReleasesResponseSchema,
294
+ OversizedChangelogFileRowSchema,
295
+ OversizedChangelogFilesResponseSchema,
296
+ FetchableSourcesResponseSchema,
297
+ FeedSourcesResponseSchema,
298
+ ChangedSourcesResponseSchema,
97
299
  } from "./schemas/sources.js";
98
300
  export {
99
301
  ProductRowSchema,
@@ -108,7 +310,116 @@ export {
108
310
  ProductAdoptDryRunSchema,
109
311
  ProductAdoptResponseSchema,
110
312
  ProductDeleteResponseSchema,
313
+ ProductTagsListResponseSchema,
314
+ ProductTagsBodySchema,
315
+ ProductTagsMutationResponseSchema,
111
316
  } from "./schemas/products.js";
317
+ export {
318
+ LookupStatusSchema,
319
+ LookupBodySchema,
320
+ LookupSourceSchema,
321
+ LookupReleaseSchema,
322
+ LookupRelatedOrgSchema,
323
+ LookupResponseSchema,
324
+ LookupSourceBySlugResponseSchema,
325
+ LookupProductBySlugResponseSchema,
326
+ DomainLookupOrgSchema,
327
+ DomainLookupProductSchema,
328
+ DomainLookupResponseSchema,
329
+ } from "./schemas/lookups.js";
330
+ export {
331
+ TaxonomyOrgSchema,
332
+ TaxonomyProductSchema,
333
+ CategoryListItemSchema,
334
+ CategoryListResponseSchema,
335
+ CategoryDetailSchema,
336
+ UpdateCategoryRequestSchema,
337
+ UpdateCategoryResponseSchema,
338
+ CategoryReleaseItemSchema,
339
+ CategoryFeedPaginationSchema,
340
+ CategoryReleasesResponseSchema,
341
+ TagDetailSchema,
342
+ } from "./schemas/taxonomy.js";
343
+ export {
344
+ ReleaseLatestSourceSchema,
345
+ ReleaseLatestItemSchema,
346
+ ReleaseLatestResponseSchema,
347
+ ReleaseCoverageRowSchema,
348
+ ReleaseCoverageResponseSchema,
349
+ LinkReleaseCoverageBodySchema,
350
+ LinkReleaseCoverageResponseSchema,
351
+ UnlinkReleaseCoverageResponseSchema,
352
+ ReleaseWithMediaRowSchema,
353
+ ReleasesWithMediaResponseSchema,
354
+ ReleaseDetailOrgSchema,
355
+ ReleaseDetailResponseSchema,
356
+ UpdateReleaseBodySchema,
357
+ ReleasePatchResponseSchema,
358
+ ReleaseDeleteResponseSchema,
359
+ ReleaseSuppressResponseSchema,
360
+ ReleaseUnsuppressResponseSchema,
361
+ ReleaseSuppressBodySchema,
362
+ ReleaseStreamMessageSchema,
363
+ } from "./schemas/releases.js";
364
+ export {
365
+ SearchOrgHitSchema,
366
+ SearchCatalogHitSchema,
367
+ SearchSourceHitSchema,
368
+ SearchReleaseHitSchema,
369
+ SearchChunkHitSchema,
370
+ LookupResultPayloadSchema,
371
+ UnifiedSearchResponseSchema,
372
+ } from "./schemas/search.js";
373
+ export {
374
+ StatsSourceActivitySchema,
375
+ StatsRecentActivitySchema,
376
+ StatsResponseSchema,
377
+ } from "./schemas/stats.js";
378
+ export { SitemapSourceSchema, SitemapPayloadSchema } from "./schemas/sitemap.js";
379
+ export {
380
+ RelatedScopeSchema,
381
+ RelatedReleaseThumbnailSchema,
382
+ RelatedReleaseSourceSchema,
383
+ RelatedReleaseItemSchema,
384
+ RelatedSourceItemSchema,
385
+ RelatedReleasesOkResponseSchema,
386
+ RelatedReleasesDegradedResponseSchema,
387
+ RelatedReleasesResponseSchema,
388
+ RelatedSourcesOkResponseSchema,
389
+ RelatedSourcesDegradedResponseSchema,
390
+ RelatedSourcesResponseSchema,
391
+ } from "./schemas/related.js";
392
+ export {
393
+ CollectionMemberOrgSchema,
394
+ CollectionListItemSchema,
395
+ CollectionListResponseSchema,
396
+ CollectionDetailSchema,
397
+ CollectionReleaseItemSchema,
398
+ CollectionFeedPaginationSchema,
399
+ CollectionReleasesResponseSchema,
400
+ CollectionRowSchema,
401
+ CreateCollectionRequestSchema,
402
+ UpdateCollectionRequestSchema,
403
+ CollectionMemberInputSchema,
404
+ AddCollectionMemberRequestSchema,
405
+ ReplaceCollectionMembersRequestSchema,
406
+ ResolvedCollectionMemberSchema,
407
+ ReplaceCollectionMembersResponseSchema,
408
+ AddCollectionMemberResponseSchema,
409
+ } from "./schemas/collections.js";
410
+ export {
411
+ OrgOverviewResponseSchema,
412
+ IncomingOverviewCitationSchema,
413
+ RegenerateOverviewBodySchema,
414
+ RegenerateOverviewResponseSchema,
415
+ ProductOverviewResponseSchema,
416
+ OverviewInputsCheckResponseSchema,
417
+ OverviewInputsFullResponseSchema,
418
+ OverviewInputsResponseSchema,
419
+ PlaybookResponseSchema,
420
+ UpdatePlaybookNotesBodySchema,
421
+ UpdatePlaybookNotesResponseSchema,
422
+ } from "./schemas/overviews.js";
112
423
 
113
424
  // ── Media ──
114
425
 
@@ -131,28 +442,22 @@ export type ErrorResponse = z.infer<typeof ErrorResponseSchema>;
131
442
 
132
443
  // ── Sitemap (bulk URL emission) ──
133
444
 
134
- export interface SitemapPayload {
135
- orgs: Array<{ slug: string; lastActivity: string | null }>;
136
- sources: Array<{
137
- orgSlug: string;
138
- slug: string;
139
- latestDate: string | null;
140
- /**
141
- * Whether this source has a stored GitHub CHANGELOG file. Used by the web
142
- * sitemap to emit `/{org}/{src}/changelog` URLs only for sources where the
143
- * route resolves (#875). Optional for backwards compatibility — older
144
- * clients ignore it.
145
- */
146
- hasChangelog?: boolean;
147
- /**
148
- * Whether this source has any rolling or monthly highlight summaries.
149
- * Drives `/{org}/{src}/highlights` sitemap emission (#875).
150
- */
151
- hasHighlights?: boolean;
152
- }>;
153
- products: Array<{ orgSlug: string; slug: string }>;
154
- collections: Array<{ slug: string; updatedAt: string }>;
155
- }
445
+ export type SitemapSource = z.infer<typeof SitemapSourceSchema>;
446
+ export type SitemapPayload = z.infer<typeof SitemapPayloadSchema>;
447
+
448
+ // ── Related (Vectorize neighbors) ──
449
+
450
+ export type RelatedScope = z.infer<typeof RelatedScopeSchema>;
451
+ export type RelatedReleaseThumbnail = z.infer<typeof RelatedReleaseThumbnailSchema>;
452
+ export type RelatedReleaseSource = z.infer<typeof RelatedReleaseSourceSchema>;
453
+ export type RelatedReleaseItem = z.infer<typeof RelatedReleaseItemSchema>;
454
+ export type RelatedSourceItem = z.infer<typeof RelatedSourceItemSchema>;
455
+ export type RelatedReleasesOkResponse = z.infer<typeof RelatedReleasesOkResponseSchema>;
456
+ export type RelatedReleasesDegradedResponse = z.infer<typeof RelatedReleasesDegradedResponseSchema>;
457
+ export type RelatedReleasesResponse = z.infer<typeof RelatedReleasesResponseSchema>;
458
+ export type RelatedSourcesOkResponse = z.infer<typeof RelatedSourcesOkResponseSchema>;
459
+ export type RelatedSourcesDegradedResponse = z.infer<typeof RelatedSourcesDegradedResponseSchema>;
460
+ export type RelatedSourcesResponse = z.infer<typeof RelatedSourcesResponseSchema>;
156
461
 
157
462
  // ── Organizations ──
158
463
 
@@ -163,9 +468,31 @@ export type OrgAccountsResponse = z.infer<typeof OrgAccountsResponseSchema>;
163
468
  export type OrgTagsResponse = z.infer<typeof OrgTagsResponseSchema>;
164
469
  export type CreateOrgBody = z.infer<typeof CreateOrgBodySchema>;
165
470
  export type UpdateOrgBody = z.infer<typeof UpdateOrgBodySchema>;
166
-
167
471
  export type OrgDetail = z.infer<typeof OrgDetailSchema>;
168
472
 
473
+ export type OrgCatalogItem = z.infer<typeof OrgCatalogItemSchema>;
474
+ export type OrgCatalogResponse = z.infer<typeof OrgCatalogResponseSchema>;
475
+ export type OrgCollectionsResponse = z.infer<typeof OrgCollectionsResponseSchema>;
476
+ export type AddOrgAccountBody = z.infer<typeof AddOrgAccountBodySchema>;
477
+ export type IgnoredUrlItem = z.infer<typeof IgnoredUrlItemSchema>;
478
+ export type OrgIgnoredUrlsResponse = z.infer<typeof OrgIgnoredUrlsResponseSchema>;
479
+ export type AddIgnoredUrlBody = z.infer<typeof AddIgnoredUrlBodySchema>;
480
+ export type AddIgnoredUrlResponse = z.infer<typeof AddIgnoredUrlResponseSchema>;
481
+ export type DeleteIgnoredUrlResponse = z.infer<typeof DeleteIgnoredUrlResponseSchema>;
482
+ export type OrgTagsBody = z.infer<typeof OrgTagsBodySchema>;
483
+ export type OrgTagsMutationResponse = z.infer<typeof OrgTagsMutationResponseSchema>;
484
+ export type CreateTagBody = z.infer<typeof CreateTagBodySchema>;
485
+ export type TagRow = z.infer<typeof TagRowSchema>;
486
+ export type OrgActivityResponse = z.infer<typeof OrgActivityResponseSchema>;
487
+ export type OrgHeatmapResponse = z.infer<typeof OrgHeatmapResponseSchema>;
488
+ export type OrgSparklinesResponse = z.infer<typeof OrgSparklinesResponseSchema>;
489
+ export type OrgReleaseItem = z.infer<typeof OrgReleaseItemSchema>;
490
+ export type OrgFeedPagination = z.infer<typeof OrgFeedPaginationSchema>;
491
+ export type OrgReleasesFeedResponse = z.infer<typeof OrgReleasesFeedResponseSchema>;
492
+ export type OrgRecentReleaseItem = z.infer<typeof OrgRecentReleaseItemSchema>;
493
+ export type OrgRecentReleasesResponse = z.infer<typeof OrgRecentReleasesResponseSchema>;
494
+ export type DeleteOrgAccountResponse = z.infer<typeof DeleteOrgAccountResponseSchema>;
495
+
169
496
  // ── Sources ──
170
497
 
171
498
  export type SourceListItem = z.infer<typeof SourceListItemSchema>;
@@ -179,6 +506,31 @@ export type SourceChangelogResponse = z.infer<typeof SourceChangelogResponseSche
179
506
  export type SourceDetail = z.infer<typeof SourceDetailSchema>;
180
507
  export type SourceMutationResponse = z.infer<typeof SourceMutationResponseSchema>;
181
508
  export type SourceOrgRef = z.infer<typeof SourceOrgRefSchema>;
509
+ export type SourceActivityResponse = z.infer<typeof SourceActivityResponseSchema>;
510
+ export type SourceHeatmapResponse = z.infer<typeof SourceHeatmapResponseSchema>;
511
+ export type SourceKnownReleaseItem = z.infer<typeof SourceKnownReleaseItemSchema>;
512
+ export type SourceKnownReleasesResponse = z.infer<typeof SourceKnownReleasesResponseSchema>;
513
+ export type SourceRecentReleasesResponse = z.infer<typeof SourceRecentReleasesResponseSchema>;
514
+ export type SourceSessionsResponse = z.infer<typeof SourceSessionsResponseSchema>;
515
+ export type SourceSummaryRow = z.infer<typeof SourceSummaryRowSchema>;
516
+ export type SourceSummariesResponse = z.infer<typeof SourceSummariesResponseSchema>;
517
+ export type CreateSourceSummaryBody = z.infer<typeof CreateSourceSummaryBodySchema>;
518
+ export type CreateSourceSummaryResponse = z.infer<typeof CreateSourceSummaryResponseSchema>;
519
+ export type SourceFetchResponse = z.infer<typeof SourceFetchResponseSchema>;
520
+ export type SourceContentHashResponse = z.infer<typeof SourceContentHashResponseSchema>;
521
+ export type SourceContentHashBody = z.infer<typeof SourceContentHashBodySchema>;
522
+ export type ChangelogTokensResponse = z.infer<typeof ChangelogTokensResponseSchema>;
523
+ export type SourceMetadataResponse = z.infer<typeof SourceMetadataResponseSchema>;
524
+ export type ChangelogProbeResponse = z.infer<typeof ChangelogProbeResponseSchema>;
525
+ export type DeleteSourceResponse = z.infer<typeof DeleteSourceResponseSchema>;
526
+ export type DeleteSourceReleasesResponse = z.infer<typeof DeleteSourceReleasesResponseSchema>;
527
+ export type InsertReleaseResponse = z.infer<typeof InsertReleaseResponseSchema>;
528
+ export type BatchReleasesResponse = z.infer<typeof BatchReleasesResponseSchema>;
529
+ export type OversizedChangelogFileRow = z.infer<typeof OversizedChangelogFileRowSchema>;
530
+ export type OversizedChangelogFilesResponse = z.infer<typeof OversizedChangelogFilesResponseSchema>;
531
+ export type FetchableSourcesResponse = z.infer<typeof FetchableSourcesResponseSchema>;
532
+ export type FeedSourcesResponse = z.infer<typeof FeedSourcesResponseSchema>;
533
+ export type ChangedSourcesResponse = z.infer<typeof ChangedSourcesResponseSchema>;
182
534
 
183
535
  // ── Admin telemetry: orgs rollup ──
184
536
 
@@ -247,60 +599,37 @@ export interface ReleaseDetail {
247
599
  type?: ReleaseType;
248
600
  }
249
601
 
250
- export interface ReleaseCoverageRow {
251
- coverageId: string;
252
- canonicalId: string;
253
- reason: string | null;
254
- decidedBy: string;
255
- decidedAt: string;
256
- }
257
-
258
- export type ReleaseCoverageResponse =
259
- | { role: "standalone"; canonical: null; covers: [] }
260
- | { role: "coverage"; canonical: ReleaseCoverageRow; covers: [] }
261
- | { role: "canonical"; canonical: null; covers: ReleaseCoverageRow[] };
602
+ export type ReleaseCoverageRow = z.infer<typeof ReleaseCoverageRowSchema>;
603
+ export type ReleaseCoverageResponse = z.infer<typeof ReleaseCoverageResponseSchema>;
604
+ export type LinkReleaseCoverageBody = z.infer<typeof LinkReleaseCoverageBodySchema>;
605
+ export type LinkReleaseCoverageResponse = z.infer<typeof LinkReleaseCoverageResponseSchema>;
606
+ export type UnlinkReleaseCoverageResponse = z.infer<typeof UnlinkReleaseCoverageResponseSchema>;
607
+
608
+ export type ReleaseLatestSource = z.infer<typeof ReleaseLatestSourceSchema>;
609
+ export type ReleaseLatestItem = z.infer<typeof ReleaseLatestItemSchema>;
610
+ export type ReleaseLatestResponse = z.infer<typeof ReleaseLatestResponseSchema>;
611
+
612
+ export type ReleaseWithMediaRow = z.infer<typeof ReleaseWithMediaRowSchema>;
613
+ export type ReleasesWithMediaResponse = z.infer<typeof ReleasesWithMediaResponseSchema>;
614
+
615
+ export type ReleaseDetailOrg = z.infer<typeof ReleaseDetailOrgSchema>;
616
+ export type ReleaseDetailResponse = z.infer<typeof ReleaseDetailResponseSchema>;
617
+ export type UpdateReleaseBody = z.infer<typeof UpdateReleaseBodySchema>;
618
+ export type ReleasePatchResponse = z.infer<typeof ReleasePatchResponseSchema>;
619
+ export type ReleaseDeleteResponse = z.infer<typeof ReleaseDeleteResponseSchema>;
620
+ export type ReleaseSuppressResponse = z.infer<typeof ReleaseSuppressResponseSchema>;
621
+ export type ReleaseUnsuppressResponse = z.infer<typeof ReleaseUnsuppressResponseSchema>;
622
+ export type ReleaseSuppressBody = z.infer<typeof ReleaseSuppressBodySchema>;
623
+ export type ReleaseStreamMessage = z.infer<typeof ReleaseStreamMessageSchema>;
262
624
 
263
625
  export type ReleaseSummaryItem = z.infer<typeof ReleaseSummaryItemSchema>;
264
626
 
265
627
  // ── Search ──
266
628
 
267
- export interface SearchOrgHit {
268
- slug: string;
269
- name: string;
270
- domain: string | null;
271
- avatarUrl: string | null;
272
- category: string | null;
273
- }
629
+ export type SearchOrgHit = z.infer<typeof SearchOrgHitSchema>;
630
+ export type SearchCatalogHit = z.infer<typeof SearchCatalogHitSchema>;
274
631
 
275
- /**
276
- * Unified catalog entry — either a product row or a standalone source
277
- * presented as product-shaped. `kind` routes clicks to the right URL but
278
- * the two forms are otherwise interchangeable for display. `kind` (not
279
- * `type`) because source rows already carry `type: github|scrape|feed|agent`
280
- * on the wire.
281
- */
282
- export interface SearchCatalogHit {
283
- slug: string;
284
- name: string;
285
- orgSlug: string | null;
286
- orgName: string | null;
287
- category: string | null;
288
- kind: "product" | "source";
289
- sourceSlug?: string;
290
- sourceType?: string;
291
- }
292
-
293
- /** @deprecated Use SearchCatalogHit. */
294
- export type SearchProductHit = SearchCatalogHit;
295
-
296
- export interface SearchSourceHit {
297
- slug: string;
298
- name: string;
299
- type: string;
300
- orgSlug: string | null;
301
- orgName: string | null;
302
- productSlug: string | null;
303
- }
632
+ export type SearchSourceHit = z.infer<typeof SearchSourceHitSchema>;
304
633
 
305
634
  export interface RawSourceHit extends SearchSourceHit {
306
635
  productName?: string;
@@ -345,181 +674,28 @@ export function foldSourcesIntoCatalog(
345
674
  return result;
346
675
  }
347
676
 
348
- /** @deprecated Use foldSourcesIntoCatalog. */
349
- export const foldSourcesIntoProducts = foldSourcesIntoCatalog;
350
-
351
- export interface SearchReleaseHit {
352
- id: string;
353
- sourceSlug: string;
354
- sourceName: string;
355
- /** Source type (github, scrape, feed, agent) — drives the byline icon. */
356
- sourceType?: string;
357
- orgSlug: string | null;
358
- /** Owning organization's display name — byline disambiguation. */
359
- orgName?: string | null;
360
- version: string | null;
361
- title: string;
362
- summary: string;
363
- /** AI-generated headline (#852, renamed in #860). Optional + nullable: most rows are unpopulated. */
364
- titleGenerated?: string | null;
365
- /** AI-generated smart-brevity headline (#852, renamed in #860). Same caveat as titleGenerated. */
366
- titleShort?: string | null;
367
- /**
368
- * Full release body, media URLs hydrated through the MEDIA_ORIGIN proxy.
369
- * Present so the web can render the same markdown + thumbnail treatment
370
- * as the org/source feeds instead of a plain summary snippet.
371
- */
372
- content?: string;
373
- /** Release media with r2Url resolved. Undefined means "not hydrated". */
374
- media?: MediaItem[];
375
- publishedAt: string | null;
376
- /**
377
- * Hybrid fusion score. Present on hybrid/semantic responses (including
378
- * degraded fallbacks); absent on the legacy lexical path. Clients can
379
- * use this to interleave release and chunk hits into a single ranked list.
380
- */
381
- score?: number;
382
- /** Release type. See {@link ReleaseType}. */
383
- type?: ReleaseType;
384
- }
385
-
386
- /**
387
- * A heading-aware CHANGELOG.md slice returned by hybrid / semantic search.
388
- * Clients can deep-link to `/source/<sourceSlug>?tab=changelog&offset=<offset>`
389
- * to read the surrounding file content.
390
- */
391
- export interface SearchChunkHit {
392
- sourceSlug: string;
393
- sourceName: string;
394
- orgSlug: string | null;
395
- /** Owning organization's display name — byline disambiguation. */
396
- orgName?: string | null;
397
- filePath: string;
398
- offset: number;
399
- length: number;
400
- heading: string | null;
401
- snippet: string;
402
- score: number;
403
- }
404
-
405
- // ── Lookup by domain (entity resolution) ──
406
-
407
- /**
408
- * Returned by GET /v1/lookups/by-domain. Pure resolution: the server
409
- * normalizes the input domain, exact-matches against
410
- * `organizations.domain` (primary) and `domain_aliases.domain` (alias for
411
- * either an org or a product), and returns whatever it finds. Unknown
412
- * domains 404 — there is no on-demand probing for domains, unlike the
413
- * GitHub coordinate path.
414
- */
415
- export interface DomainLookupResponse {
416
- /** Normalized domain that was matched (lowercased, no scheme/path/www). */
417
- domain: string;
418
- /**
419
- * Owning organization, if one exists. `matchedVia` distinguishes a hit
420
- * on `organizations.domain` (`"primary"`) from an alias hit
421
- * (`"alias"`) so the UI can render the difference.
422
- */
423
- org: {
424
- id: string;
425
- slug: string;
426
- name: string;
427
- domain: string | null;
428
- description: string | null;
429
- category: string | null;
430
- avatarUrl: string | null;
431
- matchedVia: "primary" | "alias";
432
- } | null;
433
- /**
434
- * Products whose alias points at this domain. Multiple are possible
435
- * when an org owns several products that all set the same alias —
436
- * unusual, but allowed.
437
- */
438
- products: Array<{
439
- id: string;
440
- slug: string;
441
- name: string;
442
- orgId: string;
443
- orgSlug: string;
444
- orgName: string;
445
- category: string | null;
446
- }>;
447
- }
448
-
449
- // ── Lookup (on-demand GitHub index) ──
450
-
451
- export type LookupStatus = "indexed" | "existing" | "empty" | "not_found" | "deferred";
452
-
453
- /**
454
- * Slim wire payload embedded in a search response when the query is a GitHub
455
- * coordinate (org/repo) and no existing entity matched. The server performs an
456
- * on-demand lookup and includes the result here so the client can surface a
457
- * "just indexed" or "not found" rail without a second round trip.
458
- */
459
- export interface LookupResultPayload {
460
- status: LookupStatus;
461
- source?: {
462
- id: string;
463
- slug: string;
464
- name: string;
465
- url: string;
466
- discovery: "curated" | "agent" | "on_demand";
467
- };
468
- releases?: Array<{
469
- id: string;
470
- version: string | null;
471
- title: string;
472
- publishedAt: string | null;
473
- }>;
474
- /**
475
- * Unambiguous "did you mean" rail: the curated org that owns GitHub repos
476
- * under the same org segment, plus its top sources. Null when the org
477
- * segment matches multiple curated orgs or none.
478
- */
479
- relatedOrg: {
480
- org: { id: string; slug: string; name: string };
481
- sources: Array<{ id: string; slug: string; name: string; url: string }>;
482
- } | null;
483
- }
484
-
485
- export interface UnifiedSearchResponse {
486
- query: string;
487
- /**
488
- * Normalized form of `?domain=` when the caller passed it. The server
489
- * does the normalization once and echoes the canonical form back so
490
- * clients don't have to re-normalize for analytics or display. Absent
491
- * when no domain filter was applied.
492
- */
493
- domain?: string;
494
- /**
495
- * Outcome of the `?domain=` resolution step. `"matched"` means the
496
- * domain resolved to a known org and results below are scoped to it.
497
- * `"not_found"` means the domain didn't match anything; in that case
498
- * orgs/catalog/releases will all be empty arrays — the caller can
499
- * distinguish "no hits in scope" from "scope didn't exist."
500
- */
501
- domainStatus?: "matched" | "not_found";
502
- orgs: SearchOrgHit[];
503
- /** Products and standalone sources folded into a single list. */
504
- catalog: SearchCatalogHit[];
505
- /** @deprecated Use `catalog`. Kept as an alias populated with the same array. */
506
- products: SearchCatalogHit[];
507
- sources: SearchSourceHit[];
508
- releases: SearchReleaseHit[];
509
- /** Present on hybrid/semantic responses; omitted on pure lexical. */
510
- chunks?: SearchChunkHit[];
511
- /** Mode actually used by the server. Present for semantic/hybrid responses. */
512
- mode?: "lexical" | "semantic" | "hybrid";
513
- /** True when a hybrid/semantic request fell back to lexical. */
514
- degraded?: boolean;
515
- /** Human-readable reason for degradation (e.g., missing Vectorize binding). */
516
- degradedReason?: string;
517
- /**
518
- * On-demand lookup result. Present when the query parsed as a GitHub
519
- * `org/repo` coordinate and no existing entities matched. Null otherwise.
520
- */
521
- lookup?: LookupResultPayload | null;
522
- }
677
+ export type SearchReleaseHit = z.infer<typeof SearchReleaseHitSchema>;
678
+ export type SearchChunkHit = z.infer<typeof SearchChunkHitSchema>;
679
+
680
+ // ── Lookups ──
681
+
682
+ export type LookupStatus = z.infer<typeof LookupStatusSchema>;
683
+ export type LookupBody = z.infer<typeof LookupBodySchema>;
684
+ export type LookupSourceRow = z.infer<typeof LookupSourceSchema>;
685
+ export type LookupReleaseRow = z.infer<typeof LookupReleaseSchema>;
686
+ export type LookupRelatedOrg = z.infer<typeof LookupRelatedOrgSchema>;
687
+ export type LookupResponse = z.infer<typeof LookupResponseSchema>;
688
+ export type LookupSourceBySlugResponse = z.infer<typeof LookupSourceBySlugResponseSchema>;
689
+ export type LookupProductBySlugResponse = z.infer<typeof LookupProductBySlugResponseSchema>;
690
+ export type DomainLookupOrg = z.infer<typeof DomainLookupOrgSchema>;
691
+ export type DomainLookupProduct = z.infer<typeof DomainLookupProductSchema>;
692
+ export type DomainLookupResponse = z.infer<typeof DomainLookupResponseSchema>;
693
+
694
+ // Slim wire payload embedded in a search response when the query is a GitHub
695
+ // coordinate. `LookupResultPayload` is the search-embedded slim variant;
696
+ // `LookupResponse` (above) is the thicker payload returned by POST /v1/lookups.
697
+ export type LookupResultPayload = z.infer<typeof LookupResultPayloadSchema>;
698
+ export type UnifiedSearchResponse = z.infer<typeof UnifiedSearchResponseSchema>;
523
699
 
524
700
  // ── Overview Pages ──
525
701
 
@@ -529,6 +705,18 @@ export type OverviewCitation = z.infer<typeof OverviewCitationSchema>;
529
705
  /** @deprecated Use OverviewPageItem */
530
706
  export type KnowledgePageItem = OverviewPageItem;
531
707
 
708
+ export type OrgOverviewResponse = z.infer<typeof OrgOverviewResponseSchema>;
709
+ export type IncomingOverviewCitation = z.infer<typeof IncomingOverviewCitationSchema>;
710
+ export type RegenerateOverviewBody = z.infer<typeof RegenerateOverviewBodySchema>;
711
+ export type RegenerateOverviewResponse = z.infer<typeof RegenerateOverviewResponseSchema>;
712
+ export type ProductOverviewResponse = z.infer<typeof ProductOverviewResponseSchema>;
713
+ export type OverviewInputsCheckResponse = z.infer<typeof OverviewInputsCheckResponseSchema>;
714
+ export type OverviewInputsFullResponse = z.infer<typeof OverviewInputsFullResponseSchema>;
715
+ export type OverviewInputsResponse = z.infer<typeof OverviewInputsResponseSchema>;
716
+ export type PlaybookResponse = z.infer<typeof PlaybookResponseSchema>;
717
+ export type UpdatePlaybookNotesBody = z.infer<typeof UpdatePlaybookNotesBodySchema>;
718
+ export type UpdatePlaybookNotesResponse = z.infer<typeof UpdatePlaybookNotesResponseSchema>;
719
+
532
720
  // ── Overview Manifest (admin planning) ──
533
721
 
534
722
  export type OverviewStaleness = "missing" | "behind" | "fresh";
@@ -591,68 +779,45 @@ export interface WeeklyBucket {
591
779
  latestVersion: string | null;
592
780
  }
593
781
 
594
- export interface SourceActivity {
595
- source: { slug: string; name: string; orgSlug: string | null; orgName: string | null };
596
- range: { from: string; to: string };
597
- weeklyBuckets: WeeklyBucket[];
598
- }
782
+ /**
783
+ * @deprecated Use SourceActivityResponse (Zod-derived).
784
+ * The hand-written interface is kept for callsite compatibility — shape is identical.
785
+ */
786
+ export type SourceActivity = SourceActivityResponse;
599
787
 
600
- export interface OrgActivitySource {
601
- slug: string;
602
- name: string;
603
- releaseCount: number;
604
- avgReleasesPerWeek: number;
605
- earliestVersion: string | null;
606
- latestVersion: string | null;
607
- latestDate: string | null;
608
- weeklyBuckets: WeeklyBucket[];
609
- }
788
+ // ── Org Activity (Zod-derived aliases) ──
789
+ // The old hand-written OrgActivitySource / OrgActivity / OrgSparklines /
790
+ // OrgHeatmap / OrgReleaseItem / OrgReleasesResponse interfaces have been
791
+ // replaced by Zod-derived types in the Organizations section above. Keeping
792
+ // the interface names as deprecated aliases so callsites don't need an
793
+ // immediate churn.
610
794
 
611
- export interface OrgActivity {
612
- org: { slug: string; name: string };
613
- range: { from: string; to: string };
614
- sources: OrgActivitySource[];
615
- aggregateWeekly: Array<{ weekStart: string; count: number }>;
616
- }
795
+ /** @deprecated Use OrgActivityResponse */
796
+ export type OrgActivity = OrgActivityResponse;
617
797
 
618
- // ── Org Sparklines (per-source/product breakdown) ──
798
+ /** @deprecated Use OrgSparklinesResponse */
799
+ export type OrgSparklines = OrgSparklinesResponse;
619
800
 
620
- export interface OrgSparklines {
621
- org: { slug: string; name: string };
622
- range: { from: string; to: string };
623
- aggregate: number[];
624
- sources: Array<{ slug: string; name: string; sparkline: number[] }>;
625
- products: Array<{ slug: string; name: string; sparkline: number[] }>;
626
- }
801
+ /** @deprecated Use OrgHeatmapResponse */
802
+ export type OrgHeatmap = OrgHeatmapResponse;
627
803
 
628
- // ── Org Heatmap ──
804
+ /** @deprecated Use OrgReleasesFeedResponse */
805
+ export type OrgReleasesResponse = OrgReleasesFeedResponse;
629
806
 
630
- export interface OrgHeatmap {
631
- org: { slug: string; name: string };
632
- range: { from: string; to: string };
633
- dailyCounts: Array<{ date: string; count: number }>;
634
- total: number;
635
- }
807
+ // ── Org Sparklines (per-source/product breakdown) ──
808
+ // (covered above)
636
809
 
637
810
  // ── Source Heatmap ──
811
+ // (covered by SourceHeatmapResponse above)
638
812
 
639
- export interface SourceHeatmap {
640
- source: { slug: string; name: string };
641
- range: { from: string; to: string };
642
- dailyCounts: Array<{ date: string; count: number }>;
643
- total: number;
644
- }
813
+ /**
814
+ * @deprecated Use SourceHeatmapResponse (Zod-derived).
815
+ * The hand-written interface is kept for callsite compatibility — shape is identical.
816
+ */
817
+ export type SourceHeatmap = SourceHeatmapResponse;
645
818
 
646
819
  // ── Org Releases ──
647
-
648
- export interface OrgReleaseItem extends ReleaseItem {
649
- source: { slug: string; name: string; type: string };
650
- }
651
-
652
- export interface OrgReleasesResponse {
653
- releases: OrgReleaseItem[];
654
- pagination: { nextCursor: string | null; limit: number };
655
- }
820
+ // (covered by OrgReleaseItem / OrgReleasesFeedResponse above)
656
821
 
657
822
  // Source-scoped release feed — the source identity is encoded in the URL, so
658
823
  // items omit the redundant `source` block carried by the org feed.
@@ -677,195 +842,54 @@ export type ProductAdoptResult = z.infer<typeof ProductAdoptResultSchema>;
677
842
  export type ProductAdoptDryRun = z.infer<typeof ProductAdoptDryRunSchema>;
678
843
  export type ProductAdoptResponse = z.infer<typeof ProductAdoptResponseSchema>;
679
844
  export type ProductDeleteResponse = z.infer<typeof ProductDeleteResponseSchema>;
845
+ export type ProductTagsListResponse = z.infer<typeof ProductTagsListResponseSchema>;
846
+ export type ProductTagsBody = z.infer<typeof ProductTagsBodySchema>;
847
+ export type ProductTagsMutationResponse = z.infer<typeof ProductTagsMutationResponseSchema>;
680
848
 
681
849
  // ── Taxonomy (categories + tags) ──
682
850
 
683
- export interface TaxonomyOrg {
684
- slug: string;
685
- name: string;
686
- domain: string | null;
687
- avatarUrl: string | null;
688
- }
689
-
690
- export interface TaxonomyProduct {
691
- slug: string;
692
- name: string;
693
- description: string | null;
694
- orgSlug: string;
695
- orgName: string;
696
- }
697
-
698
- export interface CategoryDetail {
699
- slug: string;
700
- /**
701
- * Display name — operator override from the `categories` table if present,
702
- * otherwise `categoryDisplayName(slug)` from `@buildinternet/releases-core`.
703
- */
704
- name: string;
705
- /**
706
- * Operator-authored byline shown on the web category page. Null when no
707
- * description has been set; clients render their own fallback copy.
708
- */
709
- description: string | null;
710
- /**
711
- * Alternative slugs that redirect to this canonical category. Empty when
712
- * no aliases have been configured.
713
- */
714
- aliases: string[];
715
- orgs: TaxonomyOrg[];
716
- products: TaxonomyProduct[];
717
- }
718
-
719
- /**
720
- * Item shape on GET /v1/categories — the overview list. Categories are a
721
- * fixed taxonomy (`CATEGORIES` in `@buildinternet/releases-core/categories`),
722
- * so the API always returns every slug, including ones with zero members.
723
- * `orgCount` counts orgs whose `category` matches; `productCount` counts
724
- * products whose own `category` matches (overriding any parent-org category).
725
- * Both counts pass through `organizations_public`, so on_demand and
726
- * soft-deleted orgs are excluded. `description` comes from the optional
727
- * `categories` metadata overlay; null when no override has been set.
728
- */
729
- export interface CategoryListItem {
730
- slug: string;
731
- name: string;
732
- description: string | null;
733
- aliases: string[];
734
- orgCount: number;
735
- productCount: number;
736
- }
737
-
738
- /**
739
- * PATCH /v1/categories/:slug request body. All fields are optional. `name`
740
- * and `description` accept `null` to clear the override; `aliases` replaces
741
- * the full set when provided (pass `[]` to clear). The row is upserted —
742
- * a category that has never been customized has no row in the table.
743
- *
744
- * Each alias must be a kebab-case slug not already in `CATEGORIES` and not
745
- * claimed by another category row.
746
- */
747
- export interface UpdateCategoryRequest {
748
- name?: string | null;
749
- description?: string | null;
750
- aliases?: string[];
751
- }
851
+ export type TaxonomyOrg = z.infer<typeof TaxonomyOrgSchema>;
852
+ export type TaxonomyProduct = z.infer<typeof TaxonomyProductSchema>;
853
+ export type CategoryDetail = z.infer<typeof CategoryDetailSchema>;
854
+ export type CategoryListItem = z.infer<typeof CategoryListItemSchema>;
855
+ export type CategoryListResponse = z.infer<typeof CategoryListResponseSchema>;
856
+ export type UpdateCategoryRequest = z.infer<typeof UpdateCategoryRequestSchema>;
857
+ export type UpdateCategoryResponse = z.infer<typeof UpdateCategoryResponseSchema>;
858
+ export type CategoryFeedPagination = z.infer<typeof CategoryFeedPaginationSchema>;
859
+ export type CategoryReleasesResponse = z.infer<typeof CategoryReleasesResponseSchema>;
860
+ export type TagDetail = z.infer<typeof TagDetailSchema>;
752
861
 
753
862
  /**
754
863
  * Aggregated release feed row for a category rollup — same wire shape as
755
- * `CollectionReleaseItem` (both surfaces aggregate releases across multiple
756
- * orgs). Aliased rather than duplicated so renderers can treat them as one.
864
+ * `CollectionReleaseItem` (both surfaces use `formatAggregateReleaseRow` in
865
+ * `workers/api/src/utils.ts`). Aliased rather than duplicated so renderers
866
+ * can treat them as one.
757
867
  */
758
868
  export type CategoryReleaseItem = CollectionReleaseItem;
759
869
 
760
- export interface CategoryReleasesResponse {
761
- releases: CategoryReleaseItem[];
762
- pagination: { nextCursor: string | null; limit: number };
763
- }
764
-
765
- export interface TagDetail {
766
- slug: string;
767
- name: string;
768
- orgs: TaxonomyOrg[];
769
- products: TaxonomyProduct[];
770
- }
771
-
772
870
  // ── Collections ──
773
871
  //
774
872
  // Curated, named groups of orgs that drive a public "playlist" page (e.g.
775
873
  // /collections/frontier-ai-labs). Independent of the fixed `category` taxonomy.
776
874
 
777
- export interface CollectionMemberOrg {
778
- slug: string;
779
- name: string;
780
- domain: string | null;
781
- avatarUrl: string | null;
782
- /** GitHub handle from org_accounts; lets the avatar fall back to github.com/<handle>.png. */
783
- githubHandle: string | null;
784
- description: string | null;
785
- }
786
-
787
- /** Item shape on GET /v1/collections (list) and GET /v1/orgs/:slug/collections. */
788
- export interface CollectionListItem {
789
- slug: string;
790
- name: string;
791
- description: string | null;
792
- memberCount: number;
793
- /** First few members for inline preview on the list page (capped at 3). */
794
- previewMembers?: CollectionMemberOrg[];
795
- }
796
-
797
- /** Detail shape on GET /v1/collections/:slug. */
798
- export interface CollectionDetail {
799
- slug: string;
800
- name: string;
801
- description: string | null;
802
- orgs: CollectionMemberOrg[];
803
- }
804
-
805
- /**
806
- * Cross-org release feed row. Same shape as `OrgReleaseItem` plus the origin
807
- * `org` block, so the web's release card can render it identically — full
808
- * `content` lets "Show more" expand to the body instead of the truncated
809
- * `summary`.
810
- */
811
- export interface CollectionReleaseItem extends OrgReleaseItem {
812
- org: { slug: string; name: string };
813
- /**
814
- * Product the release belongs to, if the source is bound to one. Powers
815
- * the timeline's same-product rollup ("3 earlier Claude Code releases
816
- * today") on the collections view. `null` for orgs without products or
817
- * standalone sources. Optional on the wire so older workers mid-rollout
818
- * (and hand-constructed test fixtures) don't trip the typecheck — clients
819
- * should treat missing and `null` identically.
820
- */
821
- product?: { slug: string; name: string } | null;
822
- }
823
-
824
- export interface CollectionReleasesResponse {
825
- releases: CollectionReleaseItem[];
826
- pagination: { nextCursor: string | null; limit: number };
827
- }
828
-
829
- /** Body for POST /v1/collections. `slug` derives from `name` via toSlug() if omitted. */
830
- export interface CreateCollectionRequest {
831
- slug?: string;
832
- name: string;
833
- description?: string | null;
834
- }
835
-
836
- /** Body for PATCH /v1/collections/:slug. All fields optional; slug rename is allowed. */
837
- export interface UpdateCollectionRequest {
838
- slug?: string;
839
- name?: string;
840
- description?: string | null;
841
- }
842
-
843
- /** A single member entry accepted by the member-write endpoints. */
844
- export interface CollectionMemberInput {
845
- /** Either `orgId` (org_…) or `orgSlug` is required; if both are given, `orgId` wins. */
846
- orgId?: string;
847
- orgSlug?: string;
848
- /** Authoring position (default 0). For PUT, omit to use array index. */
849
- position?: number;
850
- }
851
-
852
- /** Body for POST /v1/collections/:slug/members. */
853
- export type AddCollectionMemberRequest = CollectionMemberInput;
854
-
855
- /** Body for PUT /v1/collections/:slug/members. Replaces the full membership atomically. */
856
- export interface ReplaceCollectionMembersRequest {
857
- orgs: CollectionMemberInput[];
858
- }
859
-
860
- /** Bare row returned by POST/PATCH on /v1/collections. */
861
- export interface CollectionRow {
862
- id: string;
863
- slug: string;
864
- name: string;
865
- description: string | null;
866
- createdAt: string;
867
- updatedAt: string;
868
- }
875
+ export type CollectionMemberOrg = z.infer<typeof CollectionMemberOrgSchema>;
876
+ export type CollectionListItem = z.infer<typeof CollectionListItemSchema>;
877
+ export type CollectionListResponse = z.infer<typeof CollectionListResponseSchema>;
878
+ export type CollectionDetail = z.infer<typeof CollectionDetailSchema>;
879
+ export type CollectionReleaseItem = z.infer<typeof CollectionReleaseItemSchema>;
880
+ export type CollectionFeedPagination = z.infer<typeof CollectionFeedPaginationSchema>;
881
+ export type CollectionReleasesResponse = z.infer<typeof CollectionReleasesResponseSchema>;
882
+ export type CollectionRow = z.infer<typeof CollectionRowSchema>;
883
+ export type CreateCollectionRequest = z.infer<typeof CreateCollectionRequestSchema>;
884
+ export type UpdateCollectionRequest = z.infer<typeof UpdateCollectionRequestSchema>;
885
+ export type CollectionMemberInput = z.infer<typeof CollectionMemberInputSchema>;
886
+ export type AddCollectionMemberRequest = z.infer<typeof AddCollectionMemberRequestSchema>;
887
+ export type ReplaceCollectionMembersRequest = z.infer<typeof ReplaceCollectionMembersRequestSchema>;
888
+ export type ResolvedCollectionMember = z.infer<typeof ResolvedCollectionMemberSchema>;
889
+ export type ReplaceCollectionMembersResponse = z.infer<
890
+ typeof ReplaceCollectionMembersResponseSchema
891
+ >;
892
+ export type AddCollectionMemberResponse = z.infer<typeof AddCollectionMemberResponseSchema>;
869
893
 
870
894
  // ── Releases (enriched) ──
871
895
 
@@ -910,42 +934,22 @@ export interface LatestRelease {
910
934
  }
911
935
 
912
936
  // ── Stats ──
913
-
914
- export interface StatsSummary {
915
- period: { days: number; cutoff: string };
916
- totals: {
917
- organizations: number;
918
- sources: number;
919
- releases: number;
920
- releasesInPeriod: number;
921
- };
922
- sourceHealth: {
923
- upToDate: number;
924
- stale: number;
925
- neverFetched: number;
926
- };
927
- sourceActivity: Array<{
928
- sourceName: string;
929
- sourceSlug: string;
930
- sourceType: string;
931
- orgName: string | null;
932
- lastFetchedAt: string | null;
933
- totalReleases: number;
934
- recentReleases: number;
935
- }>;
936
- recentActivity: Array<{
937
- sourceName: string;
938
- sourceSlug: string;
939
- orgName: string | null;
940
- releasesFound: number;
941
- releasesInserted: number;
942
- totalReleases: number;
943
- status: string;
944
- durationMs: number | null;
945
- error: string | null;
946
- createdAt: string;
947
- }>;
948
- }
937
+ //
938
+ // `Stats` (flat counts) lives near the top of this file alongside the other
939
+ // shared schema-derived aliases. The richer summary shape is the combined
940
+ // hybrid response served at `GET /v1/stats` — flat counts plus per-source
941
+ // rollups.
942
+
943
+ export type StatsSourceActivity = z.infer<typeof StatsSourceActivitySchema>;
944
+ export type StatsRecentActivity = z.infer<typeof StatsRecentActivitySchema>;
945
+ export type StatsResponse = z.infer<typeof StatsResponseSchema>;
946
+ /**
947
+ * The richer subset of the `GET /v1/stats` response — period + totals +
948
+ * sourceHealth + sourceActivity + recentActivity. The full wire shape
949
+ * (`StatsResponse`) merges these fields with the flat back-compat `Stats`
950
+ * counts.
951
+ */
952
+ export type StatsSummary = Omit<StatsResponse, "orgs" | "sources" | "releases" | "products">;
949
953
 
950
954
  // ── Fetch log ──
951
955
 
@@ -1069,14 +1073,10 @@ export interface Session {
1069
1073
  export type SessionListResponse = ListResponse<Session>;
1070
1074
 
1071
1075
  // ── Admin URL Lists ──
1072
-
1073
- export interface IgnoredUrlItem {
1074
- id: string;
1075
- url: string;
1076
- orgId: string;
1077
- reason: string | null;
1078
- ignoredAt: string;
1079
- }
1076
+ // `IgnoredUrlItem` is now the Zod-derived type exported in the Organizations
1077
+ // section. The hand-written interface below is removed to avoid a duplicate
1078
+ // identifier; callsites that imported it from here continue to work because
1079
+ // the Zod-derived alias has the same shape.
1080
1080
 
1081
1081
  export interface BlockedUrlItem {
1082
1082
  id: string;