@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
@@ -0,0 +1,32 @@
1
+ import type { FieldIssue } from "@cosmicdrift/kumiko-framework/errors";
2
+ import { type Element as ScanElement } from "happy-dom";
3
+ import type { ContentFormat } from "./constants.js";
4
+ export type DocumentViolationCode = "script_element" | "event_handler_attribute" | "disallowed_link_href" | "external_image_source" | "image_without_resource" | "invalid_reference_name" | "embedded_content" | "unsafe_attribute_value" | "button_href_not_placeholder" | "document_requires_html_format" | "layout_requires_mjml_format" | "layout_invalid_structure" | "layout_missing_content_slot" | "layout_source_system_only";
5
+ export type DocumentViolation = {
6
+ readonly code: DocumentViolationCode;
7
+ readonly detail: string;
8
+ readonly message: string;
9
+ };
10
+ export type SanitizeHtmlResult = {
11
+ readonly ok: true;
12
+ readonly html: string;
13
+ } | {
14
+ readonly ok: false;
15
+ readonly violations: readonly DocumentViolation[];
16
+ };
17
+ export type SanitizeBodyResult = {
18
+ readonly ok: true;
19
+ readonly content: string | null;
20
+ } | {
21
+ readonly ok: false;
22
+ readonly violations: readonly DocumentViolation[];
23
+ };
24
+ export declare function violation(code: DocumentViolationCode, detail: string, message: string): DocumentViolation;
25
+ export declare function withParsedDocument<T>(html: string, read: (body: ScanElement) => T): T;
26
+ export declare function sanitizeDocumentHtml(html: string): SanitizeHtmlResult;
27
+ export declare function sanitizeTemplateBody(input: {
28
+ readonly kind: string;
29
+ readonly contentFormat: ContentFormat;
30
+ readonly content: string | null;
31
+ }): SanitizeBodyResult;
32
+ export declare function documentViolationsToFieldIssues(violations: readonly DocumentViolation[]): FieldIssue[];
@@ -0,0 +1,201 @@
1
+ import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
2
+ import { generateHTML, generateJSON } from "@tiptap/html/server";
3
+ import { Window } from "happy-dom";
4
+ import { DOCUMENT_HTML_KINDS } from "./constants.js";
5
+ import { documentExtensions, isAllowedDocumentLinkHref, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "./document-schema.js";
6
+ export function violation(code, detail, message) {
7
+ return { code, detail, message };
8
+ }
9
+ // Same switches tiptap's generateJSON uses, plus navigation off: the scan
10
+ // window must never fetch or navigate anything.
11
+ function createScanWindow() {
12
+ return new Window({
13
+ settings: {
14
+ disableJavaScriptEvaluation: true,
15
+ disableJavaScriptFileLoading: true,
16
+ disableCSSFileLoading: true,
17
+ disableIframePageLoading: true,
18
+ disableComputedStyleRendering: true,
19
+ navigation: {
20
+ disableMainFrameNavigation: true,
21
+ disableChildFrameNavigation: true,
22
+ disableChildPageNavigation: true,
23
+ },
24
+ },
25
+ });
26
+ }
27
+ function scanScriptAndHandlers(tag, element, out) {
28
+ if (tag === "script") {
29
+ out.push(violation("script_element", "script", "<script> elements are not allowed in template bodies"));
30
+ }
31
+ for (const attribute of Array.from(element.attributes)) {
32
+ if (/^on/i.test(attribute.name)) {
33
+ out.push(violation("event_handler_attribute", attribute.name, `Inline event handler "${attribute.name}" on <${tag}> is not allowed`));
34
+ }
35
+ }
36
+ }
37
+ function scanAnchor(element, out) {
38
+ const href = element.getAttribute("href");
39
+ if (href !== null && !isAllowedDocumentLinkHref(href)) {
40
+ out.push(violation("disallowed_link_href", href, `Link target "${href}" is not allowed; use https, http, mailto, tel or a {{placeholder}}`));
41
+ }
42
+ if (element.hasAttribute("data-button") && !isDocumentPlaceholderHref(href ?? "")) {
43
+ out.push(violation("button_href_not_placeholder", href ?? "", `Button target "${href ?? ""}" must be a {{placeholder}}`));
44
+ }
45
+ }
46
+ function scanImage(element, out) {
47
+ const source = element.getAttribute("src") ?? element.getAttribute("srcset");
48
+ if (source !== null) {
49
+ out.push(violation("external_image_source", source, `Images must reference an uploaded resource via data-resource; external or inline image source "${source}" is not allowed`));
50
+ }
51
+ if (!element.hasAttribute("data-resource")) {
52
+ out.push(violation("image_without_resource", "img", "Images must reference an uploaded resource via the data-resource attribute"));
53
+ }
54
+ }
55
+ const REFERENCE_ATTRIBUTES = [
56
+ ["data-variable", isDocumentReferenceName],
57
+ ["data-each", isDocumentReferenceName],
58
+ ["data-resource", isDocumentResourceKey],
59
+ ];
60
+ function scanReferences(tag, element, out) {
61
+ for (const [attribute, isValid] of REFERENCE_ATTRIBUTES) {
62
+ const value = element.getAttribute(attribute);
63
+ if (value !== null && !isValid(value)) {
64
+ out.push(violation("invalid_reference_name", value, `Value "${value}" of ${attribute} on <${tag}> is not a valid name`));
65
+ }
66
+ }
67
+ }
68
+ const EMBEDDING_TAGS = new Set([
69
+ "iframe",
70
+ "frame",
71
+ "frameset",
72
+ "object",
73
+ "embed",
74
+ "applet",
75
+ "portal",
76
+ ]);
77
+ const SVG_IMAGE_TAGS = new Set(["image", "feimage", "use"]);
78
+ const URL_ATTRIBUTES = ["href", "xlink:href", "action", "formaction"];
79
+ function scanEmbedding(tag, out) {
80
+ if (EMBEDDING_TAGS.has(tag)) {
81
+ out.push(violation("embedded_content", tag, `<${tag}> elements are not allowed in template bodies`));
82
+ }
83
+ }
84
+ // html <a href> has its own rules in scanAnchor; everywhere else (svg, base,
85
+ // form controls) a URL attribute has no business in a template body.
86
+ function scanUrlAttributes(tag, element, out) {
87
+ for (const name of URL_ATTRIBUTES) {
88
+ const value = element.getAttribute(name);
89
+ if (value === null || (tag === "a" && name === "href"))
90
+ continue;
91
+ if (SVG_IMAGE_TAGS.has(tag) && name.endsWith("href")) {
92
+ out.push(violation("external_image_source", value, `Images must reference an uploaded resource via data-resource; image source "${value}" is not allowed`));
93
+ }
94
+ else if (tag === "base" || !isAllowedDocumentLinkHref(value)) {
95
+ out.push(violation("disallowed_link_href", value, `Link target "${value}" is not allowed; use https, http, mailto, tel or a {{placeholder}}`));
96
+ }
97
+ }
98
+ }
99
+ // happy-dom serializes < and > inside attribute values unescaped, so a later
100
+ // parser (MJML) could read them as markup.
101
+ function scanAltText(element, out) {
102
+ const alt = element.getAttribute("alt");
103
+ if (alt !== null && /[<>]/.test(alt)) {
104
+ out.push(violation("unsafe_attribute_value", alt, `Attribute alt must not contain "<" or ">": "${alt}"`));
105
+ }
106
+ }
107
+ function scanElement(element, out) {
108
+ const tag = element.tagName.toLowerCase();
109
+ scanEmbedding(tag, out);
110
+ scanUrlAttributes(tag, element, out);
111
+ scanAltText(element, out);
112
+ scanScriptAndHandlers(tag, element, out);
113
+ if (tag === "a")
114
+ scanAnchor(element, out);
115
+ if (tag === "img")
116
+ scanImage(element, out);
117
+ scanReferences(tag, element, out);
118
+ }
119
+ // Parses `html` in the hardened scan window and always closes it again, also
120
+ // when `read` throws. Shared by the sanitizer and the placeholder scan so there
121
+ // is exactly one DOM setup.
122
+ export function withParsedDocument(html, read) {
123
+ const window = createScanWindow();
124
+ try {
125
+ const parsed = new window.DOMParser().parseFromString(["<!DOCTYPE html><html><body>", html, "</body></html>"].join(""), "text/html");
126
+ return read(parsed.body);
127
+ }
128
+ finally {
129
+ window.happyDOM.abort();
130
+ window.happyDOM.close();
131
+ }
132
+ }
133
+ function scanDocumentHtml(html) {
134
+ const violations = [];
135
+ withParsedDocument(html, (body) => {
136
+ // A second `<body ...>` in the input merges its attributes into this body.
137
+ for (const element of [body, ...Array.from(body.querySelectorAll("*"))]) {
138
+ scanElement(element, violations);
139
+ }
140
+ });
141
+ return violations;
142
+ }
143
+ // Rejects hostile constructs, then rebuilds the body from the document model.
144
+ // The rebuilt HTML is always what gets returned (never the input), so anything
145
+ // the model cannot express is dropped silently.
146
+ export function sanitizeDocumentHtml(html) {
147
+ const violations = scanDocumentHtml(html);
148
+ if (violations.length > 0)
149
+ return { ok: false, violations };
150
+ return {
151
+ ok: true,
152
+ html: generateHTML(generateJSON(html, documentExtensions), documentExtensions),
153
+ };
154
+ }
155
+ // Snippets accept any format, but their html is as untrusted as a mail body.
156
+ function isSanitizedHtmlKind(kind) {
157
+ return kind === "snippet" || isOneOf(DOCUMENT_HTML_KINDS, kind);
158
+ }
159
+ const HTML_ONLY_KINDS = new Set(DOCUMENT_HTML_KINDS);
160
+ function requiredFormatViolation(kind, contentFormat) {
161
+ if (HTML_ONLY_KINDS.has(kind) && contentFormat !== "html") {
162
+ return violation("document_requires_html_format", contentFormat, `Templates of kind ${kind} require contentFormat html, got "${contentFormat}"`);
163
+ }
164
+ return null;
165
+ }
166
+ export function sanitizeTemplateBody(input) {
167
+ const formatViolation = requiredFormatViolation(input.kind, input.contentFormat);
168
+ if (formatViolation !== null)
169
+ return { ok: false, violations: [formatViolation] };
170
+ if (!isSanitizedHtmlKind(input.kind) ||
171
+ input.contentFormat !== "html" ||
172
+ input.content === null) {
173
+ return { ok: true, content: input.content };
174
+ }
175
+ const result = sanitizeDocumentHtml(input.content);
176
+ return result.ok ? { ok: true, content: result.html } : result;
177
+ }
178
+ const VIOLATION_I18N_KEYS = {
179
+ script_element: "templateResolver.errors.document.scriptElement",
180
+ event_handler_attribute: "templateResolver.errors.document.eventHandlerAttribute",
181
+ disallowed_link_href: "templateResolver.errors.document.disallowedLinkHref",
182
+ external_image_source: "templateResolver.errors.document.externalImageSource",
183
+ image_without_resource: "templateResolver.errors.document.imageWithoutResource",
184
+ invalid_reference_name: "templateResolver.errors.document.invalidReferenceName",
185
+ embedded_content: "templateResolver.errors.document.embeddedContent",
186
+ unsafe_attribute_value: "templateResolver.errors.document.unsafeAttributeValue",
187
+ button_href_not_placeholder: "templateResolver.errors.document.buttonHrefNotPlaceholder",
188
+ document_requires_html_format: "templateResolver.errors.document.documentRequiresHtmlFormat",
189
+ layout_requires_mjml_format: "templateResolver.errors.document.layoutRequiresMjmlFormat",
190
+ layout_invalid_structure: "templateResolver.errors.document.layoutInvalidStructure",
191
+ layout_missing_content_slot: "templateResolver.errors.document.layoutMissingContentSlot",
192
+ layout_source_system_only: "templateResolver.errors.document.layoutSourceSystemOnly",
193
+ };
194
+ export function documentViolationsToFieldIssues(violations) {
195
+ return violations.map((item) => ({
196
+ path: "content",
197
+ code: item.code,
198
+ i18nKey: VIOLATION_I18N_KEYS[item.code],
199
+ params: { detail: item.detail },
200
+ }));
201
+ }
@@ -0,0 +1,21 @@
1
+ import { Extension, type Extensions, Node } from "@tiptap/core";
2
+ export declare function isDocumentPlaceholderHref(href: string): boolean;
3
+ export declare function isAllowedDocumentLinkHref(href: string): boolean;
4
+ export declare function isDocumentReferenceName(value: string): boolean;
5
+ export declare function isDocumentResourceKey(value: string): boolean;
6
+ export declare const DOCUMENT_NODE_NAMES: readonly ["variable", "resource", "button", "divider", "pageBreak"];
7
+ export declare const DocumentVariable: Node<any, any>;
8
+ export declare const DocumentResource: Node<any, any>;
9
+ export declare const DocumentButton: Node<any, any>;
10
+ export declare const DocumentDivider: Node<any, any>;
11
+ export declare const DocumentPageBreak: Node<any, any>;
12
+ export declare const DocumentTableRow: Node<import("@tiptap/extension-table").TableRowOptions, any>;
13
+ export declare const DocumentRepeatRow: Node<import("@tiptap/extension-table").TableRowOptions, any>;
14
+ export declare const DocumentTable: Node<import("@tiptap/extension-table").TableOptions, any>;
15
+ export declare const DocumentTableCell: Node<import("@tiptap/extension-table").TableCellOptions, any>;
16
+ export declare const DocumentTableHeader: Node<import("@tiptap/extension-table").TableHeaderOptions, any>;
17
+ export declare const DocumentLink: import("@tiptap/core").Mark<import("@tiptap/extension-link").LinkOptions, any>;
18
+ export declare const DOCUMENT_TEXT_ALIGNMENTS: readonly ["left", "center", "right", "justify"];
19
+ export type DocumentTextAlignment = (typeof DOCUMENT_TEXT_ALIGNMENTS)[number];
20
+ export declare const DocumentTextAlign: Extension<any, any>;
21
+ export declare const documentExtensions: Extensions;
@@ -0,0 +1,296 @@
1
+ // @runtime client
2
+ // Canonical document model for template bodies (kinds mail, document-pdf).
3
+ // Universal on purpose: the web editor and the server sanitizer load the same
4
+ // extension list, so what the editor can produce is exactly what the server
5
+ // keeps. No DOM access at module level, no happy-dom here.
6
+ import { isOneOf, isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
7
+ import { Extension, Node } from "@tiptap/core";
8
+ import { Link } from "@tiptap/extension-link";
9
+ import { Table, TableCell, TableHeader, TableRow } from "@tiptap/extension-table";
10
+ import StarterKit from "@tiptap/starter-kit";
11
+ const PLACEHOLDER_HREF = /^\{\{[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*\}\}$/;
12
+ const REFERENCE_NAME = /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$/;
13
+ const RESOURCE_KEY = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
14
+ const ALLOWED_LINK_SCHEMES = ["https://", "http://", "mailto:", "tel:"];
15
+ export function isDocumentPlaceholderHref(href) {
16
+ return PLACEHOLDER_HREF.test(href);
17
+ }
18
+ const UNSAFE_URL_CHARACTERS = new Set(["<", ">", '"']);
19
+ const FORBIDDEN_REFERENCE_SEGMENTS = new Set(["__proto__", "prototype", "constructor"]);
20
+ function hasUnsafeUrlCharacter(value) {
21
+ return Array.from(value).some((character) => {
22
+ const code = character.charCodeAt(0);
23
+ return UNSAFE_URL_CHARACTERS.has(character) || code <= 0x1f || code === 0x7f;
24
+ });
25
+ }
26
+ function isParsableWebUrl(href, protocol) {
27
+ try {
28
+ return new URL(href).protocol === protocol;
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ }
34
+ function hasAllowedLinkScheme(href) {
35
+ if (href.startsWith("https://"))
36
+ return isParsableWebUrl(href, "https:");
37
+ if (href.startsWith("http://"))
38
+ return isParsableWebUrl(href, "http:");
39
+ return ALLOWED_LINK_SCHEMES.some((scheme) => href.startsWith(scheme));
40
+ }
41
+ // Exact lowercase prefix on the unchanged value: no trim, no case folding, so
42
+ // "JaVaScRiPt:", "HTTPS://" or a leading tab can never slip through as a
43
+ // scheme variant. Markup and control characters are refused outright because
44
+ // downstream parsers (MJML, PDF renderer) re-read the serialized attribute.
45
+ export function isAllowedDocumentLinkHref(href) {
46
+ if (hasUnsafeUrlCharacter(href))
47
+ return false;
48
+ return hasAllowedLinkScheme(href) || isDocumentPlaceholderHref(href);
49
+ }
50
+ // Segments that hit the prototype chain are refused: the renderer later walks
51
+ // the dotted path into a data object.
52
+ export function isDocumentReferenceName(value) {
53
+ return (REFERENCE_NAME.test(value) &&
54
+ !value.split(".").some((segment) => FORBIDDEN_REFERENCE_SEGMENTS.has(segment)));
55
+ }
56
+ export function isDocumentResourceKey(value) {
57
+ return RESOURCE_KEY.test(value);
58
+ }
59
+ export const DOCUMENT_NODE_NAMES = [
60
+ "variable",
61
+ "resource",
62
+ "button",
63
+ "divider",
64
+ "pageBreak",
65
+ ];
66
+ export const DocumentVariable = Node.create({
67
+ name: "variable",
68
+ group: "inline",
69
+ inline: true,
70
+ atom: true,
71
+ addAttributes() {
72
+ return { name: { default: null } };
73
+ },
74
+ parseHTML() {
75
+ return [
76
+ {
77
+ tag: "span[data-variable]",
78
+ getAttrs: (element) => {
79
+ const name = element.getAttribute("data-variable");
80
+ return name !== null && isDocumentReferenceName(name) ? { name } : false;
81
+ },
82
+ },
83
+ ];
84
+ },
85
+ renderHTML({ node }) {
86
+ return ["span", { "data-variable": node.attrs["name"] }];
87
+ },
88
+ });
89
+ export const DocumentResource = Node.create({
90
+ name: "resource",
91
+ group: "block",
92
+ atom: true,
93
+ addAttributes() {
94
+ return { resource: { default: null }, alt: { default: null } };
95
+ },
96
+ parseHTML() {
97
+ return [
98
+ {
99
+ tag: "img[data-resource]",
100
+ getAttrs: (element) => {
101
+ const resource = element.getAttribute("data-resource");
102
+ if (resource === null || !isDocumentResourceKey(resource))
103
+ return false;
104
+ return { resource, alt: element.getAttribute("alt") };
105
+ },
106
+ },
107
+ ];
108
+ },
109
+ // Never emits src: the renderer resolves the resource key at render time.
110
+ renderHTML({ node }) {
111
+ const alt = node.attrs["alt"];
112
+ return [
113
+ "img",
114
+ alt === null || alt === undefined
115
+ ? { "data-resource": node.attrs["resource"] }
116
+ : { "data-resource": node.attrs["resource"], alt },
117
+ ];
118
+ },
119
+ });
120
+ export const DocumentButton = Node.create({
121
+ name: "button",
122
+ group: "block",
123
+ content: "text*",
124
+ marks: "",
125
+ defining: true,
126
+ addAttributes() {
127
+ return { href: { default: null } };
128
+ },
129
+ parseHTML() {
130
+ return [
131
+ {
132
+ tag: "a[data-button]",
133
+ // Must win against the Link mark's `a[href]` rule.
134
+ priority: 1000,
135
+ getAttrs: (element) => {
136
+ const href = element.getAttribute("href");
137
+ return href !== null && isDocumentPlaceholderHref(href) ? { href } : false;
138
+ },
139
+ },
140
+ ];
141
+ },
142
+ renderHTML({ node }) {
143
+ return ["a", { "data-button": "", href: node.attrs["href"] }, 0];
144
+ },
145
+ });
146
+ export const DocumentDivider = Node.create({
147
+ name: "divider",
148
+ group: "block",
149
+ atom: true,
150
+ parseHTML() {
151
+ return [{ tag: "hr" }];
152
+ },
153
+ renderHTML() {
154
+ return ["hr"];
155
+ },
156
+ });
157
+ export const DocumentPageBreak = Node.create({
158
+ name: "pageBreak",
159
+ group: "block",
160
+ atom: true,
161
+ parseHTML() {
162
+ return [{ tag: "div[data-page-break]" }];
163
+ },
164
+ renderHTML() {
165
+ return ["div", { "data-page-break": "" }];
166
+ },
167
+ });
168
+ // A repeat row is a table row carrying `each`: prosemirror-tables requires
169
+ // the tableRow node type, so a separate node type is not an option.
170
+ export const DocumentTableRow = TableRow.extend({
171
+ addAttributes() {
172
+ return {
173
+ each: {
174
+ default: null,
175
+ parseHTML: (element) => {
176
+ const each = element.getAttribute("data-each");
177
+ return each !== null && isDocumentReferenceName(each) ? each : null;
178
+ },
179
+ renderHTML: (attributes) => {
180
+ const each = attributes["each"];
181
+ return typeof each === "string" && each ? { "data-each": each } : {};
182
+ },
183
+ },
184
+ repeatHeader: {
185
+ default: false,
186
+ parseHTML: (element) => element.hasAttribute("data-repeat-header"),
187
+ renderHTML: (attributes) => attributes["repeatHeader"] ? { "data-repeat-header": "" } : {},
188
+ },
189
+ };
190
+ },
191
+ });
192
+ export const DocumentRepeatRow = DocumentTableRow;
193
+ export const DocumentTable = Table.extend({
194
+ renderHTML() {
195
+ return ["table", ["tbody", 0]];
196
+ },
197
+ });
198
+ // Span attributes are rendered only when they differ from the default, and
199
+ // colwidth (an editor-resize artefact) never, so `<td><p>x</p></td>` is the
200
+ // canonical cell.
201
+ function plainObjectOrEmpty(value) {
202
+ return isPlainObject(value) ? value : {};
203
+ }
204
+ function canonicalCellAttributes(attributes) {
205
+ return {
206
+ ...attributes,
207
+ colspan: {
208
+ ...plainObjectOrEmpty(attributes["colspan"]),
209
+ renderHTML: (attrs) => attrs["colspan"] && attrs["colspan"] !== 1 ? { colspan: attrs["colspan"] } : {},
210
+ },
211
+ rowspan: {
212
+ ...plainObjectOrEmpty(attributes["rowspan"]),
213
+ renderHTML: (attrs) => attrs["rowspan"] && attrs["rowspan"] !== 1 ? { rowspan: attrs["rowspan"] } : {},
214
+ },
215
+ colwidth: {
216
+ ...plainObjectOrEmpty(attributes["colwidth"]),
217
+ renderHTML: () => ({}),
218
+ },
219
+ };
220
+ }
221
+ export const DocumentTableCell = TableCell.extend({
222
+ addAttributes() {
223
+ return canonicalCellAttributes(this.parent?.() ?? {});
224
+ },
225
+ });
226
+ export const DocumentTableHeader = TableHeader.extend({
227
+ addAttributes() {
228
+ return canonicalCellAttributes(this.parent?.() ?? {});
229
+ },
230
+ });
231
+ // Only href survives a parse: target, rel, class and title from the input would
232
+ // otherwise be kept verbatim, and the renderer decides those itself.
233
+ export const DocumentLink = Link.extend({
234
+ addAttributes() {
235
+ return { href: { default: null, parseHTML: (element) => element.getAttribute("href") } };
236
+ },
237
+ });
238
+ export const DOCUMENT_TEXT_ALIGNMENTS = ["left", "center", "right", "justify"];
239
+ // Serialized as data-align, never as a style attribute: the sanitizer keeps
240
+ // styles out of the model, and each renderer maps the value to its own CSS.
241
+ export const DocumentTextAlign = Extension.create({
242
+ name: "documentTextAlign",
243
+ addGlobalAttributes() {
244
+ return [
245
+ {
246
+ types: ["paragraph", "heading"],
247
+ attributes: {
248
+ textAlign: {
249
+ default: null,
250
+ parseHTML: (element) => {
251
+ const align = element.getAttribute("data-align");
252
+ return isOneOf(DOCUMENT_TEXT_ALIGNMENTS, align) ? align : null;
253
+ },
254
+ renderHTML: (attributes) => {
255
+ const align = attributes["textAlign"];
256
+ return isOneOf(DOCUMENT_TEXT_ALIGNMENTS, align) ? { "data-align": align } : {};
257
+ },
258
+ },
259
+ },
260
+ },
261
+ ];
262
+ },
263
+ });
264
+ export const documentExtensions = [
265
+ StarterKit.configure({
266
+ blockquote: false,
267
+ code: false,
268
+ codeBlock: false,
269
+ strike: false,
270
+ horizontalRule: false,
271
+ dropcursor: false,
272
+ gapcursor: false,
273
+ undoRedo: false,
274
+ trailingNode: false,
275
+ listKeymap: false,
276
+ heading: { levels: [1, 2, 3] },
277
+ link: false,
278
+ }),
279
+ DocumentLink.configure({
280
+ openOnClick: false,
281
+ autolink: false,
282
+ linkOnPaste: false,
283
+ HTMLAttributes: { target: null, rel: null, class: null },
284
+ isAllowedUri: (url) => isAllowedDocumentLinkHref(url),
285
+ }),
286
+ DocumentTable,
287
+ DocumentTableRow,
288
+ DocumentTableHeader,
289
+ DocumentTableCell,
290
+ DocumentVariable,
291
+ DocumentResource,
292
+ DocumentButton,
293
+ DocumentDivider,
294
+ DocumentPageBreak,
295
+ DocumentTextAlign,
296
+ ];
@@ -18,13 +18,31 @@ export declare function createTemplateResolverFeature(opts?: TemplateResolverOpt
18
18
  upsertTenant: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
19
19
  publish: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
20
20
  archive: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
21
+ publishSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
22
+ archiveSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
23
+ resetToSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
21
24
  set: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
25
+ importBundle: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
26
+ importBundleSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
27
+ copyLocale: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
28
+ resourceUpload: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
29
+ resourceRemove: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
30
+ resourceLinkPdf: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
31
+ sendTest: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
22
32
  };
23
33
  queries: {
24
34
  findById: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
25
35
  list: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
26
36
  bySlug: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
27
37
  byTenant: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
38
+ usage: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
39
+ overview: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
40
+ layoutSource: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
41
+ tenantOverrides: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
42
+ diffToSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
43
+ validate: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
44
+ preview: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
45
+ exportBundle: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
28
46
  };
29
47
  treeHandle: import("@cosmicdrift/kumiko-types/tree-node").TreeActionsHandle<"template-resolver", {
30
48
  readonly edit: {