@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.
Files changed (275) hide show
  1. package/README.md +57 -5
  2. package/dist/alerts/evaluate.d.ts.map +1 -1
  3. package/dist/alerts/evaluate.js +17 -2
  4. package/dist/alerts/evaluate.js.map +1 -1
  5. package/dist/alerts/notify.d.ts +13 -2
  6. package/dist/alerts/notify.d.ts.map +1 -1
  7. package/dist/alerts/notify.js +22 -16
  8. package/dist/alerts/notify.js.map +1 -1
  9. package/dist/app.d.ts +10 -2
  10. package/dist/app.d.ts.map +1 -1
  11. package/dist/auth/auth.d.ts +51 -0
  12. package/dist/auth/auth.d.ts.map +1 -0
  13. package/dist/auth/auth.js +63 -0
  14. package/dist/auth/auth.js.map +1 -0
  15. package/dist/auth/bridge.d.ts +7 -0
  16. package/dist/auth/bridge.d.ts.map +1 -0
  17. package/dist/auth/bridge.js +39 -0
  18. package/dist/auth/bridge.js.map +1 -0
  19. package/dist/auth/crypto.d.ts +0 -5
  20. package/dist/auth/crypto.d.ts.map +1 -1
  21. package/dist/auth/crypto.js +3 -20
  22. package/dist/auth/crypto.js.map +1 -1
  23. package/dist/auth/delete-user.d.ts +16 -0
  24. package/dist/auth/delete-user.d.ts.map +1 -0
  25. package/dist/auth/delete-user.js +21 -0
  26. package/dist/auth/delete-user.js.map +1 -0
  27. package/dist/auth/deps.d.ts +27 -0
  28. package/dist/auth/deps.d.ts.map +1 -0
  29. package/dist/auth/deps.js +3 -0
  30. package/dist/auth/deps.js.map +1 -0
  31. package/dist/auth/email-token.d.ts +8 -0
  32. package/dist/auth/email-token.d.ts.map +1 -0
  33. package/dist/auth/email-token.js +15 -0
  34. package/dist/auth/email-token.js.map +1 -0
  35. package/dist/auth/hooks.d.ts +4 -0
  36. package/dist/auth/hooks.d.ts.map +1 -0
  37. package/dist/auth/hooks.js +143 -0
  38. package/dist/auth/hooks.js.map +1 -0
  39. package/dist/auth/options.d.ts +17 -0
  40. package/dist/auth/options.d.ts.map +1 -0
  41. package/dist/auth/options.js +98 -0
  42. package/dist/auth/options.js.map +1 -0
  43. package/dist/auth/password.d.ts +10 -0
  44. package/dist/auth/password.d.ts.map +1 -0
  45. package/dist/auth/password.js +22 -0
  46. package/dist/auth/password.js.map +1 -0
  47. package/dist/auth/plugins.d.ts +4 -0
  48. package/dist/auth/plugins.d.ts.map +1 -0
  49. package/dist/auth/plugins.js +45 -0
  50. package/dist/auth/plugins.js.map +1 -0
  51. package/dist/auth/principal.d.ts +8 -3
  52. package/dist/auth/principal.d.ts.map +1 -1
  53. package/dist/auth/principal.js +13 -8
  54. package/dist/auth/principal.js.map +1 -1
  55. package/dist/auth/roles.d.ts +43 -3
  56. package/dist/auth/roles.d.ts.map +1 -1
  57. package/dist/auth/roles.js +15 -6
  58. package/dist/auth/roles.js.map +1 -1
  59. package/dist/auth/schema-names.d.ts +130 -0
  60. package/dist/auth/schema-names.d.ts.map +1 -0
  61. package/dist/auth/schema-names.js +53 -0
  62. package/dist/auth/schema-names.js.map +1 -0
  63. package/dist/auth/secret.d.ts +12 -0
  64. package/dist/auth/secret.d.ts.map +1 -0
  65. package/dist/auth/secret.js +32 -0
  66. package/dist/auth/secret.js.map +1 -0
  67. package/dist/auth/security-notices.d.ts +34 -0
  68. package/dist/auth/security-notices.d.ts.map +1 -0
  69. package/dist/auth/security-notices.js +81 -0
  70. package/dist/auth/security-notices.js.map +1 -0
  71. package/dist/auth/signup.d.ts +23 -0
  72. package/dist/auth/signup.d.ts.map +1 -0
  73. package/dist/auth/signup.js +61 -0
  74. package/dist/auth/signup.js.map +1 -0
  75. package/dist/auth/sso.d.ts +21 -0
  76. package/dist/auth/sso.d.ts.map +1 -0
  77. package/dist/auth/sso.js +35 -0
  78. package/dist/auth/sso.js.map +1 -0
  79. package/dist/auth/wire.d.ts +16 -0
  80. package/dist/auth/wire.d.ts.map +1 -0
  81. package/dist/auth/wire.js +47 -0
  82. package/dist/auth/wire.js.map +1 -0
  83. package/dist/cli-args.d.ts +1 -1
  84. package/dist/cli-args.d.ts.map +1 -1
  85. package/dist/cli-args.js +55 -14
  86. package/dist/cli-args.js.map +1 -1
  87. package/dist/cli.js +18 -2
  88. package/dist/cli.js.map +1 -1
  89. package/dist/config.d.ts +26 -4
  90. package/dist/config.d.ts.map +1 -1
  91. package/dist/config.js +35 -0
  92. package/dist/config.js.map +1 -1
  93. package/dist/db/db.d.ts +5 -2
  94. package/dist/db/db.d.ts.map +1 -1
  95. package/dist/db/db.js +15 -8
  96. package/dist/db/db.js.map +1 -1
  97. package/dist/db/migrate.d.ts +2 -2
  98. package/dist/db/migrate.d.ts.map +1 -1
  99. package/dist/db/migrate.js +15 -5
  100. package/dist/db/migrate.js.map +1 -1
  101. package/dist/db/schema-auth.d.ts +2 -0
  102. package/dist/db/schema-auth.d.ts.map +1 -0
  103. package/dist/db/schema-auth.js +93 -0
  104. package/dist/db/schema-auth.js.map +1 -0
  105. package/dist/db/schema-mail.d.ts +2 -0
  106. package/dist/db/schema-mail.d.ts.map +1 -0
  107. package/dist/db/schema-mail.js +8 -0
  108. package/dist/db/schema-mail.js.map +1 -0
  109. package/dist/db/schema-notify.d.ts +2 -0
  110. package/dist/db/schema-notify.d.ts.map +1 -0
  111. package/dist/db/schema-notify.js +26 -0
  112. package/dist/db/schema-notify.js.map +1 -0
  113. package/dist/db/schema-sso.d.ts +2 -0
  114. package/dist/db/schema-sso.d.ts.map +1 -0
  115. package/dist/db/schema-sso.js +17 -0
  116. package/dist/db/schema-sso.js.map +1 -0
  117. package/dist/db/schema.d.ts.map +1 -1
  118. package/dist/db/schema.js +8 -0
  119. package/dist/db/schema.js.map +1 -1
  120. package/dist/http/http.d.ts +2 -0
  121. package/dist/http/http.d.ts.map +1 -1
  122. package/dist/http/http.js +7 -3
  123. package/dist/http/http.js.map +1 -1
  124. package/dist/jobs.d.ts +1 -1
  125. package/dist/jobs.d.ts.map +1 -1
  126. package/dist/jobs.js +14 -3
  127. package/dist/jobs.js.map +1 -1
  128. package/dist/mail/blocks.d.ts +14 -0
  129. package/dist/mail/blocks.d.ts.map +1 -0
  130. package/dist/mail/blocks.js +35 -0
  131. package/dist/mail/blocks.js.map +1 -0
  132. package/dist/mail/content.d.ts +68 -0
  133. package/dist/mail/content.d.ts.map +1 -0
  134. package/dist/mail/content.js +6 -0
  135. package/dist/mail/content.js.map +1 -0
  136. package/dist/mail/emails-digest.d.ts +10 -0
  137. package/dist/mail/emails-digest.d.ts.map +1 -0
  138. package/dist/mail/emails-digest.js +55 -0
  139. package/dist/mail/emails-digest.js.map +1 -0
  140. package/dist/mail/emails-health.d.ts +6 -0
  141. package/dist/mail/emails-health.d.ts.map +1 -0
  142. package/dist/mail/emails-health.js +36 -0
  143. package/dist/mail/emails-health.js.map +1 -0
  144. package/dist/mail/emails-security.d.ts +14 -0
  145. package/dist/mail/emails-security.d.ts.map +1 -0
  146. package/dist/mail/emails-security.js +27 -0
  147. package/dist/mail/emails-security.js.map +1 -0
  148. package/dist/mail/emails-team.d.ts +11 -0
  149. package/dist/mail/emails-team.d.ts.map +1 -0
  150. package/dist/mail/emails-team.js +45 -0
  151. package/dist/mail/emails-team.js.map +1 -0
  152. package/dist/mail/emails.d.ts +9 -0
  153. package/dist/mail/emails.d.ts.map +1 -0
  154. package/dist/mail/emails.js +49 -0
  155. package/dist/mail/emails.js.map +1 -0
  156. package/dist/mail/layout.d.ts +6 -0
  157. package/dist/mail/layout.d.ts.map +1 -0
  158. package/dist/mail/layout.js +10 -0
  159. package/dist/mail/layout.js.map +1 -0
  160. package/dist/mail/mailer.d.ts +25 -0
  161. package/dist/mail/mailer.d.ts.map +1 -0
  162. package/dist/mail/mailer.js +49 -0
  163. package/dist/mail/mailer.js.map +1 -0
  164. package/dist/mail/preview.d.ts +6 -0
  165. package/dist/mail/preview.d.ts.map +1 -0
  166. package/dist/mail/preview.js +26 -0
  167. package/dist/mail/preview.js.map +1 -0
  168. package/dist/mail/resend.d.ts +11 -0
  169. package/dist/mail/resend.d.ts.map +1 -0
  170. package/dist/mail/resend.js +34 -0
  171. package/dist/mail/resend.js.map +1 -0
  172. package/dist/mail/samples.d.ts +3 -0
  173. package/dist/mail/samples.d.ts.map +1 -0
  174. package/dist/mail/samples.js +63 -0
  175. package/dist/mail/samples.js.map +1 -0
  176. package/dist/mail/stop-route.d.ts +4 -0
  177. package/dist/mail/stop-route.d.ts.map +1 -0
  178. package/dist/mail/stop-route.js +41 -0
  179. package/dist/mail/stop-route.js.map +1 -0
  180. package/dist/mail/svix.d.ts +8 -0
  181. package/dist/mail/svix.d.ts.map +1 -0
  182. package/dist/mail/svix.js +17 -0
  183. package/dist/mail/svix.js.map +1 -0
  184. package/dist/mail/templates.d.ts +12 -0
  185. package/dist/mail/templates.d.ts.map +1 -0
  186. package/dist/mail/templates.js +18 -0
  187. package/dist/mail/templates.js.map +1 -0
  188. package/dist/mail/text.d.ts +4 -0
  189. package/dist/mail/text.d.ts.map +1 -0
  190. package/dist/mail/text.js +17 -0
  191. package/dist/mail/text.js.map +1 -0
  192. package/dist/mail/theme.d.ts +26 -0
  193. package/dist/mail/theme.d.ts.map +1 -0
  194. package/dist/mail/theme.js +21 -0
  195. package/dist/mail/theme.js.map +1 -0
  196. package/dist/mail/unsubscribe.d.ts +14 -0
  197. package/dist/mail/unsubscribe.d.ts.map +1 -0
  198. package/dist/mail/unsubscribe.js +39 -0
  199. package/dist/mail/unsubscribe.js.map +1 -0
  200. package/dist/mail/webhook.d.ts +5 -0
  201. package/dist/mail/webhook.d.ts.map +1 -0
  202. package/dist/mail/webhook.js +41 -0
  203. package/dist/mail/webhook.js.map +1 -0
  204. package/dist/notify/digest-data.d.ts +31 -0
  205. package/dist/notify/digest-data.d.ts.map +1 -0
  206. package/dist/notify/digest-data.js +37 -0
  207. package/dist/notify/digest-data.js.map +1 -0
  208. package/dist/notify/digest.d.ts +17 -0
  209. package/dist/notify/digest.d.ts.map +1 -0
  210. package/dist/notify/digest.js +76 -0
  211. package/dist/notify/digest.js.map +1 -0
  212. package/dist/notify/health.d.ts +6 -0
  213. package/dist/notify/health.d.ts.map +1 -0
  214. package/dist/notify/health.js +43 -0
  215. package/dist/notify/health.js.map +1 -0
  216. package/dist/notify/team-describe.d.ts +22 -0
  217. package/dist/notify/team-describe.d.ts.map +1 -0
  218. package/dist/notify/team-describe.js +67 -0
  219. package/dist/notify/team-describe.js.map +1 -0
  220. package/dist/notify/team.d.ts +6 -0
  221. package/dist/notify/team.d.ts.map +1 -0
  222. package/dist/notify/team.js +56 -0
  223. package/dist/notify/team.js.map +1 -0
  224. package/dist/repo/alerts.d.ts +6 -2
  225. package/dist/repo/alerts.d.ts.map +1 -1
  226. package/dist/repo/alerts.js.map +1 -1
  227. package/dist/repo/auth-prune.d.ts +4 -0
  228. package/dist/repo/auth-prune.d.ts.map +1 -0
  229. package/dist/repo/auth-prune.js +8 -0
  230. package/dist/repo/auth-prune.js.map +1 -0
  231. package/dist/repo/mail-prefs.d.ts +35 -0
  232. package/dist/repo/mail-prefs.d.ts.map +1 -0
  233. package/dist/repo/mail-prefs.js +34 -0
  234. package/dist/repo/mail-prefs.js.map +1 -0
  235. package/dist/repo/orgs.d.ts +15 -25
  236. package/dist/repo/orgs.d.ts.map +1 -1
  237. package/dist/repo/orgs.js +18 -60
  238. package/dist/repo/orgs.js.map +1 -1
  239. package/dist/repo/suppressions.d.ts +8 -0
  240. package/dist/repo/suppressions.d.ts.map +1 -0
  241. package/dist/repo/suppressions.js +16 -0
  242. package/dist/repo/suppressions.js.map +1 -0
  243. package/dist/repo/users.d.ts +5 -16
  244. package/dist/repo/users.d.ts.map +1 -1
  245. package/dist/repo/users.js +2 -60
  246. package/dist/repo/users.js.map +1 -1
  247. package/dist/routes/alerts.d.ts.map +1 -1
  248. package/dist/routes/alerts.js +23 -6
  249. package/dist/routes/alerts.js.map +1 -1
  250. package/dist/routes/index.d.ts.map +1 -1
  251. package/dist/routes/index.js +4 -2
  252. package/dist/routes/index.js.map +1 -1
  253. package/dist/routes/me.d.ts +4 -0
  254. package/dist/routes/me.d.ts.map +1 -0
  255. package/dist/routes/me.js +37 -0
  256. package/dist/routes/me.js.map +1 -0
  257. package/dist/routes/notify.d.ts +4 -0
  258. package/dist/routes/notify.d.ts.map +1 -0
  259. package/dist/routes/notify.js +55 -0
  260. package/dist/routes/notify.js.map +1 -0
  261. package/dist/routes/orgs.d.ts.map +1 -1
  262. package/dist/routes/orgs.js +30 -53
  263. package/dist/routes/orgs.js.map +1 -1
  264. package/dist/routes/projects.d.ts.map +1 -1
  265. package/dist/routes/projects.js +4 -3
  266. package/dist/routes/projects.js.map +1 -1
  267. package/dist/server.d.ts +2 -0
  268. package/dist/server.d.ts.map +1 -1
  269. package/dist/server.js +45 -14
  270. package/dist/server.js.map +1 -1
  271. package/package.json +19 -6
  272. package/dist/routes/auth.d.ts +0 -4
  273. package/dist/routes/auth.d.ts.map +0 -1
  274. package/dist/routes/auth.js +0 -106
  275. package/dist/routes/auth.js.map +0 -1
@@ -0,0 +1,22 @@
1
+ import type { Queryable } from "../db/db.js";
2
+ /** Audit actions that become team notices. MCP calls and the first organization are not news. */
3
+ export declare const NOTICED: Set<string>;
4
+ export interface AuditRow {
5
+ id: string;
6
+ org_id: string;
7
+ actor: string;
8
+ action: string;
9
+ detail: string;
10
+ time_ms: number;
11
+ }
12
+ /** Names by id, each looked up once per run. */
13
+ export declare function namesOf(q: Queryable): {
14
+ user: (id: string) => Promise<string>;
15
+ member: (id: string) => Promise<string>;
16
+ project: (id: string) => Promise<string>;
17
+ key: (id: string) => Promise<string>;
18
+ };
19
+ export type Names = ReturnType<typeof namesOf>;
20
+ /** One sentence per change, naming who did it. */
21
+ export declare function describe(row: AuditRow, names: Names): Promise<string>;
22
+ //# sourceMappingURL=team-describe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-describe.d.ts","sourceRoot":"","sources":["../../src/notify/team-describe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,iGAAiG;AACjG,eAAO,MAAM,OAAO,aAmBlB,CAAC;AAEH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gDAAgD;AAChD,wBAAgB,OAAO,CAAC,CAAC,EAAE,SAAS;IAKhC,IAAI,OAAO,MAAM;IACjB,MAAM,OAAO,MAAM;IACnB,OAAO,OAAO,MAAM;IACpB,GAAG,OAAO,MAAM;EAEnB;AAED,MAAM,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAS/C,kDAAkD;AAClD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B3E"}
@@ -0,0 +1,67 @@
1
+ /** Audit actions that become team notices. MCP calls and the first organization are not news. */
2
+ export const NOTICED = new Set([
3
+ "member.invite",
4
+ "invite.cancel",
5
+ "member.join",
6
+ "member.leave",
7
+ "member.remove",
8
+ "member.role",
9
+ "key.create",
10
+ "key.revoke",
11
+ "sso.create",
12
+ "sso.update",
13
+ "sso.delete",
14
+ "sso.verify",
15
+ "project.create",
16
+ "project.delete",
17
+ "project.clear",
18
+ "share.create",
19
+ "share.revoke",
20
+ "org.update",
21
+ ]);
22
+ /** Names by id, each looked up once per run. */
23
+ export function namesOf(q) {
24
+ const cache = new Map();
25
+ const once = (key, load) => cache.get(key) ?? (cache.set(key, load()), cache.get(key));
26
+ const one = async (sql, id, fallback) => (await q.query(sql, [id]))[0]?.v ?? fallback;
27
+ return {
28
+ user: (id) => once(`u:${id}`, () => one("SELECT name || ' (' || email || ')' AS v FROM users WHERE id = $1", id, "Someone")),
29
+ member: (id) => once(`m:${id}`, () => one("SELECT u.email AS v FROM members m JOIN users u ON u.id = m.user_id WHERE m.id = $1", id, "a member")),
30
+ project: (id) => once(`p:${id}`, () => one("SELECT name AS v FROM projects WHERE id = $1", id, "a project")),
31
+ key: (id) => once(`k:${id}`, () => one("SELECT name AS v FROM api_keys WHERE id = $1", id, "")),
32
+ };
33
+ }
34
+ const s = (v) => (typeof v === "string" ? v : "");
35
+ async function projectsText(names, ids) {
36
+ const list = Array.isArray(ids) ? await Promise.all(ids.filter((x) => typeof x === "string").map(names.project)) : [];
37
+ return list.length ? list.join(", ") : "no project";
38
+ }
39
+ /** One sentence per change, naming who did it. */
40
+ export async function describe(row, names) {
41
+ const d = JSON.parse(row.detail);
42
+ const who = row.actor.startsWith("user:") ? await names.user(row.actor.slice(5)) : "WizeLens";
43
+ const sso = `${s(d.type).toUpperCase() || "single sign-on"} for ${s(d.domain) || s(d.providerId)}`;
44
+ const project = async () => s(d.name) || (await names.project(s(d.projectId)));
45
+ const say = {
46
+ "member.invite": () => `${who} invited ${s(d.email)} as ${s(d.role) || "member"}.`,
47
+ "invite.cancel": () => `${who} canceled an invite.`,
48
+ "member.join": () => `${who} joined${d.via === "sso" ? " through single sign-on" : ""}.`,
49
+ "member.leave": () => `${who} left.`,
50
+ "member.remove": () => `${who} removed ${s(d.memberEmail) || s(d.memberIdOrEmail) || "a member"}.`,
51
+ "member.role": async () => `${who} made ${await names.member(s(d.memberId))} ${s(d.role)}.`,
52
+ "key.create": async () => `${who} made ${d.kind === "read" ? "a read key" : "an ingest key"} for ${await projectsText(names, d.projectIds)}.`,
53
+ "key.revoke": async () => `${who} revoked the key ${(await names.key(s(d.keyId))) || s(d.keyId)}.`,
54
+ "sso.create": () => `${who} added ${sso}.`,
55
+ "sso.update": () => `${who} changed ${sso}.`,
56
+ "sso.delete": () => `${who} removed ${sso}.`,
57
+ "sso.verify": () => `${who} proved the domain for ${sso}.`,
58
+ "project.create": async () => `${who} made the project ${await project()}.`,
59
+ "project.delete": async () => `${who} deleted the project ${await project()}.`,
60
+ "project.clear": async () => `${who} deleted all data of ${await project()}.`,
61
+ "share.create": async () => `${who} shared a trace from ${await project()} for ${Number(d.days) || 7} days.`,
62
+ "share.revoke": () => `${who} revoked a share link.`,
63
+ "org.update": () => `${who} changed the organization settings${typeof d.retentionDays === "number" ? ` (keep data ${d.retentionDays} days)` : ""}.`,
64
+ };
65
+ return (await say[row.action]?.()) ?? `${who}: ${row.action}.`;
66
+ }
67
+ //# sourceMappingURL=team-describe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-describe.js","sourceRoot":"","sources":["../../src/notify/team-describe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { CloudApp } from "../app.js";
2
+ /** Send team notices for new audit lines, grouped by organization. Returns how many lines it took. */
3
+ export declare function sendTeamNotices(app: CloudApp): Promise<number>;
4
+ /** Before an organization is deleted: who to tell, since members are gone after. */
5
+ export declare function orgDeletionNotice(app: CloudApp, orgId: string, actorId: string): Promise<() => void>;
6
+ //# sourceMappingURL=team.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.d.ts","sourceRoot":"","sources":["../../src/notify/team.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AA0C1C,sGAAsG;AACtG,wBAAsB,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAOpE;AAED,oFAAoF;AACpF,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAO1G"}
@@ -0,0 +1,56 @@
1
+ import { orgDeleted, roleChanged, teamChanges } from "../mail/emails-team.js";
2
+ import { renderMail } from "../mail/templates.js";
3
+ import { stopUrl } from "../mail/unsubscribe.js";
4
+ import { managersOf } from "../repo/mail-prefs.js";
5
+ import { describe, NOTICED, namesOf } from "./team-describe.js";
6
+ const BATCH = 200;
7
+ /** Take audit lines nobody was told about yet. SKIP LOCKED lets several instances share the work without sending twice. */
8
+ async function claim(app) {
9
+ return app.db.query(`UPDATE audit SET noticed = TRUE WHERE id IN (SELECT id FROM audit WHERE NOT noticed ORDER BY time_ms LIMIT ${BATCH} FOR UPDATE SKIP LOCKED)
10
+ RETURNING id, org_id, actor, action, detail, time_ms`);
11
+ }
12
+ const auditLink = (app, orgId) => `${app.baseUrl()}/_wizelens/#/team?org=${encodeURIComponent(orgId)}`;
13
+ /** A member whose role changed hears it from us too, even when they are not a manager. */
14
+ async function tellRoleChange(app, row, org) {
15
+ const d = JSON.parse(row.detail);
16
+ const [m] = await app.db.query("SELECT m.user_id, u.email, p.team FROM members m JOIN users u ON u.id = m.user_id LEFT JOIN mail_prefs p ON p.user_id = u.id WHERE m.id = $1", [d.memberId ?? ""]);
17
+ if (!m || m.team === false || row.actor === `user:${m.user_id}`)
18
+ return;
19
+ app.mailer.send(renderMail(m.email, roleChanged(org, d.role ?? "member", auditLink(app, row.org_id), stopUrl(app, m.user_id, "team"))));
20
+ }
21
+ /** One email per manager with the changes others made in that organization. */
22
+ async function noticeOrg(app, orgId, rows, names) {
23
+ const [o] = await app.db.query("SELECT name FROM orgs WHERE id = $1", [orgId]);
24
+ if (!o)
25
+ return;
26
+ for (const row of rows.filter((r) => r.action === "member.role"))
27
+ await tellRoleChange(app, row, o.name);
28
+ const changes = await Promise.all(rows.map(async (r) => ({ actor: r.actor, text: await describe(r, names), timeMs: r.time_ms })));
29
+ for (const m of await managersOf(app.db, orgId, "team", app.mailer.live)) {
30
+ const theirs = changes.filter((c) => c.actor !== `user:${m.id}`);
31
+ if (theirs.length)
32
+ app.mailer.send(renderMail(m.email, teamChanges(o.name, theirs, auditLink(app, orgId), stopUrl(app, m.id, "team"))));
33
+ }
34
+ }
35
+ /** Send team notices for new audit lines, grouped by organization. Returns how many lines it took. */
36
+ export async function sendTeamNotices(app) {
37
+ const rows = (await claim(app)).sort((a, b) => a.time_ms - b.time_ms);
38
+ const byOrg = new Map();
39
+ for (const r of rows.filter((r) => NOTICED.has(r.action)))
40
+ byOrg.set(r.org_id, [...(byOrg.get(r.org_id) ?? []), r]);
41
+ const names = namesOf(app.db);
42
+ for (const [orgId, list] of byOrg)
43
+ await noticeOrg(app, orgId, list, names);
44
+ return rows.length;
45
+ }
46
+ /** Before an organization is deleted: who to tell, since members are gone after. */
47
+ export async function orgDeletionNotice(app, orgId, actorId) {
48
+ const [o] = await app.db.query("SELECT name FROM orgs WHERE id = $1", [orgId]);
49
+ const people = await app.db.query("SELECT u.email FROM members m JOIN users u ON u.id = m.user_id WHERE m.org_id = $1 AND u.id <> $2", [orgId, actorId]);
50
+ const by = await namesOf(app.db).user(actorId);
51
+ return () => {
52
+ for (const p of people)
53
+ app.mailer.send(renderMail(p.email, orgDeleted(o?.name ?? "An organization", by, `${app.baseUrl()}/_wizelens/`)));
54
+ };
55
+ }
56
+ //# sourceMappingURL=team.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.js","sourceRoot":"","sources":["../../src/notify/team.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,13 @@
1
1
  import type { AlertMetric, AlertOp, MetricAlertStat } from "@wizeworks/lens-core";
2
2
  import type { Queryable } from "../db/db.js";
3
- export interface Channel {
3
+ /** Where a notice goes: a webhook, a Slack incoming webhook, or email to members of the organization. */
4
+ export type Channel = {
4
5
  kind: "webhook" | "slack";
5
6
  url: string;
6
- }
7
+ } | {
8
+ kind: "email";
9
+ to: string[];
10
+ };
7
11
  export interface AlertRule {
8
12
  id: string;
9
13
  projectId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../../src/repo/alerts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../../src/repo/alerts.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"alerts.js","sourceRoot":"","sources":["../../src/repo/alerts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"alerts.js","sourceRoot":"","sources":["../../src/repo/alerts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAyC1C,MAAM,YAAY,GAAG;;0DAEqC,CAAC;AAG3D,MAAM,MAAM,GAAG,CAAC,CAAU,EAAa,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAc,EAAE,CAAC,CAAC;AAEpG,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,CAAY,EAAE,SAAiB;IAC7D,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAU,UAAU,YAAY,uDAAuD,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC1I,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,CAAY;IAC7C,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAU,UAAU,YAAY,iCAAiC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACvG,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,CAAY,EAAE,SAAiB,EAAE,EAAU;IACxE,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CAAU,UAAU,YAAY,qDAAqD,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;IACnI,OAAO,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,CAAY,EAAE,SAAiB,EAAE,CAAY,EAAE,EAAU,EAAE,GAAW;IACrG,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,CAAC,CAAC,KAAK,CACX;;+EAE2E,EAC3E,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,aAAa,CAAC,CACrK,CAAC;IACF,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,CAAY,EAAE,SAAiB,EAAE,EAAU,EAAE,CAAY;IACxF,MAAM,CAAC,CAAC,KAAK,CACX;oJACgJ,EAChJ,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,aAAa,CAAC,CAC5J,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,CAAY,EAAE,SAAiB,EAAE,EAAU;IAC1E,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,wEAAwE,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC/H,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,CAAY,EAAE,EAAU,EAAE,KAAyB,EAAE,KAAoB,EAAE,GAAW;IACzH,MAAM,CAAC,CAAC,KAAK,CAAC,qFAAqF,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;AAChI,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,CAAY,EAAE,IAAe,EAAE,CAA+D;IAC3H,MAAM,CAAC,CAAC,KAAK,CACX,oJAAoJ,EACpJ,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,CACrG,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAY,EAAE,SAAiB,EAAE,KAAa,EAAyB,EAAE,CAClG,CAAC,CAAC,KAAK,CACL;yHACqH,EACrH,CAAC,SAAS,EAAE,KAAK,CAAC,CACnB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Queryable } from "../db/db.js";
2
+ /** Remove expired sessions and links, and sign-in counters older than a day. Better Auth ignores them already; this keeps the tables small. */
3
+ export declare function pruneAuthRows(q: Queryable): Promise<void>;
4
+ //# sourceMappingURL=auth-prune.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-prune.d.ts","sourceRoot":"","sources":["../../src/repo/auth-prune.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,+IAA+I;AAC/I,wBAAsB,aAAa,CAAC,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAK/D"}
@@ -0,0 +1,8 @@
1
+ /** Remove expired sessions and links, and sign-in counters older than a day. Better Auth ignores them already; this keeps the tables small. */
2
+ export async function pruneAuthRows(q) {
3
+ await q.query("DELETE FROM sessions WHERE expires_at < now()");
4
+ await q.query("DELETE FROM verifications WHERE expires_at < now()");
5
+ await q.query("DELETE FROM rate_limits WHERE last_request < $1", [Date.now() - 86_400_000]);
6
+ await q.query("DELETE FROM invites WHERE status <> 'pending' AND created_at < now() - interval '90 days'");
7
+ }
8
+ //# sourceMappingURL=auth-prune.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-prune.js","sourceRoot":"","sources":["../../src/repo/auth-prune.ts"],"names":[],"mappings":"AAEA,+IAA+I;AAC/I,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,CAAY;IAC9C,MAAM,CAAC,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAC/D,MAAM,CAAC,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACpE,MAAM,CAAC,CAAC,KAAK,CAAC,iDAAiD,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC;IAC5F,MAAM,CAAC,CAAC,KAAK,CAAC,2FAA2F,CAAC,CAAC;AAC7G,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { Queryable } from "../db/db.js";
2
+ export type DigestPeriod = "daily" | "weekly" | "monthly";
3
+ export declare const DIGEST_PERIODS: readonly DigestPeriod[];
4
+ /** A project with no saved choice gets the weekly digest only. */
5
+ export declare const DEFAULT_DIGEST: Record<DigestPeriod, boolean>;
6
+ export interface MailPrefs {
7
+ team: boolean;
8
+ health: boolean;
9
+ /** Off stops every digest, for projects made later too. */
10
+ digests: boolean;
11
+ timeZone: string;
12
+ /** Local hour digests go out, 0 to 23. */
13
+ digestHour: number;
14
+ }
15
+ export declare const DEFAULT_PREFS: MailPrefs;
16
+ /** What a stop link turns off: team or health notices, one digest of one project, or every digest. */
17
+ export type StopScope = "team" | "health" | "digests" | {
18
+ projectId: string;
19
+ period: DigestPeriod;
20
+ };
21
+ export declare function prefsOf(q: Queryable, userId: string): Promise<MailPrefs>;
22
+ export declare function savePrefs(q: Queryable, userId: string, patch: Partial<MailPrefs>): Promise<MailPrefs>;
23
+ /** Saved digest choices by project. Projects not in the map use DEFAULT_DIGEST. */
24
+ export declare function digestPrefsOf(q: Queryable, userId: string): Promise<Map<string, Record<DigestPeriod, boolean>>>;
25
+ export declare function saveDigestPref(q: Queryable, userId: string, projectId: string, patch: Partial<Record<DigestPeriod, boolean>>): Promise<void>;
26
+ /** Turn off what a stop link names. */
27
+ export declare function applyStop(q: Queryable, userId: string, scope: StopScope): Promise<void>;
28
+ export interface Recipient {
29
+ id: string;
30
+ email: string;
31
+ name: string;
32
+ }
33
+ /** Owners and admins of an organization who keep this kind of notice on. With real mail, only confirmed addresses. */
34
+ export declare const managersOf: (q: Queryable, orgId: string, pref: "team" | "health", confirmedOnly: boolean) => Promise<Recipient[]>;
35
+ //# sourceMappingURL=mail-prefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-prefs.d.ts","sourceRoot":"","sources":["../../src/repo/mail-prefs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC1D,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAAmC,CAAC;AACtF,kEAAkE;AAClE,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,YAAY,EAAE,OAAO,CAAkD,CAAC;AAE5G,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,EAAE,SAAuF,CAAC;AAEpH,sGAAsG;AACtG,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,CAAC;AAIpG,wBAAsB,OAAO,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAG9E;AAED,wBAAsB,SAAS,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CAQ3G;AAED,mFAAmF;AACnF,wBAAsB,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,CAGrH;AAED,wBAAsB,cAAc,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlJ;AAED,uCAAuC;AACvC,wBAAsB,SAAS,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAG7F;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,sHAAsH;AACtH,eAAO,MAAM,UAAU,MAAa,SAAS,SAAS,MAAM,QAAQ,MAAM,GAAG,QAAQ,iBAAiB,OAAO,KAAG,OAAO,CAAC,SAAS,EAAE,CAKhI,CAAC"}
@@ -0,0 +1,34 @@
1
+ export const DIGEST_PERIODS = ["daily", "weekly", "monthly"];
2
+ /** A project with no saved choice gets the weekly digest only. */
3
+ export const DEFAULT_DIGEST = { daily: false, weekly: true, monthly: false };
4
+ export const DEFAULT_PREFS = { team: true, health: true, digests: true, timeZone: "UTC", digestHour: 8 };
5
+ export async function prefsOf(q, userId) {
6
+ const [r] = await q.query("SELECT team, health, digests, time_zone, digest_hour FROM mail_prefs WHERE user_id = $1", [userId]);
7
+ return r ? { team: r.team, health: r.health, digests: r.digests, timeZone: r.time_zone, digestHour: r.digest_hour } : { ...DEFAULT_PREFS };
8
+ }
9
+ export async function savePrefs(q, userId, patch) {
10
+ const p = { ...(await prefsOf(q, userId)), ...patch };
11
+ await q.query(`INSERT INTO mail_prefs (user_id, team, health, digests, time_zone, digest_hour) VALUES ($1, $2, $3, $4, $5, $6)
12
+ ON CONFLICT (user_id) DO UPDATE SET team = $2, health = $3, digests = $4, time_zone = $5, digest_hour = $6`, [userId, p.team, p.health, p.digests, p.timeZone, p.digestHour]);
13
+ return p;
14
+ }
15
+ /** Saved digest choices by project. Projects not in the map use DEFAULT_DIGEST. */
16
+ export async function digestPrefsOf(q, userId) {
17
+ const rows = await q.query("SELECT project_id, daily, weekly, monthly FROM digest_prefs WHERE user_id = $1", [userId]);
18
+ return new Map(rows.map((r) => [r.project_id, { daily: r.daily, weekly: r.weekly, monthly: r.monthly }]));
19
+ }
20
+ export async function saveDigestPref(q, userId, projectId, patch) {
21
+ const p = { ...((await digestPrefsOf(q, userId)).get(projectId) ?? DEFAULT_DIGEST), ...patch };
22
+ await q.query(`INSERT INTO digest_prefs (user_id, project_id, daily, weekly, monthly) VALUES ($1, $2, $3, $4, $5)
23
+ ON CONFLICT (user_id, project_id) DO UPDATE SET daily = $3, weekly = $4, monthly = $5`, [userId, projectId, p.daily, p.weekly, p.monthly]);
24
+ }
25
+ /** Turn off what a stop link names. */
26
+ export async function applyStop(q, userId, scope) {
27
+ if (typeof scope === "object")
28
+ return saveDigestPref(q, userId, scope.projectId, { [scope.period]: false });
29
+ await savePrefs(q, userId, { [scope]: false });
30
+ }
31
+ /** Owners and admins of an organization who keep this kind of notice on. With real mail, only confirmed addresses. */
32
+ export const managersOf = async (q, orgId, pref, confirmedOnly) => q.query(`SELECT u.id, u.email, u.name FROM members m JOIN users u ON u.id = m.user_id LEFT JOIN mail_prefs p ON p.user_id = u.id
33
+ WHERE m.org_id = $1 AND m.role IN ('owner', 'admin') AND COALESCE(p.${pref}, TRUE) AND (u.email_verified OR NOT $2) ORDER BY u.email`, [orgId, confirmedOnly]);
34
+ //# sourceMappingURL=mail-prefs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-prefs.js","sourceRoot":"","sources":["../../src/repo/mail-prefs.ts"],"names":[],"mappings":"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"}
@@ -10,38 +10,28 @@ export interface Membership extends Org {
10
10
  role: Role;
11
11
  }
12
12
  export interface Member {
13
+ /** The membership id Better Auth uses to change a role. */
14
+ memberId: string;
13
15
  userId: string;
14
16
  email: string;
15
17
  name: string;
16
18
  role: Role;
17
19
  sinceMs: number;
18
20
  }
19
- /** A new organization with `ownerId` as its owner. */
20
- export declare function createOrg(q: Queryable, name: string, ownerId: string, now: number, retentionDays?: number): Promise<Org>;
21
- export declare const orgsOfUser: (q: Queryable, userId: string) => Promise<Membership[]>;
22
- export declare function membership(q: Queryable, userId: string, orgId: string): Promise<Membership | undefined>;
23
- export declare function updateOrg(q: Queryable, orgId: string, change: {
24
- name?: string;
25
- retentionDays?: number;
26
- }): Promise<void>;
27
- export declare const listMembers: (q: Queryable, orgId: string) => Promise<Member[]>;
28
- export declare function setRole(q: Queryable, orgId: string, userId: string, role: Role): Promise<void>;
29
- export declare function removeMember(q: Queryable, orgId: string, userId: string): Promise<void>;
30
- export declare function ownerCount(q: Queryable, orgId: string): Promise<number>;
31
- /** A new invite link token for one email address. Valid for 7 days. */
32
- export declare function createInvite(q: Queryable, orgId: string, email: string, role: Role, by: string, now: number): Promise<string>;
33
- export interface Invite {
34
- orgId: string;
35
- orgName: string;
36
- email: string;
37
- role: Role;
38
- }
39
- export declare function openInvite(q: Queryable, token: string, now: number): Promise<Invite | undefined>;
40
- /** Join the organization of an open invite. The invite then cannot be used again. */
41
- export declare function acceptInvite(q: Queryable, token: string, userId: string, now: number): Promise<Invite | undefined>;
42
- export declare const pendingInvites: (q: Queryable, orgId: string, now: number) => Promise<{
21
+ export interface PendingInvite {
22
+ id: string;
43
23
  email: string;
44
24
  role: Role;
45
25
  expiresMs: number;
46
- }[]>;
26
+ }
27
+ /** A slug no organization has yet, from the name. */
28
+ export declare function freeSlug(q: Queryable, name: string): Promise<string>;
29
+ export declare const orgsOfUser: (q: Queryable, userId: string) => Promise<Membership[]>;
30
+ export declare function membership(q: Queryable, userId: string, orgId: string): Promise<Membership | undefined>;
31
+ export declare function setRetention(q: Queryable, orgId: string, retentionDays: number): Promise<void>;
32
+ export declare const listMembers: (q: Queryable, orgId: string) => Promise<Member[]>;
33
+ /** Open invites. Their ids are the secret part of the link, so only managers see them. */
34
+ export declare const pendingInvites: (q: Queryable, orgId: string) => Promise<PendingInvite[]>;
35
+ /** Delete an organization: every project's data first, then the row (members, invites, projects, keys, alerts, and shares go with it). */
36
+ export declare function deleteOrgEverything(q: Queryable, orgId: string): Promise<void>;
47
37
  //# sourceMappingURL=orgs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"orgs.d.ts","sourceRoot":"","sources":["../../src/repo/orgs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orgs.d.ts","sourceRoot":"","sources":["../../src/repo/orgs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAK7C,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAW,SAAQ,GAAG;IACrC,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,MAAM,WAAW,MAAM;IACrB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,qDAAqD;AACrD,wBAAsB,QAAQ,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM1E;AAED,eAAO,MAAM,UAAU,MAAO,SAAS,UAAU,MAAM,KAAG,OAAO,CAAC,UAAU,EAAE,CACqE,CAAC;AAEpJ,wBAAsB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAG7G;AAED,wBAAsB,YAAY,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpG;AAED,eAAO,MAAM,WAAW,MAAO,SAAS,SAAS,MAAM,KAAG,OAAO,CAAC,MAAM,EAAE,CAKvE,CAAC;AAEJ,0FAA0F;AAC1F,eAAO,MAAM,cAAc,MAAO,SAAS,SAAS,MAAM,KAAG,OAAO,CAAC,aAAa,EAAE,CAIjF,CAAC;AAEJ,0IAA0I;AAC1I,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpF"}
package/dist/repo/orgs.js CHANGED
@@ -1,8 +1,9 @@
1
- import { hashToken, newId, newToken, slugOf } from "../auth/crypto.js";
2
- import { normalizeEmail } from "./users.js";
3
- const INVITE_MS = 7 * 24 * 60 * 60_000;
4
- const ORG_COLUMNS = "o.id, o.name, o.slug, o.retention_days AS \"retentionDays\"";
5
- async function freeSlug(q, name) {
1
+ import { slugOf } from "../auth/crypto.js";
2
+ import { deleteProjectData } from "./projects.js";
3
+ const ORG_COLUMNS = `o.id, o.name, o.slug, o.retention_days AS "retentionDays"`;
4
+ const ms = (column) => `(extract(epoch FROM ${column}) * 1000)::double precision`;
5
+ /** A slug no organization has yet, from the name. */
6
+ export async function freeSlug(q, name) {
6
7
  const base = slugOf(name);
7
8
  const taken = new Set((await q.query("SELECT slug FROM orgs WHERE slug LIKE $1", [`${base}%`])).map((r) => r.slug));
8
9
  let slug = base;
@@ -10,66 +11,23 @@ async function freeSlug(q, name) {
10
11
  slug = `${base}-${i}`;
11
12
  return slug;
12
13
  }
13
- /** A new organization with `ownerId` as its owner. */
14
- export async function createOrg(q, name, ownerId, now, retentionDays = 30) {
15
- const org = { id: newId(), name: name.trim().slice(0, 100) || "My organization", slug: await freeSlug(q, name), retentionDays };
16
- await q.query("INSERT INTO orgs (id, name, slug, retention_days, created_ms) VALUES ($1, $2, $3, $4, $5)", [org.id, org.name, org.slug, retentionDays, now]);
17
- await q.query("INSERT INTO members (org_id, user_id, role, created_ms) VALUES ($1, $2, 'owner', $3)", [org.id, ownerId, now]);
18
- return org;
19
- }
20
14
  export const orgsOfUser = (q, userId) => q.query(`SELECT ${ORG_COLUMNS}, m.role FROM members m JOIN orgs o ON o.id = m.org_id WHERE m.user_id = $1 ORDER BY o.name`, [userId]);
21
15
  export async function membership(q, userId, orgId) {
22
- const [row] = await q.query(`SELECT ${ORG_COLUMNS}, m.role FROM members m JOIN orgs o ON o.id = m.org_id WHERE m.user_id = $1 AND m.org_id = $2`, [
23
- userId,
24
- orgId,
25
- ]);
16
+ const [row] = await q.query(`SELECT ${ORG_COLUMNS}, m.role FROM members m JOIN orgs o ON o.id = m.org_id WHERE m.user_id = $1 AND m.org_id = $2`, [userId, orgId]);
26
17
  return row;
27
18
  }
28
- export async function updateOrg(q, orgId, change) {
29
- if (change.name !== undefined)
30
- await q.query("UPDATE orgs SET name = $1 WHERE id = $2", [change.name.trim().slice(0, 100), orgId]);
31
- if (change.retentionDays !== undefined)
32
- await q.query("UPDATE orgs SET retention_days = $1 WHERE id = $2", [change.retentionDays, orgId]);
19
+ export async function setRetention(q, orgId, retentionDays) {
20
+ await q.query("UPDATE orgs SET retention_days = $1 WHERE id = $2", [retentionDays, orgId]);
33
21
  }
34
- export const listMembers = (q, orgId) => q.query(`SELECT u.id AS "userId", u.email, u.name, m.role, m.created_ms AS "sinceMs" FROM members m JOIN users u ON u.id = m.user_id
22
+ export const listMembers = (q, orgId) => q.query(`SELECT m.id AS "memberId", u.id AS "userId", u.email, u.name, m.role, ${ms("m.created_at")} AS "sinceMs" FROM members m JOIN users u ON u.id = m.user_id
35
23
  WHERE m.org_id = $1 ORDER BY u.name`, [orgId]);
36
- export async function setRole(q, orgId, userId, role) {
37
- await q.query("UPDATE members SET role = $1 WHERE org_id = $2 AND user_id = $3", [role, orgId, userId]);
38
- }
39
- export async function removeMember(q, orgId, userId) {
40
- await q.query("DELETE FROM members WHERE org_id = $1 AND user_id = $2", [orgId, userId]);
41
- }
42
- export async function ownerCount(q, orgId) {
43
- const [row] = await q.query("SELECT count(*)::int AS n FROM members WHERE org_id = $1 AND role = 'owner'", [orgId]);
44
- return row?.n ?? 0;
45
- }
46
- /** A new invite link token for one email address. Valid for 7 days. */
47
- export async function createInvite(q, orgId, email, role, by, now) {
48
- const token = newToken("invite");
49
- await q.query("INSERT INTO invites (token_hash, org_id, email, role, created_by, created_ms, expires_ms) VALUES ($1, $2, $3, $4, $5, $6, $7)", [
50
- hashToken(token),
51
- orgId,
52
- normalizeEmail(email),
53
- role,
54
- by,
55
- now,
56
- now + INVITE_MS,
57
- ]);
58
- return token;
59
- }
60
- export async function openInvite(q, token, now) {
61
- const [row] = await q.query(`SELECT i.org_id AS "orgId", o.name AS "orgName", i.email, i.role FROM invites i JOIN orgs o ON o.id = i.org_id
62
- WHERE i.token_hash = $1 AND i.accepted_ms IS NULL AND i.expires_ms > $2`, [hashToken(token), now]);
63
- return row;
64
- }
65
- /** Join the organization of an open invite. The invite then cannot be used again. */
66
- export async function acceptInvite(q, token, userId, now) {
67
- const invite = await openInvite(q, token, now);
68
- if (!invite)
69
- return undefined;
70
- await q.query("UPDATE invites SET accepted_ms = $1 WHERE token_hash = $2", [now, hashToken(token)]);
71
- await q.query("INSERT INTO members (org_id, user_id, role, created_ms) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING", [invite.orgId, userId, invite.role, now]);
72
- return invite;
24
+ /** Open invites. Their ids are the secret part of the link, so only managers see them. */
25
+ export const pendingInvites = (q, orgId) => q.query(`SELECT id, email, role, ${ms("expires_at")} AS "expiresMs" FROM invites WHERE org_id = $1 AND status = 'pending' AND expires_at > now() ORDER BY created_at DESC`, [orgId]);
26
+ /** Delete an organization: every project's data first, then the row (members, invites, projects, keys, alerts, and shares go with it). */
27
+ export async function deleteOrgEverything(q, orgId) {
28
+ for (const { id } of await q.query("SELECT id FROM projects WHERE org_id = $1", [orgId]))
29
+ await deleteProjectData(q, id);
30
+ await q.query("DELETE FROM audit WHERE org_id = $1", [orgId]);
31
+ await q.query("DELETE FROM orgs WHERE id = $1", [orgId]);
73
32
  }
74
- export const pendingInvites = (q, orgId, now) => q.query(`SELECT email, role, expires_ms AS "expiresMs" FROM invites WHERE org_id = $1 AND accepted_ms IS NULL AND expires_ms > $2 ORDER BY created_ms DESC`, [orgId, now]);
75
33
  //# sourceMappingURL=orgs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"orgs.js","sourceRoot":"","sources":["../../src/repo/orgs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orgs.js","sourceRoot":"","sources":["../../src/repo/orgs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAgClD,MAAM,WAAW,GAAG,2DAA2D,CAAC;AAChF,MAAM,EAAE,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,uBAAuB,MAAM,6BAA6B,CAAC;AAE1F,qDAAqD;AACrD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,CAAY,EAAE,IAAY;IACvD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAmB,0CAA0C,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACtI,IAAI,IAAI,GAAG,IAAI,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;QAAE,IAAI,GAAG,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC;IAC5D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAY,EAAE,MAAc,EAAyB,EAAE,CAChF,CAAC,CAAC,KAAK,CAAa,UAAU,WAAW,6FAA6F,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AAEpJ,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,CAAY,EAAE,MAAc,EAAE,KAAa;IAC1E,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CAAa,UAAU,WAAW,+FAA+F,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC/K,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,CAAY,EAAE,KAAa,EAAE,aAAqB;IACnF,MAAM,CAAC,CAAC,KAAK,CAAC,mDAAmD,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAY,EAAE,KAAa,EAAqB,EAAE,CAC5E,CAAC,CAAC,KAAK,CACL,yEAAyE,EAAE,CAAC,cAAc,CAAC;yCACtD,EACrC,CAAC,KAAK,CAAC,CACR,CAAC;AAEJ,0FAA0F;AAC1F,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAY,EAAE,KAAa,EAA4B,EAAE,CACtF,CAAC,CAAC,KAAK,CACL,2BAA2B,EAAE,CAAC,YAAY,CAAC,uHAAuH,EAClK,CAAC,KAAK,CAAC,CACR,CAAC;AAEJ,0IAA0I;AAC1I,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,CAAY,EAAE,KAAa;IACnE,KAAK,MAAM,EAAE,EAAE,EAAE,IAAI,MAAM,CAAC,CAAC,KAAK,CAAiB,2CAA2C,EAAE,CAAC,KAAK,CAAC,CAAC;QAAE,MAAM,iBAAiB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACzI,MAAM,CAAC,CAAC,KAAK,CAAC,qCAAqC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9D,MAAM,CAAC,CAAC,KAAK,CAAC,gCAAgC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Queryable } from "../db/db.js";
2
+ export type SuppressReason = "bounce" | "complaint";
3
+ /** Skip this address from now on. A bounce wins over a complaint, since nothing can reach the address. */
4
+ export declare function suppress(q: Queryable, email: string, reason: SuppressReason, detail: string, now: number): Promise<void>;
5
+ export declare function suppressionOf(q: Queryable, email: string): Promise<SuppressReason | null>;
6
+ /** The person proved the address works (they opened a link sent to it), so mail may go there again. */
7
+ export declare function unsuppress(q: Queryable, email: string): Promise<void>;
8
+ //# sourceMappingURL=suppressions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suppressions.d.ts","sourceRoot":"","sources":["../../src/repo/suppressions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,WAAW,CAAC;AAIpD,0GAA0G;AAC1G,wBAAsB,QAAQ,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO9H;AAED,wBAAsB,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAG/F;AAED,uGAAuG;AACvG,wBAAsB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E"}
@@ -0,0 +1,16 @@
1
+ const norm = (email) => email.trim().toLowerCase();
2
+ /** Skip this address from now on. A bounce wins over a complaint, since nothing can reach the address. */
3
+ export async function suppress(q, email, reason, detail, now) {
4
+ await q.query(`INSERT INTO mail_suppressions (email, reason, detail, created_ms) VALUES ($1, $2, $3, $4)
5
+ ON CONFLICT (email) DO UPDATE SET reason = CASE WHEN mail_suppressions.reason = 'bounce' THEN 'bounce' ELSE EXCLUDED.reason END,
6
+ detail = EXCLUDED.detail, created_ms = EXCLUDED.created_ms`, [norm(email), reason, detail.slice(0, 500), now]);
7
+ }
8
+ export async function suppressionOf(q, email) {
9
+ const rows = await q.query("SELECT reason FROM mail_suppressions WHERE email = $1", [norm(email)]);
10
+ return rows[0]?.reason ?? null;
11
+ }
12
+ /** The person proved the address works (they opened a link sent to it), so mail may go there again. */
13
+ export async function unsuppress(q, email) {
14
+ await q.query("DELETE FROM mail_suppressions WHERE email = $1", [norm(email)]);
15
+ }
16
+ //# sourceMappingURL=suppressions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suppressions.js","sourceRoot":"","sources":["../../src/repo/suppressions.ts"],"names":[],"mappings":"AAIA,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAE3D,0GAA0G;AAC1G,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,CAAY,EAAE,KAAa,EAAE,MAAsB,EAAE,MAAc,EAAE,GAAW;IAC7G,MAAM,CAAC,CAAC,KAAK,CACX;;kEAE8D,EAC9D,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CACjD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,CAAY,EAAE,KAAa;IAC7D,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,KAAK,CAA6B,uDAAuD,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/H,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,IAAI,CAAC;AACjC,CAAC;AAED,uGAAuG;AACvG,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,CAAY,EAAE,KAAa;IAC1D,MAAM,CAAC,CAAC,KAAK,CAAC,gDAAgD,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjF,CAAC"}
@@ -1,24 +1,13 @@
1
1
  import type { Queryable } from "../db/db.js";
2
+ /** A signed-in person, as our routes see them. Accounts themselves are Better Auth's (auth/auth.ts). */
2
3
  export interface User {
3
4
  id: string;
4
5
  email: string;
5
6
  name: string;
7
+ emailVerified: boolean;
8
+ twoFactorEnabled: boolean;
6
9
  }
7
- export declare const normalizeEmail: (email: string) => string;
8
- /** Check sign-up input. Returns an error message, or null when it is fine. */
9
- export declare function signUpProblem(email: string, password: string, name: string): string | null;
10
10
  export declare function userCount(q: Queryable): Promise<number>;
11
- export declare function createUser(q: Queryable, email: string, password: string, name: string, now: number): Promise<User>;
12
- export declare function userByEmail(q: Queryable, email: string): Promise<User | undefined>;
13
- /** The user when the email and password match. Takes the same time when the email is unknown. */
14
- export declare function verifyLogin(q: Queryable, email: string, password: string): Promise<User | undefined>;
15
- export declare function setPassword(q: Queryable, userId: string, password: string): Promise<void>;
16
- /** A new session. Returns the token for the cookie; only its hash is stored. */
17
- export declare function createSession(q: Queryable, userId: string, now: number): Promise<{
18
- token: string;
19
- expiresMs: number;
20
- }>;
21
- export declare function userBySession(q: Queryable, token: string, now: number): Promise<User | undefined>;
22
- export declare function endSession(q: Queryable, token: string): Promise<void>;
23
- export declare function pruneSessions(q: Queryable, now: number): Promise<void>;
11
+ /** Emails of an organization's members, for alert emails. When mail really goes out, only confirmed ones. */
12
+ export declare const memberEmails: (q: Queryable, orgId: string, confirmedOnly: boolean) => Promise<string[]>;
24
13
  //# sourceMappingURL=users.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/repo/users.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,eAAO,MAAM,cAAc,UAAW,MAAM,KAAG,MAAoC,CAAC;AAGpF,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM1F;AAED,wBAAsB,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7D;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUxH;AAED,wBAAsB,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAGxF;AAED,iGAAiG;AACjG,wBAAsB,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAM1G;AAED,wBAAsB,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG/F;AAED,gFAAgF;AAChF,wBAAsB,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAK5H;AAED,wBAAsB,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAMvG;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E;AAED,wBAAsB,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E"}
1
+ {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/repo/users.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,wGAAwG;AACxG,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAsB,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7D;AAED,6GAA6G;AAC7G,eAAO,MAAM,YAAY,MAAa,SAAS,SAAS,MAAM,iBAAiB,OAAO,KAAG,OAAO,CAAC,MAAM,EAAE,CAGtG,CAAC"}