@fabricorg/platform 0.9.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.
- package/CHANGELOG.md +48 -2
- package/README.md +21 -0
- package/dist/actions/index.cjs +11 -11
- package/dist/actions/index.d.cts +2 -0
- package/dist/actions/index.d.ts +2 -0
- package/dist/actions/index.js +1 -1
- package/dist/chunk-3JQI3OFC.js +347 -0
- package/dist/chunk-3JQI3OFC.js.map +1 -0
- package/dist/chunk-3S6UTP4X.js +110 -0
- package/dist/chunk-3S6UTP4X.js.map +1 -0
- package/dist/{chunk-JSTGOT6P.js → chunk-7WASIL46.js} +58 -3
- package/dist/chunk-7WASIL46.js.map +1 -0
- package/dist/{chunk-BWNPGRRV.cjs → chunk-HLRIXNVG.cjs} +2 -2
- package/dist/chunk-HLRIXNVG.cjs.map +1 -0
- package/dist/{chunk-4SMPJPJ6.js → chunk-JM55UQWK.js} +2 -2
- package/dist/chunk-JM55UQWK.js.map +1 -0
- package/dist/chunk-NFP5DJBT.js +219 -0
- package/dist/chunk-NFP5DJBT.js.map +1 -0
- package/dist/{chunk-Q3WYIWCN.cjs → chunk-O7IHZ53Y.cjs} +63 -2
- package/dist/chunk-O7IHZ53Y.cjs.map +1 -0
- package/dist/chunk-ODP3DO6P.cjs +355 -0
- package/dist/chunk-ODP3DO6P.cjs.map +1 -0
- package/dist/chunk-RYCHDNHZ.cjs +226 -0
- package/dist/chunk-RYCHDNHZ.cjs.map +1 -0
- package/dist/chunk-XCL2HBMB.cjs +116 -0
- package/dist/chunk-XCL2HBMB.cjs.map +1 -0
- package/dist/index.cjs +92 -39
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +6 -5
- package/dist/manifest/index.cjs +40 -0
- package/dist/manifest/index.cjs.map +1 -0
- package/dist/manifest/index.d.cts +181 -0
- package/dist/manifest/index.d.ts +181 -0
- package/dist/manifest/index.js +11 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/modules/index.cjs +11 -10
- package/dist/modules/index.d.cts +49 -1
- package/dist/modules/index.d.ts +49 -1
- package/dist/modules/index.js +4 -3
- package/dist/objects/index.cjs +9 -5
- package/dist/objects/index.d.cts +45 -1
- package/dist/objects/index.d.ts +45 -1
- package/dist/objects/index.js +1 -1
- package/dist/projections/index.cjs +26 -2
- package/dist/projections/index.d.cts +38 -2
- package/dist/projections/index.d.ts +38 -2
- package/dist/projections/index.js +1 -1
- package/package.json +11 -1
- package/dist/chunk-35DD3H55.js +0 -187
- package/dist/chunk-35DD3H55.js.map +0 -1
- package/dist/chunk-4SMPJPJ6.js.map +0 -1
- package/dist/chunk-BWNPGRRV.cjs.map +0 -1
- package/dist/chunk-I35B576X.js +0 -30
- package/dist/chunk-I35B576X.js.map +0 -1
- package/dist/chunk-JSTGOT6P.js.map +0 -1
- package/dist/chunk-Q3WYIWCN.cjs.map +0 -1
- package/dist/chunk-QETQGAXJ.cjs +0 -35
- package/dist/chunk-QETQGAXJ.cjs.map +0 -1
- package/dist/chunk-SSYKDXR4.cjs +0 -195
- package/dist/chunk-SSYKDXR4.cjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
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
|
+
|
|
18
|
+
## 0.10.0
|
|
19
|
+
|
|
20
|
+
### Minor Changes
|
|
21
|
+
|
|
22
|
+
- fdd3e69: Add provider-neutral external mutation footprints, delegated principals, enforceable obligations,
|
|
23
|
+
execution attestations, and reconciliation evidence with durable host-store support.
|
|
24
|
+
- 714ad06: Add enforceable Fabric-family compatibility controls and durable runtime contract-version evidence.
|
|
25
|
+
- 43c5770: Initial pre-1.0 Fabric platform package with action, adapter, event, ID, and module contracts.
|
|
26
|
+
- 986636b: New public subpath `@fabricorg/platform/manifest`: a stable, JSON-serializable, versioned manifest of a `FabricModule`'s ontology (object types, subject types, id prefixes, event types, actions, policies, state machines) for downstream tooling such as semantics exporters, docs generators, and tool generators.
|
|
27
|
+
|
|
28
|
+
- `MODULE_MANIFEST_VERSION` (`1`), `ModuleManifest`, and `ModuleManifestBundle` contract types.
|
|
29
|
+
- `exportModuleManifest(module)` — pure, registry-free export of a single module; no registration required.
|
|
30
|
+
- `exportModuleManifestBundle(modules)` — versioned bundle preserving input order.
|
|
31
|
+
- `JsonSchemaExportableValidator` + `isJsonSchemaExportableValidator` — actions whose schema exposes `toJSONSchema()` (e.g. Zod 4) emit `parameterSchema` / `parameterSchemaFormat: "json-schema"`.
|
|
32
|
+
- Function fields are never serialized (`handler`, `evaluate`, `guard` → `hasGuard`, dynamic `targetState`, adapter `getInput`); the manifest contains definitions only — never raw parameter values, secrets, or runtime data.
|
|
33
|
+
- Deterministic: declaration order is preserved everywhere, so the same module object always produces byte-identical JSON.
|
|
34
|
+
|
|
35
|
+
All changes are additive; no breaking API changes.
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- bc7d3ab: BYO policy engine affordance + preview-safe enforcement bug fix.
|
|
40
|
+
|
|
41
|
+
- `PolicyContext.services?: FabricRuntimeServices` (mirrors `ActionContext.services`).
|
|
42
|
+
- `PolicyDispatchEvidence.engine?: { name; version?; metadata? }` for external-engine provenance (OPA, Cedar, Cerbos, …). `normalizeOutcome` preserves evaluator-supplied `engine` blocks.
|
|
43
|
+
- `PolicyDispatchEvidence.code.skipped` / `code.skipReason` for first-class preview-skip evidence.
|
|
44
|
+
- `evaluateCodePolicy` now honors `PolicyEvaluator.previewSafe`: in `preview` mode, non-preview-safe evaluators are skipped and yield `result: "warn"` with structured evidence. Data policies still evaluate; hybrid fallback inherits the skip.
|
|
45
|
+
- New docs: `governance/byo-engine` (worked OPA example, layering, failure modes, preview semantics).
|
|
46
|
+
|
|
47
|
+
All changes are additive; no breaking API changes.
|
|
48
|
+
|
|
3
49
|
## 0.9.0
|
|
4
50
|
|
|
5
51
|
- Add versioned runtime-governance evidence shared by TypeScript and .NET hosts.
|
|
@@ -46,7 +92,7 @@
|
|
|
46
92
|
|
|
47
93
|
- **BYO policy engine affordance.** Made it possible for code policy evaluators to delegate to external policy engines (OPA, Cedar, Cerbos, …) while keeping Fabric's `policyId.vN` and `policyVersion` canonical for audit. Three additive, vendor-neutral changes to the policy contract:
|
|
48
94
|
- `PolicyContext.services?: FabricRuntimeServices` — mirrors `ActionContext.services`. Lets the runtime host inject HTTP clients, external policy engine clients, feature flags, etc. into policy evaluation without module-level globals.
|
|
49
|
-
- `PolicyDispatchEvidence.engine?: { name; version?; metadata? }` — open-ended engine provenance slot. Adapters populate it (e.g. OPA: `decisionPath`, `bundleRevision`, `decisionId`, `inputHash`). Platform `policyId` / `policyVersion` remain load-bearing; `engine` answers "
|
|
95
|
+
- `PolicyDispatchEvidence.engine?: { name; version?; metadata? }` — open-ended engine provenance slot. Adapters populate it (e.g. OPA: `decisionPath`, `bundleRevision`, `decisionId`, `inputHash`). Platform `policyId` / `policyVersion` remain load-bearing; `engine` answers "_which artifact_ produced the decision?". `normalizeOutcome` merges evaluator-supplied `engine` provenance into the platform-controlled dispatch envelope so adapters can attach it without being overwritten.
|
|
50
96
|
- `PolicyDispatchEvidence.code.skipped` / `code.skipReason` — first-class evidence shape for preview skips.
|
|
51
97
|
- **Preview-safe enforcement (bug fix).** `PolicyEvaluator.previewSafe` was previously documentation-only; `evaluateCodePolicy` ran every evaluator regardless of `ctx.mode`. Now: when `ctx.mode === "preview"` and an evaluator is not declared `previewSafe: true`, the platform skips evaluation and returns `result: "warn"` with structured skip evidence (`code.skipped`, `code.skipReason`, `metadata.previewSkipped`). `warn` is the honest preview outcome: not proven pass, not proven block. Data policies are deterministic and continue to evaluate in preview unchanged. Hybrid policies inherit the skip behavior on their fallback code evaluator automatically.
|
|
52
98
|
- **Docs:** new `governance/byo-engine` page — worked OPA example covering the four-piece pattern (vertical policy manifest, fact builder owned by TS, Rego house style returning structured decision shape, evaluator factory), failure-mode policy table, preview semantics, and the platform/adapter/vertical layering. `governance/policy-model` updated to reflect `services` and the `engine` evidence block.
|
|
@@ -68,7 +114,7 @@
|
|
|
68
114
|
- New optional method on `SagaContext`: `awaitSignal?<T>(signalName: string, timeoutMs: number) => Promise<T | null>`.
|
|
69
115
|
- Returns the payload of the first signal received, or `null` if the timeout fires.
|
|
70
116
|
- Optional: runtimes that cannot support push-based signaling (in-memory test harnesses, simple polling drivers) may omit it. Sagas should treat absence as a fallback condition and use `sleep` + `query` polling instead.
|
|
71
|
-
- Signal
|
|
117
|
+
- Signal _senders_ remain runtime-specific (e.g. Temporal `WorkflowClient.signal()` from an action handler activity, or an HTTP-based coordination service if an app exposes one). The platform does not prescribe the sender API to keep the runtime layer agnostic.
|
|
72
118
|
- **Use case:** any saga that previously polled for an external event (a user response, an upload landing, an upstream system completing) can now exit the polling loop and resume immediately when the event fires.
|
|
73
119
|
- **Tests:** 77 → 81 (added 4 tests covering the optional shape, push-vs-poll fallback pattern, and runtime mock implementations).
|
|
74
120
|
- **No breaking changes.** `SagaContext.awaitSignal` is optional; existing sagas and runtimes continue to work unchanged.
|
package/README.md
CHANGED
|
@@ -49,6 +49,7 @@ That's what this package gives you. Nothing more.
|
|
|
49
49
|
| `@fabricorg/platform/projections` | Replay/snapshot framework |
|
|
50
50
|
| `@fabricorg/platform/adapters` | `AdapterRegistry`, retry + circuit-breaker |
|
|
51
51
|
| `@fabricorg/platform/modules` | `FabricModule<TDb>`, `registerFabricModules` |
|
|
52
|
+
| `@fabricorg/platform/manifest` | `exportModuleManifest`, `exportModuleManifestBundle`, `ModuleManifest` |
|
|
52
53
|
| `@fabricorg/platform/ids` | `createFabricId`, `FABRIC_ID_PREFIXES` |
|
|
53
54
|
| `@fabricorg/platform/displays` | `DisplayRendererRegistration` |
|
|
54
55
|
| `@fabricorg/platform/privacy` | Redaction + data classification |
|
|
@@ -57,6 +58,11 @@ That's what this package gives you. Nothing more.
|
|
|
57
58
|
| `@fabricorg/platform/objects` | Shared object-type contracts |
|
|
58
59
|
| `@fabricorg/platform/testing` | In-memory adapter registry, fake `ActionContext`, deterministic IDs |
|
|
59
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
|
+
|
|
60
66
|
## Composing a vertical
|
|
61
67
|
|
|
62
68
|
Verticals declare a `FabricModule<TDb>` that registers their actions, policies, state machines, events, and adapters with the platform:
|
|
@@ -81,6 +87,21 @@ registerFabricModules([myModule]);
|
|
|
81
87
|
|
|
82
88
|
The platform never auto-loads a module. The host app composes them explicitly — no implicit defaults, no globals, no surprises.
|
|
83
89
|
|
|
90
|
+
## Exporting a module manifest
|
|
91
|
+
|
|
92
|
+
Downstream tooling — semantics exporters, docs generators, tool generators — often needs a module's ontology as data rather than live code. `@fabricorg/platform/manifest` exports a stable, JSON-serializable, versioned description of any `FabricModule`:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { exportModuleManifest } from "@fabricorg/platform/manifest";
|
|
96
|
+
|
|
97
|
+
const manifest = exportModuleManifest(myModule);
|
|
98
|
+
const json = JSON.stringify(manifest, null, 2);
|
|
99
|
+
```
|
|
100
|
+
|
|
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.
|
|
104
|
+
|
|
84
105
|
## The action lifecycle
|
|
85
106
|
|
|
86
107
|
Every `invokeAction(id, params)` call goes through:
|
package/dist/actions/index.cjs
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
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
|
|
9
|
+
get: function () { return chunkHLRIXNVG_cjs.ACTOR_TYPES; }
|
|
10
10
|
});
|
|
11
11
|
Object.defineProperty(exports, "assertActionId", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkHLRIXNVG_cjs.assertActionId; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "assertActorType", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkHLRIXNVG_cjs.assertActorType; }
|
|
18
18
|
});
|
|
19
19
|
Object.defineProperty(exports, "getRegisteredActionIds", {
|
|
20
20
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
21
|
+
get: function () { return chunkHLRIXNVG_cjs.getRegisteredActionIds; }
|
|
22
22
|
});
|
|
23
23
|
Object.defineProperty(exports, "isActorType", {
|
|
24
24
|
enumerable: true,
|
|
25
|
-
get: function () { return
|
|
25
|
+
get: function () { return chunkHLRIXNVG_cjs.isActorType; }
|
|
26
26
|
});
|
|
27
27
|
Object.defineProperty(exports, "isRegisteredActionId", {
|
|
28
28
|
enumerable: true,
|
|
29
|
-
get: function () { return
|
|
29
|
+
get: function () { return chunkHLRIXNVG_cjs.isRegisteredActionId; }
|
|
30
30
|
});
|
|
31
31
|
Object.defineProperty(exports, "registerAction", {
|
|
32
32
|
enumerable: true,
|
|
33
|
-
get: function () { return
|
|
33
|
+
get: function () { return chunkHLRIXNVG_cjs.registerAction; }
|
|
34
34
|
});
|
|
35
35
|
Object.defineProperty(exports, "registerActionIfMissing", {
|
|
36
36
|
enumerable: true,
|
|
37
|
-
get: function () { return
|
|
37
|
+
get: function () { return chunkHLRIXNVG_cjs.registerActionIfMissing; }
|
|
38
38
|
});
|
|
39
39
|
Object.defineProperty(exports, "resolveAction", {
|
|
40
40
|
enumerable: true,
|
|
41
|
-
get: function () { return
|
|
41
|
+
get: function () { return chunkHLRIXNVG_cjs.resolveAction; }
|
|
42
42
|
});
|
|
43
43
|
Object.defineProperty(exports, "resolveRegisteredAction", {
|
|
44
44
|
enumerable: true,
|
|
45
|
-
get: function () { return
|
|
45
|
+
get: function () { return chunkHLRIXNVG_cjs.resolveRegisteredAction; }
|
|
46
46
|
});
|
|
47
47
|
//# sourceMappingURL=index.cjs.map
|
|
48
48
|
//# sourceMappingURL=index.cjs.map
|
package/dist/actions/index.d.cts
CHANGED
|
@@ -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[];
|
package/dist/actions/index.d.ts
CHANGED
|
@@ -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[];
|
package/dist/actions/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { ACTOR_TYPES, assertActionId, assertActorType, getRegisteredActionIds, isActorType, isRegisteredActionId, registerAction, registerActionIfMissing, resolveAction, resolveRegisteredAction } from '../chunk-
|
|
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"]}
|