@wizeworks/lens-cloud 0.0.0-stage → 0.3.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -2
  3. package/dist/alerts/evaluate.d.ts +10 -0
  4. package/dist/alerts/evaluate.d.ts.map +1 -0
  5. package/dist/alerts/evaluate.js +81 -0
  6. package/dist/alerts/evaluate.js.map +1 -0
  7. package/dist/alerts/notify.d.ts +28 -0
  8. package/dist/alerts/notify.d.ts.map +1 -0
  9. package/dist/alerts/notify.js +52 -0
  10. package/dist/alerts/notify.js.map +1 -0
  11. package/dist/app.d.ts +26 -0
  12. package/dist/app.d.ts.map +1 -0
  13. package/dist/app.js +2 -0
  14. package/dist/app.js.map +1 -0
  15. package/dist/auth/auth.d.ts +51 -0
  16. package/dist/auth/auth.d.ts.map +1 -0
  17. package/dist/auth/auth.js +63 -0
  18. package/dist/auth/auth.js.map +1 -0
  19. package/dist/auth/bridge.d.ts +7 -0
  20. package/dist/auth/bridge.d.ts.map +1 -0
  21. package/dist/auth/bridge.js +39 -0
  22. package/dist/auth/bridge.js.map +1 -0
  23. package/dist/auth/crypto.d.ts +14 -0
  24. package/dist/auth/crypto.d.ts.map +1 -0
  25. package/dist/auth/crypto.js +16 -0
  26. package/dist/auth/crypto.js.map +1 -0
  27. package/dist/auth/delete-user.d.ts +16 -0
  28. package/dist/auth/delete-user.d.ts.map +1 -0
  29. package/dist/auth/delete-user.js +21 -0
  30. package/dist/auth/delete-user.js.map +1 -0
  31. package/dist/auth/deps.d.ts +27 -0
  32. package/dist/auth/deps.d.ts.map +1 -0
  33. package/dist/auth/deps.js +3 -0
  34. package/dist/auth/deps.js.map +1 -0
  35. package/dist/auth/email-token.d.ts +8 -0
  36. package/dist/auth/email-token.d.ts.map +1 -0
  37. package/dist/auth/email-token.js +15 -0
  38. package/dist/auth/email-token.js.map +1 -0
  39. package/dist/auth/hooks.d.ts +4 -0
  40. package/dist/auth/hooks.d.ts.map +1 -0
  41. package/dist/auth/hooks.js +143 -0
  42. package/dist/auth/hooks.js.map +1 -0
  43. package/dist/auth/options.d.ts +17 -0
  44. package/dist/auth/options.d.ts.map +1 -0
  45. package/dist/auth/options.js +98 -0
  46. package/dist/auth/options.js.map +1 -0
  47. package/dist/auth/password.d.ts +10 -0
  48. package/dist/auth/password.d.ts.map +1 -0
  49. package/dist/auth/password.js +22 -0
  50. package/dist/auth/password.js.map +1 -0
  51. package/dist/auth/plugins.d.ts +4 -0
  52. package/dist/auth/plugins.d.ts.map +1 -0
  53. package/dist/auth/plugins.js +45 -0
  54. package/dist/auth/plugins.js.map +1 -0
  55. package/dist/auth/principal.d.ts +38 -0
  56. package/dist/auth/principal.d.ts.map +1 -0
  57. package/dist/auth/principal.js +69 -0
  58. package/dist/auth/principal.js.map +1 -0
  59. package/dist/auth/roles.d.ts +50 -0
  60. package/dist/auth/roles.d.ts.map +1 -0
  61. package/dist/auth/roles.js +18 -0
  62. package/dist/auth/roles.js.map +1 -0
  63. package/dist/auth/schema-names.d.ts +130 -0
  64. package/dist/auth/schema-names.d.ts.map +1 -0
  65. package/dist/auth/schema-names.js +53 -0
  66. package/dist/auth/schema-names.js.map +1 -0
  67. package/dist/auth/secret.d.ts +12 -0
  68. package/dist/auth/secret.d.ts.map +1 -0
  69. package/dist/auth/secret.js +32 -0
  70. package/dist/auth/secret.js.map +1 -0
  71. package/dist/auth/security-notices.d.ts +34 -0
  72. package/dist/auth/security-notices.d.ts.map +1 -0
  73. package/dist/auth/security-notices.js +81 -0
  74. package/dist/auth/security-notices.js.map +1 -0
  75. package/dist/auth/signup.d.ts +23 -0
  76. package/dist/auth/signup.d.ts.map +1 -0
  77. package/dist/auth/signup.js +61 -0
  78. package/dist/auth/signup.js.map +1 -0
  79. package/dist/auth/sso.d.ts +21 -0
  80. package/dist/auth/sso.d.ts.map +1 -0
  81. package/dist/auth/sso.js +35 -0
  82. package/dist/auth/sso.js.map +1 -0
  83. package/dist/auth/wire.d.ts +16 -0
  84. package/dist/auth/wire.d.ts.map +1 -0
  85. package/dist/auth/wire.js +47 -0
  86. package/dist/auth/wire.js.map +1 -0
  87. package/dist/cli-args.d.ts +5 -0
  88. package/dist/cli-args.d.ts.map +1 -0
  89. package/dist/cli-args.js +86 -0
  90. package/dist/cli-args.js.map +1 -0
  91. package/dist/cli.d.ts +3 -0
  92. package/dist/cli.d.ts.map +1 -0
  93. package/dist/cli.js +44 -0
  94. package/dist/cli.js.map +1 -0
  95. package/dist/config.d.ts +55 -0
  96. package/dist/config.d.ts.map +1 -0
  97. package/dist/config.js +55 -0
  98. package/dist/config.js.map +1 -0
  99. package/dist/db/db.d.ts +22 -0
  100. package/dist/db/db.d.ts.map +1 -0
  101. package/dist/db/db.js +64 -0
  102. package/dist/db/db.js.map +1 -0
  103. package/dist/db/migrate.d.ts +6 -0
  104. package/dist/db/migrate.d.ts.map +1 -0
  105. package/dist/db/migrate.js +35 -0
  106. package/dist/db/migrate.js.map +1 -0
  107. package/dist/db/schema-auth.d.ts +2 -0
  108. package/dist/db/schema-auth.d.ts.map +1 -0
  109. package/dist/db/schema-auth.js +93 -0
  110. package/dist/db/schema-auth.js.map +1 -0
  111. package/dist/db/schema-mail.d.ts +2 -0
  112. package/dist/db/schema-mail.d.ts.map +1 -0
  113. package/dist/db/schema-mail.js +8 -0
  114. package/dist/db/schema-mail.js.map +1 -0
  115. package/dist/db/schema-notify.d.ts +2 -0
  116. package/dist/db/schema-notify.d.ts.map +1 -0
  117. package/dist/db/schema-notify.js +26 -0
  118. package/dist/db/schema-notify.js.map +1 -0
  119. package/dist/db/schema-sso.d.ts +2 -0
  120. package/dist/db/schema-sso.d.ts.map +1 -0
  121. package/dist/db/schema-sso.js +17 -0
  122. package/dist/db/schema-sso.js.map +1 -0
  123. package/dist/db/schema.d.ts +3 -0
  124. package/dist/db/schema.d.ts.map +1 -0
  125. package/dist/db/schema.js +208 -0
  126. package/dist/db/schema.js.map +1 -0
  127. package/dist/http/http.d.ts +19 -0
  128. package/dist/http/http.d.ts.map +1 -0
  129. package/dist/http/http.js +66 -0
  130. package/dist/http/http.js.map +1 -0
  131. package/dist/http/limiter.d.ts +11 -0
  132. package/dist/http/limiter.d.ts.map +1 -0
  133. package/dist/http/limiter.js +31 -0
  134. package/dist/http/limiter.js.map +1 -0
  135. package/dist/http/router.d.ts +21 -0
  136. package/dist/http/router.d.ts.map +1 -0
  137. package/dist/http/router.js +28 -0
  138. package/dist/http/router.js.map +1 -0
  139. package/dist/index.d.ts +7 -0
  140. package/dist/index.d.ts.map +1 -0
  141. package/dist/index.js +4 -0
  142. package/dist/index.js.map +1 -0
  143. package/dist/jobs.d.ts +4 -0
  144. package/dist/jobs.d.ts.map +1 -0
  145. package/dist/jobs.js +53 -0
  146. package/dist/jobs.js.map +1 -0
  147. package/dist/mail/blocks.d.ts +14 -0
  148. package/dist/mail/blocks.d.ts.map +1 -0
  149. package/dist/mail/blocks.js +35 -0
  150. package/dist/mail/blocks.js.map +1 -0
  151. package/dist/mail/content.d.ts +68 -0
  152. package/dist/mail/content.d.ts.map +1 -0
  153. package/dist/mail/content.js +6 -0
  154. package/dist/mail/content.js.map +1 -0
  155. package/dist/mail/emails-digest.d.ts +10 -0
  156. package/dist/mail/emails-digest.d.ts.map +1 -0
  157. package/dist/mail/emails-digest.js +55 -0
  158. package/dist/mail/emails-digest.js.map +1 -0
  159. package/dist/mail/emails-health.d.ts +6 -0
  160. package/dist/mail/emails-health.d.ts.map +1 -0
  161. package/dist/mail/emails-health.js +36 -0
  162. package/dist/mail/emails-health.js.map +1 -0
  163. package/dist/mail/emails-security.d.ts +14 -0
  164. package/dist/mail/emails-security.d.ts.map +1 -0
  165. package/dist/mail/emails-security.js +27 -0
  166. package/dist/mail/emails-security.js.map +1 -0
  167. package/dist/mail/emails-team.d.ts +11 -0
  168. package/dist/mail/emails-team.d.ts.map +1 -0
  169. package/dist/mail/emails-team.js +45 -0
  170. package/dist/mail/emails-team.js.map +1 -0
  171. package/dist/mail/emails.d.ts +9 -0
  172. package/dist/mail/emails.d.ts.map +1 -0
  173. package/dist/mail/emails.js +49 -0
  174. package/dist/mail/emails.js.map +1 -0
  175. package/dist/mail/layout.d.ts +6 -0
  176. package/dist/mail/layout.d.ts.map +1 -0
  177. package/dist/mail/layout.js +10 -0
  178. package/dist/mail/layout.js.map +1 -0
  179. package/dist/mail/mailer.d.ts +25 -0
  180. package/dist/mail/mailer.d.ts.map +1 -0
  181. package/dist/mail/mailer.js +49 -0
  182. package/dist/mail/mailer.js.map +1 -0
  183. package/dist/mail/preview.d.ts +6 -0
  184. package/dist/mail/preview.d.ts.map +1 -0
  185. package/dist/mail/preview.js +26 -0
  186. package/dist/mail/preview.js.map +1 -0
  187. package/dist/mail/resend.d.ts +11 -0
  188. package/dist/mail/resend.d.ts.map +1 -0
  189. package/dist/mail/resend.js +34 -0
  190. package/dist/mail/resend.js.map +1 -0
  191. package/dist/mail/samples.d.ts +3 -0
  192. package/dist/mail/samples.d.ts.map +1 -0
  193. package/dist/mail/samples.js +63 -0
  194. package/dist/mail/samples.js.map +1 -0
  195. package/dist/mail/stop-route.d.ts +4 -0
  196. package/dist/mail/stop-route.d.ts.map +1 -0
  197. package/dist/mail/stop-route.js +41 -0
  198. package/dist/mail/stop-route.js.map +1 -0
  199. package/dist/mail/svix.d.ts +8 -0
  200. package/dist/mail/svix.d.ts.map +1 -0
  201. package/dist/mail/svix.js +17 -0
  202. package/dist/mail/svix.js.map +1 -0
  203. package/dist/mail/templates.d.ts +12 -0
  204. package/dist/mail/templates.d.ts.map +1 -0
  205. package/dist/mail/templates.js +18 -0
  206. package/dist/mail/templates.js.map +1 -0
  207. package/dist/mail/text.d.ts +4 -0
  208. package/dist/mail/text.d.ts.map +1 -0
  209. package/dist/mail/text.js +17 -0
  210. package/dist/mail/text.js.map +1 -0
  211. package/dist/mail/theme.d.ts +26 -0
  212. package/dist/mail/theme.d.ts.map +1 -0
  213. package/dist/mail/theme.js +21 -0
  214. package/dist/mail/theme.js.map +1 -0
  215. package/dist/mail/unsubscribe.d.ts +14 -0
  216. package/dist/mail/unsubscribe.d.ts.map +1 -0
  217. package/dist/mail/unsubscribe.js +39 -0
  218. package/dist/mail/unsubscribe.js.map +1 -0
  219. package/dist/mail/webhook.d.ts +5 -0
  220. package/dist/mail/webhook.d.ts.map +1 -0
  221. package/dist/mail/webhook.js +41 -0
  222. package/dist/mail/webhook.js.map +1 -0
  223. package/dist/notify/digest-data.d.ts +31 -0
  224. package/dist/notify/digest-data.d.ts.map +1 -0
  225. package/dist/notify/digest-data.js +37 -0
  226. package/dist/notify/digest-data.js.map +1 -0
  227. package/dist/notify/digest.d.ts +17 -0
  228. package/dist/notify/digest.d.ts.map +1 -0
  229. package/dist/notify/digest.js +76 -0
  230. package/dist/notify/digest.js.map +1 -0
  231. package/dist/notify/health.d.ts +6 -0
  232. package/dist/notify/health.d.ts.map +1 -0
  233. package/dist/notify/health.js +43 -0
  234. package/dist/notify/health.js.map +1 -0
  235. package/dist/notify/team-describe.d.ts +22 -0
  236. package/dist/notify/team-describe.d.ts.map +1 -0
  237. package/dist/notify/team-describe.js +67 -0
  238. package/dist/notify/team-describe.js.map +1 -0
  239. package/dist/notify/team.d.ts +6 -0
  240. package/dist/notify/team.d.ts.map +1 -0
  241. package/dist/notify/team.js +56 -0
  242. package/dist/notify/team.js.map +1 -0
  243. package/dist/repo/alerts.d.ts +52 -0
  244. package/dist/repo/alerts.d.ts.map +1 -0
  245. package/dist/repo/alerts.js +38 -0
  246. package/dist/repo/alerts.js.map +1 -0
  247. package/dist/repo/audit.d.ts +11 -0
  248. package/dist/repo/audit.d.ts.map +1 -0
  249. package/dist/repo/audit.js +17 -0
  250. package/dist/repo/audit.js.map +1 -0
  251. package/dist/repo/auth-prune.d.ts +4 -0
  252. package/dist/repo/auth-prune.d.ts.map +1 -0
  253. package/dist/repo/auth-prune.js +8 -0
  254. package/dist/repo/auth-prune.js.map +1 -0
  255. package/dist/repo/mail-prefs.d.ts +35 -0
  256. package/dist/repo/mail-prefs.d.ts.map +1 -0
  257. package/dist/repo/mail-prefs.js +34 -0
  258. package/dist/repo/mail-prefs.js.map +1 -0
  259. package/dist/repo/metric-read.d.ts +12 -0
  260. package/dist/repo/metric-read.d.ts.map +1 -0
  261. package/dist/repo/metric-read.js +11 -0
  262. package/dist/repo/metric-read.js.map +1 -0
  263. package/dist/repo/metric-write.d.ts +9 -0
  264. package/dist/repo/metric-write.d.ts.map +1 -0
  265. package/dist/repo/metric-write.js +53 -0
  266. package/dist/repo/metric-write.js.map +1 -0
  267. package/dist/repo/orgs.d.ts +37 -0
  268. package/dist/repo/orgs.d.ts.map +1 -0
  269. package/dist/repo/orgs.js +33 -0
  270. package/dist/repo/orgs.js.map +1 -0
  271. package/dist/repo/projects.d.ts +37 -0
  272. package/dist/repo/projects.d.ts.map +1 -0
  273. package/dist/repo/projects.js +57 -0
  274. package/dist/repo/projects.js.map +1 -0
  275. package/dist/repo/suppressions.d.ts +8 -0
  276. package/dist/repo/suppressions.d.ts.map +1 -0
  277. package/dist/repo/suppressions.js +16 -0
  278. package/dist/repo/suppressions.js.map +1 -0
  279. package/dist/repo/trace-read.d.ts +28 -0
  280. package/dist/repo/trace-read.d.ts.map +1 -0
  281. package/dist/repo/trace-read.js +76 -0
  282. package/dist/repo/trace-read.js.map +1 -0
  283. package/dist/repo/trace-write.d.ts +9 -0
  284. package/dist/repo/trace-write.d.ts.map +1 -0
  285. package/dist/repo/trace-write.js +82 -0
  286. package/dist/repo/trace-write.js.map +1 -0
  287. package/dist/repo/users.d.ts +13 -0
  288. package/dist/repo/users.d.ts.map +1 -0
  289. package/dist/repo/users.js +7 -0
  290. package/dist/repo/users.js.map +1 -0
  291. package/dist/routes/alerts.d.ts +4 -0
  292. package/dist/routes/alerts.d.ts.map +1 -0
  293. package/dist/routes/alerts.js +116 -0
  294. package/dist/routes/alerts.js.map +1 -0
  295. package/dist/routes/data.d.ts +7 -0
  296. package/dist/routes/data.d.ts.map +1 -0
  297. package/dist/routes/data.js +74 -0
  298. package/dist/routes/data.js.map +1 -0
  299. package/dist/routes/index.d.ts +5 -0
  300. package/dist/routes/index.d.ts.map +1 -0
  301. package/dist/routes/index.js +25 -0
  302. package/dist/routes/index.js.map +1 -0
  303. package/dist/routes/ingest.d.ts +8 -0
  304. package/dist/routes/ingest.d.ts.map +1 -0
  305. package/dist/routes/ingest.js +38 -0
  306. package/dist/routes/ingest.js.map +1 -0
  307. package/dist/routes/mcp.d.ts +4 -0
  308. package/dist/routes/mcp.d.ts.map +1 -0
  309. package/dist/routes/mcp.js +52 -0
  310. package/dist/routes/mcp.js.map +1 -0
  311. package/dist/routes/me.d.ts +4 -0
  312. package/dist/routes/me.d.ts.map +1 -0
  313. package/dist/routes/me.js +37 -0
  314. package/dist/routes/me.js.map +1 -0
  315. package/dist/routes/metrics.d.ts +13 -0
  316. package/dist/routes/metrics.d.ts.map +1 -0
  317. package/dist/routes/metrics.js +29 -0
  318. package/dist/routes/metrics.js.map +1 -0
  319. package/dist/routes/models.d.ts +4 -0
  320. package/dist/routes/models.d.ts.map +1 -0
  321. package/dist/routes/models.js +71 -0
  322. package/dist/routes/models.js.map +1 -0
  323. package/dist/routes/notify.d.ts +4 -0
  324. package/dist/routes/notify.d.ts.map +1 -0
  325. package/dist/routes/notify.js +55 -0
  326. package/dist/routes/notify.js.map +1 -0
  327. package/dist/routes/orgs.d.ts +4 -0
  328. package/dist/routes/orgs.d.ts.map +1 -0
  329. package/dist/routes/orgs.js +73 -0
  330. package/dist/routes/orgs.js.map +1 -0
  331. package/dist/routes/projects.d.ts +4 -0
  332. package/dist/routes/projects.d.ts.map +1 -0
  333. package/dist/routes/projects.js +55 -0
  334. package/dist/routes/projects.js.map +1 -0
  335. package/dist/routes/shares.d.ts +11 -0
  336. package/dist/routes/shares.d.ts.map +1 -0
  337. package/dist/routes/shares.js +61 -0
  338. package/dist/routes/shares.js.map +1 -0
  339. package/dist/scale-exec.d.ts +11 -0
  340. package/dist/scale-exec.d.ts.map +1 -0
  341. package/dist/scale-exec.js +26 -0
  342. package/dist/scale-exec.js.map +1 -0
  343. package/dist/server.d.ts +15 -0
  344. package/dist/server.d.ts.map +1 -0
  345. package/dist/server.js +126 -0
  346. package/dist/server.js.map +1 -0
  347. package/dist/settle.d.ts +26 -0
  348. package/dist/settle.d.ts.map +1 -0
  349. package/dist/settle.js +85 -0
  350. package/dist/settle.js.map +1 -0
  351. package/package.json +76 -3
@@ -0,0 +1,31 @@
1
+ /** A fixed-window counter per key: at most `limit` calls per `windowMs`. In memory, per process. */
2
+ export class RateLimiter {
3
+ limit;
4
+ windowMs;
5
+ now;
6
+ #counts = new Map();
7
+ constructor(limit, windowMs, now = Date.now) {
8
+ this.limit = limit;
9
+ this.windowMs = windowMs;
10
+ this.now = now;
11
+ }
12
+ /** True when the call is allowed. */
13
+ take(key) {
14
+ const t = this.now();
15
+ const c = this.#counts.get(key);
16
+ if (!c || t - c.start >= this.windowMs) {
17
+ this.#counts.set(key, { start: t, n: 1 });
18
+ if (this.#counts.size > 10_000)
19
+ this.#sweep(t);
20
+ return true;
21
+ }
22
+ c.n++;
23
+ return c.n <= this.limit;
24
+ }
25
+ #sweep(t) {
26
+ for (const [k, c] of this.#counts)
27
+ if (t - c.start >= this.windowMs)
28
+ this.#counts.delete(k);
29
+ }
30
+ }
31
+ //# sourceMappingURL=limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limiter.js","sourceRoot":"","sources":["../../src/http/limiter.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,MAAM,OAAO,WAAW;IAIH,KAAK;IACL,QAAQ;IACR,GAAG;IALb,OAAO,GAAG,IAAI,GAAG,EAAwC,CAAC;IAEnE,YACmB,KAAa,EACb,QAAgB,EAChB,GAAG,GAAiB,IAAI,CAAC,GAAG;qBAF5B,KAAK;wBACL,QAAQ;mBACR,GAAG;IACnB,CAAC;IAEJ,qCAAqC;IACrC,IAAI,CAAC,GAAW;QACd,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACvC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YAC1C,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,MAAM;gBAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC/C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,CAAC,CAAC,CAAC,EAAE,CAAC;QACN,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,CAAS;QACd,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC9F,CAAC;CACF"}
@@ -0,0 +1,21 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ export interface RouteCtx {
3
+ req: IncomingMessage;
4
+ res: ServerResponse;
5
+ url: URL;
6
+ params: Record<string, string>;
7
+ }
8
+ export type Handler<C extends RouteCtx = RouteCtx> = (ctx: C) => Promise<void>;
9
+ /** Method and path matching, with `:name` path parts. Paths are below the base path. */
10
+ export declare class Router<C extends RouteCtx = RouteCtx> {
11
+ #private;
12
+ on(method: string, path: string, handler: Handler<C>): this;
13
+ /** The handler and path params for a request, or undefined. */
14
+ match(method: string, path: string): {
15
+ handler: Handler<C>;
16
+ params: Record<string, string>;
17
+ } | undefined;
18
+ /** True when some route has this path with another method (for 405). */
19
+ hasPath(path: string): boolean;
20
+ }
21
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/http/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,eAAe,CAAC;IACrB,GAAG,EAAE,cAAc,CAAC;IACpB,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAS/E,wFAAwF;AACxF,qBAAa,MAAM,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ;;IAG/C,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAK1D;IAED,+DAA+D;IAC/D,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,SAAS,CASvG;IAED,wEAAwE;IACxE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7B;CACF"}
@@ -0,0 +1,28 @@
1
+ /** Method and path matching, with `:name` path parts. Paths are below the base path. */
2
+ export class Router {
3
+ #routes = [];
4
+ on(method, path, handler) {
5
+ const keys = [];
6
+ const source = path.replace(/:([a-zA-Z]+)/g, (_, k) => (keys.push(k), "([^/]+)"));
7
+ this.#routes.push({ method, pattern: new RegExp(`^${source}$`), keys, handler });
8
+ return this;
9
+ }
10
+ /** The handler and path params for a request, or undefined. */
11
+ match(method, path) {
12
+ for (const r of this.#routes) {
13
+ if (r.method !== method)
14
+ continue;
15
+ const m = r.pattern.exec(path);
16
+ if (!m)
17
+ continue;
18
+ const params = Object.fromEntries(r.keys.map((k, i) => [k, decodeURIComponent(m[i + 1])]));
19
+ return { handler: r.handler, params };
20
+ }
21
+ return undefined;
22
+ }
23
+ /** True when some route has this path with another method (for 405). */
24
+ hasPath(path) {
25
+ return this.#routes.some((r) => r.pattern.test(path));
26
+ }
27
+ }
28
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/http/router.ts"],"names":[],"mappings":"AAkBA,wFAAwF;AACxF,MAAM,OAAO,MAAM;IACR,OAAO,GAAe,EAAE,CAAC;IAElC,EAAE,CAAC,MAAc,EAAE,IAAY,EAAE,OAAmB;QAClD,MAAM,IAAI,GAAa,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QAC1F,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACjF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,+DAA+D;IAC/D,KAAK,CAAC,MAAc,EAAE,IAAY;QAChC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;gBAAE,SAAS;YAClC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,CAAC;gBAAE,SAAS;YACjB,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5F,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QACxC,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,wEAAwE;IACxE,OAAO,CAAC,IAAY;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACxD,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ export { createCloud, CLOUD_VERSION } from "./server.js";
2
+ export type { Cloud } from "./server.js";
3
+ export type { CloudOptions } from "./config.js";
4
+ export { openDb } from "./db/db.js";
5
+ export type { Db } from "./db/db.js";
6
+ export { migrate } from "./db/migrate.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,YAAY,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { createCloud, CLOUD_VERSION } from "./server.js";
2
+ export { openDb } from "./db/db.js";
3
+ export { migrate } from "./db/migrate.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGzD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/jobs.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import type { CloudApp } from "./app.js";
2
+ /** Background work: retention, stats, rollups, sessions, alert rules, team and health notices, and digests. Returns a function that stops it. */
3
+ export declare function startJobs(app: CloudApp): () => void;
4
+ //# sourceMappingURL=jobs.d.ts.map
@@ -0,0 +1 @@
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 ADDED
@@ -0,0 +1,53 @@
1
+ import { evaluateAll } from "./alerts/evaluate.js";
2
+ import { pruneByRetention, pruneMetricsByRetention } from "./repo/trace-write.js";
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";
8
+ const HOUSEKEEPING_MS = 10 * 60_000;
9
+ const SETTLE_MS = 3_000;
10
+ const ROLLUP_PRUNE_MS = 60_000;
11
+ const NOTICE_MS = 60_000;
12
+ const DIGEST_MS = 10 * 60_000;
13
+ /** Run `job` now and then every `everyMs`. A failed run logs and waits for the next one. */
14
+ function every(name, everyMs, job) {
15
+ let running = false;
16
+ const run = () => {
17
+ if (running)
18
+ return;
19
+ running = true;
20
+ job()
21
+ .catch((err) => console.error(`[wizelens-cloud] ${name} failed:`, err))
22
+ .finally(() => (running = false));
23
+ };
24
+ const timer = setInterval(run, everyMs);
25
+ const first = setTimeout(run, 1000);
26
+ timer.unref();
27
+ first.unref();
28
+ return () => (clearInterval(timer), clearTimeout(first));
29
+ }
30
+ /** Background work: retention, stats, rollups, sessions, alert rules, team and health notices, and digests. Returns a function that stops it. */
31
+ export function startJobs(app) {
32
+ const now = app.config.now;
33
+ const stops = [
34
+ every("retention", HOUSEKEEPING_MS, async () => {
35
+ while ((await pruneByRetention(app.db, now())) > 0)
36
+ ;
37
+ await pruneMetricsByRetention(app.db, now());
38
+ await pruneRollups(app.db, now(), true);
39
+ }),
40
+ every("settle", SETTLE_MS, () => settleCloud(app.db, now(), { defaultRetentionDays: app.config.retentionDays })),
41
+ every("rollups", ROLLUP_PRUNE_MS, () => pruneRollups(app.db, now())),
42
+ every("sessions", HOUSEKEEPING_MS, () => pruneAuthRows(app.db)),
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)),
50
+ ];
51
+ return () => stops.forEach((stop) => stop());
52
+ }
53
+ //# sourceMappingURL=jobs.js.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,36 @@
1
+ import { facts, text } from "./content.js";
2
+ const clock = (ms) => `${new Date(ms).toISOString().slice(0, 16).replace("T", " ")} UTC`;
3
+ const span = (ms) => (ms >= 86_400_000 ? `${Math.round(ms / 86_400_000)} days` : `${Math.max(1, Math.round(ms / 3_600_000))} hours`);
4
+ /** A project that sends data around the clock stopped. */
5
+ export function projectQuiet(project, org, lastMs, nowMs, url, stop) {
6
+ return {
7
+ kind: "health",
8
+ subject: `${project} stopped sending data to WizeLens`,
9
+ preview: `No data from ${project} for ${span(nowMs - lastMs)}.`,
10
+ heading: `${project} went quiet.`,
11
+ tone: "bad",
12
+ blocks: [
13
+ text(`${project} in ${org} usually sends data every hour. Nothing arrived for ${span(nowMs - lastMs)}.`),
14
+ text("The app may be down, its add-on may have lost its key, or traffic may have stopped."),
15
+ facts([["Last data", clock(lastMs)], ["Quiet for", span(nowMs - lastMs)]]),
16
+ ],
17
+ action: { label: `Open ${project}`, url },
18
+ footer: `You get this because you are an owner or admin of ${org}.`,
19
+ unsubscribe: { label: "Stop project health emails", url: stop },
20
+ };
21
+ }
22
+ /** Data arrives again after a quiet notice. */
23
+ export function projectBack(project, org, quietMs, url, stop) {
24
+ return {
25
+ kind: "health",
26
+ subject: `${project} is sending data to WizeLens again`,
27
+ preview: `Data from ${project} arrives again after ${span(quietMs)}.`,
28
+ heading: `${project} is back.`,
29
+ tone: "good",
30
+ blocks: [text(`Data from ${project} in ${org} arrives again. It was quiet for about ${span(quietMs)}.`)],
31
+ action: { label: `Open ${project}`, url },
32
+ footer: `You get this because you are an owner or admin of ${org}.`,
33
+ unsubscribe: { label: "Stop project health emails", url: stop },
34
+ };
35
+ }
36
+ //# sourceMappingURL=emails-health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emails-health.js","sourceRoot":"","sources":["../../src/mail/emails-health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAE9D,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC;AACjG,MAAM,IAAI,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC;AAE7I,0DAA0D;AAC1D,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,GAAW,EAAE,MAAc,EAAE,KAAa,EAAE,GAAW,EAAE,IAAY;IACjH,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,GAAG,OAAO,mCAAmC;QACtD,OAAO,EAAE,gBAAgB,OAAO,QAAQ,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG;QAC/D,OAAO,EAAE,GAAG,OAAO,cAAc;QACjC,IAAI,EAAE,KAAK;QACX,MAAM,EAAE;YACN,IAAI,CAAC,GAAG,OAAO,OAAO,GAAG,uDAAuD,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC;YACxG,IAAI,CAAC,qFAAqF,CAAC;YAC3F,KAAK,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;SAC3E;QACD,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,OAAO,EAAE,EAAE,GAAG,EAAE;QACzC,MAAM,EAAE,qDAAqD,GAAG,GAAG;QACnE,WAAW,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE,GAAG,EAAE,IAAI,EAAE;KAChE,CAAC;AACJ,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,GAAW,EAAE,OAAe,EAAE,GAAW,EAAE,IAAY;IAClG,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,GAAG,OAAO,oCAAoC;QACvD,OAAO,EAAE,aAAa,OAAO,wBAAwB,IAAI,CAAC,OAAO,CAAC,GAAG;QACrE,OAAO,EAAE,GAAG,OAAO,WAAW;QAC9B,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,CAAC,IAAI,CAAC,aAAa,OAAO,OAAO,GAAG,0CAA0C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACxG,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,OAAO,EAAE,EAAE,GAAG,EAAE;QACzC,MAAM,EAAE,qDAAqD,GAAG,GAAG;QACnE,WAAW,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE,GAAG,EAAE,IAAI,EAAE;KAChE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type EmailContent } from "./content.js";
2
+ export interface SecurityLinks {
3
+ /** The Account page, to review devices and sign-in settings. */
4
+ account: string;
5
+ /** The page that sends a reset link, for when the person cannot sign in. */
6
+ forgot: string;
7
+ }
8
+ export declare const passwordChanged: (l: SecurityLinks, atMs: number) => EmailContent;
9
+ export declare const emailChanged: (l: SecurityLinks, newEmail: string, atMs: number) => EmailContent;
10
+ export declare const twoFactorChanged: (l: SecurityLinks, on: boolean, atMs: number) => EmailContent;
11
+ export declare const passkeyChanged: (l: SecurityLinks, added: boolean, name: string, atMs: number) => EmailContent;
12
+ export declare const backupCodesMade: (l: SecurityLinks, atMs: number) => EmailContent;
13
+ export declare const newSignIn: (l: SecurityLinks, device: string, address: string, atMs: number) => EmailContent;
14
+ //# sourceMappingURL=emails-security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emails-security.d.ts","sourceRoot":"","sources":["../../src/mail/emails-security.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAqB,MAAM,cAAc,CAAC;AAOpE,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD,eAAO,MAAM,eAAe,MAAO,aAAa,QAAQ,MAAM,iBAI1D,CAAC;AAEL,eAAO,MAAM,YAAY,MAAO,aAAa,YAAY,MAAM,QAAQ,MAAM,iBAIzE,CAAC;AAEL,eAAO,MAAM,gBAAgB,MAAO,aAAa,MAAM,OAAO,QAAQ,MAAM,iBAQzE,CAAC;AAEJ,eAAO,MAAM,cAAc,MAAO,aAAa,SAAS,OAAO,QAAQ,MAAM,QAAQ,MAAM,iBAQxF,CAAC;AAEJ,eAAO,MAAM,eAAe,MAAO,aAAa,QAAQ,MAAM,iBAI1D,CAAC;AAEL,eAAO,MAAM,SAAS,MAAO,aAAa,UAAU,MAAM,WAAW,MAAM,QAAQ,MAAM,iBAIrF,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { facts, note, text } from "./content.js";
2
+ // Notices about changes to the person's own account. They always go out: they are how a taken account gets noticed.
3
+ const FOOTER = "We send a notice for every security change to your account. These notices cannot be turned off.";
4
+ const NOT_YOU = "If this was not you, reset your password now. It signs out every device.";
5
+ const when = (ms) => `${new Date(ms).toISOString().slice(0, 16).replace("T", " ")} UTC`;
6
+ function notice(subject, heading, lines, tone, rows, action) {
7
+ return { kind: "security", subject, preview: lines[0], heading, tone, blocks: [...lines.map(text), facts(rows), note(NOT_YOU)], action, footer: FOOTER };
8
+ }
9
+ export const passwordChanged = (l, atMs) => notice("Your WizeLens password was changed", "Your password changed.", ["The password of your WizeLens account was changed. Other devices were signed out."], "neutral", [["When", when(atMs)]], {
10
+ label: "Reset your password",
11
+ url: l.forgot,
12
+ });
13
+ export const emailChanged = (l, newEmail, atMs) => notice("Your WizeLens email was changed", "Your email changed.", [`Your WizeLens account now uses ${newEmail}. This address gets no more mail from it.`], "warn", [["New email", newEmail], ["When", when(atMs)]], {
14
+ label: "Get back in",
15
+ url: l.forgot,
16
+ });
17
+ export const twoFactorChanged = (l, on, atMs) => notice(on ? "Two-step sign-in is on for WizeLens" : "Two-step sign-in is off for WizeLens", on ? "Two-step sign-in is on." : "Two-step sign-in is off.", [on ? "Signing in now needs a code from your authenticator app, or a backup code." : "Signing in now needs only your password or a passkey."], on ? "good" : "warn", [["When", when(atMs)]], { label: "Review your account", url: l.account });
18
+ export const passkeyChanged = (l, added, name, atMs) => notice(added ? "A passkey was added to your WizeLens account" : "A passkey was removed from your WizeLens account", added ? "New passkey." : "Passkey removed.", [added ? "A new passkey can now sign in to your account." : "A passkey can no longer sign in to your account."], added ? "warn" : "neutral", [["Passkey", name || "Unnamed"], ["When", when(atMs)]], { label: "Review your passkeys", url: l.account });
19
+ export const backupCodesMade = (l, atMs) => notice("New WizeLens backup codes", "New backup codes.", ["New backup codes were made for two-step sign-in. The old codes no longer work."], "neutral", [["When", when(atMs)]], {
20
+ label: "Review your account",
21
+ url: l.account,
22
+ });
23
+ export const newSignIn = (l, device, address, atMs) => notice("New sign-in to your WizeLens account", "New sign-in.", [`Your account was signed in on ${device}, a device it has not used before.`], "warn", [["Device", device], ["Address", address || "Unknown"], ["When", when(atMs)]], {
24
+ label: "Review your devices",
25
+ url: l.account,
26
+ });
27
+ //# sourceMappingURL=emails-security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emails-security.js","sourceRoot":"","sources":["../../src/mail/emails-security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type EmailContent } from "./content.js";
2
+ /** Changes in one organization since the last notice, for its owners and admins. */
3
+ export declare function teamChanges(org: string, changes: {
4
+ text: string;
5
+ timeMs: number;
6
+ }[], url: string, stop: string): EmailContent;
7
+ /** A member's own role changed. */
8
+ export declare function roleChanged(org: string, role: string, url: string, stop: string): EmailContent;
9
+ /** An organization and all its data are gone. Sent to every member, always. */
10
+ export declare function orgDeleted(org: string, by: string, url: string): EmailContent;
11
+ //# sourceMappingURL=emails-team.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emails-team.d.ts","sourceRoot":"","sources":["../../src/mail/emails-team.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAc,MAAM,cAAc,CAAC;AAI7D,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAa7H;AAED,mCAAmC;AACnC,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAY9F;AAED,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAW7E"}
@@ -0,0 +1,45 @@
1
+ import { list, text } from "./content.js";
2
+ const clock = (ms) => `${new Date(ms).toISOString().slice(0, 16).replace("T", " ")} UTC`;
3
+ /** Changes in one organization since the last notice, for its owners and admins. */
4
+ export function teamChanges(org, changes, url, stop) {
5
+ const one = changes.length === 1;
6
+ return {
7
+ kind: "team",
8
+ subject: one ? `${org}: ${changes[0].text}` : `${changes.length} changes in ${org} on WizeLens`,
9
+ preview: changes[0].text,
10
+ heading: `Changes in ${org}.`,
11
+ tone: "neutral",
12
+ blocks: [list(one ? "What changed" : `${changes.length} changes`, changes.map((c) => ({ text: c.text, meta: clock(c.timeMs) })))],
13
+ action: { label: "Open the audit log", url },
14
+ footer: `You get this because you are an owner or admin of ${org}.`,
15
+ unsubscribe: { label: "Stop team change emails", url: stop },
16
+ };
17
+ }
18
+ /** A member's own role changed. */
19
+ export function roleChanged(org, role, url, stop) {
20
+ return {
21
+ kind: "team",
22
+ subject: `Your role in ${org} is now ${role}`,
23
+ preview: `You are now ${role} in ${org}.`,
24
+ heading: `You are now ${role}.`,
25
+ tone: "neutral",
26
+ blocks: [text(`Your role in ${org} on WizeLens changed to ${role}. What you can see and change follows the new role.`)],
27
+ action: { label: `Open ${org}`, url },
28
+ footer: `You get this because you are a member of ${org}.`,
29
+ unsubscribe: { label: "Stop team change emails", url: stop },
30
+ };
31
+ }
32
+ /** An organization and all its data are gone. Sent to every member, always. */
33
+ export function orgDeleted(org, by, url) {
34
+ return {
35
+ kind: "team",
36
+ subject: `${org} was deleted on WizeLens`,
37
+ preview: `${by} deleted ${org} and all its data.`,
38
+ heading: `${org} was deleted.`,
39
+ tone: "bad",
40
+ blocks: [text(`${by} deleted ${org} on WizeLens. Its projects, traces, keys, and alerts are gone. This cannot be undone.`)],
41
+ action: { label: "Open WizeLens", url },
42
+ footer: `You get this because you were a member of ${org}.`,
43
+ };
44
+ }
45
+ //# sourceMappingURL=emails-team.js.map