@cosmicdrift/kumiko-bundled-features 0.373.0 → 0.377.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 (215) hide show
  1. package/dist/account-security/constants.d.ts +1 -0
  2. package/dist/account-security/constants.js +1 -0
  3. package/dist/account-security/index.d.ts +1 -1
  4. package/dist/account-security/index.js +1 -1
  5. package/dist/admin-shell/web/client-plugin.d.ts +1 -1
  6. package/dist/audit/web/client-plugin.d.ts +1 -1
  7. package/dist/auth-email-password/i18n.js +1 -0
  8. package/dist/auth-email-password/mail-notifications.js +1 -1
  9. package/dist/auth-email-password/web/auth-client.js +1 -1
  10. package/dist/auth-email-password/web/auth-form-primitives.js +1 -1
  11. package/dist/auth-email-password/web/client-actions.d.ts +2 -0
  12. package/dist/auth-email-password/web/client-actions.js +23 -0
  13. package/dist/auth-email-password/web/client-plugin.d.ts +2 -1
  14. package/dist/auth-email-password/web/client-plugin.js +2 -0
  15. package/dist/auth-email-password/web/default-topbar-actions.js +1 -1
  16. package/dist/auth-email-password/web/index.js +1 -1
  17. package/dist/auth-email-password/web/session.js +1 -1
  18. package/dist/auth-email-password/web/tenant-menu-items.js +1 -1
  19. package/dist/auth-email-password/web/tenant-switcher.js +1 -1
  20. package/dist/auth-email-password/web/user-menu.js +1 -1
  21. package/dist/auth-foundation/env.d.ts +9 -0
  22. package/dist/auth-foundation/env.js +21 -0
  23. package/dist/auth-foundation/index.d.ts +1 -0
  24. package/dist/auth-foundation/index.js +1 -0
  25. package/dist/auth-mfa/schema/user-mfa.d.ts +6 -6
  26. package/dist/billing-foundation/consumer-protection/confirmation-mail.js +1 -1
  27. package/dist/billing-foundation/consumer-protection/termination-pages.js +1 -1
  28. package/dist/billing-foundation/contact-card.d.ts +2 -0
  29. package/dist/billing-foundation/contact-card.js +16 -0
  30. package/dist/billing-foundation/entities.d.ts +8 -8
  31. package/dist/billing-foundation/handlers/billing-plans.query.js +1 -1
  32. package/dist/billing-foundation/index.d.ts +1 -1
  33. package/dist/billing-foundation/plan-catalog.js +1 -0
  34. package/dist/billing-foundation/projection.d.ts +8 -8
  35. package/dist/billing-foundation/types.d.ts +11 -0
  36. package/dist/billing-foundation/validate-options.js +13 -0
  37. package/dist/billing-foundation/web/billing-contact-plan.d.ts +5 -0
  38. package/dist/billing-foundation/web/billing-contact-plan.js +17 -0
  39. package/dist/billing-foundation/web/billing-plans-panel.js +5 -13
  40. package/dist/billing-foundation/web/cancel-contract-dialog.js +2 -2
  41. package/dist/billing-foundation/web/checkout-consent-dialog.d.ts +1 -1
  42. package/dist/billing-foundation/web/checkout-consent-dialog.js +1 -0
  43. package/dist/billing-foundation/web/client-plugin.d.ts +1 -1
  44. package/dist/billing-foundation/web/localized-params.d.ts +1 -0
  45. package/dist/billing-foundation/web/localized-params.js +11 -0
  46. package/dist/cap-counter/entity.d.ts +1 -1
  47. package/dist/cap-overview/handlers/tenant-caps-list.query.d.ts +9 -4
  48. package/dist/cap-overview/handlers/tenant-caps-list.query.js +14 -61
  49. package/dist/cap-overview/i18n.js +0 -2
  50. package/dist/cap-overview/web/cap-cards-panel.js +3 -3
  51. package/dist/cap-overview/web/client-plugin.d.ts +1 -1
  52. package/dist/channel-email/email-channel.d.ts +2 -1
  53. package/dist/compliance-profiles/web/client-plugin.d.ts +1 -1
  54. package/dist/config/feature.js +2 -2
  55. package/dist/config/table.d.ts +6 -6
  56. package/dist/custom-fields/entity.d.ts +4 -4
  57. package/dist/custom-fields/web/client-plugin.d.ts +1 -1
  58. package/dist/data-retention/schema/tenant-retention-override.d.ts +4 -4
  59. package/dist/delivery/tables.d.ts +6 -6
  60. package/dist/delivery/unsubscribe-page.js +1 -1
  61. package/dist/delivery/web/client-plugin.d.ts +1 -1
  62. package/dist/delivery/web/delivery-status-cell.js +1 -1
  63. package/dist/document-ingest-foundation/entity.d.ts +4 -4
  64. package/dist/feature-toggles/web/client-plugin.d.ts +1 -1
  65. package/dist/file-provider-s3/env-named-feature.d.ts +17 -0
  66. package/dist/file-provider-s3/env-named-feature.js +23 -0
  67. package/dist/file-provider-s3/env-schema.d.ts +7 -0
  68. package/dist/file-provider-s3/env-schema.js +15 -10
  69. package/dist/file-provider-s3/index.d.ts +1 -0
  70. package/dist/file-provider-s3/index.js +1 -0
  71. package/dist/folders/entity.d.ts +8 -8
  72. package/dist/folders/web/client-plugin.d.ts +1 -1
  73. package/dist/form-draft/entity.d.ts +2 -2
  74. package/dist/host-routing/constants.d.ts +2 -0
  75. package/dist/host-routing/constants.js +3 -0
  76. package/dist/host-routing/dispatch.d.ts +1 -1
  77. package/dist/host-routing/dispatch.js +35 -25
  78. package/dist/host-routing/feature.js +100 -27
  79. package/dist/host-routing/host.d.ts +9 -0
  80. package/dist/host-routing/host.js +24 -2
  81. package/dist/host-routing/index.d.ts +2 -1
  82. package/dist/host-routing/index.js +1 -0
  83. package/dist/host-routing/options.d.ts +14 -0
  84. package/dist/host-routing/redirects.d.ts +6 -0
  85. package/dist/host-routing/redirects.js +27 -0
  86. package/dist/host-routing/tenant-lookup.d.ts +7 -0
  87. package/dist/host-routing/tenant-lookup.js +39 -0
  88. package/dist/host-routing/validate-options.js +34 -1
  89. package/dist/inbound-mail-foundation/entities.d.ts +25 -25
  90. package/dist/inbound-mail-foundation/feature.js +7 -0
  91. package/dist/inbound-mail-foundation/i18n.d.ts +3 -0
  92. package/dist/inbound-mail-foundation/i18n.js +35 -0
  93. package/dist/inbound-mail-foundation/index.d.ts +1 -0
  94. package/dist/inbound-mail-foundation/index.js +1 -0
  95. package/dist/inbound-mail-foundation/projection.d.ts +20 -20
  96. package/dist/inbound-mail-foundation/screens.d.ts +7 -0
  97. package/dist/inbound-mail-foundation/screens.js +86 -0
  98. package/dist/inbound-mail-foundation/types.d.ts +2 -2
  99. package/dist/jobs/job-run-table.d.ts +6 -6
  100. package/dist/jobs/web/client-plugin.d.ts +1 -1
  101. package/dist/ledger/entity.d.ts +13 -13
  102. package/dist/legal-pages/feature.js +11 -1
  103. package/dist/legal-pages/layout.d.ts +2 -2
  104. package/dist/legal-pages/layout.js +4 -4
  105. package/dist/legal-pages/web/client-plugin.d.ts +1 -1
  106. package/dist/mail-foundation/feature.d.ts +20 -21
  107. package/dist/mail-foundation/feature.js +1 -1
  108. package/dist/managed-pages/table.d.ts +12 -12
  109. package/dist/managed-pages/web/client-plugin.d.ts +1 -1
  110. package/dist/notes-history/entity.d.ts +12 -12
  111. package/dist/notes-history/web/client-plugin.d.ts +1 -1
  112. package/dist/page-render/branding.js +1 -1
  113. package/dist/page-render/layout.d.ts +1 -1
  114. package/dist/page-render/layout.js +2 -2
  115. package/dist/page-render/markdown.js +1 -1
  116. package/dist/personal-access-tokens/i18n.js +1 -1
  117. package/dist/personal-access-tokens/schema/api-token.d.ts +6 -6
  118. package/dist/personal-access-tokens/screens.js +1 -1
  119. package/dist/secrets/feature.d.ts +1 -1
  120. package/dist/secrets/feature.js +3 -3
  121. package/dist/secrets/table.d.ts +1 -1
  122. package/dist/seo/sitemap.js +1 -1
  123. package/dist/sessions/schema/user-session.d.ts +4 -4
  124. package/dist/shared/mail-template-body.js +1 -1
  125. package/dist/shared/purge-files-reaching-subject.js +98 -3
  126. package/dist/tags/entity.d.ts +9 -9
  127. package/dist/tags/web/client-plugin.d.ts +1 -1
  128. package/dist/template-resolver/document-blocks.d.ts +5 -0
  129. package/dist/template-resolver/document-blocks.js +21 -0
  130. package/dist/template-resolver/document-ops.d.ts +167 -0
  131. package/dist/template-resolver/document-ops.js +390 -0
  132. package/dist/template-resolver/document-sanitizer.d.ts +3 -0
  133. package/dist/template-resolver/document-sanitizer.js +6 -0
  134. package/dist/template-resolver/feature.d.ts +2 -0
  135. package/dist/template-resolver/feature.js +4 -0
  136. package/dist/template-resolver/handlers/bundle-import.js +1 -0
  137. package/dist/template-resolver/handlers/document-base.d.ts +23 -0
  138. package/dist/template-resolver/handlers/document-base.js +55 -0
  139. package/dist/template-resolver/handlers/document-blocks.query.d.ts +22 -0
  140. package/dist/template-resolver/handlers/document-blocks.query.js +46 -0
  141. package/dist/template-resolver/handlers/export-bundle.query.d.ts +1 -0
  142. package/dist/template-resolver/handlers/export-bundle.query.js +9 -2
  143. package/dist/template-resolver/handlers/import-bundle-system.write.d.ts +1 -0
  144. package/dist/template-resolver/handlers/import-bundle.write.d.ts +1 -0
  145. package/dist/template-resolver/handlers/patch-draft.write.d.ts +66 -0
  146. package/dist/template-resolver/handlers/patch-draft.write.js +105 -0
  147. package/dist/template-resolver/handlers/preview.query.d.ts +1 -0
  148. package/dist/template-resolver/handlers/preview.query.js +2 -1
  149. package/dist/template-resolver/handlers/send-test.write.d.ts +1 -0
  150. package/dist/template-resolver/handlers/send-test.write.js +2 -1
  151. package/dist/template-resolver/handlers/template-write.d.ts +2 -0
  152. package/dist/template-resolver/handlers/template-write.js +14 -2
  153. package/dist/template-resolver/handlers/validate.query.d.ts +10 -4
  154. package/dist/template-resolver/handlers/validate.query.js +12 -7
  155. package/dist/template-resolver/{web/placeholder-text.js → placeholder-text.js} +1 -1
  156. package/dist/template-resolver/qualified-names.d.ts +2 -0
  157. package/dist/template-resolver/qualified-names.js +2 -0
  158. package/dist/template-resolver/seeding.d.ts +1 -0
  159. package/dist/template-resolver/seeding.js +2 -1
  160. package/dist/template-resolver/table.d.ts +10 -10
  161. package/dist/template-resolver/template-bundle.d.ts +1 -0
  162. package/dist/template-resolver/template-bundle.js +6 -1
  163. package/dist/template-resolver/template-preview.d.ts +4 -1
  164. package/dist/template-resolver/template-preview.js +16 -3
  165. package/dist/template-resolver/template-validation.d.ts +2 -1
  166. package/dist/template-resolver/template-validation.js +1 -1
  167. package/dist/template-resolver/user-content-table.d.ts +10 -10
  168. package/dist/template-resolver/web/client-plugin.d.ts +1 -1
  169. package/dist/template-resolver/web/client-plugin.js +3 -3
  170. package/dist/template-resolver/web/document-tiptap-editor.js +1 -1
  171. package/dist/template-resolver/web/document-toolbar-blocks.d.ts +2 -5
  172. package/dist/template-resolver/web/document-toolbar-blocks.js +1 -21
  173. package/dist/template-resolver/web/i18n.js +14 -0
  174. package/dist/template-resolver/web/placeholder-line-editor.js +2 -2
  175. package/dist/tenant/invitation-table.d.ts +6 -6
  176. package/dist/tenant/membership-table.d.ts +4 -4
  177. package/dist/tenant/schema/tenant.d.ts +6 -6
  178. package/dist/tenant/web/client-plugin.d.ts +1 -1
  179. package/dist/tenant/web/member-status-cell.js +1 -1
  180. package/dist/tier-engine/entity.d.ts +1 -1
  181. package/dist/tier-engine/tier-resolver.d.ts +1 -1
  182. package/dist/tier-engine/web/client-plugin.d.ts +1 -1
  183. package/dist/user/schema/user.d.ts +12 -12
  184. package/dist/user-data-rights/env.d.ts +5 -0
  185. package/dist/user-data-rights/env.js +11 -0
  186. package/dist/user-data-rights/feature.js +4 -2
  187. package/dist/user-data-rights/index.d.ts +1 -0
  188. package/dist/user-data-rights/index.js +1 -0
  189. package/dist/user-data-rights/lib/mail-transport-resolver.js +1 -1
  190. package/dist/user-data-rights/lib/storage-provider-resolver.js +1 -1
  191. package/dist/user-data-rights/mail-notifications.js +1 -1
  192. package/dist/user-data-rights/schema/download-attempt.d.ts +14 -14
  193. package/dist/user-data-rights/schema/download-token.d.ts +8 -8
  194. package/dist/user-data-rights/schema/export-job.d.ts +6 -6
  195. package/dist/user-data-rights/web/client-plugin.d.ts +1 -1
  196. package/dist/user-data-rights/web/privacy-center-screen.js +2 -2
  197. package/dist/waitlist/entity.d.ts +14 -14
  198. package/dist/waitlist/legacy-migrate.d.ts +2 -0
  199. package/dist/waitlist/legacy-migrate.js +38 -3
  200. package/package.json +16 -11
  201. package/src/account-security/changes.json +6 -0
  202. package/src/auth-email-password/changes.json +6 -0
  203. package/src/auth-foundation/changes.json +6 -0
  204. package/src/billing-foundation/changes.json +6 -0
  205. package/src/cap-overview/changes.json +7 -0
  206. package/src/channel-email/changes.json +6 -0
  207. package/src/crypto-shredding/changes.json +6 -0
  208. package/src/file-provider-s3/changes.json +6 -0
  209. package/src/host-routing/changes.json +6 -0
  210. package/src/inbound-mail-foundation/changes.json +7 -0
  211. package/src/legal-pages/changes.json +6 -0
  212. package/src/template-resolver/changes.json +18 -0
  213. package/src/user-data-rights/changes.json +6 -0
  214. package/src/waitlist/changes.json +6 -0
  215. /package/dist/template-resolver/{web/placeholder-text.d.ts → placeholder-text.d.ts} +0 -0
@@ -0,0 +1,86 @@
1
+ import { i18nKey, MAX_LIST_LIMIT, } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { InboundMailAccountStatuses, InboundMailFoundationHandlers, InboundMailFoundationQueries, } from "./constants.js";
3
+ export const MAIL_ACCOUNT_LIST_SCREEN_ID = "mail-accounts";
4
+ export const MAIL_ACCOUNT_EDIT_SCREEN_ID = "mail-account-edit";
5
+ export const MAIL_ACCOUNT_STATUS_OPTION_KEY_PREFIX = "inboundMail.accounts.status.";
6
+ // Same roles as the update/disconnect handlers: a screen rule wider than the
7
+ // handlers would only render actions that 403.
8
+ const MAIL_ACCOUNT_ADMIN_ACCESS = { roles: ["SystemAdmin", "TenantAdmin"] };
9
+ // Several mailboxes per tenant, one row each. The bound query already filters
10
+ // personal mailboxes the caller neither owns nor administers and returns no
11
+ // credential: the secret lives in the secrets feature, never in the row.
12
+ // dormant: the consuming app places the list in its own settings nav.
13
+ export const mailAccountListScreen = {
14
+ id: MAIL_ACCOUNT_LIST_SCREEN_ID,
15
+ type: "projectionList",
16
+ agent: { expose: false },
17
+ query: InboundMailFoundationQueries.listAccounts,
18
+ pagination: false,
19
+ pageSize: MAX_LIST_LIMIT,
20
+ columns: [
21
+ { field: "displayName", label: i18nKey("inboundMail.accounts.col.name"), sortable: false },
22
+ { field: "address", label: i18nKey("inboundMail.accounts.col.address"), sortable: false },
23
+ {
24
+ field: "provider",
25
+ label: i18nKey("inboundMail.accounts.col.provider"),
26
+ sortable: false,
27
+ hideOnNarrow: true,
28
+ },
29
+ {
30
+ field: "status",
31
+ label: i18nKey("inboundMail.accounts.col.status"),
32
+ sortable: false,
33
+ renderer: { format: "enumOption", keyPrefix: MAIL_ACCOUNT_STATUS_OPTION_KEY_PREFIX },
34
+ },
35
+ {
36
+ field: "connectedAt",
37
+ label: i18nKey("inboundMail.accounts.col.connected"),
38
+ sortable: false,
39
+ hideOnNarrow: true,
40
+ renderer: { format: "timestamp" },
41
+ },
42
+ ],
43
+ rowActions: [
44
+ {
45
+ kind: "navigate",
46
+ id: "edit",
47
+ label: i18nKey("inboundMail.accounts.edit"),
48
+ screen: MAIL_ACCOUNT_EDIT_SCREEN_ID,
49
+ params: { map: { accountId: "id", displayName: "displayName" } },
50
+ visible: { field: "status", ne: InboundMailAccountStatuses.disconnected },
51
+ },
52
+ {
53
+ kind: "writeHandler",
54
+ id: "disconnect",
55
+ label: i18nKey("inboundMail.accounts.disconnect"),
56
+ handler: InboundMailFoundationHandlers.disconnectAccount,
57
+ payload: { map: { accountId: "id" } },
58
+ style: "danger",
59
+ confirm: i18nKey("inboundMail.accounts.disconnect.confirm"),
60
+ visible: { field: "status", ne: InboundMailAccountStatuses.disconnected },
61
+ },
62
+ ],
63
+ access: MAIL_ACCOUNT_ADMIN_ACCESS,
64
+ dormant: true,
65
+ };
66
+ // The reason is the audit label update-account requires; it is not in the
67
+ // layout, so the default is what gets written.
68
+ export const mailAccountEditScreen = {
69
+ id: MAIL_ACCOUNT_EDIT_SCREEN_ID,
70
+ type: "actionForm",
71
+ agent: { expose: false },
72
+ handler: InboundMailFoundationHandlers.updateAccount,
73
+ fields: {
74
+ accountId: { type: "text", required: true },
75
+ displayName: { type: "text", required: true, maxLength: 200 },
76
+ reason: { type: "text", default: "tenant_admin" },
77
+ },
78
+ layout: {
79
+ sections: [{ fields: [{ field: "accountId", readOnly: true }, "displayName"] }],
80
+ },
81
+ submitLabel: i18nKey("inboundMail.accounts.edit.submit"),
82
+ redirect: MAIL_ACCOUNT_LIST_SCREEN_ID,
83
+ cancelTarget: MAIL_ACCOUNT_LIST_SCREEN_ID,
84
+ access: MAIL_ACCOUNT_ADMIN_ACCESS,
85
+ dormant: true,
86
+ };
@@ -8,7 +8,7 @@ import { INBOUND_MAIL_PROVIDER_EXTENSION, type InboundMailAccountStatus } from "
8
8
  * config — tenant config reads (host/port/... of the plugins)
9
9
  * registry — extension lookup in the factory (not plugin-internal)
10
10
  * secrets — tenant secret reads (IMAP password, OAuth refresh token)
11
- * _userId — audit identity for secret reads. Handler path: the dispatcher
11
+ * auditUserId — audit identity for secret reads. Handler path: the dispatcher
12
12
  * sets the caller user ID; worker path: system identity.
13
13
  * metricsFor — metrics handle of a feature by name, same behavior as
14
14
  * HandlerContext.metricsFor: unregistered metrics are a silent
@@ -18,7 +18,7 @@ export type InboundMailContext = {
18
18
  readonly config?: ConfigAccessor;
19
19
  readonly registry?: Registry;
20
20
  readonly secrets?: import("@cosmicdrift/kumiko-framework/secrets").SecretsContext;
21
- readonly _userId?: string | undefined;
21
+ readonly auditUserId?: string | undefined;
22
22
  readonly metricsFor?: (featureName: string) => MetricsHandle;
23
23
  };
24
24
  /**
@@ -16,7 +16,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
16
16
  readonly sensitive?: boolean;
17
17
  readonly writeOnly?: boolean;
18
18
  readonly readAsInstruction?: boolean;
19
- readonly format?: "email" | "url" | "phone" | "password";
19
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
20
20
  readonly default?: string;
21
21
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
22
22
  readonly multiline?: boolean | {
@@ -39,7 +39,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
39
39
  readonly sensitive?: boolean;
40
40
  readonly writeOnly?: boolean;
41
41
  readonly readAsInstruction?: boolean;
42
- readonly format?: "email" | "url" | "phone" | "password";
42
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
43
43
  readonly default?: string;
44
44
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
45
45
  readonly multiline?: boolean | {
@@ -62,7 +62,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
62
62
  readonly sensitive?: boolean;
63
63
  readonly writeOnly?: boolean;
64
64
  readonly readAsInstruction?: boolean;
65
- readonly format?: "email" | "url" | "phone" | "password";
65
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
66
66
  readonly default?: string;
67
67
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
68
68
  readonly multiline?: boolean | {
@@ -85,7 +85,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
85
85
  readonly sensitive?: boolean;
86
86
  readonly writeOnly?: boolean;
87
87
  readonly readAsInstruction?: boolean;
88
- readonly format?: "email" | "url" | "phone" | "password";
88
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
89
89
  readonly default?: string;
90
90
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
91
91
  readonly multiline?: boolean | {
@@ -108,7 +108,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
108
108
  readonly sensitive?: boolean;
109
109
  readonly writeOnly?: boolean;
110
110
  readonly readAsInstruction?: boolean;
111
- readonly format?: "email" | "url" | "phone" | "password";
111
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
112
112
  readonly default?: string;
113
113
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
114
114
  readonly multiline?: boolean | {
@@ -199,7 +199,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
199
199
  readonly sensitive?: boolean;
200
200
  readonly writeOnly?: boolean;
201
201
  readonly readAsInstruction?: boolean;
202
- readonly format?: "email" | "url" | "phone" | "password";
202
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
203
203
  readonly default?: string;
204
204
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
205
205
  readonly multiline?: boolean | {
@@ -1,5 +1,5 @@
1
1
  import { type TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
2
- import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer-web";
2
+ import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
3
3
  export type JobsClientOptions = {
4
4
  readonly translations?: TranslationsByLocale;
5
5
  };
@@ -13,7 +13,7 @@ export declare const accountEntity: import("@cosmicdrift/kumiko-types/fields").E
13
13
  readonly sensitive?: boolean;
14
14
  readonly writeOnly?: boolean;
15
15
  readonly readAsInstruction?: boolean;
16
- readonly format?: "email" | "url" | "phone" | "password";
16
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
17
17
  readonly default?: string;
18
18
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
19
19
  readonly multiline?: boolean | {
@@ -61,7 +61,7 @@ export declare const accountEntity: import("@cosmicdrift/kumiko-types/fields").E
61
61
  readonly sensitive?: boolean;
62
62
  readonly writeOnly?: boolean;
63
63
  readonly readAsInstruction?: boolean;
64
- readonly format?: "email" | "url" | "phone" | "password";
64
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
65
65
  readonly default?: string;
66
66
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
67
67
  readonly multiline?: boolean | {
@@ -84,7 +84,7 @@ export declare const accountEntity: import("@cosmicdrift/kumiko-types/fields").E
84
84
  readonly sensitive?: boolean;
85
85
  readonly writeOnly?: boolean;
86
86
  readonly readAsInstruction?: boolean;
87
- readonly format?: "email" | "url" | "phone" | "password";
87
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
88
88
  readonly default?: string;
89
89
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
90
90
  readonly multiline?: boolean | {
@@ -123,7 +123,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
123
123
  readonly sensitive?: boolean;
124
124
  readonly writeOnly?: boolean;
125
125
  readonly readAsInstruction?: boolean;
126
- readonly format?: "email" | "url" | "phone" | "password";
126
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
127
127
  readonly default?: string;
128
128
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
129
129
  readonly multiline?: boolean | {
@@ -146,7 +146,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
146
146
  readonly sensitive?: boolean;
147
147
  readonly writeOnly?: boolean;
148
148
  readonly readAsInstruction?: boolean;
149
- readonly format?: "email" | "url" | "phone" | "password";
149
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
150
150
  readonly default?: string;
151
151
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
152
152
  readonly multiline?: boolean | {
@@ -207,7 +207,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
207
207
  readonly sensitive?: boolean;
208
208
  readonly writeOnly?: boolean;
209
209
  readonly readAsInstruction?: boolean;
210
- readonly format?: "email" | "url" | "phone" | "password";
210
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
211
211
  readonly default?: string;
212
212
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
213
213
  readonly multiline?: boolean | {
@@ -230,7 +230,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
230
230
  readonly sensitive?: boolean;
231
231
  readonly writeOnly?: boolean;
232
232
  readonly readAsInstruction?: boolean;
233
- readonly format?: "email" | "url" | "phone" | "password";
233
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
234
234
  readonly default?: string;
235
235
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
236
236
  readonly multiline?: boolean | {
@@ -255,7 +255,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
255
255
  readonly sensitive?: boolean;
256
256
  readonly writeOnly?: boolean;
257
257
  readonly readAsInstruction?: boolean;
258
- readonly format?: "email" | "url" | "phone" | "password";
258
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
259
259
  readonly default?: string;
260
260
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
261
261
  readonly multiline?: boolean | {
@@ -346,7 +346,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
346
346
  readonly sensitive?: boolean;
347
347
  readonly writeOnly?: boolean;
348
348
  readonly readAsInstruction?: boolean;
349
- readonly format?: "email" | "url" | "phone" | "password";
349
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
350
350
  readonly default?: string;
351
351
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
352
352
  readonly multiline?: boolean | {
@@ -369,7 +369,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
369
369
  readonly sensitive?: boolean;
370
370
  readonly writeOnly?: boolean;
371
371
  readonly readAsInstruction?: boolean;
372
- readonly format?: "email" | "url" | "phone" | "password";
372
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
373
373
  readonly default?: string;
374
374
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
375
375
  readonly multiline?: boolean | {
@@ -392,7 +392,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
392
392
  readonly sensitive?: boolean;
393
393
  readonly writeOnly?: boolean;
394
394
  readonly readAsInstruction?: boolean;
395
- readonly format?: "email" | "url" | "phone" | "password";
395
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
396
396
  readonly default?: string;
397
397
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
398
398
  readonly multiline?: boolean | {
@@ -415,7 +415,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
415
415
  readonly sensitive?: boolean;
416
416
  readonly writeOnly?: boolean;
417
417
  readonly readAsInstruction?: boolean;
418
- readonly format?: "email" | "url" | "phone" | "password";
418
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
419
419
  readonly default?: string;
420
420
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
421
421
  readonly multiline?: boolean | {
@@ -438,7 +438,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
438
438
  readonly sensitive?: boolean;
439
439
  readonly writeOnly?: boolean;
440
440
  readonly readAsInstruction?: boolean;
441
- readonly format?: "email" | "url" | "phone" | "password";
441
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
442
442
  readonly default?: string;
443
443
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
444
444
  readonly multiline?: boolean | {
@@ -1,6 +1,6 @@
1
1
  import { computeRevisionEtag, etagMatches } from "@cosmicdrift/kumiko-framework/api";
2
2
  import { defineFeature, SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
3
- import { escapeHtml } from "@cosmicdrift/kumiko-headless";
3
+ import { escapeHtml } from "@cosmicdrift/kumiko-renderer/headless";
4
4
  import { cachedSecurePageResponse, redirectToCanonicalPath, slashVariantOf, } from "../page-render/index.js";
5
5
  import { LEGAL_REQUIRED_BLOCKS, LEGAL_ROUTES, LEGAL_TERMS_ROUTES, } from "./constants.js";
6
6
  import { runLegalPagesBootCheck } from "./lib/boot-check.js";
@@ -17,6 +17,14 @@ export { runLegalPagesBootCheck } from "./lib/boot-check.js";
17
17
  const TEXT_BLOCK_BY_SLUG_QN = "template-resolver:query:by-slug";
18
18
  // 60s-shared-cache saves the origin-revalidate roundtrip; legal-content edits are live within 60s.
19
19
  const PUBLIC_PAGE_CACHE = { kind: "revalidate", maxAgeSeconds: 60 };
20
+ // Only slugs served in more than one language get alternates.
21
+ function alternatesBySlugOf(routes) {
22
+ const bySlug = new Map();
23
+ for (const route of routes) {
24
+ bySlug.set(route.slug, { ...bySlug.get(route.slug), [route.lang]: route.path });
25
+ }
26
+ return new Map([...bySlug].filter(([, byLang]) => Object.keys(byLang).length > 1));
27
+ }
20
28
  export function createLegalPagesFeature(opts = {}) {
21
29
  const wrapLayout = opts.wrapLayout ?? wrapInLayout;
22
30
  const routes = [
@@ -31,6 +39,7 @@ export function createLegalPagesFeature(opts = {}) {
31
39
  throw new Error("legal-pages: custom `routes` without `requiredBlocks` — pass `requiredBlocks` explicitly (or `[]`)");
32
40
  }
33
41
  }
42
+ const alternatesBySlug = alternatesBySlugOf(routes);
34
43
  return defineFeature("legal-pages", (r) => {
35
44
  r.describe("Opt-in wrapper around `template-resolver` text-blocks that registers public HTML routes (default: `/legal/impressum`, `/legal/datenschutz`, `/legal/imprint`, `/legal/privacy`) with Markdown-to-HTML rendering and a boot-time job that hard-fails in production when the required blocks (default: `imprint/de`, `privacy/de`) are not seeded in `SYSTEM_TENANT`. Both are configurable via `routes`/`requiredBlocks` for apps with a different default language or additional pages. Requires `anonymousAccess: { defaultTenantId: SYSTEM_TENANT_ID }` and `extraContext.templateResolver` to be wired at app bootstrap; for per-tenant imprints or a custom layout call `template-resolver:query:by-slug` directly.");
36
45
  r.uiHints({
@@ -98,6 +107,7 @@ export function createLegalPagesFeature(opts = {}) {
98
107
  : renderedBody,
99
108
  lang: route.lang,
100
109
  slug: route.slug,
110
+ alternates: alternatesBySlug.get(route.slug),
101
111
  });
102
112
  return cachedSecurePageResponse(c.req.raw, {
103
113
  body: html,
@@ -3,8 +3,8 @@ export type LegalPagesLayoutOptions = {
3
3
  readonly siteName: string;
4
4
  readonly css?: string;
5
5
  readonly stylesheetHrefs?: readonly string[];
6
- readonly headerHtml?: (lang: string) => string;
7
- readonly footerHtml?: (lang: string) => string;
6
+ readonly headerHtml?: (lang: string, alternates?: Readonly<Record<string, string>>) => string;
7
+ readonly footerHtml?: (lang: string, alternates?: Readonly<Record<string, string>>) => string;
8
8
  readonly contentClass?: string;
9
9
  };
10
10
  export declare function createLegalPagesLayout(options: LegalPagesLayoutOptions): PublicPageWrapLayout;
@@ -1,4 +1,4 @@
1
- import { escapeHtml, escapeHtmlAttr } from "@cosmicdrift/kumiko-headless";
1
+ import { escapeHtml, escapeHtmlAttr } from "@cosmicdrift/kumiko-renderer/headless";
2
2
  import { TENANT_CONTENT_ATTR } from "../page-render/index.js";
3
3
  export function createLegalPagesLayout(options) {
4
4
  const stylesheets = (options.stylesheetHrefs ?? [])
@@ -9,9 +9,9 @@ export function createLegalPagesLayout(options) {
9
9
  const contentClass = options.contentClass
10
10
  ? ` class="${escapeHtmlAttr(options.contentClass)}"`
11
11
  : "";
12
- return ({ title, bodyHtml, lang }) => {
13
- const headerHtml = options.headerHtml?.(lang) ?? "";
14
- const footerHtml = options.footerHtml?.(lang) ?? "";
12
+ return ({ title, bodyHtml, lang, alternates }) => {
13
+ const headerHtml = options.headerHtml?.(lang, alternates) ?? "";
14
+ const footerHtml = options.footerHtml?.(lang, alternates) ?? "";
15
15
  return `<!doctype html>
16
16
  <html lang="${escapeHtmlAttr(lang)}">
17
17
  <head>
@@ -1,4 +1,4 @@
1
- import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer-web";
1
+ import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
2
2
  export declare function legalPagesClient(opts?: {
3
3
  readonly navId?: string;
4
4
  }): ClientFeatureDefinition;
@@ -2,34 +2,33 @@ import { type EmailTransport } from "@cosmicdrift/kumiko-bundled-features/channe
2
2
  import { type ConfigAccessor, type Registry, type TenantId } from "@cosmicdrift/kumiko-framework/engine";
3
3
  export declare const MAIL_TRANSPORT_EXTENSION: "mailTransport";
4
4
  /**
5
- * Schmaler Surface-Type fuer Transport-Plugins — gespiegelt von
6
- * file-foundation's FileProviderContext. HandlerContext ist zu fett
7
- * (haelt tx, actor, signal etc.); Plugins beschraenken sich auf die
8
- * read-Felder die fuer Tenant-Config + Secret-Lookup noetig sind.
5
+ * Narrow surface type for transport plugins, mirroring file-foundation's
6
+ * FileProviderContext. HandlerContext carries tx, actor, signal and more;
7
+ * plugins only get the read fields needed for tenant config and secret lookup.
9
8
  *
10
- * **Warum nicht voller HandlerContext?** Im Worker-Pfad (r.job-getriggerte
11
- * Transport-Builds, z.B. der user-data-rights forget/export-Cron) gibt es
12
- * keinen per-request `config`/`tx`/`actor` — der Wrapper baut den per-Tenant-
13
- * ConfigAccessor aus `ctx.configResolver`. Ein Plugin das `ctx.tx` oder
14
- * andere request-only-Felder liest, wuerde den Worker-Pfad zur Runtime
15
- * brechen — und das fiele NUR mit echtem SMTP und nur in production auf.
16
- * Cast `ctx as unknown as HandlerContext` macht den Compiler happy, fliegt
17
- * aber zur Runtime im Worker. Plugin das mehr braucht: MailTransportContext
18
- * explizit erweitern (sichtbarer breaking change) statt ctx-cast.
9
+ * **Why not the full HandlerContext?** On the worker path (transport builds
10
+ * triggered by r.job, such as the user-data-rights forget/export cron) there
11
+ * is no per-request `config`/`tx`/`actor`; the wrapper builds the per-tenant
12
+ * ConfigAccessor from `ctx.configResolver`. A plugin reading `ctx.tx` or other
13
+ * request-only fields would break the worker path at runtime, and that would
14
+ * only show up with real SMTP in production. Casting
15
+ * `ctx as unknown as HandlerContext` satisfies the compiler but fails at
16
+ * runtime in the worker. A plugin that needs more extends MailTransportContext
17
+ * explicitly (a visible breaking change) instead of casting ctx.
19
18
  *
20
- * **Felder:**
21
- * config — tenant-config-reads (host/port/from/... der Plugins)
22
- * registry — extension-Lookup in der Factory (nicht plugin-intern)
23
- * secrets — tenant-secret-reads (smtp.password)
24
- * _userId — Audit-Identity fuer secret-reads. Handler-Pfad: dispatcher
25
- * setzt Caller-User-ID; Worker-Pfad: r.job-Wrap setzt eine
26
- * System-Identity.
19
+ * **Fields:**
20
+ * config — tenant config reads (the plugin's host/port/from/...)
21
+ * registry — extension lookup in the factory (not plugin-internal)
22
+ * secrets — tenant secret reads (smtp.password)
23
+ * auditUserId — audit identity for secret reads. Handler path: the
24
+ * dispatcher sets the caller's user id; worker path: the
25
+ * r.job wrap sets a system identity.
27
26
  */
28
27
  export type MailTransportContext = {
29
28
  readonly config?: ConfigAccessor;
30
29
  readonly registry?: Registry;
31
30
  readonly secrets?: import("@cosmicdrift/kumiko-framework/secrets").SecretsContext;
32
- readonly _userId?: string | undefined;
31
+ readonly auditUserId?: string | undefined;
33
32
  };
34
33
  /**
35
34
  * Mail-Transport-Plugin contract. Each provider-feature (mail-transport-
@@ -152,6 +152,6 @@ export function tenantMailTransport(scope) {
152
152
  config: scope.config,
153
153
  registry: scope.registry,
154
154
  secrets: scope.secrets,
155
- _userId: createSystemUser(scope.tenantId).id,
155
+ auditUserId: createSystemUser(scope.tenantId).id,
156
156
  }, scope.tenantId, "channel-email");
157
157
  }
@@ -13,7 +13,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
13
13
  readonly sensitive?: boolean;
14
14
  readonly writeOnly?: boolean;
15
15
  readonly readAsInstruction?: boolean;
16
- readonly format?: "email" | "url" | "phone" | "password";
16
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
17
17
  readonly default?: string;
18
18
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
19
19
  readonly multiline?: boolean | {
@@ -36,7 +36,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
36
36
  readonly sensitive?: boolean;
37
37
  readonly writeOnly?: boolean;
38
38
  readonly readAsInstruction?: boolean;
39
- readonly format?: "email" | "url" | "phone" | "password";
39
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
40
40
  readonly default?: string;
41
41
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
42
42
  readonly multiline?: boolean | {
@@ -59,7 +59,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
59
59
  readonly sensitive?: boolean;
60
60
  readonly writeOnly?: boolean;
61
61
  readonly readAsInstruction?: boolean;
62
- readonly format?: "email" | "url" | "phone" | "password";
62
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
63
63
  readonly default?: string;
64
64
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
65
65
  readonly multiline?: boolean | {
@@ -82,7 +82,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
82
82
  readonly sensitive?: boolean;
83
83
  readonly writeOnly?: boolean;
84
84
  readonly readAsInstruction?: boolean;
85
- readonly format?: "email" | "url" | "phone" | "password";
85
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
86
86
  readonly default?: string;
87
87
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
88
88
  readonly multiline?: boolean | {
@@ -105,7 +105,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
105
105
  readonly sensitive?: boolean;
106
106
  readonly writeOnly?: boolean;
107
107
  readonly readAsInstruction?: boolean;
108
- readonly format?: "email" | "url" | "phone" | "password";
108
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
109
109
  readonly default?: string;
110
110
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
111
111
  readonly multiline?: boolean | {
@@ -128,7 +128,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
128
128
  readonly sensitive?: boolean;
129
129
  readonly writeOnly?: boolean;
130
130
  readonly readAsInstruction?: boolean;
131
- readonly format?: "email" | "url" | "phone" | "password";
131
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
132
132
  readonly default?: string;
133
133
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
134
134
  readonly multiline?: boolean | {
@@ -157,7 +157,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
157
157
  readonly sensitive?: boolean;
158
158
  readonly writeOnly?: boolean;
159
159
  readonly readAsInstruction?: boolean;
160
- readonly format?: "email" | "url" | "phone" | "password";
160
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
161
161
  readonly default?: string;
162
162
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
163
163
  readonly multiline?: boolean | {
@@ -180,7 +180,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
180
180
  readonly sensitive?: boolean;
181
181
  readonly writeOnly?: boolean;
182
182
  readonly readAsInstruction?: boolean;
183
- readonly format?: "email" | "url" | "phone" | "password";
183
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
184
184
  readonly default?: string;
185
185
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
186
186
  readonly multiline?: boolean | {
@@ -203,7 +203,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
203
203
  readonly sensitive?: boolean;
204
204
  readonly writeOnly?: boolean;
205
205
  readonly readAsInstruction?: boolean;
206
- readonly format?: "email" | "url" | "phone" | "password";
206
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
207
207
  readonly default?: string;
208
208
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
209
209
  readonly multiline?: boolean | {
@@ -226,7 +226,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
226
226
  readonly sensitive?: boolean;
227
227
  readonly writeOnly?: boolean;
228
228
  readonly readAsInstruction?: boolean;
229
- readonly format?: "email" | "url" | "phone" | "password";
229
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
230
230
  readonly default?: string;
231
231
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
232
232
  readonly multiline?: boolean | {
@@ -249,7 +249,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
249
249
  readonly sensitive?: boolean;
250
250
  readonly writeOnly?: boolean;
251
251
  readonly readAsInstruction?: boolean;
252
- readonly format?: "email" | "url" | "phone" | "password";
252
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
253
253
  readonly default?: string;
254
254
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
255
255
  readonly multiline?: boolean | {
@@ -272,7 +272,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
272
272
  readonly sensitive?: boolean;
273
273
  readonly writeOnly?: boolean;
274
274
  readonly readAsInstruction?: boolean;
275
- readonly format?: "email" | "url" | "phone" | "password";
275
+ readonly format?: "email" | "url" | "phone" | "password" | "month";
276
276
  readonly default?: string;
277
277
  readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
278
278
  readonly multiline?: boolean | {
@@ -1,5 +1,5 @@
1
1
  import { type TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
2
- import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer-web";
2
+ import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
3
3
  export type ManagedPagesClientOptions = {
4
4
  /** Key-wise Overrides über die Default-Bundles (de/en). */
5
5
  readonly translations?: TranslationsByLocale;