@cosmicdrift/kumiko-bundled-features 0.361.0 → 0.363.0

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 (323) hide show
  1. package/dist/admin-shell/feature.d.ts +3 -0
  2. package/dist/admin-shell/feature.js +6 -1
  3. package/dist/agent-tools/agent-manifest.js +2 -1
  4. package/dist/agent-tools/filter-ops.d.ts +1 -1
  5. package/dist/agent-tools/filter-ops.js +1 -3
  6. package/dist/agent-tools/tool-dispatch.js +2 -1
  7. package/dist/auth-email-password/email-templates.d.ts +4 -26
  8. package/dist/auth-email-password/email-templates.js +9 -101
  9. package/dist/auth-email-password/feature.js +24 -6
  10. package/dist/auth-email-password/handlers/invite-create.write.js +4 -4
  11. package/dist/auth-email-password/handlers/request-account-unlock.write.js +2 -4
  12. package/dist/auth-email-password/handlers/request-email-verification.write.js +2 -4
  13. package/dist/auth-email-password/handlers/request-password-reset.write.js +2 -4
  14. package/dist/auth-email-password/handlers/signup-confirm.write.js +3 -4
  15. package/dist/auth-email-password/handlers/token-request-handler.d.ts +1 -2
  16. package/dist/auth-email-password/handlers/token-request-handler.js +0 -1
  17. package/dist/auth-email-password/index.d.ts +2 -2
  18. package/dist/auth-email-password/index.js +1 -1
  19. package/dist/auth-email-password/magic-link-mail.d.ts +3 -2
  20. package/dist/auth-email-password/magic-link-mail.js +19 -14
  21. package/dist/auth-email-password/mail-notifications.d.ts +32 -0
  22. package/dist/auth-email-password/mail-notifications.js +116 -0
  23. package/dist/auth-email-password/signup-activation.d.ts +1 -1
  24. package/dist/auth-email-password/signup-activation.js +2 -3
  25. package/dist/auth-foundation/types.js +2 -8
  26. package/dist/auth-mfa/feature.js +4 -4
  27. package/dist/auth-mfa/hmac-token-codec.js +4 -4
  28. package/dist/auth-mfa/mfa-challenge-token.js +3 -3
  29. package/dist/auth-mfa/mfa-preauth-setup-token.js +3 -3
  30. package/dist/auth-mfa/mfa-setup-token.js +8 -8
  31. package/dist/billing-foundation/constants.d.ts +3 -3
  32. package/dist/billing-foundation/constants.js +5 -4
  33. package/dist/billing-foundation/consumer-protection/confirmation-mail.d.ts +32 -14
  34. package/dist/billing-foundation/consumer-protection/confirmation-mail.js +27 -32
  35. package/dist/billing-foundation/consumer-protection/issue-confirmation.js +3 -3
  36. package/dist/billing-foundation/consumer-protection/mail-notifications.d.ts +8 -0
  37. package/dist/billing-foundation/consumer-protection/mail-notifications.js +95 -0
  38. package/dist/billing-foundation/consumer-protection/register-consent.js +2 -0
  39. package/dist/billing-foundation/consumer-protection/termination-mail.d.ts +20 -10
  40. package/dist/billing-foundation/consumer-protection/termination-mail.js +10 -21
  41. package/dist/billing-foundation/consumer-protection/termination-notify.js +2 -2
  42. package/dist/billing-foundation/consumer-protection/termination-pages.js +1 -3
  43. package/dist/billing-foundation/consumer-protection/termination-request.js +2 -2
  44. package/dist/billing-foundation/handlers/process-event.write.js +2 -2
  45. package/dist/billing-foundation/handlers/process-payment-event.write.js +1 -1
  46. package/dist/billing-foundation/subscription-tier-sync.js +3 -4
  47. package/dist/cap-overview/handlers/tenant-caps-list.query.js +2 -1
  48. package/dist/cap-overview/web/cap-usage-cell.js +5 -4
  49. package/dist/channel-email/email-channel.d.ts +2 -2
  50. package/dist/channel-email/email-channel.js +89 -26
  51. package/dist/channel-email/feature.js +3 -3
  52. package/dist/channel-email/index.d.ts +1 -1
  53. package/dist/channel-email/index.js +1 -1
  54. package/dist/channel-email/pii-guard.js +10 -0
  55. package/dist/channel-email/smtp-transport.js +13 -0
  56. package/dist/channel-email/types.d.ts +8 -0
  57. package/dist/config/handlers/set.write.js +1 -2
  58. package/dist/custom-fields/lib/value-schema.js +10 -11
  59. package/dist/custom-fields/wire-user-data-rights.js +7 -6
  60. package/dist/data-retention/index.d.ts +1 -0
  61. package/dist/data-retention/index.js +1 -0
  62. package/dist/data-retention/run-retention-cleanup.js +6 -6
  63. package/dist/delivery/attachment-ref.d.ts +39 -0
  64. package/dist/delivery/attachment-ref.js +64 -0
  65. package/dist/delivery/channel-context.d.ts +8 -4
  66. package/dist/delivery/channel-context.js +76 -2
  67. package/dist/delivery/constants.d.ts +1 -0
  68. package/dist/delivery/constants.js +1 -0
  69. package/dist/delivery/delivery-service.d.ts +4 -1
  70. package/dist/delivery/delivery-service.js +38 -32
  71. package/dist/delivery/feature.js +1 -1
  72. package/dist/delivery/index.d.ts +5 -2
  73. package/dist/delivery/index.js +4 -1
  74. package/dist/delivery/jobs.js +25 -5
  75. package/dist/delivery/notify-factory.js +4 -1
  76. package/dist/delivery/testing.d.ts +4 -1
  77. package/dist/delivery/types.d.ts +20 -14
  78. package/dist/delivery/unsubscribe.js +4 -1
  79. package/dist/derivatives-sharp/render.js +1 -18
  80. package/dist/document-ingest-foundation/aggregate-id.d.ts +1 -0
  81. package/dist/document-ingest-foundation/aggregate-id.js +8 -0
  82. package/dist/document-ingest-foundation/events.js +3 -1
  83. package/dist/document-ingest-foundation/feature.js +4 -2
  84. package/dist/document-ingest-foundation/index.d.ts +1 -0
  85. package/dist/document-ingest-foundation/index.js +1 -0
  86. package/dist/document-ingest-foundation/pages.js +4 -4
  87. package/dist/feature-toggles/toggle-sync-signal.js +4 -4
  88. package/dist/file-foundation/index.d.ts +1 -0
  89. package/dist/file-foundation/index.js +1 -0
  90. package/dist/file-foundation/read-file-ref-content.d.ts +27 -0
  91. package/dist/file-foundation/read-file-ref-content.js +49 -0
  92. package/dist/folders/web/folder-manager.js +3 -2
  93. package/dist/form-draft/db/queries/cleanup.js +4 -4
  94. package/dist/form-draft/db/queries/draft-count.js +2 -2
  95. package/dist/form-draft/db/queries/owned-file-refs.js +2 -2
  96. package/dist/form-draft/release-file-refs.js +3 -2
  97. package/dist/inbound-mail-foundation/handlers/connect-account.write.js +1 -1
  98. package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +6 -6
  99. package/dist/inbound-mail-foundation/handlers/scope-visibility.d.ts +1 -1
  100. package/dist/inbound-mail-foundation/oauth-state.js +7 -7
  101. package/dist/inbound-mail-foundation/types.js +4 -4
  102. package/dist/inbound-mail-foundation/watch-supervisor.js +22 -13
  103. package/dist/inbound-provider-imap/imap-client.js +4 -3
  104. package/dist/ledger/recurring.js +1 -3
  105. package/dist/managed-pages/branding.d.ts +2 -0
  106. package/dist/managed-pages/branding.js +24 -2
  107. package/dist/managed-pages/feature.js +1 -0
  108. package/dist/managed-pages/i18n.js +1 -0
  109. package/dist/managed-pages/screens/branding-screen.js +8 -1
  110. package/dist/page-render/branding.d.ts +1 -0
  111. package/dist/page-render/branding.js +1 -0
  112. package/dist/page-render/markdown.js +1 -1
  113. package/dist/personal-access-tokens/feature.js +1 -1
  114. package/dist/personal-access-tokens/handlers/list.query.js +2 -1
  115. package/dist/personal-access-tokens/revoke-for-user.js +2 -1
  116. package/dist/renderer-foundation/api.d.ts +13 -13
  117. package/dist/renderer-foundation/api.js +1 -1
  118. package/dist/renderer-foundation/constants.js +2 -4
  119. package/dist/renderer-foundation/feature.js +7 -7
  120. package/dist/renderer-foundation/index.d.ts +2 -1
  121. package/dist/renderer-foundation/index.js +1 -0
  122. package/dist/renderer-foundation/types.d.ts +92 -32
  123. package/dist/renderer-pdf/feature.js +7 -1
  124. package/dist/sessions/db/queries/cleanup.js +2 -2
  125. package/dist/sessions/feature.js +1 -1
  126. package/dist/sessions/handlers/list.query.js +2 -1
  127. package/dist/shared/attachment-file-name.d.ts +3 -0
  128. package/dist/shared/attachment-file-name.js +35 -0
  129. package/dist/shared/index.d.ts +3 -0
  130. package/dist/shared/index.js +3 -0
  131. package/dist/shared/is-tenant-db.js +1 -1
  132. package/dist/shared/mail-template-body.d.ts +4 -0
  133. package/dist/shared/mail-template-body.js +17 -0
  134. package/dist/shared/sharp-input-limits.d.ts +6 -0
  135. package/dist/shared/sharp-input-limits.js +22 -0
  136. package/dist/shared/signup-handover.js +2 -2
  137. package/dist/tags/handlers/assign-tag.write.js +3 -1
  138. package/dist/tags/web/tag-chip.js +2 -0
  139. package/dist/template-resolver/api.d.ts +30 -2
  140. package/dist/template-resolver/api.js +40 -5
  141. package/dist/template-resolver/compile-document-body.d.ts +8 -0
  142. package/dist/template-resolver/compile-document-body.js +163 -0
  143. package/dist/template-resolver/constants.d.ts +13 -4
  144. package/dist/template-resolver/constants.js +30 -10
  145. package/dist/template-resolver/document-sanitizer.d.ts +32 -0
  146. package/dist/template-resolver/document-sanitizer.js +201 -0
  147. package/dist/template-resolver/document-schema.d.ts +21 -0
  148. package/dist/template-resolver/document-schema.js +296 -0
  149. package/dist/template-resolver/feature.d.ts +18 -0
  150. package/dist/template-resolver/feature.js +50 -6
  151. package/dist/template-resolver/handlers/bundle-import.d.ts +20 -0
  152. package/dist/template-resolver/handlers/bundle-import.js +147 -0
  153. package/dist/template-resolver/handlers/collection-set.write.js +25 -2
  154. package/dist/template-resolver/handlers/copy-locale.write.d.ts +19 -0
  155. package/dist/template-resolver/handlers/copy-locale.write.js +116 -0
  156. package/dist/template-resolver/handlers/diff-to-system.query.d.ts +22 -0
  157. package/dist/template-resolver/handlers/diff-to-system.query.js +64 -0
  158. package/dist/template-resolver/handlers/export-bundle.query.d.ts +35 -0
  159. package/dist/template-resolver/handlers/export-bundle.query.js +68 -0
  160. package/dist/template-resolver/handlers/find-by-id.query.d.ts +1 -0
  161. package/dist/template-resolver/handlers/find-by-id.query.js +3 -3
  162. package/dist/template-resolver/handlers/import-bundle-system.write.d.ts +39 -0
  163. package/dist/template-resolver/handlers/import-bundle-system.write.js +36 -0
  164. package/dist/template-resolver/handlers/import-bundle.write.d.ts +40 -0
  165. package/dist/template-resolver/handlers/import-bundle.write.js +19 -0
  166. package/dist/template-resolver/handlers/layout-source.query.d.ts +26 -0
  167. package/dist/template-resolver/handlers/layout-source.query.js +64 -0
  168. package/dist/template-resolver/handlers/list.query.d.ts +4 -1
  169. package/dist/template-resolver/handlers/list.query.js +5 -7
  170. package/dist/template-resolver/handlers/overview.query.d.ts +59 -0
  171. package/dist/template-resolver/handlers/overview.query.js +165 -0
  172. package/dist/template-resolver/handlers/preview.query.d.ts +12 -0
  173. package/dist/template-resolver/handlers/preview.query.js +24 -0
  174. package/dist/template-resolver/handlers/reset-to-system.write.d.ts +8 -0
  175. package/dist/template-resolver/handlers/reset-to-system.write.js +50 -0
  176. package/dist/template-resolver/handlers/resource-link-pdf.write.d.ts +8 -0
  177. package/dist/template-resolver/handlers/resource-link-pdf.write.js +32 -0
  178. package/dist/template-resolver/handlers/resource-remove.write.d.ts +9 -0
  179. package/dist/template-resolver/handlers/resource-remove.write.js +44 -0
  180. package/dist/template-resolver/handlers/resource-shared.d.ts +9 -0
  181. package/dist/template-resolver/handlers/resource-shared.js +14 -0
  182. package/dist/template-resolver/handlers/resource-upload.write.d.ts +13 -0
  183. package/dist/template-resolver/handlers/resource-upload.write.js +98 -0
  184. package/dist/template-resolver/handlers/send-test.write.d.ts +11 -0
  185. package/dist/template-resolver/handlers/send-test.write.js +81 -0
  186. package/dist/template-resolver/handlers/set.write.d.ts +4 -1
  187. package/dist/template-resolver/handlers/set.write.js +25 -3
  188. package/dist/template-resolver/handlers/shared.d.ts +9 -5
  189. package/dist/template-resolver/handlers/shared.js +6 -2
  190. package/dist/template-resolver/handlers/template-gates.d.ts +36 -0
  191. package/dist/template-resolver/handlers/template-gates.js +131 -0
  192. package/dist/template-resolver/handlers/template-write.d.ts +45 -0
  193. package/dist/template-resolver/handlers/template-write.js +109 -0
  194. package/dist/template-resolver/handlers/tenant-overrides.query.d.ts +17 -0
  195. package/dist/template-resolver/handlers/tenant-overrides.query.js +48 -0
  196. package/dist/template-resolver/handlers/toggle-status.write.d.ts +12 -0
  197. package/dist/template-resolver/handlers/toggle-status.write.js +27 -11
  198. package/dist/template-resolver/handlers/upsert-system.write.d.ts +5 -8
  199. package/dist/template-resolver/handlers/upsert-system.write.js +14 -59
  200. package/dist/template-resolver/handlers/upsert-tenant.write.d.ts +5 -8
  201. package/dist/template-resolver/handlers/upsert-tenant.write.js +10 -61
  202. package/dist/template-resolver/handlers/usage.query.d.ts +17 -0
  203. package/dist/template-resolver/handlers/usage.query.js +15 -0
  204. package/dist/template-resolver/handlers/validate.query.d.ts +74 -0
  205. package/dist/template-resolver/handlers/validate.query.js +80 -0
  206. package/dist/template-resolver/index.d.ts +18 -1
  207. package/dist/template-resolver/index.js +16 -1
  208. package/dist/template-resolver/layout-regions.d.ts +23 -0
  209. package/dist/template-resolver/layout-regions.js +125 -0
  210. package/dist/template-resolver/linked-resources.d.ts +17 -0
  211. package/dist/template-resolver/linked-resources.js +75 -0
  212. package/dist/template-resolver/preview-display-html.d.ts +7 -0
  213. package/dist/template-resolver/preview-display-html.js +27 -0
  214. package/dist/template-resolver/print-document.d.ts +1 -0
  215. package/dist/template-resolver/print-document.js +55 -0
  216. package/dist/template-resolver/qualified-names.d.ts +30 -0
  217. package/dist/template-resolver/qualified-names.js +30 -0
  218. package/dist/template-resolver/record-mapping.d.ts +2 -0
  219. package/dist/template-resolver/record-mapping.js +21 -0
  220. package/dist/template-resolver/resource-image.d.ts +15 -0
  221. package/dist/template-resolver/resource-image.js +34 -0
  222. package/dist/template-resolver/seeding.d.ts +14 -1
  223. package/dist/template-resolver/seeding.js +105 -15
  224. package/dist/template-resolver/store-template-resource.d.ts +64 -0
  225. package/dist/template-resolver/store-template-resource.js +264 -0
  226. package/dist/template-resolver/table.d.ts +47 -8
  227. package/dist/template-resolver/table.js +11 -0
  228. package/dist/template-resolver/template-bundle.d.ts +36 -0
  229. package/dist/template-resolver/template-bundle.js +60 -0
  230. package/dist/template-resolver/template-diff.d.ts +7 -0
  231. package/dist/template-resolver/template-diff.js +68 -0
  232. package/dist/template-resolver/template-meta.d.ts +60 -0
  233. package/dist/template-resolver/template-meta.js +101 -0
  234. package/dist/template-resolver/template-preview.d.ts +86 -0
  235. package/dist/template-resolver/template-preview.js +374 -0
  236. package/dist/template-resolver/template-resources.d.ts +14 -0
  237. package/dist/template-resolver/template-resources.js +42 -0
  238. package/dist/template-resolver/template-usage.d.ts +12 -0
  239. package/dist/template-resolver/template-usage.js +30 -0
  240. package/dist/template-resolver/template-validation.d.ts +22 -0
  241. package/dist/template-resolver/template-validation.js +172 -0
  242. package/dist/template-resolver/testing.js +5 -5
  243. package/dist/template-resolver/user-content-table.d.ts +14 -8
  244. package/dist/template-resolver/web/client-plugin.d.ts +1 -0
  245. package/dist/template-resolver/web/client-plugin.js +9 -6
  246. package/dist/template-resolver/web/document-editor-extensions.d.ts +15 -0
  247. package/dist/template-resolver/web/document-editor-extensions.js +107 -0
  248. package/dist/template-resolver/web/document-editor.d.ts +3 -0
  249. package/dist/template-resolver/web/document-editor.js +11 -0
  250. package/dist/template-resolver/web/document-tiptap-editor.d.ts +3 -0
  251. package/dist/template-resolver/web/document-tiptap-editor.js +376 -0
  252. package/dist/template-resolver/web/document-toolbar-blocks.d.ts +33 -0
  253. package/dist/template-resolver/web/document-toolbar-blocks.js +15 -0
  254. package/dist/template-resolver/web/editor-handle.d.ts +3 -0
  255. package/dist/template-resolver/web/editor-handle.js +24 -0
  256. package/dist/template-resolver/web/i18n.js +76 -0
  257. package/dist/template-resolver/web/index.d.ts +4 -0
  258. package/dist/template-resolver/web/index.js +4 -0
  259. package/dist/template-resolver/web/placeholder-line-editor-lazy.d.ts +4 -0
  260. package/dist/template-resolver/web/placeholder-line-editor-lazy.js +16 -0
  261. package/dist/template-resolver/web/placeholder-line-editor.d.ts +15 -0
  262. package/dist/template-resolver/web/placeholder-line-editor.js +94 -0
  263. package/dist/template-resolver/web/placeholder-text.d.ts +4 -0
  264. package/dist/template-resolver/web/placeholder-text.js +34 -0
  265. package/dist/template-resolver/web/use-stable-by-key.d.ts +1 -0
  266. package/dist/template-resolver/web/use-stable-by-key.js +13 -0
  267. package/dist/tenant/handlers/team-list.query.js +3 -2
  268. package/dist/tenant/seeding.js +31 -6
  269. package/dist/tenant-lifecycle/handlers/cancel-destruction.write.d.ts +1 -1
  270. package/dist/tenant-lifecycle/handlers/cancel-destruction.write.js +2 -1
  271. package/dist/user/db/queries/stream-tenant-backfill.js +4 -4
  272. package/dist/user/handlers/detail.query.js +2 -1
  273. package/dist/user-data-rights/db/queries/forget-cleanup.d.ts +2 -2
  274. package/dist/user-data-rights/email-templates.d.ts +1 -29
  275. package/dist/user-data-rights/email-templates.js +5 -106
  276. package/dist/user-data-rights/feature.js +53 -35
  277. package/dist/user-data-rights/handlers/cancel-deletion.write.d.ts +1 -1
  278. package/dist/user-data-rights/handlers/cancel-deletion.write.js +2 -1
  279. package/dist/user-data-rights/handlers/download-by-token.query.js +5 -1
  280. package/dist/user-data-rights/handlers/list-download-attempts.query.d.ts +1 -1
  281. package/dist/user-data-rights/handlers/list-download-attempts.query.js +10 -1
  282. package/dist/user-data-rights/handlers/request-deletion.write.js +5 -7
  283. package/dist/user-data-rights/index.d.ts +1 -0
  284. package/dist/user-data-rights/index.js +1 -0
  285. package/dist/user-data-rights/lib/default-mailers.d.ts +15 -7
  286. package/dist/user-data-rights/lib/default-mailers.js +100 -48
  287. package/dist/user-data-rights/lib/update-user-lifecycle.js +1 -1
  288. package/dist/user-data-rights/mail-notifications.d.ts +13 -0
  289. package/dist/user-data-rights/mail-notifications.js +118 -0
  290. package/dist/user-data-rights/schema/download-attempt.js +6 -12
  291. package/dist/user-data-rights/web/privacy-center-screen.js +2 -1
  292. package/dist/user-data-rights-defaults/feature.js +6 -1
  293. package/dist/user-data-rights-defaults/hooks/download-attempt.userdata-hook.d.ts +3 -0
  294. package/dist/user-data-rights-defaults/hooks/download-attempt.userdata-hook.js +48 -0
  295. package/dist/user-profile/web/profile-screen.js +2 -1
  296. package/dist/waitlist/feature.js +10 -0
  297. package/dist/waitlist/handlers/submit.write.js +3 -4
  298. package/dist/waitlist/mail.d.ts +19 -6
  299. package/dist/waitlist/mail.js +50 -14
  300. package/package.json +28 -17
  301. package/src/admin-shell/changes.json +6 -0
  302. package/src/auth-email-password/changes.json +14 -0
  303. package/src/billing-foundation/changes.json +7 -0
  304. package/src/channel-email/changes.json +19 -0
  305. package/src/data-retention/changes.json +6 -0
  306. package/src/delivery/changes.json +48 -0
  307. package/src/document-ingest-foundation/changes.json +6 -0
  308. package/src/managed-pages/changes.json +6 -0
  309. package/src/renderer-foundation/changes.json +39 -0
  310. package/src/template-resolver/changes.json +118 -0
  311. package/src/user-data-rights/changes.json +14 -0
  312. package/src/waitlist/changes.json +7 -0
  313. package/dist/renderer-simple/feature.d.ts +0 -10
  314. package/dist/renderer-simple/feature.js +0 -42
  315. package/dist/renderer-simple/index.d.ts +0 -3
  316. package/dist/renderer-simple/index.js +0 -2
  317. package/dist/renderer-simple/mail-blocks.d.ts +0 -21
  318. package/dist/renderer-simple/mail-blocks.js +0 -107
  319. package/dist/renderer-simple/resolve-variables.d.ts +0 -7
  320. package/dist/renderer-simple/resolve-variables.js +0 -47
  321. package/dist/renderer-simple/simple-renderer.d.ts +0 -24
  322. package/dist/renderer-simple/simple-renderer.js +0 -200
  323. package/src/renderer-simple/changes.json +0 -27
@@ -12,6 +12,9 @@ export type CreateAdminShellOptions = {
12
12
  * Requires cap-overview mounted. Default false — apps that don't mount cap-overview
13
13
  * must not get a nav entry pointing at a screen that doesn't exist. */
14
14
  readonly includeCapOverview?: boolean;
15
+ /** Tenant nav → document-designer:nav:templates, platform nav → document-designer:nav:platform-templates.
16
+ * Requires document-designer mounted (a separate package, so no import here). Default false. */
17
+ readonly includeDocumentDesigner?: boolean;
15
18
  /** When false, only overview screens + nav are registered — app owns r.workspace(). Default true. */
16
19
  readonly registerWorkspaces?: boolean;
17
20
  /** Metric list the overview panels are built from — pass the SAME list to
@@ -11,10 +11,11 @@ export function createAdminShellFeature(options = {}) {
11
11
  const platformWsId = options.workspaceIds?.platform ?? DEFAULT_PLATFORM_WORKSPACE_ID;
12
12
  const includeTierAdmin = options.includeTierAdmin ?? true;
13
13
  const includeCapOverview = options.includeCapOverview ?? false;
14
+ const includeDocumentDesigner = options.includeDocumentDesigner ?? false;
14
15
  const registerWorkspaces = options.registerWorkspaces ?? true;
15
16
  const metrics = options.metrics ?? DEFAULT_METRICS;
16
17
  return defineFeature(ADMIN_SHELL_FEATURE, (r) => {
17
- r.describe("Registers tenant-admin and platform-admin workspaces with provider nav into owner-feature screens (`tenant:screen:members`, `audit:screen:audit-log`, `tenant:screen:tenant-list`, `jobs:screen:job-runs`, optional `tier-engine:screen:tier-admin`, optional `cap-overview:screen:my-caps`/`cap-overview:screen:tenant-cap-list`) and the two overview dashboards, built from the metrics list (`metrics` option, default DEFAULT_METRICS). Mount after user, tenant, audit, jobs, metrics and metrics-system; pass `workspaceIds` to match app URL conventions (e.g. Studio `d`/`s`, PublicStatus `admin`/`sysadmin`). Client: `adminShellClient()`, `tenantClient()`, `auditClient()`, `jobsClient()`, optional `tierEngineClient()`.");
18
+ r.describe("Registers tenant-admin and platform-admin workspaces with provider nav into owner-feature screens (`tenant:screen:members`, `audit:screen:audit-log`, `tenant:screen:tenant-list`, `jobs:screen:job-runs`, optional `tier-engine:screen:tier-admin`, optional `cap-overview:screen:my-caps`/`cap-overview:screen:tenant-cap-list`, optional `document-designer` template navs) and the two overview dashboards, built from the metrics list (`metrics` option, default DEFAULT_METRICS). Mount after user, tenant, audit, jobs, metrics and metrics-system; pass `workspaceIds` to match app URL conventions (e.g. Studio `d`/`s`, PublicStatus `admin`/`sysadmin`). Client: `adminShellClient()`, `tenantClient()`, `auditClient()`, `jobsClient()`, optional `tierEngineClient()`.");
18
19
  r.uiHints({
19
20
  displayLabel: "Admin Shell",
20
21
  category: "operations",
@@ -30,18 +31,22 @@ export function createAdminShellFeature(options = {}) {
30
31
  r.requires("tier-engine");
31
32
  if (includeCapOverview)
32
33
  r.requires("cap-overview");
34
+ if (includeDocumentDesigner)
35
+ r.requires("document-designer");
33
36
  r.translations({ keys: ADMIN_SHELL_I18N });
34
37
  const tenantNav = [
35
38
  "admin-shell:nav:tenant-overview",
36
39
  "tenant:nav:members",
37
40
  "audit:nav:audit-log",
38
41
  ...(includeCapOverview ? ["admin-shell:nav:my-caps"] : []),
42
+ ...(includeDocumentDesigner ? ["document-designer:nav:templates"] : []),
39
43
  ];
40
44
  const platformNav = [
41
45
  "admin-shell:nav:platform-overview",
42
46
  "admin-shell:nav:tenants",
43
47
  ...(includeCapOverview ? ["admin-shell:nav:tenant-caps"] : []),
44
48
  "jobs:nav:job-runs",
49
+ ...(includeDocumentDesigner ? ["document-designer:nav:platform-templates"] : []),
45
50
  ...(includeTierAdmin ? ["admin-shell:nav:tier-admin"] : []),
46
51
  ];
47
52
  r.screen({
@@ -1,5 +1,6 @@
1
1
  import { hasAccess, isAgentVisibleScreen, resolveAgentExposure, SYSTEM_ONLY_JSON_SCHEMA_KEY, } from "@cosmicdrift/kumiko-framework/engine";
2
2
  import { translationValueOtherText } from "@cosmicdrift/kumiko-framework/ui-types";
3
+ import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
3
4
  import * as z from "zod";
4
5
  import { recordManifestDenyQns } from "./manifest-deny-qns.js";
5
6
  /** The manifest surfaces one string per locale — a plural entry reads as its
@@ -124,7 +125,7 @@ export function systemOnlyPropertyNames(jsonSchema) {
124
125
  if (typeof properties !== "object" || properties === null)
125
126
  return [];
126
127
  return Object.entries(properties)
127
- .filter(([, property]) => property[SYSTEM_ONLY_JSON_SCHEMA_KEY] === true)
128
+ .filter(([, property]) => isPlainObject(property) && property[SYSTEM_ONLY_JSON_SCHEMA_KEY] === true)
128
129
  .map(([name]) => name);
129
130
  }
130
131
  function withoutSystemOnlyProperties(jsonSchema) {
@@ -1,2 +1,2 @@
1
1
  export declare const FILTER_OPS: readonly ["eq", "ne", "lt", "gt", "lte", "gte", "in"];
2
- export declare function isRecord(value: unknown): value is Record<string, unknown>;
2
+ export { isPlainObject as isRecord } from "@cosmicdrift/kumiko-types/type-guards";
@@ -1,4 +1,2 @@
1
1
  export const FILTER_OPS = ["eq", "ne", "lt", "gt", "lte", "gte", "in"];
2
- export function isRecord(value) {
3
- return typeof value === "object" && value !== null && !Array.isArray(value);
4
- }
2
+ export { isPlainObject as isRecord } from "@cosmicdrift/kumiko-types/type-guards";
@@ -1,10 +1,11 @@
1
1
  import { runAsDirectCallEntry } from "@cosmicdrift/kumiko-framework/internal/request-context";
2
+ import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
2
3
  import { FILTER_OPS, isRecord } from "./filter-ops.js";
3
4
  const SEARCH_RESULT_LIMIT = 10;
4
5
  const DEFAULT_LIST_LIMIT = 10;
5
6
  const MAX_LIST_LIMIT = 200;
6
7
  function isFilterOp(value) {
7
- return typeof value === "string" && FILTER_OPS.includes(value);
8
+ return isOneOf(FILTER_OPS, value);
8
9
  }
9
10
  function buildSearchPayload(toolName, toolInput) {
10
11
  const query = toolInput["query"];
@@ -1,35 +1,13 @@
1
1
  export type AuthMailLocale = string;
2
2
  export declare const AUTH_MAIL_EN: Readonly<Record<string, string>>;
3
- export type RenderTokenContentArgs = {
4
- readonly url: string;
3
+ export type TokenMailTiming = {
5
4
  readonly expiresAt: string;
6
- readonly locale?: AuthMailLocale;
7
- /** Optional app name for subject + intro. Default from auth.mail.appNameDefault. */
8
- readonly appName?: string;
9
5
  /** ISO instant the token was issued; the validity duration is measured from it. Default: now. */
10
6
  readonly issuedAt?: string;
11
7
  /** IANA zone the expiry time is shown in. Default "UTC"; an invalid zone falls back to "UTC". */
12
8
  readonly timeZone?: string;
13
9
  };
14
- export type RenderInviteEmailArgs = RenderTokenContentArgs & {
15
- readonly role: string;
10
+ export declare function tokenMailExpiry(args: TokenMailTiming, locale: string): {
11
+ readonly validFor: string;
12
+ readonly validUntil: string;
16
13
  };
17
- export type AuthMailSection = {
18
- readonly text: string;
19
- } | {
20
- readonly button: {
21
- readonly label: string;
22
- readonly url: string;
23
- };
24
- };
25
- export type AuthMailContent = {
26
- readonly subject: string;
27
- readonly header: string;
28
- readonly sections: readonly AuthMailSection[];
29
- readonly footer: string;
30
- };
31
- export declare function renderResetPasswordEmail(args: RenderTokenContentArgs): AuthMailContent;
32
- export declare function renderUnlockAccountEmail(args: RenderTokenContentArgs): AuthMailContent;
33
- export declare function renderVerifyEmail(args: RenderTokenContentArgs): AuthMailContent;
34
- export declare function renderActivationEmail(args: RenderTokenContentArgs): AuthMailContent;
35
- export declare function renderInviteEmail(args: RenderInviteEmailArgs): AuthMailContent;
@@ -1,13 +1,10 @@
1
- // Default renderers for the transactional auth mails. All four magic-link flows
2
- // (password-reset, email-verification, signup-activation, invite) emit
3
- // structured AuthMailContent that the handler hands to delivery (ctx.notify) —
4
- // renderer-simple turns it into HTML. Apps wanting their own branding swap the
5
- // renderer; these templates are deliberately plain so the renderer (and the
6
- // operator reading the mailer log) can rely on them.
1
+ // English texts and expiry formatting for the transactional auth mails. The
2
+ // mail bodies are built from these keys into stored templates (see
3
+ // mail-notifications.ts).
7
4
  //
8
5
  // English ships here. Other languages register via @cosmicdrift/kumiko-locale-*
9
6
  // (localeDe() / localeEs() call registerMailTranslations).
10
- import { mailT, registerMailTranslations } from "@cosmicdrift/kumiko-framework/i18n";
7
+ import { registerMailTranslations } from "@cosmicdrift/kumiko-framework/i18n";
11
8
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
12
9
  export const AUTH_MAIL_EN = {
13
10
  "auth.mail.appNameDefault": "Account",
@@ -43,96 +40,6 @@ export const AUTH_MAIL_EN = {
43
40
  "auth.mail.unlock.ignore": "If you didn't trigger this lock, you can ignore this email — the lock expires on its own.",
44
41
  };
45
42
  registerMailTranslations("en", AUTH_MAIL_EN);
46
- function tokenMailContent(spec) {
47
- return {
48
- subject: spec.subject,
49
- header: spec.header,
50
- sections: [
51
- { text: spec.greeting },
52
- { text: spec.intro },
53
- { button: { label: spec.buttonLabel, url: spec.buttonUrl } },
54
- { text: spec.expiry },
55
- ],
56
- footer: spec.ignore,
57
- };
58
- }
59
- function t(locale, key, params) {
60
- return mailT(locale, key, params);
61
- }
62
- function appNameFor(args) {
63
- const locale = args.locale ?? "en";
64
- return args.appName ?? t(locale, "auth.mail.appNameDefault");
65
- }
66
- export function renderResetPasswordEmail(args) {
67
- const locale = args.locale ?? "en";
68
- const app = appNameFor(args);
69
- return tokenMailContent({
70
- subject: t(locale, "auth.mail.reset.subject", { app }),
71
- header: t(locale, "auth.mail.reset.button"),
72
- greeting: t(locale, "auth.mail.reset.greeting"),
73
- intro: t(locale, "auth.mail.reset.intro", { app }),
74
- buttonLabel: t(locale, "auth.mail.reset.button"),
75
- buttonUrl: args.url,
76
- expiry: t(locale, "auth.mail.reset.expiry", expiryParams(args, locale)),
77
- ignore: t(locale, "auth.mail.reset.ignore"),
78
- });
79
- }
80
- export function renderUnlockAccountEmail(args) {
81
- const locale = args.locale ?? "en";
82
- const app = appNameFor(args);
83
- return tokenMailContent({
84
- subject: t(locale, "auth.mail.unlock.subject", { app }),
85
- header: t(locale, "auth.mail.unlock.button"),
86
- greeting: t(locale, "auth.mail.unlock.greeting"),
87
- intro: t(locale, "auth.mail.unlock.intro", { app }),
88
- buttonLabel: t(locale, "auth.mail.unlock.button"),
89
- buttonUrl: args.url,
90
- expiry: t(locale, "auth.mail.unlock.expiry", expiryParams(args, locale)),
91
- ignore: t(locale, "auth.mail.unlock.ignore"),
92
- });
93
- }
94
- export function renderVerifyEmail(args) {
95
- const locale = args.locale ?? "en";
96
- const app = appNameFor(args);
97
- return tokenMailContent({
98
- subject: t(locale, "auth.mail.verify.subject", { app }),
99
- header: t(locale, "auth.mail.verify.button"),
100
- greeting: t(locale, "auth.mail.verify.greeting"),
101
- intro: t(locale, "auth.mail.verify.intro", { app }),
102
- buttonLabel: t(locale, "auth.mail.verify.button"),
103
- buttonUrl: args.url,
104
- expiry: t(locale, "auth.mail.verify.expiry", expiryParams(args, locale)),
105
- ignore: t(locale, "auth.mail.verify.ignore"),
106
- });
107
- }
108
- export function renderActivationEmail(args) {
109
- const locale = args.locale ?? "en";
110
- const app = appNameFor(args);
111
- return tokenMailContent({
112
- subject: t(locale, "auth.mail.activation.subject", { app }),
113
- header: t(locale, "auth.mail.activation.button"),
114
- greeting: t(locale, "auth.mail.activation.greeting"),
115
- intro: t(locale, "auth.mail.activation.intro", { app }),
116
- buttonLabel: t(locale, "auth.mail.activation.button"),
117
- buttonUrl: args.url,
118
- expiry: t(locale, "auth.mail.activation.expiry", expiryParams(args, locale)),
119
- ignore: t(locale, "auth.mail.activation.ignore"),
120
- });
121
- }
122
- export function renderInviteEmail(args) {
123
- const locale = args.locale ?? "en";
124
- const app = args.appName ?? "Workspace";
125
- return tokenMailContent({
126
- subject: t(locale, "auth.mail.invite.subject", { app }),
127
- header: t(locale, "auth.mail.invite.button"),
128
- greeting: t(locale, "auth.mail.invite.greeting"),
129
- intro: t(locale, "auth.mail.invite.intro", { app, role: args.role }),
130
- buttonLabel: t(locale, "auth.mail.invite.button"),
131
- buttonUrl: args.url,
132
- expiry: t(locale, "auth.mail.invite.expiry", expiryParams(args, locale)),
133
- ignore: t(locale, "auth.mail.invite.ignore"),
134
- });
135
- }
136
43
  const MS_PER_MINUTE = 60_000;
137
44
  const MS_PER_HOUR = 60 * MS_PER_MINUTE;
138
45
  const MS_PER_DAY = 24 * MS_PER_HOUR;
@@ -185,16 +92,17 @@ function formatWhen(expiresAt, locale, timeZone) {
185
92
  }
186
93
  }
187
94
  }
188
- function expiryParams(args, locale) {
95
+ // Formatted as text here because the stored template only knows plain variables.
96
+ export function tokenMailExpiry(args, locale) {
189
97
  try {
190
98
  const expiresAt = Temporal.Instant.from(args.expiresAt);
191
99
  const issuedAt = args.issuedAt ? Temporal.Instant.from(args.issuedAt) : Temporal.Now.instant();
192
100
  return {
193
- duration: formatDuration(expiresAt.epochMilliseconds - issuedAt.epochMilliseconds, locale),
194
- when: formatWhen(expiresAt, locale, args.timeZone ?? "UTC"),
101
+ validFor: formatDuration(expiresAt.epochMilliseconds - issuedAt.epochMilliseconds, locale),
102
+ validUntil: formatWhen(expiresAt, locale, args.timeZone ?? "UTC"),
195
103
  };
196
104
  }
197
105
  catch {
198
- return { duration: args.expiresAt, when: args.expiresAt };
106
+ return { validFor: args.expiresAt, validUntil: args.expiresAt };
199
107
  }
200
108
  }
@@ -19,6 +19,7 @@ import { createSignupConfirmHandler } from "./handlers/signup-confirm.write.js";
19
19
  import { createSignupRequestHandler, } from "./handlers/signup-request.write.js";
20
20
  import { createSwitchTenantMfaGateHandler } from "./handlers/switch-tenant-mfa-gate.write.js";
21
21
  import { createVerifyEmailHandler } from "./handlers/verify-email.write.js";
22
+ import { AUTH_MAIL_VARIABLES, authMailLocalizedTemplate, INVITE_MAIL_VARIABLES, sendsMagicLinkMail, } from "./mail-notifications.js";
22
23
  /**
23
24
  * Env-vars contract for the `auth-email-password` feature.
24
25
  *
@@ -85,14 +86,31 @@ export function createAuthEmailPasswordFeature(opts = {}) {
85
86
  // All five magic-link flows (reset/verify/signup/invite/unlock) dispatch
86
87
  // via ctx.notify → delivery must be mounted. Fail closed at boot instead
87
88
  // of silently dropping the mail.
88
- if (opts.passwordReset ||
89
- opts.emailVerification ||
90
- opts.signup ||
91
- opts.invite ||
92
- opts.accountUnlock) {
89
+ if (sendsMagicLinkMail(opts))
93
90
  r.requires("delivery");
94
- }
95
91
  r.envSchema(authEmailPasswordEnvSchema);
92
+ // Declared unconditionally: apps also issue the activation link from their
93
+ // own flows (issueSignupActivation) without enabling the signup option.
94
+ r.notification("password-reset", {
95
+ variables: AUTH_MAIL_VARIABLES,
96
+ localizedTemplate: authMailLocalizedTemplate("passwordReset"),
97
+ });
98
+ r.notification("account-unlock", {
99
+ variables: AUTH_MAIL_VARIABLES,
100
+ localizedTemplate: authMailLocalizedTemplate("accountUnlock"),
101
+ });
102
+ r.notification("email-verification", {
103
+ variables: AUTH_MAIL_VARIABLES,
104
+ localizedTemplate: authMailLocalizedTemplate("emailVerification"),
105
+ });
106
+ r.notification("signup-activation", {
107
+ variables: AUTH_MAIL_VARIABLES,
108
+ localizedTemplate: authMailLocalizedTemplate("signupActivation"),
109
+ });
110
+ r.notification("invite", {
111
+ variables: INVITE_MAIL_VARIABLES,
112
+ localizedTemplate: authMailLocalizedTemplate("invite"),
113
+ });
96
114
  const handlers = {
97
115
  login: r.writeHandler(createLoginHandler({
98
116
  strictEmailVerification: strictVerification,
@@ -33,11 +33,10 @@ import { GLOBAL_ROLE_OPTIONS } from "../../user/constants.js";
33
33
  // kumiko-lint-ignore cross-feature-import invitee lookup by email reads the user row
34
34
  import { userTable } from "../../user/schema/user.js";
35
35
  import { AUTH_INVITE_DEFAULT_TTL_MINUTES } from "../constants.js";
36
- import { renderInviteEmail } from "../email-templates.js";
37
36
  import { inviteAlreadyAccepted } from "../errors.js";
38
37
  import { invalidateExistingInviteToken, storeInviteToken } from "../invite-token-store.js";
39
38
  import { dispatchMagicLinkMail, resolveHandlerMailLocale } from "../magic-link-mail.js";
40
- const INVITE_NOTIFICATION_TYPE = "auth-email-password:invite";
39
+ import { AuthMailNotificationTypes } from "../mail-notifications.js";
41
40
  const InviteCreateSchema = z.object({
42
41
  email: z.email(),
43
42
  role: z.string().min(1).max(50),
@@ -137,8 +136,8 @@ async function issueInvitation(opts, ttlSeconds, request, inviter, ctx, refuseAc
137
136
  const locale = resolveHandlerMailLocale(ctx, opts.locale);
138
137
  await dispatchMagicLinkMail(ctx.notify, {
139
138
  handlerName: "invite-create",
140
- notificationType: INVITE_NOTIFICATION_TYPE,
141
- renderContent: (renderArgs) => renderInviteEmail({ ...renderArgs, role: request.role }),
139
+ notificationType: AuthMailNotificationTypes.invite,
140
+ fallbackAppName: "Workspace",
142
141
  }, {
143
142
  email,
144
143
  appUrl: opts.appUrl,
@@ -146,6 +145,7 @@ async function issueInvitation(opts, ttlSeconds, request, inviter, ctx, refuseAc
146
145
  expiresAt: expiresAt.toString(),
147
146
  issuedAt: issuedAt.toString(),
148
147
  timeZone: ctx.tz.user,
148
+ role: request.role,
149
149
  ...(opts.appName !== undefined && { appName: opts.appName }),
150
150
  locale,
151
151
  });
@@ -1,8 +1,7 @@
1
1
  import { AUTH_UNLOCK_DEFAULT_TTL_MINUTES, AuthErrors } from "../constants.js";
2
- import { renderUnlockAccountEmail } from "../email-templates.js";
2
+ import { AuthMailNotificationTypes } from "../mail-notifications.js";
3
3
  import { signUnlockToken } from "../unlock-token.js";
4
4
  import { createTokenRequestHandler, } from "./token-request-handler.js";
5
- const UNLOCK_NOTIFICATION_TYPE = "auth-email-password:account-unlock";
6
5
  // @wrapper-known semantic-alias
7
6
  export function createRequestAccountUnlockHandler(opts) {
8
7
  return createTokenRequestHandler({
@@ -18,7 +17,6 @@ export function createRequestAccountUnlockHandler(opts) {
18
17
  // locked right now. Confirming just clears the (possibly already
19
18
  // empty) lockout state — harmless no-op if they weren't locked.
20
19
  extraSilentSkip: () => false,
21
- notificationType: UNLOCK_NOTIFICATION_TYPE,
22
- renderContent: renderUnlockAccountEmail,
20
+ notificationType: AuthMailNotificationTypes.accountUnlock,
23
21
  }, opts);
24
22
  }
@@ -1,8 +1,7 @@
1
1
  import { AUTH_VERIFY_DEFAULT_TTL_MINUTES, AuthErrors } from "../constants.js";
2
- import { renderVerifyEmail } from "../email-templates.js";
2
+ import { AuthMailNotificationTypes } from "../mail-notifications.js";
3
3
  import { signVerificationToken } from "../verification-token.js";
4
4
  import { createTokenRequestHandler, } from "./token-request-handler.js";
5
- const VERIFY_NOTIFICATION_TYPE = "auth-email-password:email-verification";
6
5
  // @wrapper-known semantic-alias
7
6
  export function createRequestEmailVerificationHandler(opts) {
8
7
  return createTokenRequestHandler({
@@ -17,7 +16,6 @@ export function createRequestEmailVerificationHandler(opts) {
17
16
  // unknown/deleted to keep the enumeration surface symmetric — the
18
17
  // caller sees the same 200 regardless of whether a token was minted.
19
18
  extraSilentSkip: (user) => user.emailVerified === true,
20
- notificationType: VERIFY_NOTIFICATION_TYPE,
21
- renderContent: renderVerifyEmail,
19
+ notificationType: AuthMailNotificationTypes.emailVerification,
22
20
  }, opts);
23
21
  }
@@ -1,8 +1,7 @@
1
1
  import { AUTH_RESET_DEFAULT_TTL_MINUTES, AuthErrors } from "../constants.js";
2
- import { renderResetPasswordEmail } from "../email-templates.js";
2
+ import { AuthMailNotificationTypes } from "../mail-notifications.js";
3
3
  import { signResetToken } from "../reset-token.js";
4
4
  import { createTokenRequestHandler, } from "./token-request-handler.js";
5
- const RESET_NOTIFICATION_TYPE = "auth-email-password:password-reset";
6
5
  // @wrapper-known semantic-alias
7
6
  export function createRequestPasswordResetHandler(opts) {
8
7
  return createTokenRequestHandler({
@@ -17,7 +16,6 @@ export function createRequestPasswordResetHandler(opts) {
17
16
  // non-deleted user can initiate a reset regardless of verification
18
17
  // state. The sessions feature handles the post-change revocation.
19
18
  extraSilentSkip: () => false,
20
- notificationType: RESET_NOTIFICATION_TYPE,
21
- renderContent: renderResetPasswordEmail,
19
+ notificationType: AuthMailNotificationTypes.passwordReset,
22
20
  }, opts);
23
21
  }
@@ -23,6 +23,7 @@ import { defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
23
23
  import { ConflictError, InternalError, reraiseAsKumikoError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
24
24
  import { generateUniqueName } from "@cosmicdrift/kumiko-framework/random";
25
25
  import { generateId } from "@cosmicdrift/kumiko-framework/utils";
26
+ import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
26
27
  import * as z from "zod";
27
28
  import { findSignupHandoverProvider, registrationLocaleFromRequest, SIGNUP_HANDOVER_BENIGN_CLAIM_REJECTION_CODE, } from "../../shared/index.js";
28
29
  // kumiko-lint-ignore cross-feature-import signup-confirm reads tenants.key for slug-uniqueness check (TOCTOU + DB-unique-index zusammen)
@@ -44,10 +45,8 @@ const SIGNUP_CONFIRM_PROVISION_REASON = "provisions a new tenant, its first user
44
45
  // directly against SIGNUP_HANDOVER_BENIGN_CLAIM_REJECTION_CODE would never
45
46
  // match; this reads the same field the framework itself uses.
46
47
  function isBenignClaimRejection(error) {
47
- return (typeof error.details === "object" &&
48
- error.details !== null &&
49
- error.details["reason"] ===
50
- SIGNUP_HANDOVER_BENIGN_CLAIM_REJECTION_CODE);
48
+ return (isPlainObject(error.details) &&
49
+ error.details["reason"] === SIGNUP_HANDOVER_BENIGN_CLAIM_REJECTION_CODE);
51
50
  }
52
51
  // Rides the caller's tx. A benign claim rejection (nothing was written) logs
53
52
  // and yields undefined; any other failure — including a real DB error, which
@@ -1,7 +1,7 @@
1
1
  import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
  import * as z from "zod";
3
3
  import { type AuthUserRow } from "../auth-user-row.js";
4
- import type { AuthMailContent, AuthMailLocale, RenderTokenContentArgs } from "../email-templates.js";
4
+ import type { AuthMailLocale } from "../email-templates.js";
5
5
  export type TokenRequestSuccess<K extends string> = {
6
6
  readonly kind: K;
7
7
  readonly email: string;
@@ -25,7 +25,6 @@ export type TokenRequestSpec<TName extends string, TSuccessKind extends string>
25
25
  readonly notConfiguredI18nKey: string;
26
26
  readonly extraSilentSkip: (user: AuthUserRow) => boolean;
27
27
  readonly notificationType: string;
28
- readonly renderContent: (args: RenderTokenContentArgs) => AuthMailContent;
29
28
  };
30
29
  export type TokenRequestOptions = {
31
30
  readonly hmacSecret: string;
@@ -67,7 +67,6 @@ export function createTokenRequestHandler(spec, opts) {
67
67
  await dispatchMagicLinkMail(ctx.notify, {
68
68
  handlerName: spec.handlerName,
69
69
  notificationType: spec.notificationType,
70
- renderContent: spec.renderContent,
71
70
  }, {
72
71
  // Row value is ciphertext with an active KMS; the byte-exact
73
72
  // lookup above guarantees the payload IS the stored plaintext.
@@ -3,10 +3,10 @@ export { type AuthPath, type AuthPaths, DEFAULT_AUTH_PATHS, makeAuthPaths } from
3
3
  export type { BootstrapConfigValue, BootstrapDeps, BootstrapInvite, BootstrapInviteOutcome, BootstrapPlan, BootstrapReport, BootstrapSeedDeps, BootstrapSystemAdmin, BootstrapTenant, BootstrapTenantOutcome, } from "./bootstrap.js";
4
4
  export { BootstrapPlanError, BootstrapWriteError, bootstrapTenants } from "./bootstrap.js";
5
5
  export { AUTH_EMAIL_PASSWORD_FEATURE, AuthErrors, AuthHandlers, AuthQueries } from "./constants.js";
6
- export type { AuthMailContent, AuthMailLocale, AuthMailSection, RenderInviteEmailArgs, RenderTokenContentArgs, } from "./email-templates.js";
7
- export { renderActivationEmail, renderInviteEmail, renderResetPasswordEmail, renderUnlockAccountEmail, renderVerifyEmail, } from "./email-templates.js";
6
+ export type { AuthMailLocale } from "./email-templates.js";
8
7
  export type { AccountLockoutOptions, AccountUnlockOptions, AuthEmailPasswordOptions, EmailVerificationOptions, InviteOptions, PasswordResetOptions, SignupOptions, } from "./feature.js";
9
8
  export { authEmailPasswordEnvSchema, createAuthEmailPasswordFeature } from "./feature.js";
9
+ export { AuthMailNotificationTypes } from "./mail-notifications.js";
10
10
  export { AUTH_SELF_REGISTRATION_FEATURE, createAuthSelfRegistrationToggleFeature, } from "./self-registration-toggle.js";
11
11
  export { signToken, TokenPurpose, type VerifyResult, verifyToken } from "./signed-token.js";
12
12
  export { type IssuedSignupActivation, type IssueSignupActivationArgs, issueSignupActivation, SIGNUP_ACTIVATION_NOTIFICATION_TYPE, } from "./signup-activation.js";
@@ -8,8 +8,8 @@ export { hashPassword, verifyPassword } from "../shared/password-hashing.js";
8
8
  export { DEFAULT_AUTH_PATHS, makeAuthPaths } from "./auth-paths.js";
9
9
  export { BootstrapPlanError, BootstrapWriteError, bootstrapTenants } from "./bootstrap.js";
10
10
  export { AUTH_EMAIL_PASSWORD_FEATURE, AuthErrors, AuthHandlers, AuthQueries } from "./constants.js";
11
- export { renderActivationEmail, renderInviteEmail, renderResetPasswordEmail, renderUnlockAccountEmail, renderVerifyEmail, } from "./email-templates.js";
12
11
  export { authEmailPasswordEnvSchema, createAuthEmailPasswordFeature } from "./feature.js";
12
+ export { AuthMailNotificationTypes } from "./mail-notifications.js";
13
13
  export { AUTH_SELF_REGISTRATION_FEATURE, createAuthSelfRegistrationToggleFeature, } from "./self-registration-toggle.js";
14
14
  // Generic HMAC-signed single-purpose token helpers. Re-exported damit
15
15
  // app-spezifische out-of-band-Flows (subscriber-confirm, magic-links,
@@ -1,9 +1,9 @@
1
1
  import type { NotifyFn } from "@cosmicdrift/kumiko-framework/engine";
2
- import type { AuthMailContent, AuthMailLocale, RenderTokenContentArgs } from "./email-templates.js";
2
+ import { type AuthMailLocale } from "./email-templates.js";
3
3
  export type MagicLinkMailSpec = {
4
4
  readonly handlerName: string;
5
5
  readonly notificationType: string;
6
- readonly renderContent: (args: RenderTokenContentArgs) => AuthMailContent;
6
+ readonly fallbackAppName?: string;
7
7
  };
8
8
  export type MagicLinkMailParams = {
9
9
  readonly email: string;
@@ -14,6 +14,7 @@ export type MagicLinkMailParams = {
14
14
  readonly locale?: AuthMailLocale;
15
15
  readonly issuedAt?: string;
16
16
  readonly timeZone?: string;
17
+ readonly role?: string;
17
18
  };
18
19
  export declare function resolveHandlerMailLocale(ctx: {
19
20
  readonly locale?: string;
@@ -1,13 +1,15 @@
1
1
  // Shared dispatch for the magic-link mails (password-reset, email-verification,
2
- // signup-activation). All three follow the same delivery shape: append the
3
- // token to the app page, render structured content, and notify the recipient
4
- // email directly (route:{email} skips preferences — the recipient may not have
5
- // a user account yet — and critical priority keeps a security mail
6
- // non-unsubscribable). No r.notification is declared; buildMessage falls back
7
- // to the structured `data` for the renderer.
2
+ // account-unlock, signup-activation, invite). All follow the same delivery
3
+ // shape: append the token to the app page and notify the recipient email
4
+ // directly (route:{email} skips preferences — the recipient may not have a user
5
+ // account yet — and critical priority keeps a security mail non-unsubscribable).
6
+ // Each mail type is a trigger-less r.notification whose stored template renders
7
+ // from the variables passed here.
8
8
  import { requestContext } from "@cosmicdrift/kumiko-framework/api";
9
9
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
10
- import { resolveMailLocale } from "@cosmicdrift/kumiko-framework/i18n";
10
+ import { mailT, resolveMailLocale } from "@cosmicdrift/kumiko-framework/i18n";
11
+ import { tokenMailExpiry } from "./email-templates.js";
12
+ import { authMailTemplateLocale } from "./mail-notifications.js";
11
13
  function resolveAppUrl(appUrl, locale) {
12
14
  return typeof appUrl === "function" ? appUrl(locale) : appUrl;
13
15
  }
@@ -35,18 +37,21 @@ export async function dispatchMagicLinkMail(notify, spec, params) {
35
37
  // mailT already root-falls-back; appUrl must use the same negotiated tag
36
38
  // or language-in-path apps 404 on e.g. /de-AT/activate.
37
39
  const urlLocale = resolveMailLocale(locale);
38
- const content = spec.renderContent({
39
- url: appendToken(resolveAppUrl(params.appUrl, urlLocale), params.token),
40
+ const { validFor, validUntil } = tokenMailExpiry({
40
41
  expiresAt: params.expiresAt,
41
- ...(params.locale !== undefined && { locale: params.locale }),
42
- ...(params.appName !== undefined && { appName: params.appName }),
43
42
  ...(params.issuedAt !== undefined && { issuedAt: params.issuedAt }),
44
43
  ...(params.timeZone !== undefined && { timeZone: params.timeZone }),
45
- });
44
+ }, locale);
46
45
  await notify(spec.notificationType, {
47
46
  route: { email: params.email },
48
- data: content,
49
- locale,
47
+ data: {
48
+ appName: params.appName ?? spec.fallbackAppName ?? mailT(locale, "auth.mail.appNameDefault"),
49
+ actionUrl: appendToken(resolveAppUrl(params.appUrl, urlLocale), params.token),
50
+ validFor,
51
+ validUntil,
52
+ ...(params.role !== undefined && { role: params.role }),
53
+ },
54
+ locale: authMailTemplateLocale(spec.notificationType, locale),
50
55
  priority: "critical",
51
56
  });
52
57
  }
@@ -0,0 +1,32 @@
1
+ import { type NotificationLocalizedTemplate, type TemplateVariables } from "@cosmicdrift/kumiko-framework/engine";
2
+ export declare const AUTH_MAIL_KINDS: {
3
+ readonly passwordReset: {
4
+ readonly name: "password-reset";
5
+ readonly translationKey: "reset";
6
+ };
7
+ readonly accountUnlock: {
8
+ readonly name: "account-unlock";
9
+ readonly translationKey: "unlock";
10
+ };
11
+ readonly emailVerification: {
12
+ readonly name: "email-verification";
13
+ readonly translationKey: "verify";
14
+ };
15
+ readonly signupActivation: {
16
+ readonly name: "signup-activation";
17
+ readonly translationKey: "activation";
18
+ };
19
+ readonly invite: {
20
+ readonly name: "invite";
21
+ readonly translationKey: "invite";
22
+ };
23
+ };
24
+ export type AuthMailKind = keyof typeof AUTH_MAIL_KINDS;
25
+ type MagicLinkFlowOptions = Partial<Record<"passwordReset" | "emailVerification" | "signup" | "invite" | "accountUnlock", unknown>>;
26
+ export declare function sendsMagicLinkMail(flows: MagicLinkFlowOptions): boolean;
27
+ export declare const AuthMailNotificationTypes: Readonly<Record<AuthMailKind, string>>;
28
+ export declare function authMailTemplateLocale(notificationType: string, requestedLocale: string): string;
29
+ export declare const AUTH_MAIL_VARIABLES: TemplateVariables;
30
+ export declare const INVITE_MAIL_VARIABLES: TemplateVariables;
31
+ export declare function authMailLocalizedTemplate(kind: AuthMailKind): () => NotificationLocalizedTemplate;
32
+ export {};