@buildinternet/releases-api-types 0.52.1 → 0.54.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 +154 -0
- package/src/schemas/classifications.ts +6 -2
- package/src/schemas/collections.ts +24 -1
- package/src/schemas/marketing-classifier.ts +29 -0
- package/src/schemas/search.ts +11 -0
- package/src/schemas/semantic-alert-summary.ts +65 -0
- package/src/schemas/shared.ts +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buildinternet/releases-api-types",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.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.31.0",
|
|
21
21
|
"zod": "^4.4.3"
|
|
22
22
|
},
|
|
23
23
|
"publishConfig": {
|
package/src/api-types.ts
CHANGED
|
@@ -21,6 +21,11 @@ import type {
|
|
|
21
21
|
OpenRouterCatalogModelSchema,
|
|
22
22
|
AiLaneModelsResponseSchema,
|
|
23
23
|
} from "./schemas/ai-models.js";
|
|
24
|
+
import type {
|
|
25
|
+
MarketingClassifierThresholdPutSchema,
|
|
26
|
+
MarketingFilteredSourceSchema,
|
|
27
|
+
MarketingClassifierStateSchema,
|
|
28
|
+
} from "./schemas/marketing-classifier.js";
|
|
24
29
|
import type {
|
|
25
30
|
MediaItemSchema,
|
|
26
31
|
PaginationSchema,
|
|
@@ -221,6 +226,7 @@ import type {
|
|
|
221
226
|
ClassificationRecentResponseSchema,
|
|
222
227
|
ClassificationRecentItemSchema,
|
|
223
228
|
} from "./schemas/classifications.js";
|
|
229
|
+
import type { SemanticAlertSummarySchema } from "./schemas/semantic-alert-summary.js";
|
|
224
230
|
import type {
|
|
225
231
|
RecommendationNotifyAddedBodySchema,
|
|
226
232
|
RecommendationNotifyAddedResultSchema,
|
|
@@ -269,6 +275,7 @@ import type {
|
|
|
269
275
|
CollectionWeeklyDigestListItemSchema,
|
|
270
276
|
CollectionWeeklyDigestsResponseSchema,
|
|
271
277
|
DigestCoveredReleaseSchema,
|
|
278
|
+
DigestSectionSchema,
|
|
272
279
|
CollectionWeeklyDigestDetailSchema,
|
|
273
280
|
} from "./schemas/collections.js";
|
|
274
281
|
import type {
|
|
@@ -309,6 +316,13 @@ export {
|
|
|
309
316
|
OpenRouterCatalogModelSchema,
|
|
310
317
|
AiLaneModelsResponseSchema,
|
|
311
318
|
} from "./schemas/ai-models.js";
|
|
319
|
+
export {
|
|
320
|
+
MarketingClassifierThresholdPutSchema,
|
|
321
|
+
MarketingFilteredSourceSchema,
|
|
322
|
+
MarketingClassifierStateSchema,
|
|
323
|
+
MARKETING_THRESHOLD_MIN,
|
|
324
|
+
MARKETING_THRESHOLD_MAX,
|
|
325
|
+
} from "./schemas/marketing-classifier.js";
|
|
312
326
|
export {
|
|
313
327
|
OrgListItemSchema,
|
|
314
328
|
OrgListResponseSchema,
|
|
@@ -561,6 +575,7 @@ export {
|
|
|
561
575
|
ClassificationRecentResponseSchema,
|
|
562
576
|
ClassificationRecentItemSchema,
|
|
563
577
|
} from "./schemas/classifications.js";
|
|
578
|
+
export { SemanticAlertSummarySchema } from "./schemas/semantic-alert-summary.js";
|
|
564
579
|
export {
|
|
565
580
|
RecommendationNotifyAddedBodySchema,
|
|
566
581
|
RecommendationNotifyAddedResultSchema,
|
|
@@ -611,6 +626,7 @@ export {
|
|
|
611
626
|
CollectionWeeklyDigestListItemSchema,
|
|
612
627
|
CollectionWeeklyDigestsResponseSchema,
|
|
613
628
|
DigestCoveredReleaseSchema,
|
|
629
|
+
DigestSectionSchema,
|
|
614
630
|
CollectionWeeklyDigestDetailSchema,
|
|
615
631
|
} from "./schemas/collections.js";
|
|
616
632
|
export {
|
|
@@ -639,6 +655,10 @@ export type AiLaneState = z.infer<typeof AiLaneStateSchema>;
|
|
|
639
655
|
export type OpenRouterCatalogModel = z.infer<typeof OpenRouterCatalogModelSchema>;
|
|
640
656
|
export type AiLaneModelsResponse = z.infer<typeof AiLaneModelsResponseSchema>;
|
|
641
657
|
|
|
658
|
+
export type MarketingClassifierThresholdPut = z.infer<typeof MarketingClassifierThresholdPutSchema>;
|
|
659
|
+
export type MarketingFilteredSource = z.infer<typeof MarketingFilteredSourceSchema>;
|
|
660
|
+
export type MarketingClassifierState = z.infer<typeof MarketingClassifierStateSchema>;
|
|
661
|
+
|
|
642
662
|
// ── Stub tier (#1947) ──
|
|
643
663
|
|
|
644
664
|
export type OrgStatus = z.infer<typeof OrgStatusSchema>;
|
|
@@ -1250,6 +1270,46 @@ export interface TestUserWebhookResponse {
|
|
|
1250
1270
|
eventId: string;
|
|
1251
1271
|
}
|
|
1252
1272
|
|
|
1273
|
+
// ── Workspace webhooks ──
|
|
1274
|
+
|
|
1275
|
+
/** Workspace member role (Better Auth `member.role`, not `user.role`). */
|
|
1276
|
+
export type WorkspaceMemberRole = "owner" | "admin" | "member";
|
|
1277
|
+
|
|
1278
|
+
/**
|
|
1279
|
+
* A workspace-owned webhook subscription row (no signing secret). Workspace
|
|
1280
|
+
* webhooks are org-scoped only; there is no workspace follows scope.
|
|
1281
|
+
*/
|
|
1282
|
+
export interface WorkspaceWebhookSubscription extends Omit<
|
|
1283
|
+
UserWebhookSubscription,
|
|
1284
|
+
"userId" | "scope"
|
|
1285
|
+
> {
|
|
1286
|
+
workspaceId: string;
|
|
1287
|
+
scope: "org";
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
/** List item returned by GET /v1/workspaces/:workspaceId/webhooks. */
|
|
1291
|
+
export interface WorkspaceWebhookListItem extends Omit<UserWebhookListItem, "scope"> {
|
|
1292
|
+
workspaceId: string;
|
|
1293
|
+
scope: "org";
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
/** GET /v1/workspaces/:workspaceId/webhooks response. */
|
|
1297
|
+
export interface WorkspaceWebhookListResponse {
|
|
1298
|
+
subscriptions: WorkspaceWebhookListItem[];
|
|
1299
|
+
/** The caller's role in the workspace. */
|
|
1300
|
+
role: WorkspaceMemberRole;
|
|
1301
|
+
/** True for owners and admins: create, edit, rotate, and delete. Members can view and test. */
|
|
1302
|
+
canManage: boolean;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
/** POST /v1/workspaces/:workspaceId/webhooks response — signing key shown once (omitted for slack/discord). */
|
|
1306
|
+
export interface CreateWorkspaceWebhookResponse
|
|
1307
|
+
extends WorkspaceWebhookSubscription, UserWebhookDeliveryHealth {
|
|
1308
|
+
orgSlug: string | null;
|
|
1309
|
+
orgName: string | null;
|
|
1310
|
+
signingKey?: string;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1253
1313
|
/** One Analytics Engine delivery-attempt row from GET …/webhooks/:id/deliveries. */
|
|
1254
1314
|
export interface WebhookDeliveryRow {
|
|
1255
1315
|
timestamp?: string;
|
|
@@ -1279,15 +1339,88 @@ export interface DigestPrefsRequest {
|
|
|
1279
1339
|
cadence: DigestCadence;
|
|
1280
1340
|
}
|
|
1281
1341
|
|
|
1342
|
+
// ── Semantic alerts (#2304 Phase 1) ──
|
|
1343
|
+
|
|
1344
|
+
/** Hard cap on saved semantic alerts per account. Enforced on create. */
|
|
1345
|
+
export const SEMANTIC_ALERT_MAX_PER_USER = 5;
|
|
1346
|
+
|
|
1347
|
+
/** Freeform interest text, after trim. User-private — never an analytics label. */
|
|
1348
|
+
export const SEMANTIC_ALERT_QUERY_MAX_CHARS = 500;
|
|
1349
|
+
|
|
1350
|
+
/** Default selected-choice probability. Phase 2 matcher uses this unless overridden. */
|
|
1351
|
+
export const SEMANTIC_ALERT_THRESHOLD_DEFAULT = 0.8;
|
|
1352
|
+
|
|
1353
|
+
export const SEMANTIC_ALERT_THRESHOLD_MIN = 0.5;
|
|
1354
|
+
export const SEMANTIC_ALERT_THRESHOLD_MAX = 1;
|
|
1355
|
+
|
|
1356
|
+
/**
|
|
1357
|
+
* v1 candidate pool. Matching (Phase 2) scores only releases that already hit
|
|
1358
|
+
* the caller's follow graph. Not a per-alert setting.
|
|
1359
|
+
*/
|
|
1360
|
+
export const SEMANTIC_ALERT_CANDIDATE_POOL = "follows" as const;
|
|
1361
|
+
|
|
1362
|
+
/** One saved semantic alert. Query text is returned only to the owning user. */
|
|
1363
|
+
export interface SemanticAlert {
|
|
1364
|
+
id: string;
|
|
1365
|
+
query: string;
|
|
1366
|
+
enabled: boolean;
|
|
1367
|
+
/** Inclusive match probability in [0.50, 1.00]. Default 0.80. */
|
|
1368
|
+
threshold: number;
|
|
1369
|
+
/** Stored preference. Phase 1 does not send email. */
|
|
1370
|
+
deliverEmail: boolean;
|
|
1371
|
+
/** Stored preference. Phase 1 does not send webhook deliveries. */
|
|
1372
|
+
deliverWebhook: boolean;
|
|
1373
|
+
/** Optional link to one of the caller's `/v1/me/webhooks` subscriptions. */
|
|
1374
|
+
webhookSubscriptionId: string | null;
|
|
1375
|
+
createdAt: string;
|
|
1376
|
+
updatedAt: string;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* Claimed-match activity for one alert (#2320). Counts are rows in
|
|
1381
|
+
* `semantic_alert_matches` (notified matches only — below-threshold scores
|
|
1382
|
+
* are not stored). Present on list and notifications-bootstrap rows.
|
|
1383
|
+
*/
|
|
1384
|
+
export interface SemanticAlertActivity {
|
|
1385
|
+
/** Matches in the last 7 days. Included in `matches30d`. */
|
|
1386
|
+
matches7d: number;
|
|
1387
|
+
/** Matches in the last 30 days. */
|
|
1388
|
+
matches30d: number;
|
|
1389
|
+
/** Newest claim, or null when the alert has never matched. */
|
|
1390
|
+
lastMatchedAt: string | null;
|
|
1391
|
+
/** Newest claim's release, when that row still exists. */
|
|
1392
|
+
lastMatch: {
|
|
1393
|
+
releaseId: string;
|
|
1394
|
+
title: string;
|
|
1395
|
+
/** Canonical site path, `/release/rel_…`. */
|
|
1396
|
+
path: string;
|
|
1397
|
+
} | null;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
/** A list row: the saved alert plus recent match activity. */
|
|
1401
|
+
export interface SemanticAlertListItem extends SemanticAlert {
|
|
1402
|
+
activity: SemanticAlertActivity;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
/** GET /v1/me/semantic-alerts. `candidatePool` is the locked v1 scope. */
|
|
1406
|
+
export interface SemanticAlertListResponse {
|
|
1407
|
+
alerts: SemanticAlertListItem[];
|
|
1408
|
+
candidatePool: typeof SEMANTIC_ALERT_CANDIDATE_POOL;
|
|
1409
|
+
maxAlerts: number;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1282
1412
|
/**
|
|
1283
1413
|
* GET /v1/me/settings/notifications — one-shot bootstrap for `/account/notifications`.
|
|
1284
1414
|
* Composes digest cadence + feed token + webhook list so the settings page can
|
|
1285
1415
|
* render with a single round-trip instead of three independent mounts.
|
|
1416
|
+
* `semanticAlerts` is `null` when `semantic-alerts-enabled` is off (hide the
|
|
1417
|
+
* section); an array, possibly empty, when the lane is on.
|
|
1286
1418
|
*/
|
|
1287
1419
|
export interface NotificationSettingsResponse {
|
|
1288
1420
|
cadence: DigestCadence;
|
|
1289
1421
|
feedToken: FeedToken | null;
|
|
1290
1422
|
webhooks: UserWebhookListItem[];
|
|
1423
|
+
semanticAlerts: SemanticAlertListItem[] | null;
|
|
1291
1424
|
}
|
|
1292
1425
|
|
|
1293
1426
|
/**
|
|
@@ -1300,6 +1433,24 @@ export interface DeveloperSettingsResponse {
|
|
|
1300
1433
|
apiKeys: UserApiKey[] | null;
|
|
1301
1434
|
}
|
|
1302
1435
|
|
|
1436
|
+
/** GET /v1/me/workspaces — one row per workspace the caller belongs to. */
|
|
1437
|
+
export interface MeWorkspace {
|
|
1438
|
+
/** Better Auth organization id. */
|
|
1439
|
+
id: string;
|
|
1440
|
+
name: string;
|
|
1441
|
+
slug: string;
|
|
1442
|
+
logo: string | null;
|
|
1443
|
+
/** Workspace membership role (`member.role`, not `user.role`). */
|
|
1444
|
+
role: WorkspaceMemberRole;
|
|
1445
|
+
/** The caller's active workspace (see docs/architecture/workspaces.md). */
|
|
1446
|
+
active: boolean;
|
|
1447
|
+
createdAt: string;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
export interface MeWorkspacesResponse {
|
|
1451
|
+
workspaces: MeWorkspace[];
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1303
1454
|
// ── Search ──
|
|
1304
1455
|
|
|
1305
1456
|
export type SearchOrgHit = z.infer<typeof SearchOrgHitSchema>;
|
|
@@ -1657,6 +1808,7 @@ export type CollectionDailySummariesResponse = z.infer<
|
|
|
1657
1808
|
export type CollectionWeeklyDigestListItem = z.infer<typeof CollectionWeeklyDigestListItemSchema>;
|
|
1658
1809
|
export type CollectionWeeklyDigestsResponse = z.infer<typeof CollectionWeeklyDigestsResponseSchema>;
|
|
1659
1810
|
export type DigestCoveredRelease = z.infer<typeof DigestCoveredReleaseSchema>;
|
|
1811
|
+
export type DigestSection = z.infer<typeof DigestSectionSchema>;
|
|
1660
1812
|
export type CollectionWeeklyDigestDetail = z.infer<typeof CollectionWeeklyDigestDetailSchema>;
|
|
1661
1813
|
|
|
1662
1814
|
// ── Releases (enriched) ──
|
|
@@ -1770,6 +1922,8 @@ export type ClassificationSummary = z.infer<typeof ClassificationSummarySchema>;
|
|
|
1770
1922
|
export type ClassificationRecentResponse = z.infer<typeof ClassificationRecentResponseSchema>;
|
|
1771
1923
|
export type ClassificationRecentItem = z.infer<typeof ClassificationRecentItemSchema>;
|
|
1772
1924
|
|
|
1925
|
+
export type SemanticAlertSummary = z.infer<typeof SemanticAlertSummarySchema>;
|
|
1926
|
+
|
|
1773
1927
|
// ── Recommendations ──
|
|
1774
1928
|
export type RecommendationNotifyAddedBody = z.infer<typeof RecommendationNotifyAddedBodySchema>;
|
|
1775
1929
|
export type RecommendationNotifyAddedResult = z.infer<typeof RecommendationNotifyAddedResultSchema>;
|
|
@@ -11,7 +11,8 @@ const ClassificationOriginFilterSchema = z.enum(["ingest", "manual", "eval", "al
|
|
|
11
11
|
const ClassificationDispositionSchema = z.enum(["kept", "suppressed", "failed", "skipped"]);
|
|
12
12
|
|
|
13
13
|
const ProbabilityBinSchema = z.object({
|
|
14
|
-
/** Inclusive. Width is 0.1. `
|
|
14
|
+
/** Inclusive. Width is 0.1. See `probability.threshold` for the current
|
|
15
|
+
* effective suppression threshold and which bin it falls in. */
|
|
15
16
|
start: z.number(),
|
|
16
17
|
/** Exclusive, except the last bin (`0.9`–`1`) which includes `1`. */
|
|
17
18
|
end: z.number(),
|
|
@@ -65,7 +66,10 @@ export const ClassificationSummarySchema = z.object({
|
|
|
65
66
|
}),
|
|
66
67
|
),
|
|
67
68
|
probability: z.object({
|
|
68
|
-
threshold
|
|
69
|
+
/** Current effective suppression threshold (operator override, else the
|
|
70
|
+
* code default) — no longer a fixed literal now that it's editable via
|
|
71
|
+
* `GET/PUT /v1/admin/marketing-classifier`. */
|
|
72
|
+
threshold: z.number(),
|
|
69
73
|
selected: ProbabilityHistogramSchema,
|
|
70
74
|
confidence: ProbabilityHistogramSchema,
|
|
71
75
|
}),
|
|
@@ -273,8 +273,18 @@ export const CollectionWeeklyDigestsResponseSchema = z.object({
|
|
|
273
273
|
export const DigestCoveredReleaseSchema = z.object({
|
|
274
274
|
id: z.string(),
|
|
275
275
|
title: z.string(),
|
|
276
|
+
/** Internal `/release/*` path — fallback link only (see `url`). */
|
|
276
277
|
path: z.string(),
|
|
277
|
-
|
|
278
|
+
/** Upstream source URL. Primary link target when http(s); optional for older servers. */
|
|
279
|
+
url: z.string().nullable().optional(),
|
|
280
|
+
org: z.object({
|
|
281
|
+
slug: z.string(),
|
|
282
|
+
name: z.string(),
|
|
283
|
+
avatarUrl: z.string().nullable().optional(),
|
|
284
|
+
githubHandle: z.string().nullable().optional(),
|
|
285
|
+
}),
|
|
286
|
+
/** Product the release's source belongs to, when it has one. */
|
|
287
|
+
product: z.object({ slug: z.string(), name: z.string() }).nullable().optional(),
|
|
278
288
|
/**
|
|
279
289
|
* AI-scored importance 1–5. Null when unscored; optional for older
|
|
280
290
|
* servers. Cheap to project on the existing hydrate — powers the flame
|
|
@@ -283,6 +293,17 @@ export const DigestCoveredReleaseSchema = z.object({
|
|
|
283
293
|
importance: ImportanceScoreSchema,
|
|
284
294
|
});
|
|
285
295
|
|
|
296
|
+
/** One `###` section of a digest body, parsed server-side. */
|
|
297
|
+
export const DigestSectionSchema = z.object({
|
|
298
|
+
heading: z.string(),
|
|
299
|
+
/** Slug the digest page renders as the heading's `id` — link target `#anchor`. */
|
|
300
|
+
anchor: z.string(),
|
|
301
|
+
/** First sentence of the section, plain text. */
|
|
302
|
+
lede: z.string(),
|
|
303
|
+
/** Cited release ids in first-seen order; resolve against the detail's `releases`. */
|
|
304
|
+
releaseIds: z.array(z.string()),
|
|
305
|
+
});
|
|
306
|
+
|
|
286
307
|
/** Full row returned by `GET /v1/collections/:slug/digests/:weekStart`. */
|
|
287
308
|
export const CollectionWeeklyDigestDetailSchema = z.object({
|
|
288
309
|
id: z.string(),
|
|
@@ -297,4 +318,6 @@ export const CollectionWeeklyDigestDetailSchema = z.object({
|
|
|
297
318
|
* still resolves — a release deleted/suppressed after generation is
|
|
298
319
|
* dropped rather than surfaced as a dead link. */
|
|
299
320
|
releases: z.array(DigestCoveredReleaseSchema),
|
|
321
|
+
/** Parsed `###` sections. Optional for older servers. */
|
|
322
|
+
sections: z.array(DigestSectionSchema).optional(),
|
|
300
323
|
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const MARKETING_THRESHOLD_MIN = 0.5;
|
|
4
|
+
export const MARKETING_THRESHOLD_MAX = 0.99;
|
|
5
|
+
|
|
6
|
+
/** PUT /v1/admin/marketing-classifier — set the suppression threshold. */
|
|
7
|
+
export const MarketingClassifierThresholdPutSchema = z
|
|
8
|
+
.object({
|
|
9
|
+
threshold: z.number().min(MARKETING_THRESHOLD_MIN).max(MARKETING_THRESHOLD_MAX),
|
|
10
|
+
})
|
|
11
|
+
.strict();
|
|
12
|
+
|
|
13
|
+
export const MarketingFilteredSourceSchema = z.object({
|
|
14
|
+
id: z.string(),
|
|
15
|
+
slug: z.string(),
|
|
16
|
+
name: z.string(),
|
|
17
|
+
type: z.string(),
|
|
18
|
+
orgSlug: z.string().nullable(),
|
|
19
|
+
hint: z.string().nullable(),
|
|
20
|
+
recentReleaseCount: z.number(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/** GET/PUT /v1/admin/marketing-classifier response. */
|
|
24
|
+
export const MarketingClassifierStateSchema = z.object({
|
|
25
|
+
threshold: z.number(),
|
|
26
|
+
defaultThreshold: z.number(),
|
|
27
|
+
updatedAt: z.string().nullable(),
|
|
28
|
+
sources: z.array(MarketingFilteredSourceSchema),
|
|
29
|
+
});
|
package/src/schemas/search.ts
CHANGED
|
@@ -110,6 +110,14 @@ export const SearchReleaseHitSchema = z.object({
|
|
|
110
110
|
summary: z.string(),
|
|
111
111
|
titleGenerated: z.string().nullable().optional(),
|
|
112
112
|
titleShort: z.string().nullable().optional(),
|
|
113
|
+
/**
|
|
114
|
+
* The release's upstream source URL, when it has one. Lets the web link
|
|
115
|
+
* search/lookup hits straight to the original page instead of the
|
|
116
|
+
* noindexed `/release/<id>` stub — see `releaseLinkProps()` in
|
|
117
|
+
* `web/src/lib/release-link.ts`. Optional for older servers / mid-deploy
|
|
118
|
+
* pin tolerance.
|
|
119
|
+
*/
|
|
120
|
+
url: z.string().nullable().optional(),
|
|
113
121
|
/**
|
|
114
122
|
* AI-scored importance 1–5 (5=landmark, 1=housekeeping). Null when
|
|
115
123
|
* unscored; optional for older servers / mid-deploy pin tolerance.
|
|
@@ -213,6 +221,9 @@ export const LookupResultPayloadSchema = z.object({
|
|
|
213
221
|
publishedAt: z.string().nullable(),
|
|
214
222
|
/** First image/gif thumbnail; null when the release has none. */
|
|
215
223
|
thumbnail: ReleaseThumbnailSchema.nullable().optional(),
|
|
224
|
+
/** The release's upstream source URL, when it has one. See
|
|
225
|
+
* `SearchReleaseHitSchema.url`. */
|
|
226
|
+
url: z.string().nullable().optional(),
|
|
216
227
|
}),
|
|
217
228
|
)
|
|
218
229
|
.optional(),
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Admin interest-alert quality (`GET /v1/admin/semantic-alerts/summary`).
|
|
5
|
+
* Decisions live in the classifications Analytics Engine dataset with
|
|
6
|
+
* `blob4 = semantic-alert`. This is the hydrated read model. Alert query
|
|
7
|
+
* text is not a field — it is not stored on the points.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const ProbabilityBinSchema = z.object({
|
|
11
|
+
/** Inclusive. Width is 0.1. `0.8` is the start of the default-threshold bin. */
|
|
12
|
+
start: z.number(),
|
|
13
|
+
/** Exclusive, except the last bin (`0.9`–`1`) which includes `1`. */
|
|
14
|
+
end: z.number(),
|
|
15
|
+
count: z.number(),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const SemanticAlertDispositionCountsSchema = z.object({
|
|
19
|
+
matched: z.number(),
|
|
20
|
+
belowThreshold: z.number(),
|
|
21
|
+
failed: z.number(),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* `GET /v1/admin/semantic-alerts/summary`.
|
|
26
|
+
*
|
|
27
|
+
* `scored` is matched + below threshold (a probability came back).
|
|
28
|
+
* `matchRate` is matched / scored, or null when nothing was scored.
|
|
29
|
+
* `failed` is fail-closed and stays out of the rate.
|
|
30
|
+
* Cost is not on these points; `meta.costLane` names the `ai_usage` lane.
|
|
31
|
+
*/
|
|
32
|
+
export const SemanticAlertSummarySchema = z.object({
|
|
33
|
+
after: z.string(),
|
|
34
|
+
before: z.string(),
|
|
35
|
+
bucket: z.enum(["hour", "day"]),
|
|
36
|
+
totals: SemanticAlertDispositionCountsSchema.extend({
|
|
37
|
+
scored: z.number(),
|
|
38
|
+
matchRate: z.number().nullable(),
|
|
39
|
+
}),
|
|
40
|
+
series: z.array(
|
|
41
|
+
SemanticAlertDispositionCountsSchema.extend({
|
|
42
|
+
t: z.string(),
|
|
43
|
+
}),
|
|
44
|
+
),
|
|
45
|
+
failures: z.array(
|
|
46
|
+
z.object({
|
|
47
|
+
category: z.enum(["provider_error", "invalid_probability", "unknown"]),
|
|
48
|
+
count: z.number(),
|
|
49
|
+
}),
|
|
50
|
+
),
|
|
51
|
+
probability: z.object({
|
|
52
|
+
/** Default alert threshold. Each point stores its own threshold separately. */
|
|
53
|
+
defaultThreshold: z.literal(0.8),
|
|
54
|
+
bins: z.array(ProbabilityBinSchema),
|
|
55
|
+
/** Sampled rows whose probability double is `< 0` (the absent sentinel). */
|
|
56
|
+
missing: z.number(),
|
|
57
|
+
}),
|
|
58
|
+
meta: z.object({
|
|
59
|
+
dataset: z.string(),
|
|
60
|
+
retentionDays: z.literal(90),
|
|
61
|
+
sampled: z.literal(true),
|
|
62
|
+
/** `ai_usage` lane that carries JEV cost. Not summed from these points. */
|
|
63
|
+
costLane: z.literal("semantic-alert-match"),
|
|
64
|
+
}),
|
|
65
|
+
});
|
package/src/schemas/shared.ts
CHANGED
|
@@ -206,8 +206,9 @@ export const OverviewCitationSchema = z.object({
|
|
|
206
206
|
releaseId: z.string().nullable().optional(),
|
|
207
207
|
/**
|
|
208
208
|
* Canonical web URL of the on-registry release page for this source, when
|
|
209
|
-
* `releaseId` resolved (#1934).
|
|
210
|
-
*
|
|
209
|
+
* `releaseId` resolved (#1934). Kept for machine consumers; the web Sources
|
|
210
|
+
* footer links `sourceUrl` (the #2218 link policy — `/release/*` pages are
|
|
211
|
+
* noindexed).
|
|
211
212
|
*/
|
|
212
213
|
releaseWebUrl: z.string().nullable().optional(),
|
|
213
214
|
/**
|