@cosmicdrift/kumiko-bundled-features 0.13.0 → 0.15.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 (268) hide show
  1. package/package.json +6 -6
  2. package/src/__tests__/env-schemas.test.ts +1 -1
  3. package/src/__tests__/es-ops-e2e.integration.ts +10 -9
  4. package/src/audit/__tests__/audit.integration.ts +3 -3
  5. package/src/audit/handlers/list.query.ts +39 -51
  6. package/src/auth-email-password/__tests__/account-lockout-no-redis.integration.ts +4 -3
  7. package/src/auth-email-password/__tests__/account-lockout.integration.ts +4 -3
  8. package/src/auth-email-password/__tests__/auth-claims.integration.ts +5 -4
  9. package/src/auth-email-password/__tests__/auth.integration.ts +4 -3
  10. package/src/auth-email-password/__tests__/confirm-token-flow.test.ts +1 -1
  11. package/src/auth-email-password/__tests__/email-templates.test.ts +1 -1
  12. package/src/auth-email-password/__tests__/email-verification.integration.ts +7 -10
  13. package/src/auth-email-password/__tests__/identity-v3-hash.test.ts +1 -1
  14. package/src/auth-email-password/__tests__/identity-v3-login.integration.ts +4 -3
  15. package/src/auth-email-password/__tests__/invite-flow.integration.ts +16 -43
  16. package/src/auth-email-password/__tests__/multi-roles.integration.ts +6 -9
  17. package/src/auth-email-password/__tests__/password-reset.integration.ts +8 -7
  18. package/src/auth-email-password/__tests__/public-routes-rate-limit.integration.ts +4 -3
  19. package/src/auth-email-password/__tests__/seed-admin.integration.ts +19 -32
  20. package/src/auth-email-password/__tests__/session-callbacks.integration.ts +6 -5
  21. package/src/auth-email-password/__tests__/session-strict-mode.integration.ts +1 -1
  22. package/src/auth-email-password/__tests__/signed-token.test.ts +1 -1
  23. package/src/auth-email-password/__tests__/signup-flow.integration.ts +11 -15
  24. package/src/auth-email-password/handlers/invite-accept-with-login.write.ts +26 -26
  25. package/src/auth-email-password/handlers/invite-accept.write.ts +24 -21
  26. package/src/auth-email-password/handlers/invite-create.write.ts +3 -8
  27. package/src/auth-email-password/handlers/invite-signup-complete.write.ts +20 -17
  28. package/src/auth-email-password/handlers/signup-confirm.write.ts +3 -7
  29. package/src/auth-email-password/seeding.ts +1 -1
  30. package/src/auth-email-password/web/__tests__/auth-gate.test.tsx +1 -2
  31. package/src/auth-email-password/web/__tests__/forgot-password-screen.test.tsx +10 -19
  32. package/src/auth-email-password/web/__tests__/login-screen.test.tsx +12 -18
  33. package/src/auth-email-password/web/__tests__/reset-password-screen.test.tsx +12 -17
  34. package/src/auth-email-password/web/__tests__/session-roles.test.ts +1 -1
  35. package/src/auth-email-password/web/__tests__/tenant-switcher.test.tsx +1 -8
  36. package/src/auth-email-password/web/__tests__/test-utils.tsx +4 -8
  37. package/src/auth-email-password/web/__tests__/user-menu.test.tsx +2 -8
  38. package/src/auth-email-password/web/__tests__/verify-email-screen.test.tsx +10 -15
  39. package/src/billing-foundation/__tests__/billing-foundation.integration.ts +1 -1
  40. package/src/billing-foundation/__tests__/feature.test.ts +1 -1
  41. package/src/billing-foundation/__tests__/webhook-handler.test.ts +6 -5
  42. package/src/billing-foundation/db/queries/subscription-projection.ts +15 -0
  43. package/src/billing-foundation/get-subscription-for-tenant.ts +2 -6
  44. package/src/billing-foundation/handlers/create-portal-session.write.ts +2 -2
  45. package/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -1
  46. package/src/billing-foundation/projection.ts +32 -13
  47. package/src/cap-counter/__tests__/cap-counter.integration.ts +1 -1
  48. package/src/cap-counter/__tests__/enforce-cap.test.ts +37 -32
  49. package/src/cap-counter/__tests__/with-cap-enforcement.integration.ts +1 -1
  50. package/src/cap-counter/enforce-cap.ts +14 -20
  51. package/src/cap-counter/handlers/get-counter.query.ts +7 -13
  52. package/src/cap-counter/handlers/increment.write.ts +2 -2
  53. package/src/cap-counter/handlers/mark-soft-warned.write.ts +2 -2
  54. package/src/channel-in-app/handlers/inbox.query.ts +7 -13
  55. package/src/channel-in-app/handlers/mark-all-read.write.ts +7 -9
  56. package/src/channel-in-app/handlers/mark-read.write.ts +8 -14
  57. package/src/channel-in-app/handlers/unread-count.query.ts +10 -9
  58. package/src/channel-in-app/in-app-channel.ts +10 -12
  59. package/src/channel-in-app/tables.ts +1 -1
  60. package/src/compliance-profiles/__tests__/compliance-profiles.integration.ts +1 -1
  61. package/src/compliance-profiles/__tests__/seeding.integration.ts +1 -1
  62. package/src/compliance-profiles/handlers/for-tenant.query.ts +4 -7
  63. package/src/compliance-profiles/handlers/needs-profile.query.ts +4 -7
  64. package/src/compliance-profiles/handlers/set-profile.write.ts +5 -7
  65. package/src/compliance-profiles/resolve-for-tenant.ts +5 -7
  66. package/src/compliance-profiles/schema/profile-selection.ts +2 -2
  67. package/src/compliance-profiles/seeding.ts +4 -7
  68. package/src/config/__tests__/app-overrides.test.ts +1 -1
  69. package/src/config/__tests__/cascade.integration.ts +1 -1
  70. package/src/config/__tests__/config.integration.ts +8 -27
  71. package/src/config/db/queries/resolver.ts +47 -0
  72. package/src/config/handlers/__tests__/prepare-config-write.test.ts +1 -1
  73. package/src/config/resolver.ts +14 -62
  74. package/src/config/table.ts +4 -4
  75. package/src/config/write-helpers.ts +7 -11
  76. package/src/custom-fields/__tests__/audit-integration.integration.ts +6 -6
  77. package/src/custom-fields/__tests__/custom-fields.integration.ts +7 -7
  78. package/src/custom-fields/__tests__/feature.test.ts +1 -1
  79. package/src/custom-fields/__tests__/field-access.integration.ts +6 -6
  80. package/src/custom-fields/__tests__/quota.integration.ts +6 -6
  81. package/src/custom-fields/__tests__/retention.integration.ts +12 -10
  82. package/src/custom-fields/__tests__/user-data-rights.integration.ts +27 -17
  83. package/src/custom-fields/__tests__/wire-for-entity.test.ts +5 -5
  84. package/src/custom-fields/db/queries/field-access.ts +16 -0
  85. package/src/custom-fields/db/queries/projection.ts +43 -0
  86. package/src/custom-fields/db/queries/quota.ts +14 -0
  87. package/src/custom-fields/db/queries/retention.ts +39 -0
  88. package/src/custom-fields/db/queries/user-data-rights.ts +54 -0
  89. package/src/custom-fields/lib/field-access.ts +2 -41
  90. package/src/custom-fields/lib/quota.ts +2 -25
  91. package/src/custom-fields/run-retention.ts +19 -21
  92. package/src/custom-fields/wire-for-entity.ts +30 -23
  93. package/src/custom-fields/wire-user-data-rights.ts +33 -85
  94. package/src/data-retention/__tests__/data-retention.integration.ts +1 -1
  95. package/src/data-retention/__tests__/keep-for.test.ts +1 -1
  96. package/src/data-retention/__tests__/override-schema.test.ts +1 -1
  97. package/src/data-retention/__tests__/policy-for.integration.ts +1 -1
  98. package/src/data-retention/__tests__/resolver.test.ts +1 -1
  99. package/src/data-retention/handlers/policy-for.query.ts +5 -8
  100. package/src/data-retention/resolve-for-tenant.ts +6 -8
  101. package/src/data-retention/schema/tenant-retention-override.ts +2 -2
  102. package/src/delivery/__tests__/delivery-events.integration.ts +8 -21
  103. package/src/delivery/__tests__/delivery.integration.ts +100 -190
  104. package/src/delivery/db/queries/preferences.ts +30 -0
  105. package/src/delivery/delivery-service.ts +8 -36
  106. package/src/delivery/feature.ts +2 -1
  107. package/src/delivery/handlers/log.query.ts +5 -7
  108. package/src/delivery/handlers/preferences.query.ts +2 -5
  109. package/src/delivery/tables.ts +26 -1
  110. package/src/delivery/upsert-preference.ts +8 -14
  111. package/src/feature-toggles/__tests__/feature-toggles.integration.ts +30 -30
  112. package/src/feature-toggles/__tests__/registered-system-tenant.test.ts +7 -6
  113. package/src/feature-toggles/db/queries/toggle-state.ts +25 -0
  114. package/src/feature-toggles/feature.ts +16 -2
  115. package/src/feature-toggles/global-feature-state-table.ts +1 -1
  116. package/src/feature-toggles/handlers/list.query.ts +9 -2
  117. package/src/feature-toggles/handlers/registered.query.ts +3 -7
  118. package/src/feature-toggles/handlers/set.write.ts +37 -25
  119. package/src/feature-toggles/toggle-runtime.ts +3 -6
  120. package/src/file-foundation/__tests__/feature.test.ts +1 -1
  121. package/src/file-foundation/__tests__/file-foundation.integration.ts +1 -1
  122. package/src/file-provider-inmemory/__tests__/feature.test.ts +1 -1
  123. package/src/file-provider-s3/__tests__/feature.test.ts +1 -1
  124. package/src/files/__tests__/files.integration.ts +18 -7
  125. package/src/files/schema/file-ref.ts +1 -1
  126. package/src/files-provider-s3/__tests__/env-helper.test.ts +1 -1
  127. package/src/files-provider-s3/__tests__/s3-provider.integration.ts +1 -1
  128. package/src/files-provider-s3/__tests__/s3-provider.test.ts +1 -1
  129. package/src/jobs/__tests__/job-system-user.integration.ts +1 -1
  130. package/src/jobs/__tests__/jobs-events.integration.ts +8 -21
  131. package/src/jobs/__tests__/jobs-feature.integration.ts +1 -1
  132. package/src/jobs/feature.ts +22 -14
  133. package/src/jobs/handlers/detail.query.ts +10 -8
  134. package/src/jobs/handlers/list.query.ts +9 -21
  135. package/src/jobs/handlers/retry.write.ts +2 -7
  136. package/src/jobs/job-run-logger.ts +3 -9
  137. package/src/jobs/job-run-table.ts +49 -17
  138. package/src/legal-pages/__tests__/legal-pages.integration.ts +1 -1
  139. package/src/mail-foundation/__tests__/feature.test.ts +1 -1
  140. package/src/mail-foundation/__tests__/mail-foundation.integration.ts +1 -1
  141. package/src/mail-transport-inmemory/__tests__/feature.test.ts +1 -1
  142. package/src/mail-transport-smtp/__tests__/feature.test.ts +1 -1
  143. package/src/rate-limiting/__tests__/rate-limiting.integration.ts +1 -1
  144. package/src/renderer-foundation/__tests__/api.test.ts +2 -2
  145. package/src/renderer-foundation/__tests__/collect-plugins.integration.ts +1 -1
  146. package/src/renderer-simple/__tests__/adapter.test.ts +2 -2
  147. package/src/renderer-simple/__tests__/simple-renderer.test.ts +1 -1
  148. package/src/secrets/__tests__/require-secrets-context.test.ts +6 -5
  149. package/src/secrets/__tests__/rotate.integration.ts +6 -9
  150. package/src/secrets/__tests__/secrets-events.integration.ts +6 -12
  151. package/src/secrets/__tests__/secrets.integration.ts +6 -11
  152. package/src/secrets/db/queries/read.ts +16 -0
  153. package/src/secrets/handlers/list.query.ts +16 -17
  154. package/src/secrets/handlers/rotate.job.ts +8 -12
  155. package/src/secrets/secrets-context.ts +9 -21
  156. package/src/secrets/table.ts +1 -1
  157. package/src/sessions/__tests__/cleanup.integration.ts +8 -6
  158. package/src/sessions/__tests__/password-auto-revoke.integration.ts +7 -6
  159. package/src/sessions/__tests__/sessions.integration.ts +23 -38
  160. package/src/sessions/__tests__/test-helpers.ts +1 -1
  161. package/src/sessions/db/queries/cleanup.ts +21 -0
  162. package/src/sessions/handlers/cleanup.job.ts +6 -29
  163. package/src/sessions/handlers/list.query.ts +24 -24
  164. package/src/sessions/handlers/mine.query.ts +24 -23
  165. package/src/sessions/handlers/revoke-all-for-user.write.ts +7 -11
  166. package/src/sessions/handlers/revoke-all-others.write.ts +7 -12
  167. package/src/sessions/handlers/revoke.write.ts +11 -18
  168. package/src/sessions/schema/user-session.ts +2 -2
  169. package/src/sessions/session-callbacks.ts +19 -21
  170. package/src/subscription-mollie/__tests__/feature.test.ts +1 -1
  171. package/src/subscription-mollie/__tests__/mollie-foundation.integration.ts +1 -1
  172. package/src/subscription-mollie/__tests__/verify-webhook.test.ts +8 -7
  173. package/src/subscription-stripe/__tests__/feature.test.ts +1 -1
  174. package/src/subscription-stripe/__tests__/plugin-methods.test.ts +14 -15
  175. package/src/subscription-stripe/__tests__/stripe-foundation.integration.ts +1 -1
  176. package/src/subscription-stripe/__tests__/verify-webhook.test.ts +14 -14
  177. package/src/subscription-stripe/verify-webhook.ts +1 -1
  178. package/src/template-resolver/__tests__/handlers.integration.ts +1 -1
  179. package/src/template-resolver/__tests__/template-resolver.integration.ts +3 -2
  180. package/src/template-resolver/api.ts +7 -13
  181. package/src/template-resolver/handlers/archive.write.ts +4 -7
  182. package/src/template-resolver/handlers/find-by-id.query.ts +4 -7
  183. package/src/template-resolver/handlers/list.query.ts +13 -21
  184. package/src/template-resolver/handlers/publish.write.ts +4 -7
  185. package/src/template-resolver/handlers/upsert-system.write.ts +7 -10
  186. package/src/template-resolver/handlers/upsert-tenant.write.ts +7 -10
  187. package/src/template-resolver/table.ts +2 -5
  188. package/src/tenant/__tests__/multi-tenant.integration.ts +1 -1
  189. package/src/tenant/__tests__/seed-testing.integration.ts +19 -45
  190. package/src/tenant/__tests__/tenant.integration.ts +1 -1
  191. package/src/tenant/handlers/active-tenant-ids.query.ts +3 -8
  192. package/src/tenant/handlers/add-member.write.ts +6 -8
  193. package/src/tenant/handlers/cancel-invitation.write.ts +5 -7
  194. package/src/tenant/handlers/invitations.query.ts +5 -10
  195. package/src/tenant/handlers/me.query.ts +2 -3
  196. package/src/tenant/handlers/members.query.ts +4 -5
  197. package/src/tenant/handlers/memberships.query.ts +2 -5
  198. package/src/tenant/handlers/remove-member.write.ts +6 -8
  199. package/src/tenant/handlers/resolve-user-ids.query.ts +6 -16
  200. package/src/tenant/handlers/update-member-roles.write.ts +6 -8
  201. package/src/tenant/invitation-table.ts +2 -5
  202. package/src/tenant/membership-table.ts +3 -6
  203. package/src/tenant/schema/tenant.ts +2 -2
  204. package/src/tenant/seeding.ts +12 -18
  205. package/src/text-content/README.md +1 -1
  206. package/src/text-content/__tests__/text-content.integration.ts +2 -2
  207. package/src/text-content/api.ts +2 -9
  208. package/src/text-content/handlers/by-slug.query.ts +6 -9
  209. package/src/text-content/handlers/by-tenant.query.ts +2 -2
  210. package/src/text-content/handlers/set.write.ts +7 -9
  211. package/src/text-content/seeding.ts +6 -9
  212. package/src/text-content/table.ts +2 -2
  213. package/src/text-content/web/__tests__/editor-read-only.test.tsx +31 -45
  214. package/src/text-content/web/__tests__/group-blocks.test.ts +1 -18
  215. package/src/text-content/web/client-plugin.tsx +11 -23
  216. package/src/tier-engine/__tests__/auto-default-tier.integration.ts +10 -16
  217. package/src/tier-engine/__tests__/compose-app.test.ts +1 -1
  218. package/src/tier-engine/__tests__/drift.test.ts +1 -1
  219. package/src/tier-engine/__tests__/resolver.integration.ts +6 -6
  220. package/src/tier-engine/__tests__/tier-engine.integration.ts +1 -1
  221. package/src/tier-engine/feature.ts +9 -16
  222. package/src/user/__tests__/seed-testing.integration.ts +10 -22
  223. package/src/user/__tests__/user-status.test.ts +1 -1
  224. package/src/user/__tests__/user.integration.ts +6 -5
  225. package/src/user/handlers/create.write.ts +5 -7
  226. package/src/user/handlers/find-for-auth.query.ts +5 -7
  227. package/src/user/schema/user.ts +2 -2
  228. package/src/user/seeding.ts +2 -3
  229. package/src/user-data-rights/__tests__/audit-log.integration.ts +24 -12
  230. package/src/user-data-rights/__tests__/cross-data-matrix.integration.ts +64 -37
  231. package/src/user-data-rights/__tests__/download.integration.ts +29 -46
  232. package/src/user-data-rights/__tests__/export-job-idempotency.integration.ts +35 -28
  233. package/src/user-data-rights/__tests__/export-job-schema.test.ts +2 -2
  234. package/src/user-data-rights/__tests__/policy-to-strategy.test.ts +1 -1
  235. package/src/user-data-rights/__tests__/request-cancel-deletion.integration.ts +11 -15
  236. package/src/user-data-rights/__tests__/request-deletion-callback.integration.ts +10 -12
  237. package/src/user-data-rights/__tests__/request-export.integration.ts +23 -16
  238. package/src/user-data-rights/__tests__/restriction-flow.integration.ts +24 -32
  239. package/src/user-data-rights/__tests__/run-export-jobs.integration.ts +142 -137
  240. package/src/user-data-rights/__tests__/run-forget-cleanup.integration.ts +46 -28
  241. package/src/user-data-rights/__tests__/run-user-export.integration.ts +20 -14
  242. package/src/user-data-rights/__tests__/token-helpers.test.ts +1 -1
  243. package/src/user-data-rights/__tests__/user-data-rights.integration.ts +1 -1
  244. package/src/user-data-rights/__tests__/zip-path.test.ts +1 -1
  245. package/src/user-data-rights/audit-download.ts +3 -3
  246. package/src/user-data-rights/db/queries/export-jobs.ts +23 -0
  247. package/src/user-data-rights/db/queries/forget-cleanup.ts +13 -0
  248. package/src/user-data-rights/handlers/cancel-deletion.write.ts +28 -22
  249. package/src/user-data-rights/handlers/download-by-job.query.ts +11 -21
  250. package/src/user-data-rights/handlers/download-by-token.query.ts +20 -35
  251. package/src/user-data-rights/handlers/export-status.query.ts +19 -33
  252. package/src/user-data-rights/handlers/lift-restriction.write.ts +7 -12
  253. package/src/user-data-rights/handlers/list-download-attempts.query.ts +14 -23
  254. package/src/user-data-rights/handlers/my-audit-log.query.ts +33 -23
  255. package/src/user-data-rights/handlers/request-deletion.write.ts +15 -15
  256. package/src/user-data-rights/handlers/request-export.write.ts +7 -11
  257. package/src/user-data-rights/handlers/restrict-account.write.ts +12 -12
  258. package/src/user-data-rights/run-export-jobs.ts +20 -60
  259. package/src/user-data-rights/run-forget-cleanup.ts +19 -33
  260. package/src/user-data-rights/run-user-export.ts +4 -6
  261. package/src/user-data-rights/schema/download-attempt.ts +2 -2
  262. package/src/user-data-rights/schema/download-token.ts +2 -2
  263. package/src/user-data-rights/schema/export-job.ts +2 -3
  264. package/src/user-data-rights-defaults/__tests__/user-data-rights-defaults.integration.ts +37 -30
  265. package/src/user-data-rights-defaults/db/queries/user-hook.ts +17 -0
  266. package/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +12 -27
  267. package/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +16 -18
  268. package/CHANGELOG.md +0 -680
@@ -20,6 +20,7 @@
20
20
  // landen. user-data-rights-defaults/hooks/user.userdata-hook expose
21
21
  // expliziert KEIN passwordHash + KEINE roles (privileged columns).
22
22
 
23
+ import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
23
24
  import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
24
25
  import {
25
26
  EXT_USER_DATA,
@@ -29,7 +30,6 @@ import {
29
30
  type UserDataExportSnippet,
30
31
  } from "@cosmicdrift/kumiko-framework/engine";
31
32
  import type { getTemporal } from "@cosmicdrift/kumiko-framework/time";
32
- import { eq } from "drizzle-orm";
33
33
  import { tenantMembershipsTable } from "../tenant";
34
34
  import { buildFileRefZipPath } from "./zip-path";
35
35
 
@@ -116,11 +116,9 @@ export async function runUserExport(args: RunUserExportArgs): Promise<UserExport
116
116
  const { db, registry, userId, now } = args;
117
117
 
118
118
  // Memberships → Tenant-Liste fuer Hook-Iteration.
119
- // @cast-boundary db-row.
120
- const memberships = (await db
121
- .select({ tenantId: tenantMembershipsTable["tenantId"] })
122
- .from(tenantMembershipsTable)
123
- .where(eq(tenantMembershipsTable["userId"], userId))) as Array<{ tenantId: TenantId }>;
119
+ const memberships = await selectMany<{ tenantId: TenantId }>(db, tenantMembershipsTable, {
120
+ userId,
121
+ });
124
122
 
125
123
  const tenantList: TenantId[] = memberships.map((m) => m.tenantId);
126
124
 
@@ -1,4 +1,4 @@
1
- import { buildDrizzleTable } from "@cosmicdrift/kumiko-framework/db";
1
+ import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
2
2
  import {
3
3
  createEntity,
4
4
  createTextField,
@@ -34,4 +34,4 @@ export const downloadAttemptEntity = createEntity({
34
34
  retention: { keepFor: "90d", strategy: "hardDelete", reference: "attemptedAt" },
35
35
  });
36
36
 
37
- export const downloadAttemptsTable = buildDrizzleTable("downloadAttempt", downloadAttemptEntity);
37
+ export const downloadAttemptsTable = buildEntityTable("downloadAttempt", downloadAttemptEntity);
@@ -1,4 +1,4 @@
1
- import { buildDrizzleTable } from "@cosmicdrift/kumiko-framework/db";
1
+ import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
2
2
  import {
3
3
  createBigIntField,
4
4
  createEntity,
@@ -105,7 +105,7 @@ export const exportDownloadTokenEntity = createEntity({
105
105
  ],
106
106
  });
107
107
 
108
- export const exportDownloadTokensTable = buildDrizzleTable(
108
+ export const exportDownloadTokensTable = buildEntityTable(
109
109
  "exportDownloadToken",
110
110
  exportDownloadTokenEntity,
111
111
  );
@@ -1,4 +1,4 @@
1
- import { buildDrizzleTable } from "@cosmicdrift/kumiko-framework/db";
1
+ import { buildEntityTable, sql } from "@cosmicdrift/kumiko-framework/db";
2
2
  import {
3
3
  createBigIntField,
4
4
  createEntity,
@@ -7,7 +7,6 @@ import {
7
7
  createTextField,
8
8
  createTimestampField,
9
9
  } from "@cosmicdrift/kumiko-framework/engine";
10
- import { sql } from "drizzle-orm";
11
10
 
12
11
  // Export-Job-Lifecycle (S2.U3+U4 Atom 1).
13
12
  //
@@ -163,4 +162,4 @@ export const exportJobEntity = createEntity({
163
162
  ],
164
163
  });
165
164
 
166
- export const exportJobsTable = buildDrizzleTable("exportJob", exportJobEntity);
165
+ export const exportJobsTable = buildEntityTable("exportJob", exportJobEntity);
@@ -10,13 +10,13 @@
10
10
  // - "cross data matrix checks" (Cross-Tenant-Isolation: Tenant A's
11
11
  // fileRef-Forget beruehrt Tenant B's Files nicht)
12
12
 
13
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
14
+ import { asRawClient, insertOne } from "@cosmicdrift/kumiko-framework/bun-db";
13
15
  import {
14
16
  setupTestStack,
15
17
  type TestStack,
16
18
  unsafeCreateEntityTable,
17
19
  } from "@cosmicdrift/kumiko-framework/stack";
18
- import { sql } from "drizzle-orm";
19
- import { afterAll, beforeAll, describe, expect, test } from "vitest";
20
20
  import { createComplianceProfilesFeature } from "../../compliance-profiles";
21
21
  import { createDataRetentionFeature } from "../../data-retention";
22
22
  import { createFilesFeature } from "../../files";
@@ -52,9 +52,9 @@ beforeAll(async () => {
52
52
  await unsafeCreateEntityTable(stack.db, userEntity);
53
53
 
54
54
  // file_refs ist framework-pgTable (nicht entity-getrieben, S1.5 hat
55
- // die Schema-Sicht ohne buildDrizzleTable-Auto-Generation). Manuelle
55
+ // die Schema-Sicht ohne buildEntityTable-Auto-Generation). Manuelle
56
56
  // CREATE matched die Spalten aus framework/src/files/file-ref-table.ts
57
- await stack.db.execute(sql`
57
+ await asRawClient(stack.db).unsafe(`
58
58
  CREATE TABLE IF NOT EXISTS file_refs (
59
59
  id UUID PRIMARY KEY,
60
60
  tenant_id UUID NOT NULL,
@@ -90,21 +90,18 @@ async function seedUser(id: string, overrides: Record<string, unknown> = {}): Pr
90
90
  // Schema hat tenant_id-Spalte automatisch (Framework-Default).
91
91
  // Pragmatisch: SYSTEM_TENANT_ID fuer User-Rows in Tests.
92
92
  const SYSTEM_TENANT = "00000000-0000-4000-8000-000000000001";
93
- await stack.db
94
- .insert(userTable)
95
- .values({
96
- id,
97
- tenantId: SYSTEM_TENANT,
98
- email: `user-${id}@example.com`,
99
- passwordHash: "hashed-password",
100
- displayName: `User ${id}`,
101
- locale: "de",
102
- emailVerified: true,
103
- roles: '["Member"]',
104
- status: USER_STATUS.Active,
105
- ...overrides,
106
- })
107
- .onConflictDoNothing();
93
+ await insertOne(stack.db, userTable, {
94
+ id,
95
+ tenantId: SYSTEM_TENANT,
96
+ email: `user-${id}@example.com`,
97
+ passwordHash: "hashed-password",
98
+ displayName: `User ${id}`,
99
+ locale: "de",
100
+ emailVerified: true,
101
+ roles: '["Member"]',
102
+ status: USER_STATUS.Active,
103
+ ...overrides,
104
+ });
108
105
  }
109
106
 
110
107
  async function seedFileRef(
@@ -113,18 +110,24 @@ async function seedFileRef(
113
110
  insertedById: string | null,
114
111
  fileName: string,
115
112
  ): Promise<void> {
116
- await stack.db.execute(sql`
113
+ await asRawClient(stack.db).unsafe(
114
+ `
117
115
  INSERT INTO file_refs (id, tenant_id, storage_key, file_name, mime_type, size, inserted_by_id)
118
- VALUES (${id}, ${tenantId}, ${`storage/${id}`}, ${fileName}, 'application/pdf', 1024, ${insertedById})
116
+ VALUES ($1, $2, $3, $4, 'application/pdf', 1024, $5)
119
117
  ON CONFLICT (id) DO NOTHING
120
- `);
118
+ `,
119
+ [id, tenantId, `storage/${id}`, fileName, insertedById],
120
+ );
121
121
  }
122
122
 
123
123
  async function fetchUser(id: string) {
124
- const result = await stack.db.execute(sql`
124
+ const result = await asRawClient(stack.db).unsafe(
125
+ `
125
126
  SELECT id, email, display_name, password_hash, status, deleted_at
126
- FROM read_users WHERE id = ${id}
127
- `);
127
+ FROM read_users WHERE id = $1
128
+ `,
129
+ [id],
130
+ );
128
131
  // biome-ignore lint/suspicious/noExplicitAny: drizzle execute returns any-typed array
129
132
  const rows = ((result as any).rows ?? result) as Array<{
130
133
  id: string;
@@ -140,13 +143,17 @@ async function fetchUser(id: string) {
140
143
  async function fetchFileRefs(tenantId: string, insertedById?: string | null) {
141
144
  const result =
142
145
  insertedById === undefined
143
- ? await stack.db.execute(sql`SELECT * FROM file_refs WHERE tenant_id = ${tenantId}`)
146
+ ? await asRawClient(stack.db).unsafe(`SELECT * FROM file_refs WHERE tenant_id = $1`, [
147
+ tenantId,
148
+ ])
144
149
  : insertedById === null
145
- ? await stack.db.execute(
146
- sql`SELECT * FROM file_refs WHERE tenant_id = ${tenantId} AND inserted_by_id IS NULL`,
150
+ ? await asRawClient(stack.db).unsafe(
151
+ `SELECT * FROM file_refs WHERE tenant_id = $1 AND inserted_by_id IS NULL`,
152
+ [tenantId],
147
153
  )
148
- : await stack.db.execute(
149
- sql`SELECT * FROM file_refs WHERE tenant_id = ${tenantId} AND inserted_by_id = ${insertedById}`,
154
+ : await asRawClient(stack.db).unsafe(
155
+ `SELECT * FROM file_refs WHERE tenant_id = $1 AND inserted_by_id = $2`,
156
+ [tenantId, insertedById],
150
157
  );
151
158
  // biome-ignore lint/suspicious/noExplicitAny: drizzle execute typing
152
159
  return (result as any).rows ?? result;
@@ -0,0 +1,17 @@
1
+ import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
2
+ import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
3
+
4
+ export async function anonymizeDeletedUser(
5
+ db: DbRunner,
6
+ params: {
7
+ readonly email: string;
8
+ readonly displayName: string;
9
+ readonly status: string;
10
+ readonly userId: string;
11
+ },
12
+ ): Promise<void> {
13
+ await asRawClient(db).unsafe(
14
+ 'UPDATE "read_users" SET email = $1, display_name = $2, password_hash = $3, status = $4, deleted_at = now() WHERE id = $5',
15
+ [params.email, params.displayName, null, params.status, params.userId],
16
+ );
17
+ }
@@ -1,6 +1,6 @@
1
+ import { deleteMany, selectMany, updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
2
  import type { UserDataDeleteHook, UserDataExportHook } from "@cosmicdrift/kumiko-framework/engine";
2
3
  import { fileRefsTable } from "@cosmicdrift/kumiko-framework/files";
3
- import { and, eq } from "drizzle-orm";
4
4
 
5
5
  // userData-Hook fuer fileRef-entity (S2.H2).
6
6
  //
@@ -30,15 +30,10 @@ import { and, eq } from "drizzle-orm";
30
30
  // Cleanup als TODO und faellen das in S2.U5 nochmal an.
31
31
 
32
32
  export const fileRefExportHook: UserDataExportHook = async (ctx) => {
33
- const rawRows = await ctx.db
34
- .select()
35
- .from(fileRefsTable)
36
- .where(
37
- and(
38
- eq(fileRefsTable["tenantId"], ctx.tenantId),
39
- eq(fileRefsTable["insertedById"], ctx.userId),
40
- ),
41
- );
33
+ const rawRows = await selectMany(ctx.db, fileRefsTable, {
34
+ tenantId: ctx.tenantId,
35
+ insertedById: ctx.userId,
36
+ });
42
37
 
43
38
  // @cast-boundary db-row: drizzle liefert insertedAt als Instant
44
39
  // (framework-customType). Fuer JSON-Export brauchen wir String —
@@ -83,27 +78,17 @@ export const fileRefDeleteHook: UserDataDeleteHook = async (ctx, strategy) => {
83
78
  // Hard-delete der FileRef-Rows fuer diesen User in diesem Tenant.
84
79
  // Storage-Binary-Cleanup folgt in S2.U5 wenn der Forget-Job-Ctx
85
80
  // den Storage-Provider exposed.
86
- await ctx.db
87
- .delete(fileRefsTable)
88
- .where(
89
- and(
90
- eq(fileRefsTable["tenantId"], ctx.tenantId),
91
- eq(fileRefsTable["insertedById"], ctx.userId),
92
- ),
93
- );
81
+ await deleteMany(ctx.db, fileRefsTable, { tenantId: ctx.tenantId, insertedById: ctx.userId });
94
82
  } else {
95
83
  // anonymize: insertedById=null, FileRef + binary bleiben.
96
84
  // Use-case: shared chat-Attachment in einem Multi-User-Channel —
97
85
  // Author-Identifikation raus, Datei bleibt fuer andere User
98
86
  // sichtbar.
99
- await ctx.db
100
- .update(fileRefsTable)
101
- .set({ insertedById: null })
102
- .where(
103
- and(
104
- eq(fileRefsTable["tenantId"], ctx.tenantId),
105
- eq(fileRefsTable["insertedById"], ctx.userId),
106
- ),
107
- );
87
+ await updateMany(
88
+ ctx.db,
89
+ fileRefsTable,
90
+ { insertedById: null },
91
+ { tenantId: ctx.tenantId, insertedById: ctx.userId },
92
+ );
108
93
  }
109
94
  };
@@ -1,6 +1,5 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
1
+ import { fetchOne, updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
2
  import type { UserDataDeleteHook, UserDataExportHook } from "@cosmicdrift/kumiko-framework/engine";
3
- import { eq, sql } from "drizzle-orm";
4
3
  import {
5
4
  USER_ANONYMIZED_DISPLAY_NAME,
6
5
  USER_ANONYMIZED_EMAIL_DOMAIN,
@@ -10,6 +9,7 @@ import {
10
9
  USER_STATUS,
11
10
  userTable,
12
11
  } from "../../user";
12
+ import { anonymizeDeletedUser } from "../db/queries/user-hook";
13
13
 
14
14
  // userData-Hook fuer user-entity (S2.H1).
15
15
  //
@@ -32,7 +32,7 @@ import {
32
32
  // Frist auf einer FK-target-Entity)
33
33
 
34
34
  export const userExportHook: UserDataExportHook = async (ctx) => {
35
- const row = (await fetchOne(ctx.db, userTable, eq(userTable["id"], ctx.userId))) as {
35
+ const row = (await fetchOne(ctx.db, userTable, { id: ctx.userId })) as {
36
36
  id: string;
37
37
  email: string;
38
38
  displayName: string;
@@ -64,28 +64,26 @@ export const userDeleteHook: UserDataDeleteHook = async (ctx, strategy) => {
64
64
  // Tenants Member sein), kein tenantId-Filter noetig.
65
65
 
66
66
  if (strategy === "delete") {
67
- await ctx.db
68
- .update(userTable)
69
- .set({
70
- email: `${USER_DELETED_EMAIL_PREFIX}-${ctx.userId}@${USER_ANONYMIZED_EMAIL_DOMAIN}`,
71
- displayName: USER_DELETED_DISPLAY_NAME,
72
- passwordHash: null,
73
- status: USER_STATUS.Deleted,
74
- deletedAt: sql`now()`,
75
- })
76
- .where(eq(userTable["id"], ctx.userId));
67
+ await anonymizeDeletedUser(ctx.db, {
68
+ email: `${USER_DELETED_EMAIL_PREFIX}-${ctx.userId}@${USER_ANONYMIZED_EMAIL_DOMAIN}`,
69
+ displayName: USER_DELETED_DISPLAY_NAME,
70
+ status: USER_STATUS.Deleted,
71
+ userId: ctx.userId,
72
+ });
77
73
  } else {
78
74
  // anonymize: PII raus, aber Row bleibt active (damit FK-References
79
75
  // weiter aufloesbar sind). Account ist effektiv weiter nutzbar
80
76
  // wenn der User sich neu authentifiziert — pragmatisch akzeptabel
81
77
  // weil "anonymize" auf user-entity ein seltener Edge-Case ist
82
78
  // (typisch hard-delete fuer User).
83
- await ctx.db
84
- .update(userTable)
85
- .set({
79
+ await updateMany(
80
+ ctx.db,
81
+ userTable,
82
+ {
86
83
  email: `${USER_ANONYMIZED_EMAIL_PREFIX}-${ctx.userId}@${USER_ANONYMIZED_EMAIL_DOMAIN}`,
87
84
  displayName: USER_ANONYMIZED_DISPLAY_NAME,
88
- })
89
- .where(eq(userTable["id"], ctx.userId));
85
+ },
86
+ { id: ctx.userId },
87
+ );
90
88
  }
91
89
  };