@buildinternet/releases-api-types 0.21.0 → 0.22.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.21.0",
3
+ "version": "0.22.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",
@@ -17,7 +17,7 @@
17
17
  "README.md"
18
18
  ],
19
19
  "dependencies": {
20
- "@buildinternet/releases-core": "^0.21.0",
20
+ "@buildinternet/releases-core": "^0.22.0",
21
21
  "zod": "^4.4.3"
22
22
  },
23
23
  "publishConfig": {
package/src/api-types.ts CHANGED
@@ -644,17 +644,22 @@ export type SearchSourceHit = z.infer<typeof SearchSourceHitSchema>;
644
644
  export interface RawSourceHit extends SearchSourceHit {
645
645
  productName?: string;
646
646
  productCategory?: string;
647
+ /** Entity taxonomy kind from the `sources.kind` column. */
648
+ entityKind?: string | null;
647
649
  }
648
650
 
649
651
  /**
650
652
  * Fold source hits into the catalog list. Sources under a matched product
651
- * are dropped (product wins); orphan sources become `kind: "source"`.
653
+ * are dropped (product wins); orphan sources become `entryType: "source"`.
652
654
  */
653
655
  export function foldSourcesIntoCatalog(
654
656
  existingProducts: SearchCatalogHit[],
655
657
  rawSources: RawSourceHit[],
656
658
  ): SearchCatalogHit[] {
657
- const result: SearchCatalogHit[] = existingProducts.map((p) => ({ ...p, kind: "product" }));
659
+ const result: SearchCatalogHit[] = existingProducts.map((p) => ({
660
+ ...p,
661
+ entryType: "product" as const,
662
+ }));
658
663
  const seen = new Set(result.map((p) => p.slug));
659
664
  for (const s of rawSources) {
660
665
  if (s.productSlug) {
@@ -665,7 +670,8 @@ export function foldSourcesIntoCatalog(
665
670
  orgSlug: s.orgSlug,
666
671
  orgName: s.orgName,
667
672
  category: s.productCategory ?? null,
668
- kind: "product",
673
+ entryType: "product",
674
+ kind: undefined,
669
675
  });
670
676
  seen.add(s.productSlug);
671
677
  } else {
@@ -675,7 +681,8 @@ export function foldSourcesIntoCatalog(
675
681
  orgSlug: s.orgSlug,
676
682
  orgName: s.orgName,
677
683
  category: null,
678
- kind: "source",
684
+ entryType: "source",
685
+ kind: (s.entityKind as SearchCatalogHit["kind"]) ?? undefined,
679
686
  sourceSlug: s.slug,
680
687
  sourceType: s.type,
681
688
  });
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { KIND_VALUES } from "@buildinternet/releases-core/kinds";
2
3
  import { CategorySchema } from "./shared.js";
3
4
 
4
5
  /**
@@ -114,6 +115,7 @@ export const DomainLookupProductSchema = z.object({
114
115
  // path resolves through `resolveCategoryInput` before persisting — unlike
115
116
  // the search catalog category, which passes the column through raw.
116
117
  category: CategorySchema.nullable(),
118
+ kind: z.enum(KIND_VALUES).nullable().optional(),
117
119
  });
118
120
 
119
121
  export const DomainLookupResponseSchema = z.object({
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { KIND_VALUES } from "@buildinternet/releases-core/kinds";
2
3
  import {
3
4
  CategorySchema,
4
5
  ListResponseSchema,
@@ -125,7 +126,8 @@ const OrgDetailPlaybookSchema = z.object({
125
126
  // ── Org catalog (/orgs/:slug/catalog) ──
126
127
 
127
128
  const OrgCatalogProductItemSchema = z.object({
128
- kind: z.literal("product"),
129
+ entryType: z.literal("product"),
130
+ kind: z.enum(KIND_VALUES).nullable().optional(),
129
131
  id: z.string(),
130
132
  slug: z.string(),
131
133
  name: z.string(),
@@ -135,7 +137,8 @@ const OrgCatalogProductItemSchema = z.object({
135
137
  });
136
138
 
137
139
  const OrgCatalogSourceItemSchema = z.object({
138
- kind: z.literal("source"),
140
+ entryType: z.literal("source"),
141
+ kind: z.enum(KIND_VALUES).nullable().optional(),
139
142
  id: z.string(),
140
143
  slug: z.string(),
141
144
  name: z.string(),
@@ -146,10 +149,12 @@ const OrgCatalogSourceItemSchema = z.object({
146
149
 
147
150
  /**
148
151
  * Combined product + source catalog for `GET /v1/orgs/:slug/catalog`.
149
- * `kind` discriminates between the two row shapes. Products carry
150
- * `category` and `description`; sources carry `type` and `productId`.
152
+ * `entryType` discriminates between the two row shapes (`"product"` vs
153
+ * `"source"`). `kind` carries the entity taxonomy (platform/sdk/mobile/…).
154
+ * Products carry `category` and `description`; sources carry `type` and
155
+ * `productId`.
151
156
  */
152
- export const OrgCatalogItemSchema = z.discriminatedUnion("kind", [
157
+ export const OrgCatalogItemSchema = z.discriminatedUnion("entryType", [
153
158
  OrgCatalogProductItemSchema,
154
159
  OrgCatalogSourceItemSchema,
155
160
  ]);
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { KIND_VALUES } from "@buildinternet/releases-core/kinds";
2
3
  import { CategorySchema, ListResponseSchema } from "./shared.js";
3
4
  import { SourceTypeSchema } from "./sources.js";
4
5
 
@@ -19,6 +20,7 @@ export const ProductRowSchema = z.object({
19
20
  url: z.string().nullable(),
20
21
  description: z.string().nullable(),
21
22
  category: CategorySchema.nullable(),
23
+ kind: z.enum(KIND_VALUES).nullable().optional(),
22
24
  createdAt: z.string(),
23
25
  embeddedAt: z.string().nullable(),
24
26
  deletedAt: z.string().nullable(),
@@ -37,6 +39,7 @@ export const ProductListItemSchema = z.object({
37
39
  url: z.string().nullable(),
38
40
  description: z.string().nullable(),
39
41
  category: CategorySchema.nullable(),
42
+ kind: z.enum(KIND_VALUES).nullable().optional(),
40
43
  createdAt: z.string(),
41
44
  sourceCount: z.number().int().min(0),
42
45
  });
@@ -83,6 +86,7 @@ export const CreateProductBodySchema = z.object({
83
86
  description: z.string().optional(),
84
87
  category: z.string().min(1).optional(),
85
88
  tags: z.array(z.string()).optional(),
89
+ kind: z.enum(KIND_VALUES).nullable().optional(),
86
90
  });
87
91
 
88
92
  /**
@@ -97,6 +101,7 @@ export const UpdateProductBodySchema = z.object({
97
101
  category: z.string().min(1).nullable().optional(),
98
102
  tags: z.array(z.string()).optional(),
99
103
  aliases: z.array(z.string()).optional(),
104
+ kind: z.enum(KIND_VALUES).nullable().optional(),
100
105
  });
101
106
 
102
107
  /**
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { KIND_VALUES } from "@buildinternet/releases-core/kinds";
2
3
  import { MediaItemSchema, ReleaseTypeSchema } from "./shared.js";
3
4
  import { SourceTypeSchema } from "./sources.js";
4
5
  import { LookupStatusSchema } from "./lookups.js";
@@ -24,10 +25,10 @@ export const SearchOrgHitSchema = z.object({
24
25
 
25
26
  /**
26
27
  * Unified catalog entry — either a product row or a standalone source
27
- * presented as product-shaped. `kind` routes clicks to the right URL but
28
- * the two forms are otherwise interchangeable for display. `kind` (not
29
- * `type`) because source rows already carry
30
- * `type: github|scrape|feed|agent` on the wire.
28
+ * presented as product-shaped. `entryType` discriminates between the two
29
+ * row shapes (`"product"` vs `"source"`). `kind` carries the entity
30
+ * taxonomy (platform/sdk/mobile/…). `entryType` (not `type`) because
31
+ * source rows already carry `type: github|scrape|feed|agent` on the wire.
31
32
  */
32
33
  export const SearchCatalogHitSchema = z.object({
33
34
  slug: z.string(),
@@ -41,7 +42,8 @@ export const SearchCatalogHitSchema = z.object({
41
42
  // that haven't been migrated yet. Tighten once #689 (category overlay
42
43
  // backfill) lands across the prod data set.
43
44
  category: z.string().nullable(),
44
- kind: z.enum(["product", "source"]),
45
+ entryType: z.enum(["product", "source"]),
46
+ kind: z.enum(KIND_VALUES).nullable().optional(),
45
47
  sourceSlug: z.string().optional(),
46
48
  sourceType: SourceTypeSchema.optional(),
47
49
  });
@@ -4,6 +4,7 @@ import {
4
4
  SOURCE_DISCOVERY,
5
5
  SOURCE_FETCH_PRIORITIES,
6
6
  } from "@buildinternet/releases-core/source-enums";
7
+ import { KIND_VALUES } from "@buildinternet/releases-core/kinds";
7
8
  import { ListResponseSchema, ReleaseItemSchema, ReleaseSummaryItemSchema } from "./shared.js";
8
9
 
9
10
  export const SourceTypeSchema = z.enum(SOURCE_TYPES);
@@ -48,6 +49,7 @@ export const SourceListItemSchema = z.object({
48
49
  metadata: z.string().nullable().optional(),
49
50
  productName: z.string().nullable().optional(),
50
51
  productSlug: z.string().nullable().optional(),
52
+ kind: z.enum(KIND_VALUES).nullable().optional(),
51
53
  });
52
54
 
53
55
  /**
@@ -81,6 +83,7 @@ export const SourceWithOrgSchema = z.object({
81
83
  nextFetchAfter: z.string().nullable(),
82
84
  medianGapDays: z.number().nullable(),
83
85
  lastRetieredAt: z.string().nullable(),
86
+ kind: z.enum(KIND_VALUES).nullable().optional(),
84
87
  });
85
88
 
86
89
  export const SourceListResponseSchema = ListResponseSchema(SourceWithOrgSchema);
@@ -157,6 +160,7 @@ export const SourceDetailSchema = z.object({
157
160
  releases: z.array(ReleaseItemSchema),
158
161
  pagination: SourceFeedPaginationSchema,
159
162
  summaries: SourceDetailSummariesSchema,
163
+ kind: z.enum(KIND_VALUES).nullable().optional(),
160
164
  });
161
165
 
162
166
  /**
@@ -187,6 +191,7 @@ export const SourceMutationResponseSchema = z.looseObject({
187
191
  isHidden: z.boolean().nullable().optional(),
188
192
  discovery: SourceDiscoverySchema.optional(),
189
193
  createdAt: z.string().optional(),
194
+ kind: z.enum(KIND_VALUES).nullable().optional(),
190
195
  });
191
196
 
192
197
  /** Body accepted by `PATCH /v1/sources/:slug`. */
@@ -208,6 +213,7 @@ export const SourcePatchInputSchema = z.object({
208
213
  isHidden: z.boolean().optional(),
209
214
  changeDetectedAt: z.string().nullable().optional(),
210
215
  lastPolledAt: z.string().nullable().optional(),
216
+ kind: z.enum(KIND_VALUES).nullable().optional(),
211
217
  });
212
218
 
213
219
  /** Body accepted by `POST /v1/sources`. */
@@ -228,6 +234,7 @@ export const CreateSourceBodySchema = z.object({
228
234
  productSlug: z.string().optional(),
229
235
  metadata: z.string().optional(),
230
236
  isPrimary: z.boolean().optional(),
237
+ kind: z.enum(KIND_VALUES).nullable().optional(),
231
238
  });
232
239
 
233
240
  export const ChangelogFileSummarySchema = z.object({