@secondlayer/shared 13.4.0 → 13.5.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/dist/src/archive/range-digest.d.ts +31 -0
- package/dist/src/archive/semantic-digest-builder.d.ts +31 -0
- package/dist/src/coverage/index.d.ts +31 -0
- package/dist/src/db/index.d.ts +34 -1
- package/dist/src/db/index.js +3 -1
- package/dist/src/db/index.js.map +3 -3
- package/dist/src/db/queries/chain-reorgs.d.ts +31 -0
- package/dist/src/db/queries/chain-reorgs.js +3 -1
- package/dist/src/db/queries/chain-reorgs.js.map +3 -3
- package/dist/src/db/queries/contracts.d.ts +31 -0
- package/dist/src/db/queries/instance.d.ts +31 -0
- package/dist/src/db/queries/integrity.d.ts +31 -0
- package/dist/src/db/queries/subgraph-gaps.d.ts +31 -0
- package/dist/src/db/queries/subgraph-operations.d.ts +31 -0
- package/dist/src/db/queries/subgraphs.d.ts +31 -0
- package/dist/src/db/queries/sync-scope.d.ts +31 -0
- package/dist/src/db/queries/webhooks.d.ts +31 -0
- package/dist/src/db/schema.d.ts +32 -1
- package/dist/src/index.d.ts +128 -7
- package/dist/src/index.js +182 -87
- package/dist/src/index.js.map +5 -4
- package/dist/src/insights/index.d.ts +1540 -0
- package/dist/src/insights/index.js +2284 -0
- package/dist/src/insights/index.js.map +29 -0
- package/dist/src/insights/thresholds.d.ts +56 -0
- package/dist/src/insights/thresholds.js +86 -0
- package/dist/src/insights/thresholds.js.map +10 -0
- package/dist/src/leader.d.ts +3 -1
- package/dist/src/leader.js +3 -1
- package/dist/src/leader.js.map +3 -3
- package/dist/src/node/local-client.d.ts +31 -0
- package/dist/src/queue/listener.js +3 -1
- package/dist/src/queue/listener.js.map +3 -3
- package/dist/src/schemas/index.d.ts +95 -7
- package/dist/src/schemas/index.js +180 -87
- package/dist/src/schemas/index.js.map +4 -3
- package/dist/src/schemas/insights.d.ts +89 -0
- package/dist/src/schemas/insights.js +98 -0
- package/dist/src/schemas/insights.js.map +10 -0
- package/migrations/0170_insights.ts +63 -0
- package/package.json +13 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* The insight contract. The tenant (`/api/insights`) and platform
|
|
4
|
+
* (`/api/accounts/insights`) routes serve `Insight` verbatim. The web app keeps
|
|
5
|
+
* a field-for-field copy in `apps/web/src/lib/insights.ts`; change both
|
|
6
|
+
* together.
|
|
7
|
+
*
|
|
8
|
+
* The types are written out and the schemas annotated with them, rather than
|
|
9
|
+
* inferred: the bundled `.d.ts` loses inferred zod types (they come out as
|
|
10
|
+
* `unknown`), the same reason `schemas/webhooks.ts` annotates its schemas.
|
|
11
|
+
*/
|
|
12
|
+
declare const INSIGHT_SEVERITIES: readonly ["losing", "will_fail", "costs", "recovered"];
|
|
13
|
+
type InsightSeverity = (typeof INSIGHT_SEVERITIES)[number];
|
|
14
|
+
type InsightResourceKind = "webhook" | "subgraph" | "account";
|
|
15
|
+
type InsightEvidence = {
|
|
16
|
+
kind: "series"
|
|
17
|
+
title: string
|
|
18
|
+
series: {
|
|
19
|
+
name: string
|
|
20
|
+
role: "a" | "context" | "mark"
|
|
21
|
+
points: number[]
|
|
22
|
+
}[]
|
|
23
|
+
labels: [number, string][]
|
|
24
|
+
unit?: string
|
|
25
|
+
} | {
|
|
26
|
+
kind: "table"
|
|
27
|
+
title: string
|
|
28
|
+
columns: string[]
|
|
29
|
+
rows: (string | number)[][]
|
|
30
|
+
markRow?: number
|
|
31
|
+
} | {
|
|
32
|
+
kind: "shapes"
|
|
33
|
+
title: string
|
|
34
|
+
shapes: {
|
|
35
|
+
code: string
|
|
36
|
+
body: string
|
|
37
|
+
count: number
|
|
38
|
+
isNew: boolean
|
|
39
|
+
}[]
|
|
40
|
+
} | {
|
|
41
|
+
kind: "timeline"
|
|
42
|
+
title: string
|
|
43
|
+
steps: {
|
|
44
|
+
what: string
|
|
45
|
+
at: string
|
|
46
|
+
note?: string
|
|
47
|
+
failed: boolean
|
|
48
|
+
}[]
|
|
49
|
+
};
|
|
50
|
+
interface Insight {
|
|
51
|
+
id: string;
|
|
52
|
+
rule: string;
|
|
53
|
+
severity: InsightSeverity;
|
|
54
|
+
impact: number;
|
|
55
|
+
resource: {
|
|
56
|
+
kind: InsightResourceKind
|
|
57
|
+
id: string
|
|
58
|
+
name: string
|
|
59
|
+
};
|
|
60
|
+
line: string;
|
|
61
|
+
meta?: string;
|
|
62
|
+
lead: string;
|
|
63
|
+
body: string;
|
|
64
|
+
evidence: InsightEvidence[];
|
|
65
|
+
handoff: {
|
|
66
|
+
prompt: string
|
|
67
|
+
commands: string[]
|
|
68
|
+
};
|
|
69
|
+
how: {
|
|
70
|
+
detector: string
|
|
71
|
+
facts: [string, string][]
|
|
72
|
+
label?: {
|
|
73
|
+
cause: string
|
|
74
|
+
confidence: number
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
createdAt: string;
|
|
78
|
+
resolvedAt?: string | null;
|
|
79
|
+
}
|
|
80
|
+
interface InsightListResponse {
|
|
81
|
+
data: Insight[];
|
|
82
|
+
}
|
|
83
|
+
declare const InsightSeveritySchema: z.ZodType<InsightSeverity>;
|
|
84
|
+
declare const InsightResourceKindSchema: z.ZodType<InsightResourceKind>;
|
|
85
|
+
declare const InsightEvidenceSchema: z.ZodType<InsightEvidence>;
|
|
86
|
+
declare const InsightSchema: z.ZodType<Insight>;
|
|
87
|
+
declare const InsightListResponseSchema: z.ZodType<InsightListResponse>;
|
|
88
|
+
declare const SEVERITY_ORDER: Record<InsightSeverity, number>;
|
|
89
|
+
export { INSIGHT_SEVERITIES, Insight, InsightEvidence, InsightEvidenceSchema, InsightListResponse, InsightListResponseSchema, InsightResourceKind, InsightResourceKindSchema, InsightSchema, InsightSeverity, InsightSeveritySchema, SEVERITY_ORDER };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// src/schemas/insights.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var INSIGHT_SEVERITIES = [
|
|
4
|
+
"losing",
|
|
5
|
+
"will_fail",
|
|
6
|
+
"costs",
|
|
7
|
+
"recovered"
|
|
8
|
+
];
|
|
9
|
+
var InsightSeveritySchema = z.enum(INSIGHT_SEVERITIES);
|
|
10
|
+
var InsightResourceKindSchema = z.enum(["webhook", "subgraph", "account"]);
|
|
11
|
+
var InsightEvidenceSchema = z.discriminatedUnion("kind", [
|
|
12
|
+
z.object({
|
|
13
|
+
kind: z.literal("series"),
|
|
14
|
+
title: z.string(),
|
|
15
|
+
series: z.array(z.object({
|
|
16
|
+
name: z.string(),
|
|
17
|
+
role: z.enum(["a", "context", "mark"]),
|
|
18
|
+
points: z.array(z.number())
|
|
19
|
+
})),
|
|
20
|
+
labels: z.array(z.tuple([z.number(), z.string()])),
|
|
21
|
+
unit: z.string().optional()
|
|
22
|
+
}),
|
|
23
|
+
z.object({
|
|
24
|
+
kind: z.literal("table"),
|
|
25
|
+
title: z.string(),
|
|
26
|
+
columns: z.array(z.string()),
|
|
27
|
+
rows: z.array(z.array(z.union([z.string(), z.number()]))),
|
|
28
|
+
markRow: z.number().optional()
|
|
29
|
+
}),
|
|
30
|
+
z.object({
|
|
31
|
+
kind: z.literal("shapes"),
|
|
32
|
+
title: z.string(),
|
|
33
|
+
shapes: z.array(z.object({
|
|
34
|
+
code: z.string(),
|
|
35
|
+
body: z.string(),
|
|
36
|
+
count: z.number(),
|
|
37
|
+
isNew: z.boolean()
|
|
38
|
+
}))
|
|
39
|
+
}),
|
|
40
|
+
z.object({
|
|
41
|
+
kind: z.literal("timeline"),
|
|
42
|
+
title: z.string(),
|
|
43
|
+
steps: z.array(z.object({
|
|
44
|
+
what: z.string(),
|
|
45
|
+
at: z.string(),
|
|
46
|
+
note: z.string().optional(),
|
|
47
|
+
failed: z.boolean()
|
|
48
|
+
}))
|
|
49
|
+
})
|
|
50
|
+
]);
|
|
51
|
+
var InsightSchema = z.object({
|
|
52
|
+
id: z.string(),
|
|
53
|
+
rule: z.string(),
|
|
54
|
+
severity: InsightSeveritySchema,
|
|
55
|
+
impact: z.number(),
|
|
56
|
+
resource: z.object({
|
|
57
|
+
kind: InsightResourceKindSchema,
|
|
58
|
+
id: z.string(),
|
|
59
|
+
name: z.string()
|
|
60
|
+
}),
|
|
61
|
+
line: z.string(),
|
|
62
|
+
meta: z.string().optional(),
|
|
63
|
+
lead: z.string(),
|
|
64
|
+
body: z.string(),
|
|
65
|
+
evidence: z.array(InsightEvidenceSchema),
|
|
66
|
+
handoff: z.object({
|
|
67
|
+
prompt: z.string(),
|
|
68
|
+
commands: z.array(z.string())
|
|
69
|
+
}),
|
|
70
|
+
how: z.object({
|
|
71
|
+
detector: z.string(),
|
|
72
|
+
facts: z.array(z.tuple([z.string(), z.string()])),
|
|
73
|
+
label: z.object({ cause: z.string(), confidence: z.number() }).optional()
|
|
74
|
+
}),
|
|
75
|
+
createdAt: z.string(),
|
|
76
|
+
resolvedAt: z.string().nullable().optional()
|
|
77
|
+
});
|
|
78
|
+
var InsightListResponseSchema = z.object({
|
|
79
|
+
data: z.array(InsightSchema)
|
|
80
|
+
});
|
|
81
|
+
var SEVERITY_ORDER = {
|
|
82
|
+
losing: 0,
|
|
83
|
+
will_fail: 1,
|
|
84
|
+
costs: 2,
|
|
85
|
+
recovered: 3
|
|
86
|
+
};
|
|
87
|
+
export {
|
|
88
|
+
INSIGHT_SEVERITIES,
|
|
89
|
+
InsightEvidenceSchema,
|
|
90
|
+
InsightListResponseSchema,
|
|
91
|
+
InsightResourceKindSchema,
|
|
92
|
+
InsightSchema,
|
|
93
|
+
InsightSeveritySchema,
|
|
94
|
+
SEVERITY_ORDER
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
//# debugId=3EFEA80342CD257B64756E2164756E21
|
|
98
|
+
//# sourceMappingURL=insights.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/schemas/insights.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import { z } from \"zod\";\n\n/**\n * The insight contract. The tenant (`/api/insights`) and platform\n * (`/api/accounts/insights`) routes serve `Insight` verbatim. The web app keeps\n * a field-for-field copy in `apps/web/src/lib/insights.ts`; change both\n * together.\n *\n * The types are written out and the schemas annotated with them, rather than\n * inferred: the bundled `.d.ts` loses inferred zod types (they come out as\n * `unknown`), the same reason `schemas/webhooks.ts` annotates its schemas.\n */\n\nexport const INSIGHT_SEVERITIES = [\n\t\"losing\",\n\t\"will_fail\",\n\t\"costs\",\n\t\"recovered\",\n] as const;\n\nexport type InsightSeverity = (typeof INSIGHT_SEVERITIES)[number];\n\nexport type InsightResourceKind = \"webhook\" | \"subgraph\" | \"account\";\n\nexport type InsightEvidence =\n\t| {\n\t\t\tkind: \"series\";\n\t\t\ttitle: string;\n\t\t\tseries: {\n\t\t\t\tname: string;\n\t\t\t\trole: \"a\" | \"context\" | \"mark\";\n\t\t\t\tpoints: number[];\n\t\t\t}[];\n\t\t\tlabels: [number, string][];\n\t\t\tunit?: string;\n\t }\n\t| {\n\t\t\tkind: \"table\";\n\t\t\ttitle: string;\n\t\t\tcolumns: string[];\n\t\t\trows: (string | number)[][];\n\t\t\tmarkRow?: number;\n\t }\n\t| {\n\t\t\tkind: \"shapes\";\n\t\t\ttitle: string;\n\t\t\tshapes: { code: string; body: string; count: number; isNew: boolean }[];\n\t }\n\t| {\n\t\t\tkind: \"timeline\";\n\t\t\ttitle: string;\n\t\t\tsteps: { what: string; at: string; note?: string; failed: boolean }[];\n\t };\n\nexport interface Insight {\n\tid: string;\n\trule: string;\n\tseverity: InsightSeverity;\n\timpact: number;\n\tresource: {\n\t\tkind: InsightResourceKind;\n\t\tid: string;\n\t\tname: string;\n\t};\n\tline: string;\n\tmeta?: string;\n\tlead: string;\n\tbody: string;\n\tevidence: InsightEvidence[];\n\thandoff: { prompt: string; commands: string[] };\n\thow: {\n\t\tdetector: string;\n\t\tfacts: [string, string][];\n\t\tlabel?: { cause: string; confidence: number };\n\t};\n\tcreatedAt: string;\n\tresolvedAt?: string | null;\n}\n\nexport interface InsightListResponse {\n\tdata: Insight[];\n}\n\nexport const InsightSeveritySchema: z.ZodType<InsightSeverity> =\n\tz.enum(INSIGHT_SEVERITIES);\n\nexport const InsightResourceKindSchema: z.ZodType<InsightResourceKind> = z.enum(\n\t[\"webhook\", \"subgraph\", \"account\"],\n);\n\nexport const InsightEvidenceSchema: z.ZodType<InsightEvidence> =\n\tz.discriminatedUnion(\"kind\", [\n\t\tz.object({\n\t\t\tkind: z.literal(\"series\"),\n\t\t\ttitle: z.string(),\n\t\t\tseries: z.array(\n\t\t\t\tz.object({\n\t\t\t\t\tname: z.string(),\n\t\t\t\t\trole: z.enum([\"a\", \"context\", \"mark\"]),\n\t\t\t\t\tpoints: z.array(z.number()),\n\t\t\t\t}),\n\t\t\t),\n\t\t\tlabels: z.array(z.tuple([z.number(), z.string()])),\n\t\t\tunit: z.string().optional(),\n\t\t}),\n\t\tz.object({\n\t\t\tkind: z.literal(\"table\"),\n\t\t\ttitle: z.string(),\n\t\t\tcolumns: z.array(z.string()),\n\t\t\trows: z.array(z.array(z.union([z.string(), z.number()]))),\n\t\t\tmarkRow: z.number().optional(),\n\t\t}),\n\t\tz.object({\n\t\t\tkind: z.literal(\"shapes\"),\n\t\t\ttitle: z.string(),\n\t\t\tshapes: z.array(\n\t\t\t\tz.object({\n\t\t\t\t\tcode: z.string(),\n\t\t\t\t\tbody: z.string(),\n\t\t\t\t\tcount: z.number(),\n\t\t\t\t\tisNew: z.boolean(),\n\t\t\t\t}),\n\t\t\t),\n\t\t}),\n\t\tz.object({\n\t\t\tkind: z.literal(\"timeline\"),\n\t\t\ttitle: z.string(),\n\t\t\tsteps: z.array(\n\t\t\t\tz.object({\n\t\t\t\t\twhat: z.string(),\n\t\t\t\t\tat: z.string(),\n\t\t\t\t\tnote: z.string().optional(),\n\t\t\t\t\tfailed: z.boolean(),\n\t\t\t\t}),\n\t\t\t),\n\t\t}),\n\t]);\n\nexport const InsightSchema: z.ZodType<Insight> = z.object({\n\tid: z.string(),\n\trule: z.string(),\n\tseverity: InsightSeveritySchema,\n\timpact: z.number(),\n\tresource: z.object({\n\t\tkind: InsightResourceKindSchema,\n\t\tid: z.string(),\n\t\tname: z.string(),\n\t}),\n\tline: z.string(),\n\tmeta: z.string().optional(),\n\tlead: z.string(),\n\tbody: z.string(),\n\tevidence: z.array(InsightEvidenceSchema),\n\thandoff: z.object({\n\t\tprompt: z.string(),\n\t\tcommands: z.array(z.string()),\n\t}),\n\thow: z.object({\n\t\tdetector: z.string(),\n\t\tfacts: z.array(z.tuple([z.string(), z.string()])),\n\t\tlabel: z.object({ cause: z.string(), confidence: z.number() }).optional(),\n\t}),\n\tcreatedAt: z.string(),\n\tresolvedAt: z.string().nullable().optional(),\n});\n\nexport const InsightListResponseSchema: z.ZodType<InsightListResponse> =\n\tz.object({\n\t\tdata: z.array(InsightSchema),\n\t});\n\nexport const SEVERITY_ORDER: Record<InsightSeverity, number> = {\n\tlosing: 0,\n\twill_fail: 1,\n\tcosts: 2,\n\trecovered: 3,\n};\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "3EFEA80342CD257B64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type Kysely, sql } from "kysely";
|
|
2
|
+
import { onControlPlane } from "../src/db/migration-role.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Ranked dashboard insights (one open row per resource + rule) and the
|
|
6
|
+
* per-resource "expected" mutes. Created on every control-plane database:
|
|
7
|
+
* the platform DB (account rules) and each tenant / self-host DB (webhook and
|
|
8
|
+
* subgraph rules). `account_id` is NULL on tenant and self-host rows (there is
|
|
9
|
+
* no meaningful account id there) so it carries no foreign key.
|
|
10
|
+
*/
|
|
11
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
12
|
+
await onControlPlane(async () => {
|
|
13
|
+
await sql`
|
|
14
|
+
CREATE TABLE insights (
|
|
15
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
16
|
+
account_id uuid,
|
|
17
|
+
resource_kind text NOT NULL,
|
|
18
|
+
resource_id text NOT NULL,
|
|
19
|
+
rule text NOT NULL,
|
|
20
|
+
severity text NOT NULL,
|
|
21
|
+
impact double precision NOT NULL DEFAULT 0,
|
|
22
|
+
payload jsonb NOT NULL,
|
|
23
|
+
first_seen_at timestamptz NOT NULL DEFAULT now(),
|
|
24
|
+
last_seen_at timestamptz NOT NULL DEFAULT now(),
|
|
25
|
+
clear_streak integer NOT NULL DEFAULT 0,
|
|
26
|
+
resolved_at timestamptz,
|
|
27
|
+
dismissed_at timestamptz
|
|
28
|
+
)
|
|
29
|
+
`.execute(db);
|
|
30
|
+
|
|
31
|
+
await sql`
|
|
32
|
+
CREATE UNIQUE INDEX insights_open_key ON insights
|
|
33
|
+
(coalesce(account_id, '00000000-0000-0000-0000-000000000000'::uuid), resource_kind, resource_id, rule)
|
|
34
|
+
WHERE resolved_at IS NULL
|
|
35
|
+
`.execute(db);
|
|
36
|
+
|
|
37
|
+
await sql`
|
|
38
|
+
CREATE INDEX insights_account_recent ON insights (account_id, resolved_at)
|
|
39
|
+
`.execute(db);
|
|
40
|
+
|
|
41
|
+
await sql`
|
|
42
|
+
CREATE TABLE insight_mutes (
|
|
43
|
+
account_id uuid,
|
|
44
|
+
resource_kind text NOT NULL,
|
|
45
|
+
resource_id text NOT NULL,
|
|
46
|
+
rule text NOT NULL,
|
|
47
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
48
|
+
)
|
|
49
|
+
`.execute(db);
|
|
50
|
+
|
|
51
|
+
await sql`
|
|
52
|
+
CREATE UNIQUE INDEX insight_mutes_key ON insight_mutes
|
|
53
|
+
(coalesce(account_id, '00000000-0000-0000-0000-000000000000'::uuid), resource_kind, resource_id, rule)
|
|
54
|
+
`.execute(db);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
59
|
+
await onControlPlane(async () => {
|
|
60
|
+
await sql`DROP TABLE IF EXISTS insight_mutes`.execute(db);
|
|
61
|
+
await sql`DROP TABLE IF EXISTS insights`.execute(db);
|
|
62
|
+
});
|
|
63
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@secondlayer/shared",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.5.0",
|
|
4
4
|
"description": "Internal building blocks shared across Secondlayer packages.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -240,6 +240,18 @@
|
|
|
240
240
|
"./classify": {
|
|
241
241
|
"types": "./dist/src/classify/index.d.ts",
|
|
242
242
|
"import": "./dist/src/classify/index.js"
|
|
243
|
+
},
|
|
244
|
+
"./insights": {
|
|
245
|
+
"types": "./dist/src/insights/index.d.ts",
|
|
246
|
+
"import": "./dist/src/insights/index.js"
|
|
247
|
+
},
|
|
248
|
+
"./insights/thresholds": {
|
|
249
|
+
"types": "./dist/src/insights/thresholds.d.ts",
|
|
250
|
+
"import": "./dist/src/insights/thresholds.js"
|
|
251
|
+
},
|
|
252
|
+
"./schemas/insights": {
|
|
253
|
+
"types": "./dist/src/schemas/insights.d.ts",
|
|
254
|
+
"import": "./dist/src/schemas/insights.js"
|
|
243
255
|
}
|
|
244
256
|
},
|
|
245
257
|
"files": ["dist", "migrations"],
|