@wizeworks/lens-cloud 0.3.0-alpha.1 → 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/README.md +57 -5
- package/dist/alerts/evaluate.d.ts.map +1 -1
- package/dist/alerts/evaluate.js +17 -2
- package/dist/alerts/evaluate.js.map +1 -1
- package/dist/alerts/notify.d.ts +13 -2
- package/dist/alerts/notify.d.ts.map +1 -1
- package/dist/alerts/notify.js +22 -16
- package/dist/alerts/notify.js.map +1 -1
- package/dist/app.d.ts +10 -2
- package/dist/app.d.ts.map +1 -1
- 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 +0 -5
- package/dist/auth/crypto.d.ts.map +1 -1
- package/dist/auth/crypto.js +3 -20
- package/dist/auth/crypto.js.map +1 -1
- 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 +8 -3
- package/dist/auth/principal.d.ts.map +1 -1
- package/dist/auth/principal.js +13 -8
- package/dist/auth/principal.js.map +1 -1
- package/dist/auth/roles.d.ts +43 -3
- package/dist/auth/roles.d.ts.map +1 -1
- package/dist/auth/roles.js +15 -6
- package/dist/auth/roles.js.map +1 -1
- 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 +1 -1
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +55 -14
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.js +18 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +26 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +35 -0
- package/dist/config.js.map +1 -1
- package/dist/db/db.d.ts +5 -2
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +15 -8
- package/dist/db/db.js.map +1 -1
- package/dist/db/migrate.d.ts +2 -2
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +15 -5
- package/dist/db/migrate.js.map +1 -1
- 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.map +1 -1
- package/dist/db/schema.js +8 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/http/http.d.ts +2 -0
- package/dist/http/http.d.ts.map +1 -1
- package/dist/http/http.js +7 -3
- package/dist/http/http.js.map +1 -1
- package/dist/jobs.d.ts +1 -1
- package/dist/jobs.d.ts.map +1 -1
- package/dist/jobs.js +14 -3
- package/dist/jobs.js.map +1 -1
- 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 +6 -2
- package/dist/repo/alerts.d.ts.map +1 -1
- package/dist/repo/alerts.js.map +1 -1
- 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/orgs.d.ts +15 -25
- package/dist/repo/orgs.d.ts.map +1 -1
- package/dist/repo/orgs.js +18 -60
- package/dist/repo/orgs.js.map +1 -1
- 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/users.d.ts +5 -16
- package/dist/repo/users.d.ts.map +1 -1
- package/dist/repo/users.js +2 -60
- package/dist/repo/users.js.map +1 -1
- package/dist/routes/alerts.d.ts.map +1 -1
- package/dist/routes/alerts.js +23 -6
- package/dist/routes/alerts.js.map +1 -1
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +4 -2
- package/dist/routes/index.js.map +1 -1
- 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/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.map +1 -1
- package/dist/routes/orgs.js +30 -53
- package/dist/routes/orgs.js.map +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +4 -3
- package/dist/routes/projects.js.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +45 -14
- package/dist/server.js.map +1 -1
- package/package.json +19 -6
- package/dist/routes/auth.d.ts +0 -4
- package/dist/routes/auth.d.ts.map +0 -1
- package/dist/routes/auth.js +0 -106
- package/dist/routes/auth.js.map +0 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Migration 4: accounts move to Better Auth (names in auth/schema-names.ts). Rows and ids stay; sessions start over; invites get new links.
|
|
2
|
+
export const AUTH_MIGRATION = `
|
|
3
|
+
ALTER TABLE users ADD COLUMN email_verified BOOLEAN NOT NULL DEFAULT FALSE;
|
|
4
|
+
ALTER TABLE users ADD COLUMN image TEXT;
|
|
5
|
+
ALTER TABLE users ADD COLUMN created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
|
6
|
+
ALTER TABLE users ADD COLUMN updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
|
7
|
+
ALTER TABLE users ADD COLUMN two_factor_enabled BOOLEAN DEFAULT FALSE;
|
|
8
|
+
UPDATE users SET email = lower(email), email_verified = TRUE, created_at = to_timestamp(created_ms / 1000.0), updated_at = to_timestamp(created_ms / 1000.0);
|
|
9
|
+
CREATE TABLE accounts (
|
|
10
|
+
id TEXT NOT NULL PRIMARY KEY, account_id TEXT NOT NULL, provider_id TEXT NOT NULL,
|
|
11
|
+
user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, access_token TEXT, refresh_token TEXT, id_token TEXT,
|
|
12
|
+
access_token_expires_at TIMESTAMPTZ, refresh_token_expires_at TIMESTAMPTZ, scope TEXT, password TEXT,
|
|
13
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL
|
|
14
|
+
);
|
|
15
|
+
CREATE INDEX accounts_user_id_idx ON accounts (user_id);
|
|
16
|
+
CREATE UNIQUE INDEX ux_accounts_provider_account ON accounts (provider_id, account_id);
|
|
17
|
+
INSERT INTO accounts (id, account_id, provider_id, user_id, password, created_at, updated_at)
|
|
18
|
+
SELECT gen_random_uuid()::text, id, 'credential', id, password_hash, created_at, CURRENT_TIMESTAMP FROM users;
|
|
19
|
+
ALTER TABLE users DROP COLUMN password_hash;
|
|
20
|
+
ALTER TABLE users DROP COLUMN created_ms;
|
|
21
|
+
DROP TABLE sessions;
|
|
22
|
+
CREATE TABLE sessions (
|
|
23
|
+
id TEXT NOT NULL PRIMARY KEY, expires_at TIMESTAMPTZ NOT NULL, token TEXT NOT NULL UNIQUE,
|
|
24
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL, ip_address TEXT, user_agent TEXT,
|
|
25
|
+
user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, active_org_id TEXT
|
|
26
|
+
);
|
|
27
|
+
CREATE INDEX sessions_user_id_idx ON sessions (user_id);
|
|
28
|
+
ALTER TABLE orgs ADD COLUMN logo TEXT;
|
|
29
|
+
ALTER TABLE orgs ADD COLUMN metadata TEXT;
|
|
30
|
+
ALTER TABLE orgs ADD COLUMN created_at TIMESTAMPTZ;
|
|
31
|
+
UPDATE orgs SET created_at = to_timestamp(created_ms / 1000.0);
|
|
32
|
+
ALTER TABLE orgs ALTER COLUMN created_at SET NOT NULL;
|
|
33
|
+
ALTER TABLE orgs DROP COLUMN created_ms;
|
|
34
|
+
ALTER TABLE members ADD COLUMN id TEXT;
|
|
35
|
+
ALTER TABLE members ADD COLUMN created_at TIMESTAMPTZ;
|
|
36
|
+
UPDATE members SET id = gen_random_uuid()::text, created_at = to_timestamp(created_ms / 1000.0);
|
|
37
|
+
ALTER TABLE members DROP CONSTRAINT members_pkey;
|
|
38
|
+
ALTER TABLE members ALTER COLUMN id SET NOT NULL;
|
|
39
|
+
ALTER TABLE members ALTER COLUMN created_at SET NOT NULL;
|
|
40
|
+
ALTER TABLE members DROP COLUMN created_ms;
|
|
41
|
+
ALTER TABLE members ADD PRIMARY KEY (id);
|
|
42
|
+
CREATE UNIQUE INDEX ux_members_org_user ON members (org_id, user_id);
|
|
43
|
+
CREATE INDEX members_org_id_idx ON members (org_id);
|
|
44
|
+
CREATE INDEX members_user_id_idx ON members (user_id);
|
|
45
|
+
DROP INDEX ix_members_user;
|
|
46
|
+
ALTER TABLE invites RENAME TO legacy_invites;
|
|
47
|
+
CREATE TABLE invites (
|
|
48
|
+
id TEXT NOT NULL PRIMARY KEY, org_id TEXT NOT NULL REFERENCES orgs (id) ON DELETE CASCADE, email TEXT NOT NULL, role TEXT,
|
|
49
|
+
status TEXT NOT NULL, expires_at TIMESTAMPTZ NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
50
|
+
inviter_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE
|
|
51
|
+
);
|
|
52
|
+
CREATE INDEX invites_org_id_idx ON invites (org_id);
|
|
53
|
+
CREATE INDEX invites_email_idx ON invites (email);
|
|
54
|
+
INSERT INTO invites (id, org_id, email, role, status, expires_at, created_at, inviter_id)
|
|
55
|
+
SELECT gen_random_uuid()::text, i.org_id, lower(i.email), i.role, 'pending', to_timestamp(i.expires_ms / 1000.0), to_timestamp(i.created_ms / 1000.0),
|
|
56
|
+
COALESCE((SELECT u.id FROM users u WHERE u.id = i.created_by),
|
|
57
|
+
(SELECT m.user_id FROM members m WHERE m.org_id = i.org_id AND m.role = 'owner' ORDER BY m.created_at LIMIT 1))
|
|
58
|
+
FROM legacy_invites i
|
|
59
|
+
WHERE i.accepted_ms IS NULL AND i.expires_ms > extract(epoch FROM CURRENT_TIMESTAMP) * 1000
|
|
60
|
+
AND EXISTS (SELECT 1 FROM members m WHERE m.org_id = i.org_id AND m.role = 'owner');
|
|
61
|
+
DROP TABLE legacy_invites;
|
|
62
|
+
CREATE TABLE verifications (
|
|
63
|
+
id TEXT NOT NULL PRIMARY KEY, identifier TEXT NOT NULL, value TEXT NOT NULL, expires_at TIMESTAMPTZ NOT NULL,
|
|
64
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
65
|
+
);
|
|
66
|
+
CREATE INDEX verifications_identifier_idx ON verifications (identifier);
|
|
67
|
+
CREATE TABLE two_factors (
|
|
68
|
+
id TEXT NOT NULL PRIMARY KEY, secret TEXT NOT NULL, backup_codes TEXT NOT NULL, user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
|
69
|
+
verified BOOLEAN, failed_verification_count INTEGER, locked_until TIMESTAMPTZ
|
|
70
|
+
);
|
|
71
|
+
CREATE INDEX two_factors_secret_idx ON two_factors (secret);
|
|
72
|
+
CREATE INDEX two_factors_user_id_idx ON two_factors (user_id);
|
|
73
|
+
CREATE TABLE passkeys (
|
|
74
|
+
id TEXT NOT NULL PRIMARY KEY, name TEXT, public_key TEXT NOT NULL, user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
|
75
|
+
credential_id TEXT NOT NULL, counter INTEGER NOT NULL, device_type TEXT NOT NULL, backed_up BOOLEAN NOT NULL, transports TEXT,
|
|
76
|
+
created_at TIMESTAMPTZ, aaguid TEXT
|
|
77
|
+
);
|
|
78
|
+
CREATE INDEX passkeys_user_id_idx ON passkeys (user_id);
|
|
79
|
+
CREATE INDEX passkeys_credential_id_idx ON passkeys (credential_id);
|
|
80
|
+
CREATE TABLE rate_limits (id TEXT NOT NULL PRIMARY KEY, key TEXT NOT NULL UNIQUE, count INTEGER NOT NULL, last_request BIGINT NOT NULL);
|
|
81
|
+
CREATE TABLE cloud_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);
|
|
82
|
+
CREATE FUNCTION wl_org_keeps_owner() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
83
|
+
DECLARE oid TEXT := COALESCE(OLD.org_id, NEW.org_id);
|
|
84
|
+
BEGIN
|
|
85
|
+
IF EXISTS (SELECT 1 FROM orgs WHERE id = oid) AND NOT EXISTS (SELECT 1 FROM members WHERE org_id = oid AND role = 'owner') THEN
|
|
86
|
+
RAISE EXCEPTION 'organization % must keep at least one owner', oid USING ERRCODE = 'check_violation';
|
|
87
|
+
END IF;
|
|
88
|
+
RETURN NULL;
|
|
89
|
+
END $$;
|
|
90
|
+
CREATE CONSTRAINT TRIGGER members_keep_owner AFTER UPDATE OR DELETE ON members
|
|
91
|
+
DEFERRABLE INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION wl_org_keeps_owner();
|
|
92
|
+
`;
|
|
93
|
+
//# sourceMappingURL=schema-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-auth.js","sourceRoot":"","sources":["../../src/db/schema-auth.ts"],"names":[],"mappings":"AAAA,4IAA4I;AAC5I,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0F7B,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const MAIL_MIGRATION = "\nCREATE TABLE mail_suppressions (\n email TEXT NOT NULL PRIMARY KEY, reason TEXT NOT NULL CHECK (reason IN ('bounce', 'complaint')), detail TEXT NOT NULL,\n created_ms DOUBLE PRECISION NOT NULL\n);\n";
|
|
2
|
+
//# sourceMappingURL=schema-mail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-mail.d.ts","sourceRoot":"","sources":["../../src/db/schema-mail.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,cAAc,+MAK1B,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Migration 6: addresses mail must skip. A hard bounce skips every email; a spam complaint skips all but mail the person asked for.
|
|
2
|
+
export const MAIL_MIGRATION = `
|
|
3
|
+
CREATE TABLE mail_suppressions (
|
|
4
|
+
email TEXT NOT NULL PRIMARY KEY, reason TEXT NOT NULL CHECK (reason IN ('bounce', 'complaint')), detail TEXT NOT NULL,
|
|
5
|
+
created_ms DOUBLE PRECISION NOT NULL
|
|
6
|
+
);
|
|
7
|
+
`;
|
|
8
|
+
//# sourceMappingURL=schema-mail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-mail.js","sourceRoot":"","sources":["../../src/db/schema-mail.ts"],"names":[],"mappings":"AAAA,oIAAoI;AACpI,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;CAK7B,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const NOTIFY_MIGRATION = "\nALTER TABLE audit ADD COLUMN noticed BOOLEAN NOT NULL DEFAULT TRUE;\nALTER TABLE audit ALTER COLUMN noticed SET DEFAULT FALSE;\nCREATE INDEX ix_audit_unnoticed ON audit (time_ms) WHERE NOT noticed;\nCREATE TABLE mail_prefs (\n user_id TEXT NOT NULL PRIMARY KEY REFERENCES users (id) ON DELETE CASCADE, team BOOLEAN NOT NULL DEFAULT TRUE,\n health BOOLEAN NOT NULL DEFAULT TRUE, digests BOOLEAN NOT NULL DEFAULT TRUE, time_zone TEXT NOT NULL DEFAULT 'UTC', digest_hour SMALLINT NOT NULL DEFAULT 8\n);\nCREATE TABLE digest_prefs (\n user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, project_id TEXT NOT NULL REFERENCES projects (id) ON DELETE CASCADE,\n daily BOOLEAN NOT NULL, weekly BOOLEAN NOT NULL, monthly BOOLEAN NOT NULL, PRIMARY KEY (user_id, project_id)\n);\nCREATE TABLE digest_sends (\n user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, project_id TEXT NOT NULL REFERENCES projects (id) ON DELETE CASCADE,\n period TEXT NOT NULL, period_key TEXT NOT NULL, sent_ms DOUBLE PRECISION NOT NULL, PRIMARY KEY (user_id, project_id, period, period_key)\n);\nCREATE TABLE known_devices (\n user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, device TEXT NOT NULL, first_ms DOUBLE PRECISION NOT NULL,\n last_ms DOUBLE PRECISION NOT NULL, PRIMARY KEY (user_id, device)\n);\nCREATE TABLE project_health (\n project_id TEXT NOT NULL PRIMARY KEY REFERENCES projects (id) ON DELETE CASCADE, quiet BOOLEAN NOT NULL, changed_ms DOUBLE PRECISION NOT NULL\n);\n";
|
|
2
|
+
//# sourceMappingURL=schema-notify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-notify.d.ts","sourceRoot":"","sources":["../../src/db/schema-notify.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,gBAAgB,g+CAuB5B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Migration 7: notices and digests. Old audit lines count as noticed, so an upgrade sends nothing for the past.
|
|
2
|
+
export const NOTIFY_MIGRATION = `
|
|
3
|
+
ALTER TABLE audit ADD COLUMN noticed BOOLEAN NOT NULL DEFAULT TRUE;
|
|
4
|
+
ALTER TABLE audit ALTER COLUMN noticed SET DEFAULT FALSE;
|
|
5
|
+
CREATE INDEX ix_audit_unnoticed ON audit (time_ms) WHERE NOT noticed;
|
|
6
|
+
CREATE TABLE mail_prefs (
|
|
7
|
+
user_id TEXT NOT NULL PRIMARY KEY REFERENCES users (id) ON DELETE CASCADE, team BOOLEAN NOT NULL DEFAULT TRUE,
|
|
8
|
+
health BOOLEAN NOT NULL DEFAULT TRUE, digests BOOLEAN NOT NULL DEFAULT TRUE, time_zone TEXT NOT NULL DEFAULT 'UTC', digest_hour SMALLINT NOT NULL DEFAULT 8
|
|
9
|
+
);
|
|
10
|
+
CREATE TABLE digest_prefs (
|
|
11
|
+
user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, project_id TEXT NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
|
|
12
|
+
daily BOOLEAN NOT NULL, weekly BOOLEAN NOT NULL, monthly BOOLEAN NOT NULL, PRIMARY KEY (user_id, project_id)
|
|
13
|
+
);
|
|
14
|
+
CREATE TABLE digest_sends (
|
|
15
|
+
user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, project_id TEXT NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
|
|
16
|
+
period TEXT NOT NULL, period_key TEXT NOT NULL, sent_ms DOUBLE PRECISION NOT NULL, PRIMARY KEY (user_id, project_id, period, period_key)
|
|
17
|
+
);
|
|
18
|
+
CREATE TABLE known_devices (
|
|
19
|
+
user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, device TEXT NOT NULL, first_ms DOUBLE PRECISION NOT NULL,
|
|
20
|
+
last_ms DOUBLE PRECISION NOT NULL, PRIMARY KEY (user_id, device)
|
|
21
|
+
);
|
|
22
|
+
CREATE TABLE project_health (
|
|
23
|
+
project_id TEXT NOT NULL PRIMARY KEY REFERENCES projects (id) ON DELETE CASCADE, quiet BOOLEAN NOT NULL, changed_ms DOUBLE PRECISION NOT NULL
|
|
24
|
+
);
|
|
25
|
+
`;
|
|
26
|
+
//# sourceMappingURL=schema-notify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-notify.js","sourceRoot":"","sources":["../../src/db/schema-notify.ts"],"names":[],"mappings":"AAAA,gHAAgH;AAChH,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuB/B,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const SSO_MIGRATION = "\nCREATE TABLE sso_providers (\n id TEXT NOT NULL PRIMARY KEY, provider_id TEXT NOT NULL UNIQUE, issuer TEXT NOT NULL, domain TEXT NOT NULL, domain_verified BOOLEAN,\n oidc_config TEXT, saml_config TEXT, user_id TEXT REFERENCES users (id) ON DELETE SET NULL,\n org_id TEXT NOT NULL REFERENCES orgs (id) ON DELETE CASCADE\n);\nCREATE INDEX sso_providers_user_id_idx ON sso_providers (user_id);\nCREATE INDEX sso_providers_org_id_idx ON sso_providers (org_id);\nCREATE FUNCTION wl_sso_accounts_go() RETURNS trigger LANGUAGE plpgsql AS $$\nBEGIN\n DELETE FROM accounts WHERE provider_id = OLD.provider_id;\n RETURN NULL;\nEND $$;\nCREATE TRIGGER sso_providers_accounts_go AFTER DELETE ON sso_providers FOR EACH ROW EXECUTE FUNCTION wl_sso_accounts_go();\n";
|
|
2
|
+
//# sourceMappingURL=schema-sso.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-sso.d.ts","sourceRoot":"","sources":["../../src/db/schema-sso.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa,0vBAczB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Migration 5: single sign-on providers, one organization each (Better Auth's SSO plugin; names in auth/schema-names.ts).
|
|
2
|
+
export const SSO_MIGRATION = `
|
|
3
|
+
CREATE TABLE sso_providers (
|
|
4
|
+
id TEXT NOT NULL PRIMARY KEY, provider_id TEXT NOT NULL UNIQUE, issuer TEXT NOT NULL, domain TEXT NOT NULL, domain_verified BOOLEAN,
|
|
5
|
+
oidc_config TEXT, saml_config TEXT, user_id TEXT REFERENCES users (id) ON DELETE SET NULL,
|
|
6
|
+
org_id TEXT NOT NULL REFERENCES orgs (id) ON DELETE CASCADE
|
|
7
|
+
);
|
|
8
|
+
CREATE INDEX sso_providers_user_id_idx ON sso_providers (user_id);
|
|
9
|
+
CREATE INDEX sso_providers_org_id_idx ON sso_providers (org_id);
|
|
10
|
+
CREATE FUNCTION wl_sso_accounts_go() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
11
|
+
BEGIN
|
|
12
|
+
DELETE FROM accounts WHERE provider_id = OLD.provider_id;
|
|
13
|
+
RETURN NULL;
|
|
14
|
+
END $$;
|
|
15
|
+
CREATE TRIGGER sso_providers_accounts_go AFTER DELETE ON sso_providers FOR EACH ROW EXECUTE FUNCTION wl_sso_accounts_go();
|
|
16
|
+
`;
|
|
17
|
+
//# sourceMappingURL=schema-sso.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-sso.js","sourceRoot":"","sources":["../../src/db/schema-sso.ts"],"names":[],"mappings":"AAAA,0HAA0H;AAC1H,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;CAc5B,CAAC"}
|
package/dist/db/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAwMvC,CAAC;AAEF,eAAO,MAAM,gBAAgB,uHAAuH,CAAC"}
|
package/dist/db/schema.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { AUTH_MIGRATION } from "./schema-auth.js";
|
|
2
|
+
import { MAIL_MIGRATION } from "./schema-mail.js";
|
|
3
|
+
import { NOTIFY_MIGRATION } from "./schema-notify.js";
|
|
4
|
+
import { SSO_MIGRATION } from "./schema-sso.js";
|
|
1
5
|
// Cloud schema, one entry per version. Never edit a shipped entry: add a new one (docs/CONTRACT.md, "Cloud storage").
|
|
2
6
|
export const MIGRATIONS = [
|
|
3
7
|
`
|
|
@@ -195,6 +199,10 @@ CREATE INDEX ix_metric_10s_time ON metric_10s (project_id, bucket_ms);
|
|
|
195
199
|
CREATE INDEX ix_metric_5m_time ON metric_5m (project_id, bucket_ms);
|
|
196
200
|
CREATE INDEX ix_metric_1h_time ON metric_1h (project_id, bucket_ms);
|
|
197
201
|
`,
|
|
202
|
+
AUTH_MIGRATION,
|
|
203
|
+
SSO_MIGRATION,
|
|
204
|
+
MAIL_MIGRATION,
|
|
205
|
+
NOTIFY_MIGRATION,
|
|
198
206
|
];
|
|
199
207
|
export const MIGRATIONS_TABLE = `CREATE TABLE IF NOT EXISTS wizelens_migrations (version INTEGER PRIMARY KEY, applied_ms DOUBLE PRECISION NOT NULL)`;
|
|
200
208
|
//# sourceMappingURL=schema.js.map
|
package/dist/db/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA,sHAAsH;AACtH,MAAM,CAAC,MAAM,UAAU,GAAsB;IAC3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6ED;IACC;;;;;;;;;;CAUD;IACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyGD;
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,sHAAsH;AACtH,MAAM,CAAC,MAAM,UAAU,GAAsB;IAC3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6ED;IACC;;;;;;;;;;CAUD;IACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyGD;IACC,cAAc;IACd,aAAa;IACb,cAAc;IACd,gBAAgB;CACjB,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,oHAAoH,CAAC"}
|
package/dist/http/http.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export declare class HttpError extends Error {
|
|
|
6
6
|
}
|
|
7
7
|
export declare const fail: (status: number, message: string) => never;
|
|
8
8
|
export declare function sendJson(res: ServerResponse, status: number, value: unknown, headers?: Record<string, string | string[]>): void;
|
|
9
|
+
/** The body exactly as sent, for signature checks. Throws 413 past 1 MB. */
|
|
10
|
+
export declare function readRawBody(req: IncomingMessage): Promise<string>;
|
|
9
11
|
/** A small JSON body. Throws 400 for bad JSON or more than 1 MB. */
|
|
10
12
|
export declare function readJsonBody(req: IncomingMessage): Promise<Record<string, unknown>>;
|
|
11
13
|
export declare function cookieOf(req: IncomingMessage, name: string): string | undefined;
|
package/dist/http/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/http/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAIjE,oDAAoD;AACpD,qBAAa,SAAU,SAAQ,KAAK;IAEhC,QAAQ,CAAC,MAAM,EAAE,MAAM;IADzB,YACW,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EAGhB;CACF;AAED,eAAO,MAAM,IAAI,WAAY,MAAM,WAAW,MAAM,KAAG,KAEtD,CAAC;AAEF,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAM,GAAG,IAAI,CAGnI;AAED,oEAAoE;AACpE,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/http/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAIjE,oDAAoD;AACpD,qBAAa,SAAU,SAAQ,KAAK;IAEhC,QAAQ,CAAC,MAAM,EAAE,MAAM;IADzB,YACW,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EAGhB;CACF;AAED,eAAO,MAAM,IAAI,WAAY,MAAM,WAAW,MAAM,KAAG,KAEtD,CAAC;AAEF,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAM,GAAG,IAAI,CAGnI;AAED,4EAA4E;AAC5E,wBAAsB,WAAW,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAUvE;AAED,oEAAoE;AACpE,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CASzF;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAM/E;AAED,wFAAwF;AACxF,eAAO,MAAM,MAAM,SAAU,MAAM,SAAS,MAAM,WAAW,MAAM,UAAU,OAAO,KAAG,MACgC,CAAC;AAExH,eAAO,MAAM,QAAQ,QAAS,eAAe,KAAG,MAAM,GAAG,SAGxD,CAAC;AAEF,uEAAuE;AACvE,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,UAAO,GAAG,MAAM,CAKvF"}
|
package/dist/http/http.js
CHANGED
|
@@ -14,8 +14,8 @@ export function sendJson(res, status, value, headers = {}) {
|
|
|
14
14
|
res.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Cache-Control": "no-store", ...headers });
|
|
15
15
|
res.end(JSON.stringify(value));
|
|
16
16
|
}
|
|
17
|
-
/**
|
|
18
|
-
export async function
|
|
17
|
+
/** The body exactly as sent, for signature checks. Throws 413 past 1 MB. */
|
|
18
|
+
export async function readRawBody(req) {
|
|
19
19
|
const chunks = [];
|
|
20
20
|
let size = 0;
|
|
21
21
|
for await (const chunk of req) {
|
|
@@ -25,7 +25,11 @@ export async function readJsonBody(req) {
|
|
|
25
25
|
fail(413, "The body is too large.");
|
|
26
26
|
chunks.push(buf);
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
29
|
+
}
|
|
30
|
+
/** A small JSON body. Throws 400 for bad JSON or more than 1 MB. */
|
|
31
|
+
export async function readJsonBody(req) {
|
|
32
|
+
const text = await readRawBody(req);
|
|
29
33
|
try {
|
|
30
34
|
const v = text ? JSON.parse(text) : {};
|
|
31
35
|
return v && typeof v === "object" && !Array.isArray(v) ? v : fail(400, "Send a JSON object.");
|
package/dist/http/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/http/http.ts"],"names":[],"mappings":"AAEA,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;AAE7B,oDAAoD;AACpD,MAAM,OAAO,SAAU,SAAQ,KAAK;IAEvB,MAAM;IADjB,YACW,MAAc,EACvB,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;sBAHN,MAAM;IAIjB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,MAAc,EAAE,OAAe,EAAS,EAAE;IAC7D,MAAM,IAAI,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,KAAc,EAAE,OAAO,GAAsC,EAAE;IAC3H,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,iCAAiC,EAAE,eAAe,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IACtH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/http/http.ts"],"names":[],"mappings":"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"}
|
package/dist/jobs.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { CloudApp } from "./app.js";
|
|
2
|
-
/** Background work: retention,
|
|
2
|
+
/** Background work: retention, stats, rollups, sessions, alert rules, team and health notices, and digests. Returns a function that stops it. */
|
|
3
3
|
export declare function startJobs(app: CloudApp): () => void;
|
|
4
4
|
//# sourceMappingURL=jobs.d.ts.map
|
package/dist/jobs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../src/jobs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../src/jobs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AA+BzC,iJAAiJ;AACjJ,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,IAAI,CAmBnD"}
|
package/dist/jobs.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { evaluateAll } from "./alerts/evaluate.js";
|
|
2
2
|
import { pruneByRetention, pruneMetricsByRetention } from "./repo/trace-write.js";
|
|
3
|
-
import { pruneSessions } from "./repo/users.js";
|
|
4
3
|
import { pruneRollups, settleCloud } from "./settle.js";
|
|
4
|
+
import { pruneAuthRows } from "./repo/auth-prune.js";
|
|
5
|
+
import { sendDigests } from "./notify/digest.js";
|
|
6
|
+
import { checkHealth } from "./notify/health.js";
|
|
7
|
+
import { sendTeamNotices } from "./notify/team.js";
|
|
5
8
|
const HOUSEKEEPING_MS = 10 * 60_000;
|
|
6
9
|
const SETTLE_MS = 3_000;
|
|
7
10
|
const ROLLUP_PRUNE_MS = 60_000;
|
|
11
|
+
const NOTICE_MS = 60_000;
|
|
12
|
+
const DIGEST_MS = 10 * 60_000;
|
|
8
13
|
/** Run `job` now and then every `everyMs`. A failed run logs and waits for the next one. */
|
|
9
14
|
function every(name, everyMs, job) {
|
|
10
15
|
let running = false;
|
|
@@ -22,7 +27,7 @@ function every(name, everyMs, job) {
|
|
|
22
27
|
first.unref();
|
|
23
28
|
return () => (clearInterval(timer), clearTimeout(first));
|
|
24
29
|
}
|
|
25
|
-
/** Background work: retention,
|
|
30
|
+
/** Background work: retention, stats, rollups, sessions, alert rules, team and health notices, and digests. Returns a function that stops it. */
|
|
26
31
|
export function startJobs(app) {
|
|
27
32
|
const now = app.config.now;
|
|
28
33
|
const stops = [
|
|
@@ -34,8 +39,14 @@ export function startJobs(app) {
|
|
|
34
39
|
}),
|
|
35
40
|
every("settle", SETTLE_MS, () => settleCloud(app.db, now(), { defaultRetentionDays: app.config.retentionDays })),
|
|
36
41
|
every("rollups", ROLLUP_PRUNE_MS, () => pruneRollups(app.db, now())),
|
|
37
|
-
every("sessions", HOUSEKEEPING_MS, () =>
|
|
42
|
+
every("sessions", HOUSEKEEPING_MS, () => pruneAuthRows(app.db)),
|
|
38
43
|
every("alerts", app.config.alertIntervalMs, () => evaluateAll(app)),
|
|
44
|
+
every("team notices", NOTICE_MS, async () => {
|
|
45
|
+
while ((await sendTeamNotices(app)) > 0)
|
|
46
|
+
;
|
|
47
|
+
}),
|
|
48
|
+
every("project health", HOUSEKEEPING_MS, () => checkHealth(app)),
|
|
49
|
+
every("digests", DIGEST_MS, () => sendDigests(app)),
|
|
39
50
|
];
|
|
40
51
|
return () => stops.forEach((stop) => stop());
|
|
41
52
|
}
|
package/dist/jobs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jobs.js","sourceRoot":"","sources":["../src/jobs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"jobs.js","sourceRoot":"","sources":["../src/jobs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Block, EmailContent } from "./content.js";
|
|
2
|
+
/** The logo, the word mark, and the status dot in the tone's color. */
|
|
3
|
+
export declare function Header({ tone }: {
|
|
4
|
+
tone: EmailContent["tone"];
|
|
5
|
+
}): import("react").JSX.Element;
|
|
6
|
+
/** One body block. A new block kind needs a case here and in text.ts. */
|
|
7
|
+
export declare function BlockView({ block }: {
|
|
8
|
+
block: Block;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
10
|
+
/** The one button, with the link written out below it for mail apps that hide buttons. */
|
|
11
|
+
export declare function Action({ action }: {
|
|
12
|
+
action: NonNullable<EmailContent["action"]>;
|
|
13
|
+
}): import("react").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=blocks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../src/mail/blocks.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAQ,MAAM,cAAc,CAAC;AAM9D,uEAAuE;AACvE,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAA;CAAE,+BAe9D;AAiDD,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,+BAKpD;AAED,0FAA0F;AAC1F,wBAAgB,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,WAAW,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAA;CAAE,+BAWjF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Column, Img, Link, Row, Section, Text } from "@react-email/components";
|
|
3
|
+
import { theme } from "./theme.js";
|
|
4
|
+
const textStyle = { margin: "0 0 16px", fontSize: "15px", lineHeight: "24px", color: theme.body };
|
|
5
|
+
const noteStyle = { margin: "0 0 16px", fontSize: "13px", lineHeight: "20px", color: theme.muted };
|
|
6
|
+
/** The logo, the word mark, and the status dot in the tone's color. */
|
|
7
|
+
export function Header({ tone }) {
|
|
8
|
+
return (_jsx(Section, { style: { padding: "24px 32px 0" }, children: _jsxs(Row, { children: [_jsx(Column, { style: { width: "32px" }, children: _jsx(Img, { src: theme.logoUrl, width: "28", height: "28", alt: "WizeLens", style: { display: "block", borderRadius: "6px" } }) }), _jsx(Column, { children: _jsxs(Text, { style: { margin: 0, fontSize: "16px", fontWeight: 700, color: theme.ink, letterSpacing: "-0.01em" }, children: ["WizeLens ", _jsx("span", { style: { color: theme.tone[tone] }, children: "\u25CF" })] }) })] }) }));
|
|
9
|
+
}
|
|
10
|
+
function Facts({ rows }) {
|
|
11
|
+
return (_jsx(Section, { style: { margin: "0 0 16px", padding: "12px 16px", background: theme.factsBg, borderRadius: "8px" }, children: rows.map((r) => (_jsxs(Row, { children: [_jsx(Column, { style: { width: "40%", padding: "4px 0", fontSize: "13px", color: theme.muted }, children: r.label }), _jsx(Column, { style: { padding: "4px 0", fontSize: "13px", color: theme.ink, fontFamily: theme.mono }, children: r.value })] }, r.label))) }));
|
|
12
|
+
}
|
|
13
|
+
/** Up to 3 numbers per row, each with its change in the tone's color. */
|
|
14
|
+
function Stats({ items }) {
|
|
15
|
+
const rows = Array.from({ length: Math.ceil(items.length / 3) }, (_, i) => items.slice(i * 3, i * 3 + 3));
|
|
16
|
+
return (_jsx(Section, { style: { margin: "0 0 16px" }, children: rows.map((row, i) => (_jsx(Row, { children: row.map((s) => (_jsxs(Column, { style: { width: "33%", padding: "8px 8px 8px 0", verticalAlign: "top" }, children: [_jsx(Text, { style: { margin: 0, fontSize: "12px", color: theme.muted }, children: s.label }), _jsx(Text, { style: { margin: "2px 0 0", fontSize: "20px", fontWeight: 700, color: theme.ink, letterSpacing: "-0.01em" }, children: s.value }), s.change && _jsx(Text, { style: { margin: "2px 0 0", fontSize: "12px", color: s.tone ? theme.tone[s.tone] : theme.muted }, children: s.change })] }, s.label))) }, i))) }));
|
|
17
|
+
}
|
|
18
|
+
function List({ title, items }) {
|
|
19
|
+
return (_jsxs(Section, { style: { margin: "0 0 16px" }, children: [_jsx(Text, { style: { margin: "0 0 8px", fontSize: "13px", fontWeight: 700, color: theme.ink }, children: title }), items.map((item, i) => (_jsxs(Row, { style: { borderTop: `1px solid ${theme.line}` }, children: [_jsx(Column, { style: { padding: "8px 0", fontSize: "13px", color: theme.body, fontFamily: theme.mono, wordBreak: "break-all" }, children: item.text }), _jsx(Column, { style: { width: "30%", padding: "8px 0", fontSize: "13px", color: theme.muted, textAlign: "right" }, children: item.meta ?? "" })] }, i)))] }));
|
|
20
|
+
}
|
|
21
|
+
/** One body block. A new block kind needs a case here and in text.ts. */
|
|
22
|
+
export function BlockView({ block }) {
|
|
23
|
+
if (block.kind === "facts")
|
|
24
|
+
return _jsx(Facts, { rows: block.rows });
|
|
25
|
+
if (block.kind === "stats")
|
|
26
|
+
return _jsx(Stats, { items: block.items });
|
|
27
|
+
if (block.kind === "list")
|
|
28
|
+
return _jsx(List, { title: block.title, items: block.items });
|
|
29
|
+
return _jsx(Text, { style: block.kind === "note" ? noteStyle : textStyle, children: block.text });
|
|
30
|
+
}
|
|
31
|
+
/** The one button, with the link written out below it for mail apps that hide buttons. */
|
|
32
|
+
export function Action({ action }) {
|
|
33
|
+
return (_jsxs(Section, { style: { margin: "8px 0 24px" }, children: [_jsx(Button, { href: action.url, style: { background: theme.accent, color: theme.accentText, fontSize: "15px", fontWeight: 600, padding: "12px 20px", borderRadius: "8px" }, children: action.label }), _jsxs(Text, { style: { ...noteStyle, margin: "16px 0 0", wordBreak: "break-all" }, children: ["Or open this link: ", _jsx(Link, { href: action.url, style: { color: theme.accent }, children: action.url })] })] }));
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks.js","sourceRoot":"","sources":["../../src/mail/blocks.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { MailKind } from "./mailer.js";
|
|
2
|
+
import type { Tone } from "./theme.js";
|
|
3
|
+
/** One part of an email body. The layout decides how each kind looks; the text version uses the same parts. */
|
|
4
|
+
export type Block = {
|
|
5
|
+
kind: "text";
|
|
6
|
+
text: string;
|
|
7
|
+
} | {
|
|
8
|
+
kind: "facts";
|
|
9
|
+
rows: {
|
|
10
|
+
label: string;
|
|
11
|
+
value: string;
|
|
12
|
+
}[];
|
|
13
|
+
} | {
|
|
14
|
+
kind: "note";
|
|
15
|
+
text: string;
|
|
16
|
+
}
|
|
17
|
+
/** Numbers side by side, each with how it changed. */
|
|
18
|
+
| {
|
|
19
|
+
kind: "stats";
|
|
20
|
+
items: Stat[];
|
|
21
|
+
}
|
|
22
|
+
/** A titled list, for example the slowest endpoints. */
|
|
23
|
+
| {
|
|
24
|
+
kind: "list";
|
|
25
|
+
title: string;
|
|
26
|
+
items: {
|
|
27
|
+
text: string;
|
|
28
|
+
meta?: string;
|
|
29
|
+
}[];
|
|
30
|
+
};
|
|
31
|
+
export interface Stat {
|
|
32
|
+
label: string;
|
|
33
|
+
value: string;
|
|
34
|
+
/** "+12% vs last week". */
|
|
35
|
+
change?: string;
|
|
36
|
+
tone?: Tone;
|
|
37
|
+
}
|
|
38
|
+
/** What an email says, with no markup. Templates in emails.ts make these; layout.tsx and text.ts draw them. */
|
|
39
|
+
export interface EmailContent {
|
|
40
|
+
kind: MailKind;
|
|
41
|
+
subject: string;
|
|
42
|
+
/** The line inboxes show after the subject. */
|
|
43
|
+
preview: string;
|
|
44
|
+
heading: string;
|
|
45
|
+
/** The status dot next to the logo: blue for account mail, red when an alert fires, green when it resolves. */
|
|
46
|
+
tone: Tone;
|
|
47
|
+
blocks: Block[];
|
|
48
|
+
action?: {
|
|
49
|
+
label: string;
|
|
50
|
+
url: string;
|
|
51
|
+
};
|
|
52
|
+
/** Why the person got this email. */
|
|
53
|
+
footer: string;
|
|
54
|
+
/** For repeated mail: a one-click stop link, also sent as the List-Unsubscribe header. */
|
|
55
|
+
unsubscribe?: {
|
|
56
|
+
label: string;
|
|
57
|
+
url: string;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export declare const text: (t: string) => Block;
|
|
61
|
+
export declare const note: (t: string) => Block;
|
|
62
|
+
export declare const facts: (rows: [string, string][]) => Block;
|
|
63
|
+
export declare const stats: (items: Stat[]) => Block;
|
|
64
|
+
export declare const list: (title: string, items: {
|
|
65
|
+
text: string;
|
|
66
|
+
meta?: string;
|
|
67
|
+
}[]) => Block;
|
|
68
|
+
//# sourceMappingURL=content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/mail/content.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,+GAA+G;AAC/G,MAAM,MAAM,KAAK,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAChC,sDAAsD;GACpD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE;AAClC,wDAAwD;GACtD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC;AAE9E,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AAED,+GAA+G;AAC/G,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,+GAA+G;IAC/G,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,WAAW,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAED,eAAO,MAAM,IAAI,MAAO,MAAM,KAAG,KAAoC,CAAC;AACtE,eAAO,MAAM,IAAI,MAAO,MAAM,KAAG,KAAoC,CAAC;AACtE,eAAO,MAAM,KAAK,SAAU,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAG,KAAoF,CAAC;AACtI,eAAO,MAAM,KAAK,UAAW,IAAI,EAAE,KAAG,KAAmC,CAAC;AAC1E,eAAO,MAAM,IAAI,UAAW,MAAM,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,KAAG,KAAyC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const text = (t) => ({ kind: "text", text: t });
|
|
2
|
+
export const note = (t) => ({ kind: "note", text: t });
|
|
3
|
+
export const facts = (rows) => ({ kind: "facts", rows: rows.map(([label, value]) => ({ label, value })) });
|
|
4
|
+
export const stats = (items) => ({ kind: "stats", items });
|
|
5
|
+
export const list = (title, items) => ({ kind: "list", title, items });
|
|
6
|
+
//# sourceMappingURL=content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/mail/content.ts"],"names":[],"mappings":"AAsCA,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAS,EAAS,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AACtE,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAS,EAAS,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AACtE,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,IAAwB,EAAS,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AACtI,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAa,EAAS,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;AAC1E,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,KAAwC,EAAS,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DigestData } from "../notify/digest-data.js";
|
|
2
|
+
import type { DigestPeriod } from "../repo/mail-prefs.js";
|
|
3
|
+
import { type EmailContent } from "./content.js";
|
|
4
|
+
export interface DigestLinks {
|
|
5
|
+
project: string;
|
|
6
|
+
stop: string;
|
|
7
|
+
}
|
|
8
|
+
/** One project's day, week, or month: headline numbers with their change, then errors, slow endpoints, and insights. */
|
|
9
|
+
export declare function digest(project: string, org: string, period: DigestPeriod, d: DigestData, links: DigestLinks): EmailContent;
|
|
10
|
+
//# sourceMappingURL=emails-digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emails-digest.d.ts","sourceRoot":"","sources":["../../src/mail/emails-digest.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAc,KAAK,YAAY,EAA0B,MAAM,cAAc,CAAC;AA6BrF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wHAAwH;AACxH,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,YAAY,CAwB1H"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { list, stats } from "./content.js";
|
|
2
|
+
const WORD = {
|
|
3
|
+
daily: { noun: "day", vs: "vs the day before", adj: "daily" },
|
|
4
|
+
weekly: { noun: "week", vs: "vs last week", adj: "weekly" },
|
|
5
|
+
monthly: { noun: "month", vs: "vs the 30 days before", adj: "monthly" },
|
|
6
|
+
};
|
|
7
|
+
const count = (v) => (v === null ? "–" : Math.round(v).toLocaleString("en-US"));
|
|
8
|
+
const ms = (v) => (v === null ? "–" : v >= 1000 ? `${(v / 1000).toFixed(1)} s` : `${Math.round(v)} ms`);
|
|
9
|
+
const pct = (v) => (v === null ? "–" : `${v.toFixed(v < 10 ? 1 : 0)}%`);
|
|
10
|
+
/** "+12% vs last week" in red when a bigger number is worse, green when it is better. `null`: neither, for traffic. */
|
|
11
|
+
function stat(label, h, show, vs, higherIsBad) {
|
|
12
|
+
if (h.change === null || h.previous === null)
|
|
13
|
+
return { label, value: show(h.value) };
|
|
14
|
+
const up = h.change > 0;
|
|
15
|
+
const change = Math.abs(h.change) < 0.5 ? `same ${vs}` : `${up ? "+" : "−"}${Math.abs(Math.round(h.change))}% ${vs}`;
|
|
16
|
+
const tone = Math.abs(h.change) < 0.5 || higherIsBad === null ? undefined : up === higherIsBad ? "bad" : "good";
|
|
17
|
+
return { label, value: show(h.value), change, tone };
|
|
18
|
+
}
|
|
19
|
+
function lists(d) {
|
|
20
|
+
const out = [];
|
|
21
|
+
if (d.errors.length)
|
|
22
|
+
out.push(list("Top errors", d.errors.map((e) => ({ text: `${e.type}: ${e.message}`.slice(0, 140), meta: `${count(e.count)} times` }))));
|
|
23
|
+
if (d.slowest.length)
|
|
24
|
+
out.push(list("Slowest endpoints (p95)", d.slowest.map((s) => ({ text: s.endpoint, meta: `${ms(s.p95Ms)} · ${count(s.count)} calls` }))));
|
|
25
|
+
if (d.insights.length)
|
|
26
|
+
out.push(list("Insights", d.insights.map((i) => ({ text: i.title, meta: `${count(i.occurrences)} requests` }))));
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
/** One project's day, week, or month: headline numbers with their change, then errors, slow endpoints, and insights. */
|
|
30
|
+
export function digest(project, org, period, d, links) {
|
|
31
|
+
const w = WORD[period];
|
|
32
|
+
const errorsUp = (d.errorRate.change ?? 0) >= 0.5 && (d.errorRate.value ?? 0) > 0;
|
|
33
|
+
return {
|
|
34
|
+
kind: "digest",
|
|
35
|
+
subject: `${project}: your ${w.noun} on WizeLens (${count(d.requests.value)} requests, ${pct(d.errorRate.value)} errors)`,
|
|
36
|
+
preview: `${count(d.requests.value)} requests, ${pct(d.errorRate.value)} errors, p95 ${ms(d.p95Ms)}.`,
|
|
37
|
+
heading: `Your ${w.noun} in ${project}.`,
|
|
38
|
+
tone: errorsUp || d.alertsFired > 0 ? "warn" : "good",
|
|
39
|
+
blocks: [
|
|
40
|
+
stats([
|
|
41
|
+
stat("Requests", d.requests, count, w.vs, null),
|
|
42
|
+
stat("Error rate", d.errorRate, pct, w.vs, true),
|
|
43
|
+
stat("Average time", d.avgMs, ms, w.vs, true),
|
|
44
|
+
{ label: "p95 time", value: ms(d.p95Ms) },
|
|
45
|
+
stat("SQL queries", d.sqlQueries, count, w.vs, true),
|
|
46
|
+
{ label: "Alerts fired", value: count(d.alertsFired), tone: d.alertsFired ? "bad" : undefined },
|
|
47
|
+
]),
|
|
48
|
+
...lists(d),
|
|
49
|
+
],
|
|
50
|
+
action: { label: `Open ${project}`, url: links.project },
|
|
51
|
+
footer: `You get the ${w.adj} digest of ${project} because you are a member of ${org}. Pick digests on your Account page.`,
|
|
52
|
+
unsubscribe: { label: `Stop the ${w.adj} digest for ${project}`, url: links.stop },
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=emails-digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emails-digest.js","sourceRoot":"","sources":["../../src/mail/emails-digest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type EmailContent } from "./content.js";
|
|
2
|
+
/** A project that sends data around the clock stopped. */
|
|
3
|
+
export declare function projectQuiet(project: string, org: string, lastMs: number, nowMs: number, url: string, stop: string): EmailContent;
|
|
4
|
+
/** Data arrives again after a quiet notice. */
|
|
5
|
+
export declare function projectBack(project: string, org: string, quietMs: number, url: string, stop: string): EmailContent;
|
|
6
|
+
//# sourceMappingURL=emails-health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emails-health.d.ts","sourceRoot":"","sources":["../../src/mail/emails-health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAe,MAAM,cAAc,CAAC;AAK9D,0DAA0D;AAC1D,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAgBjI;AAED,+CAA+C;AAC/C,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAYlH"}
|