@cosmicdrift/kumiko-types 0.386.0 → 0.387.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/LICENSE +21 -57
- package/README.md +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/entity-table-meta-types.js +1 -1
- package/dist/event-store-executor-types.d.ts +1 -1
- package/dist/event-store-types.js +1 -1
- package/dist/event-type-map.js +12 -12
- package/dist/feature.d.ts +23 -23
- package/dist/fields.d.ts +113 -115
- package/dist/fields.js +6 -3
- package/dist/handlers.d.ts +19 -21
- package/dist/http-route.d.ts +15 -15
- package/dist/http-route.js +1 -1
- package/dist/screen-action-form.d.ts +3 -3
- package/dist/screen-custom-config.d.ts +7 -8
- package/dist/screen-entity-edit.d.ts +1 -1
- package/dist/screen-entity-list.d.ts +2 -2
- package/dist/screen-projection.d.ts +2 -2
- package/dist/screen.d.ts +1 -1
- package/dist/step.d.ts +1 -1
- package/dist/target-ref.js +10 -13
- package/dist/tree-node.js +17 -17
- package/package.json +2 -2
package/LICENSE
CHANGED
|
@@ -1,57 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
controlling, or under common control with the Licensor ("Affiliates"), or
|
|
23
|
-
contractors acting on their behalf. The Licensor remains free to use the
|
|
24
|
-
Licensed Work for any purpose, including for the operation of kumiko.rocks.
|
|
25
|
-
|
|
26
|
-
Change Date: 2030-05-05
|
|
27
|
-
Change License: Apache License, Version 2.0
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Terms
|
|
31
|
-
|
|
32
|
-
The Licensor hereby grants you the right to copy, modify, create derivative works,
|
|
33
|
-
redistribute, and make non-production use of the Licensed Work. The Licensor may
|
|
34
|
-
make an Additional Use Grant, above, permitting limited production use.
|
|
35
|
-
|
|
36
|
-
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
37
|
-
available distribution of the Licensed Work under this License, whichever comes
|
|
38
|
-
first, this License will convert to the Change License.
|
|
39
|
-
|
|
40
|
-
This Business Source License governs use of the Licensed Work in all cases, except
|
|
41
|
-
as to any use that is explicitly granted in the Additional Use Grant above or
|
|
42
|
-
under the Change License after the Change Date.
|
|
43
|
-
|
|
44
|
-
If your use of the Licensed Work does not comply with the requirements of this
|
|
45
|
-
License, you must cease use of the Licensed Work immediately.
|
|
46
|
-
|
|
47
|
-
All copies of the Licensed Work, and all derivative works thereof, must include
|
|
48
|
-
this License.
|
|
49
|
-
|
|
50
|
-
This License does not grant you any right, title, or interest in any trademark,
|
|
51
|
-
logo, or branding of the Licensor, except as required to comply with this License.
|
|
52
|
-
|
|
53
|
-
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
|
|
54
|
-
“AS IS” BASIS. LICENSOR DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
|
55
|
-
WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
|
56
|
-
TITLE, AND NON-INFRINGEMENT. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DAMAGES
|
|
57
|
-
ARISING OUT OF OR RELATED TO THIS LICENSE OR THE USE OF THE LICENSED WORK.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marc Frost
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @cosmicdrift/kumiko-types
|
|
2
2
|
|
|
3
|
-
[](../../LICENSE)
|
|
4
4
|
[](https://www.typescriptlang.org/)
|
|
5
5
|
|
|
6
6
|
Framework type definitions for Kumiko — `FeatureDefinition`, boot-check types,
|
package/dist/config.d.ts
CHANGED
|
@@ -50,7 +50,7 @@ export type ConfigKeyDefinition<T extends ConfigKeyType = ConfigKeyType> = {
|
|
|
50
50
|
* encrypted under the DEK of the scope actually written to (tenant-row
|
|
51
51
|
* → tenant subject, user-row → user subject). Only on `type: "text"`,
|
|
52
52
|
* `scope !== "system"` (no subject there), and mutually exclusive with
|
|
53
|
-
* `encrypted
|
|
53
|
+
* `encrypted`. */
|
|
54
54
|
readonly piiEncrypted?: boolean;
|
|
55
55
|
readonly options?: readonly string[];
|
|
56
56
|
/** Only on `type: "select"`: loads the options from this query (QN), contract
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
// Plain-data types for EntityTableMeta — split from the runtime
|
|
3
3
|
// (deriveEntityTableMeta, resolveTableName, defineUnmanagedTable) in
|
|
4
4
|
// entity-table-meta.ts. Prep step for the types-only package extraction
|
|
5
|
-
//
|
|
5
|
+
// — this file must have ONLY `import type`, no value imports
|
|
6
6
|
// (crypto/DB deps).
|
|
7
7
|
export {};
|
|
@@ -64,7 +64,7 @@ export type EventStoreExecutor<Row extends Record<string, unknown> = Record<stri
|
|
|
64
64
|
readonly value: unknown;
|
|
65
65
|
}> | undefined;
|
|
66
66
|
}, user: SessionUser, db: TenantDb,
|
|
67
|
-
/**
|
|
67
|
+
/** Per-call SearchAdapter override. When the
|
|
68
68
|
* executor didn't get a SearchAdapter via Options at build time
|
|
69
69
|
* (defaultEntityQueryHandler path), the caller (handler) can pass
|
|
70
70
|
* one from ctx.searchAdapter here at runtime.
|
|
@@ -3,5 +3,5 @@ export function isPersonalDataGated(origin) {
|
|
|
3
3
|
}
|
|
4
4
|
// Stamped when an append runs outside any attributed scope (seed scripts,
|
|
5
5
|
// tests, direct event-store use). A distinct value, not an omission —
|
|
6
|
-
// omitted would be indistinguishable from
|
|
6
|
+
// omitted would be indistinguishable from an earlier row.
|
|
7
7
|
export const UNATTRIBUTED_ORIGIN = "unknown";
|
package/dist/event-type-map.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
// Cross-Feature Compile-Time
|
|
1
|
+
// Cross-Feature Compile-Time Type Map.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// (zod-validate)
|
|
6
|
-
//
|
|
7
|
-
//
|
|
3
|
+
// Purpose: check ctx.appendEvent / ctx.queryProjection / dispatcher.write against a
|
|
4
|
+
// statically known schema image instead of failing only at boot or runtime
|
|
5
|
+
// (zod-validate). The Designer/AI layer benefits immediately: autocomplete knows all
|
|
6
|
+
// event types from all loaded features, and payload-shape mismatches appear in the
|
|
7
|
+
// editor rather than only at boot.
|
|
8
8
|
//
|
|
9
|
-
//
|
|
10
|
-
// —
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
9
|
+
// Each feature populates the map through `declare module "@cosmicdrift/kumiko-framework/engine"`
|
|
10
|
+
// — either manually (for stable framework internals) or through the code-generation
|
|
11
|
+
// script (for apps/bundled-features). Empty defaults are not a bug: a feature without
|
|
12
|
+
// augmentation is runtime-pluggable and uses the fallback overload with `unknown`
|
|
13
|
+
// payload.
|
|
14
14
|
//
|
|
15
|
-
// Pattern
|
|
15
|
+
// Pattern for a manually written augmentation at the top of the file:
|
|
16
16
|
//
|
|
17
17
|
// declare module "@cosmicdrift/kumiko-framework/engine" {
|
|
18
18
|
// interface KumikoEventTypeMap {
|
package/dist/feature.d.ts
CHANGED
|
@@ -79,7 +79,7 @@ export type StoreTableOptions = {
|
|
|
79
79
|
/** Direct-write stores skip the executor, so the executor's PII
|
|
80
80
|
* encryption never runs for them — a feature whose meta carries
|
|
81
81
|
* piiSubjectFields must encrypt those fields itself before every
|
|
82
|
-
* insert/update and declare that here, or boot fails
|
|
82
|
+
* insert/update and declare that here, or boot fails. */
|
|
83
83
|
readonly piiEncryptedOnWrite?: true;
|
|
84
84
|
};
|
|
85
85
|
/** Per-feature store-table registration. `meta` is the `EntityTableMeta`
|
|
@@ -152,17 +152,17 @@ export type FeatureDefinition = {
|
|
|
152
152
|
readonly extensionSelectors: readonly ExtensionSelectorDef[];
|
|
153
153
|
/**
|
|
154
154
|
* Cross-feature API names this feature exposes via `r.exposesApi(name)`.
|
|
155
|
-
* Pure
|
|
156
|
-
*
|
|
157
|
-
* `compliance-profiles:query:effective-profile`).
|
|
158
|
-
*
|
|
159
|
-
*
|
|
155
|
+
* Pure marker declaration — the implementation is registered separately as
|
|
156
|
+
* a query or write handler under the QN pattern (for example,
|
|
157
|
+
* `compliance-profiles:query:effective-profile`). The boot validator checks
|
|
158
|
+
* that every `r.usesApi(name)` finds a matching exposer, so typos or dropped
|
|
159
|
+
* refactors fail at boot instead of causing a runtime crash.
|
|
160
160
|
*/
|
|
161
161
|
readonly exposedApis: ReadonlySet<string>;
|
|
162
162
|
/**
|
|
163
|
-
* Cross-feature API names this feature calls.
|
|
164
|
-
*
|
|
165
|
-
*
|
|
163
|
+
* Cross-feature API names this feature calls. The boot check requires every
|
|
164
|
+
* entry to appear in some feature's `exposedApis` and the provider feature
|
|
165
|
+
* to be listed in requires/optionalRequires.
|
|
166
166
|
*/
|
|
167
167
|
readonly usedApis: ReadonlySet<string>;
|
|
168
168
|
/**
|
|
@@ -406,30 +406,30 @@ export type FeatureRegistrar<TFeature extends string = string> = {
|
|
|
406
406
|
readonly panels?: readonly ExtensionSelectorPanel[];
|
|
407
407
|
}): void;
|
|
408
408
|
/**
|
|
409
|
-
* Marker
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
409
|
+
* Marker declaration: this feature provides a cross-feature API under the
|
|
410
|
+
* given name. The implementation is registered separately as a query or
|
|
411
|
+
* write handler under the QN pattern; `r.exposesApi` is only a boot-check
|
|
412
|
+
* surface.
|
|
413
413
|
*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
414
|
+
* The boot validator checks that every `r.usesApi(name)` finds a matching
|
|
415
|
+
* exposer, that the exposer feature is listed in requires/optionalRequires,
|
|
416
|
+
* and that no API name is exposed more than once.
|
|
417
417
|
*
|
|
418
418
|
* ```ts
|
|
419
419
|
* defineFeature("compliance-profiles", (r) => {
|
|
420
420
|
* r.exposesApi("compliance.forTenant");
|
|
421
421
|
* r.queryHandler({
|
|
422
422
|
* name: "compliance:query:for-tenant",
|
|
423
|
-
* // ...
|
|
423
|
+
* // ... actual implementation
|
|
424
424
|
* });
|
|
425
425
|
* });
|
|
426
426
|
* ```
|
|
427
427
|
*/
|
|
428
428
|
exposesApi(apiName: string): void;
|
|
429
429
|
/**
|
|
430
|
-
* Declares that this feature calls a cross-feature API.
|
|
431
|
-
*
|
|
432
|
-
*
|
|
430
|
+
* Declares that this feature calls a cross-feature API. The boot validator
|
|
431
|
+
* checks that another feature provides `r.exposesApi(apiName)` and that
|
|
432
|
+
* this feature lists it in `r.requires/optionalRequires`.
|
|
433
433
|
*
|
|
434
434
|
* ```ts
|
|
435
435
|
* defineFeature("user-data-rights", (r) => {
|
|
@@ -447,9 +447,9 @@ export type FeatureRegistrar<TFeature extends string = string> = {
|
|
|
447
447
|
* Use for cross-feature invariants that `r.requires` can't express
|
|
448
448
|
* because they're conditional (only fail when the feature has a
|
|
449
449
|
* specific shape), e.g. "if this feature has PII entities, some
|
|
450
|
-
* user-data-hook feature must be mounted" (the prompt-store trap
|
|
451
|
-
*
|
|
452
|
-
*
|
|
450
|
+
* user-data-hook feature must be mounted" (the prompt-store trap —
|
|
451
|
+
* a UserData feature was written but never mounted, and nothing caught
|
|
452
|
+
* it at boot):
|
|
453
453
|
*
|
|
454
454
|
* ```ts
|
|
455
455
|
* defineFeature("prompt-store", (r) => {
|
package/dist/fields.d.ts
CHANGED
|
@@ -17,11 +17,10 @@ export type ResolvedPiiFlags = {
|
|
|
17
17
|
readonly recordOwned?: true;
|
|
18
18
|
readonly anonymize?: () => unknown | Promise<unknown>;
|
|
19
19
|
readonly allowPlaintext?: string;
|
|
20
|
-
/** Equality
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* Siehe docs/plans/datenschutz/blind-index.md (kumiko-framework#818). */
|
|
20
|
+
/** Equality lookups (`fetchOne`/`filter eq`) remain possible despite encryption:
|
|
21
|
+
* the generated `<snake>_bidx` column carries an HMAC blind index, and the
|
|
22
|
+
* query compiler matches `(col = $1 OR col_bidx = $2)`. Allowed only on text
|
|
23
|
+
* fields with subject annotations, as enforced by the boot validator. */
|
|
25
24
|
readonly lookupable?: true;
|
|
26
25
|
/** Foreign key into the `user` entity (authorId, assigneeId, ...) with no
|
|
27
26
|
* annotated content of its own. Triggers no encryption — feeds only the
|
|
@@ -94,9 +93,9 @@ export type TextFieldDef = {
|
|
|
94
93
|
readonly required?: boolean;
|
|
95
94
|
readonly searchable?: boolean;
|
|
96
95
|
readonly sortable?: boolean;
|
|
97
|
-
/**
|
|
98
|
-
*
|
|
99
|
-
* Default: false
|
|
96
|
+
/** Allows screen filters on this field.
|
|
97
|
+
* The boot validator rejects filters with `filterable !== true`.
|
|
98
|
+
* Default: false, analogous to `sortable`, and therefore opt-in. */
|
|
100
99
|
readonly filterable?: boolean;
|
|
101
100
|
readonly encrypted?: boolean;
|
|
102
101
|
readonly sensitive?: boolean;
|
|
@@ -125,40 +124,38 @@ export type TextFieldDef = {
|
|
|
125
124
|
readonly format?: "email" | "url" | "phone" | "password" | "month" | "iban";
|
|
126
125
|
readonly default?: string;
|
|
127
126
|
readonly access?: FieldAccess;
|
|
128
|
-
/**
|
|
129
|
-
* <input type="text">. `true`
|
|
130
|
-
*
|
|
131
|
-
*
|
|
127
|
+
/** Multiline text causes DefaultInput to render a <textarea> instead of
|
|
128
|
+
* <input type="text">. `true` uses four rows by default; `{ rows: N }`
|
|
129
|
+
* sets an explicit height. Search, sort, and encryption remain unchanged;
|
|
130
|
+
* only the rendering surface differs. */
|
|
132
131
|
readonly multiline?: boolean | {
|
|
133
132
|
readonly rows?: number;
|
|
134
133
|
};
|
|
135
134
|
} & ResolvedPiiFlags;
|
|
136
135
|
/**
|
|
137
|
-
* Long-form text content — source
|
|
138
|
-
* templates, anything that can be megabytes large.
|
|
139
|
-
*
|
|
136
|
+
* Long-form text content — source code, markdown, blog posts, email
|
|
137
|
+
* templates, and anything that can be megabytes large. Its surface is
|
|
138
|
+
* intentionally minimal compared with `text`:
|
|
140
139
|
*
|
|
141
|
-
* - **
|
|
142
|
-
*
|
|
143
|
-
* - **
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* - **
|
|
148
|
-
*
|
|
149
|
-
* - **Kein `format`**: email/url/phone sind kurz definierte Inputs,
|
|
150
|
-
* longText ist per Definition unstrukturiert.
|
|
140
|
+
* - **No `sortable`**: ordering 100 KB strings costs I/O without useful UX;
|
|
141
|
+
* lexicographic ordering of code is not meaningful.
|
|
142
|
+
* - **No `searchable`**: ILIKE/substring searches do not scale on long text.
|
|
143
|
+
* Full-text search should use the SearchAdapter (Meilisearch), which has
|
|
144
|
+
* its own tokenizer and index rather than this field flag.
|
|
145
|
+
* - **No `filterable`**: filtering long strings has the same issue as sorting.
|
|
146
|
+
* - **No `format`**: email/url/phone are short, structured inputs, whereas
|
|
147
|
+
* longText is unstructured by definition.
|
|
151
148
|
*
|
|
152
|
-
* Type-level enforcement
|
|
153
|
-
*
|
|
154
|
-
*
|
|
149
|
+
* Type-level enforcement means callers who need sorting or searching must use
|
|
150
|
+
* `text` and accept its scaling trade-offs. Database mapping is identical to
|
|
151
|
+
* `text` (Postgres `text` is unbounded).
|
|
155
152
|
*/
|
|
156
153
|
export type LongTextFieldDef = {
|
|
157
154
|
readonly type: "longText";
|
|
158
155
|
readonly description?: string;
|
|
159
|
-
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
156
|
+
/** Optional soft cap. Default is unbounded (= Postgres text limit, 1 GB).
|
|
157
|
+
* Useful for defensive limits such as 1 MB so an accidental browser paste
|
|
158
|
+
* does not overwhelm the database. */
|
|
162
159
|
readonly maxLength?: number;
|
|
163
160
|
readonly required?: boolean;
|
|
164
161
|
readonly encrypted?: boolean;
|
|
@@ -265,7 +262,7 @@ export type MultiSelectFieldDef<TOptions extends readonly string[] = readonly st
|
|
|
265
262
|
readonly required?: boolean;
|
|
266
263
|
readonly filterable?: boolean;
|
|
267
264
|
readonly sensitive?: boolean;
|
|
268
|
-
/** Default
|
|
265
|
+
/** Default selection. Every entry must occur in `options` (boot validator). */
|
|
269
266
|
readonly default?: readonly TOptions[number][];
|
|
270
267
|
readonly access?: FieldAccess;
|
|
271
268
|
/** Renderer metadata: `"checkboxes"` renders every option as a visible
|
|
@@ -321,16 +318,15 @@ export type NumberFieldDef = {
|
|
|
321
318
|
readonly grouping?: boolean;
|
|
322
319
|
} & ResolvedPiiFlags;
|
|
323
320
|
/**
|
|
324
|
-
* 64-bit
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
321
|
+
* 64-bit integer field for audit counters, byte sizes, event IDs, and other
|
|
322
|
+
* values that can exceed 2^31 (~2.1 billion). Stored as Postgres `bigint`,
|
|
323
|
+
* with a JavaScript `number` round trip (`mode:"number"`, safe through 2^53
|
|
324
|
+
* ≈ 9 PB and JSON-serializable). Values above 2^53 should use a `text` field
|
|
325
|
+
* with a custom codec.
|
|
329
326
|
*
|
|
330
|
-
*
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
* hat dafuer den eigenen `MoneyFieldDef` (mit Currency-Spalte).
|
|
327
|
+
* Prefer this over `NumberFieldDef`'s 32-bit integer cap whenever a value can
|
|
328
|
+
* physically exceed that limit: bytes, events, high-throughput counters, and
|
|
329
|
+
* cumulative sums. Money has its own `MoneyFieldDef` with a currency column.
|
|
334
330
|
*/
|
|
335
331
|
export type BigIntFieldDef = {
|
|
336
332
|
readonly type: "bigInt";
|
|
@@ -368,9 +364,9 @@ export type DecimalFieldDef = {
|
|
|
368
364
|
} & ResolvedPiiFlags;
|
|
369
365
|
/** Where a money field's currency comes from. `"tenant"` is the
|
|
370
366
|
* tenant-settings bundle's per-tenant currency (`tenant-settings:config:
|
|
371
|
-
* currency
|
|
372
|
-
* is checked against the app's `currencies` list at boot
|
|
373
|
-
*
|
|
367
|
+
* currency`); `"literal"` names a fixed ISO code and
|
|
368
|
+
* is checked against the app's `currencies` list at boot.
|
|
369
|
+
* Discriminated union so a `{ kind: "field", of }`
|
|
374
370
|
* variant (amount and currency-picker side by side) can still be added
|
|
375
371
|
* without a breaking change, once a multi-currency form actually exists. */
|
|
376
372
|
export type MoneyCurrencySource = {
|
|
@@ -382,7 +378,7 @@ export type MoneyCurrencySource = {
|
|
|
382
378
|
/** Qualified config key a `{ kind: "tenant" }` MoneyCurrencySource resolves
|
|
383
379
|
* against — the tenant-settings bundle's per-tenant currency. Lives here
|
|
384
380
|
* (client-safe) rather than framework/engine so renderer code can read it
|
|
385
|
-
* without a runtime-only import
|
|
381
|
+
* without a runtime-only import. */
|
|
386
382
|
export declare const TENANT_CURRENCY_CONFIG_KEY = "tenant-settings:config:currency";
|
|
387
383
|
export type MoneyFieldDef = {
|
|
388
384
|
readonly type: "money";
|
|
@@ -406,27 +402,27 @@ export type ReferenceFieldDef = {
|
|
|
406
402
|
readonly filterable?: boolean;
|
|
407
403
|
readonly sensitive?: boolean;
|
|
408
404
|
readonly access?: FieldAccess;
|
|
409
|
-
/**
|
|
410
|
-
*
|
|
411
|
-
*
|
|
405
|
+
/** Field of the referenced entity displayed as the Select dropdown label.
|
|
406
|
+
* Default: "id". The boot validator ensures that the field exists on the
|
|
407
|
+
* referenced entity. */
|
|
412
408
|
readonly labelField?: string;
|
|
413
|
-
/** Multi-
|
|
414
|
-
*
|
|
415
|
-
*
|
|
409
|
+
/** Multi-reference: the value is an array of UUIDs rather than a single UUID.
|
|
410
|
+
* Stored as a jsonb array of UUIDs; the UI renders a multi-select combobox
|
|
411
|
+
* with tags for the selected items. */
|
|
416
412
|
readonly multiple?: boolean;
|
|
417
413
|
/** Include a row in this entity's result set on a text-search hit against
|
|
418
414
|
* the referenced entity's `labelField`, instead of only matching the UUID
|
|
419
|
-
* column itself
|
|
415
|
+
* column itself. Requires an explicit `labelField` — the boot
|
|
420
416
|
* validator rejects it otherwise, since the default "id" is a UUID column
|
|
421
417
|
* and ILIKE against it would crash at runtime. */
|
|
422
418
|
readonly searchable?: true;
|
|
423
419
|
/** Order a list by the referenced entity's `labelField` instead of by the raw
|
|
424
|
-
* UUID column
|
|
420
|
+
* UUID column. Requires an explicit, non-"id" `labelField` — the
|
|
425
421
|
* boot validator rejects it otherwise, since ordering by a UUID produces a
|
|
426
422
|
* sequence that looks meaningful to the user but is arbitrary. */
|
|
427
423
|
readonly sortable?: true;
|
|
428
424
|
/** Fill the picker from this query handler instead of the referenced
|
|
429
|
-
* entity's own list handler
|
|
425
|
+
* entity's own list handler — for targets whose identity is
|
|
430
426
|
* composed from joined rows, where no single column of the referenced
|
|
431
427
|
* entity is a readable label. Fully-qualified QN
|
|
432
428
|
* ("<feature>:query:<short>"), boot-validated against the registered
|
|
@@ -481,7 +477,7 @@ export type EmbeddedSubFieldDef = (EmbeddedSubFieldBase & {
|
|
|
481
477
|
readonly type: "reference";
|
|
482
478
|
readonly entity: string;
|
|
483
479
|
readonly labelField?: string;
|
|
484
|
-
/** Same contract as `ReferenceFieldDef.optionsQuery
|
|
480
|
+
/** Same contract as `ReferenceFieldDef.optionsQuery`. */
|
|
485
481
|
readonly optionsQuery?: string;
|
|
486
482
|
});
|
|
487
483
|
/** A cell computed from other cells of the same row. `from` names the
|
|
@@ -535,7 +531,7 @@ export type EmbeddedFieldDef = {
|
|
|
535
531
|
* field's amount. Validated both client- and server-side (schema-builder
|
|
536
532
|
* superRefine). Only meaningful with `multiple: true`. Compares against
|
|
537
533
|
* rounded `derived` cells, i.e. "sum-of-rounded" not "round-of-sum" —
|
|
538
|
-
* see
|
|
534
|
+
* see the embedded-list totals-matching behavior. */
|
|
539
535
|
readonly totalsMatch?: Readonly<Record<string, string>>;
|
|
540
536
|
} & ResolvedPiiFlags;
|
|
541
537
|
export type JsonbFieldDef = {
|
|
@@ -557,13 +553,13 @@ export type DateFieldDef = {
|
|
|
557
553
|
readonly filterable?: boolean;
|
|
558
554
|
readonly sensitive?: boolean;
|
|
559
555
|
readonly access?: FieldAccess;
|
|
560
|
-
/**
|
|
561
|
-
* in
|
|
562
|
-
* Zod
|
|
556
|
+
/** Permitted date bounds as ISO `yyyy-mm-dd` (for example, a birth date
|
|
557
|
+
* cannot be in the future when `max` is today). The bounds constrain the
|
|
558
|
+
* picker and are enforced by the Zod schema on write. */
|
|
563
559
|
readonly min?: string;
|
|
564
560
|
readonly max?: string;
|
|
565
|
-
/** Format/
|
|
566
|
-
* "de-DE"). Default
|
|
561
|
+
/** Format/locale override for display and input parsing (for example,
|
|
562
|
+
* "de-DE"). Default: app locale. */
|
|
567
563
|
readonly locale?: string;
|
|
568
564
|
} & ResolvedPiiFlags;
|
|
569
565
|
export type TimestampFieldDef = {
|
|
@@ -575,21 +571,20 @@ export type TimestampFieldDef = {
|
|
|
575
571
|
readonly sensitive?: boolean;
|
|
576
572
|
readonly access?: FieldAccess;
|
|
577
573
|
/**
|
|
578
|
-
* Marker:
|
|
579
|
-
*
|
|
574
|
+
* Marker: this timestamp field represents wall-clock time at a location.
|
|
575
|
+
* The value is the name of the accompanying tz field (IANA zone).
|
|
580
576
|
*
|
|
581
|
-
*
|
|
577
|
+
* Example: manual pair
|
|
582
578
|
* { pickupAt: { type: "timestamp", locatedBy: "pickupTz" }, pickupTz: { type: "tz" } }
|
|
583
|
-
* —
|
|
579
|
+
* — prefer `createLocatedTimestampField()` instead.
|
|
584
580
|
*/
|
|
585
581
|
readonly locatedBy?: string;
|
|
586
|
-
/**
|
|
587
|
-
*
|
|
588
|
-
* beim Write durch. */
|
|
582
|
+
/** Permitted bounds as ISO datetime values. The picker is limited to day
|
|
583
|
+
* granularity; the Zod schema enforces the exact time bound on write. */
|
|
589
584
|
readonly min?: string;
|
|
590
585
|
readonly max?: string;
|
|
591
|
-
/** Format/
|
|
592
|
-
*
|
|
586
|
+
/** Format/locale override for display and input parsing. Default: app
|
|
587
|
+
* locale. */
|
|
593
588
|
readonly locale?: string;
|
|
594
589
|
} & ResolvedPiiFlags;
|
|
595
590
|
export type TzFieldDef = {
|
|
@@ -607,13 +602,13 @@ export type LocatedTimestampFieldDef = {
|
|
|
607
602
|
readonly filterable?: boolean;
|
|
608
603
|
readonly sensitive?: boolean;
|
|
609
604
|
readonly access?: FieldAccess;
|
|
610
|
-
/**
|
|
611
|
-
*
|
|
612
|
-
*
|
|
605
|
+
/** Permitted bounds as ISO datetime values (wall-clock time). The picker is
|
|
606
|
+
* limited to day granularity; the Zod schema enforces the exact time bound
|
|
607
|
+
* on write. */
|
|
613
608
|
readonly min?: string;
|
|
614
609
|
readonly max?: string;
|
|
615
|
-
/** Format/
|
|
616
|
-
*
|
|
610
|
+
/** Format/locale override for display and input parsing. Default: app
|
|
611
|
+
* locale. */
|
|
617
612
|
readonly locale?: string;
|
|
618
613
|
} & ResolvedPiiFlags;
|
|
619
614
|
export type FileFieldDef = {
|
|
@@ -673,7 +668,7 @@ export declare const FIELD_TYPE_NAMES: readonly FieldDefinition["type"][];
|
|
|
673
668
|
* secretMint) may declare it: a `money` field there has no entity to borrow
|
|
674
669
|
* `defaultCurrency` from, so it must name its own currency source, or the
|
|
675
670
|
* form seeds a bare `0` that the handler's zod schema then rejects
|
|
676
|
-
*
|
|
671
|
+
* . Entity fields keep the optional `currency` —
|
|
677
672
|
* `entity.defaultCurrency` is already boot-enforced for them. */
|
|
678
673
|
export type FormFieldDefinition = Exclude<FieldDefinition, MoneyFieldDef> | (MoneyFieldDef & {
|
|
679
674
|
readonly currency: MoneyCurrencySource;
|
|
@@ -707,35 +702,35 @@ export type DerivedFieldsMap = Readonly<Record<string, DerivedFieldDef>>;
|
|
|
707
702
|
* DerivedFieldDef` cast lying about a field that's actually missing. */
|
|
708
703
|
export type ClientDerivedFieldDef = Pick<DerivedFieldDef, "valueType">;
|
|
709
704
|
export type TransitionMap = Readonly<Record<string, readonly string[]>>;
|
|
710
|
-
/** Composite
|
|
711
|
-
*
|
|
712
|
-
*
|
|
705
|
+
/** Composite index on an entity. Columns are referenced by field name
|
|
706
|
+
* (camelCase). `buildEntityTable` maps them to snake_case column names and
|
|
707
|
+
* names the index by convention:
|
|
713
708
|
*
|
|
714
709
|
* <table>_<col1>_<col2>_idx (non-unique)
|
|
715
710
|
* <table>_<col1>_<col2>_unique (unique)
|
|
716
711
|
*
|
|
717
|
-
*
|
|
718
|
-
*
|
|
712
|
+
* A `name` override is allowed to avoid migration churn when refactoring
|
|
713
|
+
* existing code.
|
|
719
714
|
*
|
|
720
|
-
* Single-column
|
|
721
|
-
*
|
|
722
|
-
* `{ unique: true }
|
|
715
|
+
* Single-column indexes over `tenantId` are redundant because
|
|
716
|
+
* `buildEntityTable` creates them automatically; boot validation warns about
|
|
717
|
+
* them unless `{ unique: true }`, which expresses a semantic 1:1 constraint
|
|
718
|
+
* rather than a performance hint. */
|
|
723
719
|
export type EntityIndexDef = {
|
|
724
720
|
readonly columns: readonly [string, ...string[]];
|
|
725
721
|
readonly unique?: boolean;
|
|
726
722
|
readonly name?: string;
|
|
727
723
|
/**
|
|
728
|
-
* Optional SQL
|
|
729
|
-
* ... WHERE <condition>`.
|
|
730
|
-
*
|
|
731
|
-
* `UNIQUE(userId) WHERE status IN ('pending', 'running')`.
|
|
724
|
+
* Optional SQL fragment for a partial index — `CREATE [UNIQUE] INDEX
|
|
725
|
+
* ... WHERE <condition>`. This is PostgreSQL's pattern for indexing only
|
|
726
|
+
* rows that meet specified conditions; a typical example is export-job
|
|
727
|
+
* idempotency: `UNIQUE(userId) WHERE status IN ('pending', 'running')`.
|
|
732
728
|
*
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
*
|
|
736
|
-
* non-unique
|
|
737
|
-
*
|
|
738
|
-
* statt voller Tabelle).
|
|
729
|
+
* Callers build the fragment with the drizzle-orm `sql\`...\`` tagged
|
|
730
|
+
* template. table-builder.ts emits `.where(def.where)` on the Drizzle
|
|
731
|
+
* IndexBuilder. It applies to both unique and non-unique indexes; a
|
|
732
|
+
* non-unique partial index can target a status subset instead of the full
|
|
733
|
+
* table.
|
|
739
734
|
*/
|
|
740
735
|
readonly where?: unknown;
|
|
741
736
|
};
|
|
@@ -800,17 +795,20 @@ export type EntityDefinition<F extends FieldsMap = FieldsMap, T extends EntityTe
|
|
|
800
795
|
readonly lockedWhen?: FieldCondition;
|
|
801
796
|
/** Allowed state transitions per field. Boot validates against select options. */
|
|
802
797
|
readonly transitions?: Readonly<Record<string, TransitionMap>>;
|
|
803
|
-
/** Composite
|
|
804
|
-
*
|
|
805
|
-
*
|
|
806
|
-
*
|
|
798
|
+
/** Composite indexes over multiple fields. Single-column foreign-key indexes
|
|
799
|
+
* and the tenant_id index are still created automatically by
|
|
800
|
+
* `buildEntityTable`; this list is only for custom indexes explicitly
|
|
801
|
+
* declared by the author (for example,
|
|
802
|
+
* `{ unique: true, columns: ["key", "tenantId", "userId"] }`). */
|
|
807
803
|
readonly indexes?: readonly EntityIndexDef[];
|
|
808
804
|
/**
|
|
809
|
-
*
|
|
810
|
-
* - `"serial"` (default): bigserial integer —
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
*
|
|
805
|
+
* Entity primary-key type.
|
|
806
|
+
* - `"serial"` (default): bigserial integer — faster and more compact, suitable
|
|
807
|
+
* for classic CRUD entities.
|
|
808
|
+
* - `"uuid"`: UUID with a `gen_random_uuid()` default — required for entities
|
|
809
|
+
* whose `id` travels as a foreign-key value in multi-tenant contexts (for
|
|
810
|
+
* example, `tenant.id` is the `tenantId`). Also required for event-sourced
|
|
811
|
+
* aggregates because events are grouped by UUID.
|
|
814
812
|
*/
|
|
815
813
|
readonly idType?: "serial" | "uuid";
|
|
816
814
|
/**
|
|
@@ -837,19 +835,19 @@ export type EntityDefinition<F extends FieldsMap = FieldsMap, T extends EntityTe
|
|
|
837
835
|
*/
|
|
838
836
|
readonly parentRef?: ParentRefDef;
|
|
839
837
|
/**
|
|
840
|
-
* Default
|
|
841
|
-
*
|
|
842
|
-
*
|
|
838
|
+
* Default retention policy for this entity. Tenant administrators can
|
|
839
|
+
* override it through compliance profiles and tenant overrides.
|
|
840
|
+
* The cleanup job applies these strategies:
|
|
843
841
|
*
|
|
844
|
-
* - "hardDelete" →
|
|
845
|
-
* - "softDelete" → deletedAt = now() (
|
|
846
|
-
* - "anonymize" →
|
|
847
|
-
*
|
|
848
|
-
* - "blockDelete" →
|
|
849
|
-
*
|
|
850
|
-
*
|
|
842
|
+
* - "hardDelete" → physically remove the row after `keepFor`
|
|
843
|
+
* - "softDelete" → set `deletedAt = now()` (with the core-soft-delete feature)
|
|
844
|
+
* - "anonymize" → overwrite fields with an `anonymize` function while the
|
|
845
|
+
* row remains
|
|
846
|
+
* - "blockDelete" → the cleanup job skips the row; user forget instead
|
|
847
|
+
* triggers anonymization. Accounting records, mandates,
|
|
848
|
+
* and patient records.
|
|
851
849
|
*
|
|
852
|
-
*
|
|
850
|
+
* See docs/plans/features/core-data-retention.md.
|
|
853
851
|
*/
|
|
854
852
|
readonly retention?: RetentionDef;
|
|
855
853
|
/**
|
|
@@ -862,7 +860,7 @@ export type EntityDefinition<F extends FieldsMap = FieldsMap, T extends EntityTe
|
|
|
862
860
|
readonly description?: string;
|
|
863
861
|
/**
|
|
864
862
|
* Opts this entity's rows into the `tenant-handover` bundled feature
|
|
865
|
-
|
|
863
|
+
*: a row-bound-grant-legitimated ownership change
|
|
866
864
|
* from an anonymous/public tenant to a freshly signed-up account's tenant.
|
|
867
865
|
* An entity reachable from a transfer's root — the root itself, or any
|
|
868
866
|
* entity whose `parentRef` names the root's type — that is NOT declared
|
package/dist/fields.js
CHANGED
|
@@ -12,7 +12,7 @@ export function optionsQueryFieldRefs(payload) {
|
|
|
12
12
|
/** Qualified config key a `{ kind: "tenant" }` MoneyCurrencySource resolves
|
|
13
13
|
* against — the tenant-settings bundle's per-tenant currency. Lives here
|
|
14
14
|
* (client-safe) rather than framework/engine so renderer code can read it
|
|
15
|
-
* without a runtime-only import
|
|
15
|
+
* without a runtime-only import. */
|
|
16
16
|
export const TENANT_CURRENCY_CONFIG_KEY = "tenant-settings:config:currency";
|
|
17
17
|
// Exhaustive catalogue of `FieldDefinition["type"]` values, derived from a
|
|
18
18
|
// `Record` so an added/removed union member fails to compile here instead of
|
|
@@ -41,13 +41,16 @@ const FIELD_TYPE_NAME_FLAGS = {
|
|
|
41
41
|
files: true,
|
|
42
42
|
images: true,
|
|
43
43
|
};
|
|
44
|
-
|
|
44
|
+
function isFieldTypeName(name) {
|
|
45
|
+
return Object.hasOwn(FIELD_TYPE_NAME_FLAGS, name);
|
|
46
|
+
}
|
|
47
|
+
export const FIELD_TYPE_NAMES = Object.keys(FIELD_TYPE_NAME_FLAGS).filter(isFieldTypeName);
|
|
45
48
|
// Field types with no bound, editable widget on the auto-wired entityEdit
|
|
46
49
|
// path (render-field.tsx renders a read-only banner instead) — shared by
|
|
47
50
|
// the boot validator (packages/framework/src/engine/boot-validator/screens.ts)
|
|
48
51
|
// and the client-side required-field check (packages/renderer/src/app/form-schema.ts).
|
|
49
52
|
// Embedded LIST fields (`multiple: true`) are the one exception — they get
|
|
50
|
-
// their own EmbeddedListField grid widget
|
|
53
|
+
// their own EmbeddedListField grid widget — callers must check that
|
|
51
54
|
// separately, this array alone doesn't distinguish plain embedded from embedded lists.
|
|
52
55
|
// A plain array, not a Set: kumiko-types stays free of module-scope runtime
|
|
53
56
|
// identity (guard-types-class-free.test.ts) since a consumer may resolve two
|
package/dist/handlers.d.ts
CHANGED
|
@@ -268,23 +268,23 @@ export type AppContext = SharedContextFields & {
|
|
|
268
268
|
readonly id: string;
|
|
269
269
|
readonly tenantId: TenantId;
|
|
270
270
|
} | null;
|
|
271
|
-
/**
|
|
272
|
-
* (r.job
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
271
|
+
/** For job-handler calls triggered by an event
|
|
272
|
+
* (`r.job` with `trigger: { on: ... }`): the name of the handler that
|
|
273
|
+
* emitted the event. For multi-trigger jobs (`on: [...]`), this is the
|
|
274
|
+
* only way for the handler to know which trigger fired. Cron and manual
|
|
275
|
+
* jobs leave the field undefined. */
|
|
276
276
|
readonly triggerName?: string;
|
|
277
|
-
/**
|
|
278
|
-
* runProdApp
|
|
279
|
-
* ctx.tz.fromCoordinates / fromAddress
|
|
277
|
+
/** Optional Geo→zone adapter. When set (via buildServer context or
|
|
278
|
+
* `runProdApp`/`runDevApp` `extraContext`), the dispatcher passes it to
|
|
279
|
+
* `ctx.tz.fromCoordinates` / `fromAddress`. These methods throw without
|
|
280
|
+
* a provider. */
|
|
280
281
|
readonly geoTzProvider?: GeoTzProvider;
|
|
281
282
|
/** Overrides the system clock behind ctx.tz in handlers and jobs; tests inject a fixed time. */
|
|
282
283
|
readonly clock?: Clock;
|
|
283
|
-
/** Tenant
|
|
284
|
-
*
|
|
285
|
-
* pipeline
|
|
286
|
-
*
|
|
287
|
-
* in den hook-filter-Stellen. */
|
|
284
|
+
/** Tenant of the current pipeline call. The dispatcher mirrors
|
|
285
|
+
* `user.tenantId` here when building HandlerContext so the lifecycle
|
|
286
|
+
* pipeline and system hooks can access it without the user object.
|
|
287
|
+
* `effectiveFeatures(ctx._tenantId)` uses it at hook-filter points. */
|
|
288
288
|
readonly _tenantId?: TenantId;
|
|
289
289
|
/** Boot-configured default locale (BCP-47). Last fallback in ctx.locale's
|
|
290
290
|
* Request-Locale → Boot-Default chain (dispatch-shared.ts) — used when
|
|
@@ -307,13 +307,11 @@ export type HandlerContext<TMap extends object = KumikoEventTypeMap> = SharedCon
|
|
|
307
307
|
readonly systemDb?: UncheckedSystemDb;
|
|
308
308
|
readonly crossTenantReads?: CrossTenantReads;
|
|
309
309
|
readonly registry: Registry;
|
|
310
|
-
/**
|
|
311
|
-
* `event.user`.
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
* Identisch zum event.user-Wert; Identity-Switches nutzen
|
|
316
|
-
* weiterhin queryAs/writeAs. */
|
|
310
|
+
/** The active SessionUser for the handler call, exposed as a convenience
|
|
311
|
+
* alias for `event.user`. Handlers naturally write `ctx.user.tenantId`;
|
|
312
|
+
* without the alias that path does not exist and silently ends in `internal_error`.
|
|
313
|
+
* The value is identical to `event.user`; identity switches still use
|
|
314
|
+
* `queryAs`/`writeAs`. */
|
|
317
315
|
readonly user: SessionUser;
|
|
318
316
|
readonly systemUser?: SessionUser;
|
|
319
317
|
readonly log?: Logger;
|
|
@@ -676,7 +674,7 @@ export type QueryHandlerDef = {
|
|
|
676
674
|
* the boot-validator skips any column-reference check that would need
|
|
677
675
|
* it (screens.ts projectionList/relatedList `columns`, projectionDetail
|
|
678
676
|
* `header`/`metrics`, dashboard `valueField`/`subField`/etc.) rather
|
|
679
|
-
* than requiring it retroactively.
|
|
677
|
+
* than requiring it retroactively. */
|
|
680
678
|
readonly outputSchema?: ZodType;
|
|
681
679
|
/** Entities whose changes this query reflects. Anonymous callers with
|
|
682
680
|
* access to this query receive /api/sse change signals (no field values)
|
package/dist/http-route.d.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import type { Context } from "hono";
|
|
2
2
|
import type { RateLimitOption } from "./handlers.ts";
|
|
3
|
-
/** Subset
|
|
4
|
-
*
|
|
5
|
-
* realistisch deklariert. */
|
|
3
|
+
/** Subset of HTTP methods actively supported. Hono supports all methods,
|
|
4
|
+
* but these are the only ones a feature author is expected to declare. */
|
|
6
5
|
export type HttpRouteMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
|
|
7
|
-
/** Dependencies
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
/** Dependencies provided to the handler by the framework. The app can be
|
|
7
|
+
* called directly (`deps.app.fetch(...)` for internal calls), or data can
|
|
8
|
+
* be fetched through the dispatcher. Db/Redis are raw connections — tenant
|
|
9
|
+
* scoping requires going through dispatcher.query.
|
|
11
10
|
*
|
|
12
|
-
* Hono
|
|
13
|
-
*
|
|
11
|
+
* Hono typing: `Context<any, any>` is used because Hono's type-parameter
|
|
12
|
+
* setup is only relevant internally. The concrete Hono app is assigned
|
|
13
|
+
* during boot. */
|
|
14
14
|
export type HttpRouteHandlerDeps = {
|
|
15
|
-
/**
|
|
16
|
-
*
|
|
15
|
+
/** The Hono app — the handler can use app.fetch(...) to call internal routes
|
|
16
|
+
* (e.g. /api/query with the full auth/anonymous chain). */
|
|
17
17
|
readonly app: import("hono").Hono<any, any>;
|
|
18
18
|
/** Run a query handler in-process, forcing a SPECIFIC tenant — WITHOUT
|
|
19
19
|
* going through the public /api/query HTTP layer (no header parsing, no
|
|
@@ -45,9 +45,9 @@ export type HttpRouteRateLimit = Omit<RateLimitOption, "per"> & {
|
|
|
45
45
|
readonly per: "ip" | "ip+handler";
|
|
46
46
|
};
|
|
47
47
|
export type HttpRouteDefinition = {
|
|
48
|
-
/** HTTP
|
|
48
|
+
/** HTTP method — mounted in Hono via app.{get,post,...}(path). */
|
|
49
49
|
readonly method: HttpRouteMethod;
|
|
50
|
-
/** URL
|
|
50
|
+
/** URL path (Hono pattern, e.g. "/feed.xml" or "/og/:tenantId.png"). */
|
|
51
51
|
readonly path: string;
|
|
52
52
|
/** true = public, no session required. false = mounted behind the
|
|
53
53
|
* session auth chain (global IP rate limit when configured, PII
|
|
@@ -56,8 +56,8 @@ export type HttpRouteDefinition = {
|
|
|
56
56
|
* `/api/*` chain only. A request without a session gets 401. The
|
|
57
57
|
* handler reads the caller via getUser(c). */
|
|
58
58
|
readonly anonymous: boolean;
|
|
59
|
-
/** Hono
|
|
60
|
-
* Response
|
|
59
|
+
/** Hono handler. Receives the Hono context and framework dependencies;
|
|
60
|
+
* returns a Response synchronously or asynchronously. */
|
|
61
61
|
readonly handler: HttpRouteHandler;
|
|
62
62
|
/** Enforced before the route's guards through the server's rate-limit
|
|
63
63
|
* resolver (fail-open like the global L1 limiter: a limiter outage
|
package/dist/http-route.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// feature author controls the wire format themselves.
|
|
5
5
|
//
|
|
6
6
|
// Pattern symmetric to r.queryHandler / r.writeHandler: definition as
|
|
7
|
-
// part of the feature (not the app bootstrapping).
|
|
7
|
+
// part of the feature (not the app bootstrapping). Multi-tenant support
|
|
8
8
|
// becomes trivial because tenant context is picked up via host resolution.
|
|
9
9
|
//
|
|
10
10
|
// Escape-hatch stays: runProdApp.extraRoutes (declarative list with
|
|
@@ -55,7 +55,7 @@ export type ActionFormScreenDefinition = {
|
|
|
55
55
|
* validator).
|
|
56
56
|
*
|
|
57
57
|
* A `money` field here must name its own currency source: this screen
|
|
58
|
-
* has no entity whose `defaultCurrency` it could inherit
|
|
58
|
+
* has no entity whose `defaultCurrency` it could inherit. */
|
|
59
59
|
readonly fields: Readonly<Record<string, FormFieldDefinition>>;
|
|
60
60
|
/** Fields computed from other fields, shown read-only and recomputed on every
|
|
61
61
|
* change. A `listSum` over an empty list without `whenEmpty` leaves the field
|
|
@@ -109,7 +109,7 @@ export type ActionFormScreenDefinition = {
|
|
|
109
109
|
* The object form additionally names the success-payload field the
|
|
110
110
|
* navigation id comes from (`ActionFormRedirect.idFrom`) — needed when
|
|
111
111
|
* the handler creates a child record but the target screen is the
|
|
112
|
-
* parent's detail screen
|
|
112
|
+
* parent's detail screen. */
|
|
113
113
|
readonly redirect?: string | ActionFormRedirect;
|
|
114
114
|
/** Links shown in the success box after a successful submit while the
|
|
115
115
|
* screen stays put. Targets resolve like `redirect` (the id comes from the
|
|
@@ -164,7 +164,7 @@ export type ActionFormFooterAction = {
|
|
|
164
164
|
* id. The write-handler reports the id of what it wrote (`data.id`); when
|
|
165
165
|
* that record is a child and the target screen shows its parent, the
|
|
166
166
|
* parent id has to be read from a different field instead of forcing the
|
|
167
|
-
* handler to misreport its own result
|
|
167
|
+
* handler to misreport its own result. */
|
|
168
168
|
export type ActionFormRedirect = {
|
|
169
169
|
/** Same target forms as the string `redirect`: short screen ID
|
|
170
170
|
* (same-feature) or a fully-qualified cross-feature screen QN. */
|
|
@@ -21,14 +21,13 @@ export type CustomScreenDefinition = {
|
|
|
21
21
|
readonly access?: AccessRule;
|
|
22
22
|
/** This screen is registered without a self-owned `r.nav()` entry by
|
|
23
23
|
* design — an app opts in by navving it explicitly (e.g. a settings-area
|
|
24
|
-
* self-service screen). `createKumikoApp`'s boot diagnostic
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* boot-validator's nav-area check, same as `dormant` on other screens. */
|
|
24
|
+
* self-service screen). `createKumikoApp`'s boot diagnostic skips dormant
|
|
25
|
+
* screens instead of flagging every consumer that doesn't mount the client
|
|
26
|
+
* plugin as a false positive. Only set this on screens the feature itself
|
|
27
|
+
* never navs — a screen the feature DOES nav still needs its client plugin
|
|
28
|
+
* mounted by every consumer, and should keep triggering the diagnostic if
|
|
29
|
+
* it's missing. Also gates the boot-validator's nav-area check, same as
|
|
30
|
+
* `dormant` on other screens. */
|
|
32
31
|
readonly dormant?: boolean;
|
|
33
32
|
/** UI-only gate, also on direct URL access; handlers still enforce access. Unmet or failed renders `fallback`. */
|
|
34
33
|
readonly visibleWhen?: DashboardPanelVisibility;
|
|
@@ -149,7 +149,7 @@ export type EditExtensionSection = {
|
|
|
149
149
|
* surrounding form's Save button should activate for its dirty state.
|
|
150
150
|
* Omit/false for extensions that persist through their own dispatcher
|
|
151
151
|
* writes (e.g. notes-history NotesSection) — otherwise a read-only form
|
|
152
|
-
* shows a Save button that does nothing
|
|
152
|
+
* shows a Save button that does nothing. */
|
|
153
153
|
readonly contributesToFormSubmit?: boolean;
|
|
154
154
|
/** Overrides the host-derived entity name passed to the mounted component.
|
|
155
155
|
* Required on `projectionDetail` (which has no real entity — the host
|
|
@@ -105,7 +105,7 @@ export type RowActionWriteHandler = {
|
|
|
105
105
|
readonly kind?: "writeHandler";
|
|
106
106
|
/** Stable id per screen — kebab-case, unique within the action set. */
|
|
107
107
|
readonly id: string;
|
|
108
|
-
/**
|
|
108
|
+
/** Display text (i18n key). */
|
|
109
109
|
readonly label: string;
|
|
110
110
|
/** Qualified name of the server handler, e.g.
|
|
111
111
|
* "publicstatus:write:maintenance:start". Dispatched via
|
|
@@ -188,7 +188,7 @@ export type RowActionNavigate = RowActionNavigateBase & ({
|
|
|
188
188
|
readonly screen: string;
|
|
189
189
|
readonly entity?: never;
|
|
190
190
|
} | {
|
|
191
|
-
/** Entity name instead of screen id
|
|
191
|
+
/** Entity name instead of screen id — resolves at boot time to
|
|
192
192
|
* the screen that declares `detailFor: "<entity>"` (see ObjectTarget/
|
|
193
193
|
* resolveTarget in @cosmicdrift/kumiko-renderer's nav.tsx). */
|
|
194
194
|
readonly entity: string;
|
|
@@ -86,7 +86,7 @@ export type ProjectionListScreenDefinition = {
|
|
|
86
86
|
* param present). Same type serves author and wire schema (no separate
|
|
87
87
|
* client-facing screen type exists), so this stays structurally
|
|
88
88
|
* writable — validateProjectionListScreens rejects any hand-authored
|
|
89
|
-
* value at boot
|
|
89
|
+
* value at boot. */
|
|
90
90
|
readonly sortable?: boolean;
|
|
91
91
|
/** Derived by buildAppSchema from the query handler's Zod schema (`cursor`
|
|
92
92
|
* or `offset` param present). See `sortable` doc for why this is
|
|
@@ -212,6 +212,6 @@ export type ProjectionDetailScreenDefinition = {
|
|
|
212
212
|
/** How head fields render. Default "text" — plain text instead of a
|
|
213
213
|
* disabled Input, since every field on this screen type is forced
|
|
214
214
|
* readOnly anyway (there is no write path, see the shim doc above).
|
|
215
|
-
* Set "form" to opt back into the disabled-Input look
|
|
215
|
+
* Set "form" to opt back into the disabled-Input look. */
|
|
216
216
|
readonly valueDisplay?: "form" | "text";
|
|
217
217
|
};
|
package/dist/screen.d.ts
CHANGED
|
@@ -91,7 +91,7 @@ export type ScreenSlots = {
|
|
|
91
91
|
readonly sidebar?: PlatformComponent;
|
|
92
92
|
readonly footer?: PlatformComponent;
|
|
93
93
|
/** entityEdit wizard: marks `footer` as the sticky-footer primary action
|
|
94
|
-
* (
|
|
94
|
+
* (pinned `max-sm:fixed` group on mobile) instead of the
|
|
95
95
|
* non-sticky secondary bucket it falls into by default alongside
|
|
96
96
|
* Back/Cancel. Set this when `footer` renders the screen's actual
|
|
97
97
|
* submit-type action (e.g. a custom "Publish" button standing in for, or
|
package/dist/step.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export type PipelineCtx<TPayload = unknown, TMap extends object = KumikoEventTyp
|
|
|
39
39
|
*/
|
|
40
40
|
readonly retryAttempt?: number;
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
42
|
+
* Snapshot-at-Start fingerprint of the workflow definition that
|
|
43
43
|
* started this run. Propagated into every suspension event payload so
|
|
44
44
|
* the resume-loop can detect library-upgrades that changed the closure
|
|
45
45
|
* source and surface them as a typed failure instead of running a
|
package/dist/target-ref.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
// TargetRef — runtime
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// TargetRef — runtime representation of a typed buildTarget output.
|
|
2
|
+
// It is dispatched by the Visual Tree component (renderer/web) to a target
|
|
3
|
+
// resolver, which finds the editor form via featureId.
|
|
4
4
|
//
|
|
5
|
-
// **Compile-time
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// Features validiert sind.
|
|
5
|
+
// **Compile-time safety:** TargetRef is never written by hand. Instead, the
|
|
6
|
+
// typed buildTarget builder (engine/build-target.ts) creates a TargetRef whose
|
|
7
|
+
// action + args are validated against the target feature's treeActions map.
|
|
9
8
|
//
|
|
10
|
-
// **Runtime:** args
|
|
11
|
-
// TargetRef
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// Siehe docs/plans/architecture/visual-tree.md A5.
|
|
9
|
+
// **Runtime:** args are untyped here (Record<string, unknown>) because
|
|
10
|
+
// TargetRef is the erased runtime version. The resolver knows the target
|
|
11
|
+
// feature and can cast args accordingly, similar to event payloads in the
|
|
12
|
+
// event store.
|
|
16
13
|
export {};
|
package/dist/tree-node.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
// TreeNode — single
|
|
2
|
-
//
|
|
1
|
+
// TreeNode — a single node in the client nav-provider tree. Providers return
|
|
2
|
+
// either static readonly TreeNode[] or dynamic TreeChildrenSubscribe.
|
|
3
3
|
//
|
|
4
|
-
// **Mental
|
|
4
|
+
// **Mental model** (VS Code Explorer):
|
|
5
5
|
// [icon] [label] [...hover-actions]
|
|
6
|
-
// optional
|
|
7
|
-
//
|
|
6
|
+
// An optional target makes the node clickable (opening an editor form via
|
|
7
|
+
// the target resolver), and optional children form a nested tree.
|
|
8
8
|
//
|
|
9
|
-
// **State**
|
|
10
|
-
// - "filled" (default) —
|
|
11
|
-
// - "stub" —
|
|
12
|
-
// - "empty" —
|
|
13
|
-
// - "loading" —
|
|
14
|
-
// - "error" —
|
|
15
|
-
//
|
|
9
|
+
// **State** selects the visual mode for the skeleton pattern:
|
|
10
|
+
// - "filled" (default) — black; the node has content
|
|
11
|
+
// - "stub" — light gray; existing but empty (designer stub file)
|
|
12
|
+
// - "empty" — placeholder for the "+ create" affordance
|
|
13
|
+
// - "loading" — children are currently being resolved
|
|
14
|
+
// - "error" — the provider emitted an error
|
|
15
|
+
// Providers that do not need the skeleton pattern can omit state.
|
|
16
16
|
//
|
|
17
|
-
// **Subscribe
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
17
|
+
// **Subscribe form** for dynamic children: the provider receives emit()
|
|
18
|
+
// and returns unsubscribe(). The initial emit may be synchronous or async;
|
|
19
|
+
// further emits may occur arbitrarily often (for example, when an entity row
|
|
20
|
+
// appears through SSE). This works with the existing SSE frame: a provider
|
|
21
|
+
// can subscribe internally to entity-update events and call emit() on change.
|
|
22
22
|
export {};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-types",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.387.0",
|
|
4
4
|
"description": "Framework-Type-Definitions für Kumiko — FeatureDefinition, BootCheck-Types und die reinen Engine-Types. Erlaubt Downstream-Konsumenten, gegen die Type-Contracts zu bauen, ohne das ganze Framework-Package zu importieren. Enthaelt keine identitaets-sensitiven Runtime-Werte mehr (Error-Klassen leben seit #1629 in kumiko-framework, Brand-Symbole nutzen Symbol.for) und ist deshalb eine plain dependency, keine peerDependency.",
|
|
5
|
-
"license": "
|
|
5
|
+
"license": "MIT",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|