@cosmicdrift/kumiko-bundled-features 0.307.0 → 0.308.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 (243) hide show
  1. package/package.json +9 -9
  2. package/src/__tests__/access-invalidation-consumer.integration.test.ts +107 -0
  3. package/src/__tests__/access-invalidation-stream.integration.test.ts +1 -1
  4. package/src/__tests__/credential-scoped-sse-revoke.integration.test.ts +296 -0
  5. package/src/agent-tools/__tests__/agent-doc-lint.test.ts +1 -1
  6. package/src/agent-tools/__tests__/agent-manifest.test.ts +1 -1
  7. package/src/agent-tools/__tests__/agent-optout.test.ts +1 -1
  8. package/src/agent-tools/__tests__/agent-tools.integration.test.ts +1 -1
  9. package/src/agent-tools/__tests__/feature.test.ts +1 -1
  10. package/src/agent-tools/__tests__/tool-catalog.test.ts +1 -1
  11. package/src/agent-tools/agent-manifest.ts +1 -1
  12. package/src/audit/__tests__/escape-hatch-audit.integration.test.ts +1 -1
  13. package/src/audit/escape-hatch-audit-sink.ts +1 -1
  14. package/src/audit/handlers/details.query.ts +1 -1
  15. package/src/audit/handlers/list.query.ts +1 -1
  16. package/src/auth-email-password/__tests__/query-as-member.integration.test.ts +1 -1
  17. package/src/auth-email-password/feature.ts +1 -1
  18. package/src/auth-email-password/handlers/change-password.write.ts +1 -1
  19. package/src/auth-email-password/handlers/confirm-account-unlock.write.ts +1 -1
  20. package/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -1
  21. package/src/auth-email-password/handlers/invite-accept.write.ts +1 -1
  22. package/src/auth-email-password/handlers/invite-create.write.ts +1 -1
  23. package/src/auth-email-password/handlers/invite-signup-complete.write.ts +1 -1
  24. package/src/auth-email-password/handlers/login.write.ts +1 -1
  25. package/src/auth-email-password/handlers/logout.write.ts +1 -1
  26. package/src/auth-email-password/handlers/reset-password.write.ts +1 -1
  27. package/src/auth-email-password/handlers/self-registration-status.query.ts +1 -1
  28. package/src/auth-email-password/handlers/signup-confirm.write.ts +1 -1
  29. package/src/auth-email-password/handlers/signup-request.write.ts +1 -1
  30. package/src/auth-email-password/handlers/token-request-handler.ts +1 -1
  31. package/src/auth-email-password/handlers/verify-email.write.ts +1 -1
  32. package/src/auth-email-password/password-policy.ts +1 -1
  33. package/src/auth-mfa/__tests__/session-scoped-sse-revoke.integration.test.ts +1 -1
  34. package/src/auth-mfa/handlers/disable.write.ts +1 -1
  35. package/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +1 -1
  36. package/src/auth-mfa/handlers/enable-confirm.write.ts +1 -1
  37. package/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
  38. package/src/auth-mfa/handlers/enable-start.write.ts +1 -1
  39. package/src/auth-mfa/handlers/regenerate-recovery.write.ts +1 -1
  40. package/src/auth-mfa/handlers/status.query.ts +1 -1
  41. package/src/auth-mfa/handlers/verify.write.ts +1 -1
  42. package/src/billing-foundation/billing-info-query.ts +1 -1
  43. package/src/billing-foundation/events.ts +1 -1
  44. package/src/billing-foundation/handlers/create-checkout-session.write.ts +1 -1
  45. package/src/billing-foundation/handlers/create-portal-session.write.ts +1 -1
  46. package/src/billing-foundation/handlers/list-subscriptions.query.ts +1 -1
  47. package/src/billing-foundation/handlers/process-event.write.ts +1 -1
  48. package/src/billing-foundation/handlers/process-payment-event.write.ts +1 -1
  49. package/src/cap-counter/__tests__/cap-counter.integration.test.ts +1 -1
  50. package/src/cap-counter/__tests__/stock-cap-guard.integration.test.ts +1 -1
  51. package/src/cap-counter/__tests__/with-cap-enforcement.integration.test.ts +1 -1
  52. package/src/cap-counter/book-cap-usage.ts +1 -1
  53. package/src/cap-counter/handlers/get-counter.query.ts +1 -1
  54. package/src/cap-counter/handlers/increment-rolling.write.ts +1 -1
  55. package/src/cap-counter/handlers/increment.write.ts +1 -1
  56. package/src/cap-counter/handlers/mark-soft-warned.write.ts +1 -1
  57. package/src/cap-overview/handlers/caps-usage.query.ts +1 -1
  58. package/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
  59. package/src/cap-overview/handlers/tenant-options.query.ts +1 -1
  60. package/src/channel-in-app/handlers/inbox.query.ts +1 -1
  61. package/src/channel-in-app/handlers/mark-all-read.write.ts +1 -1
  62. package/src/channel-in-app/handlers/mark-read.write.ts +1 -1
  63. package/src/channel-in-app/handlers/unread-count.query.ts +1 -1
  64. package/src/compliance-profiles/handlers/for-tenant.query.ts +1 -1
  65. package/src/compliance-profiles/handlers/list-profiles.query.ts +1 -1
  66. package/src/compliance-profiles/handlers/needs-profile.query.ts +1 -1
  67. package/src/compliance-profiles/handlers/set-profile.write.ts +1 -1
  68. package/src/compliance-profiles/handlers/sub-processors.query.ts +1 -1
  69. package/src/compliance-profiles-ops/handlers/tenants-missing-profile.query.ts +1 -1
  70. package/src/config/__tests__/backing-secrets.integration.test.ts +1 -1
  71. package/src/config/__tests__/config.integration.test.ts +1 -1
  72. package/src/config/__tests__/tz-resolution.integration.test.ts +1 -1
  73. package/src/config/handlers/cascade.query.ts +1 -1
  74. package/src/config/handlers/readiness.query.ts +1 -1
  75. package/src/config/handlers/reset.write.ts +1 -1
  76. package/src/config/handlers/schema.query.ts +1 -1
  77. package/src/config/handlers/set.write.ts +1 -1
  78. package/src/config/handlers/values.query.ts +1 -1
  79. package/src/crypto-shredding/handlers/forget-subject.write.ts +1 -1
  80. package/src/custom-fields/__tests__/audit-integration.integration.test.ts +1 -1
  81. package/src/custom-fields/__tests__/cross-tenant-field-delete.integration.test.ts +1 -1
  82. package/src/custom-fields/__tests__/cross-tenant-set-write.integration.test.ts +1 -1
  83. package/src/custom-fields/__tests__/custom-fields.integration.test.ts +1 -1
  84. package/src/custom-fields/__tests__/field-access.integration.test.ts +1 -1
  85. package/src/custom-fields/__tests__/quota.integration.test.ts +1 -1
  86. package/src/custom-fields/__tests__/retention.integration.test.ts +1 -1
  87. package/src/custom-fields/__tests__/user-data-rights.integration.test.ts +1 -1
  88. package/src/custom-fields/events.ts +1 -1
  89. package/src/custom-fields/feature.ts +1 -1
  90. package/src/custom-fields/handlers/clear-custom-field.write.ts +1 -1
  91. package/src/custom-fields/handlers/set-custom-field.write.ts +1 -1
  92. package/src/custom-fields/lib/value-schema.ts +1 -1
  93. package/src/custom-fields/schemas.ts +1 -1
  94. package/src/data-retention/handlers/policy-for.query.ts +1 -1
  95. package/src/data-retention/override-schema.ts +1 -1
  96. package/src/delivery/__tests__/delivery-pii-kms.integration.test.ts +1 -1
  97. package/src/delivery/__tests__/delivery.integration.test.ts +1 -1
  98. package/src/delivery/events.ts +1 -1
  99. package/src/delivery/feature.ts +1 -1
  100. package/src/delivery/handlers/log.query.ts +1 -1
  101. package/src/delivery/handlers/preferences.query.ts +1 -1
  102. package/src/delivery/handlers/set-preference.write.ts +1 -1
  103. package/src/delivery/jobs.ts +1 -1
  104. package/src/delivery/unsubscribe.ts +1 -1
  105. package/src/derivatives-sharp/__tests__/derivatives-sharp.integration.test.ts +1 -1
  106. package/src/document-ingest-foundation/events.ts +1 -1
  107. package/src/document-ingest-foundation/feature.ts +1 -1
  108. package/src/feature-toggles/__tests__/feature-toggles.integration.test.ts +1 -1
  109. package/src/feature-toggles/events.ts +1 -1
  110. package/src/feature-toggles/handlers/list.query.ts +1 -1
  111. package/src/feature-toggles/handlers/registered.query.ts +1 -1
  112. package/src/feature-toggles/handlers/set.write.ts +1 -1
  113. package/src/file-derivatives/handlers/public-variant.query.ts +1 -1
  114. package/src/file-foundation/__tests__/file-foundation.integration.test.ts +1 -1
  115. package/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +1 -1
  116. package/src/folders/handlers/delete-folder.write.ts +1 -1
  117. package/src/folders/schemas.ts +1 -1
  118. package/src/form-draft/schemas.ts +1 -1
  119. package/src/inbound-mail-foundation/events.ts +1 -1
  120. package/src/inbound-mail-foundation/handlers/connect-account.write.ts +1 -1
  121. package/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +1 -1
  122. package/src/inbound-mail-foundation/handlers/ingest-message.write.ts +1 -1
  123. package/src/inbound-mail-foundation/handlers/list-accounts.query.ts +1 -1
  124. package/src/inbound-mail-foundation/handlers/list-messages.query.ts +1 -1
  125. package/src/inbound-mail-foundation/handlers/update-account.write.ts +1 -1
  126. package/src/inbound-provider-imap/credential-document.ts +1 -1
  127. package/src/jobs/__tests__/jobs-catalog.integration.test.ts +1 -1
  128. package/src/jobs/__tests__/tenant-job-failures.integration.test.ts +1 -1
  129. package/src/jobs/events.ts +1 -1
  130. package/src/jobs/handlers/catalog.query.ts +1 -1
  131. package/src/jobs/handlers/detail.query.ts +1 -1
  132. package/src/jobs/handlers/list.query.ts +1 -1
  133. package/src/jobs/handlers/projection-rebuild.job.ts +1 -1
  134. package/src/jobs/handlers/reindex-entity.job.ts +1 -1
  135. package/src/jobs/handlers/retry.write.ts +1 -1
  136. package/src/jobs/handlers/tenant-failures.query.ts +1 -1
  137. package/src/jobs/handlers/trigger.write.ts +1 -1
  138. package/src/ledger/handlers/reports.query.ts +1 -1
  139. package/src/ledger/schemas.ts +1 -1
  140. package/src/mail-foundation/__tests__/mail-foundation.integration.test.ts +1 -1
  141. package/src/managed-pages/handlers/branding.query.ts +1 -1
  142. package/src/managed-pages/handlers/by-slug.query.ts +1 -1
  143. package/src/managed-pages/handlers/by-tenant-published.query.ts +1 -1
  144. package/src/managed-pages/handlers/set.write.ts +1 -1
  145. package/src/notes-history/changes.json +7 -0
  146. package/src/notes-history/schemas.ts +1 -1
  147. package/src/notes-history/web/notes-section.tsx +37 -36
  148. package/src/personal-access-tokens/feature.ts +10 -0
  149. package/src/personal-access-tokens/handlers/available-scopes.query.ts +1 -1
  150. package/src/personal-access-tokens/handlers/create.write.ts +1 -1
  151. package/src/personal-access-tokens/handlers/list.query.ts +1 -1
  152. package/src/personal-access-tokens/handlers/revoke.write.ts +18 -2
  153. package/src/personal-access-tokens/index.ts +7 -0
  154. package/src/personal-access-tokens/pat-revoked-event.ts +23 -0
  155. package/src/personal-access-tokens/revoke-for-user.ts +31 -0
  156. package/src/rate-limiting/__tests__/rate-limiting.integration.test.ts +1 -1
  157. package/src/rate-limiting/handlers/status.query.ts +1 -1
  158. package/src/readiness/handlers/status.query.ts +1 -1
  159. package/src/secrets/feature.ts +1 -1
  160. package/src/secrets/handlers/delete.write.ts +1 -1
  161. package/src/secrets/handlers/list.query.ts +1 -1
  162. package/src/secrets/handlers/set.write.ts +1 -1
  163. package/src/secrets/secrets-context.ts +1 -1
  164. package/src/seo/handlers/seo-config.query.ts +1 -1
  165. package/src/sessions/handlers/detail.query.ts +1 -1
  166. package/src/sessions/handlers/list.query.ts +1 -1
  167. package/src/sessions/handlers/mine.query.ts +1 -1
  168. package/src/sessions/handlers/revoke-all-for-user.write.ts +1 -1
  169. package/src/sessions/handlers/revoke-all-others.write.ts +1 -1
  170. package/src/sessions/handlers/revoke.write.ts +1 -1
  171. package/src/sessions/session-callbacks.ts +25 -1
  172. package/src/sessions/session-revoked-event.ts +6 -1
  173. package/src/shared/__tests__/row-bound-grant.integration.test.ts +1 -1
  174. package/src/step-dispatcher/mail-runner.ts +1 -1
  175. package/src/step-dispatcher/webhook-runner.ts +1 -1
  176. package/src/subscription-mollie/feature.ts +1 -1
  177. package/src/subscription-stripe/feature.ts +1 -1
  178. package/src/tags/schemas.ts +1 -1
  179. package/src/template-resolver/handlers/by-slug.query.ts +1 -1
  180. package/src/template-resolver/handlers/by-tenant.query.ts +1 -1
  181. package/src/template-resolver/handlers/collection-item.query.ts +1 -1
  182. package/src/template-resolver/handlers/collection-list.query.ts +1 -1
  183. package/src/template-resolver/handlers/collection-set.write.ts +1 -1
  184. package/src/template-resolver/handlers/find-by-id.query.ts +1 -1
  185. package/src/template-resolver/handlers/list.query.ts +1 -1
  186. package/src/template-resolver/handlers/set.write.ts +1 -1
  187. package/src/template-resolver/handlers/shared.ts +1 -1
  188. package/src/template-resolver/handlers/toggle-status.write.ts +1 -1
  189. package/src/template-resolver/handlers/upsert-tenant.write.ts +1 -1
  190. package/src/tenant/__tests__/tenant-timezone-boot.integration.test.ts +1 -1
  191. package/src/tenant/handlers/active-tenant-ids.query.ts +1 -1
  192. package/src/tenant/handlers/add-member.write.ts +1 -1
  193. package/src/tenant/handlers/cancel-invitation.write.ts +1 -1
  194. package/src/tenant/handlers/create.write.ts +1 -1
  195. package/src/tenant/handlers/invitations.query.ts +1 -1
  196. package/src/tenant/handlers/list.query.ts +1 -1
  197. package/src/tenant/handlers/me.query.ts +1 -1
  198. package/src/tenant/handlers/member-directory.query.ts +1 -1
  199. package/src/tenant/handlers/members.query.ts +1 -1
  200. package/src/tenant/handlers/memberships.query.ts +1 -1
  201. package/src/tenant/handlers/remove-member.write.ts +1 -1
  202. package/src/tenant/handlers/resolve-user-ids.query.ts +1 -1
  203. package/src/tenant/handlers/team-list.query.ts +1 -1
  204. package/src/tenant/handlers/tenant-directory.query.ts +1 -1
  205. package/src/tenant/handlers/toggle-enabled.write.ts +1 -1
  206. package/src/tenant/handlers/update-member-roles.write.ts +1 -1
  207. package/src/tenant/handlers/update.write.ts +1 -1
  208. package/src/tenant-handover/events.ts +1 -1
  209. package/src/tenant-handover/handlers/claim.write.ts +1 -1
  210. package/src/tenant-lifecycle/events.ts +1 -1
  211. package/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +1 -1
  212. package/src/tenant-lifecycle/handlers/request-destruction.write.ts +1 -1
  213. package/src/tenant-settings/tenant-defaults.ts +1 -1
  214. package/src/tier-engine/__tests__/tier-resolver.integration.test.ts +1 -1
  215. package/src/tier-engine/feature.ts +1 -1
  216. package/src/tier-engine/handlers/active-tier.query.ts +1 -1
  217. package/src/tier-engine/handlers/get-tenant-tier.query.ts +1 -1
  218. package/src/tier-engine/handlers/set-tenant-tier.write.ts +1 -1
  219. package/src/user/__tests__/user-global-tenancy.integration.test.ts +1 -1
  220. package/src/user/handlers/create.write.ts +1 -1
  221. package/src/user/handlers/find-for-auth.query.ts +1 -1
  222. package/src/user/handlers/me.query.ts +1 -1
  223. package/src/user/handlers/update.write.ts +1 -1
  224. package/src/user/roles-input-schema.ts +1 -1
  225. package/src/user-data-rights/__tests__/boot-checks.test.ts +1 -1
  226. package/src/user-data-rights/changes.json +6 -0
  227. package/src/user-data-rights/feature.ts +1 -0
  228. package/src/user-data-rights/handlers/cancel-deletion.write.ts +1 -1
  229. package/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +1 -1
  230. package/src/user-data-rights/handlers/download-by-job.query.ts +1 -1
  231. package/src/user-data-rights/handlers/download-by-token.query.ts +1 -1
  232. package/src/user-data-rights/handlers/export-status.query.ts +1 -1
  233. package/src/user-data-rights/handlers/lift-restriction.write.ts +1 -1
  234. package/src/user-data-rights/handlers/list-download-attempts.query.ts +1 -1
  235. package/src/user-data-rights/handlers/my-audit-log.query.ts +1 -1
  236. package/src/user-data-rights/handlers/request-deletion-by-email.write.ts +1 -1
  237. package/src/user-data-rights/handlers/request-deletion.write.ts +1 -1
  238. package/src/user-data-rights/handlers/request-export.write.ts +1 -1
  239. package/src/user-data-rights/handlers/restrict-account.write.ts +1 -1
  240. package/src/user-data-rights/handlers/run-forget-cleanup.write.ts +1 -1
  241. package/src/user-profile/handlers/change-email.write.ts +1 -1
  242. package/src/workflow-runner/__tests__/pending-projection.integration.test.ts +1 -1
  243. package/src/workflow-runner/handlers/resume-run.write.ts +1 -1
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import * as z from "zod";
2
2
 
3
3
  // entityType/entityId are app-supplied — mirror tags' NO_PIPE guard isn't
4
4
  // needed here since note-entry has no deterministic aggregate-id derived
@@ -48,7 +48,7 @@ export function NotesSection({
48
48
  readonly entityName: string;
49
49
  readonly entityId: string | null;
50
50
  }): ReactNode {
51
- const { Banner, Button, Card, Grid, Text, Input } = usePrimitives();
51
+ const { Banner, Button, Grid, Heading, Text, Input } = usePrimitives();
52
52
  const t = useTranslation();
53
53
  const dispatcher = useDispatcher();
54
54
  const enabled = entityId !== null;
@@ -117,43 +117,44 @@ export function NotesSection({
117
117
  })();
118
118
  };
119
119
 
120
+ // No own Card/SectionCard here — the host (ExtensionSectionMount) already
121
+ // frames this whole component in one card; a nested card would double the
122
+ // border/padding. "New note" and "History" are sub-headers within that
123
+ // single frame instead.
120
124
  return (
121
125
  <Grid columns={1} testId="notes-section">
122
- <Card slots={{ title: t("notesHistory.section.newNoteTitle") }} testId="notes-section-new">
123
- <Grid columns={1}>
124
- <Input
125
- kind="textarea"
126
- id="notes-section-draft"
127
- name="draft"
128
- value={draft}
129
- onChange={setDraft}
130
- onSubmitShortcut={() => {
131
- if (!busy && draft.trim() !== "") addNote();
132
- }}
133
- />
134
- <div className="flex items-center justify-between gap-2">
135
- <Text variant="small">{t("notesHistory.section.shortcutHint")}</Text>
136
- <Button
137
- variant="primary"
138
- disabled={busy || draft.trim() === ""}
139
- onClick={() => addNote()}
140
- testId="notes-section-add"
141
- >
142
- {busy ? t("notesHistory.section.working") : t("notesHistory.section.add")}
143
- </Button>
144
- </div>
145
- {errorKey !== null && (
146
- <Banner variant="error" testId="notes-section-action-error">
147
- <Text>{t(errorKey)}</Text>
148
- </Banner>
149
- )}
150
- </Grid>
151
- </Card>
126
+ <div className="flex flex-col gap-3" data-testid="notes-section-new">
127
+ <Heading variant="section">{t("notesHistory.section.newNoteTitle")}</Heading>
128
+ <Input
129
+ kind="textarea"
130
+ id="notes-section-draft"
131
+ name="draft"
132
+ value={draft}
133
+ onChange={setDraft}
134
+ onSubmitShortcut={() => {
135
+ if (!busy && draft.trim() !== "") addNote();
136
+ }}
137
+ />
138
+ <div className="flex items-center justify-between gap-2">
139
+ <Text variant="small">{t("notesHistory.section.shortcutHint")}</Text>
140
+ <Button
141
+ variant="primary"
142
+ disabled={busy || draft.trim() === ""}
143
+ onClick={() => addNote()}
144
+ testId="notes-section-add"
145
+ >
146
+ {busy ? t("notesHistory.section.working") : t("notesHistory.section.add")}
147
+ </Button>
148
+ </div>
149
+ {errorKey !== null && (
150
+ <Banner variant="error" testId="notes-section-action-error">
151
+ <Text>{t(errorKey)}</Text>
152
+ </Banner>
153
+ )}
154
+ </div>
152
155
 
153
- <Card
154
- slots={{ title: t("notesHistory.section.historyTitle") }}
155
- testId="notes-section-history"
156
- >
156
+ <div className="flex flex-col gap-3" data-testid="notes-section-history">
157
+ <Heading variant="section">{t("notesHistory.section.historyTitle")}</Heading>
157
158
  {rows.length === 0 ? (
158
159
  <Text variant="small">{t("notesHistory.section.empty")}</Text>
159
160
  ) : (
@@ -178,7 +179,7 @@ export function NotesSection({
178
179
  ))}
179
180
  </div>
180
181
  )}
181
- </Card>
182
+ </div>
182
183
  </Grid>
183
184
  );
184
185
  }
@@ -11,6 +11,7 @@ import { type CreatePatOptions, createPatCreateHandler } from "./handlers/create
11
11
  import { listPatQuery } from "./handlers/list.query";
12
12
  import { revokePatWrite } from "./handlers/revoke.write";
13
13
  import { PAT_FEATURE_I18N, patScopeOptionTranslations } from "./i18n";
14
+ import { PAT_REVOKED_EVENT_SHORT, patRevokedSchema } from "./pat-revoked-event";
14
15
  import { createPatResolver } from "./resolver";
15
16
  import { apiTokenEntity } from "./schema/api-token";
16
17
  import type { PatScopeConfig } from "./scopes";
@@ -114,6 +115,15 @@ export function createPersonalAccessTokensFeature(
114
115
  piiEncryptedOnWrite: true,
115
116
  });
116
117
 
118
+ // Custom domain-event for cross-instance access-invalidation,
119
+ // mirroring sessions' SESSION_REVOKED_EVENT_SHORT. r.defineEvent
120
+ // registers the schema so ctx.unsafeAppendEvent (revoke) enforces it at
121
+ // append time. revoke-for-user.ts appends via the low-level append()
122
+ // instead (needs to anchor on SYSTEM_TENANT_ID) — same guarantee via a
123
+ // different path. No projection: the payload IS the read, consumed
124
+ // directly off the event-store NOTIFY.
125
+ r.defineEvent(PAT_REVOKED_EVENT_SHORT, patRevokedSchema, { piiFields: "none" });
126
+
117
127
  // Password-change auto-revoke — mirrors sessions' own
118
128
  // autoRevokeOnPasswordChange postSave hook, including WHY it's a
119
129
  // late-bind callback rather than direct ctx.db use: user:write:user:update
@@ -1,5 +1,5 @@
1
1
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
2
- import { z } from "zod";
2
+ import * as z from "zod";
3
3
  import type { PatScopeConfig } from "../scopes";
4
4
 
5
5
  // Returns the app-declared scope domains ({name, label, canWrite}) so the mint
@@ -8,7 +8,7 @@ import {
8
8
  import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
9
9
  import { generateId } from "@cosmicdrift/kumiko-framework/utils";
10
10
  import { Temporal } from "temporal-polyfill";
11
- import { z } from "zod";
11
+ import * as z from "zod";
12
12
  import { encryptForDirectWrite, verifyPassword } from "../../shared";
13
13
  import { UserQueries } from "../../user";
14
14
  import { PAT_DEFAULT_EXPIRES_IN_DAYS, PatErrors } from "../constants";
@@ -1,6 +1,6 @@
1
1
  import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
2
  import { definePagedQueryHandler, MAX_LIST_LIMIT } from "@cosmicdrift/kumiko-framework/engine";
3
- import { z } from "zod";
3
+ import * as z from "zod";
4
4
  import { decryptStoredPii } from "../../shared";
5
5
  import { isExpiredAt } from "../expiry";
6
6
  import { apiTokenTable } from "../schema/api-token";
@@ -1,9 +1,11 @@
1
1
  import { updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
2
  import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
4
+ import { generateId } from "@cosmicdrift/kumiko-framework/utils";
4
5
  import { Temporal } from "temporal-polyfill";
5
- import { z } from "zod";
6
+ import * as z from "zod";
6
7
  import { PatErrors } from "../constants";
8
+ import { PAT_REVOKED_AGGREGATE_TYPE, PAT_REVOKED_EVENT_QN } from "../pat-revoked-event";
7
9
  import { apiTokenTable } from "../schema/api-token";
8
10
 
9
11
  // Revoke one of the caller's own tokens. Ownership is enforced in the WHERE
@@ -30,7 +32,21 @@ export const revokePatWrite = defineWriteHandler({
30
32
  { revokedAt: Temporal.Now.instant() },
31
33
  { id: event.payload.id, userId: event.user.id, revokedAt: null },
32
34
  );
33
- if (updated.length > 0) return { isSuccess: true, data: { id: event.payload.id } };
35
+ if (updated.length > 0) {
36
+ // Lightweight append alongside the direct-write above, mirroring
37
+ // sessions' revoke.write.ts. NOT a lifecycle event for
38
+ // store_api_tokens (that table stays an unmanaged direct-write store,
39
+ // see feature.ts). Without this, the access-invalidation consumer
40
+ // never hears about the revoke and an already-open SSE stream
41
+ // authenticated by this exact token survives it.
42
+ await ctx.unsafeAppendEvent({
43
+ aggregateId: generateId(),
44
+ aggregateType: PAT_REVOKED_AGGREGATE_TYPE,
45
+ type: PAT_REVOKED_EVENT_QN,
46
+ payload: { userId: event.user.id, tokenIds: [event.payload.id] },
47
+ });
48
+ return { isSuccess: true, data: { id: event.payload.id } };
49
+ }
34
50
  return writeFailure(
35
51
  new UnprocessableError(PatErrors.ownershipDenied, {
36
52
  i18nKey: "errors.ownershipDenied",
@@ -10,6 +10,13 @@ export {
10
10
  } from "./feature";
11
11
  export type { CreatePatOptions, PatMfaVerifyResult } from "./handlers/create.write";
12
12
  export { hashPatToken, mintPatToken } from "./hash";
13
+ export {
14
+ PAT_REVOKED_AGGREGATE_TYPE,
15
+ PAT_REVOKED_EVENT_QN,
16
+ PAT_REVOKED_EVENT_SHORT,
17
+ type PatRevokedPayload,
18
+ patRevokedSchema,
19
+ } from "./pat-revoked-event";
13
20
  export { createPatResolver } from "./resolver";
14
21
  export { revokeAllPatTokensForUser } from "./revoke-for-user";
15
22
  export { apiTokenEntity, apiTokenTable } from "./schema/api-token";
@@ -0,0 +1,23 @@
1
+ import * as z from "zod";
2
+
3
+ // Lightweight custom event appended alongside the direct-write updateMany()
4
+ // in revoke.write.ts / revoke-for-user.ts (mirrors sessions'
5
+ // session-revoked-event.ts). apiTokenTable itself stays an unmanaged
6
+ // direct-write store (see feature.ts) — this event is NOT a CRUD/lifecycle
7
+ // event for that table and carries no projection. Its only job is to give
8
+ // the access-invalidation consumer something to LISTEN for, keyed by the
9
+ // affected userId, so a revoked PAT's open SSE stream closes.
10
+ export const PAT_REVOKED_EVENT_SHORT = "pat-revoked" as const;
11
+ export const PAT_REVOKED_EVENT_QN = "personal-access-tokens:event:pat-revoked" as const;
12
+
13
+ // Own aggregate type, decoupled from apiTokenEntity's implicit
14
+ // "api-token" — each revoke action mints a fresh aggregate id (no
15
+ // predecessor to satisfy, no version_conflict against concurrent revokes).
16
+ export const PAT_REVOKED_AGGREGATE_TYPE = "api-token-revocation" as const;
17
+
18
+ export const patRevokedSchema = z.object({
19
+ userId: z.string().min(1),
20
+ tokenIds: z.array(z.uuid()).min(1),
21
+ });
22
+
23
+ export type PatRevokedPayload = z.infer<typeof patRevokedSchema>;
@@ -1,6 +1,14 @@
1
1
  import { updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
2
  import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
3
+ import { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
4
+ import { append } from "@cosmicdrift/kumiko-framework/event-store";
5
+ import { generateId } from "@cosmicdrift/kumiko-framework/utils";
3
6
  import { Temporal } from "temporal-polyfill";
7
+ import {
8
+ PAT_REVOKED_AGGREGATE_TYPE,
9
+ PAT_REVOKED_EVENT_QN,
10
+ patRevokedSchema,
11
+ } from "./pat-revoked-event";
4
12
  import { apiTokenTable } from "./schema/api-token";
5
13
 
6
14
  // Cross-tenant revoke: password-change and MFA-enable/disable are account-
@@ -14,5 +22,28 @@ export async function revokeAllPatTokensForUser(db: DbRunner, userId: string): P
14
22
  { revokedAt: Temporal.Now.instant() },
15
23
  { userId, revokedAt: null },
16
24
  );
25
+
26
+ // Same reasoning as sessionMassRevoker's append — this raw
27
+ // callback has no dispatcher ctx to call unsafeAppendEvent from, so it
28
+ // uses the low-level append() directly, anchored on SYSTEM_TENANT_ID like
29
+ // sessions' cross-tenant writes. Without it, the access-invalidation
30
+ // consumer never hears about a password-change/MFA-toggle/forget-subject
31
+ // PAT revoke and any already-open SSE stream on those tokens survives it.
32
+ if (updated.length > 0) {
33
+ const payload = patRevokedSchema.parse({
34
+ userId,
35
+ tokenIds: updated.map((row) => row.id),
36
+ });
37
+ await append(db, {
38
+ aggregateId: generateId(),
39
+ aggregateType: PAT_REVOKED_AGGREGATE_TYPE,
40
+ tenantId: SYSTEM_TENANT_ID,
41
+ expectedVersion: 0,
42
+ type: PAT_REVOKED_EVENT_QN,
43
+ payload,
44
+ metadata: { userId },
45
+ });
46
+ }
47
+
17
48
  return updated.length;
18
49
  }
@@ -13,7 +13,7 @@ import {
13
13
  TestUsers,
14
14
  testTenantId,
15
15
  } from "@cosmicdrift/kumiko-framework/stack";
16
- import { z } from "zod";
16
+ import * as z from "zod";
17
17
  import { createRateLimitingFeature } from "../feature";
18
18
 
19
19
  let stack: TestStack;
@@ -1,6 +1,6 @@
1
1
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
2
2
  import { UnprocessableError } from "@cosmicdrift/kumiko-framework/errors";
3
- import { z } from "zod";
3
+ import * as z from "zod";
4
4
  import { RateLimitErrors } from "../constants";
5
5
  import { bucketAccessDenied } from "./bucket-access";
6
6
 
@@ -4,7 +4,7 @@ import {
4
4
  } from "@cosmicdrift/kumiko-bundled-features/config";
5
5
  import { requireSecretsContext } from "@cosmicdrift/kumiko-bundled-features/secrets";
6
6
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
7
- import { z } from "zod";
7
+ import * as z from "zod";
8
8
  import { ReadinessQueries } from "../constants";
9
9
 
10
10
  export type ReadinessMissingSecret = { readonly key: string };
@@ -7,7 +7,7 @@ import {
7
7
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
8
8
  import { SETTINGS_HUB_I18N } from "@cosmicdrift/kumiko-framework/i18n";
9
9
  import type { SecretsContext } from "@cosmicdrift/kumiko-framework/secrets";
10
- import { z } from "zod";
10
+ import * as z from "zod";
11
11
  import { DEFAULT_SECRETS_ACCESS } from "./constants";
12
12
  import { createDeleteHandler } from "./handlers/delete.write";
13
13
  import { createListHandler } from "./handlers/list.query";
@@ -1,6 +1,6 @@
1
1
  import { type AccessRule, defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
2
2
  import { failNotFound } from "@cosmicdrift/kumiko-framework/errors";
3
- import { z } from "zod";
3
+ import * as z from "zod";
4
4
  import { DEFAULT_SECRETS_ACCESS } from "../constants";
5
5
  import { requireSecretsContext } from "../feature";
6
6
 
@@ -1,5 +1,5 @@
1
1
  import { type AccessRule, defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
2
- import { z } from "zod";
2
+ import * as z from "zod";
3
3
  import { DEFAULT_SECRETS_ACCESS } from "../constants";
4
4
  import { tenantSecretsTable } from "../table";
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { type AccessRule, defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
2
- import { z } from "zod";
2
+ import * as z from "zod";
3
3
  import { DEFAULT_SECRETS_ACCESS } from "../constants";
4
4
  import { requireSecretsContext } from "../feature";
5
5
 
@@ -34,7 +34,7 @@ import {
34
34
  withDekCache,
35
35
  } from "@cosmicdrift/kumiko-framework/secrets";
36
36
  import { generateId } from "@cosmicdrift/kumiko-framework/utils";
37
- import { z } from "zod";
37
+ import * as z from "zod";
38
38
  import { selectTenantSecretEnvelope } from "./db/queries/read";
39
39
  import {
40
40
  type StoredEnvelope,
@@ -1,5 +1,5 @@
1
1
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
2
- import { z } from "zod";
2
+ import * as z from "zod";
3
3
  import { SEO_CONFIG_QN } from "../constants";
4
4
 
5
5
  // Public read of the seo feature's own tenant-config values, for the
@@ -1,6 +1,6 @@
1
1
  import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
2
2
  import { access, defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
- import { z } from "zod";
3
+ import * as z from "zod";
4
4
  import { decryptStoredPii } from "../../shared";
5
5
  import { userSessionTable } from "../schema/user-session";
6
6
 
@@ -4,7 +4,7 @@ import {
4
4
  definePagedQueryHandler,
5
5
  MAX_LIST_LIMIT,
6
6
  } from "@cosmicdrift/kumiko-framework/engine";
7
- import { z } from "zod";
7
+ import * as z from "zod";
8
8
  import { decryptStoredPii } from "../../shared";
9
9
  import { userSessionTable } from "../schema/user-session";
10
10
 
@@ -1,6 +1,6 @@
1
1
  import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
2
  import { definePagedQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
- import { z } from "zod";
3
+ import * as z from "zod";
4
4
  import { decryptStoredPii } from "../../shared";
5
5
  import { userSessionTable } from "../schema/user-session";
6
6
 
@@ -5,7 +5,7 @@ import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/
5
5
  import { append } from "@cosmicdrift/kumiko-framework/event-store";
6
6
  import { generateId } from "@cosmicdrift/kumiko-framework/utils";
7
7
  import { Temporal } from "temporal-polyfill";
8
- import { z } from "zod";
8
+ import * as z from "zod";
9
9
  import { userSessionTable } from "../schema/user-session";
10
10
  import {
11
11
  SESSION_REVOKED_AGGREGATE_TYPE,
@@ -3,7 +3,7 @@ import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import { generateId } from "@cosmicdrift/kumiko-framework/utils";
5
5
  import { Temporal } from "temporal-polyfill";
6
- import { z } from "zod";
6
+ import * as z from "zod";
7
7
  import { SessionErrors } from "../constants";
8
8
  import { userSessionTable } from "../schema/user-session";
9
9
  import { SESSION_REVOKED_AGGREGATE_TYPE, SESSION_REVOKED_EVENT_QN } from "../session-revoked-event";
@@ -3,7 +3,7 @@ import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import { generateId } from "@cosmicdrift/kumiko-framework/utils";
5
5
  import { Temporal } from "temporal-polyfill";
6
- import { z } from "zod";
6
+ import * as z from "zod";
7
7
  import { SessionErrors } from "../constants";
8
8
  import { userSessionTable } from "../schema/user-session";
9
9
  import { SESSION_REVOKED_AGGREGATE_TYPE, SESSION_REVOKED_EVENT_QN } from "../session-revoked-event";
@@ -97,12 +97,36 @@ export function createSessionCallbacks(opts: SessionCallbacksOptions): SessionCa
97
97
  // original timestamp. Double-revoke races land here via logout +
98
98
  // switch-tenant on the same sid. (Password-change uses a different
99
99
  // callback — sessionMassRevoker — and isn't in scope for this guard.)
100
- await updateMany(
100
+ const result = await updateMany<{ userId: string }>(
101
101
  db,
102
102
  userSessionTable,
103
103
  { revokedAt: Temporal.Now.instant() },
104
104
  { id: sid, revokedAt: null },
105
105
  );
106
+
107
+ // This is the ONLY caller of sessionRevoker — logout and tenant-switch
108
+ // — so it's also the only source of streamScope: "revoked-sessions".
109
+ // Without this append, a live SSE stream on this exact sid outlives its
110
+ // own logout because the access-invalidation consumer never hears
111
+ // about it — same gap sessionMassRevoker closed for
112
+ // password-change.
113
+ const revoked = result[0];
114
+ if (revoked) {
115
+ const payload = sessionRevokedSchema.parse({
116
+ userId: revoked.userId,
117
+ sessionIds: [sid],
118
+ streamScope: "revoked-sessions",
119
+ });
120
+ await append(db, {
121
+ aggregateId: generateId(),
122
+ aggregateType: SESSION_REVOKED_AGGREGATE_TYPE,
123
+ tenantId: SYSTEM_TENANT_ID,
124
+ expectedVersion: 0,
125
+ type: SESSION_REVOKED_EVENT_QN,
126
+ payload,
127
+ metadata: { userId: revoked.userId },
128
+ });
129
+ }
106
130
  },
107
131
 
108
132
  // kumiko-lint-ignore complexity-budget session check + lastSeen refresh on hot path
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import * as z from "zod";
2
2
 
3
3
  // Lightweight custom event appended alongside the direct-write
4
4
  // updateMany() in revoke.write.ts / revoke-all-others.write.ts /
@@ -27,6 +27,11 @@ export const sessionRevokedSchema = z.object({
27
27
  // The caller's own session a "revoke all others" write spared. Optional so
28
28
  // events appended before it existed still replay.
29
29
  keptSessionId: z.uuid().optional(),
30
+ // Set only by the raw sessionRevoker callback (logout / tenant-switch) —
31
+ // tells the access-invalidation consumer to close exactly `sessionIds`
32
+ // instead of the userwide default every other source keeps using.
33
+ // Optional so events appended before it existed still replay unscoped.
34
+ streamScope: z.literal("revoked-sessions").optional(),
30
35
  });
31
36
 
32
37
  export type SessionRevokedPayload = z.infer<typeof sessionRevokedSchema>;
@@ -10,7 +10,7 @@ import { executeRawQuery } from "@cosmicdrift/kumiko-framework/db";
10
10
  import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
11
11
  import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
12
12
  import { setupTestStack, type TestStack, testTenantId } from "@cosmicdrift/kumiko-framework/stack";
13
- import { z } from "zod";
13
+ import * as z from "zod";
14
14
  import { redeemRowBoundGrant, signRowBoundGrant } from "../row-bound-grant";
15
15
 
16
16
  const TABLE = "row_bound_grant_demo";
@@ -2,7 +2,7 @@
2
2
  // Production wiring (mail-foundation transport) is a follow-up; the
3
3
  // default impl throws so a missing setMailRunner is loud, not silent.
4
4
 
5
- import { z } from "zod";
5
+ import * as z from "zod";
6
6
 
7
7
  export const mailSpecSchema = z.object({
8
8
  to: z.union([z.string(), z.array(z.string())]),
@@ -1,7 +1,7 @@
1
1
  // Webhook execution logic — separated from feature.ts so tests can stub
2
2
  // the fetch without touching the MSP wiring.
3
3
 
4
- import { z } from "zod";
4
+ import * as z from "zod";
5
5
 
6
6
  export const webhookSpecSchema = z.object({
7
7
  url: z.string(),
@@ -42,7 +42,7 @@
42
42
  import type { SubscriptionProviderPlugin } from "@cosmicdrift/kumiko-bundled-features/billing-foundation";
43
43
  import { defineFeature, type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
44
44
  import { createMollieClient } from "@mollie/api-client";
45
- import { z } from "zod";
45
+ import * as z from "zod";
46
46
  import { MOLLIE_PROVIDER_NAME, SUBSCRIPTION_MOLLIE_FEATURE } from "./constants";
47
47
  import { createMollieCheckoutSession, type MolliePriceConfig } from "./plugin-methods";
48
48
  import { type MollieClientShape, verifyAndParseMollieWebhook } from "./verify-webhook";
@@ -38,7 +38,7 @@ import {
38
38
  defineFeature,
39
39
  type FeatureDefinition,
40
40
  } from "@cosmicdrift/kumiko-framework/engine";
41
- import { z } from "zod";
41
+ import * as z from "zod";
42
42
  import {
43
43
  STRIPE_API_KEY_CONFIG,
44
44
  STRIPE_BILLING_LIVE_CONFIG,
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import * as z from "zod";
2
2
 
3
3
  export const createTagPayloadSchema = z.object({
4
4
  name: z.string().trim().min(1).max(64),
@@ -3,7 +3,7 @@ import {
3
3
  crossTenantOverrideDenied,
4
4
  defineQueryHandler,
5
5
  } from "@cosmicdrift/kumiko-framework/engine";
6
- import { z } from "zod";
6
+ import * as z from "zod";
7
7
  import { TEXT_BLOCK_KIND } from "../constants";
8
8
  import { type TemplateResourceRow, templateResourcesTable } from "../table";
9
9
 
@@ -4,7 +4,7 @@ import {
4
4
  crossTenantOverrideDenied,
5
5
  defineQueryHandler,
6
6
  } from "@cosmicdrift/kumiko-framework/engine";
7
- import { z } from "zod";
7
+ import * as z from "zod";
8
8
  import { TEXT_BLOCK_KIND } from "../constants";
9
9
  import { type TemplateResourceRow, templateResourcesTable } from "../table";
10
10
 
@@ -4,7 +4,7 @@ import {
4
4
  crossTenantOverrideDenied,
5
5
  defineQueryHandler,
6
6
  } from "@cosmicdrift/kumiko-framework/engine";
7
- import { z } from "zod";
7
+ import * as z from "zod";
8
8
  import {
9
9
  type CollectionEntryRow,
10
10
  collectionStore,
@@ -5,7 +5,7 @@ import {
5
5
  crossTenantOverrideDenied,
6
6
  defineQueryHandler,
7
7
  } from "@cosmicdrift/kumiko-framework/engine";
8
- import { z } from "zod";
8
+ import * as z from "zod";
9
9
  import {
10
10
  type CollectionEntryRow,
11
11
  collectionStore,
@@ -6,7 +6,7 @@ import {
6
6
  type TenantId,
7
7
  } from "@cosmicdrift/kumiko-framework/engine";
8
8
  import { writeFailure } from "@cosmicdrift/kumiko-framework/errors";
9
- import { z } from "zod";
9
+ import * as z from "zod";
10
10
  import {
11
11
  type CollectionEntryRow,
12
12
  collectionStore,
@@ -1,6 +1,6 @@
1
1
  import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
2
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
- import { z } from "zod";
3
+ import * as z from "zod";
4
4
  import { type TemplateResourceRow, templateResourcesTable } from "../table";
5
5
 
6
6
  // Admin-Lookup für UI-Edit-Flow. Returnt das raw Template inkl. draft/
@@ -1,6 +1,6 @@
1
1
  import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
- import { z } from "zod";
3
+ import * as z from "zod";
4
4
  import { RENDER_KINDS, TEMPLATE_STATUSES } from "../constants";
5
5
  import { type TemplateResourceRow, templateResourcesTable } from "../table";
6
6
 
@@ -6,7 +6,7 @@ import {
6
6
  type TenantId,
7
7
  } from "@cosmicdrift/kumiko-framework/engine";
8
8
  import { writeFailure } from "@cosmicdrift/kumiko-framework/errors";
9
- import { z } from "zod";
9
+ import * as z from "zod";
10
10
  import { TEMPLATE_KINDS, TEXT_BLOCK_KIND } from "../constants";
11
11
  import { type TemplateResourceRow, templateResourcesTable } from "../table";
12
12
  import { contentFormatSchema, executor, folderSchema, localeSchema, slugSchema } from "./shared";
@@ -1,5 +1,5 @@
1
1
  import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
2
- import { z } from "zod";
2
+ import * as z from "zod";
3
3
  import { CONTENT_FORMATS, TEMPLATE_STATUSES, UPSERT_KINDS } from "../constants";
4
4
  import { templateResourceEntity, templateResourcesTable } from "../table";
5
5