@fabricorg/gen-capability 0.3.0 → 0.4.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 CHANGED
@@ -1,5 +1,40 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c504d0a: Make generated artifacts carry their own weight instead of handing back a seam.
8
+
9
+ `gen-graphql` projects each view's JSON Schema into named GraphQL types rather than an opaque
10
+ `JSON` scalar, declares the Federation 2 `@link` directive, and emits `createResolvers()` — an
11
+ executable resolver map whose Query fields read through `ProjectionHost` and whose Mutation fields
12
+ submit through `submitAction()`. Shapes with no GraphQL projection (`oneOf`, `anyOf`, `allOf`, tuple
13
+ `items`, multi-type unions, non-local `$ref`) now fail the generator instead of silently degrading
14
+ to `JSON`; only a schema that genuinely admits any value projects as `JSON`. Recursive `#/$defs`
15
+ references resolve to a single named type.
16
+
17
+ `gen-conformance` emits a runnable suite alongside the plan. The ten Phase 1 checks split into eight
18
+ `MODULE_CONFORMANCE_CHECKS` a module verifies against a governed host and two
19
+ `PLATFORM_CONFORMANCE_CHECKS` a repository owns. A check a module cannot exercise reports
20
+ `not-applicable` with a reason rather than passing silently, and `@fabricorg/gen-conformance/memory`
21
+ ships a reference harness so a suite runs with no infrastructure.
22
+
23
+ `gen-capability` emits a usage contract with its own `formatVersion`, validated by
24
+ `assertUsageContract` and described by `USAGE_CONTRACT_JSON_SCHEMA`.
25
+
26
+ ### Patch Changes
27
+
28
+ - Updated dependencies [c504d0a]
29
+ - @fabricorg/compiler@2.1.0
30
+
31
+ ## 0.3.1
32
+
33
+ ### Patch Changes
34
+
35
+ - Updated dependencies
36
+ - @fabricorg/compiler@2.0.0
37
+
3
38
  ## 0.3.0
4
39
 
5
40
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -20,15 +20,201 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ USAGE_CONTRACT_FORMAT_VERSION: () => USAGE_CONTRACT_FORMAT_VERSION,
24
+ USAGE_CONTRACT_JSON_SCHEMA: () => USAGE_CONTRACT_JSON_SCHEMA,
25
+ assertUsageContract: () => assertUsageContract,
26
+ assertUsageContractDocument: () => assertUsageContractDocument,
27
+ buildUsageContract: () => buildUsageContract,
23
28
  capabilityGenerator: () => capabilityGenerator
24
29
  });
25
30
  module.exports = __toCommonJS(index_exports);
26
31
  var import_compiler = require("@fabricorg/compiler");
27
- var capabilityGenerator = { name: "@fabricorg/gen-capability", version: "0.3.0", generate(ir) {
28
- return ir.modules.filter((module2) => module2.capability).map((module2) => ({ path: `${module2.namespace}/capability.json`, content: (0, import_compiler.stableStringify)({ generator: { name: capabilityGenerator.name, version: capabilityGenerator.version }, manifestDigest: ir.manifestDigest, capability: { namespace: module2.namespace, version: module2.version, ...module2.capability, actions: module2.actions.map(({ actionId, version, parameterSchema, resultSchema, requiredRoles, requiredPermissions, execution }) => ({ actionId, version, parameterSchema, resultSchema, requiredRoles, requiredPermissions, execution })), views: module2.views, events: module2.eventTypes } }) }));
29
- } };
32
+ var USAGE_CONTRACT_FORMAT_VERSION = 1;
33
+ var STABILITIES = ["experimental", "beta", "stable", "deprecated"];
34
+ function fail(path, message) {
35
+ throw new Error(`Usage contract ${path} ${message}.`);
36
+ }
37
+ function requireString(value, path) {
38
+ if (typeof value !== "string" || !value.trim()) fail(path, "must be a non-empty string");
39
+ return value;
40
+ }
41
+ function requireArray(value, path) {
42
+ if (!Array.isArray(value)) fail(path, "must be an array");
43
+ return value;
44
+ }
45
+ function assertUsageContract(value, path = "capability") {
46
+ if (!value || typeof value !== "object" || Array.isArray(value)) fail(path, "must be an object");
47
+ const contract = value;
48
+ if (contract.formatVersion !== USAGE_CONTRACT_FORMAT_VERSION) {
49
+ fail(`${path}.formatVersion`, `must be ${USAGE_CONTRACT_FORMAT_VERSION}, received ${JSON.stringify(contract.formatVersion)}`);
50
+ }
51
+ if (!/^[a-z][a-z0-9-]*$/.test(requireString(contract.namespace, `${path}.namespace`))) {
52
+ fail(`${path}.namespace`, "must be lowercase letters, numbers and hyphens");
53
+ }
54
+ requireString(contract.displayName, `${path}.displayName`);
55
+ requireString(contract.description, `${path}.description`);
56
+ if (!STABILITIES.includes(contract.stability)) {
57
+ fail(`${path}.stability`, `must be one of ${STABILITIES.join(", ")}`);
58
+ }
59
+ const actionIds = /* @__PURE__ */ new Set();
60
+ requireArray(contract.actions, `${path}.actions`).forEach((entry, index) => {
61
+ const action = entry;
62
+ const actionId = requireString(action?.actionId, `${path}.actions[${index}].actionId`);
63
+ if (actionIds.has(actionId)) fail(`${path}.actions[${index}]`, `repeats actionId "${actionId}"`);
64
+ actionIds.add(actionId);
65
+ if (!Number.isInteger(action.version)) fail(`${path}.actions[${index}].version`, "must be an integer");
66
+ if (action.requiredRoles !== void 0 && !Array.isArray(action.requiredRoles)) fail(`${path}.actions[${index}].requiredRoles`, "must be an array");
67
+ if (action.requiredPermissions !== void 0 && !Array.isArray(action.requiredPermissions)) fail(`${path}.actions[${index}].requiredPermissions`, "must be an array");
68
+ });
69
+ const viewKeys = /* @__PURE__ */ new Set();
70
+ requireArray(contract.views, `${path}.views`).forEach((entry, index) => {
71
+ const view = entry;
72
+ const name = requireString(view?.name, `${path}.views[${index}].name`);
73
+ const version = requireString(view?.version, `${path}.views[${index}].version`);
74
+ const key = `${name}@${version}`;
75
+ if (viewKeys.has(key)) fail(`${path}.views[${index}]`, `repeats view "${key}"`);
76
+ viewKeys.add(key);
77
+ if (!view.shape || typeof view.shape !== "object" || Array.isArray(view.shape)) fail(`${path}.views[${index}].shape`, "must be a JSON Schema object");
78
+ if (view.scope !== "tenant-space") fail(`${path}.views[${index}].scope`, 'must be "tenant-space"');
79
+ if (!Number.isInteger(view.snapshotVersion) || view.snapshotVersion < 1) fail(`${path}.views[${index}].snapshotVersion`, "must be a positive integer");
80
+ });
81
+ requireArray(contract.events, `${path}.events`).forEach((entry, index) => {
82
+ const event = entry;
83
+ requireString(event?.eventType, `${path}.events[${index}].eventType`);
84
+ if (!Number.isInteger(event.schemaVersion)) fail(`${path}.events[${index}].schemaVersion`, "must be an integer");
85
+ });
86
+ if (contract.extensions !== void 0) {
87
+ if (!contract.extensions || typeof contract.extensions !== "object" || Array.isArray(contract.extensions)) fail(`${path}.extensions`, "must be an object");
88
+ for (const namespace of Object.keys(contract.extensions)) {
89
+ if (!/^[a-z][a-z0-9.-]*\.[a-z0-9.-]+\/v[1-9][0-9]*$/.test(namespace)) {
90
+ fail(`${path}.extensions`, `has invalid extension namespace "${namespace}"`);
91
+ }
92
+ }
93
+ }
94
+ }
95
+ function assertUsageContractDocument(value) {
96
+ if (!value || typeof value !== "object" || Array.isArray(value)) fail("document", "must be an object");
97
+ const document = value;
98
+ if (!/^[0-9a-f]{64}$/.test(String(document.manifestDigest))) fail("document.manifestDigest", "must be a lowercase SHA-256 digest");
99
+ const generator = document.generator;
100
+ if (!generator || typeof generator !== "object" || Array.isArray(generator)) fail("document.generator", "must be an object");
101
+ requireString(generator.name, "document.generator.name");
102
+ requireString(generator.version, "document.generator.version");
103
+ assertUsageContract(document.capability);
104
+ }
105
+ var USAGE_CONTRACT_JSON_SCHEMA = {
106
+ $schema: "https://json-schema.org/draft/2020-12/schema",
107
+ title: "Fabric capability usage contract",
108
+ type: "object",
109
+ required: ["formatVersion", "namespace", "displayName", "description", "stability", "actions", "views", "events"],
110
+ properties: {
111
+ formatVersion: { type: "integer", enum: [USAGE_CONTRACT_FORMAT_VERSION] },
112
+ namespace: { type: "string", pattern: "^[a-z][a-z0-9-]*$" },
113
+ version: { type: "string" },
114
+ displayName: { type: "string", minLength: 1 },
115
+ description: { type: "string", minLength: 1 },
116
+ stability: { type: "string", enum: [...STABILITIES] },
117
+ deprecated: { type: "object" },
118
+ requirements: { type: "object" },
119
+ certification: { type: "object" },
120
+ extensions: { type: "object" },
121
+ actions: {
122
+ type: "array",
123
+ items: {
124
+ type: "object",
125
+ required: ["actionId", "version"],
126
+ properties: {
127
+ actionId: { type: "string" },
128
+ version: { type: "integer" },
129
+ parameterSchema: { type: "object" },
130
+ resultSchema: { type: "object" },
131
+ requiredRoles: { type: "array", items: { type: "string" } },
132
+ requiredPermissions: { type: "array", items: { type: "string" } },
133
+ execution: { type: "object" }
134
+ }
135
+ }
136
+ },
137
+ views: {
138
+ type: "array",
139
+ items: {
140
+ type: "object",
141
+ required: ["name", "version", "shape", "scope", "snapshotVersion"],
142
+ properties: {
143
+ name: { type: "string" },
144
+ version: { type: "string" },
145
+ shape: { type: "object" },
146
+ scope: { type: "string", enum: ["tenant-space"] },
147
+ snapshotVersion: { type: "integer" },
148
+ usage: { type: "object" }
149
+ }
150
+ }
151
+ },
152
+ events: {
153
+ type: "array",
154
+ items: {
155
+ type: "object",
156
+ required: ["eventType", "schemaVersion"],
157
+ properties: {
158
+ eventType: { type: "string" },
159
+ schemaVersion: { type: "integer" },
160
+ description: { type: "string" },
161
+ schema: { type: "object" }
162
+ }
163
+ }
164
+ }
165
+ }
166
+ };
167
+ function buildUsageContract(module2) {
168
+ const capability = module2.capability;
169
+ if (!capability) return void 0;
170
+ return {
171
+ formatVersion: USAGE_CONTRACT_FORMAT_VERSION,
172
+ namespace: module2.namespace,
173
+ ...module2.version === void 0 ? {} : { version: module2.version },
174
+ displayName: capability.displayName,
175
+ description: capability.description,
176
+ stability: capability.stability,
177
+ ...capability.deprecated === void 0 ? {} : { deprecated: capability.deprecated },
178
+ ...capability.requirements === void 0 ? {} : { requirements: capability.requirements },
179
+ ...capability.certification === void 0 ? {} : { certification: capability.certification },
180
+ ...capability.extensions === void 0 ? {} : { extensions: capability.extensions },
181
+ actions: module2.actions.map(({ actionId, version, parameterSchema, resultSchema, requiredRoles, requiredPermissions, execution }) => ({
182
+ actionId,
183
+ version,
184
+ parameterSchema,
185
+ resultSchema,
186
+ requiredRoles,
187
+ requiredPermissions,
188
+ execution
189
+ })),
190
+ views: module2.views.map(({ name, version, shape, scope, snapshotVersion, usage }) => ({ name, version, shape, scope, snapshotVersion, usage })),
191
+ events: module2.eventTypes.map(({ eventType, schemaVersion, description, schema }) => ({ eventType, schemaVersion, description, schema }))
192
+ };
193
+ }
194
+ var capabilityGenerator = {
195
+ name: "@fabricorg/gen-capability",
196
+ version: "0.4.0",
197
+ generate(ir) {
198
+ return ir.modules.flatMap((module2) => {
199
+ const capability = buildUsageContract(module2);
200
+ if (!capability) return [];
201
+ assertUsageContract(capability);
202
+ const document = {
203
+ generator: { name: capabilityGenerator.name, version: capabilityGenerator.version },
204
+ manifestDigest: ir.manifestDigest,
205
+ capability
206
+ };
207
+ return [{ path: `${module2.namespace}/capability.json`, content: (0, import_compiler.stableStringify)(document) }];
208
+ });
209
+ }
210
+ };
30
211
  // Annotate the CommonJS export names for ESM import in node:
31
212
  0 && (module.exports = {
213
+ USAGE_CONTRACT_FORMAT_VERSION,
214
+ USAGE_CONTRACT_JSON_SCHEMA,
215
+ assertUsageContract,
216
+ assertUsageContractDocument,
217
+ buildUsageContract,
32
218
  capabilityGenerator
33
219
  });
34
220
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../index.ts"],"sourcesContent":["import { stableStringify, type GeneratorTarget } from \"@fabricorg/compiler\";\nexport const capabilityGenerator: GeneratorTarget = { name:\"@fabricorg/gen-capability\", version:\"0.3.0\", generate(ir) { return ir.modules.filter((module) => module.capability).map((module) => ({ path:`${module.namespace}/capability.json`, content:stableStringify({ generator:{name:capabilityGenerator.name,version:capabilityGenerator.version},manifestDigest:ir.manifestDigest,capability:{namespace:module.namespace,version:module.version,...module.capability,actions:module.actions.map(({actionId,version,parameterSchema,resultSchema,requiredRoles,requiredPermissions,execution})=>({actionId,version,parameterSchema,resultSchema,requiredRoles,requiredPermissions,execution})),views:module.views,events:module.eventTypes}}) })); } };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAsD;AAC/C,IAAM,sBAAuC,EAAE,MAAK,6BAA6B,SAAQ,SAAS,SAAS,IAAI;AAAE,SAAO,GAAG,QAAQ,OAAO,CAACA,YAAWA,QAAO,UAAU,EAAE,IAAI,CAACA,aAAY,EAAE,MAAK,GAAGA,QAAO,SAAS,oBAAoB,aAAQ,iCAAgB,EAAE,WAAU,EAAC,MAAK,oBAAoB,MAAK,SAAQ,oBAAoB,QAAO,GAAE,gBAAe,GAAG,gBAAe,YAAW,EAAC,WAAUA,QAAO,WAAU,SAAQA,QAAO,SAAQ,GAAGA,QAAO,YAAW,SAAQA,QAAO,QAAQ,IAAI,CAAC,EAAC,UAAS,SAAQ,iBAAgB,cAAa,eAAc,qBAAoB,UAAS,OAAK,EAAC,UAAS,SAAQ,iBAAgB,cAAa,eAAc,qBAAoB,UAAS,EAAE,GAAE,OAAMA,QAAO,OAAM,QAAOA,QAAO,WAAU,EAAC,CAAC,EAAE,EAAE;AAAG,EAAE;","names":["module"]}
1
+ {"version":3,"sources":["../index.ts"],"sourcesContent":["import { stableStringify, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport type {\n\tActionExecutionContract,\n\tCapabilityMetadata,\n\tJsonValue,\n\tModuleManifest,\n\tPortableJsonSchema,\n} from \"@fabricorg/platform\";\n\n/**\n * Version of the usage contract document. Adopters negotiate on this, not on the\n * generator's package version, and bump it only when the serialized shape changes\n * in a way a consumer must detect.\n */\nexport const USAGE_CONTRACT_FORMAT_VERSION = 1 as const;\n\nexport interface UsageContractAction {\n\tactionId: string;\n\tversion: number;\n\tparameterSchema?: unknown;\n\tresultSchema?: unknown;\n\trequiredRoles?: string[];\n\trequiredPermissions?: string[];\n\texecution?: ActionExecutionContract;\n}\n\nexport interface UsageContractView {\n\tname: string;\n\tversion: string;\n\tshape: PortableJsonSchema;\n\tscope: \"tenant-space\";\n\tsnapshotVersion: number;\n\tusage?: ModuleManifest[\"views\"][number][\"usage\"];\n}\n\nexport interface UsageContractEvent {\n\teventType: string;\n\tschemaVersion: number;\n\tdescription?: string;\n\tschema?: PortableJsonSchema;\n}\n\n/**\n * What a capability promises its adopters: the governed operations it dispatches,\n * the view payloads it serves, the events it emits, and the namespaced extensions\n * an experience system interprets. Experience semantics stay inside `extensions`,\n * where ADR 0006 put them — this document never interprets them.\n */\nexport interface UsageContract {\n\tformatVersion: typeof USAGE_CONTRACT_FORMAT_VERSION;\n\tnamespace: string;\n\tversion?: string;\n\tdisplayName: string;\n\tdescription: string;\n\tstability: CapabilityMetadata[\"stability\"];\n\tdeprecated?: CapabilityMetadata[\"deprecated\"];\n\trequirements?: CapabilityMetadata[\"requirements\"];\n\tcertification?: CapabilityMetadata[\"certification\"];\n\textensions?: Record<string, JsonValue>;\n\tactions: UsageContractAction[];\n\tviews: UsageContractView[];\n\tevents: UsageContractEvent[];\n}\n\nexport interface UsageContractDocument {\n\tgenerator: { name: string; version: string };\n\tmanifestDigest: string;\n\tcapability: UsageContract;\n}\n\nconst STABILITIES = [\"experimental\", \"beta\", \"stable\", \"deprecated\"];\n\nfunction fail(path: string, message: string): never {\n\tthrow new Error(`Usage contract ${path} ${message}.`);\n}\n\nfunction requireString(value: unknown, path: string): string {\n\tif (typeof value !== \"string\" || !value.trim()) fail(path, \"must be a non-empty string\");\n\treturn value;\n}\n\nfunction requireArray(value: unknown, path: string): unknown[] {\n\tif (!Array.isArray(value)) fail(path, \"must be an array\");\n\treturn value;\n}\n\n/**\n * Structural validation an adopter can run before binding against a contract.\n * It checks the document's own shape; it does not re-validate the manifest it\n * was generated from.\n */\nexport function assertUsageContract(value: unknown, path = \"capability\"): asserts value is UsageContract {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) fail(path, \"must be an object\");\n\tconst contract = value as Record<string, unknown>;\n\tif (contract.formatVersion !== USAGE_CONTRACT_FORMAT_VERSION) {\n\t\tfail(`${path}.formatVersion`, `must be ${USAGE_CONTRACT_FORMAT_VERSION}, received ${JSON.stringify(contract.formatVersion)}`);\n\t}\n\tif (!/^[a-z][a-z0-9-]*$/.test(requireString(contract.namespace, `${path}.namespace`))) {\n\t\tfail(`${path}.namespace`, \"must be lowercase letters, numbers and hyphens\");\n\t}\n\trequireString(contract.displayName, `${path}.displayName`);\n\trequireString(contract.description, `${path}.description`);\n\tif (!STABILITIES.includes(contract.stability as string)) {\n\t\tfail(`${path}.stability`, `must be one of ${STABILITIES.join(\", \")}`);\n\t}\n\tconst actionIds = new Set<string>();\n\trequireArray(contract.actions, `${path}.actions`).forEach((entry, index) => {\n\t\tconst action = entry as Record<string, unknown>;\n\t\tconst actionId = requireString(action?.actionId, `${path}.actions[${index}].actionId`);\n\t\tif (actionIds.has(actionId)) fail(`${path}.actions[${index}]`, `repeats actionId \"${actionId}\"`);\n\t\tactionIds.add(actionId);\n\t\tif (!Number.isInteger(action.version)) fail(`${path}.actions[${index}].version`, \"must be an integer\");\n\t\tif (action.requiredRoles !== undefined && !Array.isArray(action.requiredRoles)) fail(`${path}.actions[${index}].requiredRoles`, \"must be an array\");\n\t\tif (action.requiredPermissions !== undefined && !Array.isArray(action.requiredPermissions)) fail(`${path}.actions[${index}].requiredPermissions`, \"must be an array\");\n\t});\n\tconst viewKeys = new Set<string>();\n\trequireArray(contract.views, `${path}.views`).forEach((entry, index) => {\n\t\tconst view = entry as Record<string, unknown>;\n\t\tconst name = requireString(view?.name, `${path}.views[${index}].name`);\n\t\tconst version = requireString(view?.version, `${path}.views[${index}].version`);\n\t\tconst key = `${name}@${version}`;\n\t\tif (viewKeys.has(key)) fail(`${path}.views[${index}]`, `repeats view \"${key}\"`);\n\t\tviewKeys.add(key);\n\t\tif (!view.shape || typeof view.shape !== \"object\" || Array.isArray(view.shape)) fail(`${path}.views[${index}].shape`, \"must be a JSON Schema object\");\n\t\tif (view.scope !== \"tenant-space\") fail(`${path}.views[${index}].scope`, 'must be \"tenant-space\"');\n\t\tif (!Number.isInteger(view.snapshotVersion) || (view.snapshotVersion as number) < 1) fail(`${path}.views[${index}].snapshotVersion`, \"must be a positive integer\");\n\t});\n\trequireArray(contract.events, `${path}.events`).forEach((entry, index) => {\n\t\tconst event = entry as Record<string, unknown>;\n\t\trequireString(event?.eventType, `${path}.events[${index}].eventType`);\n\t\tif (!Number.isInteger(event.schemaVersion)) fail(`${path}.events[${index}].schemaVersion`, \"must be an integer\");\n\t});\n\tif (contract.extensions !== undefined) {\n\t\tif (!contract.extensions || typeof contract.extensions !== \"object\" || Array.isArray(contract.extensions)) fail(`${path}.extensions`, \"must be an object\");\n\t\tfor (const namespace of Object.keys(contract.extensions as Record<string, unknown>)) {\n\t\t\tif (!/^[a-z][a-z0-9.-]*\\.[a-z0-9.-]+\\/v[1-9][0-9]*$/.test(namespace)) {\n\t\t\t\tfail(`${path}.extensions`, `has invalid extension namespace \"${namespace}\"`);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function assertUsageContractDocument(value: unknown): asserts value is UsageContractDocument {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) fail(\"document\", \"must be an object\");\n\tconst document = value as Record<string, unknown>;\n\tif (!/^[0-9a-f]{64}$/.test(String(document.manifestDigest))) fail(\"document.manifestDigest\", \"must be a lowercase SHA-256 digest\");\n\tconst generator = document.generator as { name?: unknown; version?: unknown } | undefined;\n\tif (!generator || typeof generator !== \"object\" || Array.isArray(generator)) fail(\"document.generator\", \"must be an object\");\n\trequireString(generator.name, \"document.generator.name\");\n\trequireString(generator.version, \"document.generator.version\");\n\tassertUsageContract(document.capability);\n}\n\n/** Machine-readable shape of the usage contract, for adopters that validate with their own tooling. */\nexport const USAGE_CONTRACT_JSON_SCHEMA: PortableJsonSchema = {\n\t$schema: \"https://json-schema.org/draft/2020-12/schema\",\n\ttitle: \"Fabric capability usage contract\",\n\ttype: \"object\",\n\trequired: [\"formatVersion\", \"namespace\", \"displayName\", \"description\", \"stability\", \"actions\", \"views\", \"events\"],\n\tproperties: {\n\t\tformatVersion: { type: \"integer\", enum: [USAGE_CONTRACT_FORMAT_VERSION] },\n\t\tnamespace: { type: \"string\", pattern: \"^[a-z][a-z0-9-]*$\" },\n\t\tversion: { type: \"string\" },\n\t\tdisplayName: { type: \"string\", minLength: 1 },\n\t\tdescription: { type: \"string\", minLength: 1 },\n\t\tstability: { type: \"string\", enum: [...STABILITIES] },\n\t\tdeprecated: { type: \"object\" },\n\t\trequirements: { type: \"object\" },\n\t\tcertification: { type: \"object\" },\n\t\textensions: { type: \"object\" },\n\t\tactions: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\trequired: [\"actionId\", \"version\"],\n\t\t\t\tproperties: {\n\t\t\t\t\tactionId: { type: \"string\" },\n\t\t\t\t\tversion: { type: \"integer\" },\n\t\t\t\t\tparameterSchema: { type: \"object\" },\n\t\t\t\t\tresultSchema: { type: \"object\" },\n\t\t\t\t\trequiredRoles: { type: \"array\", items: { type: \"string\" } },\n\t\t\t\t\trequiredPermissions: { type: \"array\", items: { type: \"string\" } },\n\t\t\t\t\texecution: { type: \"object\" },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tviews: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\trequired: [\"name\", \"version\", \"shape\", \"scope\", \"snapshotVersion\"],\n\t\t\t\tproperties: {\n\t\t\t\t\tname: { type: \"string\" },\n\t\t\t\t\tversion: { type: \"string\" },\n\t\t\t\t\tshape: { type: \"object\" },\n\t\t\t\t\tscope: { type: \"string\", enum: [\"tenant-space\"] },\n\t\t\t\t\tsnapshotVersion: { type: \"integer\" },\n\t\t\t\t\tusage: { type: \"object\" },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tevents: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\trequired: [\"eventType\", \"schemaVersion\"],\n\t\t\t\tproperties: {\n\t\t\t\t\teventType: { type: \"string\" },\n\t\t\t\t\tschemaVersion: { type: \"integer\" },\n\t\t\t\t\tdescription: { type: \"string\" },\n\t\t\t\t\tschema: { type: \"object\" },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n};\n\nexport function buildUsageContract(module: ModuleManifest): UsageContract | undefined {\n\tconst capability = module.capability;\n\tif (!capability) return undefined;\n\treturn {\n\t\tformatVersion: USAGE_CONTRACT_FORMAT_VERSION,\n\t\tnamespace: module.namespace,\n\t\t...(module.version === undefined ? {} : { version: module.version }),\n\t\tdisplayName: capability.displayName,\n\t\tdescription: capability.description,\n\t\tstability: capability.stability,\n\t\t...(capability.deprecated === undefined ? {} : { deprecated: capability.deprecated }),\n\t\t...(capability.requirements === undefined ? {} : { requirements: capability.requirements }),\n\t\t...(capability.certification === undefined ? {} : { certification: capability.certification }),\n\t\t...(capability.extensions === undefined ? {} : { extensions: capability.extensions }),\n\t\tactions: module.actions.map(({ actionId, version, parameterSchema, resultSchema, requiredRoles, requiredPermissions, execution }) => ({\n\t\t\tactionId,\n\t\t\tversion,\n\t\t\tparameterSchema,\n\t\t\tresultSchema,\n\t\t\trequiredRoles,\n\t\t\trequiredPermissions,\n\t\t\texecution,\n\t\t})),\n\t\tviews: module.views.map(({ name, version, shape, scope, snapshotVersion, usage }) => ({ name, version, shape, scope, snapshotVersion, usage })),\n\t\tevents: module.eventTypes.map(({ eventType, schemaVersion, description, schema }) => ({ eventType, schemaVersion, description, schema })),\n\t};\n}\n\nexport const capabilityGenerator: GeneratorTarget = {\n\tname: \"@fabricorg/gen-capability\",\n\tversion: \"0.4.0\",\n\tgenerate(ir) {\n\t\treturn ir.modules.flatMap((module) => {\n\t\t\tconst capability = buildUsageContract(module);\n\t\t\tif (!capability) return [];\n\t\t\tassertUsageContract(capability);\n\t\t\tconst document: UsageContractDocument = {\n\t\t\t\tgenerator: { name: capabilityGenerator.name, version: capabilityGenerator.version },\n\t\t\t\tmanifestDigest: ir.manifestDigest,\n\t\t\t\tcapability,\n\t\t\t};\n\t\t\treturn [{ path: `${module.namespace}/capability.json`, content: stableStringify(document) }];\n\t\t});\n\t},\n};\n"],"mappings":"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","names":["module"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,74 @@
1
1
  import { GeneratorTarget } from '@fabricorg/compiler';
2
+ import { PortableJsonSchema, CapabilityMetadata, JsonValue, ActionExecutionContract, ModuleManifest } from '@fabricorg/platform';
2
3
 
4
+ /**
5
+ * Version of the usage contract document. Adopters negotiate on this, not on the
6
+ * generator's package version, and bump it only when the serialized shape changes
7
+ * in a way a consumer must detect.
8
+ */
9
+ declare const USAGE_CONTRACT_FORMAT_VERSION: 1;
10
+ interface UsageContractAction {
11
+ actionId: string;
12
+ version: number;
13
+ parameterSchema?: unknown;
14
+ resultSchema?: unknown;
15
+ requiredRoles?: string[];
16
+ requiredPermissions?: string[];
17
+ execution?: ActionExecutionContract;
18
+ }
19
+ interface UsageContractView {
20
+ name: string;
21
+ version: string;
22
+ shape: PortableJsonSchema;
23
+ scope: "tenant-space";
24
+ snapshotVersion: number;
25
+ usage?: ModuleManifest["views"][number]["usage"];
26
+ }
27
+ interface UsageContractEvent {
28
+ eventType: string;
29
+ schemaVersion: number;
30
+ description?: string;
31
+ schema?: PortableJsonSchema;
32
+ }
33
+ /**
34
+ * What a capability promises its adopters: the governed operations it dispatches,
35
+ * the view payloads it serves, the events it emits, and the namespaced extensions
36
+ * an experience system interprets. Experience semantics stay inside `extensions`,
37
+ * where ADR 0006 put them — this document never interprets them.
38
+ */
39
+ interface UsageContract {
40
+ formatVersion: typeof USAGE_CONTRACT_FORMAT_VERSION;
41
+ namespace: string;
42
+ version?: string;
43
+ displayName: string;
44
+ description: string;
45
+ stability: CapabilityMetadata["stability"];
46
+ deprecated?: CapabilityMetadata["deprecated"];
47
+ requirements?: CapabilityMetadata["requirements"];
48
+ certification?: CapabilityMetadata["certification"];
49
+ extensions?: Record<string, JsonValue>;
50
+ actions: UsageContractAction[];
51
+ views: UsageContractView[];
52
+ events: UsageContractEvent[];
53
+ }
54
+ interface UsageContractDocument {
55
+ generator: {
56
+ name: string;
57
+ version: string;
58
+ };
59
+ manifestDigest: string;
60
+ capability: UsageContract;
61
+ }
62
+ /**
63
+ * Structural validation an adopter can run before binding against a contract.
64
+ * It checks the document's own shape; it does not re-validate the manifest it
65
+ * was generated from.
66
+ */
67
+ declare function assertUsageContract(value: unknown, path?: string): asserts value is UsageContract;
68
+ declare function assertUsageContractDocument(value: unknown): asserts value is UsageContractDocument;
69
+ /** Machine-readable shape of the usage contract, for adopters that validate with their own tooling. */
70
+ declare const USAGE_CONTRACT_JSON_SCHEMA: PortableJsonSchema;
71
+ declare function buildUsageContract(module: ModuleManifest): UsageContract | undefined;
3
72
  declare const capabilityGenerator: GeneratorTarget;
4
73
 
5
- export { capabilityGenerator };
74
+ export { USAGE_CONTRACT_FORMAT_VERSION, USAGE_CONTRACT_JSON_SCHEMA, type UsageContract, type UsageContractAction, type UsageContractDocument, type UsageContractEvent, type UsageContractView, assertUsageContract, assertUsageContractDocument, buildUsageContract, capabilityGenerator };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,74 @@
1
1
  import { GeneratorTarget } from '@fabricorg/compiler';
2
+ import { PortableJsonSchema, CapabilityMetadata, JsonValue, ActionExecutionContract, ModuleManifest } from '@fabricorg/platform';
2
3
 
4
+ /**
5
+ * Version of the usage contract document. Adopters negotiate on this, not on the
6
+ * generator's package version, and bump it only when the serialized shape changes
7
+ * in a way a consumer must detect.
8
+ */
9
+ declare const USAGE_CONTRACT_FORMAT_VERSION: 1;
10
+ interface UsageContractAction {
11
+ actionId: string;
12
+ version: number;
13
+ parameterSchema?: unknown;
14
+ resultSchema?: unknown;
15
+ requiredRoles?: string[];
16
+ requiredPermissions?: string[];
17
+ execution?: ActionExecutionContract;
18
+ }
19
+ interface UsageContractView {
20
+ name: string;
21
+ version: string;
22
+ shape: PortableJsonSchema;
23
+ scope: "tenant-space";
24
+ snapshotVersion: number;
25
+ usage?: ModuleManifest["views"][number]["usage"];
26
+ }
27
+ interface UsageContractEvent {
28
+ eventType: string;
29
+ schemaVersion: number;
30
+ description?: string;
31
+ schema?: PortableJsonSchema;
32
+ }
33
+ /**
34
+ * What a capability promises its adopters: the governed operations it dispatches,
35
+ * the view payloads it serves, the events it emits, and the namespaced extensions
36
+ * an experience system interprets. Experience semantics stay inside `extensions`,
37
+ * where ADR 0006 put them — this document never interprets them.
38
+ */
39
+ interface UsageContract {
40
+ formatVersion: typeof USAGE_CONTRACT_FORMAT_VERSION;
41
+ namespace: string;
42
+ version?: string;
43
+ displayName: string;
44
+ description: string;
45
+ stability: CapabilityMetadata["stability"];
46
+ deprecated?: CapabilityMetadata["deprecated"];
47
+ requirements?: CapabilityMetadata["requirements"];
48
+ certification?: CapabilityMetadata["certification"];
49
+ extensions?: Record<string, JsonValue>;
50
+ actions: UsageContractAction[];
51
+ views: UsageContractView[];
52
+ events: UsageContractEvent[];
53
+ }
54
+ interface UsageContractDocument {
55
+ generator: {
56
+ name: string;
57
+ version: string;
58
+ };
59
+ manifestDigest: string;
60
+ capability: UsageContract;
61
+ }
62
+ /**
63
+ * Structural validation an adopter can run before binding against a contract.
64
+ * It checks the document's own shape; it does not re-validate the manifest it
65
+ * was generated from.
66
+ */
67
+ declare function assertUsageContract(value: unknown, path?: string): asserts value is UsageContract;
68
+ declare function assertUsageContractDocument(value: unknown): asserts value is UsageContractDocument;
69
+ /** Machine-readable shape of the usage contract, for adopters that validate with their own tooling. */
70
+ declare const USAGE_CONTRACT_JSON_SCHEMA: PortableJsonSchema;
71
+ declare function buildUsageContract(module: ModuleManifest): UsageContract | undefined;
3
72
  declare const capabilityGenerator: GeneratorTarget;
4
73
 
5
- export { capabilityGenerator };
74
+ export { USAGE_CONTRACT_FORMAT_VERSION, USAGE_CONTRACT_JSON_SCHEMA, type UsageContract, type UsageContractAction, type UsageContractDocument, type UsageContractEvent, type UsageContractView, assertUsageContract, assertUsageContractDocument, buildUsageContract, capabilityGenerator };
package/dist/index.js CHANGED
@@ -1,9 +1,190 @@
1
1
  // index.ts
2
2
  import { stableStringify } from "@fabricorg/compiler";
3
- var capabilityGenerator = { name: "@fabricorg/gen-capability", version: "0.3.0", generate(ir) {
4
- return ir.modules.filter((module) => module.capability).map((module) => ({ path: `${module.namespace}/capability.json`, content: stableStringify({ generator: { name: capabilityGenerator.name, version: capabilityGenerator.version }, manifestDigest: ir.manifestDigest, capability: { namespace: module.namespace, version: module.version, ...module.capability, actions: module.actions.map(({ actionId, version, parameterSchema, resultSchema, requiredRoles, requiredPermissions, execution }) => ({ actionId, version, parameterSchema, resultSchema, requiredRoles, requiredPermissions, execution })), views: module.views, events: module.eventTypes } }) }));
5
- } };
3
+ var USAGE_CONTRACT_FORMAT_VERSION = 1;
4
+ var STABILITIES = ["experimental", "beta", "stable", "deprecated"];
5
+ function fail(path, message) {
6
+ throw new Error(`Usage contract ${path} ${message}.`);
7
+ }
8
+ function requireString(value, path) {
9
+ if (typeof value !== "string" || !value.trim()) fail(path, "must be a non-empty string");
10
+ return value;
11
+ }
12
+ function requireArray(value, path) {
13
+ if (!Array.isArray(value)) fail(path, "must be an array");
14
+ return value;
15
+ }
16
+ function assertUsageContract(value, path = "capability") {
17
+ if (!value || typeof value !== "object" || Array.isArray(value)) fail(path, "must be an object");
18
+ const contract = value;
19
+ if (contract.formatVersion !== USAGE_CONTRACT_FORMAT_VERSION) {
20
+ fail(`${path}.formatVersion`, `must be ${USAGE_CONTRACT_FORMAT_VERSION}, received ${JSON.stringify(contract.formatVersion)}`);
21
+ }
22
+ if (!/^[a-z][a-z0-9-]*$/.test(requireString(contract.namespace, `${path}.namespace`))) {
23
+ fail(`${path}.namespace`, "must be lowercase letters, numbers and hyphens");
24
+ }
25
+ requireString(contract.displayName, `${path}.displayName`);
26
+ requireString(contract.description, `${path}.description`);
27
+ if (!STABILITIES.includes(contract.stability)) {
28
+ fail(`${path}.stability`, `must be one of ${STABILITIES.join(", ")}`);
29
+ }
30
+ const actionIds = /* @__PURE__ */ new Set();
31
+ requireArray(contract.actions, `${path}.actions`).forEach((entry, index) => {
32
+ const action = entry;
33
+ const actionId = requireString(action?.actionId, `${path}.actions[${index}].actionId`);
34
+ if (actionIds.has(actionId)) fail(`${path}.actions[${index}]`, `repeats actionId "${actionId}"`);
35
+ actionIds.add(actionId);
36
+ if (!Number.isInteger(action.version)) fail(`${path}.actions[${index}].version`, "must be an integer");
37
+ if (action.requiredRoles !== void 0 && !Array.isArray(action.requiredRoles)) fail(`${path}.actions[${index}].requiredRoles`, "must be an array");
38
+ if (action.requiredPermissions !== void 0 && !Array.isArray(action.requiredPermissions)) fail(`${path}.actions[${index}].requiredPermissions`, "must be an array");
39
+ });
40
+ const viewKeys = /* @__PURE__ */ new Set();
41
+ requireArray(contract.views, `${path}.views`).forEach((entry, index) => {
42
+ const view = entry;
43
+ const name = requireString(view?.name, `${path}.views[${index}].name`);
44
+ const version = requireString(view?.version, `${path}.views[${index}].version`);
45
+ const key = `${name}@${version}`;
46
+ if (viewKeys.has(key)) fail(`${path}.views[${index}]`, `repeats view "${key}"`);
47
+ viewKeys.add(key);
48
+ if (!view.shape || typeof view.shape !== "object" || Array.isArray(view.shape)) fail(`${path}.views[${index}].shape`, "must be a JSON Schema object");
49
+ if (view.scope !== "tenant-space") fail(`${path}.views[${index}].scope`, 'must be "tenant-space"');
50
+ if (!Number.isInteger(view.snapshotVersion) || view.snapshotVersion < 1) fail(`${path}.views[${index}].snapshotVersion`, "must be a positive integer");
51
+ });
52
+ requireArray(contract.events, `${path}.events`).forEach((entry, index) => {
53
+ const event = entry;
54
+ requireString(event?.eventType, `${path}.events[${index}].eventType`);
55
+ if (!Number.isInteger(event.schemaVersion)) fail(`${path}.events[${index}].schemaVersion`, "must be an integer");
56
+ });
57
+ if (contract.extensions !== void 0) {
58
+ if (!contract.extensions || typeof contract.extensions !== "object" || Array.isArray(contract.extensions)) fail(`${path}.extensions`, "must be an object");
59
+ for (const namespace of Object.keys(contract.extensions)) {
60
+ if (!/^[a-z][a-z0-9.-]*\.[a-z0-9.-]+\/v[1-9][0-9]*$/.test(namespace)) {
61
+ fail(`${path}.extensions`, `has invalid extension namespace "${namespace}"`);
62
+ }
63
+ }
64
+ }
65
+ }
66
+ function assertUsageContractDocument(value) {
67
+ if (!value || typeof value !== "object" || Array.isArray(value)) fail("document", "must be an object");
68
+ const document = value;
69
+ if (!/^[0-9a-f]{64}$/.test(String(document.manifestDigest))) fail("document.manifestDigest", "must be a lowercase SHA-256 digest");
70
+ const generator = document.generator;
71
+ if (!generator || typeof generator !== "object" || Array.isArray(generator)) fail("document.generator", "must be an object");
72
+ requireString(generator.name, "document.generator.name");
73
+ requireString(generator.version, "document.generator.version");
74
+ assertUsageContract(document.capability);
75
+ }
76
+ var USAGE_CONTRACT_JSON_SCHEMA = {
77
+ $schema: "https://json-schema.org/draft/2020-12/schema",
78
+ title: "Fabric capability usage contract",
79
+ type: "object",
80
+ required: ["formatVersion", "namespace", "displayName", "description", "stability", "actions", "views", "events"],
81
+ properties: {
82
+ formatVersion: { type: "integer", enum: [USAGE_CONTRACT_FORMAT_VERSION] },
83
+ namespace: { type: "string", pattern: "^[a-z][a-z0-9-]*$" },
84
+ version: { type: "string" },
85
+ displayName: { type: "string", minLength: 1 },
86
+ description: { type: "string", minLength: 1 },
87
+ stability: { type: "string", enum: [...STABILITIES] },
88
+ deprecated: { type: "object" },
89
+ requirements: { type: "object" },
90
+ certification: { type: "object" },
91
+ extensions: { type: "object" },
92
+ actions: {
93
+ type: "array",
94
+ items: {
95
+ type: "object",
96
+ required: ["actionId", "version"],
97
+ properties: {
98
+ actionId: { type: "string" },
99
+ version: { type: "integer" },
100
+ parameterSchema: { type: "object" },
101
+ resultSchema: { type: "object" },
102
+ requiredRoles: { type: "array", items: { type: "string" } },
103
+ requiredPermissions: { type: "array", items: { type: "string" } },
104
+ execution: { type: "object" }
105
+ }
106
+ }
107
+ },
108
+ views: {
109
+ type: "array",
110
+ items: {
111
+ type: "object",
112
+ required: ["name", "version", "shape", "scope", "snapshotVersion"],
113
+ properties: {
114
+ name: { type: "string" },
115
+ version: { type: "string" },
116
+ shape: { type: "object" },
117
+ scope: { type: "string", enum: ["tenant-space"] },
118
+ snapshotVersion: { type: "integer" },
119
+ usage: { type: "object" }
120
+ }
121
+ }
122
+ },
123
+ events: {
124
+ type: "array",
125
+ items: {
126
+ type: "object",
127
+ required: ["eventType", "schemaVersion"],
128
+ properties: {
129
+ eventType: { type: "string" },
130
+ schemaVersion: { type: "integer" },
131
+ description: { type: "string" },
132
+ schema: { type: "object" }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ };
138
+ function buildUsageContract(module) {
139
+ const capability = module.capability;
140
+ if (!capability) return void 0;
141
+ return {
142
+ formatVersion: USAGE_CONTRACT_FORMAT_VERSION,
143
+ namespace: module.namespace,
144
+ ...module.version === void 0 ? {} : { version: module.version },
145
+ displayName: capability.displayName,
146
+ description: capability.description,
147
+ stability: capability.stability,
148
+ ...capability.deprecated === void 0 ? {} : { deprecated: capability.deprecated },
149
+ ...capability.requirements === void 0 ? {} : { requirements: capability.requirements },
150
+ ...capability.certification === void 0 ? {} : { certification: capability.certification },
151
+ ...capability.extensions === void 0 ? {} : { extensions: capability.extensions },
152
+ actions: module.actions.map(({ actionId, version, parameterSchema, resultSchema, requiredRoles, requiredPermissions, execution }) => ({
153
+ actionId,
154
+ version,
155
+ parameterSchema,
156
+ resultSchema,
157
+ requiredRoles,
158
+ requiredPermissions,
159
+ execution
160
+ })),
161
+ views: module.views.map(({ name, version, shape, scope, snapshotVersion, usage }) => ({ name, version, shape, scope, snapshotVersion, usage })),
162
+ events: module.eventTypes.map(({ eventType, schemaVersion, description, schema }) => ({ eventType, schemaVersion, description, schema }))
163
+ };
164
+ }
165
+ var capabilityGenerator = {
166
+ name: "@fabricorg/gen-capability",
167
+ version: "0.4.0",
168
+ generate(ir) {
169
+ return ir.modules.flatMap((module) => {
170
+ const capability = buildUsageContract(module);
171
+ if (!capability) return [];
172
+ assertUsageContract(capability);
173
+ const document = {
174
+ generator: { name: capabilityGenerator.name, version: capabilityGenerator.version },
175
+ manifestDigest: ir.manifestDigest,
176
+ capability
177
+ };
178
+ return [{ path: `${module.namespace}/capability.json`, content: stableStringify(document) }];
179
+ });
180
+ }
181
+ };
6
182
  export {
183
+ USAGE_CONTRACT_FORMAT_VERSION,
184
+ USAGE_CONTRACT_JSON_SCHEMA,
185
+ assertUsageContract,
186
+ assertUsageContractDocument,
187
+ buildUsageContract,
7
188
  capabilityGenerator
8
189
  };
9
190
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../index.ts"],"sourcesContent":["import { stableStringify, type GeneratorTarget } from \"@fabricorg/compiler\";\nexport const capabilityGenerator: GeneratorTarget = { name:\"@fabricorg/gen-capability\", version:\"0.3.0\", generate(ir) { return ir.modules.filter((module) => module.capability).map((module) => ({ path:`${module.namespace}/capability.json`, content:stableStringify({ generator:{name:capabilityGenerator.name,version:capabilityGenerator.version},manifestDigest:ir.manifestDigest,capability:{namespace:module.namespace,version:module.version,...module.capability,actions:module.actions.map(({actionId,version,parameterSchema,resultSchema,requiredRoles,requiredPermissions,execution})=>({actionId,version,parameterSchema,resultSchema,requiredRoles,requiredPermissions,execution})),views:module.views,events:module.eventTypes}}) })); } };\n"],"mappings":";AAAA,SAAS,uBAA6C;AAC/C,IAAM,sBAAuC,EAAE,MAAK,6BAA6B,SAAQ,SAAS,SAAS,IAAI;AAAE,SAAO,GAAG,QAAQ,OAAO,CAAC,WAAW,OAAO,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE,MAAK,GAAG,OAAO,SAAS,oBAAoB,SAAQ,gBAAgB,EAAE,WAAU,EAAC,MAAK,oBAAoB,MAAK,SAAQ,oBAAoB,QAAO,GAAE,gBAAe,GAAG,gBAAe,YAAW,EAAC,WAAU,OAAO,WAAU,SAAQ,OAAO,SAAQ,GAAG,OAAO,YAAW,SAAQ,OAAO,QAAQ,IAAI,CAAC,EAAC,UAAS,SAAQ,iBAAgB,cAAa,eAAc,qBAAoB,UAAS,OAAK,EAAC,UAAS,SAAQ,iBAAgB,cAAa,eAAc,qBAAoB,UAAS,EAAE,GAAE,OAAM,OAAO,OAAM,QAAO,OAAO,WAAU,EAAC,CAAC,EAAE,EAAE;AAAG,EAAE;","names":[]}
1
+ {"version":3,"sources":["../index.ts"],"sourcesContent":["import { stableStringify, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport type {\n\tActionExecutionContract,\n\tCapabilityMetadata,\n\tJsonValue,\n\tModuleManifest,\n\tPortableJsonSchema,\n} from \"@fabricorg/platform\";\n\n/**\n * Version of the usage contract document. Adopters negotiate on this, not on the\n * generator's package version, and bump it only when the serialized shape changes\n * in a way a consumer must detect.\n */\nexport const USAGE_CONTRACT_FORMAT_VERSION = 1 as const;\n\nexport interface UsageContractAction {\n\tactionId: string;\n\tversion: number;\n\tparameterSchema?: unknown;\n\tresultSchema?: unknown;\n\trequiredRoles?: string[];\n\trequiredPermissions?: string[];\n\texecution?: ActionExecutionContract;\n}\n\nexport interface UsageContractView {\n\tname: string;\n\tversion: string;\n\tshape: PortableJsonSchema;\n\tscope: \"tenant-space\";\n\tsnapshotVersion: number;\n\tusage?: ModuleManifest[\"views\"][number][\"usage\"];\n}\n\nexport interface UsageContractEvent {\n\teventType: string;\n\tschemaVersion: number;\n\tdescription?: string;\n\tschema?: PortableJsonSchema;\n}\n\n/**\n * What a capability promises its adopters: the governed operations it dispatches,\n * the view payloads it serves, the events it emits, and the namespaced extensions\n * an experience system interprets. Experience semantics stay inside `extensions`,\n * where ADR 0006 put them — this document never interprets them.\n */\nexport interface UsageContract {\n\tformatVersion: typeof USAGE_CONTRACT_FORMAT_VERSION;\n\tnamespace: string;\n\tversion?: string;\n\tdisplayName: string;\n\tdescription: string;\n\tstability: CapabilityMetadata[\"stability\"];\n\tdeprecated?: CapabilityMetadata[\"deprecated\"];\n\trequirements?: CapabilityMetadata[\"requirements\"];\n\tcertification?: CapabilityMetadata[\"certification\"];\n\textensions?: Record<string, JsonValue>;\n\tactions: UsageContractAction[];\n\tviews: UsageContractView[];\n\tevents: UsageContractEvent[];\n}\n\nexport interface UsageContractDocument {\n\tgenerator: { name: string; version: string };\n\tmanifestDigest: string;\n\tcapability: UsageContract;\n}\n\nconst STABILITIES = [\"experimental\", \"beta\", \"stable\", \"deprecated\"];\n\nfunction fail(path: string, message: string): never {\n\tthrow new Error(`Usage contract ${path} ${message}.`);\n}\n\nfunction requireString(value: unknown, path: string): string {\n\tif (typeof value !== \"string\" || !value.trim()) fail(path, \"must be a non-empty string\");\n\treturn value;\n}\n\nfunction requireArray(value: unknown, path: string): unknown[] {\n\tif (!Array.isArray(value)) fail(path, \"must be an array\");\n\treturn value;\n}\n\n/**\n * Structural validation an adopter can run before binding against a contract.\n * It checks the document's own shape; it does not re-validate the manifest it\n * was generated from.\n */\nexport function assertUsageContract(value: unknown, path = \"capability\"): asserts value is UsageContract {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) fail(path, \"must be an object\");\n\tconst contract = value as Record<string, unknown>;\n\tif (contract.formatVersion !== USAGE_CONTRACT_FORMAT_VERSION) {\n\t\tfail(`${path}.formatVersion`, `must be ${USAGE_CONTRACT_FORMAT_VERSION}, received ${JSON.stringify(contract.formatVersion)}`);\n\t}\n\tif (!/^[a-z][a-z0-9-]*$/.test(requireString(contract.namespace, `${path}.namespace`))) {\n\t\tfail(`${path}.namespace`, \"must be lowercase letters, numbers and hyphens\");\n\t}\n\trequireString(contract.displayName, `${path}.displayName`);\n\trequireString(contract.description, `${path}.description`);\n\tif (!STABILITIES.includes(contract.stability as string)) {\n\t\tfail(`${path}.stability`, `must be one of ${STABILITIES.join(\", \")}`);\n\t}\n\tconst actionIds = new Set<string>();\n\trequireArray(contract.actions, `${path}.actions`).forEach((entry, index) => {\n\t\tconst action = entry as Record<string, unknown>;\n\t\tconst actionId = requireString(action?.actionId, `${path}.actions[${index}].actionId`);\n\t\tif (actionIds.has(actionId)) fail(`${path}.actions[${index}]`, `repeats actionId \"${actionId}\"`);\n\t\tactionIds.add(actionId);\n\t\tif (!Number.isInteger(action.version)) fail(`${path}.actions[${index}].version`, \"must be an integer\");\n\t\tif (action.requiredRoles !== undefined && !Array.isArray(action.requiredRoles)) fail(`${path}.actions[${index}].requiredRoles`, \"must be an array\");\n\t\tif (action.requiredPermissions !== undefined && !Array.isArray(action.requiredPermissions)) fail(`${path}.actions[${index}].requiredPermissions`, \"must be an array\");\n\t});\n\tconst viewKeys = new Set<string>();\n\trequireArray(contract.views, `${path}.views`).forEach((entry, index) => {\n\t\tconst view = entry as Record<string, unknown>;\n\t\tconst name = requireString(view?.name, `${path}.views[${index}].name`);\n\t\tconst version = requireString(view?.version, `${path}.views[${index}].version`);\n\t\tconst key = `${name}@${version}`;\n\t\tif (viewKeys.has(key)) fail(`${path}.views[${index}]`, `repeats view \"${key}\"`);\n\t\tviewKeys.add(key);\n\t\tif (!view.shape || typeof view.shape !== \"object\" || Array.isArray(view.shape)) fail(`${path}.views[${index}].shape`, \"must be a JSON Schema object\");\n\t\tif (view.scope !== \"tenant-space\") fail(`${path}.views[${index}].scope`, 'must be \"tenant-space\"');\n\t\tif (!Number.isInteger(view.snapshotVersion) || (view.snapshotVersion as number) < 1) fail(`${path}.views[${index}].snapshotVersion`, \"must be a positive integer\");\n\t});\n\trequireArray(contract.events, `${path}.events`).forEach((entry, index) => {\n\t\tconst event = entry as Record<string, unknown>;\n\t\trequireString(event?.eventType, `${path}.events[${index}].eventType`);\n\t\tif (!Number.isInteger(event.schemaVersion)) fail(`${path}.events[${index}].schemaVersion`, \"must be an integer\");\n\t});\n\tif (contract.extensions !== undefined) {\n\t\tif (!contract.extensions || typeof contract.extensions !== \"object\" || Array.isArray(contract.extensions)) fail(`${path}.extensions`, \"must be an object\");\n\t\tfor (const namespace of Object.keys(contract.extensions as Record<string, unknown>)) {\n\t\t\tif (!/^[a-z][a-z0-9.-]*\\.[a-z0-9.-]+\\/v[1-9][0-9]*$/.test(namespace)) {\n\t\t\t\tfail(`${path}.extensions`, `has invalid extension namespace \"${namespace}\"`);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function assertUsageContractDocument(value: unknown): asserts value is UsageContractDocument {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) fail(\"document\", \"must be an object\");\n\tconst document = value as Record<string, unknown>;\n\tif (!/^[0-9a-f]{64}$/.test(String(document.manifestDigest))) fail(\"document.manifestDigest\", \"must be a lowercase SHA-256 digest\");\n\tconst generator = document.generator as { name?: unknown; version?: unknown } | undefined;\n\tif (!generator || typeof generator !== \"object\" || Array.isArray(generator)) fail(\"document.generator\", \"must be an object\");\n\trequireString(generator.name, \"document.generator.name\");\n\trequireString(generator.version, \"document.generator.version\");\n\tassertUsageContract(document.capability);\n}\n\n/** Machine-readable shape of the usage contract, for adopters that validate with their own tooling. */\nexport const USAGE_CONTRACT_JSON_SCHEMA: PortableJsonSchema = {\n\t$schema: \"https://json-schema.org/draft/2020-12/schema\",\n\ttitle: \"Fabric capability usage contract\",\n\ttype: \"object\",\n\trequired: [\"formatVersion\", \"namespace\", \"displayName\", \"description\", \"stability\", \"actions\", \"views\", \"events\"],\n\tproperties: {\n\t\tformatVersion: { type: \"integer\", enum: [USAGE_CONTRACT_FORMAT_VERSION] },\n\t\tnamespace: { type: \"string\", pattern: \"^[a-z][a-z0-9-]*$\" },\n\t\tversion: { type: \"string\" },\n\t\tdisplayName: { type: \"string\", minLength: 1 },\n\t\tdescription: { type: \"string\", minLength: 1 },\n\t\tstability: { type: \"string\", enum: [...STABILITIES] },\n\t\tdeprecated: { type: \"object\" },\n\t\trequirements: { type: \"object\" },\n\t\tcertification: { type: \"object\" },\n\t\textensions: { type: \"object\" },\n\t\tactions: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\trequired: [\"actionId\", \"version\"],\n\t\t\t\tproperties: {\n\t\t\t\t\tactionId: { type: \"string\" },\n\t\t\t\t\tversion: { type: \"integer\" },\n\t\t\t\t\tparameterSchema: { type: \"object\" },\n\t\t\t\t\tresultSchema: { type: \"object\" },\n\t\t\t\t\trequiredRoles: { type: \"array\", items: { type: \"string\" } },\n\t\t\t\t\trequiredPermissions: { type: \"array\", items: { type: \"string\" } },\n\t\t\t\t\texecution: { type: \"object\" },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tviews: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\trequired: [\"name\", \"version\", \"shape\", \"scope\", \"snapshotVersion\"],\n\t\t\t\tproperties: {\n\t\t\t\t\tname: { type: \"string\" },\n\t\t\t\t\tversion: { type: \"string\" },\n\t\t\t\t\tshape: { type: \"object\" },\n\t\t\t\t\tscope: { type: \"string\", enum: [\"tenant-space\"] },\n\t\t\t\t\tsnapshotVersion: { type: \"integer\" },\n\t\t\t\t\tusage: { type: \"object\" },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tevents: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\trequired: [\"eventType\", \"schemaVersion\"],\n\t\t\t\tproperties: {\n\t\t\t\t\teventType: { type: \"string\" },\n\t\t\t\t\tschemaVersion: { type: \"integer\" },\n\t\t\t\t\tdescription: { type: \"string\" },\n\t\t\t\t\tschema: { type: \"object\" },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n};\n\nexport function buildUsageContract(module: ModuleManifest): UsageContract | undefined {\n\tconst capability = module.capability;\n\tif (!capability) return undefined;\n\treturn {\n\t\tformatVersion: USAGE_CONTRACT_FORMAT_VERSION,\n\t\tnamespace: module.namespace,\n\t\t...(module.version === undefined ? {} : { version: module.version }),\n\t\tdisplayName: capability.displayName,\n\t\tdescription: capability.description,\n\t\tstability: capability.stability,\n\t\t...(capability.deprecated === undefined ? {} : { deprecated: capability.deprecated }),\n\t\t...(capability.requirements === undefined ? {} : { requirements: capability.requirements }),\n\t\t...(capability.certification === undefined ? {} : { certification: capability.certification }),\n\t\t...(capability.extensions === undefined ? {} : { extensions: capability.extensions }),\n\t\tactions: module.actions.map(({ actionId, version, parameterSchema, resultSchema, requiredRoles, requiredPermissions, execution }) => ({\n\t\t\tactionId,\n\t\t\tversion,\n\t\t\tparameterSchema,\n\t\t\tresultSchema,\n\t\t\trequiredRoles,\n\t\t\trequiredPermissions,\n\t\t\texecution,\n\t\t})),\n\t\tviews: module.views.map(({ name, version, shape, scope, snapshotVersion, usage }) => ({ name, version, shape, scope, snapshotVersion, usage })),\n\t\tevents: module.eventTypes.map(({ eventType, schemaVersion, description, schema }) => ({ eventType, schemaVersion, description, schema })),\n\t};\n}\n\nexport const capabilityGenerator: GeneratorTarget = {\n\tname: \"@fabricorg/gen-capability\",\n\tversion: \"0.4.0\",\n\tgenerate(ir) {\n\t\treturn ir.modules.flatMap((module) => {\n\t\t\tconst capability = buildUsageContract(module);\n\t\t\tif (!capability) return [];\n\t\t\tassertUsageContract(capability);\n\t\t\tconst document: UsageContractDocument = {\n\t\t\t\tgenerator: { name: capabilityGenerator.name, version: capabilityGenerator.version },\n\t\t\t\tmanifestDigest: ir.manifestDigest,\n\t\t\t\tcapability,\n\t\t\t};\n\t\t\treturn [{ path: `${module.namespace}/capability.json`, content: stableStringify(document) }];\n\t\t});\n\t},\n};\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabricorg/gen-capability",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Capability usage contract generator for Fabric compiler IR.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -25,13 +25,14 @@
25
25
  "CHANGELOG.md"
26
26
  ],
27
27
  "dependencies": {
28
- "@fabricorg/compiler": "^1.0.0"
28
+ "@fabricorg/compiler": "^2.1.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^22.10.0",
32
32
  "tsup": "^8.5.0",
33
33
  "typescript": "^5.7.3",
34
- "vitest": "^4.1.5"
34
+ "vitest": "^4.1.5",
35
+ "@fabricorg/platform": "^1.1.0"
35
36
  },
36
37
  "engines": {
37
38
  "node": ">=20"
@@ -39,6 +40,9 @@
39
40
  "publishConfig": {
40
41
  "access": "public"
41
42
  },
43
+ "peerDependencies": {
44
+ "@fabricorg/platform": "^1.1.0"
45
+ },
42
46
  "scripts": {
43
47
  "clean": "rm -rf dist tsconfig.tsbuildinfo",
44
48
  "build": "tsup",