@buildinternet/releases-api-types 0.57.0 → 0.58.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 +2 -2
- package/src/api-types.ts +2 -0
- package/src/schemas/listing.ts +14 -2
- package/src/schemas/shared.ts +4 -0
- package/src/schemas/well-known.test.ts +61 -0
- package/src/schemas/well-known.ts +36 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buildinternet/releases-api-types",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.58.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.
|
|
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,
|
package/src/schemas/listing.ts
CHANGED
|
@@ -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
|
|
package/src/schemas/shared.ts
CHANGED
|
@@ -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
|