@cosmicdrift/kumiko-bundled-features 0.333.0 → 0.335.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 (277) hide show
  1. package/dist/admin-shell/overview-panels.js +2 -2
  2. package/dist/agent-tools/agent-doc-lint.d.ts +1 -0
  3. package/dist/agent-tools/agent-doc-lint.js +33 -3
  4. package/dist/agent-tools/agent-manifest.js +47 -6
  5. package/dist/agent-tools/filter-ops.d.ts +2 -0
  6. package/dist/agent-tools/filter-ops.js +4 -0
  7. package/dist/agent-tools/tool-catalog.js +1 -4
  8. package/dist/agent-tools/tool-dispatch.js +1 -4
  9. package/dist/audit/constants.d.ts +1 -1
  10. package/dist/audit/constants.js +1 -1
  11. package/dist/audit/handlers/list.query.js +4 -3
  12. package/dist/auth-email-password/handlers/change-password.write.js +2 -0
  13. package/dist/auth-email-password/handlers/invite-create.write.js +12 -2
  14. package/dist/auth-email-password/handlers/login.write.js +2 -0
  15. package/dist/auth-email-password/handlers/self-registration-status.query.js +1 -1
  16. package/dist/auth-email-password/i18n.js +2 -0
  17. package/dist/auth-email-password/web/auth-client.d.ts +1 -0
  18. package/dist/auth-email-password/web/auth-client.js +1 -1
  19. package/dist/auth-email-password/web/auth-gate.js +6 -8
  20. package/dist/auth-email-password/web/index.d.ts +1 -1
  21. package/dist/auth-email-password/web/index.js +1 -1
  22. package/dist/auth-email-password/web/invite-accept-screen.js +16 -12
  23. package/dist/auth-email-password/web/login-screen.js +1 -1
  24. package/dist/auth-email-password/web/session-bootstrap-error.d.ts +5 -1
  25. package/dist/auth-email-password/web/session-bootstrap-error.js +2 -2
  26. package/dist/auth-email-password/web/session.d.ts +4 -0
  27. package/dist/auth-email-password/web/session.js +15 -0
  28. package/dist/auth-mfa/feature.js +3 -2
  29. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +2 -2
  30. package/dist/auth-mfa/handlers/verify.write.js +2 -0
  31. package/dist/auth-mfa/hmac-token-codec.js +3 -0
  32. package/dist/auth-mfa/mfa-challenge-token.js +4 -0
  33. package/dist/auth-mfa/mfa-preauth-setup-token.js +3 -0
  34. package/dist/auth-mfa/schema/user-mfa.d.ts +6 -0
  35. package/dist/auth-mfa/web/mfa-client.d.ts +1 -1
  36. package/dist/auth-mfa/web/mfa-client.js +4 -10
  37. package/dist/billing-foundation/billing-info-query.js +1 -1
  38. package/dist/billing-foundation/checkout-core.d.ts +5 -5
  39. package/dist/billing-foundation/checkout-core.js +10 -6
  40. package/dist/billing-foundation/entities.d.ts +8 -0
  41. package/dist/billing-foundation/handlers/switch-plan.write.js +5 -8
  42. package/dist/billing-foundation/projection.d.ts +8 -0
  43. package/dist/cap-counter/book-cap-usage.js +15 -5
  44. package/dist/cap-counter/enforce-cap.js +9 -3
  45. package/dist/cap-counter/entity.d.ts +1 -0
  46. package/dist/cap-counter/feature.js +3 -2
  47. package/dist/cap-counter/i18n.d.ts +1 -0
  48. package/dist/cap-counter/i18n.js +6 -5
  49. package/dist/cap-overview/handlers/caps-usage.query.js +9 -16
  50. package/dist/cap-overview/handlers/tenant-caps-list.query.js +41 -15
  51. package/dist/cap-overview/i18n.js +5 -0
  52. package/dist/cap-overview/web/cap-cards-panel.js +4 -1
  53. package/dist/cap-overview/web/cap-usage-bar.js +1 -1
  54. package/dist/channel-email/email-channel.js +12 -1
  55. package/dist/channel-in-app/tables.js +2 -6
  56. package/dist/compliance-profiles/handlers/sub-processors.query.js +1 -1
  57. package/dist/compliance-profiles/schema/profile-selection.d.ts +2 -2
  58. package/dist/config/db/queries/resolver.js +3 -1
  59. package/dist/config/handlers/set.write.js +8 -4
  60. package/dist/config/table.d.ts +6 -0
  61. package/dist/config/web/i18n.js +13 -4
  62. package/dist/config/write-helpers.d.ts +1 -1
  63. package/dist/config/write-helpers.js +11 -5
  64. package/dist/crypto-shredding/handlers/forget-subject.write.js +15 -8
  65. package/dist/custom-fields/constants.js +1 -4
  66. package/dist/custom-fields/entity.d.ts +4 -0
  67. package/dist/data-retention/resolve-for-tenant.d.ts +2 -3
  68. package/dist/data-retention/run-retention-cleanup.js +100 -44
  69. package/dist/data-retention/schema/tenant-retention-override.d.ts +4 -0
  70. package/dist/delivery/tables.d.ts +6 -0
  71. package/dist/delivery/types.d.ts +2 -1
  72. package/dist/delivery/types.js +7 -0
  73. package/dist/delivery/unsubscribe.js +5 -11
  74. package/dist/derivatives-sharp/render.js +27 -9
  75. package/dist/document-ingest-foundation/entity.d.ts +4 -0
  76. package/dist/document-ingest-foundation/feature.js +5 -5
  77. package/dist/document-ingest-foundation/providers.d.ts +1 -0
  78. package/dist/document-ingest-foundation/providers.js +6 -0
  79. package/dist/document-ingest-foundation/write-document-extract.d.ts +2 -2
  80. package/dist/document-ingest-foundation/write-document-extract.js +10 -0
  81. package/dist/feature-toggles/global-feature-state-table.js +2 -7
  82. package/dist/feature-toggles/toggle-sync-signal.d.ts +2 -1
  83. package/dist/feature-toggles/toggle-sync-signal.js +3 -2
  84. package/dist/file-provider-s3/feature.js +1 -1
  85. package/dist/files-tenant-data/index.js +3 -2
  86. package/dist/folders/entity.d.ts +8 -0
  87. package/dist/folders/handlers/clear-folder.write.js +4 -11
  88. package/dist/folders/handlers/set-folder.write.js +4 -10
  89. package/dist/form-draft/entity.d.ts +2 -0
  90. package/dist/form-draft/feature.js +3 -2
  91. package/dist/form-draft/handlers/discard.write.js +7 -8
  92. package/dist/form-draft/handlers/get.query.js +7 -1
  93. package/dist/foundation-shared/host-allowlist.d.ts +4 -0
  94. package/dist/foundation-shared/host-allowlist.js +14 -0
  95. package/dist/foundation-shared/index.d.ts +1 -0
  96. package/dist/foundation-shared/index.js +1 -0
  97. package/dist/foundation-shared/mail-host-policy.d.ts +0 -2
  98. package/dist/foundation-shared/mail-host-policy.js +3 -13
  99. package/dist/inbound-mail-foundation/connect-routes.js +7 -5
  100. package/dist/inbound-mail-foundation/entities.d.ts +25 -0
  101. package/dist/inbound-mail-foundation/projection.d.ts +20 -0
  102. package/dist/inbound-mail-foundation/watch-supervisor.js +47 -43
  103. package/dist/jobs/handlers/list.query.d.ts +7 -2
  104. package/dist/jobs/handlers/list.query.js +9 -2
  105. package/dist/jobs/handlers/retry.write.js +3 -2
  106. package/dist/jobs/handlers/tenant-failures.query.js +3 -9
  107. package/dist/jobs/job-run-logger.js +18 -2
  108. package/dist/jobs/job-run-table.d.ts +6 -0
  109. package/dist/jobs/tenant-job-failure-table.js +2 -6
  110. package/dist/ledger/entity.d.ts +16 -3
  111. package/dist/ledger/handlers/confirm-schedule-period.write.js +2 -2
  112. package/dist/ledger/handlers/reverse-transaction.write.js +2 -2
  113. package/dist/ledger/subject-reference.d.ts +4 -0
  114. package/dist/ledger/subject-reference.js +7 -0
  115. package/dist/legal-pages/feature.js +8 -1
  116. package/dist/managed-pages/handlers/branding.query.js +1 -1
  117. package/dist/managed-pages/handlers/by-slug.query.js +1 -1
  118. package/dist/managed-pages/handlers/by-tenant-published.query.js +1 -1
  119. package/dist/managed-pages/table.d.ts +12 -0
  120. package/dist/metrics/compute.js +7 -1
  121. package/dist/metrics/window.js +5 -0
  122. package/dist/notes-history/entity.d.ts +12 -0
  123. package/dist/notes-history/handlers/add-note.write.js +4 -9
  124. package/dist/notes-history-user-data/hooks.js +8 -1
  125. package/dist/personal-access-tokens/constants.d.ts +1 -0
  126. package/dist/personal-access-tokens/constants.js +1 -0
  127. package/dist/personal-access-tokens/feature.js +2 -2
  128. package/dist/personal-access-tokens/handlers/create.write.js +2 -2
  129. package/dist/personal-access-tokens/handlers/revoke.write.js +2 -2
  130. package/dist/personal-access-tokens/i18n.js +12 -13
  131. package/dist/personal-access-tokens/schema/api-token.d.ts +6 -0
  132. package/dist/personal-access-tokens/schema/api-token.js +2 -1
  133. package/dist/personal-access-tokens/screens.js +5 -1
  134. package/dist/rate-limiting/feature.js +2 -0
  135. package/dist/rate-limiting/handlers/bucket-access.js +15 -7
  136. package/dist/rate-limiting/i18n.d.ts +10 -0
  137. package/dist/rate-limiting/i18n.js +10 -0
  138. package/dist/secrets/feature.js +3 -2
  139. package/dist/secrets/table.d.ts +1 -0
  140. package/dist/seo/handlers/seo-config.query.js +1 -1
  141. package/dist/sessions/constants.d.ts +1 -0
  142. package/dist/sessions/constants.js +1 -0
  143. package/dist/sessions/feature.js +5 -3
  144. package/dist/sessions/handlers/revoke-all-for-user.write.d.ts +1 -0
  145. package/dist/sessions/handlers/revoke-all-for-user.write.js +12 -2
  146. package/dist/sessions/handlers/revoke.write.js +2 -2
  147. package/dist/sessions/schema/user-session.d.ts +4 -0
  148. package/dist/sessions/schema/user-session.js +2 -1
  149. package/dist/sessions/screens.js +5 -1
  150. package/dist/sessions/session-callbacks.js +2 -2
  151. package/dist/shared/index.d.ts +1 -1
  152. package/dist/shared/index.js +1 -1
  153. package/dist/shared/lockout-counter.js +1 -1
  154. package/dist/shared/parent-visibility.d.ts +5 -0
  155. package/dist/shared/parent-visibility.js +17 -1
  156. package/dist/shared/row-bound-grant.js +20 -9
  157. package/dist/shared/single-use-token-store.js +5 -13
  158. package/dist/step-dispatcher/webhook-runner.d.ts +0 -2
  159. package/dist/step-dispatcher/webhook-runner.js +18 -17
  160. package/dist/subscription-mollie/plugin-methods.d.ts +3 -2
  161. package/dist/subscription-mollie/plugin-methods.js +7 -1
  162. package/dist/subscription-mollie/verify-webhook.js +6 -0
  163. package/dist/subscription-stripe/feature.js +3 -3
  164. package/dist/subscription-stripe/plugin-methods.js +25 -6
  165. package/dist/subscription-stripe/verify-webhook.js +13 -6
  166. package/dist/tags/entity.d.ts +9 -0
  167. package/dist/tags/handlers/assign-tag.write.js +4 -10
  168. package/dist/tags/handlers/remove-tag.write.js +4 -11
  169. package/dist/template-resolver/api.d.ts +2 -1
  170. package/dist/template-resolver/api.js +1 -1
  171. package/dist/template-resolver/handlers/by-slug.query.d.ts +1 -1
  172. package/dist/template-resolver/handlers/by-slug.query.js +2 -2
  173. package/dist/template-resolver/handlers/by-tenant.query.d.ts +3 -2
  174. package/dist/template-resolver/handlers/by-tenant.query.js +2 -2
  175. package/dist/template-resolver/handlers/collection-item.query.d.ts +1 -1
  176. package/dist/template-resolver/handlers/collection-list.query.d.ts +1 -1
  177. package/dist/template-resolver/handlers/collection-shared.d.ts +3 -2
  178. package/dist/template-resolver/handlers/collection-shared.js +1 -1
  179. package/dist/template-resolver/handlers/find-by-id.query.d.ts +1 -1
  180. package/dist/template-resolver/handlers/find-by-id.query.js +1 -1
  181. package/dist/template-resolver/handlers/list.query.d.ts +1 -1
  182. package/dist/template-resolver/handlers/list.query.js +1 -1
  183. package/dist/template-resolver/seeding.js +41 -39
  184. package/dist/template-resolver/table.d.ts +26 -13
  185. package/dist/template-resolver/testing.js +2 -2
  186. package/dist/template-resolver/user-content-table.d.ts +16 -9
  187. package/dist/template-resolver/web/client-plugin.d.ts +1 -1
  188. package/dist/template-resolver-user-data/hooks.js +1 -1
  189. package/dist/tenant/cancel-pending-invitation.d.ts +8 -0
  190. package/dist/tenant/cancel-pending-invitation.js +22 -0
  191. package/dist/tenant/feature.js +4 -2
  192. package/dist/tenant/handlers/cancel-invitation.write.js +6 -21
  193. package/dist/tenant/handlers/member-directory.query.d.ts +1 -0
  194. package/dist/tenant/handlers/member-directory.query.js +17 -4
  195. package/dist/tenant/handlers/remove-member.write.js +9 -14
  196. package/dist/tenant/handlers/team-list.query.js +2 -2
  197. package/dist/tenant/handlers/tenant-directory.query.d.ts +1 -0
  198. package/dist/tenant/handlers/tenant-directory.query.js +13 -3
  199. package/dist/tenant/handlers/update-member-roles.write.d.ts +1 -1
  200. package/dist/tenant/handlers/update-member-roles.write.js +28 -12
  201. package/dist/tenant/i18n.js +4 -0
  202. package/dist/tenant/index.d.ts +1 -1
  203. package/dist/tenant/index.js +1 -1
  204. package/dist/tenant/invitation-table.d.ts +8 -2
  205. package/dist/tenant/last-tenant-admin.d.ts +1 -1
  206. package/dist/tenant/last-tenant-admin.js +5 -3
  207. package/dist/tenant/membership-table.d.ts +4 -0
  208. package/dist/tenant/schema/tenant.d.ts +8 -2
  209. package/dist/tenant/seeding.d.ts +4 -0
  210. package/dist/tenant/seeding.js +9 -2
  211. package/dist/tenant-lifecycle/boot-checks.d.ts +1 -0
  212. package/dist/tenant-lifecycle/boot-checks.js +27 -1
  213. package/dist/tenant-lifecycle/feature.js +2 -1
  214. package/dist/tenant-lifecycle/stages.js +2 -2
  215. package/dist/tenant-settings/feature.js +9 -6
  216. package/dist/tier-engine/entity.d.ts +2 -0
  217. package/dist/tier-engine/feature.js +3 -2
  218. package/dist/tier-engine/tier-resolver.d.ts +2 -0
  219. package/dist/user/command-schemas.d.ts +2 -2
  220. package/dist/user/handlers/create.write.d.ts +1 -1
  221. package/dist/user/handlers/create.write.js +8 -2
  222. package/dist/user/handlers/update.write.d.ts +1 -1
  223. package/dist/user/handlers/update.write.js +8 -2
  224. package/dist/user/schema/user.d.ts +14 -2
  225. package/dist/user-data-rights/db/queries/export-jobs.d.ts +2 -0
  226. package/dist/user-data-rights/feature.js +22 -9
  227. package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +4 -7
  228. package/dist/user-data-rights/handlers/deletion-grace-period.d.ts +3 -2
  229. package/dist/user-data-rights/handlers/deletion-grace-period.js +30 -8
  230. package/dist/user-data-rights/handlers/download-by-token.query.js +1 -1
  231. package/dist/user-data-rights/handlers/request-deletion-by-email.write.js +1 -1
  232. package/dist/user-data-rights/handlers/request-deletion.write.js +3 -6
  233. package/dist/user-data-rights/lib/update-user-lifecycle.js +7 -14
  234. package/dist/user-data-rights/run-export-jobs.d.ts +1 -0
  235. package/dist/user-data-rights/run-export-jobs.js +74 -41
  236. package/dist/user-data-rights/run-forget-cleanup.js +2 -2
  237. package/dist/user-data-rights/run-user-export.js +8 -4
  238. package/dist/user-data-rights/schema/download-attempt.d.ts +14 -0
  239. package/dist/user-data-rights/schema/download-token.d.ts +8 -0
  240. package/dist/user-data-rights/schema/export-job.d.ts +8 -2
  241. package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +4 -1
  242. package/dist/user-profile/feature.js +6 -1
  243. package/dist/user-profile/handlers/change-email.write.js +2 -0
  244. package/dist/workflow-runner/db/queries/due-runs.js +6 -9
  245. package/dist/workflow-runner/event-subscriber.js +29 -9
  246. package/dist/workflow-runner/handlers/resume-run.write.js +8 -5
  247. package/dist/workflow-runner/pending-projection.js +8 -1
  248. package/package.json +11 -9
  249. package/src/agent-tools/changes.json +12 -0
  250. package/src/auth-email-password/changes.json +18 -0
  251. package/src/auth-mfa/changes.json +6 -0
  252. package/src/billing-foundation/changes.json +7 -0
  253. package/src/cap-counter/changes.json +7 -0
  254. package/src/cap-overview/changes.json +12 -0
  255. package/src/channel-email/changes.json +6 -0
  256. package/src/config/changes.json +6 -0
  257. package/src/crypto-shredding/changes.json +6 -0
  258. package/src/data-retention/changes.json +12 -0
  259. package/src/delivery/changes.json +7 -0
  260. package/src/derivatives-sharp/changes.json +11 -0
  261. package/src/document-ingest-foundation/changes.json +12 -0
  262. package/src/inbound-mail-foundation/changes.json +12 -0
  263. package/src/jobs/changes.json +13 -0
  264. package/src/legal-pages/changes.json +8 -1
  265. package/src/managed-pages/changes.json +5 -0
  266. package/src/metrics/changes.json +6 -0
  267. package/src/rate-limiting/changes.json +5 -0
  268. package/src/secrets/changes.json +7 -0
  269. package/src/sessions/changes.json +5 -0
  270. package/src/shared/changes.json +6 -0
  271. package/src/step-dispatcher/changes.json +5 -0
  272. package/src/subscription-mollie/changes.json +7 -0
  273. package/src/subscription-stripe/changes.json +11 -0
  274. package/src/template-resolver/changes.json +7 -0
  275. package/src/tenant/changes.json +29 -0
  276. package/src/user-data-rights/changes.json +22 -0
  277. package/src/workflow-runner/changes.json +6 -0
@@ -10,6 +10,7 @@ export declare const folderEntity: EntityDefinition<{
10
10
  readonly filterable?: boolean;
11
11
  readonly encrypted?: boolean;
12
12
  readonly sensitive?: boolean;
13
+ readonly writeOnly?: boolean;
13
14
  readonly readAsInstruction?: boolean;
14
15
  readonly format?: "email" | "url" | "phone" | "password";
15
16
  readonly default?: string;
@@ -30,6 +31,7 @@ export declare const folderEntity: EntityDefinition<{
30
31
  readonly filterable?: boolean;
31
32
  readonly encrypted?: boolean;
32
33
  readonly sensitive?: boolean;
34
+ readonly writeOnly?: boolean;
33
35
  readonly readAsInstruction?: boolean;
34
36
  readonly format?: "email" | "url" | "phone" | "password";
35
37
  readonly default?: string;
@@ -52,6 +54,7 @@ export declare function createFolderAssignmentEntity(access?: EntityDefinition["
52
54
  readonly filterable?: boolean;
53
55
  readonly encrypted?: boolean;
54
56
  readonly sensitive?: boolean;
57
+ readonly writeOnly?: boolean;
55
58
  readonly readAsInstruction?: boolean;
56
59
  readonly format?: "email" | "url" | "phone" | "password";
57
60
  readonly default?: string;
@@ -72,6 +75,7 @@ export declare function createFolderAssignmentEntity(access?: EntityDefinition["
72
75
  readonly filterable?: boolean;
73
76
  readonly encrypted?: boolean;
74
77
  readonly sensitive?: boolean;
78
+ readonly writeOnly?: boolean;
75
79
  readonly readAsInstruction?: boolean;
76
80
  readonly format?: "email" | "url" | "phone" | "password";
77
81
  readonly default?: string;
@@ -92,6 +96,7 @@ export declare function createFolderAssignmentEntity(access?: EntityDefinition["
92
96
  readonly filterable?: boolean;
93
97
  readonly encrypted?: boolean;
94
98
  readonly sensitive?: boolean;
99
+ readonly writeOnly?: boolean;
95
100
  readonly readAsInstruction?: boolean;
96
101
  readonly format?: "email" | "url" | "phone" | "password";
97
102
  readonly default?: string;
@@ -114,6 +119,7 @@ export declare const folderAssignmentEntity: EntityDefinition<{
114
119
  readonly filterable?: boolean;
115
120
  readonly encrypted?: boolean;
116
121
  readonly sensitive?: boolean;
122
+ readonly writeOnly?: boolean;
117
123
  readonly readAsInstruction?: boolean;
118
124
  readonly format?: "email" | "url" | "phone" | "password";
119
125
  readonly default?: string;
@@ -134,6 +140,7 @@ export declare const folderAssignmentEntity: EntityDefinition<{
134
140
  readonly filterable?: boolean;
135
141
  readonly encrypted?: boolean;
136
142
  readonly sensitive?: boolean;
143
+ readonly writeOnly?: boolean;
137
144
  readonly readAsInstruction?: boolean;
138
145
  readonly format?: "email" | "url" | "phone" | "password";
139
146
  readonly default?: string;
@@ -154,6 +161,7 @@ export declare const folderAssignmentEntity: EntityDefinition<{
154
161
  readonly filterable?: boolean;
155
162
  readonly encrypted?: boolean;
156
163
  readonly sensitive?: boolean;
164
+ readonly writeOnly?: boolean;
157
165
  readonly readAsInstruction?: boolean;
158
166
  readonly format?: "email" | "url" | "phone" | "password";
159
167
  readonly default?: string;
@@ -1,5 +1,4 @@
1
- import { NotFoundError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
2
- import { joinRowParentIsVisible } from "../../shared/index.js";
1
+ import { denyUnlessJoinRowParentVisible } from "../../shared/index.js";
3
2
  import { folderAssignmentAggregateId } from "../aggregate-id.js";
4
3
  import { DEFAULT_FOLDER_ACCESS } from "../constants.js";
5
4
  import { folderAssignmentExecutor } from "../executor.js";
@@ -19,15 +18,9 @@ export function createClearFolderHandler(access = DEFAULT_FOLDER_ACCESS) {
19
18
  description: "Unfiles a host entity so it sits in no folder at all, reporting success when it was already unfiled; use it to take an entity out of its folder without touching the folder itself.",
20
19
  handler: async (event, ctx) => {
21
20
  const payload = event.payload; // @cast-boundary engine-payload
22
- // entityType/entityId are client input: the caller must be able to see
23
- // the host row through that entity's own read path (tenant scope plus its
24
- // `access.read` ownership) before its assignment row may be written.
25
- // Checked FIRST, ahead of every lookup below, so a denied caller can't tell
26
- // an invisible parent apart from a missing assignment or an unknown folder —
27
- // every path answers with the same NotFoundError.
28
- if (!(await joinRowParentIsVisible(ctx.registry, "folder-assignment", payload, event.user, ctx.db))) {
29
- return writeFailure(new NotFoundError(payload.entityType, payload.entityId));
30
- }
21
+ const denied = await denyUnlessJoinRowParentVisible(ctx.registry, "folder-assignment", payload, event.user, ctx.db);
22
+ if (denied)
23
+ return denied;
31
24
  const id = folderAssignmentAggregateId(event.user.tenantId, payload.entityType, payload.entityId);
32
25
  const existing = await folderAssignmentExecutor.detail({ id }, event.user, ctx.db);
33
26
  if (!existing) {
@@ -1,5 +1,5 @@
1
1
  import { NotFoundError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
2
- import { joinRowParentIsVisible } from "../../shared/index.js";
2
+ import { denyUnlessJoinRowParentVisible } from "../../shared/index.js";
3
3
  import { folderAssignmentAggregateId } from "../aggregate-id.js";
4
4
  import { DEFAULT_FOLDER_ACCESS } from "../constants.js";
5
5
  import { folderAssignmentExecutor, folderExecutor } from "../executor.js";
@@ -35,15 +35,9 @@ export function createSetFolderHandler(access = DEFAULT_FOLDER_ACCESS) {
35
35
  description: "Files a host entity into one existing folder and moves it out of whatever folder it was in, since an entity belongs to at most one folder; use it for both the first filing and every later move.",
36
36
  handler: async (event, ctx) => {
37
37
  const payload = event.payload; // @cast-boundary engine-payload
38
- // entityType/entityId are client input: the caller must be able to see
39
- // the host row through that entity's own read path (tenant scope plus its
40
- // `access.read` ownership) before its assignment row may be written.
41
- // Checked FIRST, ahead of every lookup below, so a denied caller can't tell
42
- // an invisible parent apart from a missing assignment or an unknown folder —
43
- // every path answers with the same NotFoundError.
44
- if (!(await joinRowParentIsVisible(ctx.registry, "folder-assignment", payload, event.user, ctx.db))) {
45
- return writeFailure(new NotFoundError(payload.entityType, payload.entityId));
46
- }
38
+ const denied = await denyUnlessJoinRowParentVisible(ctx.registry, "folder-assignment", payload, event.user, ctx.db);
39
+ if (denied)
40
+ return denied;
47
41
  const id = folderAssignmentAggregateId(event.user.tenantId, payload.entityType, payload.entityId);
48
42
  const folder = await folderExecutor.detail({ id: payload.folderId }, event.user, ctx.db);
49
43
  if (!folder)
@@ -9,6 +9,7 @@ export declare const formDraftEntity: import("@cosmicdrift/kumiko-types/fields")
9
9
  readonly filterable?: boolean;
10
10
  readonly encrypted?: boolean;
11
11
  readonly sensitive?: boolean;
12
+ readonly writeOnly?: boolean;
12
13
  readonly readAsInstruction?: boolean;
13
14
  readonly format?: "email" | "url" | "phone" | "password";
14
15
  readonly default?: string;
@@ -29,6 +30,7 @@ export declare const formDraftEntity: import("@cosmicdrift/kumiko-types/fields")
29
30
  readonly filterable?: boolean;
30
31
  readonly encrypted?: boolean;
31
32
  readonly sensitive?: boolean;
33
+ readonly writeOnly?: boolean;
32
34
  readonly readAsInstruction?: boolean;
33
35
  readonly format?: "email" | "url" | "phone" | "password";
34
36
  readonly default?: string;
@@ -12,6 +12,7 @@ import { discardDraftWrite } from "./handlers/discard.write.js";
12
12
  import { getDraftQuery } from "./handlers/get.query.js";
13
13
  import { listDraftsQuery } from "./handlers/list.query.js";
14
14
  import { saveDraftWrite } from "./handlers/save.write.js";
15
+ const CLEANUP_ESCAPE_HATCH_REASON = "purges stale drafts of every tenant";
15
16
  function registerFormDraft(r) {
16
17
  r.describe("Per-user, per-tenant working copy of an in-progress form, saved BEFORE the real domain entity exists. Owns one event-sourced entity, `form-draft` (`read_form_drafts`), keyed by a caller-assigned draftKey (typically screenId + optional hostEntityId), unique per (tenant, owner, draftKey). `save` upserts the draft blob ({ values, stepIndex, savedAt } — savedAt stamped server-side), `discard` deletes it (called once the real submit succeeds), `get` resumes it, `list` finds a user's open drafts for a given screenId (draftKey prefix match) — the fallback when a client-generated draftId is lost. Ownership is enforced by a per-row owner filter in every handler, not by roles — a foreign user's save/discard/get/list for someone else's draftKey never sees or touches that row. Never holds anything that already lives in a domain stream; the consuming app is responsible for discarding once the domain write succeeds. A daily cron job hard-deletes drafts past a configurable retention window (`form-draft:config:retention-days`, SystemAdmin-writable, default 30 days).");
17
18
  r.uiHints({
@@ -36,8 +37,8 @@ function registerFormDraft(r) {
36
37
  name: "cleanup",
37
38
  trigger: { cron: "0 3 * * *" },
38
39
  concurrency: "skip",
39
- escapeHatch: { reason: "purges stale drafts of every tenant" },
40
- handler: (payload, ctx) => cleanupDraftsJob(payload, ctx, ctx.db.unsafeRaw("purges stale drafts of every tenant")),
40
+ escapeHatch: { reason: CLEANUP_ESCAPE_HATCH_REASON },
41
+ handler: (payload, ctx) => cleanupDraftsJob(payload, ctx, ctx.db.unsafeRaw(CLEANUP_ESCAPE_HATCH_REASON)),
41
42
  });
42
43
  }
43
44
  export const formDraftFeature = defineFeature(FORM_DRAFT_FEATURE_NAME, registerFormDraft);
@@ -73,18 +73,17 @@ export const discardDraftWrite = defineWriteHandler({
73
73
  const keys = ownedRefs.map((ref) => ref.storageKey);
74
74
  const log = ctx.log;
75
75
  const schedule = ctx.scheduleAfterCommit;
76
+ const release = async () => {
77
+ await releaseDraftFileRefs(keys, async (key) => {
78
+ await files.ref(key).delete();
79
+ }, log);
80
+ };
76
81
  if (schedule) {
77
- schedule(async () => {
78
- await releaseDraftFileRefs(keys, async (key) => {
79
- await files.ref(key).delete();
80
- }, log);
81
- });
82
+ schedule(release);
82
83
  }
83
84
  else {
84
85
  // Unit/harness paths without a commit sink — best-effort inline.
85
- await releaseDraftFileRefs(keys, async (key) => {
86
- await files.ref(key).delete();
87
- }, log);
86
+ await release();
88
87
  }
89
88
  }
90
89
  return { isSuccess: true, data: { discarded: true } };
@@ -16,6 +16,12 @@ export const getDraftQuery = defineQueryHandler({
16
16
  if (!row)
17
17
  return { draft: null };
18
18
  const parsed = formDraftBlobSchema.safeParse(row.draft);
19
- return { draft: parsed.success ? parsed.data : null };
19
+ if (!parsed.success) {
20
+ // Schema evolution or a corrupt jsonb row: surface it to operators
21
+ // instead of silently making the user's draft vanish.
22
+ ctx.log?.warn?.(`[form-draft:get] stored blob for draftKey=${query.payload.draftKey} failed schema, treating as absent: ${parsed.error.message}`);
23
+ return { draft: null };
24
+ }
25
+ return { draft: parsed.data };
20
26
  },
21
27
  });
@@ -0,0 +1,4 @@
1
+ /** Parses a comma-separated operator host allowlist env var. Never throws —
2
+ * an unset or empty value just means no bypass. */
3
+ export declare function readHostAllowlistFromEnv(envVar: string, env?: Readonly<Record<string, string | undefined>>): readonly string[];
4
+ export declare function isHostAllowlisted(host: string, allowlist: readonly string[]): boolean;
@@ -0,0 +1,14 @@
1
+ /** Parses a comma-separated operator host allowlist env var. Never throws —
2
+ * an unset or empty value just means no bypass. */
3
+ export function readHostAllowlistFromEnv(envVar, env = process.env) {
4
+ const raw = env[envVar];
5
+ if (!raw)
6
+ return [];
7
+ return raw
8
+ .split(",")
9
+ .map((host) => host.trim())
10
+ .filter((host) => host.length > 0);
11
+ }
12
+ export function isHostAllowlisted(host, allowlist) {
13
+ return allowlist.some((candidate) => candidate.toLowerCase() === host.toLowerCase());
14
+ }
@@ -1,2 +1,3 @@
1
1
  export { requireDefined, requireNonEmpty, requireSecretSet } from "./config-helpers.js";
2
+ export { isHostAllowlisted, readHostAllowlistFromEnv } from "./host-allowlist.js";
2
3
  export { BlockedHostError, HostResolutionError, MAIL_ALLOWED_PRIVATE_HOSTS_ENV_VAR, type MailConnectTarget, type MailHostGuardOptions, readAllowedPrivateMailHostsFromEnv, resolveMailConnectTarget, } from "./mail-host-policy.js";
@@ -1,4 +1,5 @@
1
1
  // Public API of foundation-shared — utilities consumed by the per-tenant
2
2
  // Foundation packages (ai-foundation, mail-foundation, file-foundation).
3
3
  export { requireDefined, requireNonEmpty, requireSecretSet } from "./config-helpers.js";
4
+ export { isHostAllowlisted, readHostAllowlistFromEnv } from "./host-allowlist.js";
4
5
  export { BlockedHostError, HostResolutionError, MAIL_ALLOWED_PRIVATE_HOSTS_ENV_VAR, readAllowedPrivateMailHostsFromEnv, resolveMailConnectTarget, } from "./mail-host-policy.js";
@@ -1,7 +1,5 @@
1
1
  import type { lookup } from "node:dns/promises";
2
2
  export declare const MAIL_ALLOWED_PRIVATE_HOSTS_ENV_VAR = "KUMIKO_MAIL_ALLOWED_PRIVATE_HOSTS";
3
- /** Parses the comma-separated operator allowlist env var. Never throws —
4
- * an unset or empty value just means no bypass. */
5
3
  export declare function readAllowedPrivateMailHostsFromEnv(env?: Readonly<Record<string, string | undefined>>): readonly string[];
6
4
  export type MailHostGuardOptions = {
7
5
  readonly allowedPrivateMailHosts?: readonly string[];
@@ -16,23 +16,13 @@
16
16
  // conflict check tripping when both features are mounted together.
17
17
  import { isIP } from "node:net";
18
18
  import { resolvePublicHostname } from "@cosmicdrift/kumiko-framework/http";
19
+ import { isHostAllowlisted, readHostAllowlistFromEnv } from "./host-allowlist.js";
19
20
  export const MAIL_ALLOWED_PRIVATE_HOSTS_ENV_VAR = "KUMIKO_MAIL_ALLOWED_PRIVATE_HOSTS";
20
- /** Parses the comma-separated operator allowlist env var. Never throws —
21
- * an unset or empty value just means no bypass. */
22
21
  export function readAllowedPrivateMailHostsFromEnv(env = process.env) {
23
- const raw = env[MAIL_ALLOWED_PRIVATE_HOSTS_ENV_VAR];
24
- if (!raw)
25
- return [];
26
- return raw
27
- .split(",")
28
- .map((host) => host.trim())
29
- .filter((host) => host.length > 0);
30
- }
31
- function isAllowedPrivateMailHost(host, allowed) {
32
- return allowed.some((candidate) => candidate.toLowerCase() === host.toLowerCase());
22
+ return readHostAllowlistFromEnv(MAIL_ALLOWED_PRIVATE_HOSTS_ENV_VAR, env);
33
23
  }
34
24
  export async function resolveMailConnectTarget(host, options = {}) {
35
- if (isAllowedPrivateMailHost(host, options.allowedPrivateMailHosts ?? [])) {
25
+ if (isHostAllowlisted(host, options.allowedPrivateMailHosts ?? [])) {
36
26
  return { host };
37
27
  }
38
28
  const resolved = await resolvePublicHostname(host, options.lookupFn);
@@ -73,6 +73,12 @@ export function createInboundMailConnectRoutes(options) {
73
73
  verify: async (request) => verifyCallbackRequest(request, options.stateSecret),
74
74
  handler: async (c, verified, deps) => {
75
75
  const { code, state } = verified;
76
+ // Checked before exchangeCode/connectAccount: the code is single-use and
77
+ // an account created without a persistable refresh token is an orphan.
78
+ // `deps.secrets` is optional on SignatureExtraRouteDeps.
79
+ if (!deps.secrets) {
80
+ return errorJson(c, 500, "secrets_context_missing", `${INBOUND_MAIL_FOUNDATION_FEATURE}: no secrets context wired for the oauth callback route — the refresh token cannot be persisted`);
81
+ }
76
82
  const providerCtx = { registry: deps.registry, secrets: deps.secrets, config: undefined };
77
83
  let plugin;
78
84
  try {
@@ -123,11 +129,7 @@ export function createInboundMailConnectRoutes(options) {
123
129
  }
124
130
  // Refresh-token into the per-account secret slot (Slot = accountId).
125
131
  // Access tokens (~1h) are NEVER persisted — refresh-before-poll in the
126
- // sync path. `deps.secrets` is optional on SignatureExtraRouteDeps —
127
- // without it the token would be silently lost, so fail loud instead.
128
- if (!deps.secrets) {
129
- return errorJson(c, 500, "secrets_context_missing", `${INBOUND_MAIL_FOUNDATION_FEATURE}: no secrets context wired for the oauth callback route — the refresh token cannot be persisted`);
130
- }
132
+ // sync path.
131
133
  await deps.secrets.set(state.tenantId, inboundCredentialSecretKey(accountId), tokens.refreshToken, {
132
134
  redact: (plaintext) => `${plaintext.slice(0, 4)}…`,
133
135
  hint: `OAuth refresh token for inbound mail account ${accountId}`,
@@ -11,6 +11,7 @@ export declare const mailAccountEntity: import("@cosmicdrift/kumiko-types/fields
11
11
  readonly filterable?: boolean;
12
12
  readonly encrypted?: boolean;
13
13
  readonly sensitive?: boolean;
14
+ readonly writeOnly?: boolean;
14
15
  readonly readAsInstruction?: boolean;
15
16
  readonly format?: "email" | "url" | "phone" | "password";
16
17
  readonly default?: string;
@@ -31,6 +32,7 @@ export declare const mailAccountEntity: import("@cosmicdrift/kumiko-types/fields
31
32
  readonly filterable?: boolean;
32
33
  readonly encrypted?: boolean;
33
34
  readonly sensitive?: boolean;
35
+ readonly writeOnly?: boolean;
34
36
  readonly readAsInstruction?: boolean;
35
37
  readonly format?: "email" | "url" | "phone" | "password";
36
38
  readonly default?: string;
@@ -51,6 +53,7 @@ export declare const mailAccountEntity: import("@cosmicdrift/kumiko-types/fields
51
53
  readonly filterable?: boolean;
52
54
  readonly encrypted?: boolean;
53
55
  readonly sensitive?: boolean;
56
+ readonly writeOnly?: boolean;
54
57
  readonly readAsInstruction?: boolean;
55
58
  readonly format?: "email" | "url" | "phone" | "password";
56
59
  readonly default?: string;
@@ -71,6 +74,7 @@ export declare const mailAccountEntity: import("@cosmicdrift/kumiko-types/fields
71
74
  readonly filterable?: boolean;
72
75
  readonly encrypted?: boolean;
73
76
  readonly sensitive?: boolean;
77
+ readonly writeOnly?: boolean;
74
78
  readonly readAsInstruction?: boolean;
75
79
  readonly format?: "email" | "url" | "phone" | "password";
76
80
  readonly default?: string;
@@ -91,6 +95,7 @@ export declare const mailAccountEntity: import("@cosmicdrift/kumiko-types/fields
91
95
  readonly filterable?: boolean;
92
96
  readonly encrypted?: boolean;
93
97
  readonly sensitive?: boolean;
98
+ readonly writeOnly?: boolean;
94
99
  readonly readAsInstruction?: boolean;
95
100
  readonly format?: "email" | "url" | "phone" | "password";
96
101
  readonly default?: string;
@@ -111,6 +116,7 @@ export declare const mailAccountEntity: import("@cosmicdrift/kumiko-types/fields
111
116
  readonly filterable?: boolean;
112
117
  readonly encrypted?: boolean;
113
118
  readonly sensitive?: boolean;
119
+ readonly writeOnly?: boolean;
114
120
  readonly readAsInstruction?: boolean;
115
121
  readonly format?: "email" | "url" | "phone" | "password";
116
122
  readonly default?: string;
@@ -131,6 +137,7 @@ export declare const mailAccountEntity: import("@cosmicdrift/kumiko-types/fields
131
137
  readonly filterable?: boolean;
132
138
  readonly encrypted?: boolean;
133
139
  readonly sensitive?: boolean;
140
+ readonly writeOnly?: boolean;
134
141
  readonly readAsInstruction?: boolean;
135
142
  readonly format?: "email" | "url" | "phone" | "password";
136
143
  readonly default?: string;
@@ -171,6 +178,7 @@ export declare const inboundMessageEntity: import("@cosmicdrift/kumiko-types/fie
171
178
  readonly filterable?: boolean;
172
179
  readonly encrypted?: boolean;
173
180
  readonly sensitive?: boolean;
181
+ readonly writeOnly?: boolean;
174
182
  readonly readAsInstruction?: boolean;
175
183
  readonly format?: "email" | "url" | "phone" | "password";
176
184
  readonly default?: string;
@@ -191,6 +199,7 @@ export declare const inboundMessageEntity: import("@cosmicdrift/kumiko-types/fie
191
199
  readonly filterable?: boolean;
192
200
  readonly encrypted?: boolean;
193
201
  readonly sensitive?: boolean;
202
+ readonly writeOnly?: boolean;
194
203
  readonly readAsInstruction?: boolean;
195
204
  readonly format?: "email" | "url" | "phone" | "password";
196
205
  readonly default?: string;
@@ -211,6 +220,7 @@ export declare const inboundMessageEntity: import("@cosmicdrift/kumiko-types/fie
211
220
  readonly filterable?: boolean;
212
221
  readonly encrypted?: boolean;
213
222
  readonly sensitive?: boolean;
223
+ readonly writeOnly?: boolean;
214
224
  readonly readAsInstruction?: boolean;
215
225
  readonly format?: "email" | "url" | "phone" | "password";
216
226
  readonly default?: string;
@@ -231,6 +241,7 @@ export declare const inboundMessageEntity: import("@cosmicdrift/kumiko-types/fie
231
241
  readonly filterable?: boolean;
232
242
  readonly encrypted?: boolean;
233
243
  readonly sensitive?: boolean;
244
+ readonly writeOnly?: boolean;
234
245
  readonly readAsInstruction?: boolean;
235
246
  readonly format?: "email" | "url" | "phone" | "password";
236
247
  readonly default?: string;
@@ -251,6 +262,7 @@ export declare const inboundMessageEntity: import("@cosmicdrift/kumiko-types/fie
251
262
  readonly filterable?: boolean;
252
263
  readonly encrypted?: boolean;
253
264
  readonly sensitive?: boolean;
265
+ readonly writeOnly?: boolean;
254
266
  readonly readAsInstruction?: boolean;
255
267
  readonly format?: "email" | "url" | "phone" | "password";
256
268
  readonly default?: string;
@@ -271,6 +283,7 @@ export declare const inboundMessageEntity: import("@cosmicdrift/kumiko-types/fie
271
283
  readonly filterable?: boolean;
272
284
  readonly encrypted?: boolean;
273
285
  readonly sensitive?: boolean;
286
+ readonly writeOnly?: boolean;
274
287
  readonly readAsInstruction?: boolean;
275
288
  readonly format?: "email" | "url" | "phone" | "password";
276
289
  readonly default?: string;
@@ -291,6 +304,7 @@ export declare const inboundMessageEntity: import("@cosmicdrift/kumiko-types/fie
291
304
  readonly filterable?: boolean;
292
305
  readonly encrypted?: boolean;
293
306
  readonly sensitive?: boolean;
307
+ readonly writeOnly?: boolean;
294
308
  readonly readAsInstruction?: boolean;
295
309
  readonly format?: "email" | "url" | "phone" | "password";
296
310
  readonly default?: string;
@@ -311,6 +325,7 @@ export declare const inboundMessageEntity: import("@cosmicdrift/kumiko-types/fie
311
325
  readonly filterable?: boolean;
312
326
  readonly encrypted?: boolean;
313
327
  readonly sensitive?: boolean;
328
+ readonly writeOnly?: boolean;
314
329
  readonly readAsInstruction?: boolean;
315
330
  readonly format?: "email" | "url" | "phone" | "password";
316
331
  readonly default?: string;
@@ -331,6 +346,7 @@ export declare const inboundMessageEntity: import("@cosmicdrift/kumiko-types/fie
331
346
  readonly filterable?: boolean;
332
347
  readonly encrypted?: boolean;
333
348
  readonly sensitive?: boolean;
349
+ readonly writeOnly?: boolean;
334
350
  readonly readAsInstruction?: boolean;
335
351
  readonly format?: "email" | "url" | "phone" | "password";
336
352
  readonly default?: string;
@@ -366,6 +382,7 @@ export declare const inboundMessageEntity: import("@cosmicdrift/kumiko-types/fie
366
382
  readonly filterable?: boolean;
367
383
  readonly encrypted?: boolean;
368
384
  readonly sensitive?: boolean;
385
+ readonly writeOnly?: boolean;
369
386
  readonly readAsInstruction?: boolean;
370
387
  readonly format?: "email" | "url" | "phone" | "password";
371
388
  readonly default?: string;
@@ -386,6 +403,7 @@ export declare const inboundMessageEntity: import("@cosmicdrift/kumiko-types/fie
386
403
  readonly filterable?: boolean;
387
404
  readonly encrypted?: boolean;
388
405
  readonly sensitive?: boolean;
406
+ readonly writeOnly?: boolean;
389
407
  readonly readAsInstruction?: boolean;
390
408
  readonly format?: "email" | "url" | "phone" | "password";
391
409
  readonly default?: string;
@@ -410,6 +428,7 @@ export declare const mailThreadEntity: import("@cosmicdrift/kumiko-types/fields"
410
428
  readonly filterable?: boolean;
411
429
  readonly encrypted?: boolean;
412
430
  readonly sensitive?: boolean;
431
+ readonly writeOnly?: boolean;
413
432
  readonly readAsInstruction?: boolean;
414
433
  readonly format?: "email" | "url" | "phone" | "password";
415
434
  readonly default?: string;
@@ -430,6 +449,7 @@ export declare const mailThreadEntity: import("@cosmicdrift/kumiko-types/fields"
430
449
  readonly filterable?: boolean;
431
450
  readonly encrypted?: boolean;
432
451
  readonly sensitive?: boolean;
452
+ readonly writeOnly?: boolean;
433
453
  readonly readAsInstruction?: boolean;
434
454
  readonly format?: "email" | "url" | "phone" | "password";
435
455
  readonly default?: string;
@@ -493,6 +513,7 @@ export declare const syncCursorEntity: import("@cosmicdrift/kumiko-types/fields"
493
513
  readonly filterable?: boolean;
494
514
  readonly encrypted?: boolean;
495
515
  readonly sensitive?: boolean;
516
+ readonly writeOnly?: boolean;
496
517
  readonly readAsInstruction?: boolean;
497
518
  readonly format?: "email" | "url" | "phone" | "password";
498
519
  readonly default?: string;
@@ -513,6 +534,7 @@ export declare const syncCursorEntity: import("@cosmicdrift/kumiko-types/fields"
513
534
  readonly filterable?: boolean;
514
535
  readonly encrypted?: boolean;
515
536
  readonly sensitive?: boolean;
537
+ readonly writeOnly?: boolean;
516
538
  readonly readAsInstruction?: boolean;
517
539
  readonly format?: "email" | "url" | "phone" | "password";
518
540
  readonly default?: string;
@@ -533,6 +555,7 @@ export declare const syncCursorEntity: import("@cosmicdrift/kumiko-types/fields"
533
555
  readonly filterable?: boolean;
534
556
  readonly encrypted?: boolean;
535
557
  readonly sensitive?: boolean;
558
+ readonly writeOnly?: boolean;
536
559
  readonly readAsInstruction?: boolean;
537
560
  readonly format?: "email" | "url" | "phone" | "password";
538
561
  readonly default?: string;
@@ -574,6 +597,7 @@ export declare const seenMessageEntity: import("@cosmicdrift/kumiko-types/fields
574
597
  readonly filterable?: boolean;
575
598
  readonly encrypted?: boolean;
576
599
  readonly sensitive?: boolean;
600
+ readonly writeOnly?: boolean;
577
601
  readonly readAsInstruction?: boolean;
578
602
  readonly format?: "email" | "url" | "phone" | "password";
579
603
  readonly default?: string;
@@ -594,6 +618,7 @@ export declare const seenMessageEntity: import("@cosmicdrift/kumiko-types/fields
594
618
  readonly filterable?: boolean;
595
619
  readonly encrypted?: boolean;
596
620
  readonly sensitive?: boolean;
621
+ readonly writeOnly?: boolean;
597
622
  readonly readAsInstruction?: boolean;
598
623
  readonly format?: "email" | "url" | "phone" | "password";
599
624
  readonly default?: string;
@@ -9,6 +9,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
9
9
  readonly filterable?: boolean;
10
10
  readonly encrypted?: boolean;
11
11
  readonly sensitive?: boolean;
12
+ readonly writeOnly?: boolean;
12
13
  readonly readAsInstruction?: boolean;
13
14
  readonly format?: "email" | "url" | "phone" | "password";
14
15
  readonly default?: string;
@@ -29,6 +30,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
29
30
  readonly filterable?: boolean;
30
31
  readonly encrypted?: boolean;
31
32
  readonly sensitive?: boolean;
33
+ readonly writeOnly?: boolean;
32
34
  readonly readAsInstruction?: boolean;
33
35
  readonly format?: "email" | "url" | "phone" | "password";
34
36
  readonly default?: string;
@@ -49,6 +51,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
49
51
  readonly filterable?: boolean;
50
52
  readonly encrypted?: boolean;
51
53
  readonly sensitive?: boolean;
54
+ readonly writeOnly?: boolean;
52
55
  readonly readAsInstruction?: boolean;
53
56
  readonly format?: "email" | "url" | "phone" | "password";
54
57
  readonly default?: string;
@@ -69,6 +72,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
69
72
  readonly filterable?: boolean;
70
73
  readonly encrypted?: boolean;
71
74
  readonly sensitive?: boolean;
75
+ readonly writeOnly?: boolean;
72
76
  readonly readAsInstruction?: boolean;
73
77
  readonly format?: "email" | "url" | "phone" | "password";
74
78
  readonly default?: string;
@@ -89,6 +93,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
89
93
  readonly filterable?: boolean;
90
94
  readonly encrypted?: boolean;
91
95
  readonly sensitive?: boolean;
96
+ readonly writeOnly?: boolean;
92
97
  readonly readAsInstruction?: boolean;
93
98
  readonly format?: "email" | "url" | "phone" | "password";
94
99
  readonly default?: string;
@@ -109,6 +114,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
109
114
  readonly filterable?: boolean;
110
115
  readonly encrypted?: boolean;
111
116
  readonly sensitive?: boolean;
117
+ readonly writeOnly?: boolean;
112
118
  readonly readAsInstruction?: boolean;
113
119
  readonly format?: "email" | "url" | "phone" | "password";
114
120
  readonly default?: string;
@@ -129,6 +135,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
129
135
  readonly filterable?: boolean;
130
136
  readonly encrypted?: boolean;
131
137
  readonly sensitive?: boolean;
138
+ readonly writeOnly?: boolean;
132
139
  readonly readAsInstruction?: boolean;
133
140
  readonly format?: "email" | "url" | "phone" | "password";
134
141
  readonly default?: string;
@@ -166,6 +173,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
166
173
  readonly filterable?: boolean;
167
174
  readonly encrypted?: boolean;
168
175
  readonly sensitive?: boolean;
176
+ readonly writeOnly?: boolean;
169
177
  readonly readAsInstruction?: boolean;
170
178
  readonly format?: "email" | "url" | "phone" | "password";
171
179
  readonly default?: string;
@@ -186,6 +194,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
186
194
  readonly filterable?: boolean;
187
195
  readonly encrypted?: boolean;
188
196
  readonly sensitive?: boolean;
197
+ readonly writeOnly?: boolean;
189
198
  readonly readAsInstruction?: boolean;
190
199
  readonly format?: "email" | "url" | "phone" | "password";
191
200
  readonly default?: string;
@@ -206,6 +215,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
206
215
  readonly filterable?: boolean;
207
216
  readonly encrypted?: boolean;
208
217
  readonly sensitive?: boolean;
218
+ readonly writeOnly?: boolean;
209
219
  readonly readAsInstruction?: boolean;
210
220
  readonly format?: "email" | "url" | "phone" | "password";
211
221
  readonly default?: string;
@@ -226,6 +236,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
226
236
  readonly filterable?: boolean;
227
237
  readonly encrypted?: boolean;
228
238
  readonly sensitive?: boolean;
239
+ readonly writeOnly?: boolean;
229
240
  readonly readAsInstruction?: boolean;
230
241
  readonly format?: "email" | "url" | "phone" | "password";
231
242
  readonly default?: string;
@@ -246,6 +257,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
246
257
  readonly filterable?: boolean;
247
258
  readonly encrypted?: boolean;
248
259
  readonly sensitive?: boolean;
260
+ readonly writeOnly?: boolean;
249
261
  readonly readAsInstruction?: boolean;
250
262
  readonly format?: "email" | "url" | "phone" | "password";
251
263
  readonly default?: string;
@@ -266,6 +278,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
266
278
  readonly filterable?: boolean;
267
279
  readonly encrypted?: boolean;
268
280
  readonly sensitive?: boolean;
281
+ readonly writeOnly?: boolean;
269
282
  readonly readAsInstruction?: boolean;
270
283
  readonly format?: "email" | "url" | "phone" | "password";
271
284
  readonly default?: string;
@@ -286,6 +299,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
286
299
  readonly filterable?: boolean;
287
300
  readonly encrypted?: boolean;
288
301
  readonly sensitive?: boolean;
302
+ readonly writeOnly?: boolean;
289
303
  readonly readAsInstruction?: boolean;
290
304
  readonly format?: "email" | "url" | "phone" | "password";
291
305
  readonly default?: string;
@@ -306,6 +320,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
306
320
  readonly filterable?: boolean;
307
321
  readonly encrypted?: boolean;
308
322
  readonly sensitive?: boolean;
323
+ readonly writeOnly?: boolean;
309
324
  readonly readAsInstruction?: boolean;
310
325
  readonly format?: "email" | "url" | "phone" | "password";
311
326
  readonly default?: string;
@@ -326,6 +341,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
326
341
  readonly filterable?: boolean;
327
342
  readonly encrypted?: boolean;
328
343
  readonly sensitive?: boolean;
344
+ readonly writeOnly?: boolean;
329
345
  readonly readAsInstruction?: boolean;
330
346
  readonly format?: "email" | "url" | "phone" | "password";
331
347
  readonly default?: string;
@@ -361,6 +377,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
361
377
  readonly filterable?: boolean;
362
378
  readonly encrypted?: boolean;
363
379
  readonly sensitive?: boolean;
380
+ readonly writeOnly?: boolean;
364
381
  readonly readAsInstruction?: boolean;
365
382
  readonly format?: "email" | "url" | "phone" | "password";
366
383
  readonly default?: string;
@@ -381,6 +398,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
381
398
  readonly filterable?: boolean;
382
399
  readonly encrypted?: boolean;
383
400
  readonly sensitive?: boolean;
401
+ readonly writeOnly?: boolean;
384
402
  readonly readAsInstruction?: boolean;
385
403
  readonly format?: "email" | "url" | "phone" | "password";
386
404
  readonly default?: string;
@@ -403,6 +421,7 @@ export declare const mailThreadsProjectionTable: import("@cosmicdrift/kumiko-fra
403
421
  readonly filterable?: boolean;
404
422
  readonly encrypted?: boolean;
405
423
  readonly sensitive?: boolean;
424
+ readonly writeOnly?: boolean;
406
425
  readonly readAsInstruction?: boolean;
407
426
  readonly format?: "email" | "url" | "phone" | "password";
408
427
  readonly default?: string;
@@ -423,6 +442,7 @@ export declare const mailThreadsProjectionTable: import("@cosmicdrift/kumiko-fra
423
442
  readonly filterable?: boolean;
424
443
  readonly encrypted?: boolean;
425
444
  readonly sensitive?: boolean;
445
+ readonly writeOnly?: boolean;
426
446
  readonly readAsInstruction?: boolean;
427
447
  readonly format?: "email" | "url" | "phone" | "password";
428
448
  readonly default?: string;