@buildinternet/releases-api-types 0.14.0 → 0.16.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.14.0",
3
+ "version": "0.16.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.19.0",
20
+ "@buildinternet/releases-core": "^0.21.0",
21
21
  "zod": "^4.3.6"
22
22
  },
23
23
  "publishConfig": {
package/src/api-types.ts CHANGED
@@ -133,7 +133,23 @@ export type ErrorResponse = z.infer<typeof ErrorResponseSchema>;
133
133
 
134
134
  export interface SitemapPayload {
135
135
  orgs: Array<{ slug: string; lastActivity: string | null }>;
136
- sources: Array<{ orgSlug: string; slug: string; latestDate: 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
+ }>;
137
153
  products: Array<{ orgSlug: string; slug: string }>;
138
154
  collections: Array<{ slug: string; updatedAt: string }>;
139
155
  }
@@ -681,10 +697,71 @@ export interface TaxonomyProduct {
681
697
 
682
698
  export interface CategoryDetail {
683
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[];
684
715
  orgs: TaxonomyOrg[];
685
716
  products: TaxonomyProduct[];
686
717
  }
687
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
+ }
752
+
753
+ /**
754
+ * 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.
757
+ */
758
+ export type CategoryReleaseItem = CollectionReleaseItem;
759
+
760
+ export interface CategoryReleasesResponse {
761
+ releases: CategoryReleaseItem[];
762
+ pagination: { nextCursor: string | null; limit: number };
763
+ }
764
+
688
765
  export interface TagDetail {
689
766
  slug: string;
690
767
  name: string;
@@ -47,6 +47,12 @@ export const ReleaseItemSchema = z.object({
47
47
  summary: z.string(),
48
48
  content: z.string().optional(),
49
49
  publishedAt: z.string().nullable(),
50
+ // ISO timestamp of when the row was fetched/inserted — used by the feed
51
+ // cursor's tie-break (publishedAt|fetchedAt|id) so that same-`publishedAt`
52
+ // rows stay stably ordered across paginated requests. `.optional()` because
53
+ // not every endpoint that returns a ReleaseItem populates it (notably
54
+ // single-release reads).
55
+ fetchedAt: z.string().optional(),
50
56
  url: z.string().nullable(),
51
57
  media: z.array(MediaItemSchema).optional(),
52
58
  // `.optional()` — older API responses (mid-deploy or pinned old workers)