@wizeworks/lens-cloud 0.0.0-stage → 0.3.0-alpha.2
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 +115 -2
- package/dist/alerts/evaluate.d.ts +10 -0
- package/dist/alerts/evaluate.d.ts.map +1 -0
- package/dist/alerts/evaluate.js +81 -0
- package/dist/alerts/evaluate.js.map +1 -0
- package/dist/alerts/notify.d.ts +28 -0
- package/dist/alerts/notify.d.ts.map +1 -0
- package/dist/alerts/notify.js +52 -0
- package/dist/alerts/notify.js.map +1 -0
- package/dist/app.d.ts +26 -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/auth.d.ts +51 -0
- package/dist/auth/auth.d.ts.map +1 -0
- package/dist/auth/auth.js +63 -0
- package/dist/auth/auth.js.map +1 -0
- package/dist/auth/bridge.d.ts +7 -0
- package/dist/auth/bridge.d.ts.map +1 -0
- package/dist/auth/bridge.js +39 -0
- package/dist/auth/bridge.js.map +1 -0
- package/dist/auth/crypto.d.ts +14 -0
- package/dist/auth/crypto.d.ts.map +1 -0
- package/dist/auth/crypto.js +16 -0
- package/dist/auth/crypto.js.map +1 -0
- package/dist/auth/delete-user.d.ts +16 -0
- package/dist/auth/delete-user.d.ts.map +1 -0
- package/dist/auth/delete-user.js +21 -0
- package/dist/auth/delete-user.js.map +1 -0
- package/dist/auth/deps.d.ts +27 -0
- package/dist/auth/deps.d.ts.map +1 -0
- package/dist/auth/deps.js +3 -0
- package/dist/auth/deps.js.map +1 -0
- package/dist/auth/email-token.d.ts +8 -0
- package/dist/auth/email-token.d.ts.map +1 -0
- package/dist/auth/email-token.js +15 -0
- package/dist/auth/email-token.js.map +1 -0
- package/dist/auth/hooks.d.ts +4 -0
- package/dist/auth/hooks.d.ts.map +1 -0
- package/dist/auth/hooks.js +143 -0
- package/dist/auth/hooks.js.map +1 -0
- package/dist/auth/options.d.ts +17 -0
- package/dist/auth/options.d.ts.map +1 -0
- package/dist/auth/options.js +98 -0
- package/dist/auth/options.js.map +1 -0
- package/dist/auth/password.d.ts +10 -0
- package/dist/auth/password.d.ts.map +1 -0
- package/dist/auth/password.js +22 -0
- package/dist/auth/password.js.map +1 -0
- package/dist/auth/plugins.d.ts +4 -0
- package/dist/auth/plugins.d.ts.map +1 -0
- package/dist/auth/plugins.js +45 -0
- package/dist/auth/plugins.js.map +1 -0
- package/dist/auth/principal.d.ts +38 -0
- package/dist/auth/principal.d.ts.map +1 -0
- package/dist/auth/principal.js +69 -0
- package/dist/auth/principal.js.map +1 -0
- package/dist/auth/roles.d.ts +50 -0
- package/dist/auth/roles.d.ts.map +1 -0
- package/dist/auth/roles.js +18 -0
- package/dist/auth/roles.js.map +1 -0
- package/dist/auth/schema-names.d.ts +130 -0
- package/dist/auth/schema-names.d.ts.map +1 -0
- package/dist/auth/schema-names.js +53 -0
- package/dist/auth/schema-names.js.map +1 -0
- package/dist/auth/secret.d.ts +12 -0
- package/dist/auth/secret.d.ts.map +1 -0
- package/dist/auth/secret.js +32 -0
- package/dist/auth/secret.js.map +1 -0
- package/dist/auth/security-notices.d.ts +34 -0
- package/dist/auth/security-notices.d.ts.map +1 -0
- package/dist/auth/security-notices.js +81 -0
- package/dist/auth/security-notices.js.map +1 -0
- package/dist/auth/signup.d.ts +23 -0
- package/dist/auth/signup.d.ts.map +1 -0
- package/dist/auth/signup.js +61 -0
- package/dist/auth/signup.js.map +1 -0
- package/dist/auth/sso.d.ts +21 -0
- package/dist/auth/sso.d.ts.map +1 -0
- package/dist/auth/sso.js +35 -0
- package/dist/auth/sso.js.map +1 -0
- package/dist/auth/wire.d.ts +16 -0
- package/dist/auth/wire.d.ts.map +1 -0
- package/dist/auth/wire.js +47 -0
- package/dist/auth/wire.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 +86 -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 +44 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +55 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +55 -0
- package/dist/config.js.map +1 -0
- package/dist/db/db.d.ts +22 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +64 -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 +35 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/schema-auth.d.ts +2 -0
- package/dist/db/schema-auth.d.ts.map +1 -0
- package/dist/db/schema-auth.js +93 -0
- package/dist/db/schema-auth.js.map +1 -0
- package/dist/db/schema-mail.d.ts +2 -0
- package/dist/db/schema-mail.d.ts.map +1 -0
- package/dist/db/schema-mail.js +8 -0
- package/dist/db/schema-mail.js.map +1 -0
- package/dist/db/schema-notify.d.ts +2 -0
- package/dist/db/schema-notify.d.ts.map +1 -0
- package/dist/db/schema-notify.js +26 -0
- package/dist/db/schema-notify.js.map +1 -0
- package/dist/db/schema-sso.d.ts +2 -0
- package/dist/db/schema-sso.d.ts.map +1 -0
- package/dist/db/schema-sso.js +17 -0
- package/dist/db/schema-sso.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 +208 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/http/http.d.ts +19 -0
- package/dist/http/http.d.ts.map +1 -0
- package/dist/http/http.js +66 -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 +53 -0
- package/dist/jobs.js.map +1 -0
- package/dist/mail/blocks.d.ts +14 -0
- package/dist/mail/blocks.d.ts.map +1 -0
- package/dist/mail/blocks.js +35 -0
- package/dist/mail/blocks.js.map +1 -0
- package/dist/mail/content.d.ts +68 -0
- package/dist/mail/content.d.ts.map +1 -0
- package/dist/mail/content.js +6 -0
- package/dist/mail/content.js.map +1 -0
- package/dist/mail/emails-digest.d.ts +10 -0
- package/dist/mail/emails-digest.d.ts.map +1 -0
- package/dist/mail/emails-digest.js +55 -0
- package/dist/mail/emails-digest.js.map +1 -0
- package/dist/mail/emails-health.d.ts +6 -0
- package/dist/mail/emails-health.d.ts.map +1 -0
- package/dist/mail/emails-health.js +36 -0
- package/dist/mail/emails-health.js.map +1 -0
- package/dist/mail/emails-security.d.ts +14 -0
- package/dist/mail/emails-security.d.ts.map +1 -0
- package/dist/mail/emails-security.js +27 -0
- package/dist/mail/emails-security.js.map +1 -0
- package/dist/mail/emails-team.d.ts +11 -0
- package/dist/mail/emails-team.d.ts.map +1 -0
- package/dist/mail/emails-team.js +45 -0
- package/dist/mail/emails-team.js.map +1 -0
- package/dist/mail/emails.d.ts +9 -0
- package/dist/mail/emails.d.ts.map +1 -0
- package/dist/mail/emails.js +49 -0
- package/dist/mail/emails.js.map +1 -0
- package/dist/mail/layout.d.ts +6 -0
- package/dist/mail/layout.d.ts.map +1 -0
- package/dist/mail/layout.js +10 -0
- package/dist/mail/layout.js.map +1 -0
- package/dist/mail/mailer.d.ts +25 -0
- package/dist/mail/mailer.d.ts.map +1 -0
- package/dist/mail/mailer.js +49 -0
- package/dist/mail/mailer.js.map +1 -0
- package/dist/mail/preview.d.ts +6 -0
- package/dist/mail/preview.d.ts.map +1 -0
- package/dist/mail/preview.js +26 -0
- package/dist/mail/preview.js.map +1 -0
- package/dist/mail/resend.d.ts +11 -0
- package/dist/mail/resend.d.ts.map +1 -0
- package/dist/mail/resend.js +34 -0
- package/dist/mail/resend.js.map +1 -0
- package/dist/mail/samples.d.ts +3 -0
- package/dist/mail/samples.d.ts.map +1 -0
- package/dist/mail/samples.js +63 -0
- package/dist/mail/samples.js.map +1 -0
- package/dist/mail/stop-route.d.ts +4 -0
- package/dist/mail/stop-route.d.ts.map +1 -0
- package/dist/mail/stop-route.js +41 -0
- package/dist/mail/stop-route.js.map +1 -0
- package/dist/mail/svix.d.ts +8 -0
- package/dist/mail/svix.d.ts.map +1 -0
- package/dist/mail/svix.js +17 -0
- package/dist/mail/svix.js.map +1 -0
- package/dist/mail/templates.d.ts +12 -0
- package/dist/mail/templates.d.ts.map +1 -0
- package/dist/mail/templates.js +18 -0
- package/dist/mail/templates.js.map +1 -0
- package/dist/mail/text.d.ts +4 -0
- package/dist/mail/text.d.ts.map +1 -0
- package/dist/mail/text.js +17 -0
- package/dist/mail/text.js.map +1 -0
- package/dist/mail/theme.d.ts +26 -0
- package/dist/mail/theme.d.ts.map +1 -0
- package/dist/mail/theme.js +21 -0
- package/dist/mail/theme.js.map +1 -0
- package/dist/mail/unsubscribe.d.ts +14 -0
- package/dist/mail/unsubscribe.d.ts.map +1 -0
- package/dist/mail/unsubscribe.js +39 -0
- package/dist/mail/unsubscribe.js.map +1 -0
- package/dist/mail/webhook.d.ts +5 -0
- package/dist/mail/webhook.d.ts.map +1 -0
- package/dist/mail/webhook.js +41 -0
- package/dist/mail/webhook.js.map +1 -0
- package/dist/notify/digest-data.d.ts +31 -0
- package/dist/notify/digest-data.d.ts.map +1 -0
- package/dist/notify/digest-data.js +37 -0
- package/dist/notify/digest-data.js.map +1 -0
- package/dist/notify/digest.d.ts +17 -0
- package/dist/notify/digest.d.ts.map +1 -0
- package/dist/notify/digest.js +76 -0
- package/dist/notify/digest.js.map +1 -0
- package/dist/notify/health.d.ts +6 -0
- package/dist/notify/health.d.ts.map +1 -0
- package/dist/notify/health.js +43 -0
- package/dist/notify/health.js.map +1 -0
- package/dist/notify/team-describe.d.ts +22 -0
- package/dist/notify/team-describe.d.ts.map +1 -0
- package/dist/notify/team-describe.js +67 -0
- package/dist/notify/team-describe.js.map +1 -0
- package/dist/notify/team.d.ts +6 -0
- package/dist/notify/team.d.ts.map +1 -0
- package/dist/notify/team.js +56 -0
- package/dist/notify/team.js.map +1 -0
- package/dist/repo/alerts.d.ts +52 -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/auth-prune.d.ts +4 -0
- package/dist/repo/auth-prune.d.ts.map +1 -0
- package/dist/repo/auth-prune.js +8 -0
- package/dist/repo/auth-prune.js.map +1 -0
- package/dist/repo/mail-prefs.d.ts +35 -0
- package/dist/repo/mail-prefs.d.ts.map +1 -0
- package/dist/repo/mail-prefs.js +34 -0
- package/dist/repo/mail-prefs.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 +37 -0
- package/dist/repo/orgs.d.ts.map +1 -0
- package/dist/repo/orgs.js +33 -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/suppressions.d.ts +8 -0
- package/dist/repo/suppressions.d.ts.map +1 -0
- package/dist/repo/suppressions.js +16 -0
- package/dist/repo/suppressions.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 +13 -0
- package/dist/repo/users.d.ts.map +1 -0
- package/dist/repo/users.js +7 -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 +116 -0
- package/dist/routes/alerts.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 +25 -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/me.d.ts +4 -0
- package/dist/routes/me.d.ts.map +1 -0
- package/dist/routes/me.js +37 -0
- package/dist/routes/me.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/notify.d.ts +4 -0
- package/dist/routes/notify.d.ts.map +1 -0
- package/dist/routes/notify.js +55 -0
- package/dist/routes/notify.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 +73 -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 +55 -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 +15 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +126 -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 +76 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/routes/mcp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AA2ChD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAE9C"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { toSummary } from "@wizeworks/lens-core";
|
|
2
|
+
import { parseJson, readBody } from "@wizeworks/lens-hub/kit";
|
|
3
|
+
import { DEFAULT_N_PLUS_ONE, DEFAULT_SLOW_QUERY_MS, handleMcp } from "@wizeworks/lens-node/kit";
|
|
4
|
+
import { principalOf, requireProject } from "../auth/principal.js";
|
|
5
|
+
import { fail } from "../http/http.js";
|
|
6
|
+
import { audit } from "../repo/audit.js";
|
|
7
|
+
import { getTrace, queryTraces } from "../repo/trace-read.js";
|
|
8
|
+
import { projectMetrics } from "./metrics.js";
|
|
9
|
+
/** Traces the MCP tools search through, newest first. */
|
|
10
|
+
const MCP_RECENT = 500;
|
|
11
|
+
/** The project to read: `?project=`, or the only project of the read key. */
|
|
12
|
+
async function projectId(ctx) {
|
|
13
|
+
const id = ctx.url.searchParams.get("project");
|
|
14
|
+
if (id)
|
|
15
|
+
return id;
|
|
16
|
+
const p = await principalOf(ctx);
|
|
17
|
+
if (p?.kind === "key" && p.key.projectIds.length === 1)
|
|
18
|
+
return p.key.projectIds[0];
|
|
19
|
+
return fail(400, "Add ?project=<project id>. Read keys for one project do not need it.");
|
|
20
|
+
}
|
|
21
|
+
/** `POST /_wizelens/mcp`: the same read-only tools as the add-ons, for one project. Needs a read key: agents get only what it allows. */
|
|
22
|
+
async function mcp(ctx) {
|
|
23
|
+
if ((await principalOf(ctx))?.kind !== "key")
|
|
24
|
+
fail(401, "Send a read key: Authorization: Bearer wl_rk_...");
|
|
25
|
+
const access = await requireProject(ctx, await projectId(ctx));
|
|
26
|
+
const { project, actor } = access;
|
|
27
|
+
const db = ctx.app.db;
|
|
28
|
+
const recent = await queryTraces(db, { projectId: project.id, limit: MCP_RECENT });
|
|
29
|
+
const writes = [];
|
|
30
|
+
const data = {
|
|
31
|
+
service: project.name,
|
|
32
|
+
version: ctx.app.version,
|
|
33
|
+
slowQueryMs: DEFAULT_SLOW_QUERY_MS,
|
|
34
|
+
nPlusOneThreshold: DEFAULT_N_PLUS_ONE,
|
|
35
|
+
list: (limit) => recent.slice(0, limit).map(toSummary),
|
|
36
|
+
all: () => recent,
|
|
37
|
+
get: (traceId) => getTrace(db, project.id, traceId),
|
|
38
|
+
metrics: (range, params) => projectMetrics(db, project.id, range, params, { now: ctx.app.config.now() }),
|
|
39
|
+
// Every tool call is kept in the organization's audit log.
|
|
40
|
+
audit: (line) => void writes.push(audit(db, project.orgId, actor, "mcp.call", { projectId: project.id, line }, ctx.app.config.now())),
|
|
41
|
+
};
|
|
42
|
+
const body = ctx.req.method === "POST" ? parseJson(await readBody(ctx.req)) : undefined;
|
|
43
|
+
await handleMcp(data, ctx.req, ctx.res, body);
|
|
44
|
+
// The audit lines are written before this request is done; a failed write is logged, never lost silently.
|
|
45
|
+
for (const r of await Promise.allSettled(writes))
|
|
46
|
+
if (r.status === "rejected")
|
|
47
|
+
console.error("[wizelens-cloud] audit write failed:", r.reason);
|
|
48
|
+
}
|
|
49
|
+
export function mcpRoutes(r) {
|
|
50
|
+
r.on("POST", "mcp", mcp).on("GET", "mcp", mcp).on("DELETE", "mcp", mcp);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/routes/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"me.d.ts","sourceRoot":"","sources":["../../src/routes/me.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAIrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAqChD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAE7C"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { blockingOrgs, ownedOrgs } from "../auth/delete-user.js";
|
|
2
|
+
import { sessionOf } from "../auth/principal.js";
|
|
3
|
+
import { fail, sendJson } from "../http/http.js";
|
|
4
|
+
import { orgsOfUser } from "../repo/orgs.js";
|
|
5
|
+
import { listProjects } from "../repo/projects.js";
|
|
6
|
+
import { userCount } from "../repo/users.js";
|
|
7
|
+
/** The signed-in person's organizations, each with its projects. */
|
|
8
|
+
async function orgsWithProjects(ctx, userId) {
|
|
9
|
+
const orgs = await orgsOfUser(ctx.app.db, userId);
|
|
10
|
+
return Promise.all(orgs.map(async (o) => ({ ...o, projects: await listProjects(ctx.app.db, o.id) })));
|
|
11
|
+
}
|
|
12
|
+
/** True once any organization has an SSO provider with a proven domain, so the sign-in page offers single sign-on. */
|
|
13
|
+
async function ssoReady(ctx) {
|
|
14
|
+
const [row] = await ctx.app.db.query("SELECT EXISTS (SELECT 1 FROM sso_providers WHERE domain_verified) AS ready");
|
|
15
|
+
return row?.ready === true;
|
|
16
|
+
}
|
|
17
|
+
/** Who is signed in, whether setup is needed, how sign-up works, whether mail goes out, and whether SSO is on. Sign-in itself is Better Auth's (api/auth/). */
|
|
18
|
+
async function me(ctx) {
|
|
19
|
+
const s = await sessionOf(ctx);
|
|
20
|
+
const base = { signedIn: !!s, needsSetup: (await userCount(ctx.app.db)) === 0, signup: ctx.app.config.signup, mail: ctx.app.mailer.live, sso: await ssoReady(ctx) };
|
|
21
|
+
if (!s)
|
|
22
|
+
return sendJson(ctx.res, 200, base);
|
|
23
|
+
const owned = await ownedOrgs(ctx.app.db, s.user.id);
|
|
24
|
+
sendJson(ctx.res, 200, { ...base, user: s.user, sessionId: s.sessionId, orgs: await orgsWithProjects(ctx, s.user.id), blockingOrgs: blockingOrgs(owned).map((o) => o.name) });
|
|
25
|
+
}
|
|
26
|
+
/** Who sent an invite and for which email, so the sign-up form can show it. The id is the link's secret. */
|
|
27
|
+
async function invitePreview(ctx) {
|
|
28
|
+
const [row] = await ctx.app.db.query(`SELECT o.name AS "orgName", i.email, i.role, u.name AS inviter FROM invites i JOIN orgs o ON o.id = i.org_id JOIN users u ON u.id = i.inviter_id
|
|
29
|
+
WHERE i.id = $1 AND i.status = 'pending' AND i.expires_at > now()`, [ctx.params.id]);
|
|
30
|
+
if (!row)
|
|
31
|
+
return fail(404, "This invite link is not valid any more.");
|
|
32
|
+
sendJson(ctx.res, 200, row);
|
|
33
|
+
}
|
|
34
|
+
export function meRoutes(r) {
|
|
35
|
+
r.on("GET", "api/me", me).on("GET", "api/invites/:id", invitePreview);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=me.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"me.js","sourceRoot":"","sources":["../../src/routes/me.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type MetricsModel, type TimeRange } from "@wizeworks/lens-core";
|
|
2
|
+
import type { Ctx } from "../app.js";
|
|
3
|
+
import type { Queryable } from "../db/db.js";
|
|
4
|
+
/** Model parameters from the query: the metric, service, grouping, stat, and search. */
|
|
5
|
+
export declare function metricParamsOf(p: URLSearchParams): Record<string, string>;
|
|
6
|
+
/** The metrics page for one project, from the metric rollup tiers. */
|
|
7
|
+
export declare function projectMetrics(db: Queryable, projectId: string, range: TimeRange, params: Record<string, string>, o: {
|
|
8
|
+
now: number;
|
|
9
|
+
env?: string;
|
|
10
|
+
}): Promise<MetricsModel>;
|
|
11
|
+
/** The range from the query, checked against the organization's retention. */
|
|
12
|
+
export declare function metricRange(ctx: Ctx, retentionDays: number): TimeRange;
|
|
13
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/routes/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,YAAY,EAAkB,KAAK,SAAS,EAAe,MAAM,sBAAsB,CAAC;AACnH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAO7C,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOzE;AAED,sEAAsE;AACtE,wBAAsB,cAAc,CAClC,EAAE,EAAE,SAAS,EACb,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,CAAC,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/B,OAAO,CAAC,YAAY,CAAC,CAEvB;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,GAAG,SAAS,CAKtE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { isTimeRange, metricsModelOf, TIME_RANGES } from "@wizeworks/lens-core";
|
|
2
|
+
import { fail } from "../http/http.js";
|
|
3
|
+
import { loadMetricData } from "../repo/metric-read.js";
|
|
4
|
+
const DAY_MS = 86_400_000;
|
|
5
|
+
const PARAMS = ["metric", "service", "group", "stat", "q"];
|
|
6
|
+
/** Model parameters from the query: the metric, service, grouping, stat, and search. */
|
|
7
|
+
export function metricParamsOf(p) {
|
|
8
|
+
const out = {};
|
|
9
|
+
for (const k of PARAMS) {
|
|
10
|
+
const v = p.get(k);
|
|
11
|
+
if (v)
|
|
12
|
+
out[k] = v.slice(0, 200);
|
|
13
|
+
}
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
/** The metrics page for one project, from the metric rollup tiers. */
|
|
17
|
+
export async function projectMetrics(db, projectId, range, params, o) {
|
|
18
|
+
return metricsModelOf(await loadMetricData(db, { projectId, env: o.env }, range, params, o.now));
|
|
19
|
+
}
|
|
20
|
+
/** The range from the query, checked against the organization's retention. */
|
|
21
|
+
export function metricRange(ctx, retentionDays) {
|
|
22
|
+
const range = ctx.url.searchParams.get("range") ?? "1h";
|
|
23
|
+
if (!isTimeRange(range))
|
|
24
|
+
return fail(400, `Unknown range "${range}".`);
|
|
25
|
+
if (TIME_RANGES[range].ms > retentionDays * DAY_MS)
|
|
26
|
+
fail(400, "This range is longer than the organization keeps data.");
|
|
27
|
+
return range;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/routes/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,cAAc,EAAkB,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnH,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,MAAM,MAAM,GAAG,UAAU,CAAC;AAC1B,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;AAE3D,wFAAwF;AACxF,MAAM,UAAU,cAAc,CAAC,CAAkB;IAC/C,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAa,EACb,SAAiB,EACjB,KAAgB,EAChB,MAA8B,EAC9B,CAAgC;IAEhC,OAAO,cAAc,CAAC,MAAM,cAAc,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACnG,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,WAAW,CAAC,GAAQ,EAAE,aAAqB;IACzD,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IACxD,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,GAAG,EAAE,kBAAkB,KAAK,IAAI,CAAC,CAAC;IACvE,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,aAAa,GAAG,MAAM;QAAE,IAAI,CAAC,GAAG,EAAE,wDAAwD,CAAC,CAAC;IACxH,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/routes/models.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAmEhD,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAEhD"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { alignNow, FACT_SLOW_QUERY_MS, isPageName, isTimeRange, pageContext, runPage, TIME_RANGES } from "@wizeworks/lens-core";
|
|
2
|
+
import { fail, sendJson } from "../http/http.js";
|
|
3
|
+
import { cloudExecutor, cloudSettling } from "../scale-exec.js";
|
|
4
|
+
import { projectOf } from "./data.js";
|
|
5
|
+
import { metricParamsOf, metricRange, projectMetrics } from "./metrics.js";
|
|
6
|
+
const CACHE_MS = 15_000;
|
|
7
|
+
const CACHE_MAX = 500;
|
|
8
|
+
const DAY_MS = 86_400_000;
|
|
9
|
+
const RESERVED = new Set(["project", "range", "env"]);
|
|
10
|
+
const cache = new Map();
|
|
11
|
+
function cached(key, now) {
|
|
12
|
+
const hit = cache.get(key);
|
|
13
|
+
return hit && now - hit.atMs < CACHE_MS ? hit.value : undefined;
|
|
14
|
+
}
|
|
15
|
+
function remember(key, value, now) {
|
|
16
|
+
if (cache.size >= CACHE_MAX)
|
|
17
|
+
cache.delete(cache.keys().next().value);
|
|
18
|
+
cache.set(key, { atMs: now, value });
|
|
19
|
+
}
|
|
20
|
+
/** Model parameters: every query value except the ones that pick the data. */
|
|
21
|
+
const paramsOf = (url) => Object.fromEntries([...url.searchParams].filter(([k]) => !RESERVED.has(k)).sort());
|
|
22
|
+
async function retentionDays(ctx, orgId) {
|
|
23
|
+
const [row] = await ctx.app.db.query("SELECT retention_days AS d FROM orgs WHERE id = $1", [orgId]);
|
|
24
|
+
return row?.d ?? ctx.app.config.retentionDays;
|
|
25
|
+
}
|
|
26
|
+
/** `GET api/models/metrics?project=&range=&env=&metric=&service=&group=&stat=&q=`: the metrics page, from the newest points. */
|
|
27
|
+
async function metrics(ctx) {
|
|
28
|
+
const { project } = await projectOf(ctx);
|
|
29
|
+
const range = metricRange(ctx, await retentionDays(ctx, project.orgId));
|
|
30
|
+
const now = alignNow(ctx.app.config.now());
|
|
31
|
+
const env = ctx.url.searchParams.get("env") || undefined;
|
|
32
|
+
const params = metricParamsOf(ctx.url.searchParams);
|
|
33
|
+
const key = JSON.stringify([project.id, "metrics", range, env, params, now]);
|
|
34
|
+
const hit = cached(key, ctx.app.config.now());
|
|
35
|
+
if (hit)
|
|
36
|
+
return sendJson(ctx.res, 200, hit);
|
|
37
|
+
const value = await projectMetrics(ctx.app.db, project.id, range, params, { now, env });
|
|
38
|
+
remember(key, value, ctx.app.config.now());
|
|
39
|
+
sendJson(ctx.res, 200, value);
|
|
40
|
+
}
|
|
41
|
+
/** `GET api/models/<page>?project=&range=&env=&...`: one page's numbers, from the project's stats tables. */
|
|
42
|
+
async function model(ctx) {
|
|
43
|
+
const page = ctx.params.page;
|
|
44
|
+
if (page === "metrics")
|
|
45
|
+
return metrics(ctx);
|
|
46
|
+
if (!isPageName(page))
|
|
47
|
+
return fail(404, `No model named "${page}".`);
|
|
48
|
+
const { project } = await projectOf(ctx);
|
|
49
|
+
const range = ctx.url.searchParams.get("range") ?? "24h";
|
|
50
|
+
if (!isTimeRange(range))
|
|
51
|
+
return fail(400, `Unknown range "${range}".`);
|
|
52
|
+
const days = await retentionDays(ctx, project.orgId);
|
|
53
|
+
if (TIME_RANGES[range].ms > days * DAY_MS)
|
|
54
|
+
fail(400, "This range is longer than the organization keeps data.");
|
|
55
|
+
const now = alignNow(ctx.app.config.now());
|
|
56
|
+
const env = ctx.url.searchParams.get("env") || undefined;
|
|
57
|
+
const params = paramsOf(ctx.url);
|
|
58
|
+
const key = JSON.stringify([project.id, page, range, env, params, now]);
|
|
59
|
+
const hit = cached(key, ctx.app.config.now());
|
|
60
|
+
if (hit)
|
|
61
|
+
return sendJson(ctx.res, 200, hit);
|
|
62
|
+
const db = ctx.app.db;
|
|
63
|
+
const pc = pageContext(range, now, params, { slowQueryMs: FACT_SLOW_QUERY_MS }, await cloudSettling(db, project.id, env));
|
|
64
|
+
const value = await runPage(page, pc, cloudExecutor(db, project.id, days * DAY_MS, env));
|
|
65
|
+
remember(key, value, ctx.app.config.now());
|
|
66
|
+
sendJson(ctx.res, 200, value);
|
|
67
|
+
}
|
|
68
|
+
export function modelRoutes(r) {
|
|
69
|
+
r.on("GET", "api/models/:page", model);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/routes/models.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../../src/routes/notify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAoDhD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAEjD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { requireUser } from "../auth/principal.js";
|
|
2
|
+
import { fail, readJsonBody, sendJson } from "../http/http.js";
|
|
3
|
+
import { DEFAULT_DIGEST, DIGEST_PERIODS, digestPrefsOf, prefsOf, saveDigestPref, savePrefs } from "../repo/mail-prefs.js";
|
|
4
|
+
const validZone = (tz) => {
|
|
5
|
+
try {
|
|
6
|
+
new Intl.DateTimeFormat("en-US", { timeZone: tz });
|
|
7
|
+
return tz.length <= 64;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
/** Projects this person can see, each with its digest choices. */
|
|
14
|
+
async function projectsOf(ctx, userId) {
|
|
15
|
+
const rows = await ctx.app.db.query("SELECT p.id, p.name, p.org_id, o.name AS org, m.role FROM members m JOIN orgs o ON o.id = m.org_id JOIN projects p ON p.org_id = o.id WHERE m.user_id = $1 ORDER BY o.name, p.name", [userId]);
|
|
16
|
+
const prefs = await digestPrefsOf(ctx.app.db, userId);
|
|
17
|
+
return rows.map((r) => ({ projectId: r.id, project: r.name, orgId: r.org_id, org: r.org, role: r.role, ...(prefs.get(r.id) ?? DEFAULT_DIGEST) }));
|
|
18
|
+
}
|
|
19
|
+
/** `GET api/me/notifications`: which emails this person gets. Security notices are always on, so they are not listed. */
|
|
20
|
+
async function show(ctx) {
|
|
21
|
+
const user = await requireUser(ctx);
|
|
22
|
+
sendJson(ctx.res, 200, { mail: ctx.app.mailer.live, ...(await prefsOf(ctx.app.db, user.id)), projects: await projectsOf(ctx, user.id) });
|
|
23
|
+
}
|
|
24
|
+
function prefsPatch(b) {
|
|
25
|
+
const out = {};
|
|
26
|
+
for (const k of ["team", "health", "digests"])
|
|
27
|
+
if (typeof b[k] === "boolean")
|
|
28
|
+
out[k] = b[k];
|
|
29
|
+
if (b.timeZone !== undefined)
|
|
30
|
+
out.timeZone = typeof b.timeZone === "string" && validZone(b.timeZone) ? b.timeZone : fail(400, "Pick a time zone such as America/Los_Angeles.");
|
|
31
|
+
if (b.digestHour !== undefined)
|
|
32
|
+
out.digestHour = Number.isInteger(b.digestHour) && Number(b.digestHour) >= 0 && Number(b.digestHour) <= 23 ? Number(b.digestHour) : fail(400, "Pick an hour from 0 to 23.");
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/** `PATCH api/me/notifications`: change only the fields sent. Projects must be ones this person can see. */
|
|
36
|
+
async function change(ctx) {
|
|
37
|
+
const user = await requireUser(ctx);
|
|
38
|
+
const body = await readJsonBody(ctx.req);
|
|
39
|
+
const patch = prefsPatch(body);
|
|
40
|
+
const visible = new Set((await projectsOf(ctx, user.id)).map((p) => p.projectId));
|
|
41
|
+
const projects = Array.isArray(body.projects) ? body.projects : [];
|
|
42
|
+
if (projects.some((p) => typeof p?.projectId !== "string" || !visible.has(p.projectId)))
|
|
43
|
+
fail(404, "Project not found.");
|
|
44
|
+
if (Object.keys(patch).length)
|
|
45
|
+
await savePrefs(ctx.app.db, user.id, patch);
|
|
46
|
+
for (const p of projects) {
|
|
47
|
+
const periods = Object.fromEntries(DIGEST_PERIODS.filter((k) => typeof p[k] === "boolean").map((k) => [k, p[k]]));
|
|
48
|
+
await saveDigestPref(ctx.app.db, user.id, p.projectId, periods);
|
|
49
|
+
}
|
|
50
|
+
await show(ctx);
|
|
51
|
+
}
|
|
52
|
+
export function notifyRoutes(r) {
|
|
53
|
+
r.on("GET", "api/me/notifications", show).on("PATCH", "api/me/notifications", change);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=notify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify.js","sourceRoot":"","sources":["../../src/routes/notify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orgs.d.ts","sourceRoot":"","sources":["../../src/routes/orgs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAIrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AA+DhD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAM9C"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { isAPIError } from "better-auth/api";
|
|
2
|
+
import { fromNodeHeaders } from "better-auth/node";
|
|
3
|
+
import { createOrgFor } from "../auth/auth.js";
|
|
4
|
+
import { requireOrg, requireUser } from "../auth/principal.js";
|
|
5
|
+
import { fail, readJsonBody, sendJson, str } from "../http/http.js";
|
|
6
|
+
import { audit, listAudit } from "../repo/audit.js";
|
|
7
|
+
import { orgDeletionNotice } from "../notify/team.js";
|
|
8
|
+
import { deleteOrgEverything, listMembers, pendingInvites, setRetention } from "../repo/orgs.js";
|
|
9
|
+
import { listKeys, listProjects } from "../repo/projects.js";
|
|
10
|
+
// Members, roles, and invites change through Better Auth (`api/auth/organization/*`). These routes add what it does not have.
|
|
11
|
+
const now = (ctx) => ctx.app.config.now();
|
|
12
|
+
async function overview(ctx) {
|
|
13
|
+
const { role } = await requireOrg(ctx, ctx.params.org, "read");
|
|
14
|
+
const db = ctx.app.db;
|
|
15
|
+
const id = ctx.params.org;
|
|
16
|
+
const manage = role === "owner" || role === "admin";
|
|
17
|
+
sendJson(ctx.res, 200, {
|
|
18
|
+
role,
|
|
19
|
+
members: await listMembers(db, id),
|
|
20
|
+
projects: await listProjects(db, id),
|
|
21
|
+
invites: manage ? await pendingInvites(db, id) : [],
|
|
22
|
+
keys: manage ? await listKeys(db, id) : [],
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async function newOrg(ctx) {
|
|
26
|
+
const user = await requireUser(ctx);
|
|
27
|
+
const name = str(await readJsonBody(ctx.req), "name");
|
|
28
|
+
sendJson(ctx.res, 201, await createOrgFor(ctx.app.auth, { db: ctx.app.db, retentionDays: ctx.app.config.retentionDays }, user.id, name));
|
|
29
|
+
}
|
|
30
|
+
async function changeOrg(ctx) {
|
|
31
|
+
const { user } = await requireOrg(ctx, ctx.params.org, "manage");
|
|
32
|
+
const body = await readJsonBody(ctx.req);
|
|
33
|
+
const days = body.retentionDays;
|
|
34
|
+
if (days !== undefined && (!Number.isInteger(days) || days < 1 || days > 400))
|
|
35
|
+
fail(400, "Retention is 1 to 400 days.");
|
|
36
|
+
const name = typeof body.name === "string" && body.name.trim() ? body.name.trim().slice(0, 100) : undefined;
|
|
37
|
+
if (name)
|
|
38
|
+
await ctx.app.db.query("UPDATE orgs SET name = $1 WHERE id = $2", [name, ctx.params.org]);
|
|
39
|
+
if (days !== undefined)
|
|
40
|
+
await setRetention(ctx.app.db, ctx.params.org, days);
|
|
41
|
+
await audit(ctx.app.db, ctx.params.org, `user:${user.id}`, "org.update", { name, retentionDays: days }, now(ctx));
|
|
42
|
+
sendJson(ctx.res, 200, { ok: true });
|
|
43
|
+
}
|
|
44
|
+
/** Owners only, with their password again: the organization and all of its data go at once. */
|
|
45
|
+
async function deleteOrg(ctx) {
|
|
46
|
+
const { user } = await requireOrg(ctx, ctx.params.org, "own");
|
|
47
|
+
const password = str(await readJsonBody(ctx.req), "password");
|
|
48
|
+
try {
|
|
49
|
+
await ctx.app.auth.api.verifyPassword({ body: { password }, headers: fromNodeHeaders(ctx.req.headers) });
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
if (isAPIError(err))
|
|
53
|
+
fail(400, "The password is not right.");
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
const tell = await orgDeletionNotice(ctx.app, ctx.params.org, user.id);
|
|
57
|
+
await ctx.app.db.tx((q) => deleteOrgEverything(q, ctx.params.org));
|
|
58
|
+
tell();
|
|
59
|
+
sendJson(ctx.res, 200, { ok: true });
|
|
60
|
+
}
|
|
61
|
+
async function auditLog(ctx) {
|
|
62
|
+
await requireOrg(ctx, ctx.params.org, "manage");
|
|
63
|
+
const before = Number(ctx.url.searchParams.get("before")) || undefined;
|
|
64
|
+
sendJson(ctx.res, 200, await listAudit(ctx.app.db, ctx.params.org, 100, before));
|
|
65
|
+
}
|
|
66
|
+
export function orgRoutes(r) {
|
|
67
|
+
r.on("POST", "api/orgs", newOrg)
|
|
68
|
+
.on("GET", "api/orgs/:org", overview)
|
|
69
|
+
.on("PATCH", "api/orgs/:org", changeOrg)
|
|
70
|
+
.on("DELETE", "api/orgs/:org", deleteOrg)
|
|
71
|
+
.on("GET", "api/orgs/:org/audit", auditLog);
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=orgs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orgs.js","sourceRoot":"","sources":["../../src/routes/orgs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/routes/projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAgDhD,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAMlD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { requireOrg } from "../auth/principal.js";
|
|
2
|
+
import { fail, readJsonBody, sendJson, str } from "../http/http.js";
|
|
3
|
+
import { audit } from "../repo/audit.js";
|
|
4
|
+
import { createKey, createProject, deleteProject, deleteProjectData, listProjects, projectInOrg, revokeKey } from "../repo/projects.js";
|
|
5
|
+
const now = (ctx) => ctx.app.config.now();
|
|
6
|
+
async function newProject(ctx) {
|
|
7
|
+
const { user } = await requireOrg(ctx, ctx.params.org, "manage");
|
|
8
|
+
const p = await createProject(ctx.app.db, ctx.params.org, str(await readJsonBody(ctx.req), "name"), now(ctx));
|
|
9
|
+
await audit(ctx.app.db, ctx.params.org, `user:${user.id}`, "project.create", { projectId: p.id, name: p.name }, now(ctx));
|
|
10
|
+
sendJson(ctx.res, 201, p);
|
|
11
|
+
}
|
|
12
|
+
/** DELETE removes the project. POST .../clear removes its data and keeps the project. */
|
|
13
|
+
async function dropProject(ctx) {
|
|
14
|
+
const { org, project } = ctx.params;
|
|
15
|
+
const { user } = await requireOrg(ctx, org, "manage");
|
|
16
|
+
const found = await projectInOrg(ctx.app.db, org, project);
|
|
17
|
+
if (!found)
|
|
18
|
+
return fail(404, "Project not found.");
|
|
19
|
+
const clearOnly = ctx.req.method === "POST";
|
|
20
|
+
await ctx.app.db.tx((q) => (clearOnly ? deleteProjectData(q, project) : deleteProject(q, project)));
|
|
21
|
+
await audit(ctx.app.db, org, `user:${user.id}`, clearOnly ? "project.clear" : "project.delete", { projectId: project, name: found.name }, now(ctx));
|
|
22
|
+
sendJson(ctx.res, 200, { ok: true });
|
|
23
|
+
}
|
|
24
|
+
/** Ingest keys belong to one project. Read keys name the projects they may read. */
|
|
25
|
+
async function newKey(ctx) {
|
|
26
|
+
const org = ctx.params.org;
|
|
27
|
+
const { user } = await requireOrg(ctx, org, "manage");
|
|
28
|
+
const body = await readJsonBody(ctx.req);
|
|
29
|
+
const kind = body.kind;
|
|
30
|
+
if (kind !== "ingest" && kind !== "read")
|
|
31
|
+
fail(400, 'Set kind to "ingest" or "read".');
|
|
32
|
+
const known = new Set((await listProjects(ctx.app.db, org)).map((p) => p.id));
|
|
33
|
+
const ids = Array.isArray(body.projectIds) ? body.projectIds.filter((id) => typeof id === "string" && known.has(id)) : [];
|
|
34
|
+
if (ids.length === 0 || (kind === "ingest" && ids.length !== 1))
|
|
35
|
+
fail(400, "Pick one project for an ingest key, or one or more for a read key.");
|
|
36
|
+
const key = await createKey(ctx.app.db, org, kind, str(body, "name", false), ids, user.id, now(ctx));
|
|
37
|
+
await audit(ctx.app.db, org, `user:${user.id}`, "key.create", { keyId: key.id, kind, projectIds: ids }, now(ctx));
|
|
38
|
+
sendJson(ctx.res, 201, key);
|
|
39
|
+
}
|
|
40
|
+
async function dropKey(ctx) {
|
|
41
|
+
const { org, key } = ctx.params;
|
|
42
|
+
const { user } = await requireOrg(ctx, org, "manage");
|
|
43
|
+
if (!(await revokeKey(ctx.app.db, org, key, now(ctx))))
|
|
44
|
+
fail(404, "Key not found.");
|
|
45
|
+
await audit(ctx.app.db, org, `user:${user.id}`, "key.revoke", { keyId: key }, now(ctx));
|
|
46
|
+
sendJson(ctx.res, 200, { ok: true });
|
|
47
|
+
}
|
|
48
|
+
export function projectRoutes(r) {
|
|
49
|
+
r.on("POST", "api/orgs/:org/projects", newProject)
|
|
50
|
+
.on("DELETE", "api/orgs/:org/projects/:project", dropProject)
|
|
51
|
+
.on("POST", "api/orgs/:org/projects/:project/clear", dropProject)
|
|
52
|
+
.on("POST", "api/orgs/:org/keys", newKey)
|
|
53
|
+
.on("DELETE", "api/orgs/:org/keys/:key", dropKey);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/routes/projects.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Ctx } from "../app.js";
|
|
2
|
+
import type { Router } from "../http/router.js";
|
|
3
|
+
export interface Share {
|
|
4
|
+
id: string;
|
|
5
|
+
traceId: string;
|
|
6
|
+
createdMs: number;
|
|
7
|
+
expiresMs: number;
|
|
8
|
+
views: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function shareRoutes(r: Router<Ctx>): void;
|
|
11
|
+
//# sourceMappingURL=shares.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shares.d.ts","sourceRoot":"","sources":["../../src/routes/shares.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAMhD,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAwDD,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAKhD"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { hashToken, newId, newToken } from "../auth/crypto.js";
|
|
2
|
+
import { requireProject } from "../auth/principal.js";
|
|
3
|
+
import { fail, readJsonBody, sendJson, str } from "../http/http.js";
|
|
4
|
+
import { audit } from "../repo/audit.js";
|
|
5
|
+
import { getTrace } from "../repo/trace-read.js";
|
|
6
|
+
const DAY_MS = 86_400_000;
|
|
7
|
+
/** A read-only link to one trace, valid for 1 to 30 days. Only the token's hash is kept. */
|
|
8
|
+
async function create(ctx) {
|
|
9
|
+
const { project, actor } = await requireProject(ctx, ctx.params.project, "write");
|
|
10
|
+
const body = await readJsonBody(ctx.req);
|
|
11
|
+
const traceId = str(body, "traceId");
|
|
12
|
+
const days = Number(body.days ?? 7);
|
|
13
|
+
if (!Number.isInteger(days) || days < 1 || days > 30)
|
|
14
|
+
fail(400, "A link lasts 1 to 30 days.");
|
|
15
|
+
if (!(await getTrace(ctx.app.db, project.id, traceId)))
|
|
16
|
+
fail(404, "Trace not found.");
|
|
17
|
+
const now = ctx.app.config.now();
|
|
18
|
+
const token = newToken("share");
|
|
19
|
+
await ctx.app.db.query("INSERT INTO shares (id, project_id, trace_id, token_hash, created_by, created_ms, expires_ms) VALUES ($1, $2, $3, $4, $5, $6, $7)", [
|
|
20
|
+
newId(),
|
|
21
|
+
project.id,
|
|
22
|
+
traceId,
|
|
23
|
+
hashToken(token),
|
|
24
|
+
actor,
|
|
25
|
+
now,
|
|
26
|
+
now + days * DAY_MS,
|
|
27
|
+
]);
|
|
28
|
+
await audit(ctx.app.db, project.orgId, actor, "share.create", { projectId: project.id, traceId, days }, now);
|
|
29
|
+
sendJson(ctx.res, 201, { url: `${ctx.app.baseUrl(ctx.req)}/_wizelens/#/shared/${token}`, expiresMs: now + days * DAY_MS });
|
|
30
|
+
}
|
|
31
|
+
async function list(ctx) {
|
|
32
|
+
const { project } = await requireProject(ctx, ctx.params.project);
|
|
33
|
+
const rows = await ctx.app.db.query(`SELECT id, trace_id AS "traceId", created_ms AS "createdMs", expires_ms AS "expiresMs", views FROM shares
|
|
34
|
+
WHERE project_id = $1 AND revoked_ms IS NULL AND expires_ms > $2 ORDER BY created_ms DESC`, [project.id, ctx.app.config.now()]);
|
|
35
|
+
sendJson(ctx.res, 200, rows);
|
|
36
|
+
}
|
|
37
|
+
async function revoke(ctx) {
|
|
38
|
+
const { project, actor } = await requireProject(ctx, ctx.params.project, "write");
|
|
39
|
+
const now = ctx.app.config.now();
|
|
40
|
+
const rows = await ctx.app.db.query("UPDATE shares SET revoked_ms = $1 WHERE project_id = $2 AND id = $3 AND revoked_ms IS NULL RETURNING id", [now, project.id, ctx.params.id]);
|
|
41
|
+
if (rows.length === 0)
|
|
42
|
+
fail(404, "Link not found.");
|
|
43
|
+
await audit(ctx.app.db, project.orgId, actor, "share.revoke", { projectId: project.id, shareId: ctx.params.id }, now);
|
|
44
|
+
sendJson(ctx.res, 200, { ok: true });
|
|
45
|
+
}
|
|
46
|
+
/** Anyone with the link can read the trace while the link is valid. Nothing else is reachable with it. */
|
|
47
|
+
async function open(ctx) {
|
|
48
|
+
const now = ctx.app.config.now();
|
|
49
|
+
const [row] = await ctx.app.db.query("UPDATE shares SET views = views + 1 WHERE token_hash = $1 AND revoked_ms IS NULL AND expires_ms > $2 RETURNING project_id, trace_id, expires_ms", [hashToken(ctx.params.token), now]);
|
|
50
|
+
const trace = row ? await getTrace(ctx.app.db, row.project_id, row.trace_id) : undefined;
|
|
51
|
+
if (!row || !trace)
|
|
52
|
+
return fail(404, "This link is not valid any more.");
|
|
53
|
+
sendJson(ctx.res, 200, { trace, expiresMs: row.expires_ms });
|
|
54
|
+
}
|
|
55
|
+
export function shareRoutes(r) {
|
|
56
|
+
r.on("POST", "api/projects/:project/shares", create)
|
|
57
|
+
.on("GET", "api/projects/:project/shares", list)
|
|
58
|
+
.on("DELETE", "api/projects/:project/shares/:id", revoke)
|
|
59
|
+
.on("GET", "api/shared/:token", open);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=shares.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shares.js","sourceRoot":"","sources":["../../src/routes/shares.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Executor, type SqlRunner } from "@wizeworks/lens-core";
|
|
2
|
+
import type { Queryable } from "./db/db.js";
|
|
3
|
+
/** Reads for the SQL executor, on the cloud database. */
|
|
4
|
+
export declare const pgRunner: (q: Queryable) => SqlRunner;
|
|
5
|
+
/** How long a project's organization keeps data, in ms; `fallbackDays` when the project has no organization. */
|
|
6
|
+
export declare function projectRetentionMs(q: Queryable, projectId: string, fallbackDays: number): Promise<number>;
|
|
7
|
+
/** Page needs from a project's stats tables, optionally one environment. The 1 h tier keeps the organization's retention. */
|
|
8
|
+
export declare function cloudExecutor(q: Queryable, projectId: string, retentionMs: number, env?: string): Executor;
|
|
9
|
+
/** Traces of a project still waiting for their stats, for `pageContext(..., settling)`. Null when none. */
|
|
10
|
+
export declare function cloudSettling(q: Queryable, projectId: string, env?: string): Promise<number | null>;
|
|
11
|
+
//# sourceMappingURL=scale-exec.d.ts.map
|