@cosmicdrift/kumiko-bundled-features 0.352.0 → 0.353.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/agent-tools/agent-manifest.js +8 -2
- package/dist/agent-tools/manifest-deny-qns.d.ts +3 -0
- package/dist/agent-tools/manifest-deny-qns.js +17 -0
- package/dist/agent-tools/tool-catalog.d.ts +2 -1
- package/dist/agent-tools/tool-catalog.js +4 -1
- package/dist/audit/handlers/list.query.js +13 -8
- package/dist/auth-email-password/handlers/signup-confirm.write.js +2 -3
- package/dist/auth-mfa/schema/user-mfa.d.ts +6 -0
- package/dist/auth-mfa/screens.js +2 -2
- package/dist/billing-foundation/checkout-core.d.ts +7 -0
- package/dist/billing-foundation/checkout-core.js +7 -2
- package/dist/billing-foundation/entities.d.ts +8 -0
- package/dist/billing-foundation/handlers/start-plan-checkout.write.js +7 -1
- package/dist/billing-foundation/projection.d.ts +8 -0
- package/dist/cap-counter/entity.d.ts +1 -0
- package/dist/cap-overview/access.js +2 -9
- package/dist/cap-overview/handlers/tenant-caps-list.query.js +2 -2
- package/dist/cap-overview/handlers/tenant-options.query.js +4 -5
- package/dist/compliance-profiles/schema/profile-selection.d.ts +8 -8
- package/dist/compliance-profiles-ops/handlers/tenants-missing-profile.query.js +2 -4
- package/dist/config/handlers/values.query.d.ts +3 -1
- package/dist/config/handlers/values.query.js +7 -2
- package/dist/config/table.d.ts +6 -0
- package/dist/custom-fields/entity.d.ts +4 -0
- package/dist/data-retention/schema/tenant-retention-override.d.ts +4 -0
- package/dist/delivery/public-names.js +1 -1
- package/dist/delivery/tables.d.ts +6 -0
- package/dist/document-ingest-foundation/entity.d.ts +4 -0
- package/dist/files-tenant-data/hooks.js +3 -2
- package/dist/folders/entity.d.ts +8 -0
- package/dist/folders/feature.js +2 -10
- package/dist/form-draft/db/queries/cleanup.d.ts +1 -1
- package/dist/form-draft/db/queries/cleanup.js +4 -3
- package/dist/form-draft/entity.d.ts +2 -0
- package/dist/form-draft/handlers/cleanup.job.d.ts +5 -1
- package/dist/form-draft/handlers/cleanup.job.js +11 -5
- package/dist/inbound-mail-foundation/entities.d.ts +25 -0
- package/dist/inbound-mail-foundation/projection.d.ts +20 -0
- package/dist/jobs/handlers/list.query.d.ts +2 -1
- package/dist/jobs/handlers/list.query.js +39 -14
- package/dist/jobs/i18n.js +1 -0
- package/dist/jobs/job-run-table.d.ts +6 -0
- package/dist/ledger/entity.d.ts +21 -8
- package/dist/ledger/entity.js +4 -0
- package/dist/ledger/schemas.js +8 -2
- package/dist/managed-pages/feature.js +28 -10
- package/dist/managed-pages/table.d.ts +12 -0
- package/dist/notes-history/entity.d.ts +12 -0
- package/dist/notes-history/feature.js +2 -10
- package/dist/personal-access-tokens/schema/api-token.d.ts +6 -0
- package/dist/personal-access-tokens/screens.js +14 -3
- package/dist/secrets/table.d.ts +1 -0
- package/dist/seo/feature.js +28 -6
- package/dist/sessions/schema/user-session.d.ts +4 -0
- package/dist/shared/assert-no-where-rule-in-ownership-write.d.ts +2 -0
- package/dist/shared/assert-no-where-rule-in-ownership-write.js +18 -0
- package/dist/shared/index.d.ts +2 -1
- package/dist/shared/index.js +2 -1
- package/dist/shared/rate-limited-text-response.d.ts +2 -0
- package/dist/shared/rate-limited-text-response.js +9 -0
- package/dist/tags/entity.d.ts +9 -0
- package/dist/tags/feature.js +2 -10
- package/dist/template-resolver/table.d.ts +40 -30
- package/dist/template-resolver/user-content-table.d.ts +30 -20
- package/dist/tenant/decrypt-tenant-names.d.ts +3 -0
- package/dist/tenant/decrypt-tenant-names.js +10 -0
- package/dist/tenant/handlers/me.query.js +5 -1
- package/dist/tenant/handlers/memberships.query.js +3 -2
- package/dist/tenant/handlers/tenant-directory.query.js +9 -3
- package/dist/tenant/index.d.ts +1 -0
- package/dist/tenant/index.js +1 -0
- package/dist/tenant/invitation-table.d.ts +14 -8
- package/dist/tenant/membership-table.d.ts +4 -0
- package/dist/tenant/schema/tenant.d.ts +16 -10
- package/dist/tenant/schema/tenant.js +4 -6
- package/dist/tenant/screens.js +1 -1
- package/dist/tenant-handover/move-entity-graph.js +11 -18
- package/dist/tenant-lifecycle/feature.js +1 -0
- package/dist/tenant-lifecycle/run-tenant-destroy.d.ts +3 -0
- package/dist/tenant-lifecycle/run-tenant-destroy.js +2 -0
- package/dist/tenant-lifecycle/stages.d.ts +2 -0
- package/dist/tenant-lifecycle/stages.js +7 -1
- package/dist/tier-engine/entity.d.ts +2 -0
- package/dist/tier-engine/tier-resolver.d.ts +2 -0
- package/dist/user/handlers/list.query.js +2 -2
- package/dist/user/schema/user.d.ts +20 -8
- package/dist/user-data-rights/boot-checks.js +5 -0
- package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +2 -2
- 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 +14 -8
- package/dist/waitlist/entity.d.ts +20 -6
- package/dist/workflow-runner/event-trigger.js +6 -3
- package/dist/workflow-runner/handlers/resume-run.write.js +3 -0
- package/package.json +9 -9
- package/src/agent-tools/changes.json +12 -0
- package/src/audit/changes.json +6 -0
- package/src/form-draft/changes.json +7 -1
- package/src/managed-pages/changes.json +6 -0
- package/src/seo/changes.json +5 -0
- package/src/tenant/changes.json +7 -0
- package/src/tenant-handover/changes.json +6 -0
- package/src/workflow-runner/changes.json +5 -0
- package/dist/shared/has-where-rule.d.ts +0 -2
- package/dist/shared/has-where-rule.js +0 -10
|
@@ -3,6 +3,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
|
|
|
3
3
|
readonly type: "text";
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
6
|
+
readonly minLength?: number;
|
|
6
7
|
readonly required?: boolean;
|
|
7
8
|
readonly searchable?: boolean;
|
|
8
9
|
readonly sortable?: boolean;
|
|
@@ -24,6 +25,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
|
|
|
24
25
|
readonly type: "text";
|
|
25
26
|
readonly description?: string;
|
|
26
27
|
readonly maxLength?: number;
|
|
28
|
+
readonly minLength?: number;
|
|
27
29
|
readonly required?: boolean;
|
|
28
30
|
readonly searchable?: boolean;
|
|
29
31
|
readonly sortable?: boolean;
|
|
@@ -45,6 +47,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
|
|
|
45
47
|
readonly type: "text";
|
|
46
48
|
readonly description?: string;
|
|
47
49
|
readonly maxLength?: number;
|
|
50
|
+
readonly minLength?: number;
|
|
48
51
|
readonly required?: boolean;
|
|
49
52
|
readonly searchable?: boolean;
|
|
50
53
|
readonly sortable?: boolean;
|
|
@@ -66,6 +69,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
|
|
|
66
69
|
readonly type: "text";
|
|
67
70
|
readonly description?: string;
|
|
68
71
|
readonly maxLength?: number;
|
|
72
|
+
readonly minLength?: number;
|
|
69
73
|
readonly required?: boolean;
|
|
70
74
|
readonly searchable?: boolean;
|
|
71
75
|
readonly sortable?: boolean;
|
|
@@ -87,6 +91,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
|
|
|
87
91
|
readonly type: "text";
|
|
88
92
|
readonly description?: string;
|
|
89
93
|
readonly maxLength?: number;
|
|
94
|
+
readonly minLength?: number;
|
|
90
95
|
readonly required?: boolean;
|
|
91
96
|
readonly searchable?: boolean;
|
|
92
97
|
readonly sortable?: boolean;
|
|
@@ -108,6 +113,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
|
|
|
108
113
|
readonly type: "text";
|
|
109
114
|
readonly description?: string;
|
|
110
115
|
readonly maxLength?: number;
|
|
116
|
+
readonly minLength?: number;
|
|
111
117
|
readonly required?: boolean;
|
|
112
118
|
readonly searchable?: boolean;
|
|
113
119
|
readonly sortable?: boolean;
|
|
@@ -129,6 +135,7 @@ export declare const mailAccountsProjectionTable: import("@cosmicdrift/kumiko-fr
|
|
|
129
135
|
readonly type: "text";
|
|
130
136
|
readonly description?: string;
|
|
131
137
|
readonly maxLength?: number;
|
|
138
|
+
readonly minLength?: number;
|
|
132
139
|
readonly required?: boolean;
|
|
133
140
|
readonly searchable?: boolean;
|
|
134
141
|
readonly sortable?: boolean;
|
|
@@ -167,6 +174,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
|
|
|
167
174
|
readonly type: "text";
|
|
168
175
|
readonly description?: string;
|
|
169
176
|
readonly maxLength?: number;
|
|
177
|
+
readonly minLength?: number;
|
|
170
178
|
readonly required?: boolean;
|
|
171
179
|
readonly searchable?: boolean;
|
|
172
180
|
readonly sortable?: boolean;
|
|
@@ -188,6 +196,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
|
|
|
188
196
|
readonly type: "text";
|
|
189
197
|
readonly description?: string;
|
|
190
198
|
readonly maxLength?: number;
|
|
199
|
+
readonly minLength?: number;
|
|
191
200
|
readonly required?: boolean;
|
|
192
201
|
readonly searchable?: boolean;
|
|
193
202
|
readonly sortable?: boolean;
|
|
@@ -209,6 +218,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
|
|
|
209
218
|
readonly type: "text";
|
|
210
219
|
readonly description?: string;
|
|
211
220
|
readonly maxLength?: number;
|
|
221
|
+
readonly minLength?: number;
|
|
212
222
|
readonly required?: boolean;
|
|
213
223
|
readonly searchable?: boolean;
|
|
214
224
|
readonly sortable?: boolean;
|
|
@@ -230,6 +240,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
|
|
|
230
240
|
readonly type: "text";
|
|
231
241
|
readonly description?: string;
|
|
232
242
|
readonly maxLength?: number;
|
|
243
|
+
readonly minLength?: number;
|
|
233
244
|
readonly required?: boolean;
|
|
234
245
|
readonly searchable?: boolean;
|
|
235
246
|
readonly sortable?: boolean;
|
|
@@ -251,6 +262,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
|
|
|
251
262
|
readonly type: "text";
|
|
252
263
|
readonly description?: string;
|
|
253
264
|
readonly maxLength?: number;
|
|
265
|
+
readonly minLength?: number;
|
|
254
266
|
readonly required?: boolean;
|
|
255
267
|
readonly searchable?: boolean;
|
|
256
268
|
readonly sortable?: boolean;
|
|
@@ -272,6 +284,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
|
|
|
272
284
|
readonly type: "text";
|
|
273
285
|
readonly description?: string;
|
|
274
286
|
readonly maxLength?: number;
|
|
287
|
+
readonly minLength?: number;
|
|
275
288
|
readonly required?: boolean;
|
|
276
289
|
readonly searchable?: boolean;
|
|
277
290
|
readonly sortable?: boolean;
|
|
@@ -293,6 +306,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
|
|
|
293
306
|
readonly type: "text";
|
|
294
307
|
readonly description?: string;
|
|
295
308
|
readonly maxLength?: number;
|
|
309
|
+
readonly minLength?: number;
|
|
296
310
|
readonly required?: boolean;
|
|
297
311
|
readonly searchable?: boolean;
|
|
298
312
|
readonly sortable?: boolean;
|
|
@@ -314,6 +328,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
|
|
|
314
328
|
readonly type: "text";
|
|
315
329
|
readonly description?: string;
|
|
316
330
|
readonly maxLength?: number;
|
|
331
|
+
readonly minLength?: number;
|
|
317
332
|
readonly required?: boolean;
|
|
318
333
|
readonly searchable?: boolean;
|
|
319
334
|
readonly sortable?: boolean;
|
|
@@ -335,6 +350,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
|
|
|
335
350
|
readonly type: "text";
|
|
336
351
|
readonly description?: string;
|
|
337
352
|
readonly maxLength?: number;
|
|
353
|
+
readonly minLength?: number;
|
|
338
354
|
readonly required?: boolean;
|
|
339
355
|
readonly searchable?: boolean;
|
|
340
356
|
readonly sortable?: boolean;
|
|
@@ -371,6 +387,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
|
|
|
371
387
|
readonly type: "text";
|
|
372
388
|
readonly description?: string;
|
|
373
389
|
readonly maxLength?: number;
|
|
390
|
+
readonly minLength?: number;
|
|
374
391
|
readonly required?: boolean;
|
|
375
392
|
readonly searchable?: boolean;
|
|
376
393
|
readonly sortable?: boolean;
|
|
@@ -392,6 +409,7 @@ export declare const inboundMessagesProjectionTable: import("@cosmicdrift/kumiko
|
|
|
392
409
|
readonly type: "text";
|
|
393
410
|
readonly description?: string;
|
|
394
411
|
readonly maxLength?: number;
|
|
412
|
+
readonly minLength?: number;
|
|
395
413
|
readonly required?: boolean;
|
|
396
414
|
readonly searchable?: boolean;
|
|
397
415
|
readonly sortable?: boolean;
|
|
@@ -415,6 +433,7 @@ export declare const mailThreadsProjectionTable: import("@cosmicdrift/kumiko-fra
|
|
|
415
433
|
readonly type: "text";
|
|
416
434
|
readonly description?: string;
|
|
417
435
|
readonly maxLength?: number;
|
|
436
|
+
readonly minLength?: number;
|
|
418
437
|
readonly required?: boolean;
|
|
419
438
|
readonly searchable?: boolean;
|
|
420
439
|
readonly sortable?: boolean;
|
|
@@ -436,6 +455,7 @@ export declare const mailThreadsProjectionTable: import("@cosmicdrift/kumiko-fra
|
|
|
436
455
|
readonly type: "text";
|
|
437
456
|
readonly description?: string;
|
|
438
457
|
readonly maxLength?: number;
|
|
458
|
+
readonly minLength?: number;
|
|
439
459
|
readonly required?: boolean;
|
|
440
460
|
readonly searchable?: boolean;
|
|
441
461
|
readonly sortable?: boolean;
|
|
@@ -28,9 +28,10 @@ export declare const listQuery: import("@cosmicdrift/kumiko-types/define-handler
|
|
|
28
28
|
desc: "desc";
|
|
29
29
|
}>>;
|
|
30
30
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
31
32
|
totalCount: z.ZodOptional<z.ZodBoolean>;
|
|
32
33
|
}, z.core.$strip>, {
|
|
33
34
|
rows: any[];
|
|
34
|
-
nextCursor: null;
|
|
35
|
+
nextCursor: string | null;
|
|
35
36
|
total?: number | undefined;
|
|
36
37
|
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { countWhere, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
|
+
import { decodeCursor, encodeCursor } from "@cosmicdrift/kumiko-framework/db";
|
|
2
3
|
import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
-
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
|
+
import { InternalError, ValidationError } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
5
|
import * as z from "zod";
|
|
5
6
|
import { decryptStoredPii, mapWithConcurrency } from "../../shared/index.js";
|
|
6
7
|
import { jobRunsTable } from "../job-run-table.js";
|
|
7
8
|
const KMS_POOL_CONCURRENCY = 4;
|
|
9
|
+
const DEFAULT_PAGE_SIZE = 50;
|
|
8
10
|
const jobRunStatusSchema = z.enum(["queued", "running", "completed", "failed"]);
|
|
9
11
|
async function decryptRunRow(row) {
|
|
10
12
|
let result = row;
|
|
@@ -19,6 +21,26 @@ async function decryptRunRow(row) {
|
|
|
19
21
|
}
|
|
20
22
|
return result;
|
|
21
23
|
}
|
|
24
|
+
function buildListWhere(payload) {
|
|
25
|
+
const where = {};
|
|
26
|
+
if (payload.jobName)
|
|
27
|
+
where["jobName"] = payload.jobName;
|
|
28
|
+
const statuses = payload.filters?.[0]?.value ?? (payload.status ? [payload.status] : []);
|
|
29
|
+
if (statuses.length === 1)
|
|
30
|
+
where["status"] = statuses[0];
|
|
31
|
+
else if (statuses.length > 1)
|
|
32
|
+
where["status"] = { in: statuses };
|
|
33
|
+
return where;
|
|
34
|
+
}
|
|
35
|
+
function parseOffsetCursor(cursor) {
|
|
36
|
+
const offset = cursor ? Number(decodeCursor(cursor)) : 0;
|
|
37
|
+
if (!Number.isInteger(offset) || offset < 0) {
|
|
38
|
+
throw new ValidationError({
|
|
39
|
+
fields: [{ path: "cursor", code: "invalid_cursor", i18nKey: "jobs.errors.invalidCursor" }],
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return offset;
|
|
43
|
+
}
|
|
22
44
|
export const listQuery = defineQueryHandler({
|
|
23
45
|
name: "list",
|
|
24
46
|
description: "Lists job runs across all tenants newest-first, optionally filtered by job name and status; use it to check whether a job ran and whether it succeeded.",
|
|
@@ -35,6 +57,7 @@ export const listQuery = defineQueryHandler({
|
|
|
35
57
|
sort: z.enum(["jobName", "status", "startedAt", "duration"]).optional(),
|
|
36
58
|
sortDirection: z.enum(["asc", "desc"]).optional(),
|
|
37
59
|
limit: z.number().optional(),
|
|
60
|
+
cursor: z.string().optional(),
|
|
38
61
|
totalCount: z.boolean().optional(),
|
|
39
62
|
}),
|
|
40
63
|
access: { roles: ["SystemAdmin"] },
|
|
@@ -45,27 +68,29 @@ export const listQuery = defineQueryHandler({
|
|
|
45
68
|
});
|
|
46
69
|
}
|
|
47
70
|
const db = ctx.systemDb.unsafeRaw("cross-tenant job monitoring: SystemAdmin lists job runs of every tenant");
|
|
48
|
-
const where =
|
|
49
|
-
if (query.payload.jobName)
|
|
50
|
-
where["jobName"] = query.payload.jobName;
|
|
51
|
-
const statusFilter = query.payload.filters?.find((filter) => filter.field === "status");
|
|
52
|
-
const statuses = statusFilter?.value ?? (query.payload.status ? [query.payload.status] : []);
|
|
53
|
-
if (statuses.length === 1)
|
|
54
|
-
where["status"] = statuses[0];
|
|
55
|
-
else if (statuses.length > 1)
|
|
56
|
-
where["status"] = { in: statuses };
|
|
71
|
+
const where = buildListWhere(query.payload);
|
|
57
72
|
const sortColumn = query.payload.sort ?? "startedAt";
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
73
|
+
const limit = query.payload.limit ?? DEFAULT_PAGE_SIZE;
|
|
74
|
+
const offset = parseOffsetCursor(query.payload.cursor);
|
|
75
|
+
const direction = query.payload.sortDirection ?? "desc";
|
|
76
|
+
// selectMany has no OFFSET: read through the end of the page plus one probe
|
|
77
|
+
// row, then slice. `id` as tiebreaker keeps pages stable for non-unique sorts.
|
|
78
|
+
const fetched = await selectMany(db, jobRunsTable, where, {
|
|
79
|
+
orderBy: [
|
|
80
|
+
{ col: sortColumn, direction },
|
|
81
|
+
{ col: "id", direction },
|
|
82
|
+
],
|
|
83
|
+
limit: offset + limit + 1,
|
|
61
84
|
});
|
|
85
|
+
const hasMore = fetched.length > offset + limit;
|
|
86
|
+
const rows = fetched.slice(offset, offset + limit);
|
|
62
87
|
// countWhere reruns the SAME `where` without the limit — `rows.length` is
|
|
63
88
|
// capped at the page size and would silently undercount the total.
|
|
64
89
|
const total = query.payload.totalCount === true ? await countWhere(db, jobRunsTable, where) : undefined;
|
|
65
90
|
// payload/error are stored encrypted under the triggering user's DEK (#799, #2307).
|
|
66
91
|
return {
|
|
67
92
|
rows: await mapWithConcurrency(rows, KMS_POOL_CONCURRENCY, decryptRunRow),
|
|
68
|
-
nextCursor: null,
|
|
93
|
+
nextCursor: hasMore ? encodeCursor(String(offset + limit)) : null,
|
|
69
94
|
...(total !== undefined && { total }),
|
|
70
95
|
};
|
|
71
96
|
},
|
package/dist/jobs/i18n.js
CHANGED
|
@@ -33,6 +33,7 @@ export const JOBS_I18N = {
|
|
|
33
33
|
"jobs.detail.logs": { en: "Logs" },
|
|
34
34
|
"jobs.detail.retry": { en: "Retry" },
|
|
35
35
|
"jobs.trigger.title": { en: "Run a job" },
|
|
36
|
+
"jobs.errors.invalidCursor": { en: "The pagination cursor is invalid." },
|
|
36
37
|
"jobs.trigger.submit": { en: "Run" },
|
|
37
38
|
"jobs.errors.unknownJob": { en: "Unknown job." },
|
|
38
39
|
"jobs.errors.notManual": {
|
|
@@ -6,6 +6,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
|
|
|
6
6
|
readonly type: "text";
|
|
7
7
|
readonly description?: string;
|
|
8
8
|
readonly maxLength?: number;
|
|
9
|
+
readonly minLength?: number;
|
|
9
10
|
readonly required?: boolean;
|
|
10
11
|
readonly searchable?: boolean;
|
|
11
12
|
readonly sortable?: boolean;
|
|
@@ -27,6 +28,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
|
|
|
27
28
|
readonly type: "text";
|
|
28
29
|
readonly description?: string;
|
|
29
30
|
readonly maxLength?: number;
|
|
31
|
+
readonly minLength?: number;
|
|
30
32
|
readonly required?: boolean;
|
|
31
33
|
readonly searchable?: boolean;
|
|
32
34
|
readonly sortable?: boolean;
|
|
@@ -48,6 +50,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
|
|
|
48
50
|
readonly type: "text";
|
|
49
51
|
readonly description?: string;
|
|
50
52
|
readonly maxLength?: number;
|
|
53
|
+
readonly minLength?: number;
|
|
51
54
|
readonly required?: boolean;
|
|
52
55
|
readonly searchable?: boolean;
|
|
53
56
|
readonly sortable?: boolean;
|
|
@@ -69,6 +72,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
|
|
|
69
72
|
readonly type: "text";
|
|
70
73
|
readonly description?: string;
|
|
71
74
|
readonly maxLength?: number;
|
|
75
|
+
readonly minLength?: number;
|
|
72
76
|
readonly required?: boolean;
|
|
73
77
|
readonly searchable?: boolean;
|
|
74
78
|
readonly sortable?: boolean;
|
|
@@ -90,6 +94,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
|
|
|
90
94
|
readonly type: "text";
|
|
91
95
|
readonly description?: string;
|
|
92
96
|
readonly maxLength?: number;
|
|
97
|
+
readonly minLength?: number;
|
|
93
98
|
readonly required?: boolean;
|
|
94
99
|
readonly searchable?: boolean;
|
|
95
100
|
readonly sortable?: boolean;
|
|
@@ -179,6 +184,7 @@ export declare const jobRunEntity: import("@cosmicdrift/kumiko-types/fields").En
|
|
|
179
184
|
readonly type: "text";
|
|
180
185
|
readonly description?: string;
|
|
181
186
|
readonly maxLength?: number;
|
|
187
|
+
readonly minLength?: number;
|
|
182
188
|
readonly required?: boolean;
|
|
183
189
|
readonly searchable?: boolean;
|
|
184
190
|
readonly sortable?: boolean;
|
package/dist/ledger/entity.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export declare const accountEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
3
3
|
readonly type: "text";
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
6
|
+
readonly minLength?: number;
|
|
6
7
|
readonly required?: boolean;
|
|
7
8
|
readonly searchable?: boolean;
|
|
8
9
|
readonly sortable?: boolean;
|
|
@@ -32,11 +33,11 @@ export declare const accountEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
32
33
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
33
34
|
readonly display?: "radio" | "dropdown";
|
|
34
35
|
readonly optionTones?: {
|
|
35
|
-
readonly asset?:
|
|
36
|
-
readonly equity?:
|
|
37
|
-
readonly expense?:
|
|
38
|
-
readonly income?:
|
|
39
|
-
readonly liability?:
|
|
36
|
+
readonly asset?: "bad" | "neutral" | "ok" | "warn" | undefined;
|
|
37
|
+
readonly equity?: "bad" | "neutral" | "ok" | "warn" | undefined;
|
|
38
|
+
readonly expense?: "bad" | "neutral" | "ok" | "warn" | undefined;
|
|
39
|
+
readonly income?: "bad" | "neutral" | "ok" | "warn" | undefined;
|
|
40
|
+
readonly liability?: "bad" | "neutral" | "ok" | "warn" | undefined;
|
|
40
41
|
} | undefined;
|
|
41
42
|
readonly optionsQuery?: string;
|
|
42
43
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
@@ -48,6 +49,7 @@ export declare const accountEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
48
49
|
readonly type: "text";
|
|
49
50
|
readonly description?: string;
|
|
50
51
|
readonly maxLength?: number;
|
|
52
|
+
readonly minLength?: number;
|
|
51
53
|
readonly required?: boolean;
|
|
52
54
|
readonly searchable?: boolean;
|
|
53
55
|
readonly sortable?: boolean;
|
|
@@ -69,6 +71,7 @@ export declare const accountEntity: import("@cosmicdrift/kumiko-types/fields").E
|
|
|
69
71
|
readonly type: "text";
|
|
70
72
|
readonly description?: string;
|
|
71
73
|
readonly maxLength?: number;
|
|
74
|
+
readonly minLength?: number;
|
|
72
75
|
readonly required?: boolean;
|
|
73
76
|
readonly searchable?: boolean;
|
|
74
77
|
readonly sortable?: boolean;
|
|
@@ -106,6 +109,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
106
109
|
readonly type: "text";
|
|
107
110
|
readonly description?: string;
|
|
108
111
|
readonly maxLength?: number;
|
|
112
|
+
readonly minLength?: number;
|
|
109
113
|
readonly required?: boolean;
|
|
110
114
|
readonly searchable?: boolean;
|
|
111
115
|
readonly sortable?: boolean;
|
|
@@ -127,6 +131,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
127
131
|
readonly type: "text";
|
|
128
132
|
readonly description?: string;
|
|
129
133
|
readonly maxLength?: number;
|
|
134
|
+
readonly minLength?: number;
|
|
130
135
|
readonly required?: boolean;
|
|
131
136
|
readonly searchable?: boolean;
|
|
132
137
|
readonly sortable?: boolean;
|
|
@@ -156,8 +161,8 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
156
161
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
157
162
|
readonly display?: "radio" | "dropdown";
|
|
158
163
|
readonly optionTones?: {
|
|
159
|
-
readonly draft?:
|
|
160
|
-
readonly posted?:
|
|
164
|
+
readonly draft?: "bad" | "neutral" | "ok" | "warn" | undefined;
|
|
165
|
+
readonly posted?: "bad" | "neutral" | "ok" | "warn" | undefined;
|
|
161
166
|
} | undefined;
|
|
162
167
|
readonly optionsQuery?: string;
|
|
163
168
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
@@ -185,6 +190,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
185
190
|
readonly type: "text";
|
|
186
191
|
readonly description?: string;
|
|
187
192
|
readonly maxLength?: number;
|
|
193
|
+
readonly minLength?: number;
|
|
188
194
|
readonly required?: boolean;
|
|
189
195
|
readonly searchable?: boolean;
|
|
190
196
|
readonly sortable?: boolean;
|
|
@@ -206,6 +212,7 @@ export declare const transactionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
206
212
|
readonly type: "text";
|
|
207
213
|
readonly description?: string;
|
|
208
214
|
readonly maxLength?: number;
|
|
215
|
+
readonly minLength?: number;
|
|
209
216
|
readonly required?: boolean;
|
|
210
217
|
readonly searchable?: boolean;
|
|
211
218
|
readonly sortable?: boolean;
|
|
@@ -229,6 +236,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
229
236
|
readonly type: "text";
|
|
230
237
|
readonly description?: string;
|
|
231
238
|
readonly maxLength?: number;
|
|
239
|
+
readonly minLength?: number;
|
|
232
240
|
readonly required?: boolean;
|
|
233
241
|
readonly searchable?: boolean;
|
|
234
242
|
readonly sortable?: boolean;
|
|
@@ -286,7 +294,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
286
294
|
readonly access?: import("@cosmicdrift/kumiko-types/fields").FieldAccess;
|
|
287
295
|
readonly display?: "radio" | "dropdown";
|
|
288
296
|
readonly optionTones?: {
|
|
289
|
-
readonly monthly?:
|
|
297
|
+
readonly monthly?: "bad" | "neutral" | "ok" | "warn" | undefined;
|
|
290
298
|
} | undefined;
|
|
291
299
|
readonly optionsQuery?: string;
|
|
292
300
|
readonly optionsQueryPayload?: import("@cosmicdrift/kumiko-types/fields").OptionsQueryPayload;
|
|
@@ -317,6 +325,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
317
325
|
readonly type: "text";
|
|
318
326
|
readonly description?: string;
|
|
319
327
|
readonly maxLength?: number;
|
|
328
|
+
readonly minLength?: number;
|
|
320
329
|
readonly required?: boolean;
|
|
321
330
|
readonly searchable?: boolean;
|
|
322
331
|
readonly sortable?: boolean;
|
|
@@ -338,6 +347,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
338
347
|
readonly type: "text";
|
|
339
348
|
readonly description?: string;
|
|
340
349
|
readonly maxLength?: number;
|
|
350
|
+
readonly minLength?: number;
|
|
341
351
|
readonly required?: boolean;
|
|
342
352
|
readonly searchable?: boolean;
|
|
343
353
|
readonly sortable?: boolean;
|
|
@@ -359,6 +369,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
359
369
|
readonly type: "text";
|
|
360
370
|
readonly description?: string;
|
|
361
371
|
readonly maxLength?: number;
|
|
372
|
+
readonly minLength?: number;
|
|
362
373
|
readonly required?: boolean;
|
|
363
374
|
readonly searchable?: boolean;
|
|
364
375
|
readonly sortable?: boolean;
|
|
@@ -380,6 +391,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
380
391
|
readonly type: "text";
|
|
381
392
|
readonly description?: string;
|
|
382
393
|
readonly maxLength?: number;
|
|
394
|
+
readonly minLength?: number;
|
|
383
395
|
readonly required?: boolean;
|
|
384
396
|
readonly searchable?: boolean;
|
|
385
397
|
readonly sortable?: boolean;
|
|
@@ -401,6 +413,7 @@ export declare const scheduleEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
401
413
|
readonly type: "text";
|
|
402
414
|
readonly description?: string;
|
|
403
415
|
readonly maxLength?: number;
|
|
416
|
+
readonly minLength?: number;
|
|
404
417
|
readonly required?: boolean;
|
|
405
418
|
readonly searchable?: boolean;
|
|
406
419
|
readonly sortable?: boolean;
|
package/dist/ledger/entity.js
CHANGED
|
@@ -80,12 +80,14 @@ export const transactionEntity = createEntity({
|
|
|
80
80
|
// Optional business-object reference (e.g. a lease contract) so entries can
|
|
81
81
|
// be filtered by what they're about, not just grepped out of `reference`.
|
|
82
82
|
subjectType: createTextField({
|
|
83
|
+
minLength: 1,
|
|
83
84
|
maxLength: 64,
|
|
84
85
|
personal: false,
|
|
85
86
|
reason: "technical_reference",
|
|
86
87
|
filterable: true,
|
|
87
88
|
}),
|
|
88
89
|
subjectId: createTextField({
|
|
90
|
+
minLength: 1,
|
|
89
91
|
maxLength: 128,
|
|
90
92
|
personal: false,
|
|
91
93
|
reason: "technical_reference",
|
|
@@ -131,12 +133,14 @@ export const scheduleEntity = createEntity({
|
|
|
131
133
|
// Confirmed periods inherit this from the schedule (see
|
|
132
134
|
// confirm-schedule-period.write.ts) rather than repeating it per period.
|
|
133
135
|
subjectType: createTextField({
|
|
136
|
+
minLength: 1,
|
|
134
137
|
maxLength: 64,
|
|
135
138
|
personal: false,
|
|
136
139
|
reason: "technical_reference",
|
|
137
140
|
filterable: true,
|
|
138
141
|
}),
|
|
139
142
|
subjectId: createTextField({
|
|
143
|
+
minLength: 1,
|
|
140
144
|
maxLength: 128,
|
|
141
145
|
personal: false,
|
|
142
146
|
reason: "technical_reference",
|
package/dist/ledger/schemas.js
CHANGED
|
@@ -21,8 +21,14 @@ export const createTransactionPayloadSchema = z
|
|
|
21
21
|
status: z.enum(TRANSACTION_STATUS).optional(),
|
|
22
22
|
lines: z.array(postingSchema).min(2),
|
|
23
23
|
// Business-object reference (e.g. a lease contract) this entry is about.
|
|
24
|
-
subjectType: z.string().max(64).optional(),
|
|
25
|
-
subjectId: z.string().max(128).optional(),
|
|
24
|
+
subjectType: z.string().min(1).max(64).optional(),
|
|
25
|
+
subjectId: z.string().min(1).max(128).optional(),
|
|
26
|
+
})
|
|
27
|
+
// Ids are only unique within their type, so a lone subjectId would match
|
|
28
|
+
// bookings of a different object type.
|
|
29
|
+
.refine((p) => (p.subjectType === undefined) === (p.subjectId === undefined), {
|
|
30
|
+
message: "subjectType and subjectId must be set together",
|
|
31
|
+
path: ["subjectId"],
|
|
26
32
|
})
|
|
27
33
|
.refine((p) => sumIsZero(p.lines), {
|
|
28
34
|
message: "Transaction must balance: Σ of posting amounts must equal 0",
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { computeRevisionEtag, etagMatches } from "@cosmicdrift/kumiko-framework/api";
|
|
2
2
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
+
import { RateLimitError } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
4
|
import { cachedSecurePageResponse, EMPTY_BRANDING, renderSafeMarkdown, wrapInLayout, } from "../page-render/index.js";
|
|
5
|
+
import { rateLimitedTextResponse } from "../shared/index.js";
|
|
4
6
|
import { BRANDING_KEYS, BRANDING_QUERY_QN, CUSTOM_CSS_KEY, coerceBranding } from "./branding.js";
|
|
5
7
|
import { createBrandingQuery } from "./handlers/branding.query.js";
|
|
6
8
|
import { bySlugQuery } from "./handlers/by-slug.query.js";
|
|
@@ -28,14 +30,17 @@ function brandingRevisionSeed(branding) {
|
|
|
28
30
|
branding.customCss,
|
|
29
31
|
]);
|
|
30
32
|
}
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
33
|
+
// A query failure or malformed result degrades to the unbranded default
|
|
34
|
+
// (branding is decoration, not a hard dependency of the page render). A rate
|
|
35
|
+
// limit is rethrown so the route answers 429 instead of serving (and caching)
|
|
36
|
+
// an unbranded page.
|
|
34
37
|
async function readBrandingViaSystemQuery(systemQuery, tenantId) {
|
|
35
38
|
try {
|
|
36
39
|
return coerceBranding(await systemQuery(BRANDING_QUERY_QN, {}, tenantId));
|
|
37
40
|
}
|
|
38
|
-
catch {
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error instanceof RateLimitError)
|
|
43
|
+
throw error;
|
|
39
44
|
return EMPTY_BRANDING;
|
|
40
45
|
}
|
|
41
46
|
}
|
|
@@ -125,12 +130,25 @@ export function createManagedPagesFeature(opts) {
|
|
|
125
130
|
// von resolverTrust: "authoritative" zurecht abgelehnt; siehe
|
|
126
131
|
// systemQuery's Doc in http-route.ts). Branding ist Deko → ein
|
|
127
132
|
// Fehlschlag degradiert zum unbranded Default, blockt nie die Page.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
133
|
+
let pageSettled;
|
|
134
|
+
let brandingResult;
|
|
135
|
+
try {
|
|
136
|
+
[pageSettled, brandingResult] = await Promise.all([
|
|
137
|
+
systemQuery(BY_SLUG_QN, { slug, lang }, tenantId)
|
|
138
|
+
.then((data) => ({ ok: true, data: data }))
|
|
139
|
+
.catch((error) => {
|
|
140
|
+
if (error instanceof RateLimitError)
|
|
141
|
+
throw error;
|
|
142
|
+
return { ok: false };
|
|
143
|
+
}),
|
|
144
|
+
readBrandingViaSystemQuery(systemQuery, tenantId),
|
|
145
|
+
]);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
if (error instanceof RateLimitError)
|
|
149
|
+
return rateLimitedTextResponse(error);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
134
152
|
if (!pageSettled.ok)
|
|
135
153
|
return c.text("page unavailable", 503);
|
|
136
154
|
const data = pageSettled.data;
|
|
@@ -3,6 +3,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
3
3
|
readonly type: "text";
|
|
4
4
|
readonly description?: string;
|
|
5
5
|
readonly maxLength?: number;
|
|
6
|
+
readonly minLength?: number;
|
|
6
7
|
readonly required?: boolean;
|
|
7
8
|
readonly searchable?: boolean;
|
|
8
9
|
readonly sortable?: boolean;
|
|
@@ -24,6 +25,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
24
25
|
readonly type: "text";
|
|
25
26
|
readonly description?: string;
|
|
26
27
|
readonly maxLength?: number;
|
|
28
|
+
readonly minLength?: number;
|
|
27
29
|
readonly required?: boolean;
|
|
28
30
|
readonly searchable?: boolean;
|
|
29
31
|
readonly sortable?: boolean;
|
|
@@ -45,6 +47,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
45
47
|
readonly type: "text";
|
|
46
48
|
readonly description?: string;
|
|
47
49
|
readonly maxLength?: number;
|
|
50
|
+
readonly minLength?: number;
|
|
48
51
|
readonly required?: boolean;
|
|
49
52
|
readonly searchable?: boolean;
|
|
50
53
|
readonly sortable?: boolean;
|
|
@@ -66,6 +69,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
66
69
|
readonly type: "text";
|
|
67
70
|
readonly description?: string;
|
|
68
71
|
readonly maxLength?: number;
|
|
72
|
+
readonly minLength?: number;
|
|
69
73
|
readonly required?: boolean;
|
|
70
74
|
readonly searchable?: boolean;
|
|
71
75
|
readonly sortable?: boolean;
|
|
@@ -87,6 +91,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
87
91
|
readonly type: "text";
|
|
88
92
|
readonly description?: string;
|
|
89
93
|
readonly maxLength?: number;
|
|
94
|
+
readonly minLength?: number;
|
|
90
95
|
readonly required?: boolean;
|
|
91
96
|
readonly searchable?: boolean;
|
|
92
97
|
readonly sortable?: boolean;
|
|
@@ -108,6 +113,7 @@ export declare const pageEntity: import("@cosmicdrift/kumiko-types/fields").Enti
|
|
|
108
113
|
readonly type: "text";
|
|
109
114
|
readonly description?: string;
|
|
110
115
|
readonly maxLength?: number;
|
|
116
|
+
readonly minLength?: number;
|
|
111
117
|
readonly required?: boolean;
|
|
112
118
|
readonly searchable?: boolean;
|
|
113
119
|
readonly sortable?: boolean;
|
|
@@ -134,6 +140,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
134
140
|
readonly type: "text";
|
|
135
141
|
readonly description?: string;
|
|
136
142
|
readonly maxLength?: number;
|
|
143
|
+
readonly minLength?: number;
|
|
137
144
|
readonly required?: boolean;
|
|
138
145
|
readonly searchable?: boolean;
|
|
139
146
|
readonly sortable?: boolean;
|
|
@@ -155,6 +162,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
155
162
|
readonly type: "text";
|
|
156
163
|
readonly description?: string;
|
|
157
164
|
readonly maxLength?: number;
|
|
165
|
+
readonly minLength?: number;
|
|
158
166
|
readonly required?: boolean;
|
|
159
167
|
readonly searchable?: boolean;
|
|
160
168
|
readonly sortable?: boolean;
|
|
@@ -176,6 +184,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
176
184
|
readonly type: "text";
|
|
177
185
|
readonly description?: string;
|
|
178
186
|
readonly maxLength?: number;
|
|
187
|
+
readonly minLength?: number;
|
|
179
188
|
readonly required?: boolean;
|
|
180
189
|
readonly searchable?: boolean;
|
|
181
190
|
readonly sortable?: boolean;
|
|
@@ -197,6 +206,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
197
206
|
readonly type: "text";
|
|
198
207
|
readonly description?: string;
|
|
199
208
|
readonly maxLength?: number;
|
|
209
|
+
readonly minLength?: number;
|
|
200
210
|
readonly required?: boolean;
|
|
201
211
|
readonly searchable?: boolean;
|
|
202
212
|
readonly sortable?: boolean;
|
|
@@ -218,6 +228,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
218
228
|
readonly type: "text";
|
|
219
229
|
readonly description?: string;
|
|
220
230
|
readonly maxLength?: number;
|
|
231
|
+
readonly minLength?: number;
|
|
221
232
|
readonly required?: boolean;
|
|
222
233
|
readonly searchable?: boolean;
|
|
223
234
|
readonly sortable?: boolean;
|
|
@@ -239,6 +250,7 @@ export declare const pagesTable: import("@cosmicdrift/kumiko-framework/db").Enti
|
|
|
239
250
|
readonly type: "text";
|
|
240
251
|
readonly description?: string;
|
|
241
252
|
readonly maxLength?: number;
|
|
253
|
+
readonly minLength?: number;
|
|
242
254
|
readonly required?: boolean;
|
|
243
255
|
readonly searchable?: boolean;
|
|
244
256
|
readonly sortable?: boolean;
|