@cosmicdrift/kumiko-bundled-features 0.356.0 → 0.358.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/i18n.js +1 -0
- package/dist/auth-mfa/schema/user-mfa.d.ts +6 -0
- package/dist/auth-mfa/screens.js +8 -1
- package/dist/billing-foundation/entities.d.ts +8 -0
- package/dist/billing-foundation/projection.d.ts +8 -0
- package/dist/cap-counter/book-cap-usage.d.ts +11 -5
- package/dist/cap-counter/book-cap-usage.js +54 -13
- package/dist/cap-counter/calendar-cap-usage-reservation.d.ts +17 -0
- package/dist/cap-counter/calendar-cap-usage-reservation.js +53 -0
- package/dist/cap-counter/cap-reservation.d.ts +15 -6
- package/dist/cap-counter/cap-reservation.js +80 -31
- package/dist/cap-counter/enforce-cap.d.ts +5 -5
- package/dist/cap-counter/enforce-cap.js +7 -20
- package/dist/cap-counter/entity.d.ts +1 -0
- package/dist/cap-counter/feature.js +7 -1
- package/dist/cap-counter/index.d.ts +1 -0
- package/dist/cap-counter/index.js +1 -0
- package/dist/cap-counter/with-cap-enforcement.js +4 -19
- package/dist/cap-overview/screens.js +3 -1
- package/dist/config/table.d.ts +6 -0
- package/dist/crypto-shredding/handlers/forget-subject.write.js +14 -3
- package/dist/custom-fields/entity.d.ts +4 -0
- package/dist/data-retention/schema/tenant-retention-override.d.ts +4 -0
- package/dist/delivery/chat-webhook-sender.js +1 -1
- package/dist/delivery/constants.d.ts +1 -0
- package/dist/delivery/constants.js +4 -0
- package/dist/delivery/delivery-service.js +62 -25
- package/dist/delivery/feature.js +7 -1
- package/dist/delivery/jobs.js +25 -1
- package/dist/delivery/tables.d.ts +6 -0
- package/dist/delivery/testing.d.ts +1 -0
- package/dist/document-ingest-foundation/entity.d.ts +4 -0
- package/dist/folders/entity.d.ts +8 -0
- package/dist/form-draft/entity.d.ts +2 -0
- package/dist/inbound-mail-foundation/entities.d.ts +25 -0
- package/dist/inbound-mail-foundation/projection.d.ts +20 -0
- package/dist/jobs/job-run-logger.js +21 -17
- package/dist/jobs/job-run-table.d.ts +6 -0
- package/dist/jobs/job-run-table.js +10 -3
- package/dist/ledger/entity.d.ts +13 -0
- package/dist/managed-pages/table.d.ts +12 -0
- package/dist/notes-history/entity.d.ts +12 -0
- package/dist/notes-history/entity.js +9 -7
- package/dist/notes-history-user-data/hooks.d.ts +8 -0
- package/dist/notes-history-user-data/hooks.js +56 -72
- package/dist/notes-history-user-data/index.d.ts +1 -0
- package/dist/notes-history-user-data/index.js +2 -1
- package/dist/personal-access-tokens/schema/api-token.d.ts +6 -0
- package/dist/personal-access-tokens/screens.js +2 -0
- package/dist/secrets/table.d.ts +1 -0
- package/dist/sessions/schema/user-session.d.ts +4 -0
- package/dist/sessions/screens.js +2 -0
- package/dist/tags/entity.d.ts +9 -0
- package/dist/template-resolver/table.d.ts +10 -0
- package/dist/template-resolver/user-content-table.d.ts +10 -0
- package/dist/tenant/constants.d.ts +1 -0
- package/dist/tenant/constants.js +6 -3
- package/dist/tenant/feature.js +2 -0
- package/dist/tenant/handlers/member-role-availability.query.d.ts +7 -0
- package/dist/tenant/handlers/member-role-availability.query.js +18 -0
- package/dist/tenant/invitation-table.d.ts +6 -0
- package/dist/tenant/member-role-options.d.ts +2 -0
- package/dist/tenant/member-role-options.js +4 -0
- package/dist/tenant/membership-table.d.ts +4 -0
- package/dist/tenant/schema/tenant.d.ts +6 -0
- package/dist/tenant/screens.d.ts +4 -2
- package/dist/tenant/screens.js +10 -6
- package/dist/tier-engine/entity.d.ts +2 -0
- package/dist/tier-engine/tier-resolver.d.ts +2 -0
- package/dist/user/schema/user.d.ts +12 -0
- package/dist/user/screens.js +8 -1
- package/dist/user-data-rights/schema/download-attempt.d.ts +14 -0
- package/dist/user-data-rights/schema/download-token.d.ts +8 -0
- package/dist/user-data-rights/schema/export-job.d.ts +6 -0
- package/dist/user-data-rights/screens.js +8 -1
- package/dist/waitlist/entity.d.ts +14 -0
- package/dist/waitlist/screens.js +8 -1
- package/package.json +9 -9
- package/src/auth-mfa/changes.json +6 -0
- package/src/cap-counter/changes.json +7 -0
- package/src/crypto-shredding/changes.json +6 -0
- package/src/delivery/changes.json +6 -0
- package/src/notes-history/changes.json +6 -0
- package/src/tenant/changes.json +6 -0
package/dist/ledger/entity.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare const accountEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
6
6
|
readonly minLength?: number;
|
|
7
|
+
readonly autoComplete?: string;
|
|
7
8
|
readonly required?: boolean;
|
|
8
9
|
readonly searchable?: boolean;
|
|
9
10
|
readonly sortable?: boolean;
|
|
@@ -51,6 +52,7 @@ export declare const accountEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
51
52
|
readonly description?: string;
|
|
52
53
|
readonly maxLength?: number;
|
|
53
54
|
readonly minLength?: number;
|
|
55
|
+
readonly autoComplete?: string;
|
|
54
56
|
readonly required?: boolean;
|
|
55
57
|
readonly searchable?: boolean;
|
|
56
58
|
readonly sortable?: boolean;
|
|
@@ -73,6 +75,7 @@ export declare const accountEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
73
75
|
readonly description?: string;
|
|
74
76
|
readonly maxLength?: number;
|
|
75
77
|
readonly minLength?: number;
|
|
78
|
+
readonly autoComplete?: string;
|
|
76
79
|
readonly required?: boolean;
|
|
77
80
|
readonly searchable?: boolean;
|
|
78
81
|
readonly sortable?: boolean;
|
|
@@ -111,6 +114,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
111
114
|
readonly description?: string;
|
|
112
115
|
readonly maxLength?: number;
|
|
113
116
|
readonly minLength?: number;
|
|
117
|
+
readonly autoComplete?: string;
|
|
114
118
|
readonly required?: boolean;
|
|
115
119
|
readonly searchable?: boolean;
|
|
116
120
|
readonly sortable?: boolean;
|
|
@@ -133,6 +137,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
133
137
|
readonly description?: string;
|
|
134
138
|
readonly maxLength?: number;
|
|
135
139
|
readonly minLength?: number;
|
|
140
|
+
readonly autoComplete?: string;
|
|
136
141
|
readonly required?: boolean;
|
|
137
142
|
readonly searchable?: boolean;
|
|
138
143
|
readonly sortable?: boolean;
|
|
@@ -193,6 +198,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
193
198
|
readonly description?: string;
|
|
194
199
|
readonly maxLength?: number;
|
|
195
200
|
readonly minLength?: number;
|
|
201
|
+
readonly autoComplete?: string;
|
|
196
202
|
readonly required?: boolean;
|
|
197
203
|
readonly searchable?: boolean;
|
|
198
204
|
readonly sortable?: boolean;
|
|
@@ -215,6 +221,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
215
221
|
readonly description?: string;
|
|
216
222
|
readonly maxLength?: number;
|
|
217
223
|
readonly minLength?: number;
|
|
224
|
+
readonly autoComplete?: string;
|
|
218
225
|
readonly required?: boolean;
|
|
219
226
|
readonly searchable?: boolean;
|
|
220
227
|
readonly sortable?: boolean;
|
|
@@ -239,6 +246,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
239
246
|
readonly description?: string;
|
|
240
247
|
readonly maxLength?: number;
|
|
241
248
|
readonly minLength?: number;
|
|
249
|
+
readonly autoComplete?: string;
|
|
242
250
|
readonly required?: boolean;
|
|
243
251
|
readonly searchable?: boolean;
|
|
244
252
|
readonly sortable?: boolean;
|
|
@@ -329,6 +337,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
329
337
|
readonly description?: string;
|
|
330
338
|
readonly maxLength?: number;
|
|
331
339
|
readonly minLength?: number;
|
|
340
|
+
readonly autoComplete?: string;
|
|
332
341
|
readonly required?: boolean;
|
|
333
342
|
readonly searchable?: boolean;
|
|
334
343
|
readonly sortable?: boolean;
|
|
@@ -351,6 +360,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
351
360
|
readonly description?: string;
|
|
352
361
|
readonly maxLength?: number;
|
|
353
362
|
readonly minLength?: number;
|
|
363
|
+
readonly autoComplete?: string;
|
|
354
364
|
readonly required?: boolean;
|
|
355
365
|
readonly searchable?: boolean;
|
|
356
366
|
readonly sortable?: boolean;
|
|
@@ -373,6 +383,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
373
383
|
readonly description?: string;
|
|
374
384
|
readonly maxLength?: number;
|
|
375
385
|
readonly minLength?: number;
|
|
386
|
+
readonly autoComplete?: string;
|
|
376
387
|
readonly required?: boolean;
|
|
377
388
|
readonly searchable?: boolean;
|
|
378
389
|
readonly sortable?: boolean;
|
|
@@ -395,6 +406,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
395
406
|
readonly description?: string;
|
|
396
407
|
readonly maxLength?: number;
|
|
397
408
|
readonly minLength?: number;
|
|
409
|
+
readonly autoComplete?: string;
|
|
398
410
|
readonly required?: boolean;
|
|
399
411
|
readonly searchable?: boolean;
|
|
400
412
|
readonly sortable?: boolean;
|
|
@@ -417,6 +429,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
417
429
|
readonly description?: string;
|
|
418
430
|
readonly maxLength?: number;
|
|
419
431
|
readonly minLength?: number;
|
|
432
|
+
readonly autoComplete?: string;
|
|
420
433
|
readonly required?: boolean;
|
|
421
434
|
readonly searchable?: boolean;
|
|
422
435
|
readonly sortable?: boolean;
|
|
@@ -4,6 +4,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
6
6
|
readonly minLength?: number;
|
|
7
|
+
readonly autoComplete?: string;
|
|
7
8
|
readonly required?: boolean;
|
|
8
9
|
readonly searchable?: boolean;
|
|
9
10
|
readonly sortable?: boolean;
|
|
@@ -26,6 +27,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
26
27
|
readonly description?: string;
|
|
27
28
|
readonly maxLength?: number;
|
|
28
29
|
readonly minLength?: number;
|
|
30
|
+
readonly autoComplete?: string;
|
|
29
31
|
readonly required?: boolean;
|
|
30
32
|
readonly searchable?: boolean;
|
|
31
33
|
readonly sortable?: boolean;
|
|
@@ -48,6 +50,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
48
50
|
readonly description?: string;
|
|
49
51
|
readonly maxLength?: number;
|
|
50
52
|
readonly minLength?: number;
|
|
53
|
+
readonly autoComplete?: string;
|
|
51
54
|
readonly required?: boolean;
|
|
52
55
|
readonly searchable?: boolean;
|
|
53
56
|
readonly sortable?: boolean;
|
|
@@ -70,6 +73,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
70
73
|
readonly description?: string;
|
|
71
74
|
readonly maxLength?: number;
|
|
72
75
|
readonly minLength?: number;
|
|
76
|
+
readonly autoComplete?: string;
|
|
73
77
|
readonly required?: boolean;
|
|
74
78
|
readonly searchable?: boolean;
|
|
75
79
|
readonly sortable?: boolean;
|
|
@@ -92,6 +96,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
92
96
|
readonly description?: string;
|
|
93
97
|
readonly maxLength?: number;
|
|
94
98
|
readonly minLength?: number;
|
|
99
|
+
readonly autoComplete?: string;
|
|
95
100
|
readonly required?: boolean;
|
|
96
101
|
readonly searchable?: boolean;
|
|
97
102
|
readonly sortable?: boolean;
|
|
@@ -114,6 +119,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
114
119
|
readonly description?: string;
|
|
115
120
|
readonly maxLength?: number;
|
|
116
121
|
readonly minLength?: number;
|
|
122
|
+
readonly autoComplete?: string;
|
|
117
123
|
readonly required?: boolean;
|
|
118
124
|
readonly searchable?: boolean;
|
|
119
125
|
readonly sortable?: boolean;
|
|
@@ -141,6 +147,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
141
147
|
readonly description?: string;
|
|
142
148
|
readonly maxLength?: number;
|
|
143
149
|
readonly minLength?: number;
|
|
150
|
+
readonly autoComplete?: string;
|
|
144
151
|
readonly required?: boolean;
|
|
145
152
|
readonly searchable?: boolean;
|
|
146
153
|
readonly sortable?: boolean;
|
|
@@ -163,6 +170,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
163
170
|
readonly description?: string;
|
|
164
171
|
readonly maxLength?: number;
|
|
165
172
|
readonly minLength?: number;
|
|
173
|
+
readonly autoComplete?: string;
|
|
166
174
|
readonly required?: boolean;
|
|
167
175
|
readonly searchable?: boolean;
|
|
168
176
|
readonly sortable?: boolean;
|
|
@@ -185,6 +193,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
185
193
|
readonly description?: string;
|
|
186
194
|
readonly maxLength?: number;
|
|
187
195
|
readonly minLength?: number;
|
|
196
|
+
readonly autoComplete?: string;
|
|
188
197
|
readonly required?: boolean;
|
|
189
198
|
readonly searchable?: boolean;
|
|
190
199
|
readonly sortable?: boolean;
|
|
@@ -207,6 +216,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
207
216
|
readonly description?: string;
|
|
208
217
|
readonly maxLength?: number;
|
|
209
218
|
readonly minLength?: number;
|
|
219
|
+
readonly autoComplete?: string;
|
|
210
220
|
readonly required?: boolean;
|
|
211
221
|
readonly searchable?: boolean;
|
|
212
222
|
readonly sortable?: boolean;
|
|
@@ -229,6 +239,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
229
239
|
readonly description?: string;
|
|
230
240
|
readonly maxLength?: number;
|
|
231
241
|
readonly minLength?: number;
|
|
242
|
+
readonly autoComplete?: string;
|
|
232
243
|
readonly required?: boolean;
|
|
233
244
|
readonly searchable?: boolean;
|
|
234
245
|
readonly sortable?: boolean;
|
|
@@ -251,6 +262,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
251
262
|
readonly description?: string;
|
|
252
263
|
readonly maxLength?: number;
|
|
253
264
|
readonly minLength?: number;
|
|
265
|
+
readonly autoComplete?: string;
|
|
254
266
|
readonly required?: boolean;
|
|
255
267
|
readonly searchable?: boolean;
|
|
256
268
|
readonly sortable?: boolean;
|
|
@@ -5,6 +5,7 @@ export declare function createNoteEntryEntity(access?: EntityDefinition["access"
|
|
|
5
5
|
readonly description?: string;
|
|
6
6
|
readonly maxLength?: number;
|
|
7
7
|
readonly minLength?: number;
|
|
8
|
+
readonly autoComplete?: string;
|
|
8
9
|
readonly required?: boolean;
|
|
9
10
|
readonly searchable?: boolean;
|
|
10
11
|
readonly sortable?: boolean;
|
|
@@ -27,6 +28,7 @@ export declare function createNoteEntryEntity(access?: EntityDefinition["access"
|
|
|
27
28
|
readonly description?: string;
|
|
28
29
|
readonly maxLength?: number;
|
|
29
30
|
readonly minLength?: number;
|
|
31
|
+
readonly autoComplete?: string;
|
|
30
32
|
readonly required?: boolean;
|
|
31
33
|
readonly searchable?: boolean;
|
|
32
34
|
readonly sortable?: boolean;
|
|
@@ -49,6 +51,7 @@ export declare function createNoteEntryEntity(access?: EntityDefinition["access"
|
|
|
49
51
|
readonly description?: string;
|
|
50
52
|
readonly maxLength?: number;
|
|
51
53
|
readonly minLength?: number;
|
|
54
|
+
readonly autoComplete?: string;
|
|
52
55
|
readonly required?: boolean;
|
|
53
56
|
readonly searchable?: boolean;
|
|
54
57
|
readonly sortable?: boolean;
|
|
@@ -71,6 +74,7 @@ export declare function createNoteEntryEntity(access?: EntityDefinition["access"
|
|
|
71
74
|
readonly description?: string;
|
|
72
75
|
readonly maxLength?: number;
|
|
73
76
|
readonly minLength?: number;
|
|
77
|
+
readonly autoComplete?: string;
|
|
74
78
|
readonly required?: boolean;
|
|
75
79
|
readonly searchable?: boolean;
|
|
76
80
|
readonly sortable?: boolean;
|
|
@@ -111,6 +115,7 @@ export declare const noteEntryEntity: EntityDefinition<{
|
|
|
111
115
|
readonly description?: string;
|
|
112
116
|
readonly maxLength?: number;
|
|
113
117
|
readonly minLength?: number;
|
|
118
|
+
readonly autoComplete?: string;
|
|
114
119
|
readonly required?: boolean;
|
|
115
120
|
readonly searchable?: boolean;
|
|
116
121
|
readonly sortable?: boolean;
|
|
@@ -133,6 +138,7 @@ export declare const noteEntryEntity: EntityDefinition<{
|
|
|
133
138
|
readonly description?: string;
|
|
134
139
|
readonly maxLength?: number;
|
|
135
140
|
readonly minLength?: number;
|
|
141
|
+
readonly autoComplete?: string;
|
|
136
142
|
readonly required?: boolean;
|
|
137
143
|
readonly searchable?: boolean;
|
|
138
144
|
readonly sortable?: boolean;
|
|
@@ -155,6 +161,7 @@ export declare const noteEntryEntity: EntityDefinition<{
|
|
|
155
161
|
readonly description?: string;
|
|
156
162
|
readonly maxLength?: number;
|
|
157
163
|
readonly minLength?: number;
|
|
164
|
+
readonly autoComplete?: string;
|
|
158
165
|
readonly required?: boolean;
|
|
159
166
|
readonly searchable?: boolean;
|
|
160
167
|
readonly sortable?: boolean;
|
|
@@ -177,6 +184,7 @@ export declare const noteEntryEntity: EntityDefinition<{
|
|
|
177
184
|
readonly description?: string;
|
|
178
185
|
readonly maxLength?: number;
|
|
179
186
|
readonly minLength?: number;
|
|
187
|
+
readonly autoComplete?: string;
|
|
180
188
|
readonly required?: boolean;
|
|
181
189
|
readonly searchable?: boolean;
|
|
182
190
|
readonly sortable?: boolean;
|
|
@@ -217,6 +225,7 @@ export declare function createNoteMentionEntity(): EntityDefinition<{
|
|
|
217
225
|
readonly description?: string;
|
|
218
226
|
readonly maxLength?: number;
|
|
219
227
|
readonly minLength?: number;
|
|
228
|
+
readonly autoComplete?: string;
|
|
220
229
|
readonly required?: boolean;
|
|
221
230
|
readonly searchable?: boolean;
|
|
222
231
|
readonly sortable?: boolean;
|
|
@@ -239,6 +248,7 @@ export declare function createNoteMentionEntity(): EntityDefinition<{
|
|
|
239
248
|
readonly description?: string;
|
|
240
249
|
readonly maxLength?: number;
|
|
241
250
|
readonly minLength?: number;
|
|
251
|
+
readonly autoComplete?: string;
|
|
242
252
|
readonly required?: boolean;
|
|
243
253
|
readonly searchable?: boolean;
|
|
244
254
|
readonly sortable?: boolean;
|
|
@@ -263,6 +273,7 @@ export declare const noteMentionEntity: EntityDefinition<{
|
|
|
263
273
|
readonly description?: string;
|
|
264
274
|
readonly maxLength?: number;
|
|
265
275
|
readonly minLength?: number;
|
|
276
|
+
readonly autoComplete?: string;
|
|
266
277
|
readonly required?: boolean;
|
|
267
278
|
readonly searchable?: boolean;
|
|
268
279
|
readonly sortable?: boolean;
|
|
@@ -285,6 +296,7 @@ export declare const noteMentionEntity: EntityDefinition<{
|
|
|
285
296
|
readonly description?: string;
|
|
286
297
|
readonly maxLength?: number;
|
|
287
298
|
readonly minLength?: number;
|
|
299
|
+
readonly autoComplete?: string;
|
|
288
300
|
readonly required?: boolean;
|
|
289
301
|
readonly searchable?: boolean;
|
|
290
302
|
readonly sortable?: boolean;
|
|
@@ -20,17 +20,18 @@ import { createEntity, createLongTextField, createTextField, } from "@cosmicdrif
|
|
|
20
20
|
//
|
|
21
21
|
// `body` is instead `personal: { of: "id" }` (Row-Subject, fw#2596/#2786):
|
|
22
22
|
// the note's OWN row is its content's subject, so `body` is encrypted under a
|
|
23
|
-
// per-note key that nothing else shares. That key gets erased only when
|
|
24
|
-
// `note-mention` (below) names
|
|
25
|
-
//
|
|
26
|
-
//
|
|
23
|
+
// per-note key that nothing else shares. That key gets erased only when the
|
|
24
|
+
// note is reached by a forgotten subject: `note-mention` (below) names the
|
|
25
|
+
// subject, or the note hangs on the subject as host (entityId, plus entityType
|
|
26
|
+
// for record subjects). See `notes-history-user-data/hooks.ts`; any other note
|
|
27
|
+
// is untouched. GDPR erasure of the AUTHOR still separately
|
|
27
28
|
// shreds `authorName` (`personal: { of: "authorId" }`, the name as stamped at
|
|
28
29
|
// write time); the two erasures are independent.
|
|
29
30
|
//
|
|
30
31
|
// Known gap (fw#2596, not fixed by this entity): prose that names a third
|
|
31
32
|
// party without a structured @-mention is not tracked — regex/NLP over
|
|
32
|
-
// free text is unreliable.
|
|
33
|
-
//
|
|
33
|
+
// free text is unreliable. An operator must erase such a note's own record
|
|
34
|
+
// subject (`forget-subject` kind "record", entity "note-entry") to cover it.
|
|
34
35
|
export function createNoteEntryEntity(access, parents) {
|
|
35
36
|
return createEntity({
|
|
36
37
|
table: "read_note_entries",
|
|
@@ -66,9 +67,10 @@ export function createNoteEntryEntity(access, parents) {
|
|
|
66
67
|
}),
|
|
67
68
|
// Stamped once at write time, never re-resolved later — the history
|
|
68
69
|
// needs the name as it was then, not whatever the account is called now.
|
|
70
|
+
// whenAbsent: authorless notes (system-written) encrypt under the tenant key.
|
|
69
71
|
authorName: createTextField({
|
|
70
72
|
maxLength: 200,
|
|
71
|
-
personal: { of: "authorId" },
|
|
73
|
+
personal: { of: "authorId", whenAbsent: "tenant" },
|
|
72
74
|
find: "none",
|
|
73
75
|
}),
|
|
74
76
|
body: createLongTextField({
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import { type SubjectId } from "@cosmicdrift/kumiko-framework/crypto";
|
|
2
|
+
import type { DbRunner, TenantDb } from "@cosmicdrift/kumiko-framework/db";
|
|
1
3
|
import type { UserDataDeleteHook, UserDataExportHook } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
4
|
export declare const noteEntryExportHook: UserDataExportHook;
|
|
5
|
+
export declare function eraseNoteBodiesReachingSubject(args: {
|
|
6
|
+
readonly db: DbRunner | TenantDb;
|
|
7
|
+
readonly subject: SubjectId;
|
|
8
|
+
readonly erasedBy: string;
|
|
9
|
+
readonly requestId: string;
|
|
10
|
+
}): Promise<void>;
|
|
3
11
|
export declare const noteEntryDeleteHook: UserDataDeleteHook;
|
|
4
12
|
export declare const noteMentionExportHook: UserDataExportHook;
|
|
5
13
|
export declare const noteMentionDeleteHook: UserDataDeleteHook;
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
// notes consumers without the user-data-rights pipeline don't pull a hard
|
|
4
4
|
// dependency. Mirrors job-run/delivery-attempt (user-data-rights-defaults):
|
|
5
5
|
// export-only, erasure via crypto-shredding.
|
|
6
|
+
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
6
7
|
import { configuredPiiSubjectKms } from "@cosmicdrift/kumiko-framework/crypto";
|
|
7
|
-
import { resolveRetentionPolicyForTenant, resolveTenantRetentionPreset, } from "../data-retention/index.js";
|
|
8
8
|
import { noteEntryTable, noteMentionTable } from "../notes-history/index.js";
|
|
9
|
-
import { policyToStrategy } from "../user-data-rights/index.js";
|
|
10
9
|
// note-entry has no per-tenant scope quirk (unlike folders) — it's genuinely
|
|
11
10
|
// per-user content, so the export filters by authorId directly.
|
|
12
11
|
export const noteEntryExportHook = async (ctx) => {
|
|
@@ -26,93 +25,78 @@ export const noteEntryExportHook = async (ctx) => {
|
|
|
26
25
|
})),
|
|
27
26
|
};
|
|
28
27
|
};
|
|
28
|
+
// What erasing a subject's key reaches: notes that @-mention the subject plus notes
|
|
29
|
+
// attached to it as host. Export and erasure both go through this, so Art. 15
|
|
30
|
+
// lists exactly what Art. 17 shreds.
|
|
31
|
+
async function selectNotesReachingSubject(db, subject) {
|
|
32
|
+
if (subject.kind === "tenant")
|
|
33
|
+
return [];
|
|
34
|
+
const subjectId = subject.kind === "user" ? subject.userId : subject.id;
|
|
35
|
+
const attachedWhere = subject.kind === "record"
|
|
36
|
+
? { entityType: subject.entity, entityId: subjectId }
|
|
37
|
+
: { entityId: subjectId };
|
|
38
|
+
const mentions = await selectMany(db, noteMentionTable, { subjectId });
|
|
39
|
+
const mentioned = mentions.length === 0
|
|
40
|
+
? []
|
|
41
|
+
: await selectMany(db, noteEntryTable, {
|
|
42
|
+
id: { in: [...new Set(mentions.map((m) => m.noteId))] },
|
|
43
|
+
});
|
|
44
|
+
const attached = await selectMany(db, noteEntryTable, attachedWhere);
|
|
45
|
+
const byId = new Map();
|
|
46
|
+
for (const note of [...mentioned, ...attached])
|
|
47
|
+
byId.set(note.id, note);
|
|
48
|
+
return [...byId.values()];
|
|
49
|
+
}
|
|
29
50
|
// `authorName` is separately annotated `personal: { of: "authorId" }`
|
|
30
51
|
// (entity.ts), so forgetting the AUTHOR already crypto-shreds that field on
|
|
31
|
-
// its own
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
// that's the documented gap in entity.ts, not a bug here.
|
|
52
|
+
// its own. `body` is Row-Subject (`personal: { of: "id" }`): its key is per
|
|
53
|
+
// note, so forgetting a subject only reaches a body when the note structurally
|
|
54
|
+
// @-mentions the subject (`note-mention`, fw#2787) or hangs on it as host.
|
|
55
|
+
// Free-text mentions are NOT detected — the documented gap in entity.ts.
|
|
36
56
|
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
// other entity. The `strategy` this hook itself is called with is resolved
|
|
41
|
-
// for note-entry, not the host, so it is deliberately unused here.
|
|
57
|
+
// Reached bodies are shredded regardless of the host entity's retention strategy:
|
|
58
|
+
// the note text is free-form PII, and a host's anonymize/blockDelete protects the
|
|
59
|
+
// row, not its content, just like the host's own PII fields get anonymized.
|
|
42
60
|
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
// specific to this hook; apps that need Art.17 coverage without KMS must
|
|
48
|
-
// mount one.
|
|
49
|
-
export const noteEntryDeleteHook = async (ctx) => {
|
|
61
|
+
// Without a mounted KMS this erases nothing: record-owned fields fall back to
|
|
62
|
+
// plaintext framework-wide (see pii-field-encryption.ts), so apps that need
|
|
63
|
+
// Art. 17 coverage must mount one.
|
|
64
|
+
export async function eraseNoteBodiesReachingSubject(args) {
|
|
50
65
|
const kms = configuredPiiSubjectKms();
|
|
51
|
-
// skip: no KMS adapter mounted —
|
|
66
|
+
// skip: no KMS adapter mounted — forget is a true no-op
|
|
52
67
|
if (!kms)
|
|
53
68
|
return;
|
|
54
|
-
const
|
|
55
|
-
subjectId: ctx.userId,
|
|
56
|
-
});
|
|
57
|
-
// skip: no note-mention rows for this user — nothing structurally reaches this user's data to shred
|
|
58
|
-
if (mentions.length === 0)
|
|
59
|
-
return;
|
|
60
|
-
const noteIds = new Set(mentions.map((m) => m.noteId));
|
|
61
|
-
// Once per hook run: the preset depends on the tenant only, not the note.
|
|
62
|
-
const tenantPreset = await resolveTenantRetentionPreset({
|
|
63
|
-
db: ctx.db,
|
|
64
|
-
registry: ctx.registry,
|
|
65
|
-
tenantId: ctx.tenantId,
|
|
66
|
-
});
|
|
67
|
-
// Append-only rows are never hard-deleted, so every mentioned note should
|
|
68
|
-
// resolve; a missing one has no host and thus no retention policy to consult.
|
|
69
|
-
const notes = await ctx.db.selectMany(noteEntryTable, {
|
|
70
|
-
id: { in: [...noteIds] },
|
|
71
|
-
});
|
|
72
|
-
const strategyByEntityType = new Map();
|
|
69
|
+
const notes = await selectNotesReachingSubject(args.db, args.subject);
|
|
73
70
|
for (const note of notes) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
registry: ctx.registry,
|
|
79
|
-
tenantId: ctx.tenantId,
|
|
80
|
-
entityName: note.entityType,
|
|
81
|
-
preloadedTenantPreset: tenantPreset,
|
|
82
|
-
});
|
|
83
|
-
strategy = policyToStrategy(hostPolicy.policy?.strategy ?? null);
|
|
84
|
-
strategyByEntityType.set(note.entityType, strategy);
|
|
85
|
-
}
|
|
86
|
-
if (strategy === "anonymize")
|
|
87
|
-
continue;
|
|
88
|
-
const noteId = note.id;
|
|
89
|
-
await kms.eraseKey({ kind: "record", entity: "note-entry", id: noteId }, {
|
|
90
|
-
requestId: "notes-history-user-data:forget-mentioned-notes",
|
|
91
|
-
userId: ctx.userId,
|
|
92
|
-
eraseReason: "notes-history:mention-forget",
|
|
71
|
+
await kms.eraseKey({ kind: "record", entity: "note-entry", id: note.id }, {
|
|
72
|
+
requestId: args.requestId,
|
|
73
|
+
userId: args.erasedBy,
|
|
74
|
+
eraseReason: "notes-history:subject-forget",
|
|
93
75
|
});
|
|
94
76
|
}
|
|
77
|
+
}
|
|
78
|
+
export const noteEntryDeleteHook = async (ctx) => {
|
|
79
|
+
await eraseNoteBodiesReachingSubject({
|
|
80
|
+
db: ctx.db,
|
|
81
|
+
subject: { kind: "user", userId: ctx.userId },
|
|
82
|
+
erasedBy: ctx.userId,
|
|
83
|
+
requestId: "notes-history-user-data:forget-reached-notes",
|
|
84
|
+
});
|
|
95
85
|
};
|
|
96
|
-
// Erasure reaches every note that
|
|
97
|
-
//
|
|
86
|
+
// Erasure reaches every note that mentions the user or hangs on the user as host
|
|
87
|
+
// (see eraseNoteBodiesReachingSubject), so the Art. 15/20 export lists those too.
|
|
98
88
|
export const noteMentionExportHook = async (ctx) => {
|
|
99
|
-
const
|
|
100
|
-
subjectId: ctx.userId,
|
|
101
|
-
});
|
|
102
|
-
if (mentions.length === 0)
|
|
103
|
-
return null;
|
|
104
|
-
const noteIds = [...new Set(mentions.map((m) => m.noteId))];
|
|
105
|
-
const notes = await ctx.db.selectMany(noteEntryTable, { id: { in: noteIds } });
|
|
89
|
+
const notes = await selectNotesReachingSubject(ctx.db, { kind: "user", userId: ctx.userId });
|
|
106
90
|
if (notes.length === 0)
|
|
107
91
|
return null;
|
|
108
92
|
return {
|
|
109
93
|
entity: "note-mention",
|
|
110
94
|
rows: notes.map((note) => ({
|
|
111
|
-
noteId: note
|
|
112
|
-
entityType: note
|
|
113
|
-
entityId: note
|
|
114
|
-
body: note
|
|
115
|
-
insertedAt: note
|
|
95
|
+
noteId: note.id,
|
|
96
|
+
entityType: note.entityType,
|
|
97
|
+
entityId: note.entityId,
|
|
98
|
+
body: note.body,
|
|
99
|
+
insertedAt: note.insertedAt,
|
|
116
100
|
})),
|
|
117
101
|
};
|
|
118
102
|
};
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
// user-data-rights stack. Mirrors folders-user-data.
|
|
7
7
|
import { defineFeature, EXT_USER_DATA } from "@cosmicdrift/kumiko-framework/engine";
|
|
8
8
|
import { noteEntryDeleteHook, noteEntryExportHook, noteMentionDeleteHook, noteMentionExportHook, } from "./hooks.js";
|
|
9
|
+
export { eraseNoteBodiesReachingSubject } from "./hooks.js";
|
|
9
10
|
export const notesHistoryUserDataFeature = defineFeature("notes-history-user-data", (r) => {
|
|
10
|
-
r.describe("GDPR (Art. 20 export / Art. 17 erasure) coverage for the `notes-history` feature's `note-entry` and `note-mention` entities. Mounts the export hook so a user's authored notes are included in the user-data export bundle; the note-entry delete hook
|
|
11
|
+
r.describe("GDPR (Art. 20 export / Art. 17 erasure) coverage for the `notes-history` feature's `note-entry` and `note-mention` entities. Mounts the export hook so a user's authored notes are included in the user-data export bundle; the note-entry delete hook crypto-shreds the row-subject key of each note that structurally @-mentions the forgotten user (`note-mention`) or hangs on the user as host entity (regardless of the host entity's retention strategy: the note text is free PII, the host's anonymize/blockDelete protects the row, not the content), keeping the append-only history intact for all other notes. The manual `crypto-shredding` forget-subject command reaches the same notes for user and record subjects through the exported `eraseNoteBodiesReachingSubject`, and the export lists them under `note-mention`. `note-mention`'s own hooks are a no-op — it is a plain FK pointer, not separately exportable content. Kept separate from `notes-history` so notes consumers without the user-data-rights pipeline don't pull a hard dependency — requires `user-data-rights`, optionalRequires `notes-history`.");
|
|
11
12
|
// user-data-rights is the hard dependency (EXT_USER_DATA host). notes-history
|
|
12
13
|
// is OPTIONAL: if it's mounted toggleable(default=false), a hard r.requires
|
|
13
14
|
// would throw an "effectively disabled" boot warning even though the
|
|
@@ -4,6 +4,7 @@ export declare const apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
6
6
|
readonly minLength?: number;
|
|
7
|
+
readonly autoComplete?: string;
|
|
7
8
|
readonly required?: boolean;
|
|
8
9
|
readonly searchable?: boolean;
|
|
9
10
|
readonly sortable?: boolean;
|
|
@@ -26,6 +27,7 @@ export declare const apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
26
27
|
readonly description?: string;
|
|
27
28
|
readonly maxLength?: number;
|
|
28
29
|
readonly minLength?: number;
|
|
30
|
+
readonly autoComplete?: string;
|
|
29
31
|
readonly required?: boolean;
|
|
30
32
|
readonly searchable?: boolean;
|
|
31
33
|
readonly sortable?: boolean;
|
|
@@ -48,6 +50,7 @@ export declare const apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
48
50
|
readonly description?: string;
|
|
49
51
|
readonly maxLength?: number;
|
|
50
52
|
readonly minLength?: number;
|
|
53
|
+
readonly autoComplete?: string;
|
|
51
54
|
readonly required?: boolean;
|
|
52
55
|
readonly searchable?: boolean;
|
|
53
56
|
readonly sortable?: boolean;
|
|
@@ -70,6 +73,7 @@ export declare const apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
70
73
|
readonly description?: string;
|
|
71
74
|
readonly maxLength?: number;
|
|
72
75
|
readonly minLength?: number;
|
|
76
|
+
readonly autoComplete?: string;
|
|
73
77
|
readonly required?: boolean;
|
|
74
78
|
readonly searchable?: boolean;
|
|
75
79
|
readonly sortable?: boolean;
|
|
@@ -92,6 +96,7 @@ export declare const apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
92
96
|
readonly description?: string;
|
|
93
97
|
readonly maxLength?: number;
|
|
94
98
|
readonly minLength?: number;
|
|
99
|
+
readonly autoComplete?: string;
|
|
95
100
|
readonly required?: boolean;
|
|
96
101
|
readonly searchable?: boolean;
|
|
97
102
|
readonly sortable?: boolean;
|
|
@@ -114,6 +119,7 @@ export declare const apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
114
119
|
readonly description?: string;
|
|
115
120
|
readonly maxLength?: number;
|
|
116
121
|
readonly minLength?: number;
|
|
122
|
+
readonly autoComplete?: string;
|
|
117
123
|
readonly required?: boolean;
|
|
118
124
|
readonly searchable?: boolean;
|
|
119
125
|
readonly sortable?: boolean;
|
|
@@ -41,11 +41,13 @@ export const patListScreen = {
|
|
|
41
41
|
{
|
|
42
42
|
field: "createdAt",
|
|
43
43
|
label: i18nKey("pat.list.col.created"),
|
|
44
|
+
hideOnNarrow: true,
|
|
44
45
|
renderer: { format: "timestamp" },
|
|
45
46
|
},
|
|
46
47
|
{
|
|
47
48
|
field: "expiresAt",
|
|
48
49
|
label: i18nKey("pat.list.col.expires"),
|
|
50
|
+
hideOnNarrow: true,
|
|
49
51
|
renderer: { format: "timestamp" },
|
|
50
52
|
},
|
|
51
53
|
],
|
package/dist/secrets/table.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare const tenantSecretEntity: import("@cosmicdrift/kumiko-types/field
|
|
|
9
9
|
readonly description?: string;
|
|
10
10
|
readonly maxLength?: number;
|
|
11
11
|
readonly minLength?: number;
|
|
12
|
+
readonly autoComplete?: string;
|
|
12
13
|
readonly required?: boolean;
|
|
13
14
|
readonly searchable?: boolean;
|
|
14
15
|
readonly sortable?: boolean;
|
|
@@ -4,6 +4,7 @@ export declare const userSessionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
6
6
|
readonly minLength?: number;
|
|
7
|
+
readonly autoComplete?: string;
|
|
7
8
|
readonly required?: boolean;
|
|
8
9
|
readonly searchable?: boolean;
|
|
9
10
|
readonly sortable?: boolean;
|
|
@@ -26,6 +27,7 @@ export declare const userSessionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
26
27
|
readonly description?: string;
|
|
27
28
|
readonly maxLength?: number;
|
|
28
29
|
readonly minLength?: number;
|
|
30
|
+
readonly autoComplete?: string;
|
|
29
31
|
readonly required?: boolean;
|
|
30
32
|
readonly searchable?: boolean;
|
|
31
33
|
readonly sortable?: boolean;
|
|
@@ -108,6 +110,7 @@ export declare const userSessionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
108
110
|
readonly description?: string;
|
|
109
111
|
readonly maxLength?: number;
|
|
110
112
|
readonly minLength?: number;
|
|
113
|
+
readonly autoComplete?: string;
|
|
111
114
|
readonly required?: boolean;
|
|
112
115
|
readonly searchable?: boolean;
|
|
113
116
|
readonly sortable?: boolean;
|
|
@@ -130,6 +133,7 @@ export declare const userSessionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
130
133
|
readonly description?: string;
|
|
131
134
|
readonly maxLength?: number;
|
|
132
135
|
readonly minLength?: number;
|
|
136
|
+
readonly autoComplete?: string;
|
|
133
137
|
readonly required?: boolean;
|
|
134
138
|
readonly searchable?: boolean;
|
|
135
139
|
readonly sortable?: boolean;
|
package/dist/sessions/screens.js
CHANGED
|
@@ -33,6 +33,7 @@ export const createSessionListScreen = (adminRoles = access.admin) => ({
|
|
|
33
33
|
{
|
|
34
34
|
field: "revokedAt",
|
|
35
35
|
label: i18nKey("sessions.list.col.revokedAt"),
|
|
36
|
+
hideOnNarrow: true,
|
|
36
37
|
renderer: { format: "timestamp" },
|
|
37
38
|
},
|
|
38
39
|
],
|
|
@@ -104,6 +105,7 @@ export const sessionMineScreen = {
|
|
|
104
105
|
{
|
|
105
106
|
field: "current",
|
|
106
107
|
label: i18nKey("sessions.mine.col.current"),
|
|
108
|
+
hideOnNarrow: true,
|
|
107
109
|
renderer: { format: "boolean" },
|
|
108
110
|
},
|
|
109
111
|
],
|