@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.
- package/package.json +1 -1
- package/packages/bundled-features/package.json +10 -10
- package/packages/bundled-features/src/auth-email-password/changes.json +6 -0
- package/packages/bundled-features/src/auth-email-password/mail-notifications.ts +11 -47
- package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +9 -1
- package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -0
- package/packages/bundled-features/src/auth-email-password/web/invite-accept-screen.tsx +10 -41
- package/packages/bundled-features/src/auth-email-password/web/tenant-label.ts +15 -0
- package/packages/bundled-features/src/auth-email-password/web/tenant-menu-items.tsx +2 -7
- package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +7 -12
- package/packages/bundled-features/src/auth-email-password/web/use-redirect-authed-from-login.ts +39 -0
- package/packages/bundled-features/src/auth-foundation/feature.ts +8 -21
- package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
- package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +9 -15
- package/packages/bundled-features/src/auth-mfa/hmac-token-codec.ts +17 -14
- package/packages/bundled-features/src/auth-mfa/mfa-challenge-token.ts +6 -8
- package/packages/bundled-features/src/auth-mfa/mfa-preauth-setup-token.ts +6 -8
- package/packages/bundled-features/src/auth-mfa/mfa-setup-token.ts +16 -57
- package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +3 -13
- package/packages/bundled-features/src/billing-foundation/feature.ts +1 -5
- package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +2 -8
- package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +2 -8
- package/packages/bundled-features/src/billing-foundation/index.ts +8 -0
- package/packages/bundled-features/src/billing-foundation/projection.ts +19 -33
- package/packages/bundled-features/src/billing-foundation/provider-event-seen.ts +14 -0
- package/packages/bundled-features/src/billing-foundation/provider-shared.ts +61 -0
- package/packages/bundled-features/src/billing-foundation/tenant-destroy-hook.ts +8 -4
- package/packages/bundled-features/src/channel-email/feature.ts +1 -1
- package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +9 -15
- package/packages/bundled-features/src/delivery/delivery-service.ts +2 -10
- package/packages/bundled-features/src/file-derivatives/feature.ts +9 -21
- package/packages/bundled-features/src/file-foundation/feature.ts +2 -6
- package/packages/bundled-features/src/files-tenant-data/hooks.ts +1 -6
- package/packages/bundled-features/src/folders/feature.ts +2 -8
- package/packages/bundled-features/src/folders/web/folder-manager.tsx +7 -32
- package/packages/bundled-features/src/folders/web/folder-section.tsx +5 -25
- package/packages/bundled-features/src/form-draft/handlers/save.write.ts +6 -16
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +2 -6
- package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +5 -13
- package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +9 -19
- package/packages/bundled-features/src/jobs/handlers/tenant-failures.query.ts +1 -15
- package/packages/bundled-features/src/jobs/handlers/tenant-runs.query.ts +1 -14
- package/packages/bundled-features/src/jobs/job-run-logger.ts +37 -40
- package/packages/bundled-features/src/jobs/parse-subject.ts +15 -0
- package/packages/bundled-features/src/ledger/feature.ts +2 -7
- package/packages/bundled-features/src/mail-foundation/feature.ts +3 -7
- package/packages/bundled-features/src/managed-pages/render-page-body.ts +4 -12
- package/packages/bundled-features/src/notes-history/feature.ts +7 -8
- package/packages/bundled-features/src/personal-access-tokens/handlers/list.query.ts +1 -9
- package/packages/bundled-features/src/personal-access-tokens/hash.ts +2 -2
- package/packages/bundled-features/src/personal-access-tokens/parse-scope-names.ts +9 -0
- package/packages/bundled-features/src/personal-access-tokens/resolver.ts +1 -9
- package/packages/bundled-features/src/renderer-foundation/feature.ts +3 -16
- package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +13 -19
- package/packages/bundled-features/src/shared/changes.json +6 -0
- package/packages/bundled-features/src/shared/collect-extension-options.ts +14 -0
- package/packages/bundled-features/src/shared/hmac-signature.ts +15 -0
- package/packages/bundled-features/src/shared/index.ts +6 -0
- package/packages/bundled-features/src/shared/is-unique-constraint-failure.ts +11 -0
- package/packages/bundled-features/src/shared/mail-locale-templates.ts +64 -0
- package/packages/bundled-features/src/shared/resolve-feature-access.ts +16 -0
- package/packages/bundled-features/src/shared/signed-token.ts +4 -14
- package/packages/bundled-features/src/shared/single-use-token-store.ts +2 -2
- package/packages/bundled-features/src/shared/stream-tenant-derived-state.ts +5 -8
- package/packages/bundled-features/src/shared/tenant-db-cache.ts +19 -0
- package/packages/bundled-features/src/shared/web/status-banner.tsx +20 -0
- package/packages/bundled-features/src/shared/web/use-dispatched-writes.ts +31 -0
- package/packages/bundled-features/src/subscription-paddle/feature.ts +5 -17
- package/packages/bundled-features/src/subscription-paddle/price-methods.ts +7 -29
- package/packages/bundled-features/src/subscription-paddle/runtime.ts +6 -17
- package/packages/bundled-features/src/subscription-stripe/feature.ts +5 -19
- package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +5 -20
- package/packages/bundled-features/src/subscription-stripe/runtime.ts +3 -19
- package/packages/bundled-features/src/tags/feature.ts +2 -8
- package/packages/bundled-features/src/tags/web/tag-manager.tsx +5 -25
- package/packages/bundled-features/src/tags/web/tag-section.tsx +3 -18
- package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +3 -10
- package/packages/bundled-features/src/tenant/handlers/decrypt-member-users.ts +30 -0
- package/packages/bundled-features/src/tenant/handlers/members.query.ts +3 -23
- package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +8 -20
- package/packages/bundled-features/src/tenant-lifecycle/archive-and-delete-tenant-rows.ts +28 -0
- package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
- package/packages/bundled-features/src/tenant-lifecycle/index.ts +5 -0
- package/packages/bundled-features/src/tier-engine/feature.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/build-hook-db.ts +40 -0
- package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +2 -19
- package/packages/bundled-features/src/user-data-rights/mail-notifications.ts +11 -47
- package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +2 -35
- package/packages/bundled-features/src/user-data-rights/run-user-export.ts +2 -31
- package/packages/bundled-features/src/user-data-rights/token-helpers.ts +3 -15
- package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +1 -18
- package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +1 -18
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|