@buildinternet/releases-api-types 0.23.0 → 0.24.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buildinternet/releases-api-types",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "Wire protocol — request/response types for the Releases registry API. Shared by web, workers, and clients.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/api-types.ts CHANGED
@@ -64,6 +64,7 @@ import type {
64
64
  SourceDetailSchema,
65
65
  SourceFeedPaginationSchema,
66
66
  SourceMutationResponseSchema,
67
+ AppStoreMaterializeResponseSchema,
67
68
  SourceOrgRefSchema,
68
69
  SourcePatchInputSchema,
69
70
  CreateSourceBodySchema,
@@ -120,6 +121,7 @@ import type {
120
121
  ReleaseLatestProductSchema,
121
122
  ReleaseLatestItemSchema,
122
123
  ReleaseLatestResponseSchema,
124
+ ReleaseCoverageSiblingSchema,
123
125
  ReleaseCoverageRowSchema,
124
126
  ReleaseCoverageResponseSchema,
125
127
  LinkReleaseCoverageBodySchema,
@@ -288,6 +290,7 @@ export {
288
290
  SourceDetailSchema,
289
291
  SourceFeedPaginationSchema,
290
292
  SourceMutationResponseSchema,
293
+ AppStoreMaterializeResponseSchema,
291
294
  SourceOrgRefSchema,
292
295
  SourcePatchInputSchema,
293
296
  CreateSourceBodySchema,
@@ -370,6 +373,7 @@ export {
370
373
  ReleaseLatestProductSchema,
371
374
  ReleaseLatestItemSchema,
372
375
  ReleaseLatestResponseSchema,
376
+ ReleaseCoverageSiblingSchema,
373
377
  ReleaseCoverageRowSchema,
374
378
  ReleaseCoverageResponseSchema,
375
379
  LinkReleaseCoverageBodySchema,
@@ -546,6 +550,7 @@ export type SourceChangelogResponse = z.infer<typeof SourceChangelogResponseSche
546
550
  export type SourceDetail = z.infer<typeof SourceDetailSchema>;
547
551
  export type SourceFeedPagination = z.infer<typeof SourceFeedPaginationSchema>;
548
552
  export type SourceMutationResponse = z.infer<typeof SourceMutationResponseSchema>;
553
+ export type AppStoreMaterializeResponse = z.infer<typeof AppStoreMaterializeResponseSchema>;
549
554
  export type SourceOrgRef = z.infer<typeof SourceOrgRefSchema>;
550
555
  export type SourceActivityResponse = z.infer<typeof SourceActivityResponseSchema>;
551
556
  export type SourceHeatmapResponse = z.infer<typeof SourceHeatmapResponseSchema>;
@@ -700,6 +705,7 @@ export interface ReleaseDetail {
700
705
  appStore?: { platform: "ios" | "macos"; iconUrl: string | null } | null;
701
706
  }
702
707
 
708
+ export type ReleaseCoverageSibling = z.infer<typeof ReleaseCoverageSiblingSchema>;
703
709
  export type ReleaseCoverageRow = z.infer<typeof ReleaseCoverageRowSchema>;
704
710
  export type ReleaseCoverageResponse = z.infer<typeof ReleaseCoverageResponseSchema>;
705
711
  export type LinkReleaseCoverageBody = z.infer<typeof LinkReleaseCoverageBodySchema>;
@@ -107,6 +107,16 @@ export const CollectionReleaseItemSchema = ReleaseItemSchema.extend({
107
107
  * typecheck — clients should treat missing and `null` identically.
108
108
  */
109
109
  product: z.object({ slug: z.string(), name: z.string() }).nullable().optional(),
110
+ /**
111
+ * Server-resolved grouping identity — `COALESCE(product.slug, source.slug)` /
112
+ * `COALESCE(product.name, source.name)`. The web release feeds key and label
113
+ * SDK/package-cluster rollups on these instead of reconstructing
114
+ * `product ?? source` client-side. Optional on the wire: older workers omit
115
+ * them, so clients must fall back to deriving from `product ?? source`. Never
116
+ * null when present (`source` is always set). #1234
117
+ */
118
+ groupSlug: z.string().optional(),
119
+ groupName: z.string().optional(),
110
120
  });
111
121
 
112
122
  /** Cursor pagination shape matches `/v1/orgs/:slug/releases`. */
@@ -348,6 +348,16 @@ export const OrgReleaseItemSchema = ReleaseItemSchema.extend({
348
348
  * omit this field; treat `undefined` as `null`. #1217.
349
349
  */
350
350
  product: z.object({ slug: z.string(), name: z.string() }).nullable().optional(),
351
+ /**
352
+ * Server-resolved grouping identity — `COALESCE(product.slug, source.slug)` /
353
+ * `COALESCE(product.name, source.name)`. The web releases feed keys and labels
354
+ * SDK/package-cluster rollups on these instead of reconstructing
355
+ * `product ?? source` client-side. Optional on the wire: older workers omit
356
+ * them, so clients must fall back to deriving from `product ?? source`. Never
357
+ * null when present (`source` is always set). #1234
358
+ */
359
+ groupSlug: z.string().optional(),
360
+ groupName: z.string().optional(),
351
361
  });
352
362
 
353
363
  /** Cursor pagination shape for the org releases feed. */
@@ -38,6 +38,8 @@ export type ProductCreateResponse = z.infer<typeof ProductCreateResponseSchema>;
38
38
  * Per-product row returned by `GET /v1/products`. Adds `sourceCount` to
39
39
  * the row shape but omits the internal `embeddedAt` / `deletedAt` columns
40
40
  * (the list handler explicitly selects only the user-facing fields).
41
+ * `avatarUrl` (the product icon, e.g. an App Store app icon) is included so
42
+ * list surfaces can render the avatar without a per-row detail round-trip.
41
43
  */
42
44
  export const ProductListItemSchema = z.object({
43
45
  id: z.string(),
@@ -48,6 +50,7 @@ export const ProductListItemSchema = z.object({
48
50
  description: z.string().nullable(),
49
51
  category: CategorySchema.nullable(),
50
52
  kind: z.enum(KIND_VALUES).nullable().optional(),
53
+ avatarUrl: z.string().nullable().optional(),
51
54
  createdAt: z.string(),
52
55
  sourceCount: z.number().int().min(0),
53
56
  });
@@ -62,9 +62,31 @@ export const ReleaseLatestResponseSchema = z.object({
62
62
  releases: z.array(ReleaseLatestItemSchema),
63
63
  });
64
64
 
65
+ /**
66
+ * Display fields for the counterpart release a coverage row points at —
67
+ * the canonical for a `coverage`-role response, or each rolled-up coverage
68
+ * release for a `canonical`-role response. Lets `GET /releases/:id/coverage`
69
+ * render a cluster without a follow-up `GET /releases/:id` per sibling.
70
+ * `null` when the counterpart is suppressed or its source was removed.
71
+ *
72
+ * Coverage-side rows are surfaced here on purpose, even though the
73
+ * `releases_visible` view (and thus `GET /releases/:id`) hides them — a
74
+ * cluster view's whole job is to show its members.
75
+ */
76
+ export const ReleaseCoverageSiblingSchema = z.object({
77
+ id: z.string(),
78
+ version: z.string().nullable(),
79
+ title: z.string(),
80
+ sourceName: z.string(),
81
+ publishedAt: z.string().nullable(),
82
+ org: z.object({ slug: z.string(), name: z.string() }).nullable(),
83
+ });
84
+
65
85
  /**
66
86
  * Single row of the `release_coverage` join table. Drives the
67
- * GET /releases/:id/coverage response.
87
+ * GET /releases/:id/coverage response. `sibling` carries the counterpart
88
+ * release's display fields (see {@link ReleaseCoverageSiblingSchema}); it is
89
+ * optional so an older server that doesn't populate it still validates.
68
90
  */
69
91
  export const ReleaseCoverageRowSchema = z.object({
70
92
  coverageId: z.string(),
@@ -72,6 +94,7 @@ export const ReleaseCoverageRowSchema = z.object({
72
94
  reason: z.string().nullable(),
73
95
  decidedBy: z.string(),
74
96
  decidedAt: z.string(),
97
+ sibling: ReleaseCoverageSiblingSchema.nullable().optional(),
75
98
  });
76
99
 
77
100
  /**
@@ -194,6 +194,38 @@ export const SourceMutationResponseSchema = z.looseObject({
194
194
  kind: z.enum(KIND_VALUES).nullable().optional(),
195
195
  });
196
196
 
197
+ /**
198
+ * Response from `POST /v1/sources/appstore` — materializes an App Store listing
199
+ * into a curated Org → Product → Source → first Release (modeled on the GitHub
200
+ * coordinate `LookupResponse`).
201
+ *
202
+ * Unlike `SourceMutationResponse`, the `source` here is the **bare inserted (or
203
+ * idempotently looked-up) drizzle row** the materialize handler returns verbatim:
204
+ * no resolved `org { id, slug, name }` block and no `productSlug`. `loose` so the
205
+ * untyped timestamp/counter columns on the row pass through.
206
+ *
207
+ * `status: "indexed"` is a brand-new source (HTTP 201); `"existing"` is the
208
+ * idempotent hit on a prior materialize of the same trackId (HTTP 200).
209
+ */
210
+ export const AppStoreMaterializeResponseSchema = z.object({
211
+ status: z.enum(["indexed", "existing"]),
212
+ source: z.looseObject({
213
+ id: z.string(),
214
+ slug: z.string(),
215
+ name: z.string(),
216
+ type: SourceTypeSchema,
217
+ url: z.string(),
218
+ orgId: z.string().nullable(),
219
+ productId: z.string().nullable(),
220
+ metadata: z.string().nullable(),
221
+ kind: z.enum(KIND_VALUES).nullable().optional(),
222
+ discovery: SourceDiscoverySchema.optional(),
223
+ isHidden: z.boolean().nullable().optional(),
224
+ createdAt: z.string().optional(),
225
+ }),
226
+ releaseCount: z.number(),
227
+ });
228
+
197
229
  /** Body accepted by `PATCH /v1/sources/:slug`. */
198
230
  export const SourcePatchInputSchema = z.object({
199
231
  name: z.string().optional(),