@q32/core 0.1.7 → 0.1.9
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/ops-events.d.ts +102 -7
- package/dist/ops-events.d.ts.map +1 -1
- package/dist/ops-events.js +209 -6
- package/dist/ops-events.js.map +1 -1
- package/package.json +12 -4
- package/src/ops-events.ts +339 -17
package/dist/ops-events.d.ts
CHANGED
|
@@ -1,25 +1,120 @@
|
|
|
1
|
+
import type postgres from "postgres";
|
|
1
2
|
import type { D1DatabaseLike } from "./d1.js";
|
|
2
|
-
export type
|
|
3
|
+
export type OpsEventStatus = "started" | "ok" | "warning" | "error" | "skipped";
|
|
4
|
+
export type OpsEventSeverity = "debug" | "info" | "warn" | "error";
|
|
3
5
|
export type OpsEventInput = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
eventId?: string;
|
|
7
|
+
eventName?: string;
|
|
8
|
+
eventType?: string;
|
|
9
|
+
workflow?: string;
|
|
10
|
+
source?: string;
|
|
11
|
+
status?: OpsEventStatus;
|
|
12
|
+
severity?: OpsEventSeverity;
|
|
13
|
+
runId?: string | null;
|
|
14
|
+
jobId?: string | null;
|
|
15
|
+
parentEventId?: string | null;
|
|
16
|
+
scopeId?: string | null;
|
|
17
|
+
sourceId?: string | null;
|
|
18
|
+
destinationId?: string | null;
|
|
19
|
+
actorId?: string | null;
|
|
20
|
+
orgId?: string | null;
|
|
21
|
+
customerId?: string | null;
|
|
22
|
+
provider?: string | null;
|
|
23
|
+
targetType?: string | null;
|
|
24
|
+
targetId?: string | null;
|
|
25
|
+
durationMs?: number | null;
|
|
26
|
+
statusCode?: number | null;
|
|
27
|
+
requestMethod?: string | null;
|
|
28
|
+
requestPath?: string | null;
|
|
29
|
+
requestUrl?: string | null;
|
|
30
|
+
message?: string | null;
|
|
31
|
+
error?: unknown;
|
|
32
|
+
errorMessage?: string | null;
|
|
8
33
|
payload?: unknown;
|
|
34
|
+
metrics?: unknown;
|
|
35
|
+
metadata?: unknown;
|
|
36
|
+
occurredAt?: string | Date;
|
|
37
|
+
fingerprint?: string | null;
|
|
38
|
+
};
|
|
39
|
+
export type NormalizedOpsEvent = {
|
|
40
|
+
eventId: string;
|
|
41
|
+
eventName: string;
|
|
42
|
+
workflow: string;
|
|
43
|
+
status: OpsEventStatus;
|
|
44
|
+
severity: OpsEventSeverity;
|
|
45
|
+
runId: string | null;
|
|
46
|
+
jobId: string | null;
|
|
47
|
+
parentEventId: string | null;
|
|
48
|
+
scopeId: string | null;
|
|
49
|
+
sourceId: string | null;
|
|
50
|
+
destinationId: string | null;
|
|
51
|
+
actorId: string | null;
|
|
52
|
+
orgId: string | null;
|
|
53
|
+
customerId: string | null;
|
|
54
|
+
provider: string | null;
|
|
55
|
+
targetType: string | null;
|
|
56
|
+
targetId: string | null;
|
|
57
|
+
durationMs: number | null;
|
|
58
|
+
statusCode: number | null;
|
|
59
|
+
requestMethod: string | null;
|
|
60
|
+
requestPath: string | null;
|
|
61
|
+
requestUrl: string | null;
|
|
62
|
+
message: string | null;
|
|
63
|
+
errorName: string | null;
|
|
64
|
+
errorMessage: string | null;
|
|
65
|
+
errorStack: string | null;
|
|
66
|
+
payload: unknown;
|
|
67
|
+
metrics: unknown;
|
|
68
|
+
metadata: unknown;
|
|
69
|
+
occurredAt: string;
|
|
70
|
+
fingerprint: string | null;
|
|
71
|
+
};
|
|
72
|
+
export type OpsEventNormalizeOptions = {
|
|
73
|
+
idPrefix?: string;
|
|
74
|
+
now?: () => Date;
|
|
9
75
|
};
|
|
76
|
+
export type OpsEventColumnValue = keyof NormalizedOpsEvent | "payloadJson" | "metricsJson" | "metadataJson" | "null";
|
|
77
|
+
export type OpsEventColumn = {
|
|
78
|
+
column: string;
|
|
79
|
+
value: OpsEventColumnValue | ((event: NormalizedOpsEvent) => unknown);
|
|
80
|
+
cast?: "jsonb" | "timestamptz";
|
|
81
|
+
};
|
|
82
|
+
export type OpsEventSqlInsert = {
|
|
83
|
+
text: string;
|
|
84
|
+
values: unknown[];
|
|
85
|
+
};
|
|
86
|
+
export type OpsEventSqlConfig = {
|
|
87
|
+
tableName: string;
|
|
88
|
+
columns: OpsEventColumn[];
|
|
89
|
+
conflictTarget?: string[];
|
|
90
|
+
updateColumns?: string[];
|
|
91
|
+
};
|
|
92
|
+
export declare function normalizeOpsEvent(input: OpsEventInput, options?: OpsEventNormalizeOptions): NormalizedOpsEvent;
|
|
93
|
+
export declare function buildOpsEventInsert(config: OpsEventSqlConfig, input: OpsEventInput | NormalizedOpsEvent, options?: OpsEventNormalizeOptions): OpsEventSqlInsert;
|
|
94
|
+
export declare function recordPostgresOpsEvent(sql: postgres.Sql, config: OpsEventSqlConfig, input: OpsEventInput | NormalizedOpsEvent, options?: OpsEventNormalizeOptions): Promise<NormalizedOpsEvent>;
|
|
95
|
+
export type D1OpsEventConfig = {
|
|
96
|
+
tableName?: string;
|
|
97
|
+
columns?: OpsEventColumn[];
|
|
98
|
+
};
|
|
99
|
+
export declare function recordD1OpsEvent(db: D1DatabaseLike, input: OpsEventInput | NormalizedOpsEvent, config?: D1OpsEventConfig): Promise<NormalizedOpsEvent>;
|
|
100
|
+
export declare function recordOpsEvent(db: D1DatabaseLike, input: OpsEventInput): Promise<void>;
|
|
10
101
|
export type OpsEventRow = {
|
|
11
102
|
id: number;
|
|
12
103
|
event_type: string;
|
|
13
|
-
severity:
|
|
104
|
+
severity: OpsEventSeverity;
|
|
14
105
|
source: string;
|
|
15
106
|
fingerprint: string | null;
|
|
16
107
|
payload_json: string;
|
|
17
108
|
created_at: string;
|
|
18
109
|
};
|
|
19
|
-
export declare function recordOpsEvent(db: D1DatabaseLike, input: OpsEventInput): Promise<void>;
|
|
20
110
|
export declare function listRecentOpsEvents(db: D1DatabaseLike, options?: {
|
|
21
111
|
limit?: number;
|
|
22
112
|
eventType?: string | null;
|
|
23
113
|
}): Promise<OpsEventRow[]>;
|
|
114
|
+
export declare const DEFAULT_D1_OPS_EVENT_COLUMNS: OpsEventColumn[];
|
|
115
|
+
export declare const GRAPHILIZE_GRAPH_EVENTS_COLUMNS: OpsEventColumn[];
|
|
116
|
+
export declare const DIRT_SIGNAL_OPS_EVENTS_COLUMNS: OpsEventColumn[];
|
|
117
|
+
export declare const RELIN_OPERATIONAL_EVENTS_COLUMNS: OpsEventColumn[];
|
|
118
|
+
export declare const ADGIRO_OPS_EVENTS_COLUMNS: OpsEventColumn[];
|
|
24
119
|
export declare const D1_OPS_EVENTS_SCHEMA = "\nCREATE TABLE IF NOT EXISTS ops_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n event_type TEXT NOT NULL,\n severity TEXT NOT NULL DEFAULT 'info',\n source TEXT NOT NULL,\n fingerprint TEXT,\n payload_json TEXT NOT NULL DEFAULT '{}',\n created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP\n);\nCREATE INDEX IF NOT EXISTS ops_events_created_at_idx ON ops_events(created_at DESC);\nCREATE INDEX IF NOT EXISTS ops_events_type_created_idx ON ops_events(event_type, created_at DESC);\nCREATE INDEX IF NOT EXISTS ops_events_severity_created_idx ON ops_events(severity, created_at DESC);\n";
|
|
25
120
|
//# sourceMappingURL=ops-events.d.ts.map
|
package/dist/ops-events.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ops-events.d.ts","sourceRoot":"","sources":["../src/ops-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"ops-events.d.ts","sourceRoot":"","sources":["../src/ops-events.ts"],"names":[],"mappings":"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"}
|
package/dist/ops-events.js
CHANGED
|
@@ -1,10 +1,79 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createId } from "./ids.js";
|
|
2
|
+
export function normalizeOpsEvent(input, options = {}) {
|
|
3
|
+
const errorInfo = normalizeError(input.error);
|
|
4
|
+
const eventName = requiredName(input.eventName ?? input.eventType, "eventName");
|
|
5
|
+
return {
|
|
6
|
+
eventId: input.eventId ?? createId(options.idPrefix ?? "opsevt"),
|
|
7
|
+
eventName,
|
|
8
|
+
workflow: requiredName(input.workflow ?? input.source ?? eventName, "workflow"),
|
|
9
|
+
status: input.status ?? statusFromSeverity(input.severity),
|
|
10
|
+
severity: input.severity ?? severityFromStatus(input.status),
|
|
11
|
+
runId: input.runId ?? null,
|
|
12
|
+
jobId: input.jobId ?? null,
|
|
13
|
+
parentEventId: input.parentEventId ?? null,
|
|
14
|
+
scopeId: input.scopeId ?? null,
|
|
15
|
+
sourceId: input.sourceId ?? null,
|
|
16
|
+
destinationId: input.destinationId ?? null,
|
|
17
|
+
actorId: input.actorId ?? null,
|
|
18
|
+
orgId: input.orgId ?? null,
|
|
19
|
+
customerId: input.customerId ?? null,
|
|
20
|
+
provider: input.provider ?? null,
|
|
21
|
+
targetType: input.targetType ?? null,
|
|
22
|
+
targetId: input.targetId ?? null,
|
|
23
|
+
durationMs: input.durationMs ?? null,
|
|
24
|
+
statusCode: input.statusCode ?? null,
|
|
25
|
+
requestMethod: input.requestMethod ?? null,
|
|
26
|
+
requestPath: input.requestPath ?? null,
|
|
27
|
+
requestUrl: input.requestUrl ?? null,
|
|
28
|
+
message: input.message ?? errorInfo.message,
|
|
29
|
+
errorName: errorInfo.name,
|
|
30
|
+
errorMessage: input.errorMessage ?? errorInfo.message,
|
|
31
|
+
errorStack: errorInfo.stack,
|
|
32
|
+
payload: input.payload ?? {},
|
|
33
|
+
metrics: input.metrics ?? {},
|
|
34
|
+
metadata: input.metadata ?? {},
|
|
35
|
+
occurredAt: normalizeOccurredAt(input.occurredAt, options.now),
|
|
36
|
+
fingerprint: input.fingerprint ?? null,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function buildOpsEventInsert(config, input, options = {}) {
|
|
40
|
+
const event = isNormalizedOpsEvent(input) ? input : normalizeOpsEvent(input, options);
|
|
41
|
+
const columns = config.columns.map((column) => quoteIdentifier(column.column)).join(", ");
|
|
42
|
+
const values = config.columns.map((column) => valueForColumn(event, column));
|
|
43
|
+
const placeholders = config.columns
|
|
44
|
+
.map((column, index) => `$${index + 1}${column.cast ? `::${column.cast}` : ""}`)
|
|
45
|
+
.join(", ");
|
|
46
|
+
let text = `INSERT INTO ${quoteIdentifier(config.tableName)} (${columns}) VALUES (${placeholders})`;
|
|
47
|
+
if (config.conflictTarget?.length) {
|
|
48
|
+
const target = config.conflictTarget.map(quoteIdentifier).join(", ");
|
|
49
|
+
const updateColumns = config.updateColumns ?? config.columns.map((column) => column.column).filter((column) => !config.conflictTarget?.includes(column));
|
|
50
|
+
if (updateColumns.length === 0) {
|
|
51
|
+
text += ` ON CONFLICT (${target}) DO NOTHING`;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
text += ` ON CONFLICT (${target}) DO UPDATE SET ${updateColumns
|
|
55
|
+
.map((column) => `${quoteIdentifier(column)} = excluded.${quoteIdentifier(column)}`)
|
|
56
|
+
.join(", ")}`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { text, values };
|
|
60
|
+
}
|
|
61
|
+
export async function recordPostgresOpsEvent(sql, config, input, options = {}) {
|
|
62
|
+
const event = isNormalizedOpsEvent(input) ? input : normalizeOpsEvent(input, options);
|
|
63
|
+
const statement = buildOpsEventInsert(config, event, options);
|
|
64
|
+
await sql.unsafe(statement.text, statement.values);
|
|
65
|
+
return event;
|
|
66
|
+
}
|
|
67
|
+
export async function recordD1OpsEvent(db, input, config = {}) {
|
|
68
|
+
const event = isNormalizedOpsEvent(input) ? input : normalizeOpsEvent(input);
|
|
69
|
+
const columns = config.columns ?? DEFAULT_D1_OPS_EVENT_COLUMNS;
|
|
70
|
+
const tableName = config.tableName ?? "ops_events";
|
|
71
|
+
const sql = `INSERT INTO ${quoteIdentifier(tableName)} (${columns.map((column) => quoteIdentifier(column.column)).join(", ")}) VALUES (${columns.map(() => "?").join(", ")})`;
|
|
72
|
+
await db.prepare(sql).bind(...columns.map((column) => valueForColumn(event, column))).run();
|
|
73
|
+
return event;
|
|
74
|
+
}
|
|
2
75
|
export async function recordOpsEvent(db, input) {
|
|
3
|
-
await db
|
|
4
|
-
.prepare(`INSERT INTO ops_events (event_type, severity, source, fingerprint, payload_json)
|
|
5
|
-
VALUES (?, ?, ?, ?, ?)`)
|
|
6
|
-
.bind(input.eventType, input.severity ?? "info", input.source, input.fingerprint ?? null, stringifyJsonColumn(input.payload ?? {}))
|
|
7
|
-
.run();
|
|
76
|
+
await recordD1OpsEvent(db, input);
|
|
8
77
|
}
|
|
9
78
|
export async function listRecentOpsEvents(db, options = {}) {
|
|
10
79
|
const limit = Math.max(1, Math.min(200, Math.floor(options.limit ?? 25)));
|
|
@@ -26,6 +95,70 @@ export async function listRecentOpsEvents(db, options = {}) {
|
|
|
26
95
|
const rows = await statement.all();
|
|
27
96
|
return rows.results ?? [];
|
|
28
97
|
}
|
|
98
|
+
export const DEFAULT_D1_OPS_EVENT_COLUMNS = [
|
|
99
|
+
{ column: "event_type", value: "eventName" },
|
|
100
|
+
{ column: "severity", value: "severity" },
|
|
101
|
+
{ column: "source", value: "workflow" },
|
|
102
|
+
{ column: "fingerprint", value: "fingerprint" },
|
|
103
|
+
{ column: "payload_json", value: "payloadJson" },
|
|
104
|
+
];
|
|
105
|
+
export const GRAPHILIZE_GRAPH_EVENTS_COLUMNS = [
|
|
106
|
+
{ column: "event_id", value: "eventId" },
|
|
107
|
+
{ column: "graph_id", value: "scopeId" },
|
|
108
|
+
{ column: "event_name", value: "eventName" },
|
|
109
|
+
{ column: "workflow", value: "workflow" },
|
|
110
|
+
{ column: "target_type", value: "targetType" },
|
|
111
|
+
{ column: "target_id", value: "targetId" },
|
|
112
|
+
{ column: "status", value: "status" },
|
|
113
|
+
{ column: "message", value: "message" },
|
|
114
|
+
{ column: "payload_json", value: "payloadJson", cast: "jsonb" },
|
|
115
|
+
{ column: "metrics_json", value: "metricsJson", cast: "jsonb" },
|
|
116
|
+
{ column: "metadata_json", value: "metadataJson", cast: "jsonb" },
|
|
117
|
+
{ column: "occurred_at", value: "occurredAt", cast: "timestamptz" },
|
|
118
|
+
];
|
|
119
|
+
export const DIRT_SIGNAL_OPS_EVENTS_COLUMNS = [
|
|
120
|
+
{ column: "event_id", value: "eventId" },
|
|
121
|
+
{ column: "run_id", value: "runId" },
|
|
122
|
+
{ column: "event_name", value: "eventName" },
|
|
123
|
+
{ column: "workflow", value: "workflow" },
|
|
124
|
+
{ column: "target_type", value: "targetType" },
|
|
125
|
+
{ column: "target_id", value: "targetId" },
|
|
126
|
+
{ column: "status", value: "status" },
|
|
127
|
+
{ column: "message", value: "message" },
|
|
128
|
+
{ column: "error_message", value: "errorMessage" },
|
|
129
|
+
{ column: "metrics_json", value: "metricsJson", cast: "jsonb" },
|
|
130
|
+
{ column: "metadata_json", value: "metadataJson", cast: "jsonb" },
|
|
131
|
+
{ column: "occurred_at", value: "occurredAt", cast: "timestamptz" },
|
|
132
|
+
];
|
|
133
|
+
export const RELIN_OPERATIONAL_EVENTS_COLUMNS = [
|
|
134
|
+
{ column: "operational_event_id", value: "eventId" },
|
|
135
|
+
{ column: "name", value: "eventName" },
|
|
136
|
+
{ column: "status", value: "status" },
|
|
137
|
+
{ column: "customer_id", value: "customerId" },
|
|
138
|
+
{ column: "source_id", value: "sourceId" },
|
|
139
|
+
{ column: "event_id", value: "targetId" },
|
|
140
|
+
{ column: "destination_id", value: "destinationId" },
|
|
141
|
+
{ column: "duration_ms", value: "durationMs" },
|
|
142
|
+
{ column: "metadata_json", value: "metadataJson" },
|
|
143
|
+
];
|
|
144
|
+
export const ADGIRO_OPS_EVENTS_COLUMNS = [
|
|
145
|
+
{ column: "ops_event_id", value: "eventId" },
|
|
146
|
+
{ column: "level", value: "severity" },
|
|
147
|
+
{ column: "event_type", value: "eventName" },
|
|
148
|
+
{ column: "request_method", value: "requestMethod" },
|
|
149
|
+
{ column: "request_path", value: "requestPath" },
|
|
150
|
+
{ column: "request_url", value: "requestUrl" },
|
|
151
|
+
{ column: "status_code", value: "statusCode" },
|
|
152
|
+
{ column: "user_id", value: "actorId" },
|
|
153
|
+
{ column: "org_id", value: "orgId" },
|
|
154
|
+
{ column: "provider", value: "provider" },
|
|
155
|
+
{ column: "message", value: (event) => event.message ?? event.eventName },
|
|
156
|
+
{ column: "error_name", value: "errorName" },
|
|
157
|
+
{ column: "error_stack", value: "errorStack" },
|
|
158
|
+
{ column: "metadata_json", value: "metadataJson" },
|
|
159
|
+
{ column: "job_id", value: "jobId" },
|
|
160
|
+
{ column: "parent_ops_event_id", value: "parentEventId" },
|
|
161
|
+
];
|
|
29
162
|
export const D1_OPS_EVENTS_SCHEMA = `
|
|
30
163
|
CREATE TABLE IF NOT EXISTS ops_events (
|
|
31
164
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -40,4 +173,74 @@ CREATE INDEX IF NOT EXISTS ops_events_created_at_idx ON ops_events(created_at DE
|
|
|
40
173
|
CREATE INDEX IF NOT EXISTS ops_events_type_created_idx ON ops_events(event_type, created_at DESC);
|
|
41
174
|
CREATE INDEX IF NOT EXISTS ops_events_severity_created_idx ON ops_events(severity, created_at DESC);
|
|
42
175
|
`;
|
|
176
|
+
function valueForColumn(event, column) {
|
|
177
|
+
if (typeof column.value === "function")
|
|
178
|
+
return column.value(event);
|
|
179
|
+
if (column.value === "payloadJson")
|
|
180
|
+
return JSON.stringify(event.payload ?? {});
|
|
181
|
+
if (column.value === "metricsJson")
|
|
182
|
+
return JSON.stringify(event.metrics ?? {});
|
|
183
|
+
if (column.value === "metadataJson")
|
|
184
|
+
return JSON.stringify(event.metadata ?? {});
|
|
185
|
+
if (column.value === "null")
|
|
186
|
+
return null;
|
|
187
|
+
return event[column.value];
|
|
188
|
+
}
|
|
189
|
+
function normalizeError(error) {
|
|
190
|
+
if (!error)
|
|
191
|
+
return { name: null, message: null, stack: null };
|
|
192
|
+
if (error instanceof Error) {
|
|
193
|
+
return {
|
|
194
|
+
name: error.name,
|
|
195
|
+
message: error.message,
|
|
196
|
+
stack: error.stack ?? error.message,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
name: typeof error,
|
|
201
|
+
message: String(error),
|
|
202
|
+
stack: String(error),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function statusFromSeverity(severity) {
|
|
206
|
+
if (severity === "error")
|
|
207
|
+
return "error";
|
|
208
|
+
if (severity === "warn")
|
|
209
|
+
return "warning";
|
|
210
|
+
return "ok";
|
|
211
|
+
}
|
|
212
|
+
function severityFromStatus(status) {
|
|
213
|
+
if (status === "error")
|
|
214
|
+
return "error";
|
|
215
|
+
if (status === "warning" || status === "skipped")
|
|
216
|
+
return "warn";
|
|
217
|
+
return "info";
|
|
218
|
+
}
|
|
219
|
+
function normalizeOccurredAt(value, now) {
|
|
220
|
+
if (value instanceof Date)
|
|
221
|
+
return value.toISOString();
|
|
222
|
+
if (typeof value === "string" && value.trim())
|
|
223
|
+
return value;
|
|
224
|
+
return (now?.() ?? new Date()).toISOString();
|
|
225
|
+
}
|
|
226
|
+
function requiredName(value, field) {
|
|
227
|
+
const trimmed = value?.trim();
|
|
228
|
+
if (!trimmed)
|
|
229
|
+
throw new Error(`Ops event ${field} is required.`);
|
|
230
|
+
return trimmed;
|
|
231
|
+
}
|
|
232
|
+
function quoteIdentifier(value) {
|
|
233
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
|
|
234
|
+
throw new Error(`Unsafe SQL identifier: ${value}`);
|
|
235
|
+
}
|
|
236
|
+
return `"${value}"`;
|
|
237
|
+
}
|
|
238
|
+
function isNormalizedOpsEvent(value) {
|
|
239
|
+
return ("eventId" in value &&
|
|
240
|
+
"eventName" in value &&
|
|
241
|
+
"workflow" in value &&
|
|
242
|
+
"severity" in value &&
|
|
243
|
+
"message" in value &&
|
|
244
|
+
"occurredAt" in value);
|
|
245
|
+
}
|
|
43
246
|
//# sourceMappingURL=ops-events.js.map
|
package/dist/ops-events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ops-events.js","sourceRoot":"","sources":["../src/ops-events.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAsB9C,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EAAkB,EAAE,KAAoB;IAC3E,MAAM,EAAE;SACL,OAAO,CACN;8BACwB,CACzB;SACA,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,QAAQ,IAAI,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;SAClI,GAAG,EAAE,CAAC;AACX,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAkB,EAClB,UAAyD,EAAE;IAE3D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1E,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC;IAC5C,MAAM,SAAS,GAAG,SAAS;QACzB,CAAC,CAAC,EAAE;aACC,OAAO,CACN;;;;mBAIS,CACV;aACA,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC;QAC3B,CAAC,CAAC,EAAE;aACC,OAAO,CACN;;;mBAGS,CACV;aACA,IAAI,CAAC,KAAK,CAAC,CAAC;IACnB,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,EAAe,CAAC;IAChD,OAAO,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;CAanC,CAAC"}
|
|
1
|
+
{"version":3,"file":"ops-events.js","sourceRoot":"","sources":["../src/ops-events.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@q32/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Shared TypeScript primitives for Q32 Cloudflare Worker projects.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -124,20 +124,28 @@
|
|
|
124
124
|
"README.md",
|
|
125
125
|
"LICENSE"
|
|
126
126
|
],
|
|
127
|
+
"peerDependencies": {
|
|
128
|
+
"kysely": ">=0.28 <0.30",
|
|
129
|
+
"kysely-postgres-js": "^3.0.0",
|
|
130
|
+
"postgres": "^3.4.0"
|
|
131
|
+
},
|
|
127
132
|
"devDependencies": {
|
|
128
133
|
"@cloudflare/workers-types": "^4.20260606.0",
|
|
129
134
|
"@vitest/coverage-v8": "^4.1.8",
|
|
135
|
+
"kysely": "^0.29.2",
|
|
136
|
+
"kysely-postgres-js": "^3.0.0",
|
|
137
|
+
"postgres": "^3.4.9",
|
|
130
138
|
"typescript": "^5.9.3",
|
|
131
139
|
"vitest": "^4.0.15"
|
|
132
140
|
},
|
|
141
|
+
"publishConfig": {
|
|
142
|
+
"access": "public"
|
|
143
|
+
},
|
|
133
144
|
"dependencies": {
|
|
134
145
|
"kysely": "^0.29.2",
|
|
135
146
|
"kysely-postgres-js": "^3.0.0",
|
|
136
147
|
"postgres": "^3.4.9"
|
|
137
148
|
},
|
|
138
|
-
"publishConfig": {
|
|
139
|
-
"access": "public"
|
|
140
|
-
},
|
|
141
149
|
"scripts": {
|
|
142
150
|
"build": "tsc -p tsconfig.json",
|
|
143
151
|
"test": "vitest run",
|
package/src/ops-events.ts
CHANGED
|
@@ -1,36 +1,222 @@
|
|
|
1
|
+
import type postgres from "postgres";
|
|
1
2
|
import type { D1DatabaseLike } from "./d1.js";
|
|
2
|
-
import {
|
|
3
|
+
import { createId } from "./ids.js";
|
|
3
4
|
|
|
4
|
-
export type
|
|
5
|
+
export type OpsEventStatus = "started" | "ok" | "warning" | "error" | "skipped";
|
|
6
|
+
export type OpsEventSeverity = "debug" | "info" | "warn" | "error";
|
|
5
7
|
|
|
6
8
|
export type OpsEventInput = {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
eventId?: string;
|
|
10
|
+
eventName?: string;
|
|
11
|
+
eventType?: string;
|
|
12
|
+
workflow?: string;
|
|
13
|
+
source?: string;
|
|
14
|
+
status?: OpsEventStatus;
|
|
15
|
+
severity?: OpsEventSeverity;
|
|
16
|
+
runId?: string | null;
|
|
17
|
+
jobId?: string | null;
|
|
18
|
+
parentEventId?: string | null;
|
|
19
|
+
scopeId?: string | null;
|
|
20
|
+
sourceId?: string | null;
|
|
21
|
+
destinationId?: string | null;
|
|
22
|
+
actorId?: string | null;
|
|
23
|
+
orgId?: string | null;
|
|
24
|
+
customerId?: string | null;
|
|
25
|
+
provider?: string | null;
|
|
26
|
+
targetType?: string | null;
|
|
27
|
+
targetId?: string | null;
|
|
28
|
+
durationMs?: number | null;
|
|
29
|
+
statusCode?: number | null;
|
|
30
|
+
requestMethod?: string | null;
|
|
31
|
+
requestPath?: string | null;
|
|
32
|
+
requestUrl?: string | null;
|
|
33
|
+
message?: string | null;
|
|
34
|
+
error?: unknown;
|
|
35
|
+
errorMessage?: string | null;
|
|
11
36
|
payload?: unknown;
|
|
37
|
+
metrics?: unknown;
|
|
38
|
+
metadata?: unknown;
|
|
39
|
+
occurredAt?: string | Date;
|
|
40
|
+
fingerprint?: string | null;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type NormalizedOpsEvent = {
|
|
44
|
+
eventId: string;
|
|
45
|
+
eventName: string;
|
|
46
|
+
workflow: string;
|
|
47
|
+
status: OpsEventStatus;
|
|
48
|
+
severity: OpsEventSeverity;
|
|
49
|
+
runId: string | null;
|
|
50
|
+
jobId: string | null;
|
|
51
|
+
parentEventId: string | null;
|
|
52
|
+
scopeId: string | null;
|
|
53
|
+
sourceId: string | null;
|
|
54
|
+
destinationId: string | null;
|
|
55
|
+
actorId: string | null;
|
|
56
|
+
orgId: string | null;
|
|
57
|
+
customerId: string | null;
|
|
58
|
+
provider: string | null;
|
|
59
|
+
targetType: string | null;
|
|
60
|
+
targetId: string | null;
|
|
61
|
+
durationMs: number | null;
|
|
62
|
+
statusCode: number | null;
|
|
63
|
+
requestMethod: string | null;
|
|
64
|
+
requestPath: string | null;
|
|
65
|
+
requestUrl: string | null;
|
|
66
|
+
message: string | null;
|
|
67
|
+
errorName: string | null;
|
|
68
|
+
errorMessage: string | null;
|
|
69
|
+
errorStack: string | null;
|
|
70
|
+
payload: unknown;
|
|
71
|
+
metrics: unknown;
|
|
72
|
+
metadata: unknown;
|
|
73
|
+
occurredAt: string;
|
|
74
|
+
fingerprint: string | null;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export type OpsEventNormalizeOptions = {
|
|
78
|
+
idPrefix?: string;
|
|
79
|
+
now?: () => Date;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export type OpsEventColumnValue =
|
|
83
|
+
| keyof NormalizedOpsEvent
|
|
84
|
+
| "payloadJson"
|
|
85
|
+
| "metricsJson"
|
|
86
|
+
| "metadataJson"
|
|
87
|
+
| "null";
|
|
88
|
+
|
|
89
|
+
export type OpsEventColumn = {
|
|
90
|
+
column: string;
|
|
91
|
+
value: OpsEventColumnValue | ((event: NormalizedOpsEvent) => unknown);
|
|
92
|
+
cast?: "jsonb" | "timestamptz";
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export type OpsEventSqlInsert = {
|
|
96
|
+
text: string;
|
|
97
|
+
values: unknown[];
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export type OpsEventSqlConfig = {
|
|
101
|
+
tableName: string;
|
|
102
|
+
columns: OpsEventColumn[];
|
|
103
|
+
conflictTarget?: string[];
|
|
104
|
+
updateColumns?: string[];
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export function normalizeOpsEvent(
|
|
108
|
+
input: OpsEventInput,
|
|
109
|
+
options: OpsEventNormalizeOptions = {},
|
|
110
|
+
): NormalizedOpsEvent {
|
|
111
|
+
const errorInfo = normalizeError(input.error);
|
|
112
|
+
const eventName = requiredName(input.eventName ?? input.eventType, "eventName");
|
|
113
|
+
return {
|
|
114
|
+
eventId: input.eventId ?? createId(options.idPrefix ?? "opsevt"),
|
|
115
|
+
eventName,
|
|
116
|
+
workflow: requiredName(input.workflow ?? input.source ?? eventName, "workflow"),
|
|
117
|
+
status: input.status ?? statusFromSeverity(input.severity),
|
|
118
|
+
severity: input.severity ?? severityFromStatus(input.status),
|
|
119
|
+
runId: input.runId ?? null,
|
|
120
|
+
jobId: input.jobId ?? null,
|
|
121
|
+
parentEventId: input.parentEventId ?? null,
|
|
122
|
+
scopeId: input.scopeId ?? null,
|
|
123
|
+
sourceId: input.sourceId ?? null,
|
|
124
|
+
destinationId: input.destinationId ?? null,
|
|
125
|
+
actorId: input.actorId ?? null,
|
|
126
|
+
orgId: input.orgId ?? null,
|
|
127
|
+
customerId: input.customerId ?? null,
|
|
128
|
+
provider: input.provider ?? null,
|
|
129
|
+
targetType: input.targetType ?? null,
|
|
130
|
+
targetId: input.targetId ?? null,
|
|
131
|
+
durationMs: input.durationMs ?? null,
|
|
132
|
+
statusCode: input.statusCode ?? null,
|
|
133
|
+
requestMethod: input.requestMethod ?? null,
|
|
134
|
+
requestPath: input.requestPath ?? null,
|
|
135
|
+
requestUrl: input.requestUrl ?? null,
|
|
136
|
+
message: input.message ?? errorInfo.message,
|
|
137
|
+
errorName: errorInfo.name,
|
|
138
|
+
errorMessage: input.errorMessage ?? errorInfo.message,
|
|
139
|
+
errorStack: errorInfo.stack,
|
|
140
|
+
payload: input.payload ?? {},
|
|
141
|
+
metrics: input.metrics ?? {},
|
|
142
|
+
metadata: input.metadata ?? {},
|
|
143
|
+
occurredAt: normalizeOccurredAt(input.occurredAt, options.now),
|
|
144
|
+
fingerprint: input.fingerprint ?? null,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function buildOpsEventInsert(
|
|
149
|
+
config: OpsEventSqlConfig,
|
|
150
|
+
input: OpsEventInput | NormalizedOpsEvent,
|
|
151
|
+
options: OpsEventNormalizeOptions = {},
|
|
152
|
+
): OpsEventSqlInsert {
|
|
153
|
+
const event = isNormalizedOpsEvent(input) ? input : normalizeOpsEvent(input, options);
|
|
154
|
+
const columns = config.columns.map((column) => quoteIdentifier(column.column)).join(", ");
|
|
155
|
+
const values = config.columns.map((column) => valueForColumn(event, column));
|
|
156
|
+
const placeholders = config.columns
|
|
157
|
+
.map((column, index) => `$${index + 1}${column.cast ? `::${column.cast}` : ""}`)
|
|
158
|
+
.join(", ");
|
|
159
|
+
let text = `INSERT INTO ${quoteIdentifier(config.tableName)} (${columns}) VALUES (${placeholders})`;
|
|
160
|
+
|
|
161
|
+
if (config.conflictTarget?.length) {
|
|
162
|
+
const target = config.conflictTarget.map(quoteIdentifier).join(", ");
|
|
163
|
+
const updateColumns = config.updateColumns ?? config.columns.map((column) => column.column).filter((column) => !config.conflictTarget?.includes(column));
|
|
164
|
+
if (updateColumns.length === 0) {
|
|
165
|
+
text += ` ON CONFLICT (${target}) DO NOTHING`;
|
|
166
|
+
} else {
|
|
167
|
+
text += ` ON CONFLICT (${target}) DO UPDATE SET ${updateColumns
|
|
168
|
+
.map((column) => `${quoteIdentifier(column)} = excluded.${quoteIdentifier(column)}`)
|
|
169
|
+
.join(", ")}`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return { text, values };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function recordPostgresOpsEvent(
|
|
177
|
+
sql: postgres.Sql,
|
|
178
|
+
config: OpsEventSqlConfig,
|
|
179
|
+
input: OpsEventInput | NormalizedOpsEvent,
|
|
180
|
+
options: OpsEventNormalizeOptions = {},
|
|
181
|
+
): Promise<NormalizedOpsEvent> {
|
|
182
|
+
const event = isNormalizedOpsEvent(input) ? input : normalizeOpsEvent(input, options);
|
|
183
|
+
const statement = buildOpsEventInsert(config, event, options);
|
|
184
|
+
await sql.unsafe(statement.text, statement.values as never[]);
|
|
185
|
+
return event;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export type D1OpsEventConfig = {
|
|
189
|
+
tableName?: string;
|
|
190
|
+
columns?: OpsEventColumn[];
|
|
12
191
|
};
|
|
13
192
|
|
|
193
|
+
export async function recordD1OpsEvent(
|
|
194
|
+
db: D1DatabaseLike,
|
|
195
|
+
input: OpsEventInput | NormalizedOpsEvent,
|
|
196
|
+
config: D1OpsEventConfig = {},
|
|
197
|
+
): Promise<NormalizedOpsEvent> {
|
|
198
|
+
const event = isNormalizedOpsEvent(input) ? input : normalizeOpsEvent(input);
|
|
199
|
+
const columns = config.columns ?? DEFAULT_D1_OPS_EVENT_COLUMNS;
|
|
200
|
+
const tableName = config.tableName ?? "ops_events";
|
|
201
|
+
const sql = `INSERT INTO ${quoteIdentifier(tableName)} (${columns.map((column) => quoteIdentifier(column.column)).join(", ")}) VALUES (${columns.map(() => "?").join(", ")})`;
|
|
202
|
+
await db.prepare(sql).bind(...(columns.map((column) => valueForColumn(event, column)) as never[])).run();
|
|
203
|
+
return event;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export async function recordOpsEvent(db: D1DatabaseLike, input: OpsEventInput): Promise<void> {
|
|
207
|
+
await recordD1OpsEvent(db, input);
|
|
208
|
+
}
|
|
209
|
+
|
|
14
210
|
export type OpsEventRow = {
|
|
15
211
|
id: number;
|
|
16
212
|
event_type: string;
|
|
17
|
-
severity:
|
|
213
|
+
severity: OpsEventSeverity;
|
|
18
214
|
source: string;
|
|
19
215
|
fingerprint: string | null;
|
|
20
216
|
payload_json: string;
|
|
21
217
|
created_at: string;
|
|
22
218
|
};
|
|
23
219
|
|
|
24
|
-
export async function recordOpsEvent(db: D1DatabaseLike, input: OpsEventInput): Promise<void> {
|
|
25
|
-
await db
|
|
26
|
-
.prepare(
|
|
27
|
-
`INSERT INTO ops_events (event_type, severity, source, fingerprint, payload_json)
|
|
28
|
-
VALUES (?, ?, ?, ?, ?)`,
|
|
29
|
-
)
|
|
30
|
-
.bind(input.eventType, input.severity ?? "info", input.source, input.fingerprint ?? null, stringifyJsonColumn(input.payload ?? {}))
|
|
31
|
-
.run();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
220
|
export async function listRecentOpsEvents(
|
|
35
221
|
db: D1DatabaseLike,
|
|
36
222
|
options: { limit?: number; eventType?: string | null } = {},
|
|
@@ -59,6 +245,75 @@ export async function listRecentOpsEvents(
|
|
|
59
245
|
return rows.results ?? [];
|
|
60
246
|
}
|
|
61
247
|
|
|
248
|
+
export const DEFAULT_D1_OPS_EVENT_COLUMNS: OpsEventColumn[] = [
|
|
249
|
+
{ column: "event_type", value: "eventName" },
|
|
250
|
+
{ column: "severity", value: "severity" },
|
|
251
|
+
{ column: "source", value: "workflow" },
|
|
252
|
+
{ column: "fingerprint", value: "fingerprint" },
|
|
253
|
+
{ column: "payload_json", value: "payloadJson" },
|
|
254
|
+
];
|
|
255
|
+
|
|
256
|
+
export const GRAPHILIZE_GRAPH_EVENTS_COLUMNS: OpsEventColumn[] = [
|
|
257
|
+
{ column: "event_id", value: "eventId" },
|
|
258
|
+
{ column: "graph_id", value: "scopeId" },
|
|
259
|
+
{ column: "event_name", value: "eventName" },
|
|
260
|
+
{ column: "workflow", value: "workflow" },
|
|
261
|
+
{ column: "target_type", value: "targetType" },
|
|
262
|
+
{ column: "target_id", value: "targetId" },
|
|
263
|
+
{ column: "status", value: "status" },
|
|
264
|
+
{ column: "message", value: "message" },
|
|
265
|
+
{ column: "payload_json", value: "payloadJson", cast: "jsonb" },
|
|
266
|
+
{ column: "metrics_json", value: "metricsJson", cast: "jsonb" },
|
|
267
|
+
{ column: "metadata_json", value: "metadataJson", cast: "jsonb" },
|
|
268
|
+
{ column: "occurred_at", value: "occurredAt", cast: "timestamptz" },
|
|
269
|
+
];
|
|
270
|
+
|
|
271
|
+
export const DIRT_SIGNAL_OPS_EVENTS_COLUMNS: OpsEventColumn[] = [
|
|
272
|
+
{ column: "event_id", value: "eventId" },
|
|
273
|
+
{ column: "run_id", value: "runId" },
|
|
274
|
+
{ column: "event_name", value: "eventName" },
|
|
275
|
+
{ column: "workflow", value: "workflow" },
|
|
276
|
+
{ column: "target_type", value: "targetType" },
|
|
277
|
+
{ column: "target_id", value: "targetId" },
|
|
278
|
+
{ column: "status", value: "status" },
|
|
279
|
+
{ column: "message", value: "message" },
|
|
280
|
+
{ column: "error_message", value: "errorMessage" },
|
|
281
|
+
{ column: "metrics_json", value: "metricsJson", cast: "jsonb" },
|
|
282
|
+
{ column: "metadata_json", value: "metadataJson", cast: "jsonb" },
|
|
283
|
+
{ column: "occurred_at", value: "occurredAt", cast: "timestamptz" },
|
|
284
|
+
];
|
|
285
|
+
|
|
286
|
+
export const RELIN_OPERATIONAL_EVENTS_COLUMNS: OpsEventColumn[] = [
|
|
287
|
+
{ column: "operational_event_id", value: "eventId" },
|
|
288
|
+
{ column: "name", value: "eventName" },
|
|
289
|
+
{ column: "status", value: "status" },
|
|
290
|
+
{ column: "customer_id", value: "customerId" },
|
|
291
|
+
{ column: "source_id", value: "sourceId" },
|
|
292
|
+
{ column: "event_id", value: "targetId" },
|
|
293
|
+
{ column: "destination_id", value: "destinationId" },
|
|
294
|
+
{ column: "duration_ms", value: "durationMs" },
|
|
295
|
+
{ column: "metadata_json", value: "metadataJson" },
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
export const ADGIRO_OPS_EVENTS_COLUMNS: OpsEventColumn[] = [
|
|
299
|
+
{ column: "ops_event_id", value: "eventId" },
|
|
300
|
+
{ column: "level", value: "severity" },
|
|
301
|
+
{ column: "event_type", value: "eventName" },
|
|
302
|
+
{ column: "request_method", value: "requestMethod" },
|
|
303
|
+
{ column: "request_path", value: "requestPath" },
|
|
304
|
+
{ column: "request_url", value: "requestUrl" },
|
|
305
|
+
{ column: "status_code", value: "statusCode" },
|
|
306
|
+
{ column: "user_id", value: "actorId" },
|
|
307
|
+
{ column: "org_id", value: "orgId" },
|
|
308
|
+
{ column: "provider", value: "provider" },
|
|
309
|
+
{ column: "message", value: (event) => event.message ?? event.eventName },
|
|
310
|
+
{ column: "error_name", value: "errorName" },
|
|
311
|
+
{ column: "error_stack", value: "errorStack" },
|
|
312
|
+
{ column: "metadata_json", value: "metadataJson" },
|
|
313
|
+
{ column: "job_id", value: "jobId" },
|
|
314
|
+
{ column: "parent_ops_event_id", value: "parentEventId" },
|
|
315
|
+
];
|
|
316
|
+
|
|
62
317
|
export const D1_OPS_EVENTS_SCHEMA = `
|
|
63
318
|
CREATE TABLE IF NOT EXISTS ops_events (
|
|
64
319
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -73,3 +328,70 @@ CREATE INDEX IF NOT EXISTS ops_events_created_at_idx ON ops_events(created_at DE
|
|
|
73
328
|
CREATE INDEX IF NOT EXISTS ops_events_type_created_idx ON ops_events(event_type, created_at DESC);
|
|
74
329
|
CREATE INDEX IF NOT EXISTS ops_events_severity_created_idx ON ops_events(severity, created_at DESC);
|
|
75
330
|
`;
|
|
331
|
+
|
|
332
|
+
function valueForColumn(event: NormalizedOpsEvent, column: OpsEventColumn): unknown {
|
|
333
|
+
if (typeof column.value === "function") return column.value(event);
|
|
334
|
+
if (column.value === "payloadJson") return JSON.stringify(event.payload ?? {});
|
|
335
|
+
if (column.value === "metricsJson") return JSON.stringify(event.metrics ?? {});
|
|
336
|
+
if (column.value === "metadataJson") return JSON.stringify(event.metadata ?? {});
|
|
337
|
+
if (column.value === "null") return null;
|
|
338
|
+
return event[column.value];
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function normalizeError(error: unknown): { name: string | null; message: string | null; stack: string | null } {
|
|
342
|
+
if (!error) return { name: null, message: null, stack: null };
|
|
343
|
+
if (error instanceof Error) {
|
|
344
|
+
return {
|
|
345
|
+
name: error.name,
|
|
346
|
+
message: error.message,
|
|
347
|
+
stack: error.stack ?? error.message,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
name: typeof error,
|
|
352
|
+
message: String(error),
|
|
353
|
+
stack: String(error),
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function statusFromSeverity(severity: OpsEventSeverity | undefined): OpsEventStatus {
|
|
358
|
+
if (severity === "error") return "error";
|
|
359
|
+
if (severity === "warn") return "warning";
|
|
360
|
+
return "ok";
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function severityFromStatus(status: OpsEventStatus | undefined): OpsEventSeverity {
|
|
364
|
+
if (status === "error") return "error";
|
|
365
|
+
if (status === "warning" || status === "skipped") return "warn";
|
|
366
|
+
return "info";
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function normalizeOccurredAt(value: string | Date | undefined, now: (() => Date) | undefined): string {
|
|
370
|
+
if (value instanceof Date) return value.toISOString();
|
|
371
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
372
|
+
return (now?.() ?? new Date()).toISOString();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function requiredName(value: string | undefined, field: string): string {
|
|
376
|
+
const trimmed = value?.trim();
|
|
377
|
+
if (!trimmed) throw new Error(`Ops event ${field} is required.`);
|
|
378
|
+
return trimmed;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function quoteIdentifier(value: string): string {
|
|
382
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
|
|
383
|
+
throw new Error(`Unsafe SQL identifier: ${value}`);
|
|
384
|
+
}
|
|
385
|
+
return `"${value}"`;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function isNormalizedOpsEvent(value: OpsEventInput | NormalizedOpsEvent): value is NormalizedOpsEvent {
|
|
389
|
+
return (
|
|
390
|
+
"eventId" in value &&
|
|
391
|
+
"eventName" in value &&
|
|
392
|
+
"workflow" in value &&
|
|
393
|
+
"severity" in value &&
|
|
394
|
+
"message" in value &&
|
|
395
|
+
"occurredAt" in value
|
|
396
|
+
);
|
|
397
|
+
}
|