@cosmicdrift/kumiko-samples 0.404.1 → 0.405.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 (93) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +10 -10
  3. package/packages/bundled-features/src/auth-email-password/changes.json +6 -0
  4. package/packages/bundled-features/src/auth-email-password/mail-notifications.ts +11 -47
  5. package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +9 -1
  6. package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -0
  7. package/packages/bundled-features/src/auth-email-password/web/invite-accept-screen.tsx +10 -41
  8. package/packages/bundled-features/src/auth-email-password/web/tenant-label.ts +15 -0
  9. package/packages/bundled-features/src/auth-email-password/web/tenant-menu-items.tsx +2 -7
  10. package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +7 -12
  11. package/packages/bundled-features/src/auth-email-password/web/use-redirect-authed-from-login.ts +39 -0
  12. package/packages/bundled-features/src/auth-foundation/feature.ts +8 -21
  13. package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
  14. package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +9 -15
  15. package/packages/bundled-features/src/auth-mfa/hmac-token-codec.ts +17 -14
  16. package/packages/bundled-features/src/auth-mfa/mfa-challenge-token.ts +6 -8
  17. package/packages/bundled-features/src/auth-mfa/mfa-preauth-setup-token.ts +6 -8
  18. package/packages/bundled-features/src/auth-mfa/mfa-setup-token.ts +16 -57
  19. package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
  20. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +3 -13
  21. package/packages/bundled-features/src/billing-foundation/feature.ts +1 -5
  22. package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +2 -8
  23. package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +2 -8
  24. package/packages/bundled-features/src/billing-foundation/index.ts +8 -0
  25. package/packages/bundled-features/src/billing-foundation/projection.ts +19 -33
  26. package/packages/bundled-features/src/billing-foundation/provider-event-seen.ts +14 -0
  27. package/packages/bundled-features/src/billing-foundation/provider-shared.ts +61 -0
  28. package/packages/bundled-features/src/billing-foundation/tenant-destroy-hook.ts +8 -4
  29. package/packages/bundled-features/src/channel-email/feature.ts +1 -1
  30. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +9 -15
  31. package/packages/bundled-features/src/delivery/delivery-service.ts +2 -10
  32. package/packages/bundled-features/src/file-derivatives/feature.ts +9 -21
  33. package/packages/bundled-features/src/file-foundation/feature.ts +2 -6
  34. package/packages/bundled-features/src/files-tenant-data/hooks.ts +1 -6
  35. package/packages/bundled-features/src/folders/feature.ts +2 -8
  36. package/packages/bundled-features/src/folders/web/folder-manager.tsx +7 -32
  37. package/packages/bundled-features/src/folders/web/folder-section.tsx +5 -25
  38. package/packages/bundled-features/src/form-draft/handlers/save.write.ts +6 -16
  39. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +2 -6
  40. package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +5 -13
  41. package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +9 -19
  42. package/packages/bundled-features/src/jobs/handlers/tenant-failures.query.ts +1 -15
  43. package/packages/bundled-features/src/jobs/handlers/tenant-runs.query.ts +1 -14
  44. package/packages/bundled-features/src/jobs/job-run-logger.ts +37 -40
  45. package/packages/bundled-features/src/jobs/parse-subject.ts +15 -0
  46. package/packages/bundled-features/src/ledger/feature.ts +2 -7
  47. package/packages/bundled-features/src/mail-foundation/feature.ts +3 -7
  48. package/packages/bundled-features/src/managed-pages/render-page-body.ts +4 -12
  49. package/packages/bundled-features/src/notes-history/feature.ts +7 -8
  50. package/packages/bundled-features/src/personal-access-tokens/handlers/list.query.ts +1 -9
  51. package/packages/bundled-features/src/personal-access-tokens/hash.ts +2 -2
  52. package/packages/bundled-features/src/personal-access-tokens/parse-scope-names.ts +9 -0
  53. package/packages/bundled-features/src/personal-access-tokens/resolver.ts +1 -9
  54. package/packages/bundled-features/src/renderer-foundation/feature.ts +3 -16
  55. package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +13 -19
  56. package/packages/bundled-features/src/shared/changes.json +6 -0
  57. package/packages/bundled-features/src/shared/collect-extension-options.ts +14 -0
  58. package/packages/bundled-features/src/shared/hmac-signature.ts +15 -0
  59. package/packages/bundled-features/src/shared/index.ts +6 -0
  60. package/packages/bundled-features/src/shared/is-unique-constraint-failure.ts +11 -0
  61. package/packages/bundled-features/src/shared/mail-locale-templates.ts +64 -0
  62. package/packages/bundled-features/src/shared/resolve-feature-access.ts +16 -0
  63. package/packages/bundled-features/src/shared/signed-token.ts +4 -14
  64. package/packages/bundled-features/src/shared/single-use-token-store.ts +2 -2
  65. package/packages/bundled-features/src/shared/stream-tenant-derived-state.ts +5 -8
  66. package/packages/bundled-features/src/shared/tenant-db-cache.ts +19 -0
  67. package/packages/bundled-features/src/shared/web/status-banner.tsx +20 -0
  68. package/packages/bundled-features/src/shared/web/use-dispatched-writes.ts +31 -0
  69. package/packages/bundled-features/src/subscription-paddle/feature.ts +5 -17
  70. package/packages/bundled-features/src/subscription-paddle/price-methods.ts +7 -29
  71. package/packages/bundled-features/src/subscription-paddle/runtime.ts +6 -17
  72. package/packages/bundled-features/src/subscription-stripe/feature.ts +5 -19
  73. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +5 -20
  74. package/packages/bundled-features/src/subscription-stripe/runtime.ts +3 -19
  75. package/packages/bundled-features/src/tags/feature.ts +2 -8
  76. package/packages/bundled-features/src/tags/web/tag-manager.tsx +5 -25
  77. package/packages/bundled-features/src/tags/web/tag-section.tsx +3 -18
  78. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +3 -10
  79. package/packages/bundled-features/src/tenant/handlers/decrypt-member-users.ts +30 -0
  80. package/packages/bundled-features/src/tenant/handlers/members.query.ts +3 -23
  81. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +8 -20
  82. package/packages/bundled-features/src/tenant-lifecycle/archive-and-delete-tenant-rows.ts +28 -0
  83. package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
  84. package/packages/bundled-features/src/tenant-lifecycle/index.ts +5 -0
  85. package/packages/bundled-features/src/tier-engine/feature.ts +1 -1
  86. package/packages/bundled-features/src/user-data-rights/build-hook-db.ts +40 -0
  87. package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +2 -19
  88. package/packages/bundled-features/src/user-data-rights/mail-notifications.ts +11 -47
  89. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +2 -35
  90. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +2 -31
  91. package/packages/bundled-features/src/user-data-rights/token-helpers.ts +3 -15
  92. package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +1 -18
  93. package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +1 -18
@@ -1,4 +1,4 @@
1
- import { createFallbackLogger, type Logger } from "@cosmicdrift/kumiko-framework/logging";
1
+ import type { Logger } from "@cosmicdrift/kumiko-framework/logging";
2
2
  // Forget-cleanup runner — pure-function pipeline.
3
3
  //
4
4
  // After the grace period, this runner processes users in DeletionRequested
@@ -34,7 +34,6 @@ import {
34
34
  subjectIdToKey,
35
35
  } from "@cosmicdrift/kumiko-framework/crypto";
36
36
  import {
37
- createTenantDb,
38
37
  type DbRunner,
39
38
  entityEventName,
40
39
  executeRawQuery,
@@ -57,10 +56,6 @@ import {
57
56
  type UserDataStorageProvider,
58
57
  } from "@cosmicdrift/kumiko-framework/engine";
59
58
  import { runInSystemRowLevelSecurityScope } from "@cosmicdrift/kumiko-framework/internal/row-level-security";
60
- import {
61
- createEscapeHatchReporter,
62
- UNATTRIBUTED_ACTOR,
63
- } from "@cosmicdrift/kumiko-framework/pipeline";
64
59
  import {
65
60
  purgeSearchDocumentsForSubject,
66
61
  type SearchAdapter,
@@ -78,6 +73,7 @@ import {
78
73
  } from "../shared/index.ts";
79
74
  import { tenantMembershipsTable } from "../tenant/index.ts";
80
75
  import { USER_STATUS, userTable } from "../user/index.ts";
76
+ import { buildHookDb } from "./build-hook-db.ts";
81
77
  import { selectUsersDueForForgetCleanup } from "./db/queries/forget-cleanup.ts";
82
78
  import { updateUserLifecycle } from "./lib/update-user-lifecycle.ts";
83
79
 
@@ -205,35 +201,6 @@ interface HookEntry {
205
201
  readonly escapeHatchReason: string | undefined;
206
202
  }
207
203
 
208
- function buildHookDb(
209
- db: DbRunner,
210
- tenantId: TenantId,
211
- entry: HookEntry,
212
- args: {
213
- readonly escapeHatchAuditSink?: EscapeHatchAuditSink;
214
- readonly escapeHatchAuditLog?: Logger;
215
- readonly actor?: string;
216
- },
217
- ) {
218
- const report = createEscapeHatchReporter({
219
- handler: `${EXT_USER_DATA}:${entry.entityName}`,
220
- tenantId,
221
- actor: args.actor ?? UNATTRIBUTED_ACTOR,
222
- sink: args.escapeHatchAuditSink,
223
- log: args.escapeHatchAuditLog ?? createFallbackLogger("user-data-rights"),
224
- });
225
- return createTenantDb({
226
- db,
227
- tenantId,
228
- mode: "tenant",
229
- grants: {
230
- unsafeRaw:
231
- entry.escapeHatchReason !== undefined ? { reason: entry.escapeHatchReason } : undefined,
232
- report,
233
- },
234
- });
235
- }
236
-
237
204
  // EXT_USER_DATA delete-hooks default here; a hook that redacts data keyed on an
238
205
  // owner column it doesn't own must register a lower order so it runs BEFORE any
239
206
  // hook that nulls that column. See custom-fields wire-user-data-rights.ts.
@@ -1,4 +1,4 @@
1
- import { createFallbackLogger, type Logger } from "@cosmicdrift/kumiko-framework/logging";
1
+ import type { Logger } from "@cosmicdrift/kumiko-framework/logging";
2
2
  // User data export pipeline — GDPR Art. 15 (access) +
3
3
  // Art. 20 (data portability).
4
4
  //
@@ -29,7 +29,6 @@ import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
29
29
  import {
30
30
  collectEncryptedFieldNames,
31
31
  configuredEntityFieldEncryption,
32
- createTenantDb,
33
32
  decryptEntityFieldValues,
34
33
  selectMany,
35
34
  } from "@cosmicdrift/kumiko-framework/db";
@@ -44,12 +43,9 @@ import {
44
43
  type UserDataExportSnippet,
45
44
  } from "@cosmicdrift/kumiko-framework/engine";
46
45
  import { runInSystemRowLevelSecurityScope } from "@cosmicdrift/kumiko-framework/internal/row-level-security";
47
- import {
48
- createEscapeHatchReporter,
49
- UNATTRIBUTED_ACTOR,
50
- } from "@cosmicdrift/kumiko-framework/pipeline";
51
46
  import type { getTemporal } from "@cosmicdrift/kumiko-framework/time";
52
47
  import { tenantMembershipsTable } from "../tenant/index.ts";
48
+ import { buildHookDb } from "./build-hook-db.ts";
53
49
  import { buildFileRefZipPath } from "./zip-path.ts";
54
50
 
55
51
  type Instant = InstanceType<ReturnType<typeof getTemporal>["Instant"]>;
@@ -108,31 +104,6 @@ interface HookEntry {
108
104
  readonly escapeHatchReason: string | undefined;
109
105
  }
110
106
 
111
- function buildHookDb(
112
- db: DbRunner,
113
- tenantId: TenantId,
114
- entry: HookEntry,
115
- args: Pick<RunUserExportArgs, "escapeHatchAuditSink" | "escapeHatchAuditLog" | "actor">,
116
- ) {
117
- const report = createEscapeHatchReporter({
118
- handler: `${EXT_USER_DATA}:${entry.entityName}`,
119
- tenantId,
120
- actor: args.actor ?? UNATTRIBUTED_ACTOR,
121
- sink: args.escapeHatchAuditSink,
122
- log: args.escapeHatchAuditLog ?? createFallbackLogger("user-data-rights"),
123
- });
124
- return createTenantDb({
125
- db,
126
- tenantId,
127
- mode: "tenant",
128
- grants: {
129
- unsafeRaw:
130
- entry.escapeHatchReason !== undefined ? { reason: entry.escapeHatchReason } : undefined,
131
- report,
132
- },
133
- });
134
- }
135
-
136
107
  /**
137
108
  * Pure function: invokes all EXT_USER_DATA hooks for each tenant
138
109
  * membership and collects snippets into a UserExportBundle.
@@ -13,10 +13,8 @@
13
13
  // **Multi-use within TTL:** The token is NOT "consumed" on download, so the user
14
14
  // can download repeatedly until expiresAt. This matches Google-Takeout (7d) and
15
15
  // Facebook-Data-Download (4d).
16
- //
17
- // **Universal Web-Crypto API:** crypto.getRandomValues + crypto.subtle.digest
18
- // runs identically in Bun, Node 19+, and browsers, avoiding platform-specific
19
- // imports.
16
+
17
+ import { hashOpaqueToken } from "@cosmicdrift/kumiko-framework/crypto";
20
18
 
21
19
  /**
22
20
  * Generates a new download token. The plain token is sent to the user by email;
@@ -41,9 +39,7 @@ export async function generateDownloadToken(): Promise<{
41
39
  * database (no constant-time comparison, see the header comment).
42
40
  */
43
41
  export async function hashDownloadToken(plain: string): Promise<string> {
44
- const encoded = new TextEncoder().encode(plain);
45
- const digest = await crypto.subtle.digest("SHA-256", encoded);
46
- return uint8ArrayToHex(new Uint8Array(digest));
42
+ return hashOpaqueToken(plain);
47
43
  }
48
44
 
49
45
  function uint8ArrayToBase64Url(bytes: Uint8Array): string {
@@ -54,11 +50,3 @@ function uint8ArrayToBase64Url(bytes: Uint8Array): string {
54
50
  }
55
51
  return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
56
52
  }
57
-
58
- function uint8ArrayToHex(bytes: Uint8Array): string {
59
- let out = "";
60
- for (let i = 0; i < bytes.length; i++) {
61
- out += (bytes[i] as number).toString(16).padStart(2, "0"); // @cast-boundary dynamic-key
62
- }
63
- return out;
64
- }
@@ -19,6 +19,7 @@ import {
19
19
  import { postWithDownload } from "@cosmicdrift/kumiko-renderer/web";
20
20
  import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
21
21
  import { type ReactNode, useEffect, useState } from "react";
22
+ import { type SectionStatus, StatusBanner } from "../../shared/web/status-banner.tsx";
22
23
  import {
23
24
  EXPORT_JOB_STATUS,
24
25
  type ExportJobStatus,
@@ -41,12 +42,6 @@ type ExportStatusResult =
41
42
  | { readonly hasJob: false }
42
43
  | { readonly hasJob: true; readonly job: ExportJob };
43
44
 
44
- type SectionStatus =
45
- | { kind: "idle" }
46
- | { kind: "submitting" }
47
- | { kind: "success"; messageKey: string }
48
- | { kind: "error"; messageKey: string };
49
-
50
45
  // Dispatcher failures include i18nKey only when the handler sets one; read it
51
46
  // at the boundary with a generic fallback.
52
47
  function failureKey(error: unknown): string {
@@ -63,18 +58,6 @@ export function formatDate(iso: string | null | undefined): string {
63
58
  return tIndex > 0 ? iso.slice(0, tIndex) : iso;
64
59
  }
65
60
 
66
- function StatusBanner({ status }: { readonly status: SectionStatus }): ReactNode {
67
- const t = useTranslation();
68
- const { Banner } = usePrimitives();
69
- if (status.kind === "success") {
70
- return <Banner variant="info">{t(status.messageKey)}</Banner>;
71
- }
72
- if (status.kind === "error") {
73
- return <Banner variant="error">{t(status.messageKey)}</Banner>;
74
- }
75
- return null;
76
- }
77
-
78
61
  // Mounted by the renderer's ExtensionSectionMount (already wrapped in
79
62
  // <Section title={...} testId="section-extension-...">) — takes no props of
80
63
  // its own, ExtensionSectionProps (entityName/entityId/...) are unused since
@@ -16,14 +16,9 @@ import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
16
16
  import { type ReactNode, useState } from "react";
17
17
  import { AuthHandlers } from "../../auth-email-password/web/constants.ts";
18
18
  import { requestEmailVerification } from "../../auth-email-password/web/index.ts";
19
+ import { type SectionStatus, StatusBanner } from "../../shared/web/status-banner.tsx";
19
20
  import { UserProfileHandlers } from "./constants.ts";
20
21
 
21
- type SectionStatus =
22
- | { kind: "idle" }
23
- | { kind: "submitting" }
24
- | { kind: "success"; messageKey: string }
25
- | { kind: "error"; messageKey: string };
26
-
27
22
  // Dispatcher failures carry an i18nKey only when the handler sets one —
28
23
  // boundary read with a generic fallback.
29
24
  function failureKey(error: unknown): string {
@@ -31,18 +26,6 @@ function failureKey(error: unknown): string {
31
26
  return typeof key === "string" ? key : "profile.errors.generic";
32
27
  }
33
28
 
34
- function StatusBanner({ status }: { readonly status: SectionStatus }): ReactNode {
35
- const t = useTranslation();
36
- const { Banner } = usePrimitives();
37
- if (status.kind === "success") {
38
- return <Banner variant="info">{t(status.messageKey)}</Banner>;
39
- }
40
- if (status.kind === "error") {
41
- return <Banner variant="error">{t(status.messageKey)}</Banner>;
42
- }
43
- return null;
44
- }
45
-
46
29
  // Mounted by the renderer's ExtensionSectionMount (already wrapped in
47
30
  // <Section title={...} testId="section-extension-...">) — takes no props of
48
31
  // its own. Deliberately NOT a <Form>: RenderEdit already renders a host