@lssm/lib.contracts 1.43.0 → 1.43.2
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/app-config/app-config.feature.d.ts +2 -1
- package/dist/app-config/contracts.d.ts +51 -51
- package/dist/app-config/events.d.ts +27 -27
- package/dist/app-config/lifecycle-contracts.d.ts +55 -55
- package/dist/app-config/runtime.d.ts +7 -4
- package/dist/app-config/spec.d.ts +3 -2
- package/dist/app-config/validation.d.ts +1 -1
- package/dist/client/react/feature-render.d.ts +3 -1
- package/dist/data-views/data-views.d.ts +5 -138
- package/dist/data-views/data-views.js +3 -57
- package/dist/data-views/index.d.ts +4 -4
- package/dist/data-views/index.js +3 -4
- package/dist/data-views/query-generator.d.ts +1 -1
- package/dist/data-views/registry.d.ts +51 -0
- package/dist/data-views/registry.js +82 -0
- package/dist/data-views/runtime.d.ts +2 -1
- package/dist/data-views/spec.d.ts +32 -0
- package/dist/data-views/spec.js +10 -0
- package/dist/data-views/types.d.ts +157 -0
- package/dist/data-views/types.js +0 -0
- package/dist/experiments/spec-resolver.d.ts +1 -1
- package/dist/features/index.d.ts +5 -0
- package/dist/features/index.js +5 -0
- package/dist/features/install.d.ts +22 -0
- package/dist/features/install.js +36 -0
- package/dist/features/registry.d.ts +26 -0
- package/dist/features/registry.js +49 -0
- package/dist/features/types.d.ts +88 -0
- package/dist/features/types.js +0 -0
- package/dist/features/validation.d.ts +8 -0
- package/dist/features/validation.js +14 -0
- package/dist/index.d.ts +16 -12
- package/dist/index.js +7 -6
- package/dist/install.d.ts +1 -1
- package/dist/integrations/integrations.feature.d.ts +2 -1
- package/dist/integrations/openbanking/contracts/accounts.d.ts +67 -67
- package/dist/integrations/openbanking/contracts/balances.d.ts +35 -35
- package/dist/integrations/openbanking/contracts/transactions.d.ts +49 -49
- package/dist/integrations/openbanking/models.d.ts +55 -55
- package/dist/integrations/openbanking/openbanking.feature.d.ts +2 -1
- package/dist/integrations/operations.d.ts +103 -103
- package/dist/jsonschema.d.ts +1 -1
- package/dist/knowledge/knowledge.feature.d.ts +2 -1
- package/dist/knowledge/operations.d.ts +67 -67
- package/dist/llm/exporters.d.ts +3 -2
- package/dist/llm/prompts.d.ts +1 -1
- package/dist/llm/types.d.ts +3 -2
- package/dist/markdown.d.ts +2 -2
- package/dist/tests/runner.js +1 -1
- package/dist/tests/spec.d.ts +2 -10
- package/dist/workflow/runner.d.ts +2 -1
- package/dist/workflow/spec.d.ts +3 -2
- package/dist/workspace-config/contractsrc-schema.d.ts +43 -2
- package/dist/workspace-config/contractsrc-schema.js +23 -2
- package/dist/workspace-config/index.d.ts +2 -2
- package/dist/workspace-config/index.js +2 -2
- package/package.json +13 -6
- package/dist/features.d.ts +0 -104
- package/dist/features.js +0 -91
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { filterBy, getUniqueTags, groupBy, init_registry_utils } from "../registry-utils.js";
|
|
2
|
+
|
|
3
|
+
//#region src/data-views/registry.ts
|
|
4
|
+
init_registry_utils();
|
|
5
|
+
/**
|
|
6
|
+
* Generate a unique key for a data view spec.
|
|
7
|
+
*/
|
|
8
|
+
function dataViewKey(spec) {
|
|
9
|
+
return `${spec.meta.key}.v${spec.meta.version}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Registry for managing data view specifications.
|
|
13
|
+
*/
|
|
14
|
+
var DataViewRegistry = class {
|
|
15
|
+
items = /* @__PURE__ */ new Map();
|
|
16
|
+
/**
|
|
17
|
+
* Register a data view spec.
|
|
18
|
+
* @throws Error if a spec with the same key already exists.
|
|
19
|
+
*/
|
|
20
|
+
register(spec) {
|
|
21
|
+
const key = dataViewKey(spec);
|
|
22
|
+
if (this.items.has(key)) throw new Error(`Duplicate data view ${key}`);
|
|
23
|
+
this.items.set(key, spec);
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* List all registered data view specs.
|
|
28
|
+
*/
|
|
29
|
+
list() {
|
|
30
|
+
return [...this.items.values()];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get a data view by key and optional version.
|
|
34
|
+
* If version is not specified, returns the latest version.
|
|
35
|
+
*/
|
|
36
|
+
get(name, version) {
|
|
37
|
+
if (version != null) return this.items.get(`${name}.v${version}`);
|
|
38
|
+
let candidate;
|
|
39
|
+
let max = -Infinity;
|
|
40
|
+
for (const spec of this.items.values()) {
|
|
41
|
+
if (spec.meta.key !== name) continue;
|
|
42
|
+
if (spec.meta.version > max) {
|
|
43
|
+
max = spec.meta.version;
|
|
44
|
+
candidate = spec;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return candidate;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Filter data views by criteria.
|
|
51
|
+
*/
|
|
52
|
+
filter(criteria) {
|
|
53
|
+
return filterBy(this.list(), criteria);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* List data views with specific tag.
|
|
57
|
+
*/
|
|
58
|
+
listByTag(tag) {
|
|
59
|
+
return this.list().filter((d) => d.meta.tags?.includes(tag));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* List data views by owner.
|
|
63
|
+
*/
|
|
64
|
+
listByOwner(owner) {
|
|
65
|
+
return this.list().filter((d) => d.meta.owners?.includes(owner));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Group data views by key function.
|
|
69
|
+
*/
|
|
70
|
+
groupBy(keyFn) {
|
|
71
|
+
return groupBy(this.list(), keyFn);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get unique tags from all data views.
|
|
75
|
+
*/
|
|
76
|
+
getUniqueTags() {
|
|
77
|
+
return getUniqueTags(this.list());
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
export { DataViewRegistry, dataViewKey };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ExperimentRef } from "../experiments/spec.js";
|
|
2
|
+
import { DataViewConfig, DataViewMeta, DataViewSource, DataViewStates } from "./types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/data-views/spec.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Complete specification for a data view.
|
|
8
|
+
*/
|
|
9
|
+
interface DataViewSpec {
|
|
10
|
+
meta: DataViewMeta;
|
|
11
|
+
source: DataViewSource;
|
|
12
|
+
view: DataViewConfig;
|
|
13
|
+
states?: DataViewStates;
|
|
14
|
+
policy?: {
|
|
15
|
+
flags?: string[];
|
|
16
|
+
pii?: string[];
|
|
17
|
+
};
|
|
18
|
+
experiments?: ExperimentRef[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Reference to a data view spec.
|
|
22
|
+
*/
|
|
23
|
+
interface DataViewRef {
|
|
24
|
+
key: string;
|
|
25
|
+
version: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Helper to define a data view spec with type safety.
|
|
29
|
+
*/
|
|
30
|
+
declare function defineDataView(spec: DataViewSpec): DataViewSpec;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { DataViewRef, DataViewSpec, defineDataView };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { OwnerShipMeta } from "../ownership.js";
|
|
2
|
+
import { EventRef, OpRef, PresentationRef } from "../features/types.js";
|
|
3
|
+
import "../features/index.js";
|
|
4
|
+
|
|
5
|
+
//#region src/data-views/types.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Supported data view kinds.
|
|
8
|
+
*/
|
|
9
|
+
type DataViewKind = 'list' | 'detail' | 'table' | 'grid';
|
|
10
|
+
/**
|
|
11
|
+
* Metadata for a data view spec.
|
|
12
|
+
*/
|
|
13
|
+
interface DataViewMeta extends OwnerShipMeta {
|
|
14
|
+
/** Canonical entity slug (e.g., "space", "resident"). */
|
|
15
|
+
entity: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Source configuration for fetching data in a data view.
|
|
19
|
+
*/
|
|
20
|
+
interface DataViewSource {
|
|
21
|
+
/** Primary query used to fetch items for this view. */
|
|
22
|
+
primary: OpRef;
|
|
23
|
+
/** Optional operation used to fetch a single item (detail views). */
|
|
24
|
+
item?: OpRef;
|
|
25
|
+
/** Optional record mutation operations (used for inline editing or actions). */
|
|
26
|
+
mutations?: {
|
|
27
|
+
create?: OpRef;
|
|
28
|
+
update?: OpRef;
|
|
29
|
+
delete?: OpRef;
|
|
30
|
+
};
|
|
31
|
+
/** Events that should trigger refresh when emitted. */
|
|
32
|
+
refreshEvents?: EventRef[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Display formatting hints for data view fields.
|
|
36
|
+
*/
|
|
37
|
+
type DataViewFieldFormat = 'text' | 'number' | 'currency' | 'percentage' | 'date' | 'dateTime' | 'boolean' | 'badge';
|
|
38
|
+
/**
|
|
39
|
+
* Field definition within a data view.
|
|
40
|
+
*/
|
|
41
|
+
interface DataViewField {
|
|
42
|
+
/** Unique identifier for the field within the view. */
|
|
43
|
+
key: string;
|
|
44
|
+
/** Human-friendly label for headers/tooltips. */
|
|
45
|
+
label: string;
|
|
46
|
+
/** Dot-path into the data item (e.g., "address.city"). */
|
|
47
|
+
dataPath: string;
|
|
48
|
+
/** Optional description surfaced in tooltips or docs. */
|
|
49
|
+
description?: string;
|
|
50
|
+
/** Optional formatting hint for renderers. */
|
|
51
|
+
format?: DataViewFieldFormat;
|
|
52
|
+
/** When true, the field can be used for sorting. */
|
|
53
|
+
sortable?: boolean;
|
|
54
|
+
/** When true, the field can be used for filtering. */
|
|
55
|
+
filterable?: boolean;
|
|
56
|
+
/** Optional width hint for table layouts. */
|
|
57
|
+
width?: 'auto' | 'xs' | 'sm' | 'md' | 'lg';
|
|
58
|
+
/** Optional presentation override (e.g., card component). */
|
|
59
|
+
presentation?: PresentationRef;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Filter definition for a data view.
|
|
63
|
+
*/
|
|
64
|
+
interface DataViewFilter {
|
|
65
|
+
key: string;
|
|
66
|
+
label: string;
|
|
67
|
+
field: string;
|
|
68
|
+
type: 'search' | 'enum' | 'number' | 'date' | 'boolean';
|
|
69
|
+
options?: {
|
|
70
|
+
value: string;
|
|
71
|
+
label: string;
|
|
72
|
+
}[];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Action that can be triggered from a data view.
|
|
76
|
+
*/
|
|
77
|
+
interface DataViewAction {
|
|
78
|
+
key: string;
|
|
79
|
+
label: string;
|
|
80
|
+
kind: 'navigation' | 'operation';
|
|
81
|
+
/** Operation invoked when kind === 'operation'. */
|
|
82
|
+
operation?: OpRef;
|
|
83
|
+
/** Optional feature flag gating the action. */
|
|
84
|
+
requiresFlag?: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Section configuration for detail views.
|
|
88
|
+
*/
|
|
89
|
+
interface DataViewSections {
|
|
90
|
+
title?: string;
|
|
91
|
+
description?: string;
|
|
92
|
+
fields: string[];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Base configuration shared by all data view kinds.
|
|
96
|
+
*/
|
|
97
|
+
interface DataViewBaseConfig {
|
|
98
|
+
kind: DataViewKind;
|
|
99
|
+
fields: DataViewField[];
|
|
100
|
+
primaryField?: string;
|
|
101
|
+
secondaryFields?: string[];
|
|
102
|
+
filters?: DataViewFilter[];
|
|
103
|
+
actions?: DataViewAction[];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* List view configuration.
|
|
107
|
+
*/
|
|
108
|
+
interface DataViewListConfig extends DataViewBaseConfig {
|
|
109
|
+
kind: 'list';
|
|
110
|
+
layout?: 'card' | 'compact';
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Detail view configuration.
|
|
114
|
+
*/
|
|
115
|
+
interface DataViewDetailConfig extends DataViewBaseConfig {
|
|
116
|
+
kind: 'detail';
|
|
117
|
+
sections?: DataViewSections[];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Table column configuration.
|
|
121
|
+
*/
|
|
122
|
+
interface DataViewTableColumn {
|
|
123
|
+
field: string;
|
|
124
|
+
label?: string;
|
|
125
|
+
width?: 'auto' | 'xs' | 'sm' | 'md' | 'lg';
|
|
126
|
+
align?: 'left' | 'center' | 'right';
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Table view configuration.
|
|
130
|
+
*/
|
|
131
|
+
interface DataViewTableConfig extends DataViewBaseConfig {
|
|
132
|
+
kind: 'table';
|
|
133
|
+
columns?: DataViewTableColumn[];
|
|
134
|
+
rowSelectable?: boolean;
|
|
135
|
+
density?: 'comfortable' | 'compact';
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Grid view configuration.
|
|
139
|
+
*/
|
|
140
|
+
interface DataViewGridConfig extends DataViewBaseConfig {
|
|
141
|
+
kind: 'grid';
|
|
142
|
+
columns?: number;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Union of all data view configurations.
|
|
146
|
+
*/
|
|
147
|
+
type DataViewConfig = DataViewListConfig | DataViewDetailConfig | DataViewTableConfig | DataViewGridConfig;
|
|
148
|
+
/**
|
|
149
|
+
* Presentation references for different view states.
|
|
150
|
+
*/
|
|
151
|
+
interface DataViewStates {
|
|
152
|
+
empty?: PresentationRef;
|
|
153
|
+
error?: PresentationRef;
|
|
154
|
+
loading?: PresentationRef;
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
export { DataViewAction, DataViewBaseConfig, DataViewConfig, DataViewDetailConfig, DataViewField, DataViewFieldFormat, DataViewFilter, DataViewGridConfig, DataViewKind, DataViewListConfig, DataViewMeta, DataViewSections, DataViewSource, DataViewStates, DataViewTableColumn, DataViewTableConfig };
|
|
File without changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import "../operations/index.js";
|
|
2
1
|
import { ResourceRefDescriptor } from "../resources.js";
|
|
3
2
|
import { HandlerCtx } from "../types.js";
|
|
4
3
|
import { OpKind, OperationSpec } from "../operations/operation.js";
|
|
4
|
+
import "../operations/index.js";
|
|
5
5
|
import { AnySchemaModel } from "@lssm/lib.schema";
|
|
6
6
|
|
|
7
7
|
//#region src/experiments/spec-resolver.d.ts
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { EventRef, FeatureModuleMeta, FeatureModuleSpec, FeatureRef, OpRef, PresentationRef } from "./types.js";
|
|
2
|
+
import { FeatureRegistry } from "./registry.js";
|
|
3
|
+
import { InstallFeatureDeps, installFeature } from "./install.js";
|
|
4
|
+
import { validateFeatureTargetsV2 } from "./validation.js";
|
|
5
|
+
export { type EventRef, type FeatureModuleMeta, type FeatureModuleSpec, type FeatureRef, FeatureRegistry, type InstallFeatureDeps, type OpRef, type PresentationRef, installFeature, validateFeatureTargetsV2 };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { PresentationSpec } from "../presentations/presentations.js";
|
|
2
|
+
import { CapabilityRegistry } from "../capabilities/capabilities.js";
|
|
3
|
+
import "../capabilities/index.js";
|
|
4
|
+
import { OperationSpecRegistry } from "../operations/registry.js";
|
|
5
|
+
import { FeatureModuleSpec } from "./types.js";
|
|
6
|
+
import { FeatureRegistry } from "./registry.js";
|
|
7
|
+
import { PresentationRegistry } from "../presentations/registry.js";
|
|
8
|
+
import "../presentations/index.js";
|
|
9
|
+
|
|
10
|
+
//#region src/features/install.d.ts
|
|
11
|
+
/** Dependencies for installing a feature. */
|
|
12
|
+
interface InstallFeatureDeps {
|
|
13
|
+
features: FeatureRegistry;
|
|
14
|
+
ops?: OperationSpecRegistry;
|
|
15
|
+
presentations?: PresentationRegistry;
|
|
16
|
+
descriptors?: PresentationSpec[];
|
|
17
|
+
capabilities?: CapabilityRegistry;
|
|
18
|
+
}
|
|
19
|
+
/** Validate and register a feature against optional registries/descriptors. */
|
|
20
|
+
declare function installFeature(feature: FeatureModuleSpec, deps: InstallFeatureDeps): FeatureRegistry;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { InstallFeatureDeps, installFeature };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/features/install.ts
|
|
2
|
+
/** Validate and register a feature against optional registries/descriptors. */
|
|
3
|
+
function installFeature(feature, deps) {
|
|
4
|
+
if (deps.ops && feature.operations) {
|
|
5
|
+
for (const o of feature.operations) if (!deps.ops.getSpec(o.key, o.version)) throw new Error(`installFeature: operation not found ${o.key}.v${o.version}`);
|
|
6
|
+
}
|
|
7
|
+
if (deps.presentations && feature.presentations) {
|
|
8
|
+
for (const p of feature.presentations) if (!deps.presentations.get(p.key, p.version)) throw new Error(`installFeature: presentation not found ${p.key}.v${p.version}`);
|
|
9
|
+
}
|
|
10
|
+
if (feature.presentationsTargets && deps.descriptors) for (const req of feature.presentationsTargets) {
|
|
11
|
+
const d = deps.descriptors.find((x) => x.meta.key === req.key && x.meta.version === req.version);
|
|
12
|
+
if (!d) throw new Error(`installFeature: V2 descriptor not found ${req.key}.v${req.version}`);
|
|
13
|
+
for (const t of req.targets) if (!d.targets.includes(t)) throw new Error(`installFeature: descriptor ${req.key}.v${req.version} missing target ${t}`);
|
|
14
|
+
}
|
|
15
|
+
if (feature.opToPresentation && feature.opToPresentation.length > 0) for (const link of feature.opToPresentation) {
|
|
16
|
+
if (deps.ops) {
|
|
17
|
+
if (!deps.ops.getSpec(link.op.key, link.op.version)) throw new Error(`installFeature: linked op not found ${link.op.key}.v${link.op.version}`);
|
|
18
|
+
}
|
|
19
|
+
if (deps.presentations) {
|
|
20
|
+
if (!deps.presentations.get(link.pres.key, link.pres.version)) throw new Error(`installFeature: linked presentation not found ${link.pres.key}.v${link.pres.version}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (deps.capabilities && feature.capabilities?.provides) {
|
|
24
|
+
for (const cap of feature.capabilities.provides) if (!deps.capabilities.get(cap.key, cap.version)) throw new Error(`installFeature: capability not registered ${cap.key}.v${cap.version}`);
|
|
25
|
+
}
|
|
26
|
+
if (feature.capabilities?.requires?.length) {
|
|
27
|
+
if (!deps.capabilities) throw new Error(`installFeature: capability registry required to validate capability requirements for ${feature.meta.key}`);
|
|
28
|
+
const provided = feature.capabilities.provides ?? [];
|
|
29
|
+
for (const req of feature.capabilities.requires) if (!deps.capabilities.satisfies(req, provided)) throw new Error(`installFeature: capability requirement not satisfied ${req.key}${req.version ? `.v${req.version}` : ""}`);
|
|
30
|
+
}
|
|
31
|
+
deps.features.register(feature);
|
|
32
|
+
return deps.features;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { installFeature };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { GroupKeyFn, RegistryFilter } from "../registry-utils.js";
|
|
2
|
+
import { FeatureModuleSpec } from "./types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/features/registry.d.ts
|
|
5
|
+
/** In-memory registry for FeatureModuleSpec. */
|
|
6
|
+
declare class FeatureRegistry {
|
|
7
|
+
private items;
|
|
8
|
+
/** Register a feature module. Throws when the key already exists. */
|
|
9
|
+
register(f: FeatureModuleSpec): this;
|
|
10
|
+
/** List all registered feature modules. */
|
|
11
|
+
list(): FeatureModuleSpec[];
|
|
12
|
+
/** Get a feature by its key (slug). */
|
|
13
|
+
get(key: string): FeatureModuleSpec | undefined;
|
|
14
|
+
/** Filter features by criteria. */
|
|
15
|
+
filter(criteria: RegistryFilter): FeatureModuleSpec[];
|
|
16
|
+
/** List features with specific tag. */
|
|
17
|
+
listByTag(tag: string): FeatureModuleSpec[];
|
|
18
|
+
/** List features by owner. */
|
|
19
|
+
listByOwner(owner: string): FeatureModuleSpec[];
|
|
20
|
+
/** Group features by key function. */
|
|
21
|
+
groupBy(keyFn: GroupKeyFn<FeatureModuleSpec>): Map<string, FeatureModuleSpec[]>;
|
|
22
|
+
/** Get unique tags from all features. */
|
|
23
|
+
getUniqueTags(): string[];
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { FeatureRegistry };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { filterBy, getUniqueTags, groupBy, init_registry_utils } from "../registry-utils.js";
|
|
2
|
+
|
|
3
|
+
//#region src/features/registry.ts
|
|
4
|
+
init_registry_utils();
|
|
5
|
+
function keyOf(f) {
|
|
6
|
+
return f.meta.key;
|
|
7
|
+
}
|
|
8
|
+
/** In-memory registry for FeatureModuleSpec. */
|
|
9
|
+
var FeatureRegistry = class {
|
|
10
|
+
items = /* @__PURE__ */ new Map();
|
|
11
|
+
/** Register a feature module. Throws when the key already exists. */
|
|
12
|
+
register(f) {
|
|
13
|
+
const key = keyOf(f);
|
|
14
|
+
if (this.items.has(key)) throw new Error(`Duplicate feature ${key}`);
|
|
15
|
+
this.items.set(key, f);
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
/** List all registered feature modules. */
|
|
19
|
+
list() {
|
|
20
|
+
return [...this.items.values()];
|
|
21
|
+
}
|
|
22
|
+
/** Get a feature by its key (slug). */
|
|
23
|
+
get(key) {
|
|
24
|
+
return this.items.get(key);
|
|
25
|
+
}
|
|
26
|
+
/** Filter features by criteria. */
|
|
27
|
+
filter(criteria) {
|
|
28
|
+
return filterBy(this.list(), criteria);
|
|
29
|
+
}
|
|
30
|
+
/** List features with specific tag. */
|
|
31
|
+
listByTag(tag) {
|
|
32
|
+
return this.list().filter((f) => f.meta.tags?.includes(tag));
|
|
33
|
+
}
|
|
34
|
+
/** List features by owner. */
|
|
35
|
+
listByOwner(owner) {
|
|
36
|
+
return this.list().filter((f) => f.meta.owners?.includes(owner));
|
|
37
|
+
}
|
|
38
|
+
/** Group features by key function. */
|
|
39
|
+
groupBy(keyFn) {
|
|
40
|
+
return groupBy(this.list(), keyFn);
|
|
41
|
+
}
|
|
42
|
+
/** Get unique tags from all features. */
|
|
43
|
+
getUniqueTags() {
|
|
44
|
+
return getUniqueTags(this.list());
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
export { FeatureRegistry };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { PresentationTarget } from "../presentations/presentations.js";
|
|
2
|
+
import { OwnerShipMeta } from "../ownership.js";
|
|
3
|
+
import { CapabilityRef, CapabilityRequirement } from "../capabilities/capabilities.js";
|
|
4
|
+
import "../capabilities/index.js";
|
|
5
|
+
import { ExperimentRef } from "../experiments/spec.js";
|
|
6
|
+
import { ImplementationRef } from "../operations/operation.js";
|
|
7
|
+
import "../operations/index.js";
|
|
8
|
+
|
|
9
|
+
//#region src/features/types.d.ts
|
|
10
|
+
/** Minimal metadata to identify and categorize a feature module. */
|
|
11
|
+
type FeatureModuleMeta = OwnerShipMeta;
|
|
12
|
+
interface OpRef {
|
|
13
|
+
/** Operation key (OperationSpec.meta.key). */
|
|
14
|
+
key: string;
|
|
15
|
+
/** Operation version (OperationSpec.meta.version). */
|
|
16
|
+
version: number;
|
|
17
|
+
}
|
|
18
|
+
interface EventRef {
|
|
19
|
+
/** Event key. */
|
|
20
|
+
key: string;
|
|
21
|
+
/** Event version. */
|
|
22
|
+
version: number;
|
|
23
|
+
}
|
|
24
|
+
interface PresentationRef {
|
|
25
|
+
/** Presentation key. */
|
|
26
|
+
key: string;
|
|
27
|
+
/** Presentation version. */
|
|
28
|
+
version: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Reference to a data view spec.
|
|
32
|
+
*/
|
|
33
|
+
interface DataViewRef {
|
|
34
|
+
key: string;
|
|
35
|
+
version: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Reference to a form spec.
|
|
39
|
+
*/
|
|
40
|
+
interface FormRef {
|
|
41
|
+
key: string;
|
|
42
|
+
version: number;
|
|
43
|
+
}
|
|
44
|
+
/** Group operations/events/presentations into an installable feature. */
|
|
45
|
+
interface FeatureModuleSpec {
|
|
46
|
+
meta: FeatureModuleMeta;
|
|
47
|
+
/** Contract operations included in this feature. */
|
|
48
|
+
operations?: OpRef[];
|
|
49
|
+
/** Events declared/emitted by this feature. */
|
|
50
|
+
events?: EventRef[];
|
|
51
|
+
/** Presentations associated to this feature. */
|
|
52
|
+
presentations?: PresentationRef[];
|
|
53
|
+
/** Experiments related to this feature. */
|
|
54
|
+
experiments?: ExperimentRef[];
|
|
55
|
+
/** Capability bindings exposed/required by this feature. */
|
|
56
|
+
capabilities?: {
|
|
57
|
+
provides?: CapabilityRef[];
|
|
58
|
+
requires?: CapabilityRequirement[];
|
|
59
|
+
};
|
|
60
|
+
/** Optional: link ops to presentations for traceability (e.g., ui for op) */
|
|
61
|
+
opToPresentation?: {
|
|
62
|
+
op: OpRef;
|
|
63
|
+
pres: PresentationRef;
|
|
64
|
+
}[];
|
|
65
|
+
/** Optional: declare per-presentation target requirements (V2 descriptors) */
|
|
66
|
+
presentationsTargets?: {
|
|
67
|
+
/** Presentation key. */
|
|
68
|
+
key: string;
|
|
69
|
+
/** Presentation version. */
|
|
70
|
+
version: number;
|
|
71
|
+
/** Required targets that must be supported by the descriptor. */
|
|
72
|
+
targets: PresentationTarget[];
|
|
73
|
+
}[];
|
|
74
|
+
/**
|
|
75
|
+
* Explicit implementation file mappings for the entire feature module.
|
|
76
|
+
* Used for tracking and verifying that this feature is correctly implemented.
|
|
77
|
+
*/
|
|
78
|
+
implementations?: ImplementationRef[];
|
|
79
|
+
/** Data views associated with this feature. */
|
|
80
|
+
dataViews?: DataViewRef[];
|
|
81
|
+
/** Forms associated with this feature. */
|
|
82
|
+
forms?: FormRef[];
|
|
83
|
+
}
|
|
84
|
+
interface FeatureRef {
|
|
85
|
+
key: string;
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { DataViewRef, EventRef, FeatureModuleMeta, FeatureModuleSpec, FeatureRef, FormRef, OpRef, PresentationRef };
|
|
File without changes
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PresentationSpec } from "../presentations/presentations.js";
|
|
2
|
+
import { FeatureModuleSpec } from "./types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/features/validation.d.ts
|
|
5
|
+
/** Ensure declared target requirements exist on the provided descriptors. */
|
|
6
|
+
declare function validateFeatureTargetsV2(feature: FeatureModuleSpec, descriptors: PresentationSpec[]): boolean;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { validateFeatureTargetsV2 };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/features/validation.ts
|
|
2
|
+
/** Ensure declared target requirements exist on the provided descriptors. */
|
|
3
|
+
function validateFeatureTargetsV2(feature, descriptors) {
|
|
4
|
+
if (!feature.presentationsTargets || feature.presentationsTargets.length === 0) return true;
|
|
5
|
+
for (const req of feature.presentationsTargets) {
|
|
6
|
+
const d = descriptors.find((x) => x.meta.key === req.key && x.meta.version === req.version);
|
|
7
|
+
if (!d) throw new Error(`V2 descriptor not found ${req.key}.v${req.version}`);
|
|
8
|
+
for (const t of req.targets) if (!d.targets.includes(t)) throw new Error(`Descriptor ${req.key}.v${req.version} missing target ${t}`);
|
|
9
|
+
}
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
export { validateFeatureTargetsV2 };
|