@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 tagEntity: 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 tagEntity: 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;
@@ -50,6 +52,7 @@ export declare const tagEntity: EntityDefinition<{
50
52
  readonly filterable?: boolean;
51
53
  readonly encrypted?: boolean;
52
54
  readonly sensitive?: boolean;
55
+ readonly writeOnly?: boolean;
53
56
  readonly readAsInstruction?: boolean;
54
57
  readonly format?: "email" | "url" | "phone" | "password";
55
58
  readonly default?: string;
@@ -72,6 +75,7 @@ export declare function createTagAssignmentEntity(access?: EntityDefinition["acc
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 createTagAssignmentEntity(access?: EntityDefinition["acc
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;
@@ -112,6 +117,7 @@ export declare function createTagAssignmentEntity(access?: EntityDefinition["acc
112
117
  readonly filterable?: boolean;
113
118
  readonly encrypted?: boolean;
114
119
  readonly sensitive?: boolean;
120
+ readonly writeOnly?: boolean;
115
121
  readonly readAsInstruction?: boolean;
116
122
  readonly format?: "email" | "url" | "phone" | "password";
117
123
  readonly default?: string;
@@ -134,6 +140,7 @@ export declare const tagAssignmentEntity: 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 tagAssignmentEntity: 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;
@@ -174,6 +182,7 @@ export declare const tagAssignmentEntity: EntityDefinition<{
174
182
  readonly filterable?: boolean;
175
183
  readonly encrypted?: boolean;
176
184
  readonly sensitive?: boolean;
185
+ readonly writeOnly?: boolean;
177
186
  readonly readAsInstruction?: boolean;
178
187
  readonly format?: "email" | "url" | "phone" | "password";
179
188
  readonly default?: string;
@@ -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 { tagAssignmentAggregateId } from "../aggregate-id.js";
4
4
  import { DEFAULT_TAG_ACCESS } from "../constants.js";
5
5
  import { tagAssignmentExecutor, tagExecutor } from "../executor.js";
@@ -33,15 +33,9 @@ export function createAssignTagHandler(access = DEFAULT_TAG_ACCESS) {
33
33
  description: "Attaches an existing catalog tag to one host entity addressed by its type and id, reporting success when the tag was already attached; use it to tag a record, not to create the tag.",
34
34
  handler: async (event, ctx) => {
35
35
  const payload = event.payload; // @cast-boundary engine-payload
36
- // entityType/entityId are client input: the caller must be able to see
37
- // the host row through that entity's own read path (tenant scope plus its
38
- // `access.read` ownership) before its assignment row may be written.
39
- // Checked FIRST, ahead of every lookup below, so a denied caller can't tell
40
- // an invisible parent apart from a missing assignment or an unknown tag —
41
- // every path answers with the same NotFoundError.
42
- if (!(await joinRowParentIsVisible(ctx.registry, "tag-assignment", payload, event.user, ctx.db))) {
43
- return writeFailure(new NotFoundError(payload.entityType, payload.entityId));
44
- }
36
+ const denied = await denyUnlessJoinRowParentVisible(ctx.registry, "tag-assignment", payload, event.user, ctx.db);
37
+ if (denied)
38
+ return denied;
45
39
  const id = tagAssignmentAggregateId(event.user.tenantId, payload.tagId, payload.entityType, payload.entityId);
46
40
  const existing = await tagAssignmentExecutor.detail({ id }, event.user, ctx.db);
47
41
  if (existing) {
@@ -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 { tagAssignmentAggregateId } from "../aggregate-id.js";
4
3
  import { DEFAULT_TAG_ACCESS } from "../constants.js";
5
4
  import { tagAssignmentExecutor } from "../executor.js";
@@ -19,15 +18,9 @@ export function createRemoveTagHandler(access = DEFAULT_TAG_ACCESS) {
19
18
  description: "Detaches one catalog tag from one host entity, reporting success when it was not attached; use it to untag a single record while the tag itself stays in the catalog.",
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 tag —
27
- // every path answers with the same NotFoundError.
28
- if (!(await joinRowParentIsVisible(ctx.registry, "tag-assignment", payload, event.user, ctx.db))) {
29
- return writeFailure(new NotFoundError(payload.entityType, payload.entityId));
30
- }
21
+ const denied = await denyUnlessJoinRowParentVisible(ctx.registry, "tag-assignment", payload, event.user, ctx.db);
22
+ if (denied)
23
+ return denied;
31
24
  const id = tagAssignmentAggregateId(event.user.tenantId, payload.tagId, payload.entityType, payload.entityId);
32
25
  const existing = await tagAssignmentExecutor.detail({ id }, event.user, ctx.db);
33
26
  if (!existing) {
@@ -1,5 +1,6 @@
1
1
  import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
2
2
  import type { SessionUser, TenantId } from "@cosmicdrift/kumiko-framework/engine";
3
+ import type { Temporal } from "temporal-polyfill";
3
4
  import type { ContentFormat, TemplateKind } from "./constants.js";
4
5
  export type TemplateResource = {
5
6
  readonly id: string;
@@ -17,7 +18,7 @@ export type TemplateResource = {
17
18
  readonly scope: "system" | "tenant";
18
19
  readonly parentTemplateId: string | null;
19
20
  readonly status: "draft" | "active" | "archived";
20
- readonly updatedAt: Date;
21
+ readonly modifiedAt: Temporal.Instant | null;
21
22
  };
22
23
  export type ResolveRequest = {
23
24
  readonly tenantId: TenantId;
@@ -70,7 +70,7 @@ function toPublic(row) {
70
70
  scope,
71
71
  parentTemplateId: row.parentTemplateId,
72
72
  status,
73
- updatedAt: row.updatedAt,
73
+ modifiedAt: row.modifiedAt,
74
74
  };
75
75
  }
76
76
  function parseJson(raw) {
@@ -10,5 +10,5 @@ export declare const bySlugQuery: import("@cosmicdrift/kumiko-types/define-handl
10
10
  content: string | null;
11
11
  contentFormat: string;
12
12
  folder: string | null;
13
- updatedAt: Date;
13
+ modifiedAt: import("temporal-spec").Temporal.Instant | null;
14
14
  } | null, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
@@ -24,7 +24,7 @@ export const bySlugQuery = defineQueryHandler({
24
24
  tenantIdOverride: z.string().min(1).optional(),
25
25
  }),
26
26
  access: { roles: ["anonymous", "User", "TenantAdmin", "SystemAdmin"] },
27
- rateLimit: { per: "ip", limit: 60, windowSeconds: 60 },
27
+ rateLimit: { per: "ip+handler", limit: 60, windowSeconds: 60 },
28
28
  description: "Reads one text-block of a tenant by slug and locale together with its body and format; it is pinned to the text-block kind so mail templates and AI prompts in the same table stay unreachable through this anonymous-capable path.",
29
29
  handler: async (query, ctx) => {
30
30
  const override = query.payload.tenantIdOverride;
@@ -47,7 +47,7 @@ export const bySlugQuery = defineQueryHandler({
47
47
  content: row.content,
48
48
  contentFormat: row.contentFormat,
49
49
  folder: row.folder,
50
- updatedAt: row.updatedAt,
50
+ modifiedAt: row.modifiedAt,
51
51
  };
52
52
  },
53
53
  });
@@ -1,3 +1,4 @@
1
+ import type { Temporal } from "temporal-polyfill";
1
2
  import * as z from "zod";
2
3
  export type TextBlockSummary = {
3
4
  readonly slug: string;
@@ -5,7 +6,7 @@ export type TextBlockSummary = {
5
6
  readonly title: string | null;
6
7
  readonly content: string | null;
7
8
  readonly folder: string | null;
8
- readonly updatedAt: Date;
9
+ readonly modifiedAt: Temporal.Instant | null;
9
10
  };
10
11
  export declare const byTenantQuery: import("@cosmicdrift/kumiko-types/define-handler").QueryHandlerDefinition<"by-tenant", z.ZodObject<{
11
12
  tenantIdOverride: z.ZodOptional<z.ZodString>;
@@ -16,6 +17,6 @@ export declare const byTenantQuery: import("@cosmicdrift/kumiko-types/define-han
16
17
  title: string | null;
17
18
  content: string | null;
18
19
  folder: string | null;
19
- updatedAt: Date;
20
+ modifiedAt: Temporal.Instant | null;
20
21
  }[];
21
22
  }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
@@ -11,7 +11,7 @@ export const byTenantQuery = defineQueryHandler({
11
11
  tenantIdOverride: z.string().min(1).optional(),
12
12
  }),
13
13
  access: { roles: ["anonymous", "User", "TenantAdmin", "SystemAdmin"] },
14
- rateLimit: { per: "ip", limit: 60, windowSeconds: 60 },
14
+ rateLimit: { per: "ip+handler", limit: 60, windowSeconds: 60 },
15
15
  description: "Lists every text-block of a tenant with slug, locale, title and body so a public content tree can be rendered in one call; use it for the whole sidebar, and by-slug when only one block is needed.",
16
16
  handler: async (query, ctx) => {
17
17
  const override = query.payload.tenantIdOverride;
@@ -27,7 +27,7 @@ export const byTenantQuery = defineQueryHandler({
27
27
  title: row.title,
28
28
  content: row.content,
29
29
  folder: row.folder,
30
- updatedAt: row.updatedAt,
30
+ modifiedAt: row.modifiedAt,
31
31
  })),
32
32
  };
33
33
  },
@@ -11,5 +11,5 @@ export declare function makeCollectionItemQuery(collection: ContentCollectionDef
11
11
  content: string | null;
12
12
  contentFormat: string;
13
13
  folder: string | null;
14
- updatedAt: Date;
14
+ modifiedAt: import("temporal-spec").Temporal.Instant | null;
15
15
  } | null, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
@@ -10,6 +10,6 @@ export declare function makeCollectionListQuery(collection: ContentCollectionDef
10
10
  content: string | null;
11
11
  contentFormat: string;
12
12
  folder: string | null;
13
- updatedAt: Date;
13
+ modifiedAt: import("temporal-spec").Temporal.Instant | null;
14
14
  }[];
15
15
  }, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
@@ -1,5 +1,6 @@
1
1
  import type { EventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
2
2
  import type { AccessRule, ContentCollectionDefinition, SessionUser, TenantId } from "@cosmicdrift/kumiko-framework/engine";
3
+ import type { Temporal } from "temporal-polyfill";
3
4
  import { templateResourcesTable } from "../table.js";
4
5
  import { userContentEntriesTable } from "../user-content-table.js";
5
6
  export declare const DEFAULT_COLLECTION_ACCESS: AccessRule;
@@ -12,7 +13,7 @@ export type CollectionEntryRow = {
12
13
  readonly content: string | null;
13
14
  readonly contentFormat: string;
14
15
  readonly folder: string | null;
15
- readonly updatedAt: Date;
16
+ readonly modifiedAt: Temporal.Instant | null;
16
17
  };
17
18
  export type CollectionStore = {
18
19
  readonly table: typeof templateResourcesTable | typeof userContentEntriesTable;
@@ -30,5 +31,5 @@ export declare function toCollectionEntry(row: CollectionEntryRow): {
30
31
  content: string | null;
31
32
  contentFormat: string;
32
33
  folder: string | null;
33
- updatedAt: Date;
34
+ modifiedAt: Temporal.Instant | null;
34
35
  };
@@ -45,6 +45,6 @@ export function toCollectionEntry(row) {
45
45
  content: row.content,
46
46
  contentFormat: row.contentFormat,
47
47
  folder: row.folder,
48
- updatedAt: row.updatedAt,
48
+ modifiedAt: row.modifiedAt,
49
49
  };
50
50
  }
@@ -15,5 +15,5 @@ export declare const findByIdQuery: import("@cosmicdrift/kumiko-types/define-han
15
15
  scope: string;
16
16
  parentTemplateId: string | null;
17
17
  status: string;
18
- updatedAt: Date;
18
+ modifiedAt: import("temporal-spec").Temporal.Instant | null;
19
19
  } | null, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
@@ -37,7 +37,7 @@ export const findByIdQuery = defineQueryHandler({
37
37
  scope: row.scope,
38
38
  parentTemplateId: row.parentTemplateId,
39
39
  status: row.status,
40
- updatedAt: row.updatedAt,
40
+ modifiedAt: row.modifiedAt,
41
41
  };
42
42
  },
43
43
  });
@@ -22,5 +22,5 @@ export declare const listQuery: import("@cosmicdrift/kumiko-types/define-handler
22
22
  scope: string;
23
23
  status: string;
24
24
  contentFormat: string;
25
- updatedAt: Date;
25
+ modifiedAt: import("temporal-spec").Temporal.Instant | null;
26
26
  }[], import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
@@ -48,7 +48,7 @@ export const listQuery = defineQueryHandler({
48
48
  scope: row.scope,
49
49
  status: row.status,
50
50
  contentFormat: row.contentFormat,
51
- updatedAt: row.updatedAt,
51
+ modifiedAt: row.modifiedAt,
52
52
  }));
53
53
  },
54
54
  });
@@ -64,6 +64,13 @@ export async function seedSystemTemplate(db, opts) {
64
64
  parentTemplateId,
65
65
  status: "active",
66
66
  };
67
+ const applyUpdate = async (row) => {
68
+ const result = await executor.update({ id: row.id, version: row.version, changes: rowFields }, by, tdb);
69
+ if (!result.isSuccess) {
70
+ throw new Error(`seedSystemTemplate update failed: ${JSON.stringify(result)}`);
71
+ }
72
+ return { id: String(row.id) };
73
+ };
67
74
  return runEventStoreSeed({
68
75
  existing,
69
76
  ifExists: opts.ifExists,
@@ -83,11 +90,13 @@ export async function seedSystemTemplate(db, opts) {
83
90
  if (resolved == null) {
84
91
  throw new Error(`seedSystemTemplate create unique_violation but row missing`);
85
92
  }
86
- const upd = await executor.update({ id: resolved.id, version: resolved.version, changes: rowFields }, by, tdb);
87
- if (!upd.isSuccess) {
88
- throw new Error(`seedSystemTemplate race-update failed: ${JSON.stringify(upd)}`);
89
- }
90
- return { id: resolved.id };
93
+ // Race loser goes through the same skip/update contract as a normal re-seed.
94
+ return runEventStoreSeed({
95
+ existing: resolved,
96
+ ifExists: opts.ifExists,
97
+ create: () => Promise.reject(new Error("seedSystemTemplate: unreachable create")),
98
+ update: applyUpdate,
99
+ });
91
100
  }
92
101
  throw new Error(`seedSystemTemplate create failed: ${JSON.stringify(result)}`);
93
102
  }
@@ -97,13 +106,7 @@ export async function seedSystemTemplate(db, opts) {
97
106
  }
98
107
  return { id: String(data.id) };
99
108
  },
100
- update: async (row) => {
101
- const result = await executor.update({ id: row.id, version: row.version, changes: rowFields }, by, tdb);
102
- if (!result.isSuccess) {
103
- throw new Error(`seedSystemTemplate update failed: ${JSON.stringify(result)}`);
104
- }
105
- return { id: String(row.id) };
106
- },
109
+ update: applyUpdate,
107
110
  });
108
111
  }
109
112
  // Boot/test seed for kind=text-block. Same projection path as set.write,
@@ -132,6 +135,24 @@ export async function seedTextBlock(db, opts) {
132
135
  parentTemplateId: null,
133
136
  status: "active",
134
137
  };
138
+ const applyUpdate = async (row, current) => {
139
+ // Skip no-op updates so a legal re-seed on every pod boot does not bump
140
+ // version/modifiedAt (ETag, "last changed", event-store growth).
141
+ if (current?.title === fields.title &&
142
+ current?.content === fields.content &&
143
+ current?.folder === fields.folder) {
144
+ return { id: String(row.id) };
145
+ }
146
+ const result = await executor.update({
147
+ id: row.id,
148
+ version: row.version,
149
+ changes: { title: fields.title, content: fields.content, folder: fields.folder },
150
+ }, by, tdb);
151
+ if (!result.isSuccess) {
152
+ throw new Error(`seedTextBlock update failed: ${JSON.stringify(result)}`);
153
+ }
154
+ return { id: String(row.id) };
155
+ };
135
156
  return runEventStoreSeed({
136
157
  existing,
137
158
  ifExists: opts.ifExists,
@@ -149,15 +170,13 @@ export async function seedTextBlock(db, opts) {
149
170
  if (resolved == null) {
150
171
  throw new Error("seedTextBlock create unique_violation but row missing");
151
172
  }
152
- const upd = await executor.update({
153
- id: resolved.id,
154
- version: resolved.version,
155
- changes: { title: fields.title, content: fields.content, folder: fields.folder },
156
- }, by, tdb);
157
- if (!upd.isSuccess) {
158
- throw new Error(`seedTextBlock race-update failed: ${JSON.stringify(upd)}`);
159
- }
160
- return { id: resolved.id };
173
+ // Race loser goes through the same skip/no-op/update contract as a normal re-seed.
174
+ return runEventStoreSeed({
175
+ existing: resolved,
176
+ ifExists: opts.ifExists,
177
+ create: () => Promise.reject(new Error("seedTextBlock: unreachable create")),
178
+ update: (row) => applyUpdate(row, again),
179
+ });
161
180
  }
162
181
  throw new Error(`seedTextBlock create failed: ${JSON.stringify(result)}`);
163
182
  }
@@ -169,24 +188,7 @@ export async function seedTextBlock(db, opts) {
169
188
  }
170
189
  return { id: String(data.id) };
171
190
  },
172
- update: async (row) => {
173
- // Skip no-op updates so a legal re-seed on every pod boot does not bump
174
- // version/updatedAt (ETag, "last changed", event-store growth).
175
- if (existingRow?.title === fields.title &&
176
- existingRow?.content === fields.content &&
177
- existingRow?.folder === fields.folder) {
178
- return { id: String(row.id) };
179
- }
180
- const result = await executor.update({
181
- id: row.id,
182
- version: row.version,
183
- changes: { title: fields.title, content: fields.content, folder: fields.folder },
184
- }, by, tdb);
185
- if (!result.isSuccess) {
186
- throw new Error(`seedTextBlock update failed: ${JSON.stringify(result)}`);
187
- }
188
- return { id: String(row.id) };
189
- },
191
+ update: (row) => applyUpdate(row, existingRow),
190
192
  });
191
193
  }
192
194
  // Boot seed for legal/marketing copy from a JSON template. `ifExists: "update"`
@@ -1,3 +1,4 @@
1
+ import type { Temporal } from "temporal-polyfill";
1
2
  export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
2
3
  slug: {
3
4
  readonly type: "text";
@@ -9,6 +10,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
9
10
  readonly filterable?: boolean;
10
11
  readonly encrypted?: boolean;
11
12
  readonly sensitive?: boolean;
13
+ readonly writeOnly?: boolean;
12
14
  readonly readAsInstruction?: boolean;
13
15
  readonly format?: "email" | "url" | "phone" | "password";
14
16
  readonly default?: string;
@@ -39,7 +41,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
39
41
  readonly "text-block"?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
40
42
  } | undefined;
41
43
  readonly optionsQuery?: string;
42
- readonly optionsQueryPayload?: Readonly<Record<string, string | number | boolean>>;
44
+ readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
43
45
  } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
44
46
  required: true;
45
47
  };
@@ -53,6 +55,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
53
55
  readonly filterable?: boolean;
54
56
  readonly encrypted?: boolean;
55
57
  readonly sensitive?: boolean;
58
+ readonly writeOnly?: boolean;
56
59
  readonly readAsInstruction?: boolean;
57
60
  readonly format?: "email" | "url" | "phone" | "password";
58
61
  readonly default?: string;
@@ -73,6 +76,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
73
76
  readonly filterable?: boolean;
74
77
  readonly encrypted?: boolean;
75
78
  readonly sensitive?: boolean;
79
+ readonly writeOnly?: boolean;
76
80
  readonly readAsInstruction?: boolean;
77
81
  readonly format?: "email" | "url" | "phone" | "password";
78
82
  readonly default?: string;
@@ -93,6 +97,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
93
97
  readonly filterable?: boolean;
94
98
  readonly encrypted?: boolean;
95
99
  readonly sensitive?: boolean;
100
+ readonly writeOnly?: boolean;
96
101
  readonly readAsInstruction?: boolean;
97
102
  readonly format?: "email" | "url" | "phone" | "password";
98
103
  readonly default?: string;
@@ -137,7 +142,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
137
142
  readonly plain?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
138
143
  } | undefined;
139
144
  readonly optionsQuery?: string;
140
- readonly optionsQueryPayload?: Readonly<Record<string, string | number | boolean>>;
145
+ readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
141
146
  } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
142
147
  required: true;
143
148
  };
@@ -189,7 +194,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
189
194
  readonly tenant?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
190
195
  } | undefined;
191
196
  readonly optionsQuery?: string;
192
- readonly optionsQueryPayload?: Readonly<Record<string, string | number | boolean>>;
197
+ readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
193
198
  } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
194
199
  required: true;
195
200
  };
@@ -203,6 +208,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
203
208
  readonly filterable?: boolean;
204
209
  readonly encrypted?: boolean;
205
210
  readonly sensitive?: boolean;
211
+ readonly writeOnly?: boolean;
206
212
  readonly readAsInstruction?: boolean;
207
213
  readonly format?: "email" | "url" | "phone" | "password";
208
214
  readonly default?: string;
@@ -230,7 +236,7 @@ export declare const templateResourceEntity: import("@cosmicdrift/kumiko-types/f
230
236
  readonly draft?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
231
237
  } | undefined;
232
238
  readonly optionsQuery?: string;
233
- readonly optionsQueryPayload?: Readonly<Record<string, string | number | boolean>>;
239
+ readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
234
240
  } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
235
241
  required: true;
236
242
  };
@@ -246,6 +252,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
246
252
  readonly filterable?: boolean;
247
253
  readonly encrypted?: boolean;
248
254
  readonly sensitive?: boolean;
255
+ readonly writeOnly?: boolean;
249
256
  readonly readAsInstruction?: boolean;
250
257
  readonly format?: "email" | "url" | "phone" | "password";
251
258
  readonly default?: string;
@@ -276,7 +283,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
276
283
  readonly "text-block"?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
277
284
  } | undefined;
278
285
  readonly optionsQuery?: string;
279
- readonly optionsQueryPayload?: Readonly<Record<string, string | number | boolean>>;
286
+ readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
280
287
  } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
281
288
  required: true;
282
289
  };
@@ -290,6 +297,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
290
297
  readonly filterable?: boolean;
291
298
  readonly encrypted?: boolean;
292
299
  readonly sensitive?: boolean;
300
+ readonly writeOnly?: boolean;
293
301
  readonly readAsInstruction?: boolean;
294
302
  readonly format?: "email" | "url" | "phone" | "password";
295
303
  readonly default?: string;
@@ -310,6 +318,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
310
318
  readonly filterable?: boolean;
311
319
  readonly encrypted?: boolean;
312
320
  readonly sensitive?: boolean;
321
+ readonly writeOnly?: boolean;
313
322
  readonly readAsInstruction?: boolean;
314
323
  readonly format?: "email" | "url" | "phone" | "password";
315
324
  readonly default?: string;
@@ -330,6 +339,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
330
339
  readonly filterable?: boolean;
331
340
  readonly encrypted?: boolean;
332
341
  readonly sensitive?: boolean;
342
+ readonly writeOnly?: boolean;
333
343
  readonly readAsInstruction?: boolean;
334
344
  readonly format?: "email" | "url" | "phone" | "password";
335
345
  readonly default?: string;
@@ -374,7 +384,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
374
384
  readonly plain?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
375
385
  } | undefined;
376
386
  readonly optionsQuery?: string;
377
- readonly optionsQueryPayload?: Readonly<Record<string, string | number | boolean>>;
387
+ readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
378
388
  } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
379
389
  required: true;
380
390
  };
@@ -426,7 +436,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
426
436
  readonly tenant?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
427
437
  } | undefined;
428
438
  readonly optionsQuery?: string;
429
- readonly optionsQueryPayload?: Readonly<Record<string, string | number | boolean>>;
439
+ readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
430
440
  } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
431
441
  required: true;
432
442
  };
@@ -440,6 +450,7 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
440
450
  readonly filterable?: boolean;
441
451
  readonly encrypted?: boolean;
442
452
  readonly sensitive?: boolean;
453
+ readonly writeOnly?: boolean;
443
454
  readonly readAsInstruction?: boolean;
444
455
  readonly format?: "email" | "url" | "phone" | "password";
445
456
  readonly default?: string;
@@ -467,11 +478,17 @@ export declare const templateResourcesTable: import("@cosmicdrift/kumiko-framewo
467
478
  readonly draft?: import("@cosmicdrift/kumiko-types/fields").SelectOptionTone | undefined;
468
479
  } | undefined;
469
480
  readonly optionsQuery?: string;
470
- readonly optionsQueryPayload?: Readonly<Record<string, string | number | boolean>>;
481
+ readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
471
482
  } & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
472
483
  required: true;
473
484
  };
474
485
  }, "tenant">>;
486
+ export type EntityAuditColumns = {
487
+ readonly insertedAt: Temporal.Instant;
488
+ readonly modifiedAt: Temporal.Instant | null;
489
+ readonly insertedById: string | null;
490
+ readonly modifiedById: string | null;
491
+ };
475
492
  export type TemplateResourceRow = {
476
493
  readonly id: string | number;
477
494
  readonly version: number;
@@ -488,8 +505,4 @@ export type TemplateResourceRow = {
488
505
  readonly scope: string;
489
506
  readonly parentTemplateId: string | null;
490
507
  readonly status: string;
491
- readonly createdAt: Date;
492
- readonly updatedAt: Date;
493
- readonly createdBy: string;
494
- readonly updatedBy: string;
495
- };
508
+ } & EntityAuditColumns;
@@ -24,8 +24,8 @@ async function seedTemplate(db, args) {
24
24
  variableSchema: JSON.stringify(args.variableSchema ?? {}),
25
25
  linkedResources: JSON.stringify(args.linkedResources ?? {}),
26
26
  parentTemplateId: args.parentTemplateId ?? null,
27
- createdBy: "conformance",
28
- updatedBy: "conformance",
27
+ insertedById: "conformance",
28
+ modifiedById: "conformance",
29
29
  });
30
30
  }
31
31
  export async function assertConsumerHandlesNotFound(consumer, opts) {