@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
|
@@ -4,6 +4,7 @@ export declare function createNoteEntryEntity(access?: EntityDefinition["access"
|
|
|
4
4
|
readonly type: "text";
|
|
5
5
|
readonly description?: string;
|
|
6
6
|
readonly maxLength?: number;
|
|
7
|
+
readonly minLength?: number;
|
|
7
8
|
readonly required?: boolean;
|
|
8
9
|
readonly searchable?: boolean;
|
|
9
10
|
readonly sortable?: boolean;
|
|
@@ -25,6 +26,7 @@ export declare function createNoteEntryEntity(access?: EntityDefinition["access"
|
|
|
25
26
|
readonly type: "text";
|
|
26
27
|
readonly description?: string;
|
|
27
28
|
readonly maxLength?: number;
|
|
29
|
+
readonly minLength?: number;
|
|
28
30
|
readonly required?: boolean;
|
|
29
31
|
readonly searchable?: boolean;
|
|
30
32
|
readonly sortable?: boolean;
|
|
@@ -46,6 +48,7 @@ export declare function createNoteEntryEntity(access?: EntityDefinition["access"
|
|
|
46
48
|
readonly type: "text";
|
|
47
49
|
readonly description?: string;
|
|
48
50
|
readonly maxLength?: number;
|
|
51
|
+
readonly minLength?: number;
|
|
49
52
|
readonly required?: boolean;
|
|
50
53
|
readonly searchable?: boolean;
|
|
51
54
|
readonly sortable?: boolean;
|
|
@@ -67,6 +70,7 @@ export declare function createNoteEntryEntity(access?: EntityDefinition["access"
|
|
|
67
70
|
readonly type: "text";
|
|
68
71
|
readonly description?: string;
|
|
69
72
|
readonly maxLength?: number;
|
|
73
|
+
readonly minLength?: number;
|
|
70
74
|
readonly required?: boolean;
|
|
71
75
|
readonly searchable?: boolean;
|
|
72
76
|
readonly sortable?: boolean;
|
|
@@ -106,6 +110,7 @@ export declare const noteEntryEntity: EntityDefinition<{
|
|
|
106
110
|
readonly type: "text";
|
|
107
111
|
readonly description?: string;
|
|
108
112
|
readonly maxLength?: number;
|
|
113
|
+
readonly minLength?: number;
|
|
109
114
|
readonly required?: boolean;
|
|
110
115
|
readonly searchable?: boolean;
|
|
111
116
|
readonly sortable?: boolean;
|
|
@@ -127,6 +132,7 @@ export declare const noteEntryEntity: EntityDefinition<{
|
|
|
127
132
|
readonly type: "text";
|
|
128
133
|
readonly description?: string;
|
|
129
134
|
readonly maxLength?: number;
|
|
135
|
+
readonly minLength?: number;
|
|
130
136
|
readonly required?: boolean;
|
|
131
137
|
readonly searchable?: boolean;
|
|
132
138
|
readonly sortable?: boolean;
|
|
@@ -148,6 +154,7 @@ export declare const noteEntryEntity: EntityDefinition<{
|
|
|
148
154
|
readonly type: "text";
|
|
149
155
|
readonly description?: string;
|
|
150
156
|
readonly maxLength?: number;
|
|
157
|
+
readonly minLength?: number;
|
|
151
158
|
readonly required?: boolean;
|
|
152
159
|
readonly searchable?: boolean;
|
|
153
160
|
readonly sortable?: boolean;
|
|
@@ -169,6 +176,7 @@ export declare const noteEntryEntity: EntityDefinition<{
|
|
|
169
176
|
readonly type: "text";
|
|
170
177
|
readonly description?: string;
|
|
171
178
|
readonly maxLength?: number;
|
|
179
|
+
readonly minLength?: number;
|
|
172
180
|
readonly required?: boolean;
|
|
173
181
|
readonly searchable?: boolean;
|
|
174
182
|
readonly sortable?: boolean;
|
|
@@ -208,6 +216,7 @@ export declare function createNoteMentionEntity(): EntityDefinition<{
|
|
|
208
216
|
readonly type: "text";
|
|
209
217
|
readonly description?: string;
|
|
210
218
|
readonly maxLength?: number;
|
|
219
|
+
readonly minLength?: number;
|
|
211
220
|
readonly required?: boolean;
|
|
212
221
|
readonly searchable?: boolean;
|
|
213
222
|
readonly sortable?: boolean;
|
|
@@ -229,6 +238,7 @@ export declare function createNoteMentionEntity(): EntityDefinition<{
|
|
|
229
238
|
readonly type: "text";
|
|
230
239
|
readonly description?: string;
|
|
231
240
|
readonly maxLength?: number;
|
|
241
|
+
readonly minLength?: number;
|
|
232
242
|
readonly required?: boolean;
|
|
233
243
|
readonly searchable?: boolean;
|
|
234
244
|
readonly sortable?: boolean;
|
|
@@ -252,6 +262,7 @@ export declare const noteMentionEntity: EntityDefinition<{
|
|
|
252
262
|
readonly type: "text";
|
|
253
263
|
readonly description?: string;
|
|
254
264
|
readonly maxLength?: number;
|
|
265
|
+
readonly minLength?: number;
|
|
255
266
|
readonly required?: boolean;
|
|
256
267
|
readonly searchable?: boolean;
|
|
257
268
|
readonly sortable?: boolean;
|
|
@@ -273,6 +284,7 @@ export declare const noteMentionEntity: EntityDefinition<{
|
|
|
273
284
|
readonly type: "text";
|
|
274
285
|
readonly description?: string;
|
|
275
286
|
readonly maxLength?: number;
|
|
287
|
+
readonly minLength?: number;
|
|
276
288
|
readonly required?: boolean;
|
|
277
289
|
readonly searchable?: boolean;
|
|
278
290
|
readonly sortable?: boolean;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// a new entry, not an edit; see entity.ts for why that still satisfies GDPR
|
|
14
14
|
// erasure without a delete path.
|
|
15
15
|
import { defineEntityListHandler, defineFeature, } from "@cosmicdrift/kumiko-framework/engine";
|
|
16
|
-
import {
|
|
16
|
+
import { assertNoWhereRuleInOwnershipWrite } from "../shared/index.js";
|
|
17
17
|
import { DEFAULT_NOTES_HISTORY_ACCESS, NOTES_HISTORY_FEATURE_NAME } from "./constants.js";
|
|
18
18
|
import { createNoteEntryEntity, noteMentionEntity } from "./entity.js";
|
|
19
19
|
import { createNoteEntryExecutor } from "./executor.js";
|
|
@@ -58,15 +58,7 @@ export function createNotesHistoryFeature(opts = {}) {
|
|
|
58
58
|
opts.parents === undefined) {
|
|
59
59
|
return notesHistoryFeature;
|
|
60
60
|
}
|
|
61
|
-
|
|
62
|
-
throw new Error("createNotesHistoryFeature({ ownership }): ownership.write must not contain a " +
|
|
63
|
-
'`{ kind: "where" }` rule — where-rules are evaluated only at the SQL ' +
|
|
64
|
-
"layer (the read path, via buildOwnershipClause). Write paths that " +
|
|
65
|
-
"consult access.write (userCanCreateFieldRow/userCanWriteFieldRow) can't " +
|
|
66
|
-
"evaluate them, so such a rule can only ever deny — boot validation " +
|
|
67
|
-
"rejects it too (fw#2626). Use a `from()` rule for ownership.write, or " +
|
|
68
|
-
"leave it unset.");
|
|
69
|
-
}
|
|
61
|
+
assertNoWhereRuleInOwnershipWrite("createNotesHistoryFeature", opts.ownership?.write);
|
|
70
62
|
// A mount that accepts no parents at all can never take a note write —
|
|
71
63
|
// that's a config mistake, not a valid allowlist. Omit `parents` instead
|
|
72
64
|
// of passing an empty array.
|
|
@@ -3,6 +3,7 @@ export declare const apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
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 apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
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 apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
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 apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
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 apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
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 apiTokenEntity: import("@cosmicdrift/kumiko-types/fields").
|
|
|
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;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { i18nKey, MAX_LIST_LIMIT, } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
import {
|
|
2
|
+
import { ACTION_FORM_ENTITY } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
3
|
+
import { fieldOptionLabelKeyPrefix } from "@cosmicdrift/kumiko-headless";
|
|
4
|
+
import { PAT_FEATURE, PAT_MINT_SCREEN_ID, PAT_SCREEN_ID, PatHandlers, PatQueries, } from "./constants.js";
|
|
3
5
|
const PAT_STATUS_OPTION_KEY_PREFIX = "pat.list.status.";
|
|
6
|
+
// Same keys the mint form's `scopes` multiSelect options resolve through
|
|
7
|
+
// (see patScopeOptionTranslations), so list and form show identical labels.
|
|
8
|
+
const PAT_SCOPE_OPTION_KEY_PREFIX = fieldOptionLabelKeyPrefix(PAT_FEATURE, ACTION_FORM_ENTITY, "scopes");
|
|
4
9
|
// Both screens render only for tenants whose tier includes the feature; the
|
|
5
10
|
// availability query is rejected by the feature gate otherwise.
|
|
6
11
|
const PAT_SCREEN_VISIBLE_WHEN = {
|
|
@@ -20,11 +25,17 @@ export const patListScreen = {
|
|
|
20
25
|
defaultSort: { field: "createdAt", dir: "desc" },
|
|
21
26
|
columns: [
|
|
22
27
|
{ field: "name", label: i18nKey("pat.list.col.name") },
|
|
23
|
-
{ field: "prefix", label: i18nKey("pat.list.col.prefix") },
|
|
24
|
-
{
|
|
28
|
+
{ field: "prefix", label: i18nKey("pat.list.col.prefix"), sortable: false },
|
|
29
|
+
{
|
|
30
|
+
field: "scopes",
|
|
31
|
+
label: i18nKey("pat.list.col.scopes"),
|
|
32
|
+
sortable: false,
|
|
33
|
+
renderer: { format: "enumOption", keyPrefix: PAT_SCOPE_OPTION_KEY_PREFIX },
|
|
34
|
+
},
|
|
25
35
|
{
|
|
26
36
|
field: "status",
|
|
27
37
|
label: i18nKey("pat.list.col.status"),
|
|
38
|
+
sortable: false,
|
|
28
39
|
renderer: { format: "enumOption", keyPrefix: PAT_STATUS_OPTION_KEY_PREFIX },
|
|
29
40
|
},
|
|
30
41
|
{
|
package/dist/secrets/table.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare const tenantSecretEntity: import("@cosmicdrift/kumiko-types/field
|
|
|
8
8
|
readonly type: "text";
|
|
9
9
|
readonly description?: string;
|
|
10
10
|
readonly maxLength?: number;
|
|
11
|
+
readonly minLength?: number;
|
|
11
12
|
readonly required?: boolean;
|
|
12
13
|
readonly searchable?: boolean;
|
|
13
14
|
readonly sortable?: boolean;
|
package/dist/seo/feature.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
// kumiko-lint-ignore app-feature-structure Phase-3 conversion tracked in #2312 (feature.ts > 300 lines)
|
|
2
2
|
import { computeRevisionEtag } from "@cosmicdrift/kumiko-framework/api";
|
|
3
3
|
import { defineFeature, SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
|
|
4
|
+
import { RateLimitError } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
5
|
import { LEGAL_ROUTES } from "../legal-pages/index.js";
|
|
5
6
|
import { cachedSecurePageResponse } from "../page-render/index.js";
|
|
7
|
+
import { rateLimitedTextResponse } from "../shared/index.js";
|
|
6
8
|
import { SEO_CONFIG_KEYS, SEO_DEFAULT_PATHS } from "./constants.js";
|
|
7
9
|
import { seoConfigQuery } from "./handlers/seo-config.query.js";
|
|
8
10
|
import { buildLlmsTxt } from "./llms-txt.js";
|
|
@@ -62,7 +64,10 @@ async function gatherEntries(opts, systemQuery, origin, host) {
|
|
|
62
64
|
});
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
|
-
catch {
|
|
67
|
+
catch (error) {
|
|
68
|
+
// A rate limit must not look like "pages removed" to a crawler.
|
|
69
|
+
if (error instanceof RateLimitError)
|
|
70
|
+
throw error;
|
|
66
71
|
// managed-pages unreachable/not mounted — degrade to callback-only entries.
|
|
67
72
|
}
|
|
68
73
|
}
|
|
@@ -113,7 +118,15 @@ export function createSeoFeature(opts) {
|
|
|
113
118
|
anonymous: true,
|
|
114
119
|
handler: async (c, { systemQuery }) => {
|
|
115
120
|
const { origin, host } = requestHost(c);
|
|
116
|
-
|
|
121
|
+
let entries;
|
|
122
|
+
try {
|
|
123
|
+
entries = await gatherEntries(opts, systemQuery, origin, host);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
if (error instanceof RateLimitError)
|
|
127
|
+
return rateLimitedTextResponse(error);
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
117
130
|
const xml = buildSitemapXml(entries);
|
|
118
131
|
const etag = computeRevisionEtag([host, xml]);
|
|
119
132
|
return cachedSecurePageResponse(c.req.raw, {
|
|
@@ -133,10 +146,19 @@ export function createSeoFeature(opts) {
|
|
|
133
146
|
const tenantId = opts.managedPages
|
|
134
147
|
? ((await opts.managedPages.resolveApexTenant(host)) ?? SYSTEM_TENANT_ID)
|
|
135
148
|
: SYSTEM_TENANT_ID;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
149
|
+
let entries;
|
|
150
|
+
let seoConfig;
|
|
151
|
+
try {
|
|
152
|
+
[entries, seoConfig] = await Promise.all([
|
|
153
|
+
gatherEntries(opts, systemQuery, origin, host),
|
|
154
|
+
readSeoConfig(systemQuery, tenantId),
|
|
155
|
+
]);
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
if (error instanceof RateLimitError)
|
|
159
|
+
return rateLimitedTextResponse(error);
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
140
162
|
const sections = entries.length > 0
|
|
141
163
|
? [
|
|
142
164
|
{
|
|
@@ -3,6 +3,7 @@ export declare const userSessionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
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 userSessionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
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;
|
|
@@ -105,6 +107,7 @@ export declare const userSessionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
105
107
|
readonly type: "text";
|
|
106
108
|
readonly description?: string;
|
|
107
109
|
readonly maxLength?: number;
|
|
110
|
+
readonly minLength?: number;
|
|
108
111
|
readonly required?: boolean;
|
|
109
112
|
readonly searchable?: boolean;
|
|
110
113
|
readonly sortable?: boolean;
|
|
@@ -126,6 +129,7 @@ export declare const userSessionEntity: import("@cosmicdrift/kumiko-types/fields
|
|
|
126
129
|
readonly type: "text";
|
|
127
130
|
readonly description?: string;
|
|
128
131
|
readonly maxLength?: number;
|
|
132
|
+
readonly minLength?: number;
|
|
129
133
|
readonly required?: boolean;
|
|
130
134
|
readonly searchable?: boolean;
|
|
131
135
|
readonly sortable?: boolean;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Boot validation rejects `{ kind: "where" }` in access.write too (fw#2626);
|
|
2
|
+
// failing at factory time names the option instead of an entity scope.
|
|
3
|
+
export function assertNoWhereRuleInOwnershipWrite(factoryName, writeOwnership) {
|
|
4
|
+
// skip: no write ownership declared, nothing to validate
|
|
5
|
+
if (!writeOwnership)
|
|
6
|
+
return;
|
|
7
|
+
const hasWhereRule = Object.values(writeOwnership).some((rule) => rule !== "all" && rule.kind === "where");
|
|
8
|
+
// skip: no where-rule present, the option is valid
|
|
9
|
+
if (!hasWhereRule)
|
|
10
|
+
return;
|
|
11
|
+
throw new Error(`${factoryName}({ ownership }): ownership.write must not contain a ` +
|
|
12
|
+
'`{ kind: "where" }` rule — where-rules are evaluated only at the SQL ' +
|
|
13
|
+
"layer (the read path, via buildOwnershipClause). Write paths that " +
|
|
14
|
+
"consult access.write (userCanCreateFieldRow/userCanWriteFieldRow) can't " +
|
|
15
|
+
"evaluate them, so such a rule can only ever deny — boot validation " +
|
|
16
|
+
"rejects it too (fw#2626). Use a `from()` rule for ownership.write, or " +
|
|
17
|
+
"leave it unset.");
|
|
18
|
+
}
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
export { collectErasureFailure, throwIfErasureFailed } from "./assert-erased.js";
|
|
2
|
+
export { assertNoWhereRuleInOwnershipWrite } from "./assert-no-where-rule-in-ownership-write.js";
|
|
2
3
|
export { type ChunkedMigrationOptions, type ChunkedMigrationResult, type ChunkedMigrationStopReason, type MigrationRowOutcome, runChunkedMigration, } from "./chunked-entity-migration.js";
|
|
3
4
|
export { classifyStoredEnvelope, type StoredEnvelopeClassification, } from "./classify-stored-envelope.js";
|
|
4
5
|
export { decryptStoredPii } from "./decrypt-stored-pii.js";
|
|
5
6
|
export { encryptForDirectWrite } from "./encrypt-for-direct-write.js";
|
|
6
7
|
export { entitiesOf } from "./entities-of.js";
|
|
7
8
|
export { isWithinGracePeriod } from "./grace-period.js";
|
|
8
|
-
export { hasWhereRule } from "./has-where-rule.js";
|
|
9
9
|
export { isIdentityV3Hash, verifyIdentityV3Hash } from "./identity-v3-hash.js";
|
|
10
10
|
export { isTenantDb } from "./is-tenant-db.js";
|
|
11
11
|
export { createLockoutCounter, type LockoutCounterState } from "./lockout-counter.js";
|
|
12
12
|
export { mapWithConcurrency } from "./map-with-concurrency.js";
|
|
13
13
|
export { denyUnlessJoinRowParentVisible, joinRowParentIsVisible, parentRowIsVisible, } from "./parent-visibility.js";
|
|
14
14
|
export { hashPassword, verifyDummyPassword, verifyPassword } from "./password-hashing.js";
|
|
15
|
+
export { rateLimitedTextResponse } from "./rate-limited-text-response.js";
|
|
15
16
|
export { redactBotTokens, redactEmailAddresses, redactErrorText, redactUrls, } from "./redact.js";
|
|
16
17
|
export { type RowBoundGrantResult, redeemRowBoundGrant, signRowBoundGrant, } from "./row-bound-grant.js";
|
|
17
18
|
export { runInSubTransaction } from "./run-in-sub-transaction.js";
|
package/dist/shared/index.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
export { collectErasureFailure, throwIfErasureFailed } from "./assert-erased.js";
|
|
2
|
+
export { assertNoWhereRuleInOwnershipWrite } from "./assert-no-where-rule-in-ownership-write.js";
|
|
2
3
|
export { runChunkedMigration, } from "./chunked-entity-migration.js";
|
|
3
4
|
export { classifyStoredEnvelope, } from "./classify-stored-envelope.js";
|
|
4
5
|
export { decryptStoredPii } from "./decrypt-stored-pii.js";
|
|
5
6
|
export { encryptForDirectWrite } from "./encrypt-for-direct-write.js";
|
|
6
7
|
export { entitiesOf } from "./entities-of.js";
|
|
7
8
|
export { isWithinGracePeriod } from "./grace-period.js";
|
|
8
|
-
export { hasWhereRule } from "./has-where-rule.js";
|
|
9
9
|
export { isIdentityV3Hash, verifyIdentityV3Hash } from "./identity-v3-hash.js";
|
|
10
10
|
export { isTenantDb } from "./is-tenant-db.js";
|
|
11
11
|
export { createLockoutCounter } from "./lockout-counter.js";
|
|
12
12
|
export { mapWithConcurrency } from "./map-with-concurrency.js";
|
|
13
13
|
export { denyUnlessJoinRowParentVisible, joinRowParentIsVisible, parentRowIsVisible, } from "./parent-visibility.js";
|
|
14
14
|
export { hashPassword, verifyDummyPassword, verifyPassword } from "./password-hashing.js";
|
|
15
|
+
export { rateLimitedTextResponse } from "./rate-limited-text-response.js";
|
|
15
16
|
export { redactBotTokens, redactEmailAddresses, redactErrorText, redactUrls, } from "./redact.js";
|
|
16
17
|
export { redeemRowBoundGrant, signRowBoundGrant, } from "./row-bound-grant.js";
|
|
17
18
|
export { runInSubTransaction } from "./run-in-sub-transaction.js";
|
package/dist/tags/entity.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare const tagEntity: EntityDefinition<{
|
|
|
4
4
|
readonly type: "text";
|
|
5
5
|
readonly description?: string;
|
|
6
6
|
readonly maxLength?: number;
|
|
7
|
+
readonly minLength?: number;
|
|
7
8
|
readonly required?: boolean;
|
|
8
9
|
readonly searchable?: boolean;
|
|
9
10
|
readonly sortable?: boolean;
|
|
@@ -25,6 +26,7 @@ export declare const tagEntity: EntityDefinition<{
|
|
|
25
26
|
readonly type: "text";
|
|
26
27
|
readonly description?: string;
|
|
27
28
|
readonly maxLength?: number;
|
|
29
|
+
readonly minLength?: number;
|
|
28
30
|
readonly required?: boolean;
|
|
29
31
|
readonly searchable?: boolean;
|
|
30
32
|
readonly sortable?: boolean;
|
|
@@ -46,6 +48,7 @@ export declare const tagEntity: EntityDefinition<{
|
|
|
46
48
|
readonly type: "text";
|
|
47
49
|
readonly description?: string;
|
|
48
50
|
readonly maxLength?: number;
|
|
51
|
+
readonly minLength?: number;
|
|
49
52
|
readonly required?: boolean;
|
|
50
53
|
readonly searchable?: boolean;
|
|
51
54
|
readonly sortable?: boolean;
|
|
@@ -69,6 +72,7 @@ export declare function createTagAssignmentEntity(access?: EntityDefinition["acc
|
|
|
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 function createTagAssignmentEntity(access?: EntityDefinition["acc
|
|
|
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;
|
|
@@ -111,6 +116,7 @@ export declare function createTagAssignmentEntity(access?: EntityDefinition["acc
|
|
|
111
116
|
readonly type: "text";
|
|
112
117
|
readonly description?: string;
|
|
113
118
|
readonly maxLength?: number;
|
|
119
|
+
readonly minLength?: number;
|
|
114
120
|
readonly required?: boolean;
|
|
115
121
|
readonly searchable?: boolean;
|
|
116
122
|
readonly sortable?: boolean;
|
|
@@ -134,6 +140,7 @@ export declare const tagAssignmentEntity: EntityDefinition<{
|
|
|
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 tagAssignmentEntity: EntityDefinition<{
|
|
|
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 tagAssignmentEntity: EntityDefinition<{
|
|
|
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;
|
package/dist/tags/feature.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// entityList/entityEdit catalog screens (legacy QNs stay for TagManager).
|
|
19
19
|
// Deferred: optional host-projection decoration (`wireTagsFor`), search indexing.
|
|
20
20
|
import { defineEntityDetailHandler, defineEntityListHandler, defineEntityUpdateHandler, defineFeature, } from "@cosmicdrift/kumiko-framework/engine";
|
|
21
|
-
import {
|
|
21
|
+
import { assertNoWhereRuleInOwnershipWrite } from "../shared/index.js";
|
|
22
22
|
import { DEFAULT_TAG_ACCESS, TAGS_FEATURE_NAME } from "./constants.js";
|
|
23
23
|
import { createTagAssignmentEntity, tagEntity } from "./entity.js";
|
|
24
24
|
import { createTagAssignmentExecutor } from "./executor.js";
|
|
@@ -109,15 +109,7 @@ export function createTagsFeature(opts = {}) {
|
|
|
109
109
|
"assignment row. Omit `parents` to keep every registered entity " +
|
|
110
110
|
"admissible as a host instead.");
|
|
111
111
|
}
|
|
112
|
-
|
|
113
|
-
throw new Error("createTagsFeature({ ownership }): ownership.write must not contain a " +
|
|
114
|
-
'`{ kind: "where" }` rule — where-rules are evaluated only at the SQL ' +
|
|
115
|
-
"layer (the read path, via buildOwnershipClause). Write paths that " +
|
|
116
|
-
"consult access.write (userCanCreateFieldRow/userCanWriteFieldRow) can't " +
|
|
117
|
-
"evaluate them, so such a rule can only ever deny — boot validation " +
|
|
118
|
-
"rejects it too (fw#2626). Use a `from()` rule for ownership.write, or " +
|
|
119
|
-
"leave it unset.");
|
|
120
|
-
}
|
|
112
|
+
assertNoWhereRuleInOwnershipWrite("createTagsFeature", opts.ownership?.write);
|
|
121
113
|
const access = resolveAccess(opts);
|
|
122
114
|
return defineFeature(TAGS_FEATURE_NAME, (r) => registerTags(r, access, opts.toggleable, opts.ownership, opts.parents));
|
|
123
115
|
}
|