@cosmicdrift/kumiko-bundled-features 0.371.1 → 0.373.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/dist/auth-mfa/db/queries.d.ts +3 -2
- package/dist/auth-mfa/db/queries.js +2 -5
- package/dist/auth-mfa/schema/user-mfa.d.ts +10 -10
- package/dist/billing-foundation/entities.d.ts +10 -10
- package/dist/billing-foundation/projection.d.ts +10 -10
- package/dist/cap-counter/entity.d.ts +4 -4
- package/dist/cap-overview/web/cap-cards-panel.js +2 -1
- package/dist/compliance-profiles/schema/profile-selection.d.ts +4 -4
- package/dist/config/table.d.ts +6 -6
- package/dist/config/web/index.d.ts +1 -0
- package/dist/config/web/index.js +1 -0
- package/dist/crypto-shredding/handlers/forget-subject.write.js +55 -30
- package/dist/crypto-shredding/resolve-file-bytes-deleter.d.ts +3 -0
- package/dist/crypto-shredding/resolve-file-bytes-deleter.js +24 -0
- package/dist/custom-fields/entity.d.ts +9 -7
- package/dist/custom-fields/executor.d.ts +19 -1
- package/dist/data-retention/index.d.ts +1 -0
- package/dist/data-retention/index.js +1 -0
- package/dist/data-retention/run-retention-cleanup.js +27 -159
- package/dist/data-retention/schema/tenant-retention-override.d.ts +6 -6
- package/dist/delivery/delivery-service.d.ts +2 -1
- package/dist/delivery/delivery-service.js +3 -2
- package/dist/delivery/handlers/unsubscribe-page-chrome.query.js +2 -2
- package/dist/delivery/index.d.ts +1 -1
- package/dist/delivery/index.js +1 -1
- package/dist/delivery/jobs.js +21 -7
- package/dist/delivery/recipient-address-seal.d.ts +13 -0
- package/dist/delivery/recipient-address-seal.js +53 -0
- package/dist/delivery/tables.d.ts +8 -7
- package/dist/delivery/testing.d.ts +2 -1
- package/dist/delivery/testing.js +1 -0
- package/dist/delivery/unsubscribe.d.ts +13 -2
- package/dist/delivery/unsubscribe.js +9 -1
- package/dist/document-ingest-foundation/entity.d.ts +8 -8
- package/dist/document-ingest-foundation/executor.d.ts +16 -1
- package/dist/file-foundation/read-file-ref-content.js +2 -2
- package/dist/folders/entity.d.ts +8 -8
- package/dist/folders/executor.d.ts +29 -2
- package/dist/form-draft/entity.d.ts +3 -3
- package/dist/form-draft/executor.d.ts +15 -1
- package/dist/inbound-mail-foundation/entities.d.ts +31 -31
- package/dist/inbound-mail-foundation/projection.d.ts +24 -24
- package/dist/jobs/job-run-table.d.ts +10 -10
- package/dist/ledger/entity.d.ts +21 -21
- package/dist/ledger/executor.d.ts +57 -3
- package/dist/managed-pages/table.d.ts +16 -14
- package/dist/notes-history/entity.d.ts +14 -14
- package/dist/notes-history/executor.d.ts +31 -2
- package/dist/personal-access-tokens/schema/api-token.d.ts +9 -9
- package/dist/personal-access-tokens/screens.js +14 -9
- package/dist/secrets/table.d.ts +2 -2
- package/dist/sessions/schema/user-session.d.ts +8 -8
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +2 -0
- package/dist/shared/purge-files-reaching-subject.d.ts +25 -0
- package/dist/shared/purge-files-reaching-subject.js +146 -0
- package/dist/shared/purge-row-file-refs.d.ts +33 -0
- package/dist/shared/purge-row-file-refs.js +152 -0
- package/dist/tags/entity.d.ts +9 -9
- package/dist/tags/executor.d.ts +30 -2
- package/dist/template-resolver/handlers/shared.d.ts +28 -1
- package/dist/template-resolver/table.d.ts +32 -32
- package/dist/template-resolver/template-preview.js +13 -4
- package/dist/template-resolver/user-content-table.d.ts +16 -16
- package/dist/template-resolver/web/client-plugin.js +2 -1
- package/dist/template-resolver/web/document-editor-extensions.d.ts +1 -1
- package/dist/template-resolver/web/document-editor-extensions.js +2 -5
- package/dist/template-resolver/web/placeholder-line-editor.js +2 -2
- package/dist/tenant/handlers/list.query.d.ts +21 -1
- package/dist/tenant/invitation-table.d.ts +14 -14
- package/dist/tenant/membership-table.d.ts +4 -4
- package/dist/tenant/schema/tenant.d.ts +20 -18
- package/dist/tier-engine/entity.d.ts +2 -2
- package/dist/tier-engine/tier-resolver.d.ts +2 -2
- package/dist/user/handlers/me.query.d.ts +21 -0
- package/dist/user/schema/user.d.ts +24 -22
- package/dist/user-data-rights/run-export-jobs.d.ts +20 -1
- package/dist/user-data-rights/run-forget-cleanup.js +35 -1
- package/dist/user-data-rights/schema/download-attempt.d.ts +16 -16
- package/dist/user-data-rights/schema/download-token.d.ts +16 -16
- package/dist/user-data-rights/schema/export-job.d.ts +20 -20
- package/dist/user-data-rights/web/privacy-center-screen.js +2 -1
- package/dist/waitlist/entity.d.ts +24 -24
- package/dist/waitlist/lib.d.ts +24 -1
- package/package.json +11 -11
- package/src/crypto-shredding/changes.json +6 -0
- package/src/data-retention/changes.json +6 -0
- package/src/delivery/changes.json +13 -0
- package/src/files/changes.json +7 -0
- package/src/personal-access-tokens/changes.json +12 -0
- package/src/template-resolver/changes.json +6 -0
- package/src/user-data-rights/changes.json +6 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type TenantDb } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import type { SessionUser } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
+
import type { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
3
4
|
export type UserMfaRow = {
|
|
4
5
|
readonly id: string;
|
|
5
6
|
readonly version: number;
|
|
@@ -8,7 +9,7 @@ export type UserMfaRow = {
|
|
|
8
9
|
readonly recoveryCodes: {
|
|
9
10
|
readonly hashes: readonly string[];
|
|
10
11
|
};
|
|
11
|
-
readonly enabledAt:
|
|
12
|
-
readonly lastUsedAt:
|
|
12
|
+
readonly enabledAt: Temporal.Instant;
|
|
13
|
+
readonly lastUsedAt: Temporal.Instant | null;
|
|
13
14
|
};
|
|
14
15
|
export declare function findUserMfaRow(db: TenantDb, user: SessionUser): Promise<UserMfaRow | null>;
|
|
@@ -22,9 +22,6 @@ export async function findUserMfaRow(db, user) {
|
|
|
22
22
|
const detail = await executor.detail({ id: idLookup.id }, user, db);
|
|
23
23
|
if (!detail)
|
|
24
24
|
return null;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const row = detail;
|
|
28
|
-
const recoveryCodes = parseJsonOrThrow(row.recoveryCodes, "user-mfa.recoveryCodes");
|
|
29
|
-
return { ...row, recoveryCodes };
|
|
25
|
+
const recoveryCodes = parseJsonOrThrow(detail.recoveryCodes, "user-mfa.recoveryCodes");
|
|
26
|
+
return { ...detail, recoveryCodes };
|
|
30
27
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const userMfaEntity: import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
2
|
-
userId: {
|
|
2
|
+
readonly userId: {
|
|
3
3
|
readonly type: "text";
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
@@ -22,7 +22,7 @@ export declare const userMfaEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
22
22
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
23
23
|
required: true;
|
|
24
24
|
};
|
|
25
|
-
totpSecret: {
|
|
25
|
+
readonly totpSecret: {
|
|
26
26
|
readonly type: "text";
|
|
27
27
|
readonly description?: string;
|
|
28
28
|
readonly maxLength?: number;
|
|
@@ -45,7 +45,7 @@ export declare const userMfaEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
45
45
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
46
46
|
required: true;
|
|
47
47
|
};
|
|
48
|
-
recoveryCodes: {
|
|
48
|
+
readonly recoveryCodes: {
|
|
49
49
|
readonly type: "text";
|
|
50
50
|
readonly description?: string;
|
|
51
51
|
readonly maxLength?: number;
|
|
@@ -68,7 +68,7 @@ export declare const userMfaEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
68
68
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
69
69
|
required: true;
|
|
70
70
|
};
|
|
71
|
-
enabledAt: {
|
|
71
|
+
readonly enabledAt: {
|
|
72
72
|
readonly type: "timestamp";
|
|
73
73
|
readonly description?: string;
|
|
74
74
|
readonly required?: boolean;
|
|
@@ -83,7 +83,7 @@ export declare const userMfaEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
83
83
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
84
84
|
required: true;
|
|
85
85
|
};
|
|
86
|
-
lastUsedAt: {
|
|
86
|
+
readonly lastUsedAt: {
|
|
87
87
|
readonly type: "timestamp";
|
|
88
88
|
readonly description?: string;
|
|
89
89
|
readonly required?: boolean;
|
|
@@ -100,7 +100,7 @@ export declare const userMfaEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
100
100
|
};
|
|
101
101
|
}, "tenant">;
|
|
102
102
|
export declare const userMfaTable: import("@cosmicdrift/kumiko-framework/db").EntityTable<import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
103
|
-
userId: {
|
|
103
|
+
readonly userId: {
|
|
104
104
|
readonly type: "text";
|
|
105
105
|
readonly description?: string;
|
|
106
106
|
readonly maxLength?: number;
|
|
@@ -123,7 +123,7 @@ export declare const userMfaTable: import("@cosmicdrift/kumiko-framework/db").En
|
|
|
123
123
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
124
124
|
required: true;
|
|
125
125
|
};
|
|
126
|
-
totpSecret: {
|
|
126
|
+
readonly totpSecret: {
|
|
127
127
|
readonly type: "text";
|
|
128
128
|
readonly description?: string;
|
|
129
129
|
readonly maxLength?: number;
|
|
@@ -146,7 +146,7 @@ export declare const userMfaTable: import("@cosmicdrift/kumiko-framework/db").En
|
|
|
146
146
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
147
147
|
required: true;
|
|
148
148
|
};
|
|
149
|
-
recoveryCodes: {
|
|
149
|
+
readonly recoveryCodes: {
|
|
150
150
|
readonly type: "text";
|
|
151
151
|
readonly description?: string;
|
|
152
152
|
readonly maxLength?: number;
|
|
@@ -169,7 +169,7 @@ export declare const userMfaTable: import("@cosmicdrift/kumiko-framework/db").En
|
|
|
169
169
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
170
170
|
required: true;
|
|
171
171
|
};
|
|
172
|
-
enabledAt: {
|
|
172
|
+
readonly enabledAt: {
|
|
173
173
|
readonly type: "timestamp";
|
|
174
174
|
readonly description?: string;
|
|
175
175
|
readonly required?: boolean;
|
|
@@ -184,7 +184,7 @@ export declare const userMfaTable: import("@cosmicdrift/kumiko-framework/db").En
|
|
|
184
184
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
185
185
|
required: true;
|
|
186
186
|
};
|
|
187
|
-
lastUsedAt: {
|
|
187
|
+
readonly lastUsedAt: {
|
|
188
188
|
readonly type: "timestamp";
|
|
189
189
|
readonly description?: string;
|
|
190
190
|
readonly required?: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const subscriptionEntity: import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
2
|
-
providerName: {
|
|
2
|
+
readonly providerName: {
|
|
3
3
|
readonly type: "text";
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
@@ -22,7 +22,7 @@ export declare const subscriptionEntity: import("@cosmicdrift/kumiko-types/field
|
|
|
22
22
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
23
23
|
required: true;
|
|
24
24
|
};
|
|
25
|
-
providerCustomerId: {
|
|
25
|
+
readonly providerCustomerId: {
|
|
26
26
|
readonly type: "text";
|
|
27
27
|
readonly description?: string;
|
|
28
28
|
readonly maxLength?: number;
|
|
@@ -45,7 +45,7 @@ export declare const subscriptionEntity: import("@cosmicdrift/kumiko-types/field
|
|
|
45
45
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
46
46
|
required: true;
|
|
47
47
|
};
|
|
48
|
-
providerSubscriptionId: {
|
|
48
|
+
readonly providerSubscriptionId: {
|
|
49
49
|
readonly type: "text";
|
|
50
50
|
readonly description?: string;
|
|
51
51
|
readonly maxLength?: number;
|
|
@@ -68,7 +68,7 @@ export declare const subscriptionEntity: import("@cosmicdrift/kumiko-types/field
|
|
|
68
68
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
69
69
|
required: true;
|
|
70
70
|
};
|
|
71
|
-
status: {
|
|
71
|
+
readonly status: {
|
|
72
72
|
readonly type: "text";
|
|
73
73
|
readonly description?: string;
|
|
74
74
|
readonly maxLength?: number;
|
|
@@ -91,7 +91,7 @@ export declare const subscriptionEntity: import("@cosmicdrift/kumiko-types/field
|
|
|
91
91
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
92
92
|
required: true;
|
|
93
93
|
};
|
|
94
|
-
tier: {
|
|
94
|
+
readonly tier: {
|
|
95
95
|
readonly type: "text";
|
|
96
96
|
readonly description?: string;
|
|
97
97
|
readonly maxLength?: number;
|
|
@@ -114,7 +114,7 @@ export declare const subscriptionEntity: import("@cosmicdrift/kumiko-types/field
|
|
|
114
114
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
115
115
|
required: true;
|
|
116
116
|
};
|
|
117
|
-
currentPeriodEnd: {
|
|
117
|
+
readonly currentPeriodEnd: {
|
|
118
118
|
readonly type: "timestamp";
|
|
119
119
|
readonly description?: string;
|
|
120
120
|
readonly required?: boolean;
|
|
@@ -129,7 +129,7 @@ export declare const subscriptionEntity: import("@cosmicdrift/kumiko-types/field
|
|
|
129
129
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
130
130
|
required: true;
|
|
131
131
|
};
|
|
132
|
-
cancelAt: {
|
|
132
|
+
readonly cancelAt: {
|
|
133
133
|
readonly type: "timestamp";
|
|
134
134
|
readonly description?: string;
|
|
135
135
|
readonly required?: boolean;
|
|
@@ -147,7 +147,7 @@ export declare const subscriptionEntity: import("@cosmicdrift/kumiko-types/field
|
|
|
147
147
|
}, "tenant">;
|
|
148
148
|
export declare const SUBSCRIPTION_PII_FIELDS: readonly string[];
|
|
149
149
|
export declare const paymentEntity: import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
150
|
-
providerName: {
|
|
150
|
+
readonly providerName: {
|
|
151
151
|
readonly type: "text";
|
|
152
152
|
readonly description?: string;
|
|
153
153
|
readonly maxLength?: number;
|
|
@@ -170,7 +170,7 @@ export declare const paymentEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
170
170
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
171
171
|
required: true;
|
|
172
172
|
};
|
|
173
|
-
providerCustomerId: {
|
|
173
|
+
readonly providerCustomerId: {
|
|
174
174
|
readonly type: "text";
|
|
175
175
|
readonly description?: string;
|
|
176
176
|
readonly maxLength?: number;
|
|
@@ -193,7 +193,7 @@ export declare const paymentEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
193
193
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
194
194
|
required: true;
|
|
195
195
|
};
|
|
196
|
-
priceId: {
|
|
196
|
+
readonly priceId: {
|
|
197
197
|
readonly type: "text";
|
|
198
198
|
readonly description?: string;
|
|
199
199
|
readonly maxLength?: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const subscriptionsProjectionTable: import("@cosmicdrift/kumiko-framework/db").EntityTable<import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
2
|
-
providerName: {
|
|
2
|
+
readonly providerName: {
|
|
3
3
|
readonly type: "text";
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
@@ -22,7 +22,7 @@ export declare const subscriptionsProjectionTable: import("@cosmicdrift/kumiko-f
|
|
|
22
22
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
23
23
|
required: true;
|
|
24
24
|
};
|
|
25
|
-
providerCustomerId: {
|
|
25
|
+
readonly providerCustomerId: {
|
|
26
26
|
readonly type: "text";
|
|
27
27
|
readonly description?: string;
|
|
28
28
|
readonly maxLength?: number;
|
|
@@ -45,7 +45,7 @@ export declare const subscriptionsProjectionTable: import("@cosmicdrift/kumiko-f
|
|
|
45
45
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
46
46
|
required: true;
|
|
47
47
|
};
|
|
48
|
-
providerSubscriptionId: {
|
|
48
|
+
readonly providerSubscriptionId: {
|
|
49
49
|
readonly type: "text";
|
|
50
50
|
readonly description?: string;
|
|
51
51
|
readonly maxLength?: number;
|
|
@@ -68,7 +68,7 @@ export declare const subscriptionsProjectionTable: import("@cosmicdrift/kumiko-f
|
|
|
68
68
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
69
69
|
required: true;
|
|
70
70
|
};
|
|
71
|
-
status: {
|
|
71
|
+
readonly status: {
|
|
72
72
|
readonly type: "text";
|
|
73
73
|
readonly description?: string;
|
|
74
74
|
readonly maxLength?: number;
|
|
@@ -91,7 +91,7 @@ export declare const subscriptionsProjectionTable: import("@cosmicdrift/kumiko-f
|
|
|
91
91
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
92
92
|
required: true;
|
|
93
93
|
};
|
|
94
|
-
tier: {
|
|
94
|
+
readonly tier: {
|
|
95
95
|
readonly type: "text";
|
|
96
96
|
readonly description?: string;
|
|
97
97
|
readonly maxLength?: number;
|
|
@@ -114,7 +114,7 @@ export declare const subscriptionsProjectionTable: import("@cosmicdrift/kumiko-f
|
|
|
114
114
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
115
115
|
required: true;
|
|
116
116
|
};
|
|
117
|
-
currentPeriodEnd: {
|
|
117
|
+
readonly currentPeriodEnd: {
|
|
118
118
|
readonly type: "timestamp";
|
|
119
119
|
readonly description?: string;
|
|
120
120
|
readonly required?: boolean;
|
|
@@ -129,7 +129,7 @@ export declare const subscriptionsProjectionTable: import("@cosmicdrift/kumiko-f
|
|
|
129
129
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
130
130
|
required: true;
|
|
131
131
|
};
|
|
132
|
-
cancelAt: {
|
|
132
|
+
readonly cancelAt: {
|
|
133
133
|
readonly type: "timestamp";
|
|
134
134
|
readonly description?: string;
|
|
135
135
|
readonly required?: boolean;
|
|
@@ -146,7 +146,7 @@ export declare const subscriptionsProjectionTable: import("@cosmicdrift/kumiko-f
|
|
|
146
146
|
};
|
|
147
147
|
}, "tenant">>;
|
|
148
148
|
export declare const paymentsProjectionTable: import("@cosmicdrift/kumiko-framework/db").EntityTable<import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
149
|
-
providerName: {
|
|
149
|
+
readonly providerName: {
|
|
150
150
|
readonly type: "text";
|
|
151
151
|
readonly description?: string;
|
|
152
152
|
readonly maxLength?: number;
|
|
@@ -169,7 +169,7 @@ export declare const paymentsProjectionTable: import("@cosmicdrift/kumiko-framew
|
|
|
169
169
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
170
170
|
required: true;
|
|
171
171
|
};
|
|
172
|
-
providerCustomerId: {
|
|
172
|
+
readonly providerCustomerId: {
|
|
173
173
|
readonly type: "text";
|
|
174
174
|
readonly description?: string;
|
|
175
175
|
readonly maxLength?: number;
|
|
@@ -192,7 +192,7 @@ export declare const paymentsProjectionTable: import("@cosmicdrift/kumiko-framew
|
|
|
192
192
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
193
193
|
required: true;
|
|
194
194
|
};
|
|
195
|
-
priceId: {
|
|
195
|
+
readonly priceId: {
|
|
196
196
|
readonly type: "text";
|
|
197
197
|
readonly description?: string;
|
|
198
198
|
readonly maxLength?: number;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const capCounterEntity: import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
2
|
-
capName: {
|
|
2
|
+
readonly capName: {
|
|
3
3
|
readonly type: "text";
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
@@ -22,7 +22,7 @@ export declare const capCounterEntity: import("@cosmicdrift/kumiko-types/fields"
|
|
|
22
22
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
23
23
|
required: true;
|
|
24
24
|
};
|
|
25
|
-
value: {
|
|
25
|
+
readonly value: {
|
|
26
26
|
readonly type: "bigInt";
|
|
27
27
|
readonly description?: string;
|
|
28
28
|
readonly required?: boolean;
|
|
@@ -34,7 +34,7 @@ export declare const capCounterEntity: import("@cosmicdrift/kumiko-types/fields"
|
|
|
34
34
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
35
35
|
required: true;
|
|
36
36
|
};
|
|
37
|
-
periodStart: {
|
|
37
|
+
readonly periodStart: {
|
|
38
38
|
readonly type: "timestamp";
|
|
39
39
|
readonly description?: string;
|
|
40
40
|
readonly required?: boolean;
|
|
@@ -49,7 +49,7 @@ export declare const capCounterEntity: import("@cosmicdrift/kumiko-types/fields"
|
|
|
49
49
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
50
50
|
required: true;
|
|
51
51
|
};
|
|
52
|
-
lastSoftWarnedAt: {
|
|
52
|
+
readonly lastSoftWarnedAt: {
|
|
53
53
|
readonly type: "timestamp";
|
|
54
54
|
readonly description?: string;
|
|
55
55
|
readonly required?: boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { EMPTY_VALUE_PLACEHOLDER } from "@cosmicdrift/kumiko-headless";
|
|
2
3
|
import { usePrimitives, useQuery, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
3
4
|
import { EmptyState, StatCard, StatusBadge, } from "@cosmicdrift/kumiko-renderer-web";
|
|
4
5
|
import { Database, FileText, Gauge, Hash, Mail, Users } from "lucide-react";
|
|
@@ -56,7 +57,7 @@ export function CapCardsPanel({ filterParams }) {
|
|
|
56
57
|
// wraps any defined child in a spacing div, so pass undefined then.
|
|
57
58
|
const body = !isMeasured(cap) || cap.limit !== null ? (_jsxs("div", { className: "flex flex-col gap-2", children: [cap.percent !== null && (_jsx("div", { className: "flex items-center justify-between gap-2", children: _jsx(StatusBadge, { tone: TONE_TO_STATUS[cap.tone], children: `${cap.percent}%` }) })), _jsx(CapUsageBar, { usage: cap, showLabel: false })] })) : undefined;
|
|
58
59
|
return (_jsx(StatCard, { icon: Icon !== undefined ? _jsx(Icon, { className: "size-4" }) : undefined, label: t(cap.label), value: !isMeasured(cap)
|
|
59
|
-
?
|
|
60
|
+
? EMPTY_VALUE_PLACEHOLDER
|
|
60
61
|
: cap.limit === null
|
|
61
62
|
? String(cap.used)
|
|
62
63
|
: `${cap.used} / ${cap.limit}`, ...(cap.accentColor !== undefined && { accentColor: cap.accentColor }), testId: "cap-card", children: body }, cap.id));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const tenantComplianceProfileEntity: import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
2
|
-
profileKey: {
|
|
2
|
+
readonly profileKey: {
|
|
3
3
|
readonly type: "select";
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly options: readonly ["eu-dsgvo", "swiss-dsg", "de-hr-dsgvo-hgb", "minimal-no-region"];
|
|
@@ -23,7 +23,7 @@ export declare const tenantComplianceProfileEntity: import("@cosmicdrift/kumiko-
|
|
|
23
23
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
24
24
|
required: true;
|
|
25
25
|
};
|
|
26
|
-
override: {
|
|
26
|
+
readonly override: {
|
|
27
27
|
readonly type: "longText";
|
|
28
28
|
readonly description?: string;
|
|
29
29
|
readonly maxLength?: number;
|
|
@@ -41,7 +41,7 @@ export declare const tenantComplianceProfileEntity: import("@cosmicdrift/kumiko-
|
|
|
41
41
|
};
|
|
42
42
|
}, "tenant">;
|
|
43
43
|
export declare const tenantComplianceProfileTable: import("@cosmicdrift/kumiko-framework/db").EntityTable<import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
44
|
-
profileKey: {
|
|
44
|
+
readonly profileKey: {
|
|
45
45
|
readonly type: "select";
|
|
46
46
|
readonly description?: string;
|
|
47
47
|
readonly options: readonly ["eu-dsgvo", "swiss-dsg", "de-hr-dsgvo-hgb", "minimal-no-region"];
|
|
@@ -65,7 +65,7 @@ export declare const tenantComplianceProfileTable: import("@cosmicdrift/kumiko-f
|
|
|
65
65
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
66
66
|
required: true;
|
|
67
67
|
};
|
|
68
|
-
override: {
|
|
68
|
+
readonly override: {
|
|
69
69
|
readonly type: "longText";
|
|
70
70
|
readonly description?: string;
|
|
71
71
|
readonly maxLength?: number;
|
package/dist/config/table.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const configValueEntity: import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
2
|
-
key: {
|
|
2
|
+
readonly key: {
|
|
3
3
|
readonly type: "text";
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
@@ -22,7 +22,7 @@ export declare const configValueEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
22
22
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
23
23
|
required: true;
|
|
24
24
|
};
|
|
25
|
-
value: {
|
|
25
|
+
readonly value: {
|
|
26
26
|
readonly type: "text";
|
|
27
27
|
readonly description?: string;
|
|
28
28
|
readonly maxLength?: number;
|
|
@@ -45,7 +45,7 @@ export declare const configValueEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
45
45
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
46
46
|
required: false;
|
|
47
47
|
};
|
|
48
|
-
userId: {
|
|
48
|
+
readonly userId: {
|
|
49
49
|
readonly type: "text";
|
|
50
50
|
readonly description?: string;
|
|
51
51
|
readonly maxLength?: number;
|
|
@@ -70,7 +70,7 @@ export declare const configValueEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
70
70
|
};
|
|
71
71
|
}, "tenant">;
|
|
72
72
|
export declare const configValuesTable: import("@cosmicdrift/kumiko-framework/db").EntityTable<import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
73
|
-
key: {
|
|
73
|
+
readonly key: {
|
|
74
74
|
readonly type: "text";
|
|
75
75
|
readonly description?: string;
|
|
76
76
|
readonly maxLength?: number;
|
|
@@ -93,7 +93,7 @@ export declare const configValuesTable: import("@cosmicdrift/kumiko-framework/db
|
|
|
93
93
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
94
94
|
required: true;
|
|
95
95
|
};
|
|
96
|
-
value: {
|
|
96
|
+
readonly value: {
|
|
97
97
|
readonly type: "text";
|
|
98
98
|
readonly description?: string;
|
|
99
99
|
readonly maxLength?: number;
|
|
@@ -116,7 +116,7 @@ export declare const configValuesTable: import("@cosmicdrift/kumiko-framework/db
|
|
|
116
116
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
117
117
|
required: false;
|
|
118
118
|
};
|
|
119
|
-
userId: {
|
|
119
|
+
readonly userId: {
|
|
120
120
|
readonly type: "text";
|
|
121
121
|
readonly description?: string;
|
|
122
122
|
readonly maxLength?: number;
|
package/dist/config/web/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { requestContext } from "@cosmicdrift/kumiko-framework/api";
|
|
|
2
2
|
import { ROLES } from "@cosmicdrift/kumiko-framework/auth";
|
|
3
3
|
import { computeBlindIndex, configuredBlindIndexKey, configuredPiiSubjectKms, subjectIdSchema, subjectIdToKey, } from "@cosmicdrift/kumiko-framework/crypto";
|
|
4
4
|
import { fetchOne, nullBlindIndexesForSubject, recordEventsOwnedExclusivelyByTenant, recordRowExistsInTenant, recordRowOwningTenantId, runInSavepointIfSupported, runnerCanBeginTransaction, subjectRowExistsInTenant, transaction, WritePurposes, } from "@cosmicdrift/kumiko-framework/db";
|
|
5
|
-
import { defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
|
|
5
|
+
import { defineWriteHandler, parseTenantId, } from "@cosmicdrift/kumiko-framework/engine";
|
|
6
6
|
import { AccessDeniedError, InternalError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
|
|
7
7
|
import { appendDomainEventCore, assertIrreversibleOperationAllowed, } from "@cosmicdrift/kumiko-framework/pipeline";
|
|
8
8
|
import { purgeSearchDocumentsForSubject } from "@cosmicdrift/kumiko-framework/search";
|
|
@@ -11,9 +11,11 @@ import * as z from "zod";
|
|
|
11
11
|
import { resolveRetentionPolicyForTenant } from "../../data-retention/index.js";
|
|
12
12
|
import { eraseNoteBodiesReachingSubject } from "../../notes-history-user-data/index.js";
|
|
13
13
|
import { revokeAllPatTokensForUser } from "../../personal-access-tokens/index.js";
|
|
14
|
+
import { purgeFilesReachingSubject } from "../../shared/index.js";
|
|
14
15
|
import { USER_STATUS, userTable } from "../../user/index.js";
|
|
15
16
|
import { denyIfTargetOutsideAdminTenant, isSystemAdminActor, updateUserLifecycle, } from "../../user-data-rights/index.js";
|
|
16
17
|
import { CRYPTO_SHREDDING_AGGREGATE_TYPE, CRYPTO_SHREDDING_FEATURE_NAME, RECORD_ENTITY_NOT_REGISTERED, SUBJECT_FORGET_DENIED_EVENT_NAME, SUBJECT_FORGOTTEN_EVENT_NAME, TARGET_RECORD_NOT_ADMIN_TENANT, TARGET_RECORD_RETENTION_BLOCK_DELETE, TARGET_TENANT_NOT_ADMIN_TENANT, } from "../constants.js";
|
|
18
|
+
import { resolveFileBytesDeleter } from "../resolve-file-bytes-deleter.js";
|
|
17
19
|
export { subjectIdSchema };
|
|
18
20
|
export const forgetSubjectSchema = z.object({
|
|
19
21
|
subject: subjectIdSchema,
|
|
@@ -142,6 +144,13 @@ getRunner) {
|
|
|
142
144
|
});
|
|
143
145
|
return effective.policy?.strategy === "blockDelete" ? deny() : undefined;
|
|
144
146
|
}
|
|
147
|
+
// The tenant that owns a record subject's row; the file purge is scoped to it.
|
|
148
|
+
async function owningTenantOfRecordSubject(runner, features, raw) {
|
|
149
|
+
if (raw.kind !== "record")
|
|
150
|
+
return undefined;
|
|
151
|
+
const owner = await recordRowOwningTenantId(runner, features, raw.entity, raw.id);
|
|
152
|
+
return parseTenantId(owner) ?? undefined;
|
|
153
|
+
}
|
|
145
154
|
// AccessDeniedError.code is the generic "access_denied" for every branch;
|
|
146
155
|
// the specific branch lives in details.reason.
|
|
147
156
|
function denialReasonOf(failure) {
|
|
@@ -212,33 +221,49 @@ function sweepErrorLabel(err) {
|
|
|
212
221
|
}
|
|
213
222
|
// The key is already erased when this runs, so a failing sweep must not skip the
|
|
214
223
|
// audit event: the failure is returned as a label for the event instead of thrown.
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
224
|
+
// Each step runs in its own savepoint: a database error must not abort the handler
|
|
225
|
+
// transaction, and one failing step must not skip or roll back the others.
|
|
226
|
+
async function sweepDerivedSubjectData(ctx, subject, subjectKey, crossTenantRunner, audit, rawSubject) {
|
|
227
|
+
const recordTenantId = await owningTenantOfRecordSubject(crossTenantRunner, ctx.registry.features, rawSubject);
|
|
228
|
+
const failureLabels = [];
|
|
229
|
+
const runStep = async (step) => {
|
|
230
|
+
try {
|
|
231
|
+
await runInSavepointIfSupported(crossTenantRunner, step);
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
failureLabels.push(sweepErrorLabel(err));
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
await runStep(async (crossTenantSubjectRunner) => {
|
|
238
|
+
// Blind-index sweep (#818): nulls bidx columns now so the deterministic
|
|
239
|
+
// HMAC doesn't stay equality-matchable; raw because the ciphertext prefix addresses the subject across tenants.
|
|
240
|
+
await nullBlindIndexesForSubject(crossTenantSubjectRunner, ctx.registry.features, subjectKey);
|
|
241
|
+
// Derived search index still holds plaintext (#1610) — purge next to the
|
|
242
|
+
// blind-index sweep. No adapter → no-op (apps without search).
|
|
243
|
+
if (ctx.searchAdapter) {
|
|
244
|
+
await purgeSearchDocumentsForSubject(crossTenantSubjectRunner, ctx.registry.features, ctx.searchAdapter, subjectKey, subject);
|
|
245
|
+
}
|
|
246
|
+
// Note bodies are keyed per note, so the subject's own key never reaches them.
|
|
247
|
+
if (ctx.registry.features.has("notes-history")) {
|
|
248
|
+
await eraseNoteBodiesReachingSubject({
|
|
249
|
+
db: crossTenantSubjectRunner,
|
|
250
|
+
subject,
|
|
251
|
+
erasedBy: audit.erasedBy,
|
|
252
|
+
requestId: audit.requestId,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
// File columns hold only the fileRef id, so the key erase never reaches the bytes.
|
|
257
|
+
await runStep((crossTenantSubjectRunner) => purgeFilesReachingSubject({
|
|
258
|
+
registry: ctx.registry,
|
|
259
|
+
db: crossTenantSubjectRunner,
|
|
260
|
+
subject,
|
|
261
|
+
subjectKey,
|
|
262
|
+
...(recordTenantId !== undefined && { recordTenantId }),
|
|
263
|
+
resolveDeleteBytes: resolveFileBytesDeleter(ctx),
|
|
264
|
+
missingStorage: { mode: "fail" },
|
|
265
|
+
}));
|
|
266
|
+
return failureLabels[0];
|
|
242
267
|
}
|
|
243
268
|
// Email subscribers and other non-user entities use user-style subject keys
|
|
244
269
|
// without a read_users row — the key erase is the GDPR-relevant part, so no row
|
|
@@ -319,7 +344,7 @@ export const forgetSubjectWrite = defineWriteHandler({
|
|
|
319
344
|
grants: ["unsafeRaw"],
|
|
320
345
|
reason: "the denial and SUBJECT_FORGOTTEN audit appends name the caller's own tenant stream on the outside-transaction db; " +
|
|
321
346
|
"the tenant-scope and retention checks run against the subject's tenant, not necessarily the caller's; " +
|
|
322
|
-
"the blind-index sweep and
|
|
347
|
+
"the blind-index sweep, search purge and file purge address the subject across tenants; the user " +
|
|
323
348
|
"lifecycle update and PAT revoke run on the SYSTEM user stream.",
|
|
324
349
|
},
|
|
325
350
|
handler: async (event, ctx) => {
|
|
@@ -382,7 +407,7 @@ export const forgetSubjectWrite = defineWriteHandler({
|
|
|
382
407
|
if (raw.kind === "user" && ctx.registry.features.has("user")) {
|
|
383
408
|
await closeUserLoginDoor(ctx, raw.userId, ctx.dbOutsideTransaction?.unsafeRaw(), ctx.db.unsafeRaw());
|
|
384
409
|
}
|
|
385
|
-
const cleanupError = await sweepDerivedSubjectData(ctx, subject, subjectKey, ctx.db.unsafeRaw(), { requestId, erasedBy: event.user.id });
|
|
410
|
+
const cleanupError = await sweepDerivedSubjectData(ctx, subject, subjectKey, ctx.db.unsafeRaw(), { requestId, erasedBy: event.user.id }, raw);
|
|
386
411
|
await appendSubjectForgotten(ctx, event, subjectAggregateId(raw), {
|
|
387
412
|
subjectKey,
|
|
388
413
|
reason: event.payload.reason,
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { HandlerContext, TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
import type { DeleteFileBytes } from "../shared/index.ts";
|
|
3
|
+
export declare function resolveFileBytesDeleter(ctx: HandlerContext): (tenantId: TenantId) => Promise<DeleteFileBytes | undefined>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { deleteFileRefBytes } from "@cosmicdrift/kumiko-framework/derivatives";
|
|
2
|
+
import { createFileContext } from "@cosmicdrift/kumiko-framework/files";
|
|
3
|
+
const ERROR_CONTEXT = "crypto-shredding:forget-subject";
|
|
4
|
+
// The upload resolver, not ctx.files: ctx.files is bound to the acting user's tenant, while a
|
|
5
|
+
// subject's rows can live in any tenant. Resolved eagerly so a missing provider surfaces as
|
|
6
|
+
// missing_file_storage instead of a failed delete.
|
|
7
|
+
export function resolveFileBytesDeleter(ctx) {
|
|
8
|
+
return async (tenantId) => {
|
|
9
|
+
const resolver = ctx._fileProviderResolver;
|
|
10
|
+
if (resolver === undefined) {
|
|
11
|
+
const own = tenantId === ctx.user.tenantId ? ctx.files : undefined;
|
|
12
|
+
return own && ((key) => deleteFileRefBytes(own, { storageKey: key }, ERROR_CONTEXT));
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const provider = await resolver(tenantId);
|
|
16
|
+
const files = createFileContext(() => Promise.resolve(provider), tenantId);
|
|
17
|
+
return (key) => deleteFileRefBytes(files, { storageKey: key }, ERROR_CONTEXT);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// skip: no provider resolvable for this tenant; surfaces as missing_file_storage when files exist
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const fieldDefinitionEntity: import("@cosmicdrift/kumiko-types/fields").EntityDefinition<{
|
|
2
|
-
entityName: {
|
|
2
|
+
readonly entityName: {
|
|
3
3
|
readonly type: "text";
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
@@ -22,7 +22,7 @@ export declare const fieldDefinitionEntity: import("@cosmicdrift/kumiko-types/fi
|
|
|
22
22
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
23
23
|
required: true;
|
|
24
24
|
};
|
|
25
|
-
fieldKey: {
|
|
25
|
+
readonly fieldKey: {
|
|
26
26
|
readonly type: "text";
|
|
27
27
|
readonly description?: string;
|
|
28
28
|
readonly maxLength?: number;
|
|
@@ -45,7 +45,7 @@ export declare const fieldDefinitionEntity: import("@cosmicdrift/kumiko-types/fi
|
|
|
45
45
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
46
46
|
required: true;
|
|
47
47
|
};
|
|
48
|
-
type: {
|
|
48
|
+
readonly type: {
|
|
49
49
|
readonly type: "text";
|
|
50
50
|
readonly description?: string;
|
|
51
51
|
readonly maxLength?: number;
|
|
@@ -68,13 +68,15 @@ export declare const fieldDefinitionEntity: import("@cosmicdrift/kumiko-types/fi
|
|
|
68
68
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
69
69
|
required: true;
|
|
70
70
|
};
|
|
71
|
-
required: import("@cosmicdrift/kumiko-types/fields").BooleanFieldDef & {
|
|
71
|
+
readonly required: import("@cosmicdrift/kumiko-types/fields").BooleanFieldDef & {
|
|
72
72
|
required: true;
|
|
73
|
+
default: boolean;
|
|
73
74
|
};
|
|
74
|
-
searchable: import("@cosmicdrift/kumiko-types/fields").BooleanFieldDef & {
|
|
75
|
+
readonly searchable: import("@cosmicdrift/kumiko-types/fields").BooleanFieldDef & {
|
|
75
76
|
required: true;
|
|
77
|
+
default: boolean;
|
|
76
78
|
};
|
|
77
|
-
displayOrder: {
|
|
79
|
+
readonly displayOrder: {
|
|
78
80
|
readonly type: "number";
|
|
79
81
|
readonly description?: string;
|
|
80
82
|
readonly required?: boolean;
|
|
@@ -93,7 +95,7 @@ export declare const fieldDefinitionEntity: import("@cosmicdrift/kumiko-types/fi
|
|
|
93
95
|
} & import("@cosmicdrift/kumiko-types/fields").ResolvedPiiFlags & {
|
|
94
96
|
required: true;
|
|
95
97
|
};
|
|
96
|
-
serializedField: {
|
|
98
|
+
readonly serializedField: {
|
|
97
99
|
readonly type: "text";
|
|
98
100
|
readonly description?: string;
|
|
99
101
|
readonly maxLength?: number;
|