@fabricorg/gen-capability 0.4.0 → 0.5.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,45 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Release additive public compiler and generator APIs as minor versions. This includes parameterized
8
+ view schema contracts, the exported usage-contract JSON schema, and the runtime Platform validation
9
+ used by capability generation.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+ - @fabricorg/compiler@2.2.0
15
+
16
+ ## 0.4.1
17
+
18
+ ### Patch Changes
19
+
20
+ - 62dd1ca: Add deterministic application assembly: versioned assembly manifests, resolved
21
+ lockfiles, and a single build gate for capabilities, component packs, and
22
+ adoption bindings. `resolveAssembly` resolves semver ranges against available
23
+ versions, rejects unresolved or duplicate capability identities, validates
24
+ usage contracts, component packs, and adoption bindings as one gate, and
25
+ produces a locked lockfile with a canonical SHA-256 digest. Lockfiles now hash
26
+ the resolved application, capability manifests, generated usage-contract
27
+ content, component-pack artifacts, and adoption bindings rather than the input
28
+ ranges. `assertAssemblyLockfile` rejects content changed after resolution.
29
+ Assembly manifest and lockfile documents move to format version 2.
30
+ - b932767: Add portable parameter schemas and validation for projection views. Projection snapshot keys now
31
+ include a canonical parameter identity, generated capability and experience contracts preserve view
32
+ parameter schemas, and compatible snapshots continue through the explicit `upgradeSnapshot` seam.
33
+ - Updated dependencies [b932767]
34
+ - @fabricorg/compiler@2.1.1
35
+
36
+ ### Additional release notes
37
+
38
+ ### Patch Changes
39
+
40
+ - Preserve projection view `parameterSchema` in generated usage contracts and validate it as portable
41
+ JSON Schema.
42
+
3
43
  ## 0.4.0
4
44
 
5
45
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -29,6 +29,7 @@ __export(index_exports, {
29
29
  });
30
30
  module.exports = __toCommonJS(index_exports);
31
31
  var import_compiler = require("@fabricorg/compiler");
32
+ var import_platform = require("@fabricorg/platform");
32
33
  var USAGE_CONTRACT_FORMAT_VERSION = 1;
33
34
  var STABILITIES = ["experimental", "beta", "stable", "deprecated"];
34
35
  function fail(path, message) {
@@ -75,6 +76,13 @@ function assertUsageContract(value, path = "capability") {
75
76
  if (viewKeys.has(key)) fail(`${path}.views[${index}]`, `repeats view "${key}"`);
76
77
  viewKeys.add(key);
77
78
  if (!view.shape || typeof view.shape !== "object" || Array.isArray(view.shape)) fail(`${path}.views[${index}].shape`, "must be a JSON Schema object");
79
+ if (view.parameterSchema !== void 0) {
80
+ try {
81
+ (0, import_platform.assertPortableJsonSchema)(view.parameterSchema, `${path}.views[${index}].parameterSchema`);
82
+ } catch (error) {
83
+ fail(`${path}.views[${index}].parameterSchema`, error instanceof Error ? error.message : String(error));
84
+ }
85
+ }
78
86
  if (view.scope !== "tenant-space") fail(`${path}.views[${index}].scope`, 'must be "tenant-space"');
79
87
  if (!Number.isInteger(view.snapshotVersion) || view.snapshotVersion < 1) fail(`${path}.views[${index}].snapshotVersion`, "must be a positive integer");
80
88
  });
@@ -143,6 +151,7 @@ var USAGE_CONTRACT_JSON_SCHEMA = {
143
151
  name: { type: "string" },
144
152
  version: { type: "string" },
145
153
  shape: { type: "object" },
154
+ parameterSchema: { type: "object" },
146
155
  scope: { type: "string", enum: ["tenant-space"] },
147
156
  snapshotVersion: { type: "integer" },
148
157
  usage: { type: "object" }
@@ -187,13 +196,13 @@ function buildUsageContract(module2) {
187
196
  requiredPermissions,
188
197
  execution
189
198
  })),
190
- views: module2.views.map(({ name, version, shape, scope, snapshotVersion, usage }) => ({ name, version, shape, scope, snapshotVersion, usage })),
199
+ views: module2.views.map(({ name, version, shape, parameterSchema, scope, snapshotVersion, usage }) => ({ name, version, shape, parameterSchema, scope, snapshotVersion, usage })),
191
200
  events: module2.eventTypes.map(({ eventType, schemaVersion, description, schema }) => ({ eventType, schemaVersion, description, schema }))
192
201
  };
193
202
  }
194
203
  var capabilityGenerator = {
195
204
  name: "@fabricorg/gen-capability",
196
- version: "0.4.0",
205
+ version: "0.5.0",
197
206
  generate(ir) {
198
207
  return ir.modules.flatMap((module2) => {
199
208
  const capability = buildUsageContract(module2);
@@ -1 +1 @@
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"]}
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\";\nimport { assertPortableJsonSchema } 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\tparameterSchema?: 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.parameterSchema !== undefined) {\n\t\t\ttry { assertPortableJsonSchema(view.parameterSchema, `${path}.views[${index}].parameterSchema`); }\n\t\t\tcatch (error) { fail(`${path}.views[${index}].parameterSchema`, error instanceof Error ? error.message : String(error)); }\n\t\t}\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\tparameterSchema: { 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, parameterSchema, scope, snapshotVersion, usage }) => ({ name, version, shape, parameterSchema, 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.5.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
@@ -20,6 +20,7 @@ interface UsageContractView {
20
20
  name: string;
21
21
  version: string;
22
22
  shape: PortableJsonSchema;
23
+ parameterSchema?: PortableJsonSchema;
23
24
  scope: "tenant-space";
24
25
  snapshotVersion: number;
25
26
  usage?: ModuleManifest["views"][number]["usage"];
package/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ interface UsageContractView {
20
20
  name: string;
21
21
  version: string;
22
22
  shape: PortableJsonSchema;
23
+ parameterSchema?: PortableJsonSchema;
23
24
  scope: "tenant-space";
24
25
  snapshotVersion: number;
25
26
  usage?: ModuleManifest["views"][number]["usage"];
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // index.ts
2
2
  import { stableStringify } from "@fabricorg/compiler";
3
+ import { assertPortableJsonSchema } from "@fabricorg/platform";
3
4
  var USAGE_CONTRACT_FORMAT_VERSION = 1;
4
5
  var STABILITIES = ["experimental", "beta", "stable", "deprecated"];
5
6
  function fail(path, message) {
@@ -46,6 +47,13 @@ function assertUsageContract(value, path = "capability") {
46
47
  if (viewKeys.has(key)) fail(`${path}.views[${index}]`, `repeats view "${key}"`);
47
48
  viewKeys.add(key);
48
49
  if (!view.shape || typeof view.shape !== "object" || Array.isArray(view.shape)) fail(`${path}.views[${index}].shape`, "must be a JSON Schema object");
50
+ if (view.parameterSchema !== void 0) {
51
+ try {
52
+ assertPortableJsonSchema(view.parameterSchema, `${path}.views[${index}].parameterSchema`);
53
+ } catch (error) {
54
+ fail(`${path}.views[${index}].parameterSchema`, error instanceof Error ? error.message : String(error));
55
+ }
56
+ }
49
57
  if (view.scope !== "tenant-space") fail(`${path}.views[${index}].scope`, 'must be "tenant-space"');
50
58
  if (!Number.isInteger(view.snapshotVersion) || view.snapshotVersion < 1) fail(`${path}.views[${index}].snapshotVersion`, "must be a positive integer");
51
59
  });
@@ -114,6 +122,7 @@ var USAGE_CONTRACT_JSON_SCHEMA = {
114
122
  name: { type: "string" },
115
123
  version: { type: "string" },
116
124
  shape: { type: "object" },
125
+ parameterSchema: { type: "object" },
117
126
  scope: { type: "string", enum: ["tenant-space"] },
118
127
  snapshotVersion: { type: "integer" },
119
128
  usage: { type: "object" }
@@ -158,13 +167,13 @@ function buildUsageContract(module) {
158
167
  requiredPermissions,
159
168
  execution
160
169
  })),
161
- views: module.views.map(({ name, version, shape, scope, snapshotVersion, usage }) => ({ name, version, shape, scope, snapshotVersion, usage })),
170
+ views: module.views.map(({ name, version, shape, parameterSchema, scope, snapshotVersion, usage }) => ({ name, version, shape, parameterSchema, scope, snapshotVersion, usage })),
162
171
  events: module.eventTypes.map(({ eventType, schemaVersion, description, schema }) => ({ eventType, schemaVersion, description, schema }))
163
172
  };
164
173
  }
165
174
  var capabilityGenerator = {
166
175
  name: "@fabricorg/gen-capability",
167
- version: "0.4.0",
176
+ version: "0.5.0",
168
177
  generate(ir) {
169
178
  return ir.modules.flatMap((module) => {
170
179
  const capability = buildUsageContract(module);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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":[]}
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\";\nimport { assertPortableJsonSchema } 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\tparameterSchema?: 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.parameterSchema !== undefined) {\n\t\t\ttry { assertPortableJsonSchema(view.parameterSchema, `${path}.views[${index}].parameterSchema`); }\n\t\t\tcatch (error) { fail(`${path}.views[${index}].parameterSchema`, error instanceof Error ? error.message : String(error)); }\n\t\t}\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\tparameterSchema: { 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, parameterSchema, scope, snapshotVersion, usage }) => ({ name, version, shape, parameterSchema, 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.5.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.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Capability usage contract generator for Fabric compiler IR.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -25,14 +25,14 @@
25
25
  "CHANGELOG.md"
26
26
  ],
27
27
  "dependencies": {
28
- "@fabricorg/compiler": "^2.1.0"
28
+ "@fabricorg/compiler": "^2.2.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
34
  "vitest": "^4.1.5",
35
- "@fabricorg/platform": "^1.1.0"
35
+ "@fabricorg/platform": "^1.2.0"
36
36
  },
37
37
  "engines": {
38
38
  "node": ">=20"
@@ -41,7 +41,7 @@
41
41
  "access": "public"
42
42
  },
43
43
  "peerDependencies": {
44
- "@fabricorg/platform": "^1.1.0"
44
+ "@fabricorg/platform": "^1.2.0"
45
45
  },
46
46
  "scripts": {
47
47
  "clean": "rm -rf dist tsconfig.tsbuildinfo",