@buildinternet/releases-api-types 0.57.1 → 0.58.1

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,7 +1,7 @@
1
1
  {
2
2
  "name": "@buildinternet/releases-api-types",
3
- "version": "0.57.1",
4
- "description": "Wire protocol — request/response types for the Releases registry API. Shared by web, workers, and clients.",
3
+ "version": "0.58.1",
4
+ "description": "Wire protocol — request/response types for the Releases Index API. Shared by web, workers, and clients.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -17,7 +17,7 @@
17
17
  "README.md"
18
18
  ],
19
19
  "dependencies": {
20
- "@buildinternet/releases-core": "^0.34.0",
20
+ "@buildinternet/releases-core": "^0.35.0",
21
21
  "zod": "^4.4.3"
22
22
  },
23
23
  "publishConfig": {
package/src/api-types.ts CHANGED
@@ -396,6 +396,7 @@ export {
396
396
  ListingValidateBodySchema,
397
397
  ListingActivateBodySchema,
398
398
  ListingIssueSchema,
399
+ ListingSetupStepSchema,
399
400
  ListingLocationSchema,
400
401
  ListingOrgPointerSchema,
401
402
  ListingValidationResultSchema,
@@ -419,6 +420,7 @@ export {
419
420
  type ListingValidateBody,
420
421
  type ListingActivateBody,
421
422
  type ListingIssue,
423
+ type ListingSetupStep,
422
424
  type ListingLocation,
423
425
  type ListingValidationResult,
424
426
  type ListingActivateResult,
@@ -2016,8 +2018,8 @@ export interface Session {
2016
2018
  * it must never be reported as `"haiku"`. Surfaces on the detail GET.
2017
2019
  *
2018
2020
  * This is a logical role label, not the runtime model identifier. The
2019
- * resolved Anthropic model string (e.g. `claude-sonnet-5`,
2020
- * `claude-haiku-4-5`) lives on `usage.model` when the session reported
2021
+ * resolved Anthropic model string (e.g. `claude-sonnet-5-5`,
2022
+ * `claude-haiku-5-5`) lives on `usage.model` when the session reported
2021
2023
  * one — consult that field for the concrete model.
2022
2024
  */
2023
2025
  agent?: "sonnet" | "haiku" | "coordinator" | "deterministic";
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { ImportanceScoreSchema, ReleaseItemSchema } from "./shared.js";
2
+ import { ImportanceScoreSchema, ReleaseCompositionSchema, ReleaseItemSchema } from "./shared.js";
3
3
 
4
4
  /**
5
5
  * One org as it appears inside a collection's preview list or detail page.
@@ -291,6 +291,18 @@ export const DigestCoveredReleaseSchema = z.object({
291
291
  * marker on the collapsed "Releases covered" list.
292
292
  */
293
293
  importance: ImportanceScoreSchema,
294
+ /**
295
+ * Per-category item counts from the AI release-content pass. Null when the
296
+ * row hasn't been summarized; optional for older servers. Powers the
297
+ * digest page's week-at-a-glance treemap.
298
+ */
299
+ composition: ReleaseCompositionSchema.nullable().optional(),
300
+ /**
301
+ * ISO publish timestamp, as stored. Null when the source gave none;
302
+ * optional for older servers. A date-only source is stored at exactly
303
+ * `T00:00:00.000Z`. Powers the digest week replay's day placement.
304
+ */
305
+ publishedAt: z.string().nullable().optional(),
294
306
  });
295
307
 
296
308
  /** One `###` section of a digest body, parsed server-side. */
@@ -24,15 +24,27 @@ export const ListingIssueSchema = z.strictObject({
24
24
  });
25
25
  export type ListingIssue = z.infer<typeof ListingIssueSchema>;
26
26
 
27
+ /** One follow-up the owner takes after declaring `publish: "push"`. */
28
+ export const ListingSetupStepSchema = z.strictObject({
29
+ id: z.enum(["verify", "token", "action"]),
30
+ title: z.string(),
31
+ detail: z.string(),
32
+ });
33
+ export type ListingSetupStep = z.infer<typeof ListingSetupStepSchema>;
34
+
27
35
  export const ListingLocationSchema = z.strictObject({
28
36
  /** The declared locator value (feed URL, github ref, url, appstore id, file). */
29
37
  locator: z.string(),
30
- kind: z.enum(["feed", "github", "appstore", "url", "file"]),
31
- classification: z.enum(["tier1-live", "tier2-paused-review"]),
38
+ kind: z.enum(["feed", "github", "appstore", "url", "file", "push"]),
39
+ classification: z.enum(["tier1-live", "tier2-paused-review", "push-setup"]),
32
40
  /** Plain-English "what this becomes" for the preview UI. */
33
41
  becomes: z.string(),
34
42
  /** Present when the locator is nested under a manifest product. */
35
43
  productName: z.string().optional(),
44
+ /** Changelog file or glob. Present on `kind: "push"`. */
45
+ path: z.string().optional(),
46
+ /** Present on `kind: "push"`: verify ownership, mint a token, add the Action. */
47
+ setupSteps: z.array(ListingSetupStepSchema).optional(),
36
48
  });
37
49
  export type ListingLocation = z.infer<typeof ListingLocationSchema>;
38
50
 
@@ -87,6 +87,10 @@ export const ReleaseLocationItemSchema = z.object({
87
87
  productId: z.string().nullable(),
88
88
  /** Set once the locator has been promoted into a source, else null. */
89
89
  sourceId: z.string().nullable(),
90
+ /** `"push"` when the owner publishes this changelog instead of us polling it. */
91
+ publish: z.literal("push").optional(),
92
+ /** Changelog file or glob. Present with `publish: "push"`. */
93
+ path: z.string().optional(),
90
94
  });
91
95
 
92
96
  export const PaginationSchema = z.object({
@@ -122,6 +122,67 @@ describe("releases.json v2 schemas", () => {
122
122
  ).toBe(false);
123
123
  });
124
124
 
125
+ it("accepts a push-publish locator on github + path", () => {
126
+ expect(
127
+ ReleasesJsonDomainSchema.parse({
128
+ version: 2,
129
+ releases: [
130
+ { github: "acme/docs", path: "changelog/**/*.mdx", publish: "push", title: "Docs" },
131
+ ],
132
+ }),
133
+ ).toEqual({
134
+ version: 2,
135
+ releases: [
136
+ { github: "acme/docs", path: "changelog/**/*.mdx", publish: "push", title: "Docs" },
137
+ ],
138
+ });
139
+ expect(
140
+ ReleasesJsonRepoSchema.safeParse({
141
+ version: 2,
142
+ releases: [{ github: "self", path: "CHANGELOG.md", publish: "push" }],
143
+ }).success,
144
+ ).toBe(true);
145
+ });
146
+
147
+ it("rejects an incomplete or unsafe push-publish locator", () => {
148
+ expect(
149
+ ReleasesJsonDomainSchema.safeParse({
150
+ version: 2,
151
+ releases: [{ github: "acme/docs", publish: "push" }],
152
+ }).success,
153
+ ).toBe(false);
154
+ expect(
155
+ ReleasesJsonDomainSchema.safeParse({
156
+ version: 2,
157
+ releases: [{ path: "CHANGELOG.md", publish: "push" }],
158
+ }).success,
159
+ ).toBe(false);
160
+ expect(
161
+ ReleasesJsonDomainSchema.safeParse({
162
+ version: 2,
163
+ releases: [{ github: "acme/docs", path: "CHANGELOG.md" }],
164
+ }).success,
165
+ ).toBe(false);
166
+ expect(
167
+ ReleasesJsonDomainSchema.safeParse({
168
+ version: 2,
169
+ releases: [{ github: "acme/docs", path: "CHANGELOG.md", publish: "poll" }],
170
+ }).success,
171
+ ).toBe(false);
172
+ expect(
173
+ ReleasesJsonDomainSchema.safeParse({
174
+ version: 2,
175
+ releases: [{ github: "acme/docs", path: "../secrets", publish: "push" }],
176
+ }).success,
177
+ ).toBe(false);
178
+ expect(
179
+ ReleasesJsonDomainSchema.safeParse({
180
+ version: 2,
181
+ releases: [{ github: "acme/docs", path: "/etc/passwd", publish: "push" }],
182
+ }).success,
183
+ ).toBe(false);
184
+ });
185
+
125
186
  it("allows github self only in repo files", () => {
126
187
  expect(
127
188
  ReleasesJsonDomainSchema.safeParse({ version: 2, releases: [{ github: "self" }] }).success,
@@ -17,6 +17,19 @@ const HttpsUrlSchema = z.url().startsWith("https://", "locator must be an https
17
17
  /** Shared tag-array bounds — kept identical for org-level and product-level tags. */
18
18
  const TagsSchema = z.array(z.string().min(1).max(60)).max(50);
19
19
 
20
+ /**
21
+ * Changelog file or glob inside the declared repo (Action `changelog-path` /
22
+ * `changelog-glob`). Relative only — no scheme, no leading slash, no `..`.
23
+ */
24
+ const PublishPathSchema = z
25
+ .string()
26
+ .min(1)
27
+ .max(200)
28
+ .regex(
29
+ /^(?!\/)(?!.*(?:^|\/)\.\.(?:\/|$))[A-Za-z0-9._~@%+\-/*?[\]{}]+$/,
30
+ "path must be a relative changelog file or glob",
31
+ );
32
+
20
33
  const ReleaseLocationFields = {
21
34
  url: HttpsUrlSchema.optional(),
22
35
  feed: HttpsUrlSchema.optional(),
@@ -24,6 +37,13 @@ const ReleaseLocationFields = {
24
37
  file: HttpsUrlSchema.optional(),
25
38
  title: z.string().min(1).max(200).optional(),
26
39
  canonical: z.boolean().optional(),
40
+ /**
41
+ * `"push"` means the owner publishes this changelog (GitHub Action / publish
42
+ * token) instead of us polling it. Requires `github` + `path`.
43
+ */
44
+ publish: z.literal("push").optional(),
45
+ /** Required with `publish: "push"`. The file or glob the Action watches. */
46
+ path: PublishPathSchema.optional(),
27
47
  };
28
48
 
29
49
  function hasLocator(value: {
@@ -36,6 +56,12 @@ function hasLocator(value: {
36
56
  return Boolean(value.url || value.feed || value.github || value.appstore || value.file);
37
57
  }
38
58
 
59
+ /** `publish: "push"` is a mode on a github locator, not a locator by itself. */
60
+ function pushPublishComplete(value: { github?: string; publish?: "push"; path?: string }): boolean {
61
+ if (value.publish === "push") return Boolean(value.github && value.path);
62
+ return value.path === undefined;
63
+ }
64
+
39
65
  /** A domain manifest can name a concrete GitHub repository, but never `self`. */
40
66
  export const ReleasesJsonDomainReleaseSchema = z
41
67
  .strictObject({
@@ -45,7 +71,11 @@ export const ReleasesJsonDomainReleaseSchema = z
45
71
  .regex(/^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/, "github must be owner/repo")
46
72
  .optional(),
47
73
  })
48
- .refine(hasLocator, "at least one release locator is required");
74
+ .refine(hasLocator, "at least one release locator is required")
75
+ .refine(
76
+ pushPublishComplete,
77
+ 'publish: "push" requires github (owner/repo) and path (changelog file or glob)',
78
+ );
49
79
 
50
80
  /** A repo manifest additionally accepts `github: "self"`. */
51
81
  export const ReleasesJsonRepoReleaseSchema = z
@@ -58,7 +88,11 @@ export const ReleasesJsonRepoReleaseSchema = z
58
88
  ])
59
89
  .optional(),
60
90
  })
61
- .refine(hasLocator, "at least one release locator is required");
91
+ .refine(hasLocator, "at least one release locator is required")
92
+ .refine(
93
+ pushPublishComplete,
94
+ 'publish: "push" requires github (owner/repo or "self") and path (changelog file or glob)',
95
+ );
62
96
 
63
97
  function releasesArray<T extends z.ZodType>(item: T, max: number) {
64
98
  return z