@buildinternet/releases-api-types 0.51.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.51.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",
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,
@@ -521,6 +551,10 @@ export {
521
551
  FeedbackUpdateBodySchema,
522
552
  FeedbackDeleteResponseSchema,
523
553
  } from "./schemas/feedback.js";
554
+ export {
555
+ RecommendationNotifyAddedBodySchema,
556
+ RecommendationNotifyAddedResultSchema,
557
+ } from "./schemas/recommendations.js";
524
558
  export {
525
559
  SitemapSourceSchema,
526
560
  SitemapPayloadSchema,
@@ -589,6 +623,12 @@ export type { ResolveResponse } from "./schemas/resolve.js";
589
623
 
590
624
  export type MediaItem = z.infer<typeof MediaItemSchema>;
591
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
+
592
632
  // ── Stub tier (#1947) ──
593
633
 
594
634
  export type OrgStatus = z.infer<typeof OrgStatusSchema>;
@@ -677,6 +717,10 @@ export type UploadAvatarResponse = z.infer<typeof UploadAvatarResponseSchema>;
677
717
  export type WorkspaceProfileFields = z.infer<typeof WorkspaceProfileFieldsSchema>;
678
718
  export type PatchWorkspaceProfileBody = z.infer<typeof PatchWorkspaceProfileBodySchema>;
679
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>;
680
724
  export type OrgDetail = z.infer<typeof OrgDetailSchema>;
681
725
 
682
726
  export type OrgCatalogItem = z.infer<typeof OrgCatalogItemSchema>;
@@ -869,6 +913,12 @@ export interface ProviderHealthResponse extends ListResponse<ProviderHealthSourc
869
913
  overdueOrgs: number;
870
914
  /** Distinct orgs represented among active sources. */
871
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;
872
922
  };
873
923
  }
874
924
 
@@ -1123,7 +1173,7 @@ export type UserWebhookScope = "org" | "follows";
1123
1173
  export type UserWebhookReleaseTypeFilter = "feature" | "rollup";
1124
1174
 
1125
1175
  /** Webhook delivery output format. */
1126
- export type UserWebhookFormat = "json" | "slack";
1176
+ export type UserWebhookFormat = "json" | "slack" | "discord";
1127
1177
 
1128
1178
  /** A user-owned webhook subscription row (no signing secret). */
1129
1179
  export interface UserWebhookSubscription {
@@ -1170,7 +1220,7 @@ export interface UserWebhookListResponse {
1170
1220
  subscriptions: UserWebhookListItem[];
1171
1221
  }
1172
1222
 
1173
- /** 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). */
1174
1224
  export interface CreateUserWebhookResponse
1175
1225
  extends UserWebhookSubscription, UserWebhookDeliveryHealth {
1176
1226
  orgSlug: string | null;
@@ -1197,7 +1247,7 @@ export interface WebhookDeliveryRow {
1197
1247
  error_message?: string | null;
1198
1248
  error_code?: string | null;
1199
1249
  outcome?: string;
1200
- /** 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. */
1201
1251
  format?: UserWebhookFormat | "";
1202
1252
  http_status?: number;
1203
1253
  latency_ms?: number;
@@ -1705,6 +1755,10 @@ export type FeedbackListResponse = z.infer<typeof FeedbackListResponseSchema>;
1705
1755
  export type FeedbackUpdateBody = z.infer<typeof FeedbackUpdateBodySchema>;
1706
1756
  export type FeedbackDeleteResponse = z.infer<typeof FeedbackDeleteResponseSchema>;
1707
1757
 
1758
+ // ── Recommendations ──
1759
+ export type RecommendationNotifyAddedBody = z.infer<typeof RecommendationNotifyAddedBodySchema>;
1760
+ export type RecommendationNotifyAddedResult = z.infer<typeof RecommendationNotifyAddedResultSchema>;
1761
+
1708
1762
  // ── Fetch log ──
1709
1763
 
1710
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
+ });
@@ -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
+ });
@@ -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
+ });