@cosmicdrift/kumiko-types 0.235.1 → 0.235.3
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/package.json +5 -1
- package/src/agent-exposure.ts +14 -0
- package/src/define-handler.ts +7 -0
- package/src/feature.ts +15 -2
- package/src/fields.ts +24 -0
- package/src/handlers.ts +18 -0
- package/src/screen.ts +11 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-types",
|
|
3
|
-
"version": "0.235.
|
|
3
|
+
"version": "0.235.3",
|
|
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
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -233,6 +233,10 @@
|
|
|
233
233
|
"./snapshot-types": {
|
|
234
234
|
"types": "./src/snapshot-types.ts",
|
|
235
235
|
"default": "./src/snapshot-types.ts"
|
|
236
|
+
},
|
|
237
|
+
"./agent-exposure": {
|
|
238
|
+
"types": "./src/agent-exposure.ts",
|
|
239
|
+
"default": "./src/agent-exposure.ts"
|
|
236
240
|
}
|
|
237
241
|
},
|
|
238
242
|
"devDependencies": {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AgentExposure, AgentHandlerHints } from "./handlers";
|
|
2
|
+
|
|
3
|
+
/** Fail-closed: a handler without a `description` stays invisible to the agent
|
|
4
|
+
* unless it opts in explicitly. `kind` is a parameter because write and query
|
|
5
|
+
* handler definitions are structurally indistinguishable at runtime. */
|
|
6
|
+
export function resolveAgentExposure(
|
|
7
|
+
def: { readonly description?: string; readonly agent?: AgentHandlerHints },
|
|
8
|
+
kind: "query" | "write",
|
|
9
|
+
): AgentExposure {
|
|
10
|
+
return {
|
|
11
|
+
expose: def.agent?.expose ?? def.description !== undefined,
|
|
12
|
+
risk: def.agent?.risk ?? (kind === "query" ? "low" : "mid"),
|
|
13
|
+
};
|
|
14
|
+
}
|
package/src/define-handler.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { ZodType, z } from "zod";
|
|
|
2
2
|
import type { KumikoEventTypeMap } from "./event-type-map";
|
|
3
3
|
import type {
|
|
4
4
|
AccessRule,
|
|
5
|
+
AgentHandlerHints,
|
|
5
6
|
HandlerContext,
|
|
6
7
|
QueryEvent,
|
|
7
8
|
RateLimitOption,
|
|
@@ -34,6 +35,8 @@ export type WriteHandlerDefinition<
|
|
|
34
35
|
readonly name: TName;
|
|
35
36
|
readonly schema: TSchema;
|
|
36
37
|
readonly access?: AccessRule;
|
|
38
|
+
readonly description?: string;
|
|
39
|
+
readonly agent?: AgentHandlerHints;
|
|
37
40
|
readonly unsafeSkipTransitionGuard?: boolean;
|
|
38
41
|
readonly rateLimit?: RateLimitOption;
|
|
39
42
|
readonly handler: (
|
|
@@ -59,6 +62,8 @@ export type WriteHandlerInput<
|
|
|
59
62
|
readonly name: TName;
|
|
60
63
|
readonly schema: TSchema;
|
|
61
64
|
readonly access?: AccessRule;
|
|
65
|
+
readonly description?: string;
|
|
66
|
+
readonly agent?: AgentHandlerHints;
|
|
62
67
|
readonly unsafeSkipTransitionGuard?: boolean;
|
|
63
68
|
readonly rateLimit?: RateLimitOption;
|
|
64
69
|
} & (
|
|
@@ -86,6 +91,8 @@ export type QueryHandlerDefinition<
|
|
|
86
91
|
readonly name: TName;
|
|
87
92
|
readonly schema: TSchema;
|
|
88
93
|
readonly access?: AccessRule;
|
|
94
|
+
readonly description?: string;
|
|
95
|
+
readonly agent?: AgentHandlerHints;
|
|
89
96
|
readonly rateLimit?: RateLimitOption;
|
|
90
97
|
readonly handler: (
|
|
91
98
|
query: QueryEvent<z.infer<TSchema>>,
|
package/src/feature.ts
CHANGED
|
@@ -27,6 +27,7 @@ import type { EntityTableMeta } from "./entity-table-meta-types";
|
|
|
27
27
|
import type { EntityDefinition } from "./fields";
|
|
28
28
|
import type {
|
|
29
29
|
AccessRule,
|
|
30
|
+
AgentHandlerHints,
|
|
30
31
|
AuthClaimsFn,
|
|
31
32
|
AuthClaimsHookDef,
|
|
32
33
|
ClaimKeyDefinition,
|
|
@@ -453,7 +454,12 @@ export type FeatureRegistrar<TFeature extends string = string> = {
|
|
|
453
454
|
name: string,
|
|
454
455
|
schema: TSchema,
|
|
455
456
|
handler: WriteHandlerFn<z.infer<TSchema>>,
|
|
456
|
-
options?: {
|
|
457
|
+
options?: {
|
|
458
|
+
access?: AccessRule;
|
|
459
|
+
rateLimit?: RateLimitOption;
|
|
460
|
+
description?: string;
|
|
461
|
+
agent?: AgentHandlerHints;
|
|
462
|
+
},
|
|
457
463
|
): HandlerRef;
|
|
458
464
|
|
|
459
465
|
queryHandler<TName extends string, TSchema extends ZodType>(
|
|
@@ -463,7 +469,13 @@ export type FeatureRegistrar<TFeature extends string = string> = {
|
|
|
463
469
|
name: string,
|
|
464
470
|
schema: TSchema,
|
|
465
471
|
handler: QueryHandlerFn<z.infer<TSchema>>,
|
|
466
|
-
options?: {
|
|
472
|
+
options?: {
|
|
473
|
+
access?: AccessRule;
|
|
474
|
+
rateLimit?: RateLimitOption;
|
|
475
|
+
outputSchema?: ZodType;
|
|
476
|
+
description?: string;
|
|
477
|
+
agent?: AgentHandlerHints;
|
|
478
|
+
},
|
|
467
479
|
): HandlerRef;
|
|
468
480
|
|
|
469
481
|
streamHandler<TName extends string, TSchema extends ZodType>(
|
|
@@ -865,6 +877,7 @@ export type Registry = {
|
|
|
865
877
|
getWriteHandler(name: string): WriteHandlerDef | undefined;
|
|
866
878
|
getQueryHandler(name: string): QueryHandlerDef | undefined;
|
|
867
879
|
getAllQueryHandlers(): ReadonlyMap<string, QueryHandlerDef>;
|
|
880
|
+
getAllWriteHandlers(): ReadonlyMap<string, WriteHandlerDef>;
|
|
868
881
|
getStreamHandler(name: string): StreamHandlerDef | undefined;
|
|
869
882
|
getAllStreamHandlers(): ReadonlyMap<string, StreamHandlerDef>;
|
|
870
883
|
getSearchableFields(entityName: string): readonly string[];
|
package/src/fields.ts
CHANGED
|
@@ -237,6 +237,9 @@ export type RetentionDef = {
|
|
|
237
237
|
|
|
238
238
|
export type TextFieldDef = {
|
|
239
239
|
readonly type: "text";
|
|
240
|
+
/** Optional free-text semantics for the AI agent manifest — never rendered;
|
|
241
|
+
* the i18n label is what users see. */
|
|
242
|
+
readonly description?: string;
|
|
240
243
|
readonly maxLength?: number;
|
|
241
244
|
readonly required?: boolean;
|
|
242
245
|
readonly searchable?: boolean;
|
|
@@ -279,6 +282,7 @@ export type TextFieldDef = {
|
|
|
279
282
|
*/
|
|
280
283
|
export type LongTextFieldDef = {
|
|
281
284
|
readonly type: "longText";
|
|
285
|
+
readonly description?: string;
|
|
282
286
|
/** Optionale soft-Cap. Default unbounded (= Postgres-text-limit, 1 GB).
|
|
283
287
|
* Nützlich für defensive Caps wie 1 MB damit ein verirrter Browser-
|
|
284
288
|
* Paste nicht die DB sprengt. */
|
|
@@ -293,6 +297,7 @@ export type LongTextFieldDef = {
|
|
|
293
297
|
|
|
294
298
|
export type BooleanFieldDef = {
|
|
295
299
|
readonly type: "boolean";
|
|
300
|
+
readonly description?: string;
|
|
296
301
|
readonly required?: boolean;
|
|
297
302
|
readonly sortable?: boolean;
|
|
298
303
|
readonly filterable?: boolean;
|
|
@@ -303,6 +308,7 @@ export type BooleanFieldDef = {
|
|
|
303
308
|
|
|
304
309
|
export type SelectFieldDef<TOptions extends readonly string[] = readonly string[]> = {
|
|
305
310
|
readonly type: "select";
|
|
311
|
+
readonly description?: string;
|
|
306
312
|
readonly options: TOptions;
|
|
307
313
|
readonly required?: boolean;
|
|
308
314
|
readonly sortable?: boolean;
|
|
@@ -327,6 +333,7 @@ export type SelectFieldDef<TOptions extends readonly string[] = readonly string[
|
|
|
327
333
|
// rejected Duplikate erst wenn Bedarf da ist.
|
|
328
334
|
export type MultiSelectFieldDef<TOptions extends readonly string[] = readonly string[]> = {
|
|
329
335
|
readonly type: "multiSelect";
|
|
336
|
+
readonly description?: string;
|
|
330
337
|
readonly options: TOptions;
|
|
331
338
|
readonly required?: boolean;
|
|
332
339
|
readonly filterable?: boolean;
|
|
@@ -359,6 +366,7 @@ export type MultiSelectFieldDef<TOptions extends readonly string[] = readonly st
|
|
|
359
366
|
*/
|
|
360
367
|
export type NumberFieldDef = {
|
|
361
368
|
readonly type: "number";
|
|
369
|
+
readonly description?: string;
|
|
362
370
|
readonly required?: boolean;
|
|
363
371
|
readonly sortable?: boolean;
|
|
364
372
|
readonly filterable?: boolean;
|
|
@@ -390,6 +398,7 @@ export type NumberFieldDef = {
|
|
|
390
398
|
*/
|
|
391
399
|
export type BigIntFieldDef = {
|
|
392
400
|
readonly type: "bigInt";
|
|
401
|
+
readonly description?: string;
|
|
393
402
|
readonly required?: boolean;
|
|
394
403
|
readonly sortable?: boolean;
|
|
395
404
|
readonly filterable?: boolean;
|
|
@@ -412,6 +421,7 @@ export type BigIntFieldDef = {
|
|
|
412
421
|
*/
|
|
413
422
|
export type DecimalFieldDef = {
|
|
414
423
|
readonly type: "decimal";
|
|
424
|
+
readonly description?: string;
|
|
415
425
|
readonly precision: number;
|
|
416
426
|
readonly scale: number;
|
|
417
427
|
readonly required?: boolean;
|
|
@@ -424,6 +434,7 @@ export type DecimalFieldDef = {
|
|
|
424
434
|
|
|
425
435
|
export type MoneyFieldDef = {
|
|
426
436
|
readonly type: "money";
|
|
437
|
+
readonly description?: string;
|
|
427
438
|
readonly required?: boolean;
|
|
428
439
|
readonly sortable?: boolean;
|
|
429
440
|
readonly filterable?: boolean;
|
|
@@ -446,6 +457,7 @@ export type MoneyFieldDef = {
|
|
|
446
457
|
// ist ein menschlich-lesbares Feld wie "name", "title", "email".
|
|
447
458
|
export type ReferenceFieldDef = {
|
|
448
459
|
readonly type: "reference";
|
|
460
|
+
readonly description?: string;
|
|
449
461
|
readonly entity: string;
|
|
450
462
|
readonly required?: boolean;
|
|
451
463
|
readonly filterable?: boolean;
|
|
@@ -528,6 +540,7 @@ export type EmbeddedDerivedCellDef = {
|
|
|
528
540
|
|
|
529
541
|
export type EmbeddedFieldDef = {
|
|
530
542
|
readonly type: "embedded";
|
|
543
|
+
readonly description?: string;
|
|
531
544
|
readonly required?: boolean;
|
|
532
545
|
readonly sensitive?: boolean;
|
|
533
546
|
readonly schema: Readonly<Record<string, EmbeddedSubFieldDef>>;
|
|
@@ -574,6 +587,7 @@ export type EmbeddedFieldDef = {
|
|
|
574
587
|
// + NOT NULL, identisch zu embedded.
|
|
575
588
|
export type JsonbFieldDef = {
|
|
576
589
|
readonly type: "jsonb";
|
|
590
|
+
readonly description?: string;
|
|
577
591
|
readonly sensitive?: boolean;
|
|
578
592
|
readonly access?: FieldAccess;
|
|
579
593
|
} & ResolvedPiiFlags;
|
|
@@ -587,6 +601,7 @@ export type JsonbFieldDef = {
|
|
|
587
601
|
// Siehe docs/plans/architecture/timezones.md
|
|
588
602
|
export type DateFieldDef = {
|
|
589
603
|
readonly type: "date";
|
|
604
|
+
readonly description?: string;
|
|
590
605
|
readonly required?: boolean;
|
|
591
606
|
readonly sortable?: boolean;
|
|
592
607
|
readonly filterable?: boolean;
|
|
@@ -615,6 +630,7 @@ export type DateFieldDef = {
|
|
|
615
630
|
// Feld statt eines lose verdrahteten Pairs (siehe LocatedTimestampFieldDef).
|
|
616
631
|
export type TimestampFieldDef = {
|
|
617
632
|
readonly type: "timestamp";
|
|
633
|
+
readonly description?: string;
|
|
618
634
|
readonly required?: boolean;
|
|
619
635
|
readonly sortable?: boolean;
|
|
620
636
|
readonly filterable?: boolean;
|
|
@@ -645,6 +661,7 @@ export type TimestampFieldDef = {
|
|
|
645
661
|
// (TEXT-Spalte) korrekt sind und der `locatedBy`-Marker eindeutig auflöst.
|
|
646
662
|
export type TzFieldDef = {
|
|
647
663
|
readonly type: "tz";
|
|
664
|
+
readonly description?: string;
|
|
648
665
|
readonly required?: boolean;
|
|
649
666
|
readonly sensitive?: boolean;
|
|
650
667
|
readonly access?: FieldAccess;
|
|
@@ -670,6 +687,7 @@ export type TzFieldDef = {
|
|
|
670
687
|
// Siehe docs/plans/architecture/timezones.md.
|
|
671
688
|
export type LocatedTimestampFieldDef = {
|
|
672
689
|
readonly type: "locatedTimestamp";
|
|
690
|
+
readonly description?: string;
|
|
673
691
|
readonly required?: boolean;
|
|
674
692
|
readonly sortable?: boolean;
|
|
675
693
|
readonly filterable?: boolean;
|
|
@@ -687,6 +705,7 @@ export type LocatedTimestampFieldDef = {
|
|
|
687
705
|
|
|
688
706
|
export type FileFieldDef = {
|
|
689
707
|
readonly type: "file";
|
|
708
|
+
readonly description?: string;
|
|
690
709
|
readonly required?: boolean;
|
|
691
710
|
readonly maxSize?: string;
|
|
692
711
|
readonly accept?: readonly string[];
|
|
@@ -695,6 +714,7 @@ export type FileFieldDef = {
|
|
|
695
714
|
|
|
696
715
|
export type ImageFieldDef = {
|
|
697
716
|
readonly type: "image";
|
|
717
|
+
readonly description?: string;
|
|
698
718
|
readonly required?: boolean;
|
|
699
719
|
readonly maxSize?: string;
|
|
700
720
|
readonly accept?: readonly string[];
|
|
@@ -710,6 +730,7 @@ export type ImageFieldDef = {
|
|
|
710
730
|
|
|
711
731
|
export type FilesFieldDef = {
|
|
712
732
|
readonly type: "files";
|
|
733
|
+
readonly description?: string;
|
|
713
734
|
readonly maxSize?: string;
|
|
714
735
|
readonly accept?: readonly string[];
|
|
715
736
|
readonly maxCount?: number;
|
|
@@ -718,6 +739,7 @@ export type FilesFieldDef = {
|
|
|
718
739
|
|
|
719
740
|
export type ImagesFieldDef = {
|
|
720
741
|
readonly type: "images";
|
|
742
|
+
readonly description?: string;
|
|
721
743
|
readonly maxSize?: string;
|
|
722
744
|
readonly accept?: readonly string[];
|
|
723
745
|
readonly maxCount?: number;
|
|
@@ -921,4 +943,6 @@ export type EntityDefinition<F extends FieldsMap = FieldsMap> = {
|
|
|
921
943
|
* nameable as a column in a declarative `entityList`. See DerivedFieldDef.
|
|
922
944
|
*/
|
|
923
945
|
readonly derivedFields?: DerivedFieldsMap;
|
|
946
|
+
/** Optional free-text semantics for the AI agent manifest — see TextFieldDef.description. */
|
|
947
|
+
readonly description?: string;
|
|
924
948
|
};
|
package/src/handlers.ts
CHANGED
|
@@ -929,11 +929,27 @@ export type RateLimitOption = {
|
|
|
929
929
|
readonly cost?: number;
|
|
930
930
|
};
|
|
931
931
|
|
|
932
|
+
export type AgentRisk = "low" | "mid" | "high";
|
|
933
|
+
|
|
934
|
+
/** Per-handler hints for the AI-agent manifest. `expose` overrides the
|
|
935
|
+
* default derived from `description`; `risk` overrides the per-kind default. */
|
|
936
|
+
export type AgentHandlerHints = {
|
|
937
|
+
readonly expose?: boolean;
|
|
938
|
+
readonly risk?: AgentRisk;
|
|
939
|
+
};
|
|
940
|
+
|
|
941
|
+
export type AgentExposure = {
|
|
942
|
+
readonly expose: boolean;
|
|
943
|
+
readonly risk: AgentRisk;
|
|
944
|
+
};
|
|
945
|
+
|
|
932
946
|
export type WriteHandlerDef = {
|
|
933
947
|
readonly name: string;
|
|
934
948
|
readonly schema: ZodType;
|
|
935
949
|
readonly handler: WriteHandlerFn;
|
|
936
950
|
readonly access?: AccessRule;
|
|
951
|
+
readonly description?: string;
|
|
952
|
+
readonly agent?: AgentHandlerHints;
|
|
937
953
|
readonly unsafeSkipTransitionGuard?: boolean;
|
|
938
954
|
readonly rateLimit?: RateLimitOption;
|
|
939
955
|
// Set when the author wrote a `perform: stepsPipeline(...)` block. Boot-
|
|
@@ -951,6 +967,8 @@ export type QueryHandlerDef = {
|
|
|
951
967
|
readonly schema: ZodType;
|
|
952
968
|
readonly handler: QueryHandlerFn;
|
|
953
969
|
readonly access?: AccessRule;
|
|
970
|
+
readonly description?: string;
|
|
971
|
+
readonly agent?: AgentHandlerHints;
|
|
954
972
|
readonly rateLimit?: RateLimitOption;
|
|
955
973
|
/** Zod schema of the handler's actual return value — the paged envelope
|
|
956
974
|
* `{ rows, nextCursor, total? }` for a `definePagedQueryHandler`, or the
|
package/src/screen.ts
CHANGED
|
@@ -326,6 +326,7 @@ export type EntityListScreenDefinition = {
|
|
|
326
326
|
readonly type: "entityList";
|
|
327
327
|
readonly nav?: ScreenNavSugar;
|
|
328
328
|
readonly detailFor?: string;
|
|
329
|
+
readonly description?: string;
|
|
329
330
|
readonly entity: string;
|
|
330
331
|
readonly columns: readonly ListColumnSpec[];
|
|
331
332
|
// Row renderer (Desktop) — when omitted, renderer draws the default table
|
|
@@ -404,6 +405,7 @@ export type ProjectionListScreenDefinition = {
|
|
|
404
405
|
readonly type: "projectionList";
|
|
405
406
|
readonly nav?: ScreenNavSugar;
|
|
406
407
|
readonly detailFor?: string;
|
|
408
|
+
readonly description?: string;
|
|
407
409
|
readonly query: string;
|
|
408
410
|
readonly columns: readonly ListColumnSpec[];
|
|
409
411
|
readonly rowRenderer?: PlatformComponent;
|
|
@@ -464,6 +466,7 @@ export type ProjectionDetailScreenDefinition = {
|
|
|
464
466
|
readonly type: "projectionDetail";
|
|
465
467
|
readonly nav?: ScreenNavSugar;
|
|
466
468
|
readonly detailFor?: string;
|
|
469
|
+
readonly description?: string;
|
|
467
470
|
readonly query: string;
|
|
468
471
|
/** Query-payload key for the row-id. Default "id". */
|
|
469
472
|
readonly idParam?: string;
|
|
@@ -632,6 +635,7 @@ export type DashboardScreenDefinition = {
|
|
|
632
635
|
readonly type: "dashboard";
|
|
633
636
|
readonly nav?: ScreenNavSugar;
|
|
634
637
|
readonly detailFor?: string;
|
|
638
|
+
readonly description?: string;
|
|
635
639
|
readonly panels: readonly DashboardPanelDefinition[];
|
|
636
640
|
readonly filter?: DashboardFilterDefinition;
|
|
637
641
|
readonly slots?: ScreenSlots;
|
|
@@ -767,6 +771,7 @@ export type EntityEditScreenDefinition = {
|
|
|
767
771
|
readonly type: "entityEdit";
|
|
768
772
|
readonly nav?: ScreenNavSugar;
|
|
769
773
|
readonly detailFor?: string;
|
|
774
|
+
readonly description?: string;
|
|
770
775
|
readonly entity: string;
|
|
771
776
|
readonly layout: EditLayout;
|
|
772
777
|
/** Optionaler i18n-Key (oder Roh-String) für den Submit-Button. Default
|
|
@@ -846,6 +851,7 @@ export type ActionFormScreenDefinition = {
|
|
|
846
851
|
readonly type: "actionForm";
|
|
847
852
|
readonly nav?: ScreenNavSugar;
|
|
848
853
|
readonly detailFor?: string;
|
|
854
|
+
readonly description?: string;
|
|
849
855
|
/** Write-Handler-QN der bei Submit gerufen wird. Form-Object landet
|
|
850
856
|
* 1:1 als payload — Handler-Schema (Zod) validiert weiter. */
|
|
851
857
|
readonly handler: string;
|
|
@@ -901,6 +907,7 @@ export type CustomScreenDefinition = {
|
|
|
901
907
|
readonly type: "custom";
|
|
902
908
|
readonly nav?: ScreenNavSugar;
|
|
903
909
|
readonly detailFor?: string;
|
|
910
|
+
readonly description?: string;
|
|
904
911
|
readonly renderer: PlatformComponent;
|
|
905
912
|
readonly routes?: readonly CustomScreenRoute[];
|
|
906
913
|
/** Parent list screen for breadcrumb when this detail is not in nav. */
|
|
@@ -956,6 +963,7 @@ export type ConfigEditScreenDefinition = {
|
|
|
956
963
|
readonly type: "configEdit";
|
|
957
964
|
readonly nav?: ScreenNavSugar;
|
|
958
965
|
readonly detailFor?: string;
|
|
966
|
+
readonly description?: string;
|
|
959
967
|
/** scope für config:write:set Calls. Muss zur Scope-Deklaration der
|
|
960
968
|
* in `configKeys` referenzierten Keys passen — Boot-Validator
|
|
961
969
|
* prüft das gegen die Registry. */
|
|
@@ -998,6 +1006,7 @@ export type SecretsEditScreenDefinition = {
|
|
|
998
1006
|
readonly type: "secretsEdit";
|
|
999
1007
|
readonly nav?: ScreenNavSugar;
|
|
1000
1008
|
readonly detailFor?: string;
|
|
1009
|
+
readonly description?: string;
|
|
1001
1010
|
/** field id -> qualified secret name (`<feature>:secret:<kebab>`). */
|
|
1002
1011
|
readonly secretKeys: Readonly<Record<string, string>>;
|
|
1003
1012
|
/** field id -> i18n key for the label. */
|
|
@@ -1035,10 +1044,10 @@ export type ScreenNavSugar = {
|
|
|
1035
1044
|
readonly order?: number;
|
|
1036
1045
|
};
|
|
1037
1046
|
|
|
1038
|
-
// `nav`/`detailFor` live directly on every variant (not only via this
|
|
1047
|
+
// `nav`/`detailFor`/`description` live directly on every variant (not only via this
|
|
1039
1048
|
// union) so a screen typed as its own concrete kind — e.g. `const screen:
|
|
1040
1049
|
// CustomScreenDefinition = {...}` in a module split out of `feature.ts` —
|
|
1041
|
-
// still accepts
|
|
1050
|
+
// still accepts all three; a union-only intersection drops them the
|
|
1042
1051
|
// moment a caller narrows to one member.
|
|
1043
1052
|
//
|
|
1044
1053
|
// `detailFor` applies to any screen kind because any kind can be the
|