@buildinternet/releases-api-types 0.50.0 → 0.52.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.50.0",
3
+ "version": "0.52.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.29.0",
20
+ "@buildinternet/releases-core": "^0.30.0",
21
21
  "zod": "^4.4.3"
22
22
  },
23
23
  "publishConfig": {
package/src/api-types.ts CHANGED
@@ -14,6 +14,13 @@ export type {
14
14
  import type { SourceType, SourceFetchPriority } from "@buildinternet/releases-core/source-enums";
15
15
  import type { ApiScope } from "@buildinternet/releases-core/api-token";
16
16
  import type { BreakingLevel } from "@buildinternet/releases-core/breaking";
17
+ import type {
18
+ AiLaneIdSchema,
19
+ AiLaneModelsPutSchema,
20
+ AiLaneStateSchema,
21
+ OpenRouterCatalogModelSchema,
22
+ AiLaneModelsResponseSchema,
23
+ } from "./schemas/ai-models.js";
17
24
  import type {
18
25
  MediaItemSchema,
19
26
  PaginationSchema,
@@ -67,6 +74,12 @@ import type {
67
74
  PatchWorkspaceProfileBodySchema,
68
75
  WorkspaceProfileResponseSchema,
69
76
  } from "./schemas/account-profile.js";
77
+ import type {
78
+ UploadsIntegrationStatusSchema,
79
+ UploadsOAuthConnectResponseSchema,
80
+ UploadsOAuthCallbackBodySchema,
81
+ UploadsOAuthCallbackResponseSchema,
82
+ } from "./schemas/workspace-integrations.js";
70
83
  import type {
71
84
  SourceListItemSchema,
72
85
  SourceWithOrgSchema,
@@ -203,6 +216,10 @@ import type {
203
216
  FeedbackUpdateBodySchema,
204
217
  FeedbackDeleteResponseSchema,
205
218
  } from "./schemas/feedback.js";
219
+ import type {
220
+ RecommendationNotifyAddedBodySchema,
221
+ RecommendationNotifyAddedResultSchema,
222
+ } from "./schemas/recommendations.js";
206
223
  import type {
207
224
  SitemapSourceSchema,
208
225
  SitemapPayloadSchema,
@@ -280,6 +297,13 @@ export {
280
297
  NoticeSchema,
281
298
  } from "./schemas/shared.js";
282
299
  export { SiteNoticeSchema, SiteNoticeResponseSchema } from "./schemas/site-notice.js";
300
+ export {
301
+ AiLaneIdSchema,
302
+ AiLaneModelsPutSchema,
303
+ AiLaneStateSchema,
304
+ OpenRouterCatalogModelSchema,
305
+ AiLaneModelsResponseSchema,
306
+ } from "./schemas/ai-models.js";
283
307
  export {
284
308
  OrgListItemSchema,
285
309
  OrgListResponseSchema,
@@ -320,6 +344,12 @@ export {
320
344
  PatchWorkspaceProfileBodySchema,
321
345
  WorkspaceProfileResponseSchema,
322
346
  } from "./schemas/account-profile.js";
347
+ export {
348
+ UploadsIntegrationStatusSchema,
349
+ UploadsOAuthConnectResponseSchema,
350
+ UploadsOAuthCallbackBodySchema,
351
+ UploadsOAuthCallbackResponseSchema,
352
+ } from "./schemas/workspace-integrations.js";
323
353
  export {
324
354
  CreateStubOrgBodySchema,
325
355
  StubFromDomainBodySchema,
@@ -363,6 +393,7 @@ export {
363
393
  ListingPromoteLocatorOutcomeSchema,
364
394
  ListingPromoteLocatorSchema,
365
395
  ListingPromoteResultSchema,
396
+ ListingCapabilitiesSchema,
366
397
  type ListingValidateBody,
367
398
  type ListingActivateBody,
368
399
  type ListingIssue,
@@ -381,6 +412,7 @@ export {
381
412
  type ListingPromoteLocatorOutcome,
382
413
  type ListingPromoteLocator,
383
414
  type ListingPromoteResult,
415
+ type ListingCapabilities,
384
416
  } from "./schemas/listing.js";
385
417
  export {
386
418
  SourceListItemSchema,
@@ -519,6 +551,10 @@ export {
519
551
  FeedbackUpdateBodySchema,
520
552
  FeedbackDeleteResponseSchema,
521
553
  } from "./schemas/feedback.js";
554
+ export {
555
+ RecommendationNotifyAddedBodySchema,
556
+ RecommendationNotifyAddedResultSchema,
557
+ } from "./schemas/recommendations.js";
522
558
  export {
523
559
  SitemapSourceSchema,
524
560
  SitemapPayloadSchema,
@@ -587,6 +623,12 @@ export type { ResolveResponse } from "./schemas/resolve.js";
587
623
 
588
624
  export type MediaItem = z.infer<typeof MediaItemSchema>;
589
625
 
626
+ export type AiLaneId = z.infer<typeof AiLaneIdSchema>;
627
+ export type AiLaneModelsPut = z.infer<typeof AiLaneModelsPutSchema>;
628
+ export type AiLaneState = z.infer<typeof AiLaneStateSchema>;
629
+ export type OpenRouterCatalogModel = z.infer<typeof OpenRouterCatalogModelSchema>;
630
+ export type AiLaneModelsResponse = z.infer<typeof AiLaneModelsResponseSchema>;
631
+
590
632
  // ── Stub tier (#1947) ──
591
633
 
592
634
  export type OrgStatus = z.infer<typeof OrgStatusSchema>;
@@ -641,7 +683,9 @@ export interface CreateUserApiKeyBody {
641
683
 
642
684
  export type SitemapSource = z.infer<typeof SitemapSourceSchema>;
643
685
  export type SitemapPayload = z.infer<typeof SitemapPayloadSchema>;
686
+ /** @deprecated The `GET /v1/sitemap/releases` endpoint was retired in #2219. */
644
687
  export type SitemapRelease = z.infer<typeof SitemapReleaseSchema>;
688
+ /** @deprecated The `GET /v1/sitemap/releases` endpoint was retired in #2219. */
645
689
  export type SitemapReleasesPayload = z.infer<typeof SitemapReleasesPayloadSchema>;
646
690
 
647
691
  // ── Related (Vectorize neighbors) ──
@@ -673,6 +717,10 @@ export type UploadAvatarResponse = z.infer<typeof UploadAvatarResponseSchema>;
673
717
  export type WorkspaceProfileFields = z.infer<typeof WorkspaceProfileFieldsSchema>;
674
718
  export type PatchWorkspaceProfileBody = z.infer<typeof PatchWorkspaceProfileBodySchema>;
675
719
  export type WorkspaceProfileResponse = z.infer<typeof WorkspaceProfileResponseSchema>;
720
+ export type UploadsIntegrationStatus = z.infer<typeof UploadsIntegrationStatusSchema>;
721
+ export type UploadsOAuthConnectResponse = z.infer<typeof UploadsOAuthConnectResponseSchema>;
722
+ export type UploadsOAuthCallbackBody = z.infer<typeof UploadsOAuthCallbackBodySchema>;
723
+ export type UploadsOAuthCallbackResponse = z.infer<typeof UploadsOAuthCallbackResponseSchema>;
676
724
  export type OrgDetail = z.infer<typeof OrgDetailSchema>;
677
725
 
678
726
  export type OrgCatalogItem = z.infer<typeof OrgCatalogItemSchema>;
@@ -865,6 +913,12 @@ export interface ProviderHealthResponse extends ListResponse<ProviderHealthSourc
865
913
  overdueOrgs: number;
866
914
  /** Distinct orgs represented among active sources. */
867
915
  totalOrgs: number;
916
+ /**
917
+ * Active sources that should still be polling but whose SourceActor mirror
918
+ * is unmanaged / missing `nextAlarmAt` (#2286). Independent of overdue
919
+ * last-check — a freshly fetched source can still have a dead alarm.
920
+ */
921
+ unmanagedActors: number;
868
922
  };
869
923
  }
870
924
 
@@ -1119,7 +1173,7 @@ export type UserWebhookScope = "org" | "follows";
1119
1173
  export type UserWebhookReleaseTypeFilter = "feature" | "rollup";
1120
1174
 
1121
1175
  /** Webhook delivery output format. */
1122
- export type UserWebhookFormat = "json" | "slack";
1176
+ export type UserWebhookFormat = "json" | "slack" | "discord";
1123
1177
 
1124
1178
  /** A user-owned webhook subscription row (no signing secret). */
1125
1179
  export interface UserWebhookSubscription {
@@ -1166,7 +1220,7 @@ export interface UserWebhookListResponse {
1166
1220
  subscriptions: UserWebhookListItem[];
1167
1221
  }
1168
1222
 
1169
- /** POST /v1/me/webhooks response — signing key shown once at creation (omitted for slack format). */
1223
+ /** POST /v1/me/webhooks response — signing key shown once at creation (omitted for slack/discord). */
1170
1224
  export interface CreateUserWebhookResponse
1171
1225
  extends UserWebhookSubscription, UserWebhookDeliveryHealth {
1172
1226
  orgSlug: string | null;
@@ -1193,7 +1247,7 @@ export interface WebhookDeliveryRow {
1193
1247
  error_message?: string | null;
1194
1248
  error_code?: string | null;
1195
1249
  outcome?: string;
1196
- /** Delivery format — "json" (signed raw event) or "slack" (Block Kit). Empty on pre-format rows. */
1250
+ /** Delivery format — "json" (signed raw event) or a chat card (`slack` / `discord`). Empty on pre-format rows. */
1197
1251
  format?: UserWebhookFormat | "";
1198
1252
  http_status?: number;
1199
1253
  latency_ms?: number;
@@ -1701,6 +1755,10 @@ export type FeedbackListResponse = z.infer<typeof FeedbackListResponseSchema>;
1701
1755
  export type FeedbackUpdateBody = z.infer<typeof FeedbackUpdateBodySchema>;
1702
1756
  export type FeedbackDeleteResponse = z.infer<typeof FeedbackDeleteResponseSchema>;
1703
1757
 
1758
+ // ── Recommendations ──
1759
+ export type RecommendationNotifyAddedBody = z.infer<typeof RecommendationNotifyAddedBodySchema>;
1760
+ export type RecommendationNotifyAddedResult = z.infer<typeof RecommendationNotifyAddedResultSchema>;
1761
+
1704
1762
  // ── Fetch log ──
1705
1763
 
1706
1764
  export interface FetchLogEntry {
@@ -0,0 +1,29 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { AiLaneModelsPutSchema } from "./ai-models";
3
+
4
+ describe("AiLaneModelsPutSchema", () => {
5
+ it("accepts a partial map", () => {
6
+ expect(
7
+ AiLaneModelsPutSchema.safeParse({
8
+ models: { summarize: "deepseek/deepseek-v4.1-flash" },
9
+ }).success,
10
+ ).toBe(true);
11
+ });
12
+
13
+ it("accepts null to clear an override", () => {
14
+ expect(AiLaneModelsPutSchema.safeParse({ models: { extract: null } }).success).toBe(true);
15
+ });
16
+
17
+ it("rejects an empty models object", () => {
18
+ expect(AiLaneModelsPutSchema.safeParse({ models: {} }).success).toBe(false);
19
+ });
20
+
21
+ it("rejects unknown keys", () => {
22
+ expect(
23
+ AiLaneModelsPutSchema.safeParse({
24
+ models: { summarize: "x" },
25
+ extra: true,
26
+ }).success,
27
+ ).toBe(false);
28
+ });
29
+ });
@@ -0,0 +1,49 @@
1
+ import { z } from "zod";
2
+
3
+ export const AiLaneIdSchema = z.enum(["summarize", "extract", "feed-enrich", "marketing"]);
4
+
5
+ const ModelIdOrClearSchema = z.string().max(200).nullable().optional();
6
+
7
+ /** PUT /v1/ai/models — partial map; `null` or `""` clears that lane's override. */
8
+ export const AiLaneModelsPutSchema = z
9
+ .object({
10
+ models: z
11
+ .object({
12
+ summarize: ModelIdOrClearSchema,
13
+ extract: ModelIdOrClearSchema,
14
+ "feed-enrich": ModelIdOrClearSchema,
15
+ marketing: ModelIdOrClearSchema,
16
+ })
17
+ .refine((m) => Object.values(m).some((v) => v !== undefined), {
18
+ message: "at least one lane is required",
19
+ }),
20
+ })
21
+ .strict();
22
+
23
+ export const AiLaneStateSchema = z.object({
24
+ id: AiLaneIdSchema,
25
+ label: z.string(),
26
+ description: z.string(),
27
+ envVar: z.string(),
28
+ wranglerDefault: z.string().nullable(),
29
+ override: z.string().nullable(),
30
+ effective: z.string().nullable(),
31
+ });
32
+
33
+ export const OpenRouterCatalogModelSchema = z.object({
34
+ id: z.string(),
35
+ name: z.string(),
36
+ contextLength: z.number().nullable(),
37
+ promptPricePerMillion: z.number().nullable(),
38
+ completionPricePerMillion: z.number().nullable(),
39
+ vision: z.boolean(),
40
+ });
41
+
42
+ /** GET /v1/ai/models — current assignments plus the OpenRouter catalog. */
43
+ export const AiLaneModelsResponseSchema = z.object({
44
+ lanes: z.array(AiLaneStateSchema),
45
+ catalog: z.array(OpenRouterCatalogModelSchema),
46
+ catalogFetchedAt: z.string().nullable(),
47
+ catalogError: z.string().nullable(),
48
+ updatedAt: z.string().nullable(),
49
+ });
@@ -168,3 +168,16 @@ export const ListingPromoteResultSchema = z.strictObject({
168
168
  locators: z.array(ListingPromoteLocatorSchema),
169
169
  });
170
170
  export type ListingPromoteResult = z.infer<typeof ListingPromoteResultSchema>;
171
+
172
+ /**
173
+ * Public capability flags for the listing lane. Anonymous + always reachable
174
+ * (does NOT 404 when either kill switch is off) so the web UI can hide CTAs
175
+ * instead of offering a button that fails with "Not found".
176
+ */
177
+ export const ListingCapabilitiesSchema = z.strictObject({
178
+ /** `listing-self-serve-enabled` — validate / activate / claim / verify. */
179
+ selfServeEnabled: z.boolean(),
180
+ /** `listing-self-serve-promotion-enabled` — POST /v1/listing/promote. */
181
+ promotionEnabled: z.boolean(),
182
+ });
183
+ export type ListingCapabilities = z.infer<typeof ListingCapabilitiesSchema>;
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * `POST /v1/admin/recommendations/:id/notify-added` body.
5
+ *
6
+ * Resolves a live registry listing (org required, source optional) and
7
+ * emails the submitter's `contactEmail` that their suggestion was added.
8
+ * Opt-in only — triage / close / archive never send this.
9
+ */
10
+ export const RecommendationNotifyAddedBodySchema = z.object({
11
+ orgSlug: z
12
+ .string()
13
+ .min(1)
14
+ .describe(
15
+ "Org slug or `org_…` id of the onboarded listing. Required so the email can link a live registry URL.",
16
+ ),
17
+ sourceSlug: z
18
+ .string()
19
+ .min(1)
20
+ .optional()
21
+ .describe(
22
+ "Optional source slug or `src_…` id under that org. When set, the email links the source page.",
23
+ ),
24
+ });
25
+
26
+ /**
27
+ * `POST /v1/admin/recommendations/:id/notify-added` success body.
28
+ *
29
+ * `sent: false` + `reason: "already_notified"` is the idempotent replay —
30
+ * a second call does not email again.
31
+ */
32
+ export const RecommendationNotifyAddedResultSchema = z.object({
33
+ ok: z.literal(true),
34
+ sent: z.boolean(),
35
+ reason: z.enum(["already_notified"]).optional(),
36
+ notifiedAt: z.number().nullable(),
37
+ registryUrl: z.string().optional(),
38
+ contactEmail: z.string().optional(),
39
+ });
@@ -57,9 +57,14 @@ export const SitemapPayloadSchema = z.object({
57
57
  });
58
58
 
59
59
  /**
60
- * Per-release row in `GET /v1/sitemap/releases` (#1181, scoped down). Carries
61
- * exactly what the web needs to build the slugged canonical `/release/...`
62
- * URL (`releasePath()` inputs) plus `fetchedAt` for `<lastmod>`.
60
+ * Per-release row previously returned by `GET /v1/sitemap/releases` (#1181,
61
+ * scoped down). Carries what the web needed to build the slugged canonical
62
+ * `/release/...` URL (`releasePath()` inputs) plus `fetchedAt` for `<lastmod>`.
63
+ *
64
+ * @deprecated The endpoint was retired in #2219 — its only consumer
65
+ * (`sitemap-releases.xml`) was removed in #2218 when release pages went
66
+ * `noindex`. Kept for one minor version per the deprecation lane; will be
67
+ * removed in a future minor.
63
68
  */
64
69
  export const SitemapReleaseSchema = z.object({
65
70
  id: z.string(),
@@ -72,8 +77,12 @@ export const SitemapReleaseSchema = z.object({
72
77
  });
73
78
 
74
79
  /**
75
- * Payload for the curated release sitemap: visible releases with a summary
76
- * and importance at or above the experiment threshold, newest first, capped.
80
+ * Payload previously returned by the curated release sitemap endpoint.
81
+ *
82
+ * @deprecated The endpoint was retired in #2219 — its only consumer
83
+ * (`sitemap-releases.xml`) was removed in #2218 when release pages went
84
+ * `noindex`. Kept for one minor version per the deprecation lane; will be
85
+ * removed in a future minor.
77
86
  */
78
87
  export const SitemapReleasesPayloadSchema = z.object({
79
88
  releases: z.array(SitemapReleaseSchema),
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+
3
+ export const UploadsIntegrationStatusSchema = z.object({
4
+ provider: z.literal("uploads"),
5
+ connected: z.boolean(),
6
+ /** False when the token-encryption key is missing. */
7
+ configured: z.boolean(),
8
+ connectedAt: z.string().nullable(),
9
+ scope: z.string().nullable(),
10
+ /** uploads.sh workspace slug from the access-token JWT (`workspace`, else `workspaces[]`). */
11
+ uploadsWorkspace: z.string().nullable(),
12
+ });
13
+
14
+ export const UploadsOAuthConnectResponseSchema = z.object({
15
+ authorizeUrl: z.string(),
16
+ redirectUri: z.string(),
17
+ });
18
+
19
+ export const UploadsOAuthCallbackBodySchema = z.object({
20
+ code: z.string().min(1),
21
+ state: z.string().min(1),
22
+ });
23
+
24
+ export const UploadsOAuthCallbackResponseSchema = UploadsIntegrationStatusSchema.extend({
25
+ workspaceId: z.string(),
26
+ });