@wizeworks/lens-cloud 0.0.0-stage → 0.3.0-alpha.1
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/LICENSE +21 -0
- package/README.md +63 -2
- package/dist/alerts/evaluate.d.ts +10 -0
- package/dist/alerts/evaluate.d.ts.map +1 -0
- package/dist/alerts/evaluate.js +66 -0
- package/dist/alerts/evaluate.js.map +1 -0
- package/dist/alerts/notify.d.ts +17 -0
- package/dist/alerts/notify.d.ts.map +1 -0
- package/dist/alerts/notify.js +46 -0
- package/dist/alerts/notify.js.map +1 -0
- package/dist/app.d.ts +18 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +2 -0
- package/dist/app.js.map +1 -0
- package/dist/auth/crypto.d.ts +19 -0
- package/dist/auth/crypto.d.ts.map +1 -0
- package/dist/auth/crypto.js +33 -0
- package/dist/auth/crypto.js.map +1 -0
- package/dist/auth/principal.d.ts +33 -0
- package/dist/auth/principal.d.ts.map +1 -0
- package/dist/auth/principal.js +64 -0
- package/dist/auth/principal.js.map +1 -0
- package/dist/auth/roles.d.ts +10 -0
- package/dist/auth/roles.d.ts.map +1 -0
- package/dist/auth/roles.js +9 -0
- package/dist/auth/roles.js.map +1 -0
- package/dist/cli-args.d.ts +5 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +45 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +28 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +20 -0
- package/dist/config.js.map +1 -0
- package/dist/db/db.d.ts +19 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +57 -0
- package/dist/db/db.js.map +1 -0
- package/dist/db/migrate.d.ts +6 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +25 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/schema.d.ts +3 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +200 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/http/http.d.ts +17 -0
- package/dist/http/http.d.ts.map +1 -0
- package/dist/http/http.js +62 -0
- package/dist/http/http.js.map +1 -0
- package/dist/http/limiter.d.ts +11 -0
- package/dist/http/limiter.d.ts.map +1 -0
- package/dist/http/limiter.js +31 -0
- package/dist/http/limiter.js.map +1 -0
- package/dist/http/router.d.ts +21 -0
- package/dist/http/router.d.ts.map +1 -0
- package/dist/http/router.js +28 -0
- package/dist/http/router.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs.d.ts +4 -0
- package/dist/jobs.d.ts.map +1 -0
- package/dist/jobs.js +42 -0
- package/dist/jobs.js.map +1 -0
- package/dist/repo/alerts.d.ts +48 -0
- package/dist/repo/alerts.d.ts.map +1 -0
- package/dist/repo/alerts.js +38 -0
- package/dist/repo/alerts.js.map +1 -0
- package/dist/repo/audit.d.ts +11 -0
- package/dist/repo/audit.d.ts.map +1 -0
- package/dist/repo/audit.js +17 -0
- package/dist/repo/audit.js.map +1 -0
- package/dist/repo/metric-read.d.ts +12 -0
- package/dist/repo/metric-read.d.ts.map +1 -0
- package/dist/repo/metric-read.js +11 -0
- package/dist/repo/metric-read.js.map +1 -0
- package/dist/repo/metric-write.d.ts +9 -0
- package/dist/repo/metric-write.d.ts.map +1 -0
- package/dist/repo/metric-write.js +53 -0
- package/dist/repo/metric-write.js.map +1 -0
- package/dist/repo/orgs.d.ts +47 -0
- package/dist/repo/orgs.d.ts.map +1 -0
- package/dist/repo/orgs.js +75 -0
- package/dist/repo/orgs.js.map +1 -0
- package/dist/repo/projects.d.ts +37 -0
- package/dist/repo/projects.d.ts.map +1 -0
- package/dist/repo/projects.js +57 -0
- package/dist/repo/projects.js.map +1 -0
- package/dist/repo/trace-read.d.ts +28 -0
- package/dist/repo/trace-read.d.ts.map +1 -0
- package/dist/repo/trace-read.js +76 -0
- package/dist/repo/trace-read.js.map +1 -0
- package/dist/repo/trace-write.d.ts +9 -0
- package/dist/repo/trace-write.d.ts.map +1 -0
- package/dist/repo/trace-write.js +82 -0
- package/dist/repo/trace-write.js.map +1 -0
- package/dist/repo/users.d.ts +24 -0
- package/dist/repo/users.d.ts.map +1 -0
- package/dist/repo/users.js +65 -0
- package/dist/repo/users.js.map +1 -0
- package/dist/routes/alerts.d.ts +4 -0
- package/dist/routes/alerts.d.ts.map +1 -0
- package/dist/routes/alerts.js +99 -0
- package/dist/routes/alerts.js.map +1 -0
- package/dist/routes/auth.d.ts +4 -0
- package/dist/routes/auth.d.ts.map +1 -0
- package/dist/routes/auth.js +106 -0
- package/dist/routes/auth.js.map +1 -0
- package/dist/routes/data.d.ts +7 -0
- package/dist/routes/data.d.ts.map +1 -0
- package/dist/routes/data.js +74 -0
- package/dist/routes/data.js.map +1 -0
- package/dist/routes/index.d.ts +5 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +23 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/ingest.d.ts +8 -0
- package/dist/routes/ingest.d.ts.map +1 -0
- package/dist/routes/ingest.js +38 -0
- package/dist/routes/ingest.js.map +1 -0
- package/dist/routes/mcp.d.ts +4 -0
- package/dist/routes/mcp.d.ts.map +1 -0
- package/dist/routes/mcp.js +52 -0
- package/dist/routes/mcp.js.map +1 -0
- package/dist/routes/metrics.d.ts +13 -0
- package/dist/routes/metrics.d.ts.map +1 -0
- package/dist/routes/metrics.js +29 -0
- package/dist/routes/metrics.js.map +1 -0
- package/dist/routes/models.d.ts +4 -0
- package/dist/routes/models.d.ts.map +1 -0
- package/dist/routes/models.js +71 -0
- package/dist/routes/models.js.map +1 -0
- package/dist/routes/orgs.d.ts +4 -0
- package/dist/routes/orgs.d.ts.map +1 -0
- package/dist/routes/orgs.js +96 -0
- package/dist/routes/orgs.js.map +1 -0
- package/dist/routes/projects.d.ts +4 -0
- package/dist/routes/projects.d.ts.map +1 -0
- package/dist/routes/projects.js +54 -0
- package/dist/routes/projects.js.map +1 -0
- package/dist/routes/shares.d.ts +11 -0
- package/dist/routes/shares.d.ts.map +1 -0
- package/dist/routes/shares.js +61 -0
- package/dist/routes/shares.js.map +1 -0
- package/dist/scale-exec.d.ts +11 -0
- package/dist/scale-exec.d.ts.map +1 -0
- package/dist/scale-exec.js +26 -0
- package/dist/scale-exec.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +95 -0
- package/dist/server.js.map +1 -0
- package/dist/settle.d.ts +26 -0
- package/dist/settle.d.ts.map +1 -0
- package/dist/settle.js +85 -0
- package/dist/settle.js.map +1 -0
- package/package.json +63 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-read.d.ts","sourceRoot":"","sources":["../../src/repo/trace-read.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,UAAU,EAA6B,KAAK,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACzI,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAsB,YAAY,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAejF;AAmBD,0CAA0C;AAC1C,wBAAsB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAS1G;AAED,eAAO,MAAM,WAAW,MAAa,SAAS,KAAK,UAAU,KAAG,OAAO,CAAC,KAAK,EAAE,CAAyD,CAAC;AAEzI,wBAAsB,QAAQ,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAG3G;AAED,6CAA6C;AAC7C,wBAAsB,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM1H;AASD,wBAAsB,YAAY,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAGtG;AAED,wBAAsB,cAAc,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAGvF;AAED,wBAAsB,SAAS,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAG3G"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { buildTrace, HUB_ONLINE_MS } from "@wizeworks/lens-core";
|
|
2
|
+
const CHUNK = 500;
|
|
3
|
+
export async function findTraceIds(q, t) {
|
|
4
|
+
const where = ["project_id = $1"];
|
|
5
|
+
const args = [t.projectId];
|
|
6
|
+
const add = (sql, v) => {
|
|
7
|
+
args.push(v);
|
|
8
|
+
where.push(sql.replace("?", `$${args.length}`));
|
|
9
|
+
};
|
|
10
|
+
if (t.since !== undefined)
|
|
11
|
+
add("updated_ms >= ?", t.since);
|
|
12
|
+
if (t.before !== undefined)
|
|
13
|
+
add("start_ms < ?", t.before);
|
|
14
|
+
if (t.from !== undefined)
|
|
15
|
+
add("start_ms >= ?", t.from);
|
|
16
|
+
if (t.env)
|
|
17
|
+
add("env = ?", t.env);
|
|
18
|
+
if (t.session)
|
|
19
|
+
add("trace_id IN (SELECT trace_id FROM spans WHERE project_id = $1 AND session = ?)", t.session);
|
|
20
|
+
args.push(t.limit);
|
|
21
|
+
const rows = await q.query(`SELECT trace_id FROM traces WHERE ${where.join(" AND ")} ORDER BY start_ms DESC LIMIT $${args.length}`, args);
|
|
22
|
+
return rows.map((r) => r.trace_id);
|
|
23
|
+
}
|
|
24
|
+
async function jsonByTrace(q, table, projectId, ids) {
|
|
25
|
+
const out = new Map();
|
|
26
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
27
|
+
const part = ids.slice(i, i + CHUNK);
|
|
28
|
+
const rows = await q.query(`SELECT trace_id, json FROM ${table} WHERE project_id = $1 AND trace_id = ANY($2)`, [
|
|
29
|
+
projectId,
|
|
30
|
+
part,
|
|
31
|
+
]);
|
|
32
|
+
for (const r of rows) {
|
|
33
|
+
const list = out.get(r.trace_id);
|
|
34
|
+
if (list)
|
|
35
|
+
list.push(r.json);
|
|
36
|
+
else
|
|
37
|
+
out.set(r.trace_id, [r.json]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
/** Full traces, in the order of `ids`. */
|
|
43
|
+
export async function loadTraces(q, projectId, ids) {
|
|
44
|
+
if (ids.length === 0)
|
|
45
|
+
return [];
|
|
46
|
+
const spans = await jsonByTrace(q, "spans", projectId, ids);
|
|
47
|
+
const logs = await jsonByTrace(q, "logs", projectId, ids);
|
|
48
|
+
return ids.map((id) => {
|
|
49
|
+
const s = (spans.get(id) ?? []).map((j) => JSON.parse(j));
|
|
50
|
+
const l = (logs.get(id) ?? []).map((j) => JSON.parse(j)).sort((a, b) => a.timeMs - b.timeMs);
|
|
51
|
+
return buildTrace(id, s, l, []);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export const queryTraces = async (q, t) => loadTraces(q, t.projectId, await findTraceIds(q, t));
|
|
55
|
+
export async function getTrace(q, projectId, traceId) {
|
|
56
|
+
const [trace] = await loadTraces(q, projectId, [traceId]);
|
|
57
|
+
return trace && trace.spanCount + trace.logs.length > 0 ? trace : undefined;
|
|
58
|
+
}
|
|
59
|
+
/** How many traces started in [from, to). */
|
|
60
|
+
export async function countTraces(q, projectId, from, to, env) {
|
|
61
|
+
const [row] = await q.query(`SELECT count(*)::int AS n FROM traces WHERE project_id = $1 AND start_ms >= $2 AND start_ms < $3 AND ($4::text = '' OR env = $4::text)`, [projectId, from, to, env ?? ""]);
|
|
62
|
+
return row?.n ?? 0;
|
|
63
|
+
}
|
|
64
|
+
export async function listServices(q, projectId, now) {
|
|
65
|
+
const rows = await q.query("SELECT via, info, first_seen, last_seen FROM services WHERE project_id = $1 ORDER BY last_seen DESC", [projectId]);
|
|
66
|
+
return rows.map((r) => ({ ...JSON.parse(r.info), via: r.via, firstSeenMs: r.first_seen, lastSeenMs: r.last_seen, online: now - r.last_seen <= HUB_ONLINE_MS }));
|
|
67
|
+
}
|
|
68
|
+
export async function environmentsOf(q, projectId) {
|
|
69
|
+
const rows = await q.query("SELECT environment AS e FROM services WHERE project_id = $1 UNION SELECT DISTINCT env FROM traces WHERE project_id = $1", [projectId]);
|
|
70
|
+
return rows.map((r) => r.e).filter(Boolean).sort();
|
|
71
|
+
}
|
|
72
|
+
export async function countRows(q, projectId) {
|
|
73
|
+
const n = async (table) => (await q.query(`SELECT count(*)::int AS n FROM ${table} WHERE project_id = $1`, [projectId]))[0]?.n ?? 0;
|
|
74
|
+
return { traces: await n("traces"), spans: await n("spans") };
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=trace-read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-read.js","sourceRoot":"","sources":["../../src/repo/trace-read.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HubWrite } from "@wizeworks/lens-hub/kit";
|
|
2
|
+
import type { Queryable } from "../db/db.js";
|
|
3
|
+
/** Save one batch for one project, in the caller's transaction. */
|
|
4
|
+
export declare function writeBatch(q: Queryable, projectId: string, w: HubWrite, now: number): Promise<void>;
|
|
5
|
+
/** Drop metric points older than each organization's retention. */
|
|
6
|
+
export declare function pruneMetricsByRetention(q: Queryable, now: number): Promise<void>;
|
|
7
|
+
/** Drop traces older than each organization's retention. Returns how many traces were dropped. */
|
|
8
|
+
export declare function pruneByRetention(q: Queryable, now: number): Promise<number>;
|
|
9
|
+
//# sourceMappingURL=trace-write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-write.d.ts","sourceRoot":"","sources":["../../src/repo/trace-write.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAM,SAAS,EAAE,MAAM,aAAa,CAAC;AAoCjD,mEAAmE;AACnE,wBAAsB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBzG;AASD,mEAAmE;AACnE,wBAAsB,uBAAuB,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOtF;AAED,kGAAkG;AAClG,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAejF"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { ATTR_BROWSER_SESSION, logKey, PG_DIALECT, pruneStatements, seriesKeyOf } from "@wizeworks/lens-core";
|
|
3
|
+
import { runStatements, stateOf } from "../settle.js";
|
|
4
|
+
import { pruneMetricRollups, writeMetricRollups } from "./metric-write.js";
|
|
5
|
+
const CHUNK = 200;
|
|
6
|
+
/** `INSERT ... VALUES ($1, $2), ($3, $4) ... <tail>` for many rows at once. */
|
|
7
|
+
async function insertMany(q, head, rows, tail) {
|
|
8
|
+
for (let i = 0; i < rows.length; i += CHUNK) {
|
|
9
|
+
const part = rows.slice(i, i + CHUNK);
|
|
10
|
+
const width = part[0].length;
|
|
11
|
+
const values = part.map((_, r) => `(${Array.from({ length: width }, (_, c) => `$${r * width + c + 1}`).join(", ")})`);
|
|
12
|
+
await q.query(`${head} VALUES ${values.join(", ")} ${tail}`, part.flat());
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const sha1 = (text) => createHash("sha1").update(text).digest("hex");
|
|
16
|
+
const sessionOf = (s) => {
|
|
17
|
+
const v = s.attributes[ATTR_BROWSER_SESSION];
|
|
18
|
+
return typeof v === "string" && v ? v : null;
|
|
19
|
+
};
|
|
20
|
+
/** Trace rows: one per trace id, with the earliest start and latest end in this batch. */
|
|
21
|
+
function traceRows(w, projectId, now) {
|
|
22
|
+
const bounds = new Map();
|
|
23
|
+
const touch = (id, start, end) => {
|
|
24
|
+
const b = bounds.get(id);
|
|
25
|
+
bounds.set(id, b ? [Math.min(b[0], start), Math.max(b[1], end)] : [start, end]);
|
|
26
|
+
};
|
|
27
|
+
for (const s of w.spans)
|
|
28
|
+
touch(s.traceId, s.startMs, s.startMs + s.durationMs);
|
|
29
|
+
for (const { traceId, log } of w.logs)
|
|
30
|
+
touch(traceId, log.timeMs, log.timeMs);
|
|
31
|
+
const env = w.sender.environment ?? "";
|
|
32
|
+
return [...bounds].map(([id, [start, end]]) => [projectId, id, start, end, now, env]);
|
|
33
|
+
}
|
|
34
|
+
/** Save one batch for one project, in the caller's transaction. */
|
|
35
|
+
export async function writeBatch(q, projectId, w, now) {
|
|
36
|
+
const s = w.sender;
|
|
37
|
+
await q.query(`INSERT INTO services (project_id, service, environment, host, via, info, first_seen, last_seen) VALUES ($1, $2, $3, $4, $5, $6, $7, $7)
|
|
38
|
+
ON CONFLICT (project_id, service, environment, host) DO UPDATE SET via = EXCLUDED.via, info = EXCLUDED.info, last_seen = EXCLUDED.last_seen`, [projectId, s.service, s.environment ?? "", s.host ?? "", w.via, JSON.stringify(s), now]);
|
|
39
|
+
await insertMany(q, "INSERT INTO traces (project_id, trace_id, start_ms, end_ms, updated_ms, env)", traceRows(w, projectId, now), `
|
|
40
|
+
ON CONFLICT (project_id, trace_id) DO UPDATE SET start_ms = LEAST(traces.start_ms, EXCLUDED.start_ms),
|
|
41
|
+
end_ms = GREATEST(traces.end_ms, EXCLUDED.end_ms), updated_ms = EXCLUDED.updated_ms,
|
|
42
|
+
env = CASE WHEN traces.env = '' THEN EXCLUDED.env ELSE traces.env END`);
|
|
43
|
+
const spans = dedupe(w.spans, (x) => x.traceId + x.spanId).map((x) => [projectId, x.traceId, x.spanId, x.service, x.startMs, x.durationMs, sessionOf(x), JSON.stringify(x)]);
|
|
44
|
+
await insertMany(q, "INSERT INTO spans (project_id, trace_id, span_id, service, start_ms, duration_ms, session, json)", spans, `
|
|
45
|
+
ON CONFLICT (project_id, trace_id, span_id) DO UPDATE SET json = EXCLUDED.json, duration_ms = EXCLUDED.duration_ms`);
|
|
46
|
+
const logs = dedupe(w.logs.map(({ traceId, log }) => ({ traceId, log, key: createHash("sha1").update(logKey(log)).digest("hex") })), (l) => l.traceId + l.key).map((l) => [projectId, l.traceId, l.key, l.log.timeMs, JSON.stringify(l.log)]);
|
|
47
|
+
await insertMany(q, "INSERT INTO logs (project_id, trace_id, key, time_ms, json)", logs, "ON CONFLICT DO NOTHING");
|
|
48
|
+
const env = s.environment ?? "";
|
|
49
|
+
// The series key holds NUL separators, which Postgres text cannot store, so keep its hash.
|
|
50
|
+
const metrics = (w.metrics ?? []).map((p) => [projectId, p.timeMs, env, p.service, p.name, sha1(seriesKeyOf(p)), JSON.stringify(p)]);
|
|
51
|
+
await insertMany(q, "INSERT INTO metric_points (project_id, time_ms, env, service, name, series_key, json)", metrics, "");
|
|
52
|
+
await writeMetricRollups(q, projectId, env, w.metrics ?? [], now);
|
|
53
|
+
}
|
|
54
|
+
/** Postgres rejects one statement that updates the same row twice, so keep the last of each key. */
|
|
55
|
+
function dedupe(items, key) {
|
|
56
|
+
const map = new Map();
|
|
57
|
+
for (const t of items)
|
|
58
|
+
map.set(key(t), t);
|
|
59
|
+
return [...map.values()];
|
|
60
|
+
}
|
|
61
|
+
/** Drop metric points older than each organization's retention. */
|
|
62
|
+
export async function pruneMetricsByRetention(q, now) {
|
|
63
|
+
await q.query(`DELETE FROM metric_points m USING projects p, orgs o WHERE p.id = m.project_id AND o.id = p.org_id
|
|
64
|
+
AND m.time_ms < $1 - o.retention_days * 86400000.0`, [now]);
|
|
65
|
+
await pruneMetricRollups(q, now);
|
|
66
|
+
}
|
|
67
|
+
/** Drop traces older than each organization's retention. Returns how many traces were dropped. */
|
|
68
|
+
export async function pruneByRetention(q, now) {
|
|
69
|
+
const prune = async (x) => {
|
|
70
|
+
const doomed = await x.query(`SELECT t.project_id, t.trace_id, t.env, t.contrib, o.retention_days FROM traces t JOIN projects p ON p.id = t.project_id JOIN orgs o ON o.id = p.org_id
|
|
71
|
+
WHERE t.start_ms < $1 - o.retention_days * 86400000.0 LIMIT 5000`, [now]);
|
|
72
|
+
// Take their contributions out of the rollups and drop their facts first.
|
|
73
|
+
await runStatements(x, pruneStatements(PG_DIALECT, doomed.map((d) => stateOf(d, d.retention_days ?? 30)), now, true));
|
|
74
|
+
for (const table of ["spans", "logs", "traces"]) {
|
|
75
|
+
for (const d of doomed)
|
|
76
|
+
await x.query(`DELETE FROM ${table} WHERE project_id = $1 AND trace_id = $2`, [d.project_id, d.trace_id]);
|
|
77
|
+
}
|
|
78
|
+
return doomed.length;
|
|
79
|
+
};
|
|
80
|
+
return "tx" in q ? q.tx(prune) : prune(q);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=trace-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-write.js","sourceRoot":"","sources":["../../src/repo/trace-write.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Queryable } from "../db/db.js";
|
|
2
|
+
export interface User {
|
|
3
|
+
id: string;
|
|
4
|
+
email: string;
|
|
5
|
+
name: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const normalizeEmail: (email: string) => string;
|
|
8
|
+
/** Check sign-up input. Returns an error message, or null when it is fine. */
|
|
9
|
+
export declare function signUpProblem(email: string, password: string, name: string): string | null;
|
|
10
|
+
export declare function userCount(q: Queryable): Promise<number>;
|
|
11
|
+
export declare function createUser(q: Queryable, email: string, password: string, name: string, now: number): Promise<User>;
|
|
12
|
+
export declare function userByEmail(q: Queryable, email: string): Promise<User | undefined>;
|
|
13
|
+
/** The user when the email and password match. Takes the same time when the email is unknown. */
|
|
14
|
+
export declare function verifyLogin(q: Queryable, email: string, password: string): Promise<User | undefined>;
|
|
15
|
+
export declare function setPassword(q: Queryable, userId: string, password: string): Promise<void>;
|
|
16
|
+
/** A new session. Returns the token for the cookie; only its hash is stored. */
|
|
17
|
+
export declare function createSession(q: Queryable, userId: string, now: number): Promise<{
|
|
18
|
+
token: string;
|
|
19
|
+
expiresMs: number;
|
|
20
|
+
}>;
|
|
21
|
+
export declare function userBySession(q: Queryable, token: string, now: number): Promise<User | undefined>;
|
|
22
|
+
export declare function endSession(q: Queryable, token: string): Promise<void>;
|
|
23
|
+
export declare function pruneSessions(q: Queryable, now: number): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=users.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/repo/users.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,eAAO,MAAM,cAAc,UAAW,MAAM,KAAG,MAAoC,CAAC;AAGpF,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM1F;AAED,wBAAsB,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7D;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUxH;AAED,wBAAsB,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAGxF;AAED,iGAAiG;AACjG,wBAAsB,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAM1G;AAED,wBAAsB,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG/F;AAED,gFAAgF;AAChF,wBAAsB,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAK5H;AAED,wBAAsB,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAMvG;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E;AAED,wBAAsB,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { checkPassword, hashPassword, hashToken, newId, newToken } from "../auth/crypto.js";
|
|
2
|
+
const SESSION_MS = 30 * 24 * 60 * 60_000;
|
|
3
|
+
export const normalizeEmail = (email) => email.trim().toLowerCase();
|
|
4
|
+
const isEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) && email.length <= 200;
|
|
5
|
+
/** Check sign-up input. Returns an error message, or null when it is fine. */
|
|
6
|
+
export function signUpProblem(email, password, name) {
|
|
7
|
+
if (!isEmail(normalizeEmail(email)))
|
|
8
|
+
return "Enter a valid email address.";
|
|
9
|
+
if (password.length < 10)
|
|
10
|
+
return "Use a password of at least 10 characters.";
|
|
11
|
+
if (password.length > 200)
|
|
12
|
+
return "Use a password of at most 200 characters.";
|
|
13
|
+
if (!name.trim() || name.length > 100)
|
|
14
|
+
return "Enter your name (at most 100 characters).";
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
export async function userCount(q) {
|
|
18
|
+
const [row] = await q.query("SELECT count(*)::int AS n FROM users");
|
|
19
|
+
return row?.n ?? 0;
|
|
20
|
+
}
|
|
21
|
+
export async function createUser(q, email, password, name, now) {
|
|
22
|
+
const user = { id: newId(), email: normalizeEmail(email), name: name.trim() };
|
|
23
|
+
await q.query("INSERT INTO users (id, email, name, password_hash, created_ms) VALUES ($1, $2, $3, $4, $5)", [
|
|
24
|
+
user.id,
|
|
25
|
+
user.email,
|
|
26
|
+
user.name,
|
|
27
|
+
await hashPassword(password),
|
|
28
|
+
now,
|
|
29
|
+
]);
|
|
30
|
+
return user;
|
|
31
|
+
}
|
|
32
|
+
export async function userByEmail(q, email) {
|
|
33
|
+
const [row] = await q.query("SELECT id, email, name FROM users WHERE email = $1", [normalizeEmail(email)]);
|
|
34
|
+
return row;
|
|
35
|
+
}
|
|
36
|
+
/** The user when the email and password match. Takes the same time when the email is unknown. */
|
|
37
|
+
export async function verifyLogin(q, email, password) {
|
|
38
|
+
const [row] = await q.query("SELECT id, email, name, password_hash FROM users WHERE email = $1", [
|
|
39
|
+
normalizeEmail(email),
|
|
40
|
+
]);
|
|
41
|
+
const ok = await checkPassword(password, row?.password_hash ?? "scrypt$AAAAAAAAAAAAAAAAAAAAAA$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
|
|
42
|
+
return row && ok ? { id: row.id, email: row.email, name: row.name } : undefined;
|
|
43
|
+
}
|
|
44
|
+
export async function setPassword(q, userId, password) {
|
|
45
|
+
await q.query("UPDATE users SET password_hash = $1 WHERE id = $2", [await hashPassword(password), userId]);
|
|
46
|
+
await q.query("DELETE FROM sessions WHERE user_id = $1", [userId]);
|
|
47
|
+
}
|
|
48
|
+
/** A new session. Returns the token for the cookie; only its hash is stored. */
|
|
49
|
+
export async function createSession(q, userId, now) {
|
|
50
|
+
const token = newToken("session");
|
|
51
|
+
const expiresMs = now + SESSION_MS;
|
|
52
|
+
await q.query("INSERT INTO sessions (token_hash, user_id, created_ms, expires_ms) VALUES ($1, $2, $3, $4)", [hashToken(token), userId, now, expiresMs]);
|
|
53
|
+
return { token, expiresMs };
|
|
54
|
+
}
|
|
55
|
+
export async function userBySession(q, token, now) {
|
|
56
|
+
const [row] = await q.query(`SELECT u.id, u.email, u.name FROM sessions s JOIN users u ON u.id = s.user_id WHERE s.token_hash = $1 AND s.expires_ms > $2`, [hashToken(token), now]);
|
|
57
|
+
return row;
|
|
58
|
+
}
|
|
59
|
+
export async function endSession(q, token) {
|
|
60
|
+
await q.query("DELETE FROM sessions WHERE token_hash = $1", [hashToken(token)]);
|
|
61
|
+
}
|
|
62
|
+
export async function pruneSessions(q, now) {
|
|
63
|
+
await q.query("DELETE FROM sessions WHERE expires_ms <= $1", [now]);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=users.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"users.js","sourceRoot":"","sources":["../../src/repo/users.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAS5F,MAAM,UAAU,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACpF,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC;AAEnG,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,QAAgB,EAAE,IAAY;IACzE,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAAE,OAAO,8BAA8B,CAAC;IAC3E,IAAI,QAAQ,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,2CAA2C,CAAC;IAC7E,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,2CAA2C,CAAC;IAC9E,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,2CAA2C,CAAC;IAC1F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,CAAY;IAC1C,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CAAgB,sCAAsC,CAAC,CAAC;IACnF,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,CAAY,EAAE,KAAa,EAAE,QAAgB,EAAE,IAAY,EAAE,GAAW;IACvG,MAAM,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;IAC9E,MAAM,CAAC,CAAC,KAAK,CAAC,4FAA4F,EAAE;QAC1G,IAAI,CAAC,EAAE;QACP,IAAI,CAAC,KAAK;QACV,IAAI,CAAC,IAAI;QACT,MAAM,YAAY,CAAC,QAAQ,CAAC;QAC5B,GAAG;KACJ,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,CAAY,EAAE,KAAa;IAC3D,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CAAO,oDAAoD,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjH,OAAO,GAAG,CAAC;AACb,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,CAAY,EAAE,KAAa,EAAE,QAAgB;IAC7E,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CAAmC,mEAAmE,EAAE;QACjI,cAAc,CAAC,KAAK,CAAC;KACtB,CAAC,CAAC;IACH,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,GAAG,EAAE,aAAa,IAAI,2EAA2E,CAAC,CAAC;IAC5I,OAAO,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAClF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,CAAY,EAAE,MAAc,EAAE,QAAgB;IAC9E,MAAM,CAAC,CAAC,KAAK,CAAC,mDAAmD,EAAE,CAAC,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3G,MAAM,CAAC,CAAC,KAAK,CAAC,yCAAyC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,CAAY,EAAE,MAAc,EAAE,GAAW;IAC3E,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,GAAG,GAAG,UAAU,CAAC;IACnC,MAAM,CAAC,CAAC,KAAK,CAAC,4FAA4F,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC;IACxJ,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,CAAY,EAAE,KAAa,EAAE,GAAW;IAC1E,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CACzB,6HAA6H,EAC7H,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CACxB,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,CAAY,EAAE,KAAa;IAC1D,MAAM,CAAC,CAAC,KAAK,CAAC,4CAA4C,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,CAAY,EAAE,GAAW;IAC3D,MAAM,CAAC,CAAC,KAAK,CAAC,6CAA6C,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../../src/routes/alerts.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAsFhD,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAMhD"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { isAlertMetric, isMetricAlertStat, MAX_METRIC_NAME } from "@wizeworks/lens-core";
|
|
2
|
+
import { notify } from "../alerts/evaluate.js";
|
|
3
|
+
import { checkTarget } from "../alerts/notify.js";
|
|
4
|
+
import { requireProject } from "../auth/principal.js";
|
|
5
|
+
import { fail, readJsonBody, sendJson, str } from "../http/http.js";
|
|
6
|
+
import { createRule, deleteRule, listEvents, listRules, ruleById, updateRule } from "../repo/alerts.js";
|
|
7
|
+
const WINDOWS = [5, 15, 60, 360, 1440].map((m) => m * 60_000);
|
|
8
|
+
const MAX_CHANNELS = 5;
|
|
9
|
+
async function channelsOf(ctx, raw) {
|
|
10
|
+
const list = Array.isArray(raw) ? raw.slice(0, MAX_CHANNELS) : [];
|
|
11
|
+
const out = [];
|
|
12
|
+
for (const c of list) {
|
|
13
|
+
if ((c.kind !== "webhook" && c.kind !== "slack") || typeof c.url !== "string")
|
|
14
|
+
return fail(400, "Each channel needs kind (webhook or slack) and url.");
|
|
15
|
+
const problem = await checkTarget(c.url, ctx.app.config.allowPrivateWebhooks);
|
|
16
|
+
if (problem)
|
|
17
|
+
fail(400, `${c.url}: ${problem}`);
|
|
18
|
+
out.push({ kind: c.kind, url: c.url });
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
/** The metric part of a rule: for "metric" rules, the OpenTelemetry metric to read. */
|
|
23
|
+
function metricPart(b) {
|
|
24
|
+
if (b.metric !== "metric") {
|
|
25
|
+
if (!isAlertMetric(b.metric))
|
|
26
|
+
fail(400, "Pick a metric: error_rate, p95_ms, avg_ms, requests, new_errors, slow_queries, or metric.");
|
|
27
|
+
return { metric: b.metric, metricName: "", metricStat: "", metricService: "" };
|
|
28
|
+
}
|
|
29
|
+
const name = typeof b.metricName === "string" ? b.metricName.trim() : "";
|
|
30
|
+
if (!name || name.length > MAX_METRIC_NAME)
|
|
31
|
+
fail(400, "Set metricName to the metric to watch, for example process.cpu.utilization.");
|
|
32
|
+
const stat = b.metricStat ?? "avg";
|
|
33
|
+
if (!isMetricAlertStat(stat))
|
|
34
|
+
fail(400, "Pick a metricStat: last, avg, max, p95, p99, or rate.");
|
|
35
|
+
const service = typeof b.metricService === "string" ? b.metricService.trim().slice(0, 100) : "";
|
|
36
|
+
return { metric: "metric", metricName: name, metricStat: stat, metricService: service };
|
|
37
|
+
}
|
|
38
|
+
/** Check a rule from the request body. A change sends only what it changes: the rest comes from `current`. */
|
|
39
|
+
async function ruleInput(ctx, current) {
|
|
40
|
+
const b = { ...current, ...(await readJsonBody(ctx.req)) };
|
|
41
|
+
const metric = metricPart(b);
|
|
42
|
+
if (b.op !== ">" && b.op !== "<")
|
|
43
|
+
fail(400, 'Set op to ">" or "<".');
|
|
44
|
+
const threshold = Number(b.threshold);
|
|
45
|
+
if (!Number.isFinite(threshold))
|
|
46
|
+
fail(400, "Set a number for threshold.");
|
|
47
|
+
const windowMs = Number(b.windowMs ?? 5 * 60_000);
|
|
48
|
+
if (!WINDOWS.includes(windowMs))
|
|
49
|
+
fail(400, "Pick a window of 5, 15, 60, 360, or 1440 minutes.");
|
|
50
|
+
return {
|
|
51
|
+
name: str(b, "name").slice(0, 100),
|
|
52
|
+
...metric,
|
|
53
|
+
op: b.op,
|
|
54
|
+
threshold,
|
|
55
|
+
windowMs,
|
|
56
|
+
env: typeof b.env === "string" ? b.env.slice(0, 50) : "",
|
|
57
|
+
channels: await channelsOf(ctx, b.channels),
|
|
58
|
+
enabled: b.enabled !== false,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async function list(ctx) {
|
|
62
|
+
const { project } = await requireProject(ctx, ctx.params.project);
|
|
63
|
+
sendJson(ctx.res, 200, { rules: await listRules(ctx.app.db, project.id), events: await listEvents(ctx.app.db, project.id, 100) });
|
|
64
|
+
}
|
|
65
|
+
async function create(ctx) {
|
|
66
|
+
const { project, actor } = await requireProject(ctx, ctx.params.project, "write");
|
|
67
|
+
const id = await createRule(ctx.app.db, project.id, await ruleInput(ctx), actor, ctx.app.config.now());
|
|
68
|
+
sendJson(ctx.res, 201, await ruleById(ctx.app.db, project.id, id));
|
|
69
|
+
}
|
|
70
|
+
async function change(ctx) {
|
|
71
|
+
const { project } = await requireProject(ctx, ctx.params.project, "write");
|
|
72
|
+
const current = await ruleById(ctx.app.db, project.id, ctx.params.id);
|
|
73
|
+
if (!current)
|
|
74
|
+
fail(404, "Alert rule not found.");
|
|
75
|
+
await updateRule(ctx.app.db, project.id, ctx.params.id, await ruleInput(ctx, current));
|
|
76
|
+
sendJson(ctx.res, 200, await ruleById(ctx.app.db, project.id, ctx.params.id));
|
|
77
|
+
}
|
|
78
|
+
async function remove(ctx) {
|
|
79
|
+
const { project } = await requireProject(ctx, ctx.params.project, "write");
|
|
80
|
+
if (!(await deleteRule(ctx.app.db, project.id, ctx.params.id)))
|
|
81
|
+
fail(404, "Alert rule not found.");
|
|
82
|
+
sendJson(ctx.res, 200, { ok: true });
|
|
83
|
+
}
|
|
84
|
+
/** Send a test notice through the rule's channels now. */
|
|
85
|
+
async function test(ctx) {
|
|
86
|
+
const { project } = await requireProject(ctx, ctx.params.project, "write");
|
|
87
|
+
const rule = await ruleById(ctx.app.db, project.id, ctx.params.id);
|
|
88
|
+
if (!rule)
|
|
89
|
+
return fail(404, "Alert rule not found.");
|
|
90
|
+
sendJson(ctx.res, 200, { delivery: await notify(ctx.app, rule, "test", rule.lastValue, ctx.app.config.now()) });
|
|
91
|
+
}
|
|
92
|
+
export function alertRoutes(r) {
|
|
93
|
+
r.on("GET", "api/projects/:project/alerts", list)
|
|
94
|
+
.on("POST", "api/projects/:project/alerts", create)
|
|
95
|
+
.on("PATCH", "api/projects/:project/alerts/:id", change)
|
|
96
|
+
.on("DELETE", "api/projects/:project/alerts/:id", remove)
|
|
97
|
+
.on("POST", "api/projects/:project/alerts/:id/test", test);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=alerts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alerts.js","sourceRoot":"","sources":["../../src/routes/alerts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/routes/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AA8FhD,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAQ/C"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { principalOf, requireUser, SESSION_COOKIE } from "../auth/principal.js";
|
|
2
|
+
import { cookie, cookieOf, fail, readJsonBody, sendJson, str } from "../http/http.js";
|
|
3
|
+
import { audit } from "../repo/audit.js";
|
|
4
|
+
import { acceptInvite, createOrg, openInvite, orgsOfUser } from "../repo/orgs.js";
|
|
5
|
+
import { createProject, listProjects } from "../repo/projects.js";
|
|
6
|
+
import { createSession, createUser, endSession, signUpProblem, userByEmail, userCount, verifyLogin } from "../repo/users.js";
|
|
7
|
+
const MAX_AGE_S = 30 * 24 * 60 * 60;
|
|
8
|
+
async function signIn(ctx, user, status = 200) {
|
|
9
|
+
const { token } = await createSession(ctx.app.db, user.id, ctx.app.config.now());
|
|
10
|
+
const set = cookie(SESSION_COOKIE, token, MAX_AGE_S, ctx.app.config.secureCookies);
|
|
11
|
+
sendJson(ctx.res, status, { user }, { "Set-Cookie": set });
|
|
12
|
+
}
|
|
13
|
+
/** The signed-in person with their organizations and each one's projects. */
|
|
14
|
+
async function meOf(ctx, user) {
|
|
15
|
+
const orgs = await orgsOfUser(ctx.app.db, user.id);
|
|
16
|
+
const withProjects = await Promise.all(orgs.map(async (o) => ({ ...o, projects: await listProjects(ctx.app.db, o.id) })));
|
|
17
|
+
return { user, orgs: withProjects };
|
|
18
|
+
}
|
|
19
|
+
async function state(ctx) {
|
|
20
|
+
const p = await principalOf(ctx);
|
|
21
|
+
const needsSetup = (await userCount(ctx.app.db)) === 0;
|
|
22
|
+
const me = p?.kind === "user" ? await meOf(ctx, p.user) : null;
|
|
23
|
+
sendJson(ctx.res, 200, { signedIn: !!me, needsSetup, signup: ctx.app.config.signup, ...(me ?? {}) });
|
|
24
|
+
}
|
|
25
|
+
/** The first account: creates the person, their organization, and a first project. Only while no account exists. */
|
|
26
|
+
async function setup(ctx) {
|
|
27
|
+
const body = await readJsonBody(ctx.req);
|
|
28
|
+
const [email, password, name] = [str(body, "email"), str(body, "password"), str(body, "name")];
|
|
29
|
+
const problem = signUpProblem(email, password, name);
|
|
30
|
+
if (problem)
|
|
31
|
+
fail(400, problem);
|
|
32
|
+
const now = ctx.app.config.now();
|
|
33
|
+
const user = await ctx.app.db.tx(async (q) => {
|
|
34
|
+
if ((await userCount(q)) > 0)
|
|
35
|
+
fail(409, "Setup is already done. Sign in instead.");
|
|
36
|
+
const u = await createUser(q, email, password, name, now);
|
|
37
|
+
const org = await createOrg(q, str(body, "orgName", false) || `${name.trim()}'s team`, u.id, now, ctx.app.config.retentionDays);
|
|
38
|
+
await createProject(q, org.id, str(body, "projectName", false) || "My app", now);
|
|
39
|
+
await audit(q, org.id, `user:${u.id}`, "org.create", { name: org.name }, now);
|
|
40
|
+
return u;
|
|
41
|
+
});
|
|
42
|
+
await signIn(ctx, user, 201);
|
|
43
|
+
}
|
|
44
|
+
/** A new account. Needs an invite, unless sign-up is open (then it gets its own organization). */
|
|
45
|
+
async function signup(ctx) {
|
|
46
|
+
const body = await readJsonBody(ctx.req);
|
|
47
|
+
const [email, password, name, invite] = [str(body, "email"), str(body, "password"), str(body, "name"), str(body, "invite", false)];
|
|
48
|
+
const problem = signUpProblem(email, password, name);
|
|
49
|
+
if (problem)
|
|
50
|
+
fail(400, problem);
|
|
51
|
+
const now = ctx.app.config.now();
|
|
52
|
+
if (!invite && ctx.app.config.signup !== "open")
|
|
53
|
+
fail(403, "Sign-up needs an invite link.");
|
|
54
|
+
if (await userByEmail(ctx.app.db, email))
|
|
55
|
+
fail(409, "An account with this email exists. Sign in instead.");
|
|
56
|
+
const user = await ctx.app.db.tx(async (q) => {
|
|
57
|
+
const open = invite ? await openInvite(q, invite, now) : undefined;
|
|
58
|
+
if (invite && !open)
|
|
59
|
+
fail(410, "This invite link is not valid any more.");
|
|
60
|
+
const u = await createUser(q, email, password, name, now);
|
|
61
|
+
if (open)
|
|
62
|
+
await acceptInvite(q, invite, u.id, now);
|
|
63
|
+
else
|
|
64
|
+
await createProject(q, (await createOrg(q, `${name.trim()}'s team`, u.id, now, ctx.app.config.retentionDays)).id, "My app", now);
|
|
65
|
+
return u;
|
|
66
|
+
});
|
|
67
|
+
await signIn(ctx, user, 201);
|
|
68
|
+
}
|
|
69
|
+
async function login(ctx) {
|
|
70
|
+
const body = await readJsonBody(ctx.req);
|
|
71
|
+
const user = await verifyLogin(ctx.app.db, str(body, "email"), str(body, "password"));
|
|
72
|
+
if (!user)
|
|
73
|
+
fail(401, "The email or password is not right.");
|
|
74
|
+
await signIn(ctx, user);
|
|
75
|
+
}
|
|
76
|
+
async function logout(ctx) {
|
|
77
|
+
const token = cookieOf(ctx.req, SESSION_COOKIE);
|
|
78
|
+
if (token)
|
|
79
|
+
await endSession(ctx.app.db, token);
|
|
80
|
+
sendJson(ctx.res, 200, { ok: true }, { "Set-Cookie": cookie(SESSION_COOKIE, "", 0, ctx.app.config.secureCookies) });
|
|
81
|
+
}
|
|
82
|
+
async function showInvite(ctx) {
|
|
83
|
+
const invite = await openInvite(ctx.app.db, ctx.params.token, ctx.app.config.now());
|
|
84
|
+
if (!invite)
|
|
85
|
+
fail(404, "This invite link is not valid any more.");
|
|
86
|
+
sendJson(ctx.res, 200, { orgName: invite.orgName, email: invite.email, role: invite.role });
|
|
87
|
+
}
|
|
88
|
+
/** A signed-in person joins with an invite link. */
|
|
89
|
+
async function joinInvite(ctx) {
|
|
90
|
+
const user = await requireUser(ctx);
|
|
91
|
+
const invite = await acceptInvite(ctx.app.db, ctx.params.token, user.id, ctx.app.config.now());
|
|
92
|
+
if (!invite)
|
|
93
|
+
fail(410, "This invite link is not valid any more.");
|
|
94
|
+
await audit(ctx.app.db, invite.orgId, `user:${user.id}`, "member.join", { role: invite.role }, ctx.app.config.now());
|
|
95
|
+
sendJson(ctx.res, 200, await meOf(ctx, user));
|
|
96
|
+
}
|
|
97
|
+
export function authRoutes(r) {
|
|
98
|
+
r.on("GET", "api/auth/state", state)
|
|
99
|
+
.on("POST", "api/auth/setup", setup)
|
|
100
|
+
.on("POST", "api/auth/signup", signup)
|
|
101
|
+
.on("POST", "api/auth/login", login)
|
|
102
|
+
.on("POST", "api/auth/logout", logout)
|
|
103
|
+
.on("GET", "api/auth/invites/:token", showInvite)
|
|
104
|
+
.on("POST", "api/auth/invites/:token/accept", joinInvite);
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/routes/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtF,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAa,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAExI,MAAM,SAAS,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAEpC,KAAK,UAAU,MAAM,CAAC,GAAQ,EAAE,IAAU,EAAE,MAAM,GAAG,GAAG;IACtD,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACjF,MAAM,GAAG,GAAG,MAAM,CAAC,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IACnF,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,6EAA6E;AAC7E,KAAK,UAAU,IAAI,CAAC,GAAQ,EAAE,IAAU;IACtC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1H,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;AACtC,CAAC;AAED,KAAK,UAAU,KAAK,CAAC,GAAQ;IAC3B,MAAM,CAAC,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,UAAU,GAAG,CAAC,MAAM,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;IACvD,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/D,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AACvG,CAAC;AAED,oHAAoH;AACpH,KAAK,UAAU,KAAK,CAAC,GAAQ;IAC3B,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/F,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACrD,IAAI,OAAO;QAAE,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC3C,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YAAE,IAAI,CAAC,GAAG,EAAE,yCAAyC,CAAC,CAAC;QACnF,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAChI,MAAM,aAAa,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,CAAC,IAAI,QAAQ,EAAE,GAAG,CAAC,CAAC;QACjF,MAAM,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9E,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED,kGAAkG;AAClG,KAAK,UAAU,MAAM,CAAC,GAAQ;IAC5B,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;IACnI,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACrD,IAAI,OAAO;QAAE,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;IACjC,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM;QAAE,IAAI,CAAC,GAAG,EAAE,+BAA+B,CAAC,CAAC;IAC5F,IAAI,MAAM,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,GAAG,EAAE,qDAAqD,CAAC,CAAC;IAC3G,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACnE,IAAI,MAAM,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,GAAG,EAAE,yCAAyC,CAAC,CAAC;QAC1E,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAC1D,IAAI,IAAI;YAAE,MAAM,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;;YAC9C,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,MAAM,SAAS,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;QACtI,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED,KAAK,UAAU,KAAK,CAAC,GAAQ;IAC3B,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;IACtF,IAAI,CAAC,IAAI;QAAE,IAAI,CAAC,GAAG,EAAE,qCAAqC,CAAC,CAAC;IAC5D,MAAM,MAAM,CAAC,GAAG,EAAE,IAAK,CAAC,CAAC;AAC3B,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,GAAQ;IAC5B,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAChD,IAAI,KAAK;QAAE,MAAM,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC/C,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,cAAc,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;AACtH,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,GAAQ;IAChC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,KAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACrF,IAAI,CAAC,MAAM;QAAE,IAAI,CAAC,GAAG,EAAE,yCAAyC,CAAC,CAAC;IAClE,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,MAAO,CAAC,OAAO,EAAE,KAAK,EAAE,MAAO,CAAC,KAAK,EAAE,IAAI,EAAE,MAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AACjG,CAAC;AAED,oDAAoD;AACpD,KAAK,UAAU,UAAU,CAAC,GAAQ;IAChC,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,KAAM,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IAChG,IAAI,CAAC,MAAM;QAAE,IAAI,CAAC,GAAG,EAAE,yCAAyC,CAAC,CAAC;IAClE,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,MAAO,CAAC,KAAK,EAAE,QAAQ,IAAI,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAO,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACvH,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAc;IACvC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,CAAC;SACjC,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,CAAC;SACnC,EAAE,CAAC,MAAM,EAAE,iBAAiB,EAAE,MAAM,CAAC;SACrC,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,CAAC;SACnC,EAAE,CAAC,MAAM,EAAE,iBAAiB,EAAE,MAAM,CAAC;SACrC,EAAE,CAAC,KAAK,EAAE,yBAAyB,EAAE,UAAU,CAAC;SAChD,EAAE,CAAC,MAAM,EAAE,gCAAgC,EAAE,UAAU,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Ctx } from "../app.js";
|
|
2
|
+
import { type ProjectAccess } from "../auth/principal.js";
|
|
3
|
+
import type { Router } from "../http/router.js";
|
|
4
|
+
/** The project named by `?project=`, with access checked. */
|
|
5
|
+
export declare function projectOf(ctx: Ctx): Promise<ProjectAccess>;
|
|
6
|
+
export declare function dataRoutes(r: Router<Ctx>): void;
|
|
7
|
+
//# sourceMappingURL=data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../src/routes/data.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAe,KAAK,aAAa,EAAkB,MAAM,sBAAsB,CAAC;AAEvF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAOhD,6DAA6D;AAC7D,wBAAsB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,CAIhE;AA0DD,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAK/C"}
|