@fabricorg/platform 0.10.0 → 0.11.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +8 -1
  3. package/dist/actions/index.cjs +11 -11
  4. package/dist/actions/index.d.cts +2 -0
  5. package/dist/actions/index.d.ts +2 -0
  6. package/dist/actions/index.js +1 -1
  7. package/dist/chunk-3JQI3OFC.js +347 -0
  8. package/dist/chunk-3JQI3OFC.js.map +1 -0
  9. package/dist/chunk-3S6UTP4X.js +110 -0
  10. package/dist/chunk-3S6UTP4X.js.map +1 -0
  11. package/dist/{chunk-Q3WYIWCN.cjs → chunk-7WASIL46.js} +58 -5
  12. package/dist/chunk-7WASIL46.js.map +1 -0
  13. package/dist/{chunk-BWNPGRRV.cjs → chunk-HLRIXNVG.cjs} +2 -2
  14. package/dist/chunk-HLRIXNVG.cjs.map +1 -0
  15. package/dist/{chunk-4SMPJPJ6.js → chunk-JM55UQWK.js} +2 -2
  16. package/dist/chunk-JM55UQWK.js.map +1 -0
  17. package/dist/{chunk-N72WJ4AU.js → chunk-NFP5DJBT.js} +65 -6
  18. package/dist/chunk-NFP5DJBT.js.map +1 -0
  19. package/dist/{chunk-JSTGOT6P.js → chunk-O7IHZ53Y.cjs} +66 -3
  20. package/dist/chunk-O7IHZ53Y.cjs.map +1 -0
  21. package/dist/chunk-ODP3DO6P.cjs +355 -0
  22. package/dist/chunk-ODP3DO6P.cjs.map +1 -0
  23. package/dist/{chunk-54EQTOH6.cjs → chunk-RYCHDNHZ.cjs} +69 -8
  24. package/dist/chunk-RYCHDNHZ.cjs.map +1 -0
  25. package/dist/chunk-XCL2HBMB.cjs +116 -0
  26. package/dist/chunk-XCL2HBMB.cjs.map +1 -0
  27. package/dist/index.cjs +67 -31
  28. package/dist/index.d.cts +4 -4
  29. package/dist/index.d.ts +4 -4
  30. package/dist/index.js +5 -5
  31. package/dist/manifest/index.cjs +17 -8
  32. package/dist/manifest/index.d.cts +39 -3
  33. package/dist/manifest/index.d.ts +39 -3
  34. package/dist/manifest/index.js +5 -4
  35. package/dist/modules/index.cjs +11 -10
  36. package/dist/modules/index.d.cts +49 -1
  37. package/dist/modules/index.d.ts +49 -1
  38. package/dist/modules/index.js +4 -3
  39. package/dist/objects/index.cjs +9 -5
  40. package/dist/objects/index.d.cts +45 -1
  41. package/dist/objects/index.d.ts +45 -1
  42. package/dist/objects/index.js +1 -1
  43. package/dist/projections/index.cjs +26 -2
  44. package/dist/projections/index.d.cts +38 -2
  45. package/dist/projections/index.d.ts +38 -2
  46. package/dist/projections/index.js +1 -1
  47. package/package.json +1 -1
  48. package/dist/chunk-35DD3H55.js +0 -187
  49. package/dist/chunk-35DD3H55.js.map +0 -1
  50. package/dist/chunk-4SMPJPJ6.js.map +0 -1
  51. package/dist/chunk-54EQTOH6.cjs.map +0 -1
  52. package/dist/chunk-BWNPGRRV.cjs.map +0 -1
  53. package/dist/chunk-I35B576X.js +0 -30
  54. package/dist/chunk-I35B576X.js.map +0 -1
  55. package/dist/chunk-JSTGOT6P.js.map +0 -1
  56. package/dist/chunk-N72WJ4AU.js.map +0 -1
  57. package/dist/chunk-Q3WYIWCN.cjs.map +0 -1
  58. package/dist/chunk-QETQGAXJ.cjs +0 -35
  59. package/dist/chunk-QETQGAXJ.cjs.map +0 -1
  60. package/dist/chunk-SSYKDXR4.cjs +0 -195
  61. package/dist/chunk-SSYKDXR4.cjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @fabricorg/platform
2
2
 
3
+ ## 0.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add versioned view contracts, manifest export, event-schema filtering, and snapshot compatibility
8
+ without prescribing a physical read-model store.
9
+ - Add manifest v2 typed entity contracts, v1 reader normalization, optional action result schemas, and
10
+ Host enforcement of result validation before events and adapters.
11
+
12
+ ## Unreleased
13
+
14
+ - Add manifest v2 typed object definitions, v1 reader normalization, and optional exported action
15
+ result schemas while preserving the zero-dependency runtime.
16
+ - Add versioned logical view contracts with event-schema filtering and explicit snapshot upgrade functions.
17
+
3
18
  ## 0.10.0
4
19
 
5
20
  ### Minor Changes
package/README.md CHANGED
@@ -58,6 +58,11 @@ That's what this package gives you. Nothing more.
58
58
  | `@fabricorg/platform/objects` | Shared object-type contracts |
59
59
  | `@fabricorg/platform/testing` | In-memory adapter registry, fake `ActionContext`, deterministic IDs |
60
60
 
61
+ Modules may publish versioned `ViewContract`s. `replayView` filters declared event schema versions and
62
+ requires an explicit upgrade function before resuming an older compatible snapshot; manifests serialize
63
+ the logical shape and metadata but never executable functions or initial state. Physical stores remain
64
+ adapter concerns.
65
+
61
66
  ## Composing a vertical
62
67
 
63
68
  Verticals declare a `FabricModule<TDb>` that registers their actions, policies, state machines, events, and adapters with the platform:
@@ -93,7 +98,9 @@ const manifest = exportModuleManifest(myModule);
93
98
  const json = JSON.stringify(manifest, null, 2);
94
99
  ```
95
100
 
96
- `exportModuleManifest` is a pure function of the module object: it does not touch the registries and the module does not need to be registered first. Declaration order is preserved everywhere, so the same module always produces byte-identical JSON. Function fields (`handler`, policy `evaluate`, transition `guard`, dynamic `targetState`, adapter `getInput`) are never serialized — the manifest contains definitions only, never raw parameter values, secrets, or runtime data. Actions whose schema validator exposes `toJSONSchema()` (for example Zod 4) include a `parameterSchema` in JSON Schema format. Use `exportModuleManifestBundle(modules)` to export several modules at once.
101
+ `exportModuleManifest` is a pure function of the module object: it does not touch the registries and the module does not need to be registered first. Declaration order is preserved everywhere, so the same module always produces byte-identical JSON. Function fields (`handler`, policy `evaluate`, transition `guard`, dynamic `targetState`, adapter `getInput`) are never serialized — the manifest contains definitions only, never raw parameter values, secrets, or runtime data. Manifest v2 object registrations may include `PortableJsonSchema`, qualified relations, namespaced semantic annotations, and enforcement-owned invariants. Actions whose validators expose `toJSONSchema()` include `parameterSchema` and optional `resultSchema` definitions. `normalizeModuleManifest` and `normalizeModuleManifestBundle` let v2 readers accept v1 input without promising down-conversion.
102
+
103
+ An entity schema does not validate arbitrary writes through `TDb`. Persisted-record validation requires an explicit Host/database adapter. When an action declares `resultSchema`, Platform Host validates the public result after the handler and before events or adapters; failure rolls back the handler transaction.
97
104
 
98
105
  ## The action lifecycle
99
106
 
@@ -1,48 +1,48 @@
1
1
  'use strict';
2
2
 
3
- var chunkBWNPGRRV_cjs = require('../chunk-BWNPGRRV.cjs');
3
+ var chunkHLRIXNVG_cjs = require('../chunk-HLRIXNVG.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "ACTOR_TYPES", {
8
8
  enumerable: true,
9
- get: function () { return chunkBWNPGRRV_cjs.ACTOR_TYPES; }
9
+ get: function () { return chunkHLRIXNVG_cjs.ACTOR_TYPES; }
10
10
  });
11
11
  Object.defineProperty(exports, "assertActionId", {
12
12
  enumerable: true,
13
- get: function () { return chunkBWNPGRRV_cjs.assertActionId; }
13
+ get: function () { return chunkHLRIXNVG_cjs.assertActionId; }
14
14
  });
15
15
  Object.defineProperty(exports, "assertActorType", {
16
16
  enumerable: true,
17
- get: function () { return chunkBWNPGRRV_cjs.assertActorType; }
17
+ get: function () { return chunkHLRIXNVG_cjs.assertActorType; }
18
18
  });
19
19
  Object.defineProperty(exports, "getRegisteredActionIds", {
20
20
  enumerable: true,
21
- get: function () { return chunkBWNPGRRV_cjs.getRegisteredActionIds; }
21
+ get: function () { return chunkHLRIXNVG_cjs.getRegisteredActionIds; }
22
22
  });
23
23
  Object.defineProperty(exports, "isActorType", {
24
24
  enumerable: true,
25
- get: function () { return chunkBWNPGRRV_cjs.isActorType; }
25
+ get: function () { return chunkHLRIXNVG_cjs.isActorType; }
26
26
  });
27
27
  Object.defineProperty(exports, "isRegisteredActionId", {
28
28
  enumerable: true,
29
- get: function () { return chunkBWNPGRRV_cjs.isRegisteredActionId; }
29
+ get: function () { return chunkHLRIXNVG_cjs.isRegisteredActionId; }
30
30
  });
31
31
  Object.defineProperty(exports, "registerAction", {
32
32
  enumerable: true,
33
- get: function () { return chunkBWNPGRRV_cjs.registerAction; }
33
+ get: function () { return chunkHLRIXNVG_cjs.registerAction; }
34
34
  });
35
35
  Object.defineProperty(exports, "registerActionIfMissing", {
36
36
  enumerable: true,
37
- get: function () { return chunkBWNPGRRV_cjs.registerActionIfMissing; }
37
+ get: function () { return chunkHLRIXNVG_cjs.registerActionIfMissing; }
38
38
  });
39
39
  Object.defineProperty(exports, "resolveAction", {
40
40
  enumerable: true,
41
- get: function () { return chunkBWNPGRRV_cjs.resolveAction; }
41
+ get: function () { return chunkHLRIXNVG_cjs.resolveAction; }
42
42
  });
43
43
  Object.defineProperty(exports, "resolveRegisteredAction", {
44
44
  enumerable: true,
45
- get: function () { return chunkBWNPGRRV_cjs.resolveRegisteredAction; }
45
+ get: function () { return chunkHLRIXNVG_cjs.resolveRegisteredAction; }
46
46
  });
47
47
  //# sourceMappingURL=index.cjs.map
48
48
  //# sourceMappingURL=index.cjs.map
@@ -64,6 +64,8 @@ interface ActionDefinition<TDb = unknown> {
64
64
  namespace: string;
65
65
  version: number;
66
66
  schema: SchemaValidator;
67
+ /** Optional validation contract for the public handler result data. */
68
+ resultSchema?: SchemaValidator;
67
69
  handler?: ActionHandler<TDb>;
68
70
  requiredRoles?: string[];
69
71
  requiredPermissions?: string[];
@@ -64,6 +64,8 @@ interface ActionDefinition<TDb = unknown> {
64
64
  namespace: string;
65
65
  version: number;
66
66
  schema: SchemaValidator;
67
+ /** Optional validation contract for the public handler result data. */
68
+ resultSchema?: SchemaValidator;
67
69
  handler?: ActionHandler<TDb>;
68
70
  requiredRoles?: string[];
69
71
  requiredPermissions?: string[];
@@ -1,3 +1,3 @@
1
- export { ACTOR_TYPES, assertActionId, assertActorType, getRegisteredActionIds, isActorType, isRegisteredActionId, registerAction, registerActionIfMissing, resolveAction, resolveRegisteredAction } from '../chunk-4SMPJPJ6.js';
1
+ export { ACTOR_TYPES, assertActionId, assertActorType, getRegisteredActionIds, isActorType, isRegisteredActionId, registerAction, registerActionIfMissing, resolveAction, resolveRegisteredAction } from '../chunk-JM55UQWK.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,347 @@
1
+ import { assertPortableJsonSchema, registerObjectType } from './chunk-3S6UTP4X.js';
2
+ import { registerPolicyIfMissing } from './chunk-6ER62UUN.js';
3
+ import { registerViewContractIfMissing } from './chunk-7WASIL46.js';
4
+ import { registerStateMachineIfMissing } from './chunk-T2JLSZN6.js';
5
+ import { registerActionIfMissing } from './chunk-JM55UQWK.js';
6
+ import { registerDisplayRenderer } from './chunk-O5WVBQ7P.js';
7
+ import { isValidEventType, registerSubjectType, registerEventType } from './chunk-4YQOGV7H.js';
8
+
9
+ // modules/index.ts
10
+ var registeredModuleNamespaces = /* @__PURE__ */ new Set();
11
+ var registeredQualifiedObjectTypes = /* @__PURE__ */ new Set();
12
+ var registeredObjectDefinitions = /* @__PURE__ */ new Map();
13
+ function getModuleDependencyNamespace(dependency) {
14
+ return typeof dependency === "string" ? dependency : dependency.namespace;
15
+ }
16
+ function getObjectTypeName(objectType) {
17
+ return typeof objectType === "string" ? objectType : objectType.type;
18
+ }
19
+ function getEventTypeName(eventType) {
20
+ return typeof eventType === "string" ? eventType : eventType.eventType;
21
+ }
22
+ function validateModuleNamespace(namespace) {
23
+ if (!namespace) {
24
+ throw new Error("Module namespace cannot be empty");
25
+ }
26
+ if (!/^[a-z][a-z0-9-]*$/.test(namespace)) {
27
+ throw new Error(
28
+ `Invalid module namespace: "${namespace}". Must be lowercase letters, numbers, and hyphens only.`
29
+ );
30
+ }
31
+ }
32
+ function createModuleRegistry(modules = []) {
33
+ const registered = /* @__PURE__ */ new Map();
34
+ for (const module of modules) {
35
+ validateModuleNamespace(module.namespace);
36
+ if (registered.has(module.namespace)) {
37
+ throw new Error(`Duplicate FabricModule namespace "${module.namespace}".`);
38
+ }
39
+ registered.set(module.namespace, module);
40
+ }
41
+ return { modules: registered };
42
+ }
43
+ function validateIdentifierList(values, label, namespace) {
44
+ for (const value of values ?? []) {
45
+ if (!value) {
46
+ throw new Error(`Module "${namespace}" has an empty ${label} entry.`);
47
+ }
48
+ }
49
+ }
50
+ function assertJsonValue(value, path) {
51
+ if (value === null || typeof value === "string" || typeof value === "boolean") return;
52
+ if (typeof value === "number" && Number.isFinite(value)) return;
53
+ if (Array.isArray(value)) {
54
+ value.forEach((item, index) => assertJsonValue(item, `${path}[${index}]`));
55
+ return;
56
+ }
57
+ if (typeof value === "object") {
58
+ for (const [key, child] of Object.entries(value)) {
59
+ assertJsonValue(child, `${path}.${key}`);
60
+ }
61
+ return;
62
+ }
63
+ throw new Error(`${path} must contain JSON-serializable values.`);
64
+ }
65
+ function qualifiedObjectType(namespace, type) {
66
+ return `${namespace}.${type}`;
67
+ }
68
+ function validateObjectDefinition(objectType, namespace, context) {
69
+ if (typeof objectType === "string") return;
70
+ if (objectType.schema !== void 0) {
71
+ assertPortableJsonSchema(objectType.schema, `Module "${namespace}" object "${objectType.type}" schema`);
72
+ }
73
+ if (objectType.semantics !== void 0) {
74
+ assertJsonValue(objectType.semantics, `Module "${namespace}" object "${objectType.type}" semantics`);
75
+ }
76
+ const relationNames = /* @__PURE__ */ new Set();
77
+ for (const relation of objectType.relations ?? []) {
78
+ if (!/^[a-z][a-zA-Z0-9]*$/.test(relation.name)) {
79
+ throw new Error(`Module "${namespace}" object "${objectType.type}" has invalid relation name "${relation.name}".`);
80
+ }
81
+ if (relationNames.has(relation.name)) {
82
+ throw new Error(`Module "${namespace}" object "${objectType.type}" has duplicate relation "${relation.name}".`);
83
+ }
84
+ relationNames.add(relation.name);
85
+ if (!/^[a-z][a-z0-9-]*\.[A-Z][a-zA-Z0-9]*$/.test(relation.target)) {
86
+ throw new Error(`Relation "${relation.name}" target "${relation.target}" must be module-qualified.`);
87
+ }
88
+ if (context.availableObjectTypes && !context.availableObjectTypes.has(relation.target)) {
89
+ throw new Error(`Relation "${relation.name}" targets missing object type "${relation.target}".`);
90
+ }
91
+ if (relation.required && relation.onTargetDelete === "set-null") {
92
+ throw new Error(`Required relation "${relation.name}" cannot use onTargetDelete "set-null".`);
93
+ }
94
+ }
95
+ const invariantIds = /* @__PURE__ */ new Set();
96
+ for (const invariant of objectType.invariants ?? []) {
97
+ if (!invariant.id.trim() || !invariant.description.trim()) {
98
+ throw new Error(`Module "${namespace}" object "${objectType.type}" has an invariant without an id or description.`);
99
+ }
100
+ if (invariantIds.has(invariant.id)) {
101
+ throw new Error(`Module "${namespace}" object "${objectType.type}" has duplicate invariant "${invariant.id}".`);
102
+ }
103
+ invariantIds.add(invariant.id);
104
+ if (invariant.required && !invariant.enforcementRef?.trim()) {
105
+ throw new Error(`Required invariant "${invariant.id}" must declare enforcementRef.`);
106
+ }
107
+ }
108
+ }
109
+ function validateManifest(module, context = {}) {
110
+ validateModuleNamespace(module.namespace);
111
+ const dependencies = (module.dependencies ?? []).map(getModuleDependencyNamespace);
112
+ const objectTypes = (module.objectTypes ?? []).map(getObjectTypeName);
113
+ const eventTypes = (module.eventTypes ?? []).map(getEventTypeName);
114
+ if (module.capability) {
115
+ if (!module.capability.displayName.trim() || !module.capability.description.trim()) {
116
+ throw new Error(`Module "${module.namespace}" capability requires displayName and description.`);
117
+ }
118
+ if (new Set(module.capability.roles ?? []).size !== (module.capability.roles ?? []).length || (module.capability.roles ?? []).some((role) => !/^[a-z][a-z0-9-]*$/.test(role))) {
119
+ throw new Error(`Module "${module.namespace}" capability has invalid or duplicate roles.`);
120
+ }
121
+ const slots = /* @__PURE__ */ new Set();
122
+ for (const slot of module.capability.slots ?? []) {
123
+ if (!/^[a-z][a-z0-9-]*$/.test(slot.name) || slots.has(slot.name)) {
124
+ throw new Error(`Module "${module.namespace}" capability has invalid or duplicate slot "${slot.name}".`);
125
+ }
126
+ slots.add(slot.name);
127
+ if (slot.shape) assertPortableJsonSchema(slot.shape, `Capability slot "${slot.name}" shape`);
128
+ }
129
+ }
130
+ for (const dependency of dependencies) {
131
+ validateModuleNamespace(dependency);
132
+ if (dependency === module.namespace) {
133
+ throw new Error(`Module "${module.namespace}" cannot depend on itself.`);
134
+ }
135
+ if (context.availableNamespaces && !context.availableNamespaces.has(dependency)) {
136
+ throw new Error(`Module "${module.namespace}" depends on missing module "${dependency}".`);
137
+ }
138
+ }
139
+ validateIdentifierList(objectTypes, "objectTypes", module.namespace);
140
+ validateIdentifierList(module.subjectTypes, "subjectTypes", module.namespace);
141
+ validateIdentifierList(eventTypes, "eventTypes", module.namespace);
142
+ for (const objectType of objectTypes) {
143
+ if (!/^[A-Z][a-zA-Z0-9]*$/.test(objectType)) {
144
+ throw new Error(
145
+ `Invalid object type: "${objectType}". Object types must be PascalCase alphanumeric.`
146
+ );
147
+ }
148
+ }
149
+ for (const objectType of module.objectTypes ?? []) {
150
+ validateObjectDefinition(objectType, module.namespace, context);
151
+ }
152
+ for (const action of module.actions ?? []) {
153
+ if (!/^[a-z][a-z0-9-]*\.[a-z][a-z0-9_]*$/.test(action.actionId)) {
154
+ throw new Error(`Invalid action ID: ${action.actionId}`);
155
+ }
156
+ if (action.namespace !== module.namespace) {
157
+ throw new Error(
158
+ `Action "${action.actionId}" declares namespace "${action.namespace}" but is registered by module "${module.namespace}".`
159
+ );
160
+ }
161
+ if (!action.actionId.startsWith(`${module.namespace}.`)) {
162
+ throw new Error(
163
+ `Action "${action.actionId}" must start with module namespace "${module.namespace}."`
164
+ );
165
+ }
166
+ if (action.mutatesDomain && action.emitsEvents.length === 0) {
167
+ throw new Error(
168
+ `Action "${action.actionId}" mutates domain but emits no events. Every mutating action must emit at least one AssetEvent.`
169
+ );
170
+ }
171
+ }
172
+ for (const descriptor of module.displayRenderers ?? []) {
173
+ const isPlannedEventType = context.plannedEventTypes?.has(descriptor.eventType) ?? false;
174
+ const isModuleEventType = eventTypes.includes(descriptor.eventType);
175
+ if (!isValidEventType(descriptor.eventType) && !isModuleEventType && !isPlannedEventType) {
176
+ throw new Error(
177
+ `Display renderer registered for unknown event type "${descriptor.eventType}". Register the event type before adding a display renderer.`
178
+ );
179
+ }
180
+ }
181
+ const viewKeys = /* @__PURE__ */ new Set();
182
+ for (const view of module.views ?? []) {
183
+ if (!view.name.startsWith(`${module.namespace}/`) || !/^[a-z][a-z0-9-]*\/[a-z][a-z0-9/_-]*$/.test(view.name)) {
184
+ throw new Error(`View "${view.name}" must start with module namespace "${module.namespace}/" and use lowercase path segments.`);
185
+ }
186
+ if (!view.version.trim()) throw new Error(`View "${view.name}" must declare a version.`);
187
+ const key = `${view.name}@${view.version}`;
188
+ if (viewKeys.has(key)) throw new Error(`Module "${module.namespace}" has duplicate view contract "${key}".`);
189
+ viewKeys.add(key);
190
+ assertPortableJsonSchema(view.shape, `View "${key}" shape`);
191
+ if (!Number.isInteger(view.snapshotVersion) || view.snapshotVersion < 1) {
192
+ throw new Error(`View "${key}" snapshotVersion must be a positive integer.`);
193
+ }
194
+ if ((view.compatibleSnapshotVersions?.some((version) => version !== view.snapshotVersion) ?? false) && !view.upgradeSnapshot) {
195
+ throw new Error(`View "${key}" declares older compatible snapshots but no upgradeSnapshot function.`);
196
+ }
197
+ for (const consumption of view.consumes) {
198
+ const isPlanned = context.plannedEventTypes?.has(consumption.eventType) ?? false;
199
+ const isModuleEvent = eventTypes.includes(consumption.eventType);
200
+ if (!isValidEventType(consumption.eventType) && !isPlanned && !isModuleEvent) {
201
+ throw new Error(`View "${key}" consumes unknown event type "${consumption.eventType}".`);
202
+ }
203
+ if (consumption.schemaVersions.length === 0 || consumption.schemaVersions.some((version) => !Number.isInteger(version) || version < 1)) {
204
+ throw new Error(`View "${key}" must declare positive consumed schema versions for "${consumption.eventType}".`);
205
+ }
206
+ }
207
+ }
208
+ }
209
+ function sortModulesByDependency(modules, registeredNamespaces = registeredModuleNamespaces) {
210
+ const modulesByNamespace = /* @__PURE__ */ new Map();
211
+ for (const module of modules) {
212
+ validateModuleNamespace(module.namespace);
213
+ if (modulesByNamespace.has(module.namespace)) {
214
+ throw new Error(`Duplicate Fabric module namespace "${module.namespace}".`);
215
+ }
216
+ modulesByNamespace.set(module.namespace, module);
217
+ }
218
+ const sorted = [];
219
+ const visiting = /* @__PURE__ */ new Set();
220
+ const visited = /* @__PURE__ */ new Set();
221
+ function visit(module, path) {
222
+ if (visited.has(module.namespace)) {
223
+ return;
224
+ }
225
+ if (visiting.has(module.namespace)) {
226
+ throw new Error(
227
+ `Cyclic Fabric module dependency detected: ${[...path, module.namespace].join(" -> ")}`
228
+ );
229
+ }
230
+ visiting.add(module.namespace);
231
+ for (const dependency of (module.dependencies ?? []).map(getModuleDependencyNamespace)) {
232
+ const dependencyModule = modulesByNamespace.get(dependency);
233
+ if (!dependencyModule) {
234
+ if (registeredNamespaces.has(dependency)) {
235
+ continue;
236
+ }
237
+ throw new Error(`Module "${module.namespace}" depends on missing module "${dependency}".`);
238
+ }
239
+ visit(dependencyModule, [...path, module.namespace]);
240
+ }
241
+ visiting.delete(module.namespace);
242
+ visited.add(module.namespace);
243
+ sorted.push(module);
244
+ }
245
+ for (const module of modules) {
246
+ visit(module, []);
247
+ }
248
+ return sorted;
249
+ }
250
+ function assertAcyclicRelations(modules) {
251
+ const relationKinds = [
252
+ { label: "owned containment", include: (relation) => relation.semantics === "owned" },
253
+ { label: "cascade-delete", include: (relation) => relation.onTargetDelete === "cascade" },
254
+ { label: "required-construction", include: (relation) => relation.required === true }
255
+ ];
256
+ for (const kind of relationKinds) {
257
+ const edges = /* @__PURE__ */ new Map();
258
+ for (const [source, objectType] of registeredObjectDefinitions) {
259
+ edges.set(source, (objectType.relations ?? []).filter(kind.include).map((relation) => relation.target));
260
+ }
261
+ for (const module of modules) {
262
+ for (const objectType of module.objectTypes ?? []) {
263
+ if (typeof objectType === "string") continue;
264
+ const source = qualifiedObjectType(module.namespace, objectType.type);
265
+ edges.set(source, (objectType.relations ?? []).filter(kind.include).map((relation) => relation.target));
266
+ }
267
+ }
268
+ const visiting = /* @__PURE__ */ new Set();
269
+ const visited = /* @__PURE__ */ new Set();
270
+ const visit = (node, path) => {
271
+ if (visiting.has(node)) {
272
+ throw new Error(`${kind.label} relation cycle detected: ${[...path, node].join(" -> ")}`);
273
+ }
274
+ if (visited.has(node)) return;
275
+ visiting.add(node);
276
+ for (const target of edges.get(node) ?? []) visit(target, [...path, node]);
277
+ visiting.delete(node);
278
+ visited.add(node);
279
+ };
280
+ for (const node of edges.keys()) visit(node, []);
281
+ }
282
+ }
283
+ function registerValidatedFabricModule(module) {
284
+ for (const objectType of module.objectTypes ?? []) {
285
+ registerObjectType(getObjectTypeName(objectType));
286
+ const qualified = qualifiedObjectType(module.namespace, getObjectTypeName(objectType));
287
+ registeredQualifiedObjectTypes.add(qualified);
288
+ if (typeof objectType !== "string") registeredObjectDefinitions.set(qualified, objectType);
289
+ }
290
+ for (const subjectType of module.subjectTypes ?? []) {
291
+ registerSubjectType(subjectType);
292
+ }
293
+ for (const eventType of module.eventTypes ?? []) {
294
+ registerEventType(getEventTypeName(eventType));
295
+ }
296
+ for (const policy of module.policies ?? []) {
297
+ registerPolicyIfMissing(policy);
298
+ }
299
+ for (const machine of module.stateMachines ?? []) {
300
+ registerStateMachineIfMissing(machine);
301
+ }
302
+ for (const action of module.actions ?? []) {
303
+ registerActionIfMissing(action);
304
+ }
305
+ for (const descriptor of module.displayRenderers ?? []) {
306
+ registerDisplayRenderer(descriptor.eventType, descriptor.renderer);
307
+ }
308
+ for (const view of module.views ?? []) registerViewContractIfMissing(view);
309
+ registeredModuleNamespaces.add(module.namespace);
310
+ }
311
+ function registerFabricModule(module) {
312
+ const availableObjectTypes = /* @__PURE__ */ new Set([
313
+ ...registeredQualifiedObjectTypes,
314
+ ...(module.objectTypes ?? []).map((objectType) => qualifiedObjectType(module.namespace, getObjectTypeName(objectType)))
315
+ ]);
316
+ validateManifest(module, { availableNamespaces: registeredModuleNamespaces, availableObjectTypes });
317
+ assertAcyclicRelations([module]);
318
+ registerValidatedFabricModule(module);
319
+ }
320
+ function registerFabricModules(modules) {
321
+ const availableNamespaces = /* @__PURE__ */ new Set([
322
+ ...registeredModuleNamespaces,
323
+ ...modules.map((module) => module.namespace)
324
+ ]);
325
+ const plannedEventTypes = new Set(
326
+ modules.flatMap((module) => (module.eventTypes ?? []).map(getEventTypeName))
327
+ );
328
+ const availableObjectTypes = /* @__PURE__ */ new Set([
329
+ ...registeredQualifiedObjectTypes,
330
+ ...modules.flatMap(
331
+ (module) => (module.objectTypes ?? []).map((objectType) => qualifiedObjectType(module.namespace, getObjectTypeName(objectType)))
332
+ )
333
+ ]);
334
+ for (const module of modules) {
335
+ validateManifest(module, { availableNamespaces, plannedEventTypes, availableObjectTypes });
336
+ }
337
+ assertAcyclicRelations(modules);
338
+ const sortedModules = sortModulesByDependency(modules);
339
+ for (const module of sortedModules) {
340
+ registerValidatedFabricModule(module);
341
+ }
342
+ return sortedModules;
343
+ }
344
+
345
+ export { createModuleRegistry, getEventTypeName, getModuleDependencyNamespace, getObjectTypeName, registerFabricModule, registerFabricModules, validateModuleNamespace };
346
+ //# sourceMappingURL=chunk-3JQI3OFC.js.map
347
+ //# sourceMappingURL=chunk-3JQI3OFC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../modules/index.ts"],"names":[],"mappings":"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","file":"chunk-3JQI3OFC.js","sourcesContent":["import { registerActionIfMissing, type ActionDefinition } from \"../actions\";\nimport { registerDisplayRenderer, type DisplayRenderer } from \"../displays\";\nimport { isValidEventType, registerEventType, registerSubjectType } from \"../events\";\nimport {\n\tassertPortableJsonSchema,\n\tregisterObjectType,\n\ttype JsonValue,\n\ttype PortableJsonSchema,\n} from \"../objects\";\nimport { registerPolicyIfMissing, type PolicyEvaluator } from \"../policies\";\nimport { registerStateMachineIfMissing, type StateMachineDefinition } from \"../state-machines\";\nimport { registerViewContractIfMissing, type ViewContract } from \"../projections\";\n\nexport interface ModuleDependency {\n\tnamespace: string;\n\tversion?: string;\n\toptional?: boolean;\n}\n\nexport type ModuleDependencyInput = string | ModuleDependency;\n\nexport interface IdPrefixRegistration {\n\tprefix: string;\n\tname: string;\n\tmodule: string;\n}\n\nexport interface EventTypeRegistration {\n\teventType: string;\n\tschemaVersion: number;\n\tdescription?: string;\n}\n\nexport type EventTypeRegistrationInput = string | EventTypeRegistration;\n\nexport interface ObjectTypeRegistration {\n\ttype: string;\n\tdisplayName?: string;\n\tidPrefix?: string;\n\tisCoreModuleType?: boolean;\n\tschema?: PortableJsonSchema;\n\tsemantics?: Record<string, JsonValue>;\n\trelations?: ObjectRelationDefinition[];\n\tinvariants?: DeclarativeInvariant[];\n}\n\nexport type ObjectRelationCardinality = \"one\" | \"many\";\nexport type ObjectRelationSemantics = \"reference\" | \"owned\";\nexport type ObjectRelationDeleteBehavior = \"restrict\" | \"cascade\" | \"set-null\";\n\nexport interface ObjectRelationDefinition {\n\tname: string;\n\ttarget: `${string}.${string}`;\n\tcardinality: ObjectRelationCardinality;\n\trequired?: boolean;\n\tsemantics: ObjectRelationSemantics;\n\tonTargetDelete: ObjectRelationDeleteBehavior;\n}\n\nexport type InvariantEnforcement =\n\t| \"json-schema\"\n\t| \"state-machine\"\n\t| \"policy\"\n\t| \"host-adapter\"\n\t| \"application\";\n\nexport interface DeclarativeInvariant {\n\tid: string;\n\tdescription: string;\n\trequired?: boolean;\n\tenforcement: InvariantEnforcement;\n\tenforcementRef?: string;\n}\n\nexport type ObjectTypeRegistrationInput = string | ObjectTypeRegistration;\n\nexport interface ModuleDisplayRendererRegistration {\n\teventType: string;\n\trenderer: DisplayRenderer;\n}\n\nexport interface PolicyRegistration {\n\tid: string;\n\tversion?: string;\n\tdescription?: string;\n}\n\nexport interface StateMachineRegistration {\n\tentityType: string;\n\tstates: string[];\n}\n\nexport interface CapabilitySlotDefinition {\n\tname: string;\n\tdescription: string;\n\tshape?: PortableJsonSchema;\n}\n\nexport interface CapabilityMetadata {\n\tdisplayName: string;\n\tdescription: string;\n\troles?: string[];\n\tstability: \"experimental\" | \"beta\" | \"stable\" | \"deprecated\";\n\tdeprecated?: { since: string; replacement?: string; message: string };\n\tslots?: CapabilitySlotDefinition[];\n\tcertification?: { profile: string; required: boolean };\n}\n\nexport interface FabricModule<TDb = unknown> {\n\tnamespace: string;\n\tversion?: string;\n\tdisplayName?: string;\n\tdescription?: string;\n\tcapability?: CapabilityMetadata;\n\tdependencies?: ModuleDependencyInput[];\n\tobjectTypes?: ObjectTypeRegistrationInput[];\n\tsubjectTypes?: string[];\n\tidPrefixes?: IdPrefixRegistration[];\n\teventTypes?: EventTypeRegistrationInput[];\n\tactions?: ActionDefinition<TDb>[];\n\tpolicies?: unknown[];\n\tstateMachines?: unknown[];\n\tdisplayRenderers?: ModuleDisplayRendererRegistration[];\n\tadapterDefinitions?: unknown[];\n\tpermissions?: unknown[];\n\troles?: unknown[];\n\tredactionRules?: unknown[];\n\tdataClassifications?: unknown[];\n\tretentionRules?: unknown[];\n\tevidenceRenderers?: unknown[];\n\tviews?: ViewContract[];\n}\n\nexport interface ModuleRegistry<TDb = unknown> {\n\tmodules: ReadonlyMap<string, FabricModule<TDb>>;\n}\n\ninterface ModuleValidationContext {\n\tavailableNamespaces?: Set<string>;\n\tplannedEventTypes?: Set<string>;\n\tavailableObjectTypes?: Set<string>;\n}\n\nconst registeredModuleNamespaces = new Set<string>();\nconst registeredQualifiedObjectTypes = new Set<string>();\nconst registeredObjectDefinitions = new Map<string, ObjectTypeRegistration>();\n\nexport function getModuleDependencyNamespace(dependency: ModuleDependencyInput): string {\n\treturn typeof dependency === \"string\" ? dependency : dependency.namespace;\n}\n\nexport function getObjectTypeName(objectType: ObjectTypeRegistrationInput): string {\n\treturn typeof objectType === \"string\" ? objectType : objectType.type;\n}\n\nexport function getEventTypeName(eventType: EventTypeRegistrationInput): string {\n\treturn typeof eventType === \"string\" ? eventType : eventType.eventType;\n}\n\nexport function validateModuleNamespace(namespace: string): void {\n\tif (!namespace) {\n\t\tthrow new Error(\"Module namespace cannot be empty\");\n\t}\n\tif (!/^[a-z][a-z0-9-]*$/.test(namespace)) {\n\t\tthrow new Error(\n\t\t\t`Invalid module namespace: \"${namespace}\". Must be lowercase letters, numbers, and hyphens only.`,\n\t\t);\n\t}\n}\n\nexport function createModuleRegistry<TDb = unknown>(\n\tmodules: FabricModule<TDb>[] = [],\n): ModuleRegistry<TDb> {\n\tconst registered = new Map<string, FabricModule<TDb>>();\n\tfor (const module of modules) {\n\t\tvalidateModuleNamespace(module.namespace);\n\t\tif (registered.has(module.namespace)) {\n\t\t\tthrow new Error(`Duplicate FabricModule namespace \"${module.namespace}\".`);\n\t\t}\n\t\tregistered.set(module.namespace, module);\n\t}\n\treturn { modules: registered };\n}\n\nfunction validateIdentifierList(\n\tvalues: string[] | undefined,\n\tlabel: string,\n\tnamespace: string,\n): void {\n\tfor (const value of values ?? []) {\n\t\tif (!value) {\n\t\t\tthrow new Error(`Module \"${namespace}\" has an empty ${label} entry.`);\n\t\t}\n\t}\n}\n\nfunction assertJsonValue(value: unknown, path: string): asserts value is JsonValue {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") return;\n\tif (typeof value === \"number\" && Number.isFinite(value)) return;\n\tif (Array.isArray(value)) {\n\t\tvalue.forEach((item, index) => assertJsonValue(item, `${path}[${index}]`));\n\t\treturn;\n\t}\n\tif (typeof value === \"object\") {\n\t\tfor (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n\t\t\tassertJsonValue(child, `${path}.${key}`);\n\t\t}\n\t\treturn;\n\t}\n\tthrow new Error(`${path} must contain JSON-serializable values.`);\n}\n\nfunction qualifiedObjectType(namespace: string, type: string): string {\n\treturn `${namespace}.${type}`;\n}\n\nfunction validateObjectDefinition(\n\tobjectType: ObjectTypeRegistrationInput,\n\tnamespace: string,\n\tcontext: ModuleValidationContext,\n): void {\n\tif (typeof objectType === \"string\") return;\n\tif (objectType.schema !== undefined) {\n\t\tassertPortableJsonSchema(objectType.schema, `Module \"${namespace}\" object \"${objectType.type}\" schema`);\n\t}\n\tif (objectType.semantics !== undefined) {\n\t\tassertJsonValue(objectType.semantics, `Module \"${namespace}\" object \"${objectType.type}\" semantics`);\n\t}\n\tconst relationNames = new Set<string>();\n\tfor (const relation of objectType.relations ?? []) {\n\t\tif (!/^[a-z][a-zA-Z0-9]*$/.test(relation.name)) {\n\t\t\tthrow new Error(`Module \"${namespace}\" object \"${objectType.type}\" has invalid relation name \"${relation.name}\".`);\n\t\t}\n\t\tif (relationNames.has(relation.name)) {\n\t\t\tthrow new Error(`Module \"${namespace}\" object \"${objectType.type}\" has duplicate relation \"${relation.name}\".`);\n\t\t}\n\t\trelationNames.add(relation.name);\n\t\tif (!/^[a-z][a-z0-9-]*\\.[A-Z][a-zA-Z0-9]*$/.test(relation.target)) {\n\t\t\tthrow new Error(`Relation \"${relation.name}\" target \"${relation.target}\" must be module-qualified.`);\n\t\t}\n\t\tif (context.availableObjectTypes && !context.availableObjectTypes.has(relation.target)) {\n\t\t\tthrow new Error(`Relation \"${relation.name}\" targets missing object type \"${relation.target}\".`);\n\t\t}\n\t\tif (relation.required && relation.onTargetDelete === \"set-null\") {\n\t\t\tthrow new Error(`Required relation \"${relation.name}\" cannot use onTargetDelete \"set-null\".`);\n\t\t}\n\t}\n\tconst invariantIds = new Set<string>();\n\tfor (const invariant of objectType.invariants ?? []) {\n\t\tif (!invariant.id.trim() || !invariant.description.trim()) {\n\t\t\tthrow new Error(`Module \"${namespace}\" object \"${objectType.type}\" has an invariant without an id or description.`);\n\t\t}\n\t\tif (invariantIds.has(invariant.id)) {\n\t\t\tthrow new Error(`Module \"${namespace}\" object \"${objectType.type}\" has duplicate invariant \"${invariant.id}\".`);\n\t\t}\n\t\tinvariantIds.add(invariant.id);\n\t\tif (invariant.required && !invariant.enforcementRef?.trim()) {\n\t\t\tthrow new Error(`Required invariant \"${invariant.id}\" must declare enforcementRef.`);\n\t\t}\n\t}\n}\n\nfunction validateManifest(module: FabricModule<unknown>, context: ModuleValidationContext = {}): void {\n\tvalidateModuleNamespace(module.namespace);\n\n\tconst dependencies = (module.dependencies ?? []).map(getModuleDependencyNamespace);\n\tconst objectTypes = (module.objectTypes ?? []).map(getObjectTypeName);\n\tconst eventTypes = (module.eventTypes ?? []).map(getEventTypeName);\n\tif (module.capability) {\n\t\tif (!module.capability.displayName.trim() || !module.capability.description.trim()) {\n\t\t\tthrow new Error(`Module \"${module.namespace}\" capability requires displayName and description.`);\n\t\t}\n\t\tif (new Set(module.capability.roles ?? []).size !== (module.capability.roles ?? []).length || (module.capability.roles ?? []).some((role) => !/^[a-z][a-z0-9-]*$/.test(role))) {\n\t\t\tthrow new Error(`Module \"${module.namespace}\" capability has invalid or duplicate roles.`);\n\t\t}\n\t\tconst slots = new Set<string>();\n\t\tfor (const slot of module.capability.slots ?? []) {\n\t\t\tif (!/^[a-z][a-z0-9-]*$/.test(slot.name) || slots.has(slot.name)) {\n\t\t\t\tthrow new Error(`Module \"${module.namespace}\" capability has invalid or duplicate slot \"${slot.name}\".`);\n\t\t\t}\n\t\t\tslots.add(slot.name);\n\t\t\tif (slot.shape) assertPortableJsonSchema(slot.shape, `Capability slot \"${slot.name}\" shape`);\n\t\t}\n\t}\n\n\tfor (const dependency of dependencies) {\n\t\tvalidateModuleNamespace(dependency);\n\t\tif (dependency === module.namespace) {\n\t\t\tthrow new Error(`Module \"${module.namespace}\" cannot depend on itself.`);\n\t\t}\n\t\tif (context.availableNamespaces && !context.availableNamespaces.has(dependency)) {\n\t\t\tthrow new Error(`Module \"${module.namespace}\" depends on missing module \"${dependency}\".`);\n\t\t}\n\t}\n\n\tvalidateIdentifierList(objectTypes, \"objectTypes\", module.namespace);\n\tvalidateIdentifierList(module.subjectTypes, \"subjectTypes\", module.namespace);\n\tvalidateIdentifierList(eventTypes, \"eventTypes\", module.namespace);\n\n\tfor (const objectType of objectTypes) {\n\t\tif (!/^[A-Z][a-zA-Z0-9]*$/.test(objectType)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid object type: \"${objectType}\". Object types must be PascalCase alphanumeric.`,\n\t\t\t);\n\t\t}\n\t}\n\tfor (const objectType of module.objectTypes ?? []) {\n\t\tvalidateObjectDefinition(objectType, module.namespace, context);\n\t}\n\n\tfor (const action of module.actions ?? []) {\n\t\tif (!/^[a-z][a-z0-9-]*\\.[a-z][a-z0-9_]*$/.test(action.actionId)) {\n\t\t\tthrow new Error(`Invalid action ID: ${action.actionId}`);\n\t\t}\n\n\t\tif (action.namespace !== module.namespace) {\n\t\t\tthrow new Error(\n\t\t\t\t`Action \"${action.actionId}\" declares namespace \"${action.namespace}\" ` +\n\t\t\t\t\t`but is registered by module \"${module.namespace}\".`,\n\t\t\t);\n\t\t}\n\n\t\tif (!action.actionId.startsWith(`${module.namespace}.`)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Action \"${action.actionId}\" must start with module namespace \"${module.namespace}.\"`,\n\t\t\t);\n\t\t}\n\n\t\tif (action.mutatesDomain && action.emitsEvents.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Action \"${action.actionId}\" mutates domain but emits no events. ` +\n\t\t\t\t\t`Every mutating action must emit at least one AssetEvent.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tfor (const descriptor of module.displayRenderers ?? []) {\n\t\tconst isPlannedEventType = context.plannedEventTypes?.has(descriptor.eventType) ?? false;\n\t\tconst isModuleEventType = eventTypes.includes(descriptor.eventType);\n\t\tif (!isValidEventType(descriptor.eventType) && !isModuleEventType && !isPlannedEventType) {\n\t\t\tthrow new Error(\n\t\t\t\t`Display renderer registered for unknown event type \"${descriptor.eventType}\". ` +\n\t\t\t\t\t`Register the event type before adding a display renderer.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tconst viewKeys = new Set<string>();\n\tfor (const view of module.views ?? []) {\n\t\tif (!view.name.startsWith(`${module.namespace}/`) || !/^[a-z][a-z0-9-]*\\/[a-z][a-z0-9/_-]*$/.test(view.name)) {\n\t\t\tthrow new Error(`View \"${view.name}\" must start with module namespace \"${module.namespace}/\" and use lowercase path segments.`);\n\t\t}\n\t\tif (!view.version.trim()) throw new Error(`View \"${view.name}\" must declare a version.`);\n\t\tconst key = `${view.name}@${view.version}`;\n\t\tif (viewKeys.has(key)) throw new Error(`Module \"${module.namespace}\" has duplicate view contract \"${key}\".`);\n\t\tviewKeys.add(key);\n\t\tassertPortableJsonSchema(view.shape, `View \"${key}\" shape`);\n\t\tif (!Number.isInteger(view.snapshotVersion) || view.snapshotVersion < 1) {\n\t\t\tthrow new Error(`View \"${key}\" snapshotVersion must be a positive integer.`);\n\t\t}\n\t\tif ((view.compatibleSnapshotVersions?.some((version) => version !== view.snapshotVersion) ?? false) && !view.upgradeSnapshot) {\n\t\t\tthrow new Error(`View \"${key}\" declares older compatible snapshots but no upgradeSnapshot function.`);\n\t\t}\n\t\tfor (const consumption of view.consumes) {\n\t\t\tconst isPlanned = context.plannedEventTypes?.has(consumption.eventType) ?? false;\n\t\t\tconst isModuleEvent = eventTypes.includes(consumption.eventType);\n\t\t\tif (!isValidEventType(consumption.eventType) && !isPlanned && !isModuleEvent) {\n\t\t\t\tthrow new Error(`View \"${key}\" consumes unknown event type \"${consumption.eventType}\".`);\n\t\t\t}\n\t\t\tif (consumption.schemaVersions.length === 0 || consumption.schemaVersions.some((version) => !Number.isInteger(version) || version < 1)) {\n\t\t\t\tthrow new Error(`View \"${key}\" must declare positive consumed schema versions for \"${consumption.eventType}\".`);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction sortModulesByDependency(\n\tmodules: FabricModule<unknown>[],\n\tregisteredNamespaces = registeredModuleNamespaces,\n): FabricModule<unknown>[] {\n\tconst modulesByNamespace = new Map<string, FabricModule<unknown>>();\n\n\tfor (const module of modules) {\n\t\tvalidateModuleNamespace(module.namespace);\n\t\tif (modulesByNamespace.has(module.namespace)) {\n\t\t\tthrow new Error(`Duplicate Fabric module namespace \"${module.namespace}\".`);\n\t\t}\n\t\tmodulesByNamespace.set(module.namespace, module);\n\t}\n\n\tconst sorted: FabricModule<unknown>[] = [];\n\tconst visiting = new Set<string>();\n\tconst visited = new Set<string>();\n\n\tfunction visit(module: FabricModule<unknown>, path: string[]): void {\n\t\tif (visited.has(module.namespace)) {\n\t\t\treturn;\n\t\t}\n\t\tif (visiting.has(module.namespace)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cyclic Fabric module dependency detected: ${[...path, module.namespace].join(\" -> \")}`,\n\t\t\t);\n\t\t}\n\n\t\tvisiting.add(module.namespace);\n\t\tfor (const dependency of (module.dependencies ?? []).map(getModuleDependencyNamespace)) {\n\t\t\tconst dependencyModule = modulesByNamespace.get(dependency);\n\t\t\tif (!dependencyModule) {\n\t\t\t\tif (registeredNamespaces.has(dependency)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow new Error(`Module \"${module.namespace}\" depends on missing module \"${dependency}\".`);\n\t\t\t}\n\t\t\tvisit(dependencyModule, [...path, module.namespace]);\n\t\t}\n\t\tvisiting.delete(module.namespace);\n\t\tvisited.add(module.namespace);\n\t\tsorted.push(module);\n\t}\n\n\tfor (const module of modules) {\n\t\tvisit(module, []);\n\t}\n\n\treturn sorted;\n}\n\nfunction assertAcyclicRelations(modules: FabricModule<unknown>[]): void {\n\tconst relationKinds = [\n\t\t{ label: \"owned containment\", include: (relation: ObjectRelationDefinition) => relation.semantics === \"owned\" },\n\t\t{ label: \"cascade-delete\", include: (relation: ObjectRelationDefinition) => relation.onTargetDelete === \"cascade\" },\n\t\t{ label: \"required-construction\", include: (relation: ObjectRelationDefinition) => relation.required === true },\n\t];\n\tfor (const kind of relationKinds) {\n\t\tconst edges = new Map<string, string[]>();\n\t\tfor (const [source, objectType] of registeredObjectDefinitions) {\n\t\t\tedges.set(source, (objectType.relations ?? []).filter(kind.include).map((relation) => relation.target));\n\t\t}\n\t\tfor (const module of modules) {\n\t\t\tfor (const objectType of module.objectTypes ?? []) {\n\t\t\t\tif (typeof objectType === \"string\") continue;\n\t\t\t\tconst source = qualifiedObjectType(module.namespace, objectType.type);\n\t\t\t\tedges.set(source, (objectType.relations ?? []).filter(kind.include).map((relation) => relation.target));\n\t\t\t}\n\t\t}\n\t\tconst visiting = new Set<string>();\n\t\tconst visited = new Set<string>();\n\t\tconst visit = (node: string, path: string[]): void => {\n\t\t\tif (visiting.has(node)) {\n\t\t\t\tthrow new Error(`${kind.label} relation cycle detected: ${[...path, node].join(\" -> \")}`);\n\t\t\t}\n\t\t\tif (visited.has(node)) return;\n\t\t\tvisiting.add(node);\n\t\t\tfor (const target of edges.get(node) ?? []) visit(target, [...path, node]);\n\t\t\tvisiting.delete(node);\n\t\t\tvisited.add(node);\n\t\t};\n\t\tfor (const node of edges.keys()) visit(node, []);\n\t}\n}\n\nfunction registerValidatedFabricModule(module: FabricModule<unknown>): void {\n\tfor (const objectType of module.objectTypes ?? []) {\n\t\tregisterObjectType(getObjectTypeName(objectType));\n\t\tconst qualified = qualifiedObjectType(module.namespace, getObjectTypeName(objectType));\n\t\tregisteredQualifiedObjectTypes.add(qualified);\n\t\tif (typeof objectType !== \"string\") registeredObjectDefinitions.set(qualified, objectType);\n\t}\n\n\tfor (const subjectType of module.subjectTypes ?? []) {\n\t\tregisterSubjectType(subjectType);\n\t}\n\n\tfor (const eventType of module.eventTypes ?? []) {\n\t\tregisterEventType(getEventTypeName(eventType));\n\t}\n\n\tfor (const policy of module.policies ?? []) {\n\t\tregisterPolicyIfMissing(policy as PolicyEvaluator);\n\t}\n\n\tfor (const machine of module.stateMachines ?? []) {\n\t\tregisterStateMachineIfMissing(machine as StateMachineDefinition);\n\t}\n\n\tfor (const action of module.actions ?? []) {\n\t\tregisterActionIfMissing(action);\n\t}\n\n\tfor (const descriptor of module.displayRenderers ?? []) {\n\t\tregisterDisplayRenderer(descriptor.eventType, descriptor.renderer as DisplayRenderer);\n\t}\n\tfor (const view of module.views ?? []) registerViewContractIfMissing(view);\n\n\tregisteredModuleNamespaces.add(module.namespace);\n}\n\nexport function registerFabricModule(module: FabricModule<unknown>): void {\n\tconst availableObjectTypes = new Set([\n\t\t...registeredQualifiedObjectTypes,\n\t\t...(module.objectTypes ?? []).map((objectType) => qualifiedObjectType(module.namespace, getObjectTypeName(objectType))),\n\t]);\n\tvalidateManifest(module, { availableNamespaces: registeredModuleNamespaces, availableObjectTypes });\n\tassertAcyclicRelations([module]);\n\tregisterValidatedFabricModule(module);\n}\n\nexport function registerFabricModules(modules: FabricModule<unknown>[]): FabricModule<unknown>[] {\n\tconst availableNamespaces = new Set([\n\t\t...registeredModuleNamespaces,\n\t\t...modules.map((module) => module.namespace),\n\t]);\n\tconst plannedEventTypes = new Set(\n\t\tmodules.flatMap((module) => (module.eventTypes ?? []).map(getEventTypeName)),\n\t);\n\tconst availableObjectTypes = new Set([\n\t\t...registeredQualifiedObjectTypes,\n\t\t...modules.flatMap((module) =>\n\t\t\t(module.objectTypes ?? []).map((objectType) => qualifiedObjectType(module.namespace, getObjectTypeName(objectType))),\n\t\t),\n\t]);\n\n\tfor (const module of modules) {\n\t\tvalidateManifest(module, { availableNamespaces, plannedEventTypes, availableObjectTypes });\n\t}\n\tassertAcyclicRelations(modules);\n\n\tconst sortedModules = sortModulesByDependency(modules);\n\tfor (const module of sortedModules) {\n\t\tregisterValidatedFabricModule(module);\n\t}\n\n\treturn sortedModules;\n}\n"]}