@wtfalch/reporting 0.7.0 → 0.9.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/README.md +59 -6
- package/dist/analytics/write.js +3 -0
- package/dist/deploy.d.ts +11 -0
- package/dist/deploy.js +13 -0
- package/dist/errors/capture.js +4 -0
- package/dist/errors/reader.js +1 -0
- package/dist/index.js +16 -1
- package/dist/migrations/0009_release_color.sql +33 -0
- package/dist/migrations/0010_requests.sql +27 -0
- package/dist/next/count.d.ts +49 -0
- package/dist/next/count.js +100 -0
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +2 -0
- package/dist/next/release-health.d.ts +24 -0
- package/dist/next/release-health.js +122 -0
- package/dist/requests.d.ts +29 -0
- package/dist/requests.js +82 -0
- package/dist/tables.d.ts +391 -1
- package/dist/tables.js +20 -0
- package/dist/types.d.ts +7 -0
- package/dist/writer.js +2 -0
- package/package.json +1 -5
- package/dist/fake/index.d.ts +0 -22
- package/dist/fake/index.js +0 -157
package/dist/fake/index.js
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { alertRow } from '../alerts.js';
|
|
2
|
-
import { createCapture } from '../errors/capture.js';
|
|
3
|
-
import { eventInputSchema } from '../schema.js';
|
|
4
|
-
import { DEFAULT_SETTINGS, RETENTION_BOUNDS } from '../settings.js';
|
|
5
|
-
import { tables } from '../tables.js';
|
|
6
|
-
const silent = { info() { }, warn() { }, error() { } };
|
|
7
|
-
export function createFakeReporting(opts = {}) {
|
|
8
|
-
const site = opts.site ?? 'test';
|
|
9
|
-
const environment = opts.environment ?? null;
|
|
10
|
-
const log = opts.log ?? silent;
|
|
11
|
-
const rows = [];
|
|
12
|
-
const alerts = [];
|
|
13
|
-
const tracked = [];
|
|
14
|
-
let settings = { ...DEFAULT_SETTINGS };
|
|
15
|
-
const tenantRetention = new Map();
|
|
16
|
-
let id = 0;
|
|
17
|
-
// No group table to fake, so the upsert never runs (`defer` is a no-op);
|
|
18
|
-
// the timeline row through `fake.event` is what a host's test asserts on.
|
|
19
|
-
const capture = createCapture({
|
|
20
|
-
db: undefined,
|
|
21
|
-
log,
|
|
22
|
-
site,
|
|
23
|
-
now: () => new Date(),
|
|
24
|
-
defer: () => { },
|
|
25
|
-
event: (input) => fake.event(input),
|
|
26
|
-
redactEnvVars: opts.redactEnvVars,
|
|
27
|
-
});
|
|
28
|
-
const fake = {
|
|
29
|
-
site,
|
|
30
|
-
log,
|
|
31
|
-
tables,
|
|
32
|
-
rows,
|
|
33
|
-
alerts,
|
|
34
|
-
tracked,
|
|
35
|
-
event(input) {
|
|
36
|
-
const v = eventInputSchema.parse(input);
|
|
37
|
-
id += 1;
|
|
38
|
-
rows.push({
|
|
39
|
-
id,
|
|
40
|
-
occurredAt: v.occurredAt ?? new Date(),
|
|
41
|
-
level: v.level,
|
|
42
|
-
kind: v.kind,
|
|
43
|
-
kindNs: v.kind.split('.')[0] ?? '',
|
|
44
|
-
site,
|
|
45
|
-
environment,
|
|
46
|
-
tenantId: v.tenantId ?? null,
|
|
47
|
-
actorClass: v.actor?.class ?? null,
|
|
48
|
-
actorId: v.actor?.id ?? null,
|
|
49
|
-
requestId: v.requestId ?? null,
|
|
50
|
-
targetType: v.target?.type ?? null,
|
|
51
|
-
targetId: v.target?.id ?? null,
|
|
52
|
-
message: v.message,
|
|
53
|
-
data: v.data,
|
|
54
|
-
schemaVersion: 1,
|
|
55
|
-
});
|
|
56
|
-
},
|
|
57
|
-
alert(finding) {
|
|
58
|
-
fake.event(alertRow(finding));
|
|
59
|
-
alerts.push(finding);
|
|
60
|
-
},
|
|
61
|
-
captureError: (error, context) => capture(error, context),
|
|
62
|
-
async flush() { },
|
|
63
|
-
events: {
|
|
64
|
-
async page(o = {}) {
|
|
65
|
-
const limit = Math.max(1, Math.min(o.limit ?? 50, 200));
|
|
66
|
-
let list = [...rows].sort((a, b) => b.occurredAt.getTime() - a.occurredAt.getTime() || b.id - a.id);
|
|
67
|
-
if (o.level)
|
|
68
|
-
list = list.filter((r) => r.level === o.level);
|
|
69
|
-
if (o.kindNs)
|
|
70
|
-
list = list.filter((r) => r.kindNs === o.kindNs);
|
|
71
|
-
if (o.tenantId)
|
|
72
|
-
list = list.filter((r) => r.tenantId === o.tenantId);
|
|
73
|
-
if (o.site)
|
|
74
|
-
list = list.filter((r) => r.site === o.site);
|
|
75
|
-
if (o.requestId)
|
|
76
|
-
list = list.filter((r) => r.requestId === o.requestId);
|
|
77
|
-
if (o.environment)
|
|
78
|
-
list = list.filter((r) => r.environment === o.environment);
|
|
79
|
-
if (o.after) {
|
|
80
|
-
const { occurredAt, id: afterId } = o.after;
|
|
81
|
-
list = list.filter((r) => r.occurredAt.getTime() < occurredAt.getTime() ||
|
|
82
|
-
(r.occurredAt.getTime() === occurredAt.getTime() && r.id < afterId));
|
|
83
|
-
}
|
|
84
|
-
const items = list.slice(0, limit);
|
|
85
|
-
const last = items.at(-1);
|
|
86
|
-
return {
|
|
87
|
-
items,
|
|
88
|
-
next: list.length > limit && last ? { occurredAt: last.occurredAt, id: last.id } : null,
|
|
89
|
-
};
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
settings: {
|
|
93
|
-
async get() {
|
|
94
|
-
return settings;
|
|
95
|
-
},
|
|
96
|
-
async set(patch, by) {
|
|
97
|
-
const before = settings;
|
|
98
|
-
for (const [key, value] of Object.entries(patch)) {
|
|
99
|
-
if (typeof value !== 'number' ||
|
|
100
|
-
!Number.isInteger(value) ||
|
|
101
|
-
value < RETENTION_BOUNDS.min ||
|
|
102
|
-
value > RETENTION_BOUNDS.max) {
|
|
103
|
-
throw new Error(`reporting.settings: ${key} out of bounds`);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
settings = { ...settings, ...patch };
|
|
107
|
-
const changed = Object.keys(patch).filter((k) => before[k] !== settings[k]);
|
|
108
|
-
return { before, after: settings, by, changed };
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
tenantSettings: {
|
|
112
|
-
async get(tenantId) {
|
|
113
|
-
const out = {};
|
|
114
|
-
for (const key of ['events.retention_days', 'analytics.retention_days']) {
|
|
115
|
-
const value = tenantRetention.get(`${tenantId}:${key}`);
|
|
116
|
-
if (value !== undefined)
|
|
117
|
-
out[key] = value;
|
|
118
|
-
}
|
|
119
|
-
return out;
|
|
120
|
-
},
|
|
121
|
-
async set(tenantId, key, days) {
|
|
122
|
-
const mapKey = `${tenantId}:${key}`;
|
|
123
|
-
if (days === null) {
|
|
124
|
-
tenantRetention.delete(mapKey);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
if (!Number.isInteger(days) || days < RETENTION_BOUNDS.min || days > RETENTION_BOUNDS.max) {
|
|
128
|
-
throw new Error(`reporting.tenantSettings: ${key} out of bounds`);
|
|
129
|
-
}
|
|
130
|
-
tenantRetention.set(mapKey, days);
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
analytics: {
|
|
134
|
-
async track(input) {
|
|
135
|
-
tracked.push({ ...input, site });
|
|
136
|
-
},
|
|
137
|
-
async series() {
|
|
138
|
-
return [];
|
|
139
|
-
},
|
|
140
|
-
async weekly() {
|
|
141
|
-
return [];
|
|
142
|
-
},
|
|
143
|
-
async recent() {
|
|
144
|
-
return [];
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
stats: () => ({ queued: 0, dropped: 0, invalid: 0, flushed: rows.length }),
|
|
148
|
-
reset() {
|
|
149
|
-
rows.length = 0;
|
|
150
|
-
alerts.length = 0;
|
|
151
|
-
settings = { ...DEFAULT_SETTINGS };
|
|
152
|
-
tenantRetention.clear();
|
|
153
|
-
id = 0;
|
|
154
|
-
},
|
|
155
|
-
};
|
|
156
|
-
return fake;
|
|
157
|
-
}
|