@fabricorg/policy-opa 0.2.0 → 0.3.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,14 @@
1
1
  # @fabricorg/policy-opa
2
2
 
3
+ ## 0.3.0 — 2026-05-17
4
+
5
+ ### Minor
6
+
7
+ - **Policy guidance support.** `OpaDecision` now accepts `guidance?: PolicyGuidance` and the evaluator maps it directly to `PolicyOutcome.guidance`. This makes OPA-backed policies render through the same audit/remediation UI contract as TypeScript code policies.
8
+ - **Engine metadata cleanup.** User-facing facts move out of `dispatchEvidence.engine.metadata` and into `PolicyOutcome.guidance`. Engine metadata remains focused on OPA provenance (`decisionPath`, `inputHash`, `decisionId`, `bundleRevision`, `conditionResults`, `obligations`, raw `provenance`).
9
+ - **Default-deny failure guidance.** OPA infrastructure failures still return `block` by default, now with generic corrective guidance telling operators to check OPA reachability, bundle serving, and decision shape.
10
+ - **Peer-deps:** `@fabricorg/platform ^0.4.0`.
11
+
3
12
  ## 0.2.0 — 2026-05-16
4
13
 
5
14
  ### Minor
package/README.md CHANGED
@@ -78,14 +78,18 @@ decision := {
78
78
  "result": result,
79
79
  "reason": reason,
80
80
  "conditionResults": condition_results,
81
- "factsUsed": facts_used,
81
+ "guidance": {
82
+ "summary": reason,
83
+ "factsUsed": facts_used,
84
+ "correctiveActions": corrective_actions,
85
+ },
82
86
  }
83
87
 
84
88
  result := "block" if not consent_active
85
89
  result := "block" if not within_window
86
90
  default result := "pass"
87
91
 
88
- # ...rules computing reason, condition_results, facts_used...
92
+ # ...rules computing reason, condition_results, facts_used, corrective_actions...
89
93
  ```
90
94
 
91
95
  The validator accepts the following fields (TypeScript types: `OpaDecision`):
@@ -100,7 +104,7 @@ The validator accepts the following fields (TypeScript types: `OpaDecision`):
100
104
  result: "pass" | "warn" | "block";
101
105
  reason?: string;
102
106
  }>;
103
- factsUsed?: Record<string, unknown>;
107
+ guidance?: PolicyGuidance;
104
108
  obligations?: Record<string, unknown>;
105
109
  }
106
110
  ```
@@ -179,13 +183,12 @@ For a successful OPA evaluation under the HTTP executor (with provenance enabled
179
183
  "version": "0.65.0",
180
184
  "bundles": { "lending": { "revision": "2026-05-16.3" } }
181
185
  },
182
- "conditionResults": [{ "conditionId": "consent_active", "passed": true, "result": "pass" }],
183
- "factsUsed": { "consent": { "active": true } }
186
+ "conditionResults": [{ "conditionId": "consent_active", "passed": true, "result": "pass" }]
184
187
  }
185
188
  }
186
189
  ```
187
190
 
188
- Fabric's `policyId` / `policyVersion` remain canonical (`"what was evaluated"`). `engine.metadata.{decisionId, bundleName, bundleRevision}` answers `"which artifact produced the answer"`, and `decisionId` is the join key against OPA's own decision-log stream if you ship it to a SIEM. All of this rides on the `PolicyEvaluation` row Fabric persists per outcome.
191
+ Fabric's `policyId` / `policyVersion` remain canonical (`"what was evaluated"`). `engine.metadata.{decisionId, bundleName, bundleRevision}` answers `"which artifact produced the answer"`, and `decisionId` is the join key against OPA's own decision-log stream if you ship it to a SIEM. User-facing facts and remediation steps live on `PolicyOutcome.guidance`, not in engine metadata, so code policies and OPA policies render through the same audit UI contract.
189
192
 
190
193
  If OPA serves multiple bundles and the binding has no `bundleName` selector, `bundleRevision` is omitted and `bundleRevisionStatus: "ambiguous"` is recorded — audit dashboards can flag these for a manual fix.
191
194
 
package/dist/index.cjs CHANGED
@@ -54,8 +54,9 @@ function parseOpaDecision(raw) {
54
54
  if (err) return { ok: false, error: err };
55
55
  }
56
56
  }
57
- if (d.factsUsed !== void 0 && !isPlainObject(d.factsUsed)) {
58
- return { ok: false, error: "factsUsed must be an object when present" };
57
+ if (d.guidance !== void 0) {
58
+ const err = validateGuidance(d.guidance);
59
+ if (err) return { ok: false, error: err };
59
60
  }
60
61
  if (d.obligations !== void 0 && !isPlainObject(d.obligations)) {
61
62
  return { ok: false, error: "obligations must be an object when present" };
@@ -81,6 +82,68 @@ function validateConditionResult(value, index) {
81
82
  }
82
83
  return null;
83
84
  }
85
+ function validateGuidance(value) {
86
+ if (!isPlainObject(value)) {
87
+ return "guidance must be an object when present";
88
+ }
89
+ const guidance = value;
90
+ if (guidance.summary !== void 0 && typeof guidance.summary !== "string") {
91
+ return "guidance.summary must be a string when present";
92
+ }
93
+ if (!Array.isArray(guidance.factsUsed)) {
94
+ return "guidance.factsUsed must be an array";
95
+ }
96
+ for (let i = 0; i < guidance.factsUsed.length; i += 1) {
97
+ const err = validatePolicyFact(guidance.factsUsed[i], i);
98
+ if (err) return err;
99
+ }
100
+ if (!Array.isArray(guidance.correctiveActions)) {
101
+ return "guidance.correctiveActions must be an array";
102
+ }
103
+ for (let i = 0; i < guidance.correctiveActions.length; i += 1) {
104
+ const err = validateCorrectiveAction(guidance.correctiveActions[i], i);
105
+ if (err) return err;
106
+ }
107
+ return null;
108
+ }
109
+ function validatePolicyFact(value, index) {
110
+ if (!isPlainObject(value)) {
111
+ return `guidance.factsUsed[${index}] must be an object`;
112
+ }
113
+ const fact = value;
114
+ if (typeof fact.name !== "string" || fact.name.length === 0) {
115
+ return `guidance.factsUsed[${index}].name must be a non-empty string`;
116
+ }
117
+ if (fact.label !== void 0 && typeof fact.label !== "string") {
118
+ return `guidance.factsUsed[${index}].label must be a string when present`;
119
+ }
120
+ return null;
121
+ }
122
+ function validateCorrectiveAction(value, index) {
123
+ if (!isPlainObject(value)) {
124
+ return `guidance.correctiveActions[${index}] must be an object`;
125
+ }
126
+ const action = value;
127
+ if (typeof action.label !== "string" || action.label.length === 0) {
128
+ return `guidance.correctiveActions[${index}].label must be a non-empty string`;
129
+ }
130
+ if (action.description !== void 0 && typeof action.description !== "string") {
131
+ return `guidance.correctiveActions[${index}].description must be a string when present`;
132
+ }
133
+ if (action.actionId !== void 0 && typeof action.actionId !== "string") {
134
+ return `guidance.correctiveActions[${index}].actionId must be a string when present`;
135
+ }
136
+ if (action.parameters !== void 0 && !isPlainObject(action.parameters)) {
137
+ return `guidance.correctiveActions[${index}].parameters must be an object when present`;
138
+ }
139
+ if (action.target !== void 0 && !isPlainObject(action.target)) {
140
+ return `guidance.correctiveActions[${index}].target must be an object when present`;
141
+ }
142
+ if (action.requiresConfirmation !== void 0 && typeof action.requiresConfirmation !== "boolean") {
143
+ return `guidance.correctiveActions[${index}].requiresConfirmation must be a boolean when present`;
144
+ }
145
+ return null;
146
+ }
84
147
  function isPlainObject(value) {
85
148
  return value !== null && typeof value === "object" && !Array.isArray(value);
86
149
  }
@@ -205,6 +268,7 @@ function buildSuccessOutcome(binding, engineVersion, decision, execution, inputH
205
268
  policyVersion: binding.version,
206
269
  result: mapped.result ?? decision.result,
207
270
  reason: mapped.reason ?? decision.reason,
271
+ guidance: mapped.guidance ?? decision.guidance,
208
272
  metadata: {
209
273
  ...mapped.metadata ?? {},
210
274
  opaDecision: decision
@@ -227,7 +291,6 @@ function buildSuccessOutcome(binding, engineVersion, decision, execution, inputH
227
291
  bundleRevisionStatus: selection.bundleRevisionStatus,
228
292
  provenance: execution.provenance,
229
293
  conditionResults: decision.conditionResults,
230
- factsUsed: decision.factsUsed,
231
294
  obligations: decision.obligations
232
295
  })
233
296
  }
@@ -246,6 +309,19 @@ function makeFailureOutcome(binding, engineVersion, error, reason, onError, inpu
246
309
  policyVersion: binding.version,
247
310
  result: "block",
248
311
  reason,
312
+ guidance: {
313
+ summary: "OPA policy evaluation could not complete.",
314
+ factsUsed: [
315
+ { name: "opaFailureKind", value: error, label: "Failure kind" },
316
+ { name: "decisionPath", value: binding.decisionPath, label: "Decision path" }
317
+ ],
318
+ correctiveActions: [
319
+ {
320
+ label: "Check OPA policy engine",
321
+ description: "Verify the OPA service is reachable, serving the expected bundle, and returning the Fabric OPA decision shape."
322
+ }
323
+ ]
324
+ },
249
325
  metadata: {
250
326
  opaError: error
251
327
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bundle-selector.ts","../src/decision-schema.ts","../src/hash.ts","../src/factory.ts","../src/executor-client.ts","../src/executor-http.ts"],"names":["createHash"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { OpaPolicyBinding, OpaPolicyExecution } from \"./types\";\n\nexport interface BundleSelection {\n\tbundleRevision?: string;\n\t/**\n\t * Set to `\"ambiguous\"` when OPA reports multiple bundles and the binding\n\t * did not pick one with `bundleName`. The adapter records this on the\n\t * evidence so dashboards can flag policies that need explicit selectors.\n\t * `\"missing\"` is set when provenance was expected but absent.\n\t */\n\tbundleRevisionStatus?: \"ambiguous\" | \"missing\";\n}\n\n/**\n * Determine which OPA bundle revision applies to this decision.\n *\n * Rules (in order):\n * 1. If the executor already populated `execution.bundleRevision`, use it.\n * 2. If `binding.bundleName` is set, look it up in `provenance.bundles`.\n * 3. If exactly one bundle is reported, use its revision unambiguously.\n * 4. If multiple bundles are reported and no selector exists, mark\n * `bundleRevisionStatus: \"ambiguous\"`.\n * 5. If no provenance is reported at all, return `{}` — the caller decides\n * whether absence is meaningful (it is not, for executors that don't\n * carry provenance).\n */\nexport function selectBundleRevision(\n\texecution: OpaPolicyExecution,\n\tbinding: OpaPolicyBinding,\n): BundleSelection {\n\tif (typeof execution.bundleRevision === \"string\" && execution.bundleRevision.length > 0) {\n\t\treturn { bundleRevision: execution.bundleRevision };\n\t}\n\n\tconst bundles = readBundles(execution.provenance);\n\tif (!bundles) return {};\n\n\tconst names = Object.keys(bundles);\n\tif (names.length === 0) return {};\n\n\tif (binding.bundleName) {\n\t\tconst revision = bundles[binding.bundleName]?.revision;\n\t\treturn typeof revision === \"string\" && revision.length > 0\n\t\t\t? { bundleRevision: revision }\n\t\t\t: {};\n\t}\n\n\tif (names.length === 1) {\n\t\tconst only = names[0];\n\t\t// names.length === 1 guarantees names[0] is defined, but the\n\t\t// non-null assertion satisfies noUncheckedIndexedAccess if enabled.\n\t\tconst revision = only !== undefined ? bundles[only]?.revision : undefined;\n\t\treturn typeof revision === \"string\" && revision.length > 0\n\t\t\t? { bundleRevision: revision }\n\t\t\t: {};\n\t}\n\n\treturn { bundleRevisionStatus: \"ambiguous\" };\n}\n\nfunction readBundles(\n\tprovenance: Record<string, unknown> | undefined,\n): Record<string, { revision?: unknown }> | undefined {\n\tif (!provenance || typeof provenance !== \"object\") return undefined;\n\tconst b = (provenance as { bundles?: unknown }).bundles;\n\tif (!b || typeof b !== \"object\" || Array.isArray(b)) return undefined;\n\treturn b as Record<string, { revision?: unknown }>;\n}\n","import type { PolicyEvaluationResult } from \"@fabricorg/platform/policies\";\nimport type { OpaDecision } from \"./types\";\n\nconst POLICY_RESULTS: readonly PolicyEvaluationResult[] = [\"pass\", \"warn\", \"block\"];\n\nexport type OpaDecisionParseResult =\n\t| { ok: true; decision: OpaDecision }\n\t| { ok: false; error: string };\n\n/**\n * Hand-rolled validator for the Rego \"house style\" decision shape. Avoids a\n * runtime zod dependency to keep the adapter zero-dep.\n *\n * Accepts a raw OPA result and either returns the parsed `OpaDecision` or a\n * single human-readable error string describing the first violation. We don't\n * accumulate every error: when audit evidence has to record \"OPA returned\n * something invalid\", one precise reason is more useful than a list.\n */\nexport function parseOpaDecision(raw: unknown): OpaDecisionParseResult {\n\tif (raw === null || typeof raw !== \"object\") {\n\t\treturn { ok: false, error: \"decision must be an object\" };\n\t}\n\n\tconst d = raw as Record<string, unknown>;\n\n\tif (typeof d.result !== \"string\" || !POLICY_RESULTS.includes(d.result as PolicyEvaluationResult)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: `result must be \"pass\" | \"warn\" | \"block\" (got ${JSON.stringify(d.result)})`,\n\t\t};\n\t}\n\n\tif (d.reason !== undefined && typeof d.reason !== \"string\") {\n\t\treturn { ok: false, error: \"reason must be a string when present\" };\n\t}\n\n\tif (d.conditionResults !== undefined) {\n\t\tif (!Array.isArray(d.conditionResults)) {\n\t\t\treturn { ok: false, error: \"conditionResults must be an array when present\" };\n\t\t}\n\t\tfor (let i = 0; i < d.conditionResults.length; i += 1) {\n\t\t\tconst err = validateConditionResult(d.conditionResults[i], i);\n\t\t\tif (err) return { ok: false, error: err };\n\t\t}\n\t}\n\n\tif (d.factsUsed !== undefined && !isPlainObject(d.factsUsed)) {\n\t\treturn { ok: false, error: \"factsUsed must be an object when present\" };\n\t}\n\n\tif (d.obligations !== undefined && !isPlainObject(d.obligations)) {\n\t\treturn { ok: false, error: \"obligations must be an object when present\" };\n\t}\n\n\treturn { ok: true, decision: d as unknown as OpaDecision };\n}\n\nfunction validateConditionResult(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `conditionResults[${index}] must be an object`;\n\t}\n\tconst c = value as Record<string, unknown>;\n\tif (typeof c.conditionId !== \"string\" || c.conditionId.length === 0) {\n\t\treturn `conditionResults[${index}].conditionId must be a non-empty string`;\n\t}\n\tif (typeof c.passed !== \"boolean\") {\n\t\treturn `conditionResults[${index}].passed must be a boolean`;\n\t}\n\tif (typeof c.result !== \"string\" || !POLICY_RESULTS.includes(c.result as PolicyEvaluationResult)) {\n\t\treturn `conditionResults[${index}].result must be \"pass\" | \"warn\" | \"block\"`;\n\t}\n\tif (c.reason !== undefined && typeof c.reason !== \"string\") {\n\t\treturn `conditionResults[${index}].reason must be a string when present`;\n\t}\n\treturn null;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","import { createHash } from \"node:crypto\";\n\n/**\n * Stable JSON stringify — sorts object keys recursively so two\n * structurally-equal inputs produce the same string regardless of property\n * insertion order. Required for hash determinism across builds of the same\n * `buildInput` function.\n */\nexport function stableStringify(value: unknown): string {\n\tif (value === undefined) return \"null\";\n\tif (value === null || typeof value !== \"object\") return JSON.stringify(value);\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map(stableStringify).join(\",\")}]`;\n\t}\n\tconst obj = value as Record<string, unknown>;\n\tconst keys = Object.keys(obj).sort();\n\treturn `{${keys\n\t\t.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`)\n\t\t.join(\",\")}}`;\n}\n\n/**\n * Default input hasher: SHA-256 over a stable stringification.\n * Format: `sha256:<hex>` — namespaced so future migrations to a different\n * algorithm can be detected by a prefix check in evidence dashboards.\n */\nexport function defaultHashInput(input: Record<string, unknown>): string {\n\tconst hex = createHash(\"sha256\").update(stableStringify(input)).digest(\"hex\");\n\treturn `sha256:${hex}`;\n}\n","import type {\n\tPolicyContext,\n\tPolicyEvaluator,\n\tPolicyOutcome,\n} from \"@fabricorg/platform/policies\";\n\nimport { selectBundleRevision } from \"./bundle-selector\";\nimport { parseOpaDecision } from \"./decision-schema\";\nimport { defaultHashInput } from \"./hash\";\nimport type {\n\tCreateOpaPolicyEvaluatorOptions,\n\tOpaDecision,\n\tOpaPolicyBinding,\n\tOpaPolicyClient,\n\tOpaPolicyExecution,\n\tOpaPolicyExecutor,\n\tOpaPolicyFailureKind,\n} from \"./types\";\n\nconst DEFAULT_SERVICE_KEY = \"opa\";\nconst ENGINE_NAME = \"opa\";\n\n/**\n * Build a Fabric `PolicyEvaluator` that delegates decision-making to an OPA\n * (Open Policy Agent) deployment.\n *\n * The adapter accepts either of two service shapes under\n * `ctx.services[serviceKey]`:\n *\n * - `OpaPolicyExecutor` (preferred) — `execute(path, input)` returning a rich\n * `OpaPolicyExecution` (decision plus `decisionId`, `bundleRevision`,\n * `opaVersion`, `provenance`). Ship one with {@link executorFromOpaHttp} or\n * {@link executorFromOpaClient}.\n * - `OpaPolicyClient` — `evaluate(path, input)` returning the raw decision\n * only. Compatible with the high-level `@open-policy-agent/opa` SDK at the\n * cost of OPA-side provenance.\n *\n * If both methods are present, `execute` is preferred.\n *\n * The evaluator:\n *\n * 1. Resolves the service from `ctx.services[serviceKey]`.\n * 2. Builds a JSON input snapshot via `buildInput(ctx)` — domain code that\n * snapshots facts the engine needs. OPA never reaches into the database\n * directly; all facts flow through this function.\n * 3. Calls OPA at `binding.decisionPath`.\n * 4. Validates the response against the house-style shape (`OpaDecision`).\n * 5. Maps the decision to a `PolicyOutcome` and attaches engine provenance\n * under `dispatchEvidence.engine` — `name`, optional `version`, and\n * metadata covering `decisionPath`, `regoPackage`, `inputHash`, plus (when\n * the executor surfaces them) `decisionId`, `bundleName`, `bundleRevision`,\n * `bundleRevisionStatus`, and the raw `provenance` block.\n *\n * Failures (missing client, build failure, network failure, malformed\n * response) are governed by `onError`. Default `\"block\"` honors Fabric's\n * default-deny posture and records the failure category under\n * `engine.metadata.error`.\n */\nexport function createOpaPolicyEvaluator<TDb = unknown>(\n\toptions: CreateOpaPolicyEvaluatorOptions<TDb>,\n): PolicyEvaluator<TDb> {\n\tconst {\n\t\tbinding,\n\t\tbuildInput,\n\t\tserviceKey = DEFAULT_SERVICE_KEY,\n\t\tonError = \"block\",\n\t\tpreviewSafe = false,\n\t\tengineVersion,\n\t\tmapDecision,\n\t\thashInput = defaultHashInput,\n\t} = options;\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tversion: binding.version,\n\t\tpreviewSafe,\n\t\tevaluate: async (ctx) => {\n\t\t\tconst service = ctx.services?.[serviceKey];\n\t\t\tconst transport = resolveTransport(service);\n\t\t\tif (!transport) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"client_unavailable\",\n\t\t\t\t\t`No OPA client/executor at ctx.services[\"${serviceKey}\"]`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet input: Record<string, unknown>;\n\t\t\ttry {\n\t\t\t\tinput = await buildInput(ctx);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"input_build_failed\",\n\t\t\t\t\t`buildInput threw: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet inputHash: string | undefined;\n\t\t\ttry {\n\t\t\t\tinputHash = hashInput(input);\n\t\t\t} catch {\n\t\t\t\t// hashing is best-effort — if a custom hasher throws, omit the\n\t\t\t\t// field rather than fail the policy.\n\t\t\t}\n\n\t\t\tlet execution: OpaPolicyExecution;\n\t\t\ttry {\n\t\t\t\texecution = await transport(binding.decisionPath, input);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"evaluation_failed\",\n\t\t\t\t\t`OPA evaluation failed: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst parsed = parseOpaDecision(execution.decision);\n\t\t\tif (!parsed.ok) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"invalid_response\",\n\t\t\t\t\t`OPA returned malformed decision: ${parsed.error}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t\texecution,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn buildSuccessOutcome(\n\t\t\t\tbinding,\n\t\t\t\tengineVersion,\n\t\t\t\tparsed.decision,\n\t\t\t\texecution,\n\t\t\t\tinputHash,\n\t\t\t\tctx,\n\t\t\t\tmapDecision,\n\t\t\t);\n\t\t},\n\t};\n}\n\n/**\n * Discriminates between the rich executor shape and the legacy client shape.\n * Returns a uniform `(path, input) => OpaPolicyExecution` transport, or\n * `null` if the service doesn't implement either contract.\n *\n * `execute` is preferred when both are present so a v0.1 client wrapped by a\n * richer executor still wins.\n */\nfunction resolveTransport(\n\tservice: unknown,\n): ((path: string, input: unknown) => Promise<OpaPolicyExecution>) | null {\n\tif (!service || typeof service !== \"object\") return null;\n\tconst exec = (service as Partial<OpaPolicyExecutor>).execute;\n\tif (typeof exec === \"function\") {\n\t\treturn (path, input) => (service as OpaPolicyExecutor).execute(path, input);\n\t}\n\tconst eval_ = (service as Partial<OpaPolicyClient>).evaluate;\n\tif (typeof eval_ === \"function\") {\n\t\treturn async (path, input) => ({\n\t\t\tdecision: await (service as OpaPolicyClient).evaluate(path, input),\n\t\t});\n\t}\n\treturn null;\n}\n\nfunction buildSuccessOutcome<TDb>(\n\tbinding: OpaPolicyBinding,\n\tengineVersion: string | undefined,\n\tdecision: OpaDecision,\n\texecution: OpaPolicyExecution,\n\tinputHash: string | undefined,\n\tctx: PolicyContext<TDb>,\n\tmapDecision: CreateOpaPolicyEvaluatorOptions<TDb>[\"mapDecision\"],\n): PolicyOutcome {\n\tconst selection = selectBundleRevision(execution, binding);\n\tconst mapped = mapDecision\n\t\t? mapDecision(decision, ctx, execution)\n\t\t: { result: decision.result, reason: decision.reason };\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: mapped.result ?? decision.result,\n\t\treason: mapped.reason ?? decision.reason,\n\t\tmetadata: {\n\t\t\t...(mapped.metadata ?? {}),\n\t\t\topaDecision: decision,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: execution.opaVersion ?? engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\tdecisionId: execution.decisionId,\n\t\t\t\t\tbundleName: binding.bundleName,\n\t\t\t\t\tbundleRevision: selection.bundleRevision,\n\t\t\t\t\tbundleRevisionStatus: selection.bundleRevisionStatus,\n\t\t\t\t\tprovenance: execution.provenance,\n\t\t\t\t\tconditionResults: decision.conditionResults,\n\t\t\t\t\tfactsUsed: decision.factsUsed,\n\t\t\t\t\tobligations: decision.obligations,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction makeFailureOutcome(\n\tbinding: OpaPolicyBinding,\n\tengineVersion: string | undefined,\n\terror: OpaPolicyFailureKind,\n\treason: string,\n\tonError: \"block\" | \"throw\",\n\tinputHash?: string,\n\texecution?: OpaPolicyExecution,\n): PolicyOutcome {\n\tif (onError === \"throw\") {\n\t\tconst err = new Error(reason);\n\t\t(err as Error & { kind?: OpaPolicyFailureKind }).kind = error;\n\t\tthrow err;\n\t}\n\n\tconst selection = execution ? selectBundleRevision(execution, binding) : {};\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: \"block\",\n\t\treason,\n\t\tmetadata: {\n\t\t\topaError: error,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: execution?.opaVersion ?? engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\tdecisionId: execution?.decisionId,\n\t\t\t\t\tbundleName: binding.bundleName,\n\t\t\t\t\tbundleRevision: selection.bundleRevision,\n\t\t\t\t\tbundleRevisionStatus: selection.bundleRevisionStatus,\n\t\t\t\t\tprovenance: execution?.provenance,\n\t\t\t\t\terror,\n\t\t\t\t\terrorReason: reason,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction stripUndefined(obj: Record<string, unknown>): Record<string, unknown> {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(obj)) {\n\t\tif (v !== undefined) out[k] = v;\n\t}\n\treturn out;\n}\n\nfunction formatError(err: unknown): string {\n\tif (err instanceof Error) return err.message;\n\tif (typeof err === \"string\") return err;\n\ttry {\n\t\treturn JSON.stringify(err);\n\t} catch {\n\t\treturn String(err);\n\t}\n}\n","import type {\n\tOpaPolicyClient,\n\tOpaPolicyExecution,\n\tOpaPolicyExecutor,\n} from \"./types\";\n\n/**\n * Wrap an `OpaPolicyClient` (the high-level `@open-policy-agent/opa` SDK\n * shape) as an {@link OpaPolicyExecutor}. The resulting executor carries no\n * OPA-side provenance — the high-level SDK discards `decisionId` and\n * `provenance` from the response — but does centralize the\n * `(path, input) => execution` plumbing so hosts can choose at startup whether\n * to wire a client or a full executor.\n *\n * For full provenance (decisionId, bundleRevision, opaVersion), prefer\n * {@link executorFromOpaHttp}.\n */\nexport function executorFromOpaClient(client: OpaPolicyClient): OpaPolicyExecutor {\n\treturn {\n\t\tasync execute(path: string, input: unknown): Promise<OpaPolicyExecution> {\n\t\t\tconst decision = await client.evaluate(path, input);\n\t\t\treturn { decision };\n\t\t},\n\t};\n}\n","import type { OpaPolicyExecution, OpaPolicyExecutor } from \"./types\";\n\nexport interface OpaHttpExecutorOptions {\n\t/**\n\t * Base URL of the OPA server, e.g. `\"http://localhost:8181\"` or\n\t * `\"https://opa.internal.example.com\"`. Trailing slash is permitted; the\n\t * executor normalizes it.\n\t */\n\tbaseUrl: string;\n\t/**\n\t * Override for `globalThis.fetch`. Lets the host inject a fetch instance\n\t * with retries, mTLS, OpenTelemetry instrumentation, etc. Defaults to\n\t * `globalThis.fetch`.\n\t */\n\tfetch?: typeof globalThis.fetch;\n\t/** Extra request headers (e.g. `Authorization`). */\n\theaders?: Record<string, string>;\n\t/**\n\t * Request OPA-side provenance (`decision_id`, `provenance.version`,\n\t * `provenance.bundles[*].revision`) via `?provenance=true`. Defaults to\n\t * `true` — turning it off forfeits OPA's contribution to audit evidence\n\t * and is rarely what you want.\n\t */\n\tprovenance?: boolean;\n}\n\ninterface OpaHttpResponseBody {\n\tresult?: unknown;\n\tdecision_id?: string;\n\tprovenance?: {\n\t\tversion?: string;\n\t\tbuild_commit?: string;\n\t\tbuild_timestamp?: string;\n\t\tbuild_host?: string;\n\t\tbundles?: Record<string, { revision?: string }>;\n\t};\n}\n\n/**\n * Build an {@link OpaPolicyExecutor} that talks to OPA's REST API directly.\n *\n * POSTs to `{baseUrl}/v1/data/{path}?provenance=true` with body\n * `{ \"input\": ... }`. Parses the snake_case response and lifts:\n *\n * - `result` → `execution.decision`\n * - `decision_id` → `execution.decisionId`\n * - `provenance.version` → `execution.opaVersion`\n * - `provenance` (whole block) → `execution.provenance`\n *\n * Bundle revision selection happens in the factory, not the executor, because\n * it depends on `binding.bundleName`.\n *\n * Calling this in environments without `globalThis.fetch` (older Node) throws\n * at call time; pass `fetch: nodeFetch` or `fetch: undici-fetch` etc. via the\n * options to support those runtimes explicitly.\n */\nexport function executorFromOpaHttp(opts: OpaHttpExecutorOptions): OpaPolicyExecutor {\n\tconst baseUrl = stripTrailingSlash(opts.baseUrl);\n\tconst provenance = opts.provenance ?? true;\n\tconst customFetch = opts.fetch;\n\tconst headers = {\n\t\t\"content-type\": \"application/json\",\n\t\taccept: \"application/json\",\n\t\t...(opts.headers ?? {}),\n\t};\n\n\treturn {\n\t\tasync execute(path: string, input: unknown): Promise<OpaPolicyExecution> {\n\t\t\tconst fetchImpl = customFetch ?? globalThis.fetch;\n\t\t\tif (typeof fetchImpl !== \"function\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"executorFromOpaHttp: no fetch implementation available. Pass `fetch` in options or run on a runtime with `globalThis.fetch`.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst url = `${baseUrl}/v1/data/${stripLeadingSlash(path)}${\n\t\t\t\tprovenance ? \"?provenance=true\" : \"\"\n\t\t\t}`;\n\t\t\tconst response = await fetchImpl(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({ input }),\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst text = await safeReadText(response);\n\t\t\t\tthrow new Error(`OPA HTTP ${response.status} at ${url}: ${truncate(text, 500)}`);\n\t\t\t}\n\n\t\t\tconst body = (await response.json()) as OpaHttpResponseBody;\n\n\t\t\treturn {\n\t\t\t\tdecision: body.result,\n\t\t\t\tdecisionId: body.decision_id,\n\t\t\t\topaVersion: body.provenance?.version,\n\t\t\t\tprovenance: body.provenance as Record<string, unknown> | undefined,\n\t\t\t};\n\t\t},\n\t};\n}\n\nfunction stripTrailingSlash(s: string): string {\n\treturn s.replace(/\\/+$/, \"\");\n}\n\nfunction stripLeadingSlash(s: string): string {\n\treturn s.replace(/^\\/+/, \"\");\n}\n\nasync function safeReadText(response: Response): Promise<string> {\n\ttry {\n\t\treturn await response.text();\n\t} catch {\n\t\treturn \"<unreadable body>\";\n\t}\n}\n\nfunction truncate(s: string, max: number): string {\n\treturn s.length <= max ? s : `${s.slice(0, max)}…`;\n}\n"]}
1
+ {"version":3,"sources":["../src/bundle-selector.ts","../src/decision-schema.ts","../src/hash.ts","../src/factory.ts","../src/executor-client.ts","../src/executor-http.ts"],"names":["createHash"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { OpaPolicyBinding, OpaPolicyExecution } from \"./types\";\n\nexport interface BundleSelection {\n\tbundleRevision?: string;\n\t/**\n\t * Set to `\"ambiguous\"` when OPA reports multiple bundles and the binding\n\t * did not pick one with `bundleName`. The adapter records this on the\n\t * evidence so dashboards can flag policies that need explicit selectors.\n\t * `\"missing\"` is set when provenance was expected but absent.\n\t */\n\tbundleRevisionStatus?: \"ambiguous\" | \"missing\";\n}\n\n/**\n * Determine which OPA bundle revision applies to this decision.\n *\n * Rules (in order):\n * 1. If the executor already populated `execution.bundleRevision`, use it.\n * 2. If `binding.bundleName` is set, look it up in `provenance.bundles`.\n * 3. If exactly one bundle is reported, use its revision unambiguously.\n * 4. If multiple bundles are reported and no selector exists, mark\n * `bundleRevisionStatus: \"ambiguous\"`.\n * 5. If no provenance is reported at all, return `{}` — the caller decides\n * whether absence is meaningful (it is not, for executors that don't\n * carry provenance).\n */\nexport function selectBundleRevision(\n\texecution: OpaPolicyExecution,\n\tbinding: OpaPolicyBinding,\n): BundleSelection {\n\tif (typeof execution.bundleRevision === \"string\" && execution.bundleRevision.length > 0) {\n\t\treturn { bundleRevision: execution.bundleRevision };\n\t}\n\n\tconst bundles = readBundles(execution.provenance);\n\tif (!bundles) return {};\n\n\tconst names = Object.keys(bundles);\n\tif (names.length === 0) return {};\n\n\tif (binding.bundleName) {\n\t\tconst revision = bundles[binding.bundleName]?.revision;\n\t\treturn typeof revision === \"string\" && revision.length > 0\n\t\t\t? { bundleRevision: revision }\n\t\t\t: {};\n\t}\n\n\tif (names.length === 1) {\n\t\tconst only = names[0];\n\t\t// names.length === 1 guarantees names[0] is defined, but the\n\t\t// non-null assertion satisfies noUncheckedIndexedAccess if enabled.\n\t\tconst revision = only !== undefined ? bundles[only]?.revision : undefined;\n\t\treturn typeof revision === \"string\" && revision.length > 0\n\t\t\t? { bundleRevision: revision }\n\t\t\t: {};\n\t}\n\n\treturn { bundleRevisionStatus: \"ambiguous\" };\n}\n\nfunction readBundles(\n\tprovenance: Record<string, unknown> | undefined,\n): Record<string, { revision?: unknown }> | undefined {\n\tif (!provenance || typeof provenance !== \"object\") return undefined;\n\tconst b = (provenance as { bundles?: unknown }).bundles;\n\tif (!b || typeof b !== \"object\" || Array.isArray(b)) return undefined;\n\treturn b as Record<string, { revision?: unknown }>;\n}\n","import type { PolicyEvaluationResult } from \"@fabricorg/platform/policies\";\nimport type { OpaDecision } from \"./types\";\n\nconst POLICY_RESULTS: readonly PolicyEvaluationResult[] = [\"pass\", \"warn\", \"block\"];\n\nexport type OpaDecisionParseResult =\n\t| { ok: true; decision: OpaDecision }\n\t| { ok: false; error: string };\n\n/**\n * Hand-rolled validator for the Rego \"house style\" decision shape. Avoids a\n * runtime zod dependency to keep the adapter zero-dep.\n *\n * Accepts a raw OPA result and either returns the parsed `OpaDecision` or a\n * single human-readable error string describing the first violation. We don't\n * accumulate every error: when audit evidence has to record \"OPA returned\n * something invalid\", one precise reason is more useful than a list.\n */\nexport function parseOpaDecision(raw: unknown): OpaDecisionParseResult {\n\tif (raw === null || typeof raw !== \"object\") {\n\t\treturn { ok: false, error: \"decision must be an object\" };\n\t}\n\n\tconst d = raw as Record<string, unknown>;\n\n\tif (typeof d.result !== \"string\" || !POLICY_RESULTS.includes(d.result as PolicyEvaluationResult)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: `result must be \"pass\" | \"warn\" | \"block\" (got ${JSON.stringify(d.result)})`,\n\t\t};\n\t}\n\n\tif (d.reason !== undefined && typeof d.reason !== \"string\") {\n\t\treturn { ok: false, error: \"reason must be a string when present\" };\n\t}\n\n\tif (d.conditionResults !== undefined) {\n\t\tif (!Array.isArray(d.conditionResults)) {\n\t\t\treturn { ok: false, error: \"conditionResults must be an array when present\" };\n\t\t}\n\t\tfor (let i = 0; i < d.conditionResults.length; i += 1) {\n\t\t\tconst err = validateConditionResult(d.conditionResults[i], i);\n\t\t\tif (err) return { ok: false, error: err };\n\t\t}\n\t}\n\n\tif (d.guidance !== undefined) {\n\t\tconst err = validateGuidance(d.guidance);\n\t\tif (err) return { ok: false, error: err };\n\t}\n\n\tif (d.obligations !== undefined && !isPlainObject(d.obligations)) {\n\t\treturn { ok: false, error: \"obligations must be an object when present\" };\n\t}\n\n\treturn { ok: true, decision: d as unknown as OpaDecision };\n}\n\nfunction validateConditionResult(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `conditionResults[${index}] must be an object`;\n\t}\n\tconst c = value as Record<string, unknown>;\n\tif (typeof c.conditionId !== \"string\" || c.conditionId.length === 0) {\n\t\treturn `conditionResults[${index}].conditionId must be a non-empty string`;\n\t}\n\tif (typeof c.passed !== \"boolean\") {\n\t\treturn `conditionResults[${index}].passed must be a boolean`;\n\t}\n\tif (typeof c.result !== \"string\" || !POLICY_RESULTS.includes(c.result as PolicyEvaluationResult)) {\n\t\treturn `conditionResults[${index}].result must be \"pass\" | \"warn\" | \"block\"`;\n\t}\n\tif (c.reason !== undefined && typeof c.reason !== \"string\") {\n\t\treturn `conditionResults[${index}].reason must be a string when present`;\n\t}\n\treturn null;\n}\n\nfunction validateGuidance(value: unknown): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn \"guidance must be an object when present\";\n\t}\n\tconst guidance = value as Record<string, unknown>;\n\tif (guidance.summary !== undefined && typeof guidance.summary !== \"string\") {\n\t\treturn \"guidance.summary must be a string when present\";\n\t}\n\tif (!Array.isArray(guidance.factsUsed)) {\n\t\treturn \"guidance.factsUsed must be an array\";\n\t}\n\tfor (let i = 0; i < guidance.factsUsed.length; i += 1) {\n\t\tconst err = validatePolicyFact(guidance.factsUsed[i], i);\n\t\tif (err) return err;\n\t}\n\tif (!Array.isArray(guidance.correctiveActions)) {\n\t\treturn \"guidance.correctiveActions must be an array\";\n\t}\n\tfor (let i = 0; i < guidance.correctiveActions.length; i += 1) {\n\t\tconst err = validateCorrectiveAction(guidance.correctiveActions[i], i);\n\t\tif (err) return err;\n\t}\n\treturn null;\n}\n\nfunction validatePolicyFact(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `guidance.factsUsed[${index}] must be an object`;\n\t}\n\tconst fact = value as Record<string, unknown>;\n\tif (typeof fact.name !== \"string\" || fact.name.length === 0) {\n\t\treturn `guidance.factsUsed[${index}].name must be a non-empty string`;\n\t}\n\tif (fact.label !== undefined && typeof fact.label !== \"string\") {\n\t\treturn `guidance.factsUsed[${index}].label must be a string when present`;\n\t}\n\treturn null;\n}\n\nfunction validateCorrectiveAction(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `guidance.correctiveActions[${index}] must be an object`;\n\t}\n\tconst action = value as Record<string, unknown>;\n\tif (typeof action.label !== \"string\" || action.label.length === 0) {\n\t\treturn `guidance.correctiveActions[${index}].label must be a non-empty string`;\n\t}\n\tif (action.description !== undefined && typeof action.description !== \"string\") {\n\t\treturn `guidance.correctiveActions[${index}].description must be a string when present`;\n\t}\n\tif (action.actionId !== undefined && typeof action.actionId !== \"string\") {\n\t\treturn `guidance.correctiveActions[${index}].actionId must be a string when present`;\n\t}\n\tif (action.parameters !== undefined && !isPlainObject(action.parameters)) {\n\t\treturn `guidance.correctiveActions[${index}].parameters must be an object when present`;\n\t}\n\tif (action.target !== undefined && !isPlainObject(action.target)) {\n\t\treturn `guidance.correctiveActions[${index}].target must be an object when present`;\n\t}\n\tif (action.requiresConfirmation !== undefined && typeof action.requiresConfirmation !== \"boolean\") {\n\t\treturn `guidance.correctiveActions[${index}].requiresConfirmation must be a boolean when present`;\n\t}\n\treturn null;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","import { createHash } from \"node:crypto\";\n\n/**\n * Stable JSON stringify — sorts object keys recursively so two\n * structurally-equal inputs produce the same string regardless of property\n * insertion order. Required for hash determinism across builds of the same\n * `buildInput` function.\n */\nexport function stableStringify(value: unknown): string {\n\tif (value === undefined) return \"null\";\n\tif (value === null || typeof value !== \"object\") return JSON.stringify(value);\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map(stableStringify).join(\",\")}]`;\n\t}\n\tconst obj = value as Record<string, unknown>;\n\tconst keys = Object.keys(obj).sort();\n\treturn `{${keys\n\t\t.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`)\n\t\t.join(\",\")}}`;\n}\n\n/**\n * Default input hasher: SHA-256 over a stable stringification.\n * Format: `sha256:<hex>` — namespaced so future migrations to a different\n * algorithm can be detected by a prefix check in evidence dashboards.\n */\nexport function defaultHashInput(input: Record<string, unknown>): string {\n\tconst hex = createHash(\"sha256\").update(stableStringify(input)).digest(\"hex\");\n\treturn `sha256:${hex}`;\n}\n","import type {\n\tPolicyContext,\n\tPolicyEvaluator,\n\tPolicyOutcome,\n} from \"@fabricorg/platform/policies\";\n\nimport { selectBundleRevision } from \"./bundle-selector\";\nimport { parseOpaDecision } from \"./decision-schema\";\nimport { defaultHashInput } from \"./hash\";\nimport type {\n\tCreateOpaPolicyEvaluatorOptions,\n\tOpaDecision,\n\tOpaPolicyBinding,\n\tOpaPolicyClient,\n\tOpaPolicyExecution,\n\tOpaPolicyExecutor,\n\tOpaPolicyFailureKind,\n} from \"./types\";\n\nconst DEFAULT_SERVICE_KEY = \"opa\";\nconst ENGINE_NAME = \"opa\";\n\n/**\n * Build a Fabric `PolicyEvaluator` that delegates decision-making to an OPA\n * (Open Policy Agent) deployment.\n *\n * The adapter accepts either of two service shapes under\n * `ctx.services[serviceKey]`:\n *\n * - `OpaPolicyExecutor` (preferred) — `execute(path, input)` returning a rich\n * `OpaPolicyExecution` (decision plus `decisionId`, `bundleRevision`,\n * `opaVersion`, `provenance`). Ship one with {@link executorFromOpaHttp} or\n * {@link executorFromOpaClient}.\n * - `OpaPolicyClient` — `evaluate(path, input)` returning the raw decision\n * only. Compatible with the high-level `@open-policy-agent/opa` SDK at the\n * cost of OPA-side provenance.\n *\n * If both methods are present, `execute` is preferred.\n *\n * The evaluator:\n *\n * 1. Resolves the service from `ctx.services[serviceKey]`.\n * 2. Builds a JSON input snapshot via `buildInput(ctx)` — domain code that\n * snapshots facts the engine needs. OPA never reaches into the database\n * directly; all facts flow through this function.\n * 3. Calls OPA at `binding.decisionPath`.\n * 4. Validates the response against the house-style shape (`OpaDecision`).\n * 5. Maps the decision to a `PolicyOutcome` and attaches engine provenance\n * under `dispatchEvidence.engine` — `name`, optional `version`, and\n * metadata covering `decisionPath`, `regoPackage`, `inputHash`, plus (when\n * the executor surfaces them) `decisionId`, `bundleName`, `bundleRevision`,\n * `bundleRevisionStatus`, and the raw `provenance` block.\n *\n * Failures (missing client, build failure, network failure, malformed\n * response) are governed by `onError`. Default `\"block\"` honors Fabric's\n * default-deny posture and records the failure category under\n * `engine.metadata.error`.\n */\nexport function createOpaPolicyEvaluator<TDb = unknown>(\n\toptions: CreateOpaPolicyEvaluatorOptions<TDb>,\n): PolicyEvaluator<TDb> {\n\tconst {\n\t\tbinding,\n\t\tbuildInput,\n\t\tserviceKey = DEFAULT_SERVICE_KEY,\n\t\tonError = \"block\",\n\t\tpreviewSafe = false,\n\t\tengineVersion,\n\t\tmapDecision,\n\t\thashInput = defaultHashInput,\n\t} = options;\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tversion: binding.version,\n\t\tpreviewSafe,\n\t\tevaluate: async (ctx) => {\n\t\t\tconst service = ctx.services?.[serviceKey];\n\t\t\tconst transport = resolveTransport(service);\n\t\t\tif (!transport) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"client_unavailable\",\n\t\t\t\t\t`No OPA client/executor at ctx.services[\"${serviceKey}\"]`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet input: Record<string, unknown>;\n\t\t\ttry {\n\t\t\t\tinput = await buildInput(ctx);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"input_build_failed\",\n\t\t\t\t\t`buildInput threw: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet inputHash: string | undefined;\n\t\t\ttry {\n\t\t\t\tinputHash = hashInput(input);\n\t\t\t} catch {\n\t\t\t\t// hashing is best-effort — if a custom hasher throws, omit the\n\t\t\t\t// field rather than fail the policy.\n\t\t\t}\n\n\t\t\tlet execution: OpaPolicyExecution;\n\t\t\ttry {\n\t\t\t\texecution = await transport(binding.decisionPath, input);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"evaluation_failed\",\n\t\t\t\t\t`OPA evaluation failed: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst parsed = parseOpaDecision(execution.decision);\n\t\t\tif (!parsed.ok) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"invalid_response\",\n\t\t\t\t\t`OPA returned malformed decision: ${parsed.error}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t\texecution,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn buildSuccessOutcome(\n\t\t\t\tbinding,\n\t\t\t\tengineVersion,\n\t\t\t\tparsed.decision,\n\t\t\t\texecution,\n\t\t\t\tinputHash,\n\t\t\t\tctx,\n\t\t\t\tmapDecision,\n\t\t\t);\n\t\t},\n\t};\n}\n\n/**\n * Discriminates between the rich executor shape and the legacy client shape.\n * Returns a uniform `(path, input) => OpaPolicyExecution` transport, or\n * `null` if the service doesn't implement either contract.\n *\n * `execute` is preferred when both are present so a v0.1 client wrapped by a\n * richer executor still wins.\n */\nfunction resolveTransport(\n\tservice: unknown,\n): ((path: string, input: unknown) => Promise<OpaPolicyExecution>) | null {\n\tif (!service || typeof service !== \"object\") return null;\n\tconst exec = (service as Partial<OpaPolicyExecutor>).execute;\n\tif (typeof exec === \"function\") {\n\t\treturn (path, input) => (service as OpaPolicyExecutor).execute(path, input);\n\t}\n\tconst eval_ = (service as Partial<OpaPolicyClient>).evaluate;\n\tif (typeof eval_ === \"function\") {\n\t\treturn async (path, input) => ({\n\t\t\tdecision: await (service as OpaPolicyClient).evaluate(path, input),\n\t\t});\n\t}\n\treturn null;\n}\n\nfunction buildSuccessOutcome<TDb>(\n\tbinding: OpaPolicyBinding,\n\tengineVersion: string | undefined,\n\tdecision: OpaDecision,\n\texecution: OpaPolicyExecution,\n\tinputHash: string | undefined,\n\tctx: PolicyContext<TDb>,\n\tmapDecision: CreateOpaPolicyEvaluatorOptions<TDb>[\"mapDecision\"],\n): PolicyOutcome {\n\tconst selection = selectBundleRevision(execution, binding);\n\tconst mapped = mapDecision\n\t\t? mapDecision(decision, ctx, execution)\n\t\t: { result: decision.result, reason: decision.reason };\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: mapped.result ?? decision.result,\n\t\treason: mapped.reason ?? decision.reason,\n\t\tguidance: mapped.guidance ?? decision.guidance,\n\t\tmetadata: {\n\t\t\t...(mapped.metadata ?? {}),\n\t\t\topaDecision: decision,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: execution.opaVersion ?? engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\tdecisionId: execution.decisionId,\n\t\t\t\t\tbundleName: binding.bundleName,\n\t\t\t\t\tbundleRevision: selection.bundleRevision,\n\t\t\t\t\tbundleRevisionStatus: selection.bundleRevisionStatus,\n\t\t\t\t\tprovenance: execution.provenance,\n\t\t\t\t\tconditionResults: decision.conditionResults,\n\t\t\t\t\tobligations: decision.obligations,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction makeFailureOutcome(\n\tbinding: OpaPolicyBinding,\n\tengineVersion: string | undefined,\n\terror: OpaPolicyFailureKind,\n\treason: string,\n\tonError: \"block\" | \"throw\",\n\tinputHash?: string,\n\texecution?: OpaPolicyExecution,\n): PolicyOutcome {\n\tif (onError === \"throw\") {\n\t\tconst err = new Error(reason);\n\t\t(err as Error & { kind?: OpaPolicyFailureKind }).kind = error;\n\t\tthrow err;\n\t}\n\n\tconst selection = execution ? selectBundleRevision(execution, binding) : {};\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: \"block\",\n\t\treason,\n\t\tguidance: {\n\t\t\tsummary: \"OPA policy evaluation could not complete.\",\n\t\t\tfactsUsed: [\n\t\t\t\t{ name: \"opaFailureKind\", value: error, label: \"Failure kind\" },\n\t\t\t\t{ name: \"decisionPath\", value: binding.decisionPath, label: \"Decision path\" },\n\t\t\t],\n\t\t\tcorrectiveActions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Check OPA policy engine\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Verify the OPA service is reachable, serving the expected bundle, and returning the Fabric OPA decision shape.\",\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\tmetadata: {\n\t\t\topaError: error,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: execution?.opaVersion ?? engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\tdecisionId: execution?.decisionId,\n\t\t\t\t\tbundleName: binding.bundleName,\n\t\t\t\t\tbundleRevision: selection.bundleRevision,\n\t\t\t\t\tbundleRevisionStatus: selection.bundleRevisionStatus,\n\t\t\t\t\tprovenance: execution?.provenance,\n\t\t\t\t\terror,\n\t\t\t\t\terrorReason: reason,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction stripUndefined(obj: Record<string, unknown>): Record<string, unknown> {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(obj)) {\n\t\tif (v !== undefined) out[k] = v;\n\t}\n\treturn out;\n}\n\nfunction formatError(err: unknown): string {\n\tif (err instanceof Error) return err.message;\n\tif (typeof err === \"string\") return err;\n\ttry {\n\t\treturn JSON.stringify(err);\n\t} catch {\n\t\treturn String(err);\n\t}\n}\n","import type {\n\tOpaPolicyClient,\n\tOpaPolicyExecution,\n\tOpaPolicyExecutor,\n} from \"./types\";\n\n/**\n * Wrap an `OpaPolicyClient` (the high-level `@open-policy-agent/opa` SDK\n * shape) as an {@link OpaPolicyExecutor}. The resulting executor carries no\n * OPA-side provenance — the high-level SDK discards `decisionId` and\n * `provenance` from the response — but does centralize the\n * `(path, input) => execution` plumbing so hosts can choose at startup whether\n * to wire a client or a full executor.\n *\n * For full provenance (decisionId, bundleRevision, opaVersion), prefer\n * {@link executorFromOpaHttp}.\n */\nexport function executorFromOpaClient(client: OpaPolicyClient): OpaPolicyExecutor {\n\treturn {\n\t\tasync execute(path: string, input: unknown): Promise<OpaPolicyExecution> {\n\t\t\tconst decision = await client.evaluate(path, input);\n\t\t\treturn { decision };\n\t\t},\n\t};\n}\n","import type { OpaPolicyExecution, OpaPolicyExecutor } from \"./types\";\n\nexport interface OpaHttpExecutorOptions {\n\t/**\n\t * Base URL of the OPA server, e.g. `\"http://localhost:8181\"` or\n\t * `\"https://opa.internal.example.com\"`. Trailing slash is permitted; the\n\t * executor normalizes it.\n\t */\n\tbaseUrl: string;\n\t/**\n\t * Override for `globalThis.fetch`. Lets the host inject a fetch instance\n\t * with retries, mTLS, OpenTelemetry instrumentation, etc. Defaults to\n\t * `globalThis.fetch`.\n\t */\n\tfetch?: typeof globalThis.fetch;\n\t/** Extra request headers (e.g. `Authorization`). */\n\theaders?: Record<string, string>;\n\t/**\n\t * Request OPA-side provenance (`decision_id`, `provenance.version`,\n\t * `provenance.bundles[*].revision`) via `?provenance=true`. Defaults to\n\t * `true` — turning it off forfeits OPA's contribution to audit evidence\n\t * and is rarely what you want.\n\t */\n\tprovenance?: boolean;\n}\n\ninterface OpaHttpResponseBody {\n\tresult?: unknown;\n\tdecision_id?: string;\n\tprovenance?: {\n\t\tversion?: string;\n\t\tbuild_commit?: string;\n\t\tbuild_timestamp?: string;\n\t\tbuild_host?: string;\n\t\tbundles?: Record<string, { revision?: string }>;\n\t};\n}\n\n/**\n * Build an {@link OpaPolicyExecutor} that talks to OPA's REST API directly.\n *\n * POSTs to `{baseUrl}/v1/data/{path}?provenance=true` with body\n * `{ \"input\": ... }`. Parses the snake_case response and lifts:\n *\n * - `result` → `execution.decision`\n * - `decision_id` → `execution.decisionId`\n * - `provenance.version` → `execution.opaVersion`\n * - `provenance` (whole block) → `execution.provenance`\n *\n * Bundle revision selection happens in the factory, not the executor, because\n * it depends on `binding.bundleName`.\n *\n * Calling this in environments without `globalThis.fetch` (older Node) throws\n * at call time; pass `fetch: nodeFetch` or `fetch: undici-fetch` etc. via the\n * options to support those runtimes explicitly.\n */\nexport function executorFromOpaHttp(opts: OpaHttpExecutorOptions): OpaPolicyExecutor {\n\tconst baseUrl = stripTrailingSlash(opts.baseUrl);\n\tconst provenance = opts.provenance ?? true;\n\tconst customFetch = opts.fetch;\n\tconst headers = {\n\t\t\"content-type\": \"application/json\",\n\t\taccept: \"application/json\",\n\t\t...(opts.headers ?? {}),\n\t};\n\n\treturn {\n\t\tasync execute(path: string, input: unknown): Promise<OpaPolicyExecution> {\n\t\t\tconst fetchImpl = customFetch ?? globalThis.fetch;\n\t\t\tif (typeof fetchImpl !== \"function\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"executorFromOpaHttp: no fetch implementation available. Pass `fetch` in options or run on a runtime with `globalThis.fetch`.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst url = `${baseUrl}/v1/data/${stripLeadingSlash(path)}${\n\t\t\t\tprovenance ? \"?provenance=true\" : \"\"\n\t\t\t}`;\n\t\t\tconst response = await fetchImpl(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({ input }),\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst text = await safeReadText(response);\n\t\t\t\tthrow new Error(`OPA HTTP ${response.status} at ${url}: ${truncate(text, 500)}`);\n\t\t\t}\n\n\t\t\tconst body = (await response.json()) as OpaHttpResponseBody;\n\n\t\t\treturn {\n\t\t\t\tdecision: body.result,\n\t\t\t\tdecisionId: body.decision_id,\n\t\t\t\topaVersion: body.provenance?.version,\n\t\t\t\tprovenance: body.provenance as Record<string, unknown> | undefined,\n\t\t\t};\n\t\t},\n\t};\n}\n\nfunction stripTrailingSlash(s: string): string {\n\treturn s.replace(/\\/+$/, \"\");\n}\n\nfunction stripLeadingSlash(s: string): string {\n\treturn s.replace(/^\\/+/, \"\");\n}\n\nasync function safeReadText(response: Response): Promise<string> {\n\ttry {\n\t\treturn await response.text();\n\t} catch {\n\t\treturn \"<unreadable body>\";\n\t}\n}\n\nfunction truncate(s: string, max: number): string {\n\treturn s.length <= max ? s : `${s.slice(0, max)}…`;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { PolicyId, PolicyContext, PolicyEvaluationResult, PolicyOutcome, PolicyEvaluator } from '@fabricorg/platform/policies';
1
+ import { PolicyId, PolicyContext, PolicyEvaluationResult, PolicyGuidance, PolicyOutcome, PolicyEvaluator } from '@fabricorg/platform/policies';
2
2
 
3
3
  /**
4
4
  * Binding between a Fabric platform policy and an OPA decision. Verticals
@@ -87,13 +87,13 @@ interface OpaPolicyExecutor {
87
87
  interface OpaDecision {
88
88
  result: PolicyEvaluationResult;
89
89
  reason?: string;
90
+ guidance?: PolicyGuidance;
90
91
  conditionResults?: Array<{
91
92
  conditionId: string;
92
93
  passed: boolean;
93
94
  result: PolicyEvaluationResult;
94
95
  reason?: string;
95
96
  }>;
96
- factsUsed?: Record<string, unknown>;
97
97
  obligations?: Record<string, unknown>;
98
98
  }
99
99
  /**
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { PolicyId, PolicyContext, PolicyEvaluationResult, PolicyOutcome, PolicyEvaluator } from '@fabricorg/platform/policies';
1
+ import { PolicyId, PolicyContext, PolicyEvaluationResult, PolicyGuidance, PolicyOutcome, PolicyEvaluator } from '@fabricorg/platform/policies';
2
2
 
3
3
  /**
4
4
  * Binding between a Fabric platform policy and an OPA decision. Verticals
@@ -87,13 +87,13 @@ interface OpaPolicyExecutor {
87
87
  interface OpaDecision {
88
88
  result: PolicyEvaluationResult;
89
89
  reason?: string;
90
+ guidance?: PolicyGuidance;
90
91
  conditionResults?: Array<{
91
92
  conditionId: string;
92
93
  passed: boolean;
93
94
  result: PolicyEvaluationResult;
94
95
  reason?: string;
95
96
  }>;
96
- factsUsed?: Record<string, unknown>;
97
97
  obligations?: Record<string, unknown>;
98
98
  }
99
99
  /**
package/dist/index.js CHANGED
@@ -52,8 +52,9 @@ function parseOpaDecision(raw) {
52
52
  if (err) return { ok: false, error: err };
53
53
  }
54
54
  }
55
- if (d.factsUsed !== void 0 && !isPlainObject(d.factsUsed)) {
56
- return { ok: false, error: "factsUsed must be an object when present" };
55
+ if (d.guidance !== void 0) {
56
+ const err = validateGuidance(d.guidance);
57
+ if (err) return { ok: false, error: err };
57
58
  }
58
59
  if (d.obligations !== void 0 && !isPlainObject(d.obligations)) {
59
60
  return { ok: false, error: "obligations must be an object when present" };
@@ -79,6 +80,68 @@ function validateConditionResult(value, index) {
79
80
  }
80
81
  return null;
81
82
  }
83
+ function validateGuidance(value) {
84
+ if (!isPlainObject(value)) {
85
+ return "guidance must be an object when present";
86
+ }
87
+ const guidance = value;
88
+ if (guidance.summary !== void 0 && typeof guidance.summary !== "string") {
89
+ return "guidance.summary must be a string when present";
90
+ }
91
+ if (!Array.isArray(guidance.factsUsed)) {
92
+ return "guidance.factsUsed must be an array";
93
+ }
94
+ for (let i = 0; i < guidance.factsUsed.length; i += 1) {
95
+ const err = validatePolicyFact(guidance.factsUsed[i], i);
96
+ if (err) return err;
97
+ }
98
+ if (!Array.isArray(guidance.correctiveActions)) {
99
+ return "guidance.correctiveActions must be an array";
100
+ }
101
+ for (let i = 0; i < guidance.correctiveActions.length; i += 1) {
102
+ const err = validateCorrectiveAction(guidance.correctiveActions[i], i);
103
+ if (err) return err;
104
+ }
105
+ return null;
106
+ }
107
+ function validatePolicyFact(value, index) {
108
+ if (!isPlainObject(value)) {
109
+ return `guidance.factsUsed[${index}] must be an object`;
110
+ }
111
+ const fact = value;
112
+ if (typeof fact.name !== "string" || fact.name.length === 0) {
113
+ return `guidance.factsUsed[${index}].name must be a non-empty string`;
114
+ }
115
+ if (fact.label !== void 0 && typeof fact.label !== "string") {
116
+ return `guidance.factsUsed[${index}].label must be a string when present`;
117
+ }
118
+ return null;
119
+ }
120
+ function validateCorrectiveAction(value, index) {
121
+ if (!isPlainObject(value)) {
122
+ return `guidance.correctiveActions[${index}] must be an object`;
123
+ }
124
+ const action = value;
125
+ if (typeof action.label !== "string" || action.label.length === 0) {
126
+ return `guidance.correctiveActions[${index}].label must be a non-empty string`;
127
+ }
128
+ if (action.description !== void 0 && typeof action.description !== "string") {
129
+ return `guidance.correctiveActions[${index}].description must be a string when present`;
130
+ }
131
+ if (action.actionId !== void 0 && typeof action.actionId !== "string") {
132
+ return `guidance.correctiveActions[${index}].actionId must be a string when present`;
133
+ }
134
+ if (action.parameters !== void 0 && !isPlainObject(action.parameters)) {
135
+ return `guidance.correctiveActions[${index}].parameters must be an object when present`;
136
+ }
137
+ if (action.target !== void 0 && !isPlainObject(action.target)) {
138
+ return `guidance.correctiveActions[${index}].target must be an object when present`;
139
+ }
140
+ if (action.requiresConfirmation !== void 0 && typeof action.requiresConfirmation !== "boolean") {
141
+ return `guidance.correctiveActions[${index}].requiresConfirmation must be a boolean when present`;
142
+ }
143
+ return null;
144
+ }
82
145
  function isPlainObject(value) {
83
146
  return value !== null && typeof value === "object" && !Array.isArray(value);
84
147
  }
@@ -203,6 +266,7 @@ function buildSuccessOutcome(binding, engineVersion, decision, execution, inputH
203
266
  policyVersion: binding.version,
204
267
  result: mapped.result ?? decision.result,
205
268
  reason: mapped.reason ?? decision.reason,
269
+ guidance: mapped.guidance ?? decision.guidance,
206
270
  metadata: {
207
271
  ...mapped.metadata ?? {},
208
272
  opaDecision: decision
@@ -225,7 +289,6 @@ function buildSuccessOutcome(binding, engineVersion, decision, execution, inputH
225
289
  bundleRevisionStatus: selection.bundleRevisionStatus,
226
290
  provenance: execution.provenance,
227
291
  conditionResults: decision.conditionResults,
228
- factsUsed: decision.factsUsed,
229
292
  obligations: decision.obligations
230
293
  })
231
294
  }
@@ -244,6 +307,19 @@ function makeFailureOutcome(binding, engineVersion, error, reason, onError, inpu
244
307
  policyVersion: binding.version,
245
308
  result: "block",
246
309
  reason,
310
+ guidance: {
311
+ summary: "OPA policy evaluation could not complete.",
312
+ factsUsed: [
313
+ { name: "opaFailureKind", value: error, label: "Failure kind" },
314
+ { name: "decisionPath", value: binding.decisionPath, label: "Decision path" }
315
+ ],
316
+ correctiveActions: [
317
+ {
318
+ label: "Check OPA policy engine",
319
+ description: "Verify the OPA service is reachable, serving the expected bundle, and returning the Fabric OPA decision shape."
320
+ }
321
+ ]
322
+ },
247
323
  metadata: {
248
324
  opaError: error
249
325
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bundle-selector.ts","../src/decision-schema.ts","../src/hash.ts","../src/factory.ts","../src/executor-client.ts","../src/executor-http.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { OpaPolicyBinding, OpaPolicyExecution } from \"./types\";\n\nexport interface BundleSelection {\n\tbundleRevision?: string;\n\t/**\n\t * Set to `\"ambiguous\"` when OPA reports multiple bundles and the binding\n\t * did not pick one with `bundleName`. The adapter records this on the\n\t * evidence so dashboards can flag policies that need explicit selectors.\n\t * `\"missing\"` is set when provenance was expected but absent.\n\t */\n\tbundleRevisionStatus?: \"ambiguous\" | \"missing\";\n}\n\n/**\n * Determine which OPA bundle revision applies to this decision.\n *\n * Rules (in order):\n * 1. If the executor already populated `execution.bundleRevision`, use it.\n * 2. If `binding.bundleName` is set, look it up in `provenance.bundles`.\n * 3. If exactly one bundle is reported, use its revision unambiguously.\n * 4. If multiple bundles are reported and no selector exists, mark\n * `bundleRevisionStatus: \"ambiguous\"`.\n * 5. If no provenance is reported at all, return `{}` — the caller decides\n * whether absence is meaningful (it is not, for executors that don't\n * carry provenance).\n */\nexport function selectBundleRevision(\n\texecution: OpaPolicyExecution,\n\tbinding: OpaPolicyBinding,\n): BundleSelection {\n\tif (typeof execution.bundleRevision === \"string\" && execution.bundleRevision.length > 0) {\n\t\treturn { bundleRevision: execution.bundleRevision };\n\t}\n\n\tconst bundles = readBundles(execution.provenance);\n\tif (!bundles) return {};\n\n\tconst names = Object.keys(bundles);\n\tif (names.length === 0) return {};\n\n\tif (binding.bundleName) {\n\t\tconst revision = bundles[binding.bundleName]?.revision;\n\t\treturn typeof revision === \"string\" && revision.length > 0\n\t\t\t? { bundleRevision: revision }\n\t\t\t: {};\n\t}\n\n\tif (names.length === 1) {\n\t\tconst only = names[0];\n\t\t// names.length === 1 guarantees names[0] is defined, but the\n\t\t// non-null assertion satisfies noUncheckedIndexedAccess if enabled.\n\t\tconst revision = only !== undefined ? bundles[only]?.revision : undefined;\n\t\treturn typeof revision === \"string\" && revision.length > 0\n\t\t\t? { bundleRevision: revision }\n\t\t\t: {};\n\t}\n\n\treturn { bundleRevisionStatus: \"ambiguous\" };\n}\n\nfunction readBundles(\n\tprovenance: Record<string, unknown> | undefined,\n): Record<string, { revision?: unknown }> | undefined {\n\tif (!provenance || typeof provenance !== \"object\") return undefined;\n\tconst b = (provenance as { bundles?: unknown }).bundles;\n\tif (!b || typeof b !== \"object\" || Array.isArray(b)) return undefined;\n\treturn b as Record<string, { revision?: unknown }>;\n}\n","import type { PolicyEvaluationResult } from \"@fabricorg/platform/policies\";\nimport type { OpaDecision } from \"./types\";\n\nconst POLICY_RESULTS: readonly PolicyEvaluationResult[] = [\"pass\", \"warn\", \"block\"];\n\nexport type OpaDecisionParseResult =\n\t| { ok: true; decision: OpaDecision }\n\t| { ok: false; error: string };\n\n/**\n * Hand-rolled validator for the Rego \"house style\" decision shape. Avoids a\n * runtime zod dependency to keep the adapter zero-dep.\n *\n * Accepts a raw OPA result and either returns the parsed `OpaDecision` or a\n * single human-readable error string describing the first violation. We don't\n * accumulate every error: when audit evidence has to record \"OPA returned\n * something invalid\", one precise reason is more useful than a list.\n */\nexport function parseOpaDecision(raw: unknown): OpaDecisionParseResult {\n\tif (raw === null || typeof raw !== \"object\") {\n\t\treturn { ok: false, error: \"decision must be an object\" };\n\t}\n\n\tconst d = raw as Record<string, unknown>;\n\n\tif (typeof d.result !== \"string\" || !POLICY_RESULTS.includes(d.result as PolicyEvaluationResult)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: `result must be \"pass\" | \"warn\" | \"block\" (got ${JSON.stringify(d.result)})`,\n\t\t};\n\t}\n\n\tif (d.reason !== undefined && typeof d.reason !== \"string\") {\n\t\treturn { ok: false, error: \"reason must be a string when present\" };\n\t}\n\n\tif (d.conditionResults !== undefined) {\n\t\tif (!Array.isArray(d.conditionResults)) {\n\t\t\treturn { ok: false, error: \"conditionResults must be an array when present\" };\n\t\t}\n\t\tfor (let i = 0; i < d.conditionResults.length; i += 1) {\n\t\t\tconst err = validateConditionResult(d.conditionResults[i], i);\n\t\t\tif (err) return { ok: false, error: err };\n\t\t}\n\t}\n\n\tif (d.factsUsed !== undefined && !isPlainObject(d.factsUsed)) {\n\t\treturn { ok: false, error: \"factsUsed must be an object when present\" };\n\t}\n\n\tif (d.obligations !== undefined && !isPlainObject(d.obligations)) {\n\t\treturn { ok: false, error: \"obligations must be an object when present\" };\n\t}\n\n\treturn { ok: true, decision: d as unknown as OpaDecision };\n}\n\nfunction validateConditionResult(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `conditionResults[${index}] must be an object`;\n\t}\n\tconst c = value as Record<string, unknown>;\n\tif (typeof c.conditionId !== \"string\" || c.conditionId.length === 0) {\n\t\treturn `conditionResults[${index}].conditionId must be a non-empty string`;\n\t}\n\tif (typeof c.passed !== \"boolean\") {\n\t\treturn `conditionResults[${index}].passed must be a boolean`;\n\t}\n\tif (typeof c.result !== \"string\" || !POLICY_RESULTS.includes(c.result as PolicyEvaluationResult)) {\n\t\treturn `conditionResults[${index}].result must be \"pass\" | \"warn\" | \"block\"`;\n\t}\n\tif (c.reason !== undefined && typeof c.reason !== \"string\") {\n\t\treturn `conditionResults[${index}].reason must be a string when present`;\n\t}\n\treturn null;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","import { createHash } from \"node:crypto\";\n\n/**\n * Stable JSON stringify — sorts object keys recursively so two\n * structurally-equal inputs produce the same string regardless of property\n * insertion order. Required for hash determinism across builds of the same\n * `buildInput` function.\n */\nexport function stableStringify(value: unknown): string {\n\tif (value === undefined) return \"null\";\n\tif (value === null || typeof value !== \"object\") return JSON.stringify(value);\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map(stableStringify).join(\",\")}]`;\n\t}\n\tconst obj = value as Record<string, unknown>;\n\tconst keys = Object.keys(obj).sort();\n\treturn `{${keys\n\t\t.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`)\n\t\t.join(\",\")}}`;\n}\n\n/**\n * Default input hasher: SHA-256 over a stable stringification.\n * Format: `sha256:<hex>` — namespaced so future migrations to a different\n * algorithm can be detected by a prefix check in evidence dashboards.\n */\nexport function defaultHashInput(input: Record<string, unknown>): string {\n\tconst hex = createHash(\"sha256\").update(stableStringify(input)).digest(\"hex\");\n\treturn `sha256:${hex}`;\n}\n","import type {\n\tPolicyContext,\n\tPolicyEvaluator,\n\tPolicyOutcome,\n} from \"@fabricorg/platform/policies\";\n\nimport { selectBundleRevision } from \"./bundle-selector\";\nimport { parseOpaDecision } from \"./decision-schema\";\nimport { defaultHashInput } from \"./hash\";\nimport type {\n\tCreateOpaPolicyEvaluatorOptions,\n\tOpaDecision,\n\tOpaPolicyBinding,\n\tOpaPolicyClient,\n\tOpaPolicyExecution,\n\tOpaPolicyExecutor,\n\tOpaPolicyFailureKind,\n} from \"./types\";\n\nconst DEFAULT_SERVICE_KEY = \"opa\";\nconst ENGINE_NAME = \"opa\";\n\n/**\n * Build a Fabric `PolicyEvaluator` that delegates decision-making to an OPA\n * (Open Policy Agent) deployment.\n *\n * The adapter accepts either of two service shapes under\n * `ctx.services[serviceKey]`:\n *\n * - `OpaPolicyExecutor` (preferred) — `execute(path, input)` returning a rich\n * `OpaPolicyExecution` (decision plus `decisionId`, `bundleRevision`,\n * `opaVersion`, `provenance`). Ship one with {@link executorFromOpaHttp} or\n * {@link executorFromOpaClient}.\n * - `OpaPolicyClient` — `evaluate(path, input)` returning the raw decision\n * only. Compatible with the high-level `@open-policy-agent/opa` SDK at the\n * cost of OPA-side provenance.\n *\n * If both methods are present, `execute` is preferred.\n *\n * The evaluator:\n *\n * 1. Resolves the service from `ctx.services[serviceKey]`.\n * 2. Builds a JSON input snapshot via `buildInput(ctx)` — domain code that\n * snapshots facts the engine needs. OPA never reaches into the database\n * directly; all facts flow through this function.\n * 3. Calls OPA at `binding.decisionPath`.\n * 4. Validates the response against the house-style shape (`OpaDecision`).\n * 5. Maps the decision to a `PolicyOutcome` and attaches engine provenance\n * under `dispatchEvidence.engine` — `name`, optional `version`, and\n * metadata covering `decisionPath`, `regoPackage`, `inputHash`, plus (when\n * the executor surfaces them) `decisionId`, `bundleName`, `bundleRevision`,\n * `bundleRevisionStatus`, and the raw `provenance` block.\n *\n * Failures (missing client, build failure, network failure, malformed\n * response) are governed by `onError`. Default `\"block\"` honors Fabric's\n * default-deny posture and records the failure category under\n * `engine.metadata.error`.\n */\nexport function createOpaPolicyEvaluator<TDb = unknown>(\n\toptions: CreateOpaPolicyEvaluatorOptions<TDb>,\n): PolicyEvaluator<TDb> {\n\tconst {\n\t\tbinding,\n\t\tbuildInput,\n\t\tserviceKey = DEFAULT_SERVICE_KEY,\n\t\tonError = \"block\",\n\t\tpreviewSafe = false,\n\t\tengineVersion,\n\t\tmapDecision,\n\t\thashInput = defaultHashInput,\n\t} = options;\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tversion: binding.version,\n\t\tpreviewSafe,\n\t\tevaluate: async (ctx) => {\n\t\t\tconst service = ctx.services?.[serviceKey];\n\t\t\tconst transport = resolveTransport(service);\n\t\t\tif (!transport) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"client_unavailable\",\n\t\t\t\t\t`No OPA client/executor at ctx.services[\"${serviceKey}\"]`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet input: Record<string, unknown>;\n\t\t\ttry {\n\t\t\t\tinput = await buildInput(ctx);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"input_build_failed\",\n\t\t\t\t\t`buildInput threw: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet inputHash: string | undefined;\n\t\t\ttry {\n\t\t\t\tinputHash = hashInput(input);\n\t\t\t} catch {\n\t\t\t\t// hashing is best-effort — if a custom hasher throws, omit the\n\t\t\t\t// field rather than fail the policy.\n\t\t\t}\n\n\t\t\tlet execution: OpaPolicyExecution;\n\t\t\ttry {\n\t\t\t\texecution = await transport(binding.decisionPath, input);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"evaluation_failed\",\n\t\t\t\t\t`OPA evaluation failed: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst parsed = parseOpaDecision(execution.decision);\n\t\t\tif (!parsed.ok) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"invalid_response\",\n\t\t\t\t\t`OPA returned malformed decision: ${parsed.error}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t\texecution,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn buildSuccessOutcome(\n\t\t\t\tbinding,\n\t\t\t\tengineVersion,\n\t\t\t\tparsed.decision,\n\t\t\t\texecution,\n\t\t\t\tinputHash,\n\t\t\t\tctx,\n\t\t\t\tmapDecision,\n\t\t\t);\n\t\t},\n\t};\n}\n\n/**\n * Discriminates between the rich executor shape and the legacy client shape.\n * Returns a uniform `(path, input) => OpaPolicyExecution` transport, or\n * `null` if the service doesn't implement either contract.\n *\n * `execute` is preferred when both are present so a v0.1 client wrapped by a\n * richer executor still wins.\n */\nfunction resolveTransport(\n\tservice: unknown,\n): ((path: string, input: unknown) => Promise<OpaPolicyExecution>) | null {\n\tif (!service || typeof service !== \"object\") return null;\n\tconst exec = (service as Partial<OpaPolicyExecutor>).execute;\n\tif (typeof exec === \"function\") {\n\t\treturn (path, input) => (service as OpaPolicyExecutor).execute(path, input);\n\t}\n\tconst eval_ = (service as Partial<OpaPolicyClient>).evaluate;\n\tif (typeof eval_ === \"function\") {\n\t\treturn async (path, input) => ({\n\t\t\tdecision: await (service as OpaPolicyClient).evaluate(path, input),\n\t\t});\n\t}\n\treturn null;\n}\n\nfunction buildSuccessOutcome<TDb>(\n\tbinding: OpaPolicyBinding,\n\tengineVersion: string | undefined,\n\tdecision: OpaDecision,\n\texecution: OpaPolicyExecution,\n\tinputHash: string | undefined,\n\tctx: PolicyContext<TDb>,\n\tmapDecision: CreateOpaPolicyEvaluatorOptions<TDb>[\"mapDecision\"],\n): PolicyOutcome {\n\tconst selection = selectBundleRevision(execution, binding);\n\tconst mapped = mapDecision\n\t\t? mapDecision(decision, ctx, execution)\n\t\t: { result: decision.result, reason: decision.reason };\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: mapped.result ?? decision.result,\n\t\treason: mapped.reason ?? decision.reason,\n\t\tmetadata: {\n\t\t\t...(mapped.metadata ?? {}),\n\t\t\topaDecision: decision,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: execution.opaVersion ?? engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\tdecisionId: execution.decisionId,\n\t\t\t\t\tbundleName: binding.bundleName,\n\t\t\t\t\tbundleRevision: selection.bundleRevision,\n\t\t\t\t\tbundleRevisionStatus: selection.bundleRevisionStatus,\n\t\t\t\t\tprovenance: execution.provenance,\n\t\t\t\t\tconditionResults: decision.conditionResults,\n\t\t\t\t\tfactsUsed: decision.factsUsed,\n\t\t\t\t\tobligations: decision.obligations,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction makeFailureOutcome(\n\tbinding: OpaPolicyBinding,\n\tengineVersion: string | undefined,\n\terror: OpaPolicyFailureKind,\n\treason: string,\n\tonError: \"block\" | \"throw\",\n\tinputHash?: string,\n\texecution?: OpaPolicyExecution,\n): PolicyOutcome {\n\tif (onError === \"throw\") {\n\t\tconst err = new Error(reason);\n\t\t(err as Error & { kind?: OpaPolicyFailureKind }).kind = error;\n\t\tthrow err;\n\t}\n\n\tconst selection = execution ? selectBundleRevision(execution, binding) : {};\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: \"block\",\n\t\treason,\n\t\tmetadata: {\n\t\t\topaError: error,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: execution?.opaVersion ?? engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\tdecisionId: execution?.decisionId,\n\t\t\t\t\tbundleName: binding.bundleName,\n\t\t\t\t\tbundleRevision: selection.bundleRevision,\n\t\t\t\t\tbundleRevisionStatus: selection.bundleRevisionStatus,\n\t\t\t\t\tprovenance: execution?.provenance,\n\t\t\t\t\terror,\n\t\t\t\t\terrorReason: reason,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction stripUndefined(obj: Record<string, unknown>): Record<string, unknown> {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(obj)) {\n\t\tif (v !== undefined) out[k] = v;\n\t}\n\treturn out;\n}\n\nfunction formatError(err: unknown): string {\n\tif (err instanceof Error) return err.message;\n\tif (typeof err === \"string\") return err;\n\ttry {\n\t\treturn JSON.stringify(err);\n\t} catch {\n\t\treturn String(err);\n\t}\n}\n","import type {\n\tOpaPolicyClient,\n\tOpaPolicyExecution,\n\tOpaPolicyExecutor,\n} from \"./types\";\n\n/**\n * Wrap an `OpaPolicyClient` (the high-level `@open-policy-agent/opa` SDK\n * shape) as an {@link OpaPolicyExecutor}. The resulting executor carries no\n * OPA-side provenance — the high-level SDK discards `decisionId` and\n * `provenance` from the response — but does centralize the\n * `(path, input) => execution` plumbing so hosts can choose at startup whether\n * to wire a client or a full executor.\n *\n * For full provenance (decisionId, bundleRevision, opaVersion), prefer\n * {@link executorFromOpaHttp}.\n */\nexport function executorFromOpaClient(client: OpaPolicyClient): OpaPolicyExecutor {\n\treturn {\n\t\tasync execute(path: string, input: unknown): Promise<OpaPolicyExecution> {\n\t\t\tconst decision = await client.evaluate(path, input);\n\t\t\treturn { decision };\n\t\t},\n\t};\n}\n","import type { OpaPolicyExecution, OpaPolicyExecutor } from \"./types\";\n\nexport interface OpaHttpExecutorOptions {\n\t/**\n\t * Base URL of the OPA server, e.g. `\"http://localhost:8181\"` or\n\t * `\"https://opa.internal.example.com\"`. Trailing slash is permitted; the\n\t * executor normalizes it.\n\t */\n\tbaseUrl: string;\n\t/**\n\t * Override for `globalThis.fetch`. Lets the host inject a fetch instance\n\t * with retries, mTLS, OpenTelemetry instrumentation, etc. Defaults to\n\t * `globalThis.fetch`.\n\t */\n\tfetch?: typeof globalThis.fetch;\n\t/** Extra request headers (e.g. `Authorization`). */\n\theaders?: Record<string, string>;\n\t/**\n\t * Request OPA-side provenance (`decision_id`, `provenance.version`,\n\t * `provenance.bundles[*].revision`) via `?provenance=true`. Defaults to\n\t * `true` — turning it off forfeits OPA's contribution to audit evidence\n\t * and is rarely what you want.\n\t */\n\tprovenance?: boolean;\n}\n\ninterface OpaHttpResponseBody {\n\tresult?: unknown;\n\tdecision_id?: string;\n\tprovenance?: {\n\t\tversion?: string;\n\t\tbuild_commit?: string;\n\t\tbuild_timestamp?: string;\n\t\tbuild_host?: string;\n\t\tbundles?: Record<string, { revision?: string }>;\n\t};\n}\n\n/**\n * Build an {@link OpaPolicyExecutor} that talks to OPA's REST API directly.\n *\n * POSTs to `{baseUrl}/v1/data/{path}?provenance=true` with body\n * `{ \"input\": ... }`. Parses the snake_case response and lifts:\n *\n * - `result` → `execution.decision`\n * - `decision_id` → `execution.decisionId`\n * - `provenance.version` → `execution.opaVersion`\n * - `provenance` (whole block) → `execution.provenance`\n *\n * Bundle revision selection happens in the factory, not the executor, because\n * it depends on `binding.bundleName`.\n *\n * Calling this in environments without `globalThis.fetch` (older Node) throws\n * at call time; pass `fetch: nodeFetch` or `fetch: undici-fetch` etc. via the\n * options to support those runtimes explicitly.\n */\nexport function executorFromOpaHttp(opts: OpaHttpExecutorOptions): OpaPolicyExecutor {\n\tconst baseUrl = stripTrailingSlash(opts.baseUrl);\n\tconst provenance = opts.provenance ?? true;\n\tconst customFetch = opts.fetch;\n\tconst headers = {\n\t\t\"content-type\": \"application/json\",\n\t\taccept: \"application/json\",\n\t\t...(opts.headers ?? {}),\n\t};\n\n\treturn {\n\t\tasync execute(path: string, input: unknown): Promise<OpaPolicyExecution> {\n\t\t\tconst fetchImpl = customFetch ?? globalThis.fetch;\n\t\t\tif (typeof fetchImpl !== \"function\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"executorFromOpaHttp: no fetch implementation available. Pass `fetch` in options or run on a runtime with `globalThis.fetch`.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst url = `${baseUrl}/v1/data/${stripLeadingSlash(path)}${\n\t\t\t\tprovenance ? \"?provenance=true\" : \"\"\n\t\t\t}`;\n\t\t\tconst response = await fetchImpl(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({ input }),\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst text = await safeReadText(response);\n\t\t\t\tthrow new Error(`OPA HTTP ${response.status} at ${url}: ${truncate(text, 500)}`);\n\t\t\t}\n\n\t\t\tconst body = (await response.json()) as OpaHttpResponseBody;\n\n\t\t\treturn {\n\t\t\t\tdecision: body.result,\n\t\t\t\tdecisionId: body.decision_id,\n\t\t\t\topaVersion: body.provenance?.version,\n\t\t\t\tprovenance: body.provenance as Record<string, unknown> | undefined,\n\t\t\t};\n\t\t},\n\t};\n}\n\nfunction stripTrailingSlash(s: string): string {\n\treturn s.replace(/\\/+$/, \"\");\n}\n\nfunction stripLeadingSlash(s: string): string {\n\treturn s.replace(/^\\/+/, \"\");\n}\n\nasync function safeReadText(response: Response): Promise<string> {\n\ttry {\n\t\treturn await response.text();\n\t} catch {\n\t\treturn \"<unreadable body>\";\n\t}\n}\n\nfunction truncate(s: string, max: number): string {\n\treturn s.length <= max ? s : `${s.slice(0, max)}…`;\n}\n"]}
1
+ {"version":3,"sources":["../src/bundle-selector.ts","../src/decision-schema.ts","../src/hash.ts","../src/factory.ts","../src/executor-client.ts","../src/executor-http.ts"],"names":[],"mappings":";;;AA0BO,SAAS,oBAAA,CACf,WACA,OAAA,EACkB;AAClB,EAAA,IAAI,OAAO,SAAA,CAAU,cAAA,KAAmB,YAAY,SAAA,CAAU,cAAA,CAAe,SAAS,CAAA,EAAG;AACxF,IAAA,OAAO,EAAE,cAAA,EAAgB,SAAA,CAAU,cAAA,EAAe;AAAA,EACnD;AAEA,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,SAAA,CAAU,UAAU,CAAA;AAChD,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAC;AAEtB,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AACjC,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,EAAC;AAEhC,EAAA,IAAI,QAAQ,UAAA,EAAY;AACvB,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,OAAA,CAAQ,UAAU,CAAA,EAAG,QAAA;AAC9C,IAAA,OAAO,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,CAAS,MAAA,GAAS,IACtD,EAAE,cAAA,EAAgB,QAAA,EAAS,GAC3B,EAAC;AAAA,EACL;AAEA,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACvB,IAAA,MAAM,IAAA,GAAO,MAAM,CAAC,CAAA;AAGpB,IAAA,MAAM,WAAW,IAAA,KAAS,MAAA,GAAY,OAAA,CAAQ,IAAI,GAAG,QAAA,GAAW,MAAA;AAChE,IAAA,OAAO,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,CAAS,MAAA,GAAS,IACtD,EAAE,cAAA,EAAgB,QAAA,EAAS,GAC3B,EAAC;AAAA,EACL;AAEA,EAAA,OAAO,EAAE,sBAAsB,WAAA,EAAY;AAC5C;AAEA,SAAS,YACR,UAAA,EACqD;AACrD,EAAA,IAAI,CAAC,UAAA,IAAc,OAAO,UAAA,KAAe,UAAU,OAAO,MAAA;AAC1D,EAAA,MAAM,IAAK,UAAA,CAAqC,OAAA;AAChD,EAAA,IAAI,CAAC,KAAK,OAAO,CAAA,KAAM,YAAY,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG,OAAO,MAAA;AAC5D,EAAA,OAAO,CAAA;AACR;;;AChEA,IAAM,cAAA,GAAoD,CAAC,MAAA,EAAQ,MAAA,EAAQ,OAAO,CAAA;AAe3E,SAAS,iBAAiB,GAAA,EAAsC;AACtE,EAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,OAAO,GAAA,KAAQ,QAAA,EAAU;AAC5C,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,4BAAA,EAA6B;AAAA,EACzD;AAEA,EAAA,MAAM,CAAA,GAAI,GAAA;AAEV,EAAA,IAAI,OAAO,EAAE,MAAA,KAAW,QAAA,IAAY,CAAC,cAAA,CAAe,QAAA,CAAS,CAAA,CAAE,MAAgC,CAAA,EAAG;AACjG,IAAA,OAAO;AAAA,MACN,EAAA,EAAI,KAAA;AAAA,MACJ,OAAO,CAAA,8CAAA,EAAiD,IAAA,CAAK,SAAA,CAAU,CAAA,CAAE,MAAM,CAAC,CAAA,CAAA;AAAA,KACjF;AAAA,EACD;AAEA,EAAA,IAAI,EAAE,MAAA,KAAW,MAAA,IAAa,OAAO,CAAA,CAAE,WAAW,QAAA,EAAU;AAC3D,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,sCAAA,EAAuC;AAAA,EACnE;AAEA,EAAA,IAAI,CAAA,CAAE,qBAAqB,MAAA,EAAW;AACrC,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,gBAAgB,CAAA,EAAG;AACvC,MAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,gDAAA,EAAiD;AAAA,IAC7E;AACA,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,EAAE,gBAAA,CAAiB,MAAA,EAAQ,KAAK,CAAA,EAAG;AACtD,MAAA,MAAM,MAAM,uBAAA,CAAwB,CAAA,CAAE,gBAAA,CAAiB,CAAC,GAAG,CAAC,CAAA;AAC5D,MAAA,IAAI,KAAK,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,GAAA,EAAI;AAAA,IACzC;AAAA,EACD;AAEA,EAAA,IAAI,CAAA,CAAE,aAAa,MAAA,EAAW;AAC7B,IAAA,MAAM,GAAA,GAAM,gBAAA,CAAiB,CAAA,CAAE,QAAQ,CAAA;AACvC,IAAA,IAAI,KAAK,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,GAAA,EAAI;AAAA,EACzC;AAEA,EAAA,IAAI,EAAE,WAAA,KAAgB,MAAA,IAAa,CAAC,aAAA,CAAc,CAAA,CAAE,WAAW,CAAA,EAAG;AACjE,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,4CAAA,EAA6C;AAAA,EACzE;AAEA,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,QAAA,EAAU,CAAA,EAA4B;AAC1D;AAEA,SAAS,uBAAA,CAAwB,OAAgB,KAAA,EAA8B;AAC9E,EAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AAC1B,IAAA,OAAO,oBAAoB,KAAK,CAAA,mBAAA,CAAA;AAAA,EACjC;AACA,EAAA,MAAM,CAAA,GAAI,KAAA;AACV,EAAA,IAAI,OAAO,CAAA,CAAE,WAAA,KAAgB,YAAY,CAAA,CAAE,WAAA,CAAY,WAAW,CAAA,EAAG;AACpE,IAAA,OAAO,oBAAoB,KAAK,CAAA,wCAAA,CAAA;AAAA,EACjC;AACA,EAAA,IAAI,OAAO,CAAA,CAAE,MAAA,KAAW,SAAA,EAAW;AAClC,IAAA,OAAO,oBAAoB,KAAK,CAAA,0BAAA,CAAA;AAAA,EACjC;AACA,EAAA,IAAI,OAAO,EAAE,MAAA,KAAW,QAAA,IAAY,CAAC,cAAA,CAAe,QAAA,CAAS,CAAA,CAAE,MAAgC,CAAA,EAAG;AACjG,IAAA,OAAO,oBAAoB,KAAK,CAAA,0CAAA,CAAA;AAAA,EACjC;AACA,EAAA,IAAI,EAAE,MAAA,KAAW,MAAA,IAAa,OAAO,CAAA,CAAE,WAAW,QAAA,EAAU;AAC3D,IAAA,OAAO,oBAAoB,KAAK,CAAA,sCAAA,CAAA;AAAA,EACjC;AACA,EAAA,OAAO,IAAA;AACR;AAEA,SAAS,iBAAiB,KAAA,EAA+B;AACxD,EAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AAC1B,IAAA,OAAO,yCAAA;AAAA,EACR;AACA,EAAA,MAAM,QAAA,GAAW,KAAA;AACjB,EAAA,IAAI,SAAS,OAAA,KAAY,MAAA,IAAa,OAAO,QAAA,CAAS,YAAY,QAAA,EAAU;AAC3E,IAAA,OAAO,gDAAA;AAAA,EACR;AACA,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,SAAS,CAAA,EAAG;AACvC,IAAA,OAAO,qCAAA;AAAA,EACR;AACA,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,SAAS,SAAA,CAAU,MAAA,EAAQ,KAAK,CAAA,EAAG;AACtD,IAAA,MAAM,MAAM,kBAAA,CAAmB,QAAA,CAAS,SAAA,CAAU,CAAC,GAAG,CAAC,CAAA;AACvD,IAAA,IAAI,KAAK,OAAO,GAAA;AAAA,EACjB;AACA,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,iBAAiB,CAAA,EAAG;AAC/C,IAAA,OAAO,6CAAA;AAAA,EACR;AACA,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,SAAS,iBAAA,CAAkB,MAAA,EAAQ,KAAK,CAAA,EAAG;AAC9D,IAAA,MAAM,MAAM,wBAAA,CAAyB,QAAA,CAAS,iBAAA,CAAkB,CAAC,GAAG,CAAC,CAAA;AACrE,IAAA,IAAI,KAAK,OAAO,GAAA;AAAA,EACjB;AACA,EAAA,OAAO,IAAA;AACR;AAEA,SAAS,kBAAA,CAAmB,OAAgB,KAAA,EAA8B;AACzE,EAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AAC1B,IAAA,OAAO,sBAAsB,KAAK,CAAA,mBAAA,CAAA;AAAA,EACnC;AACA,EAAA,MAAM,IAAA,GAAO,KAAA;AACb,EAAA,IAAI,OAAO,IAAA,CAAK,IAAA,KAAS,YAAY,IAAA,CAAK,IAAA,CAAK,WAAW,CAAA,EAAG;AAC5D,IAAA,OAAO,sBAAsB,KAAK,CAAA,iCAAA,CAAA;AAAA,EACnC;AACA,EAAA,IAAI,KAAK,KAAA,KAAU,MAAA,IAAa,OAAO,IAAA,CAAK,UAAU,QAAA,EAAU;AAC/D,IAAA,OAAO,sBAAsB,KAAK,CAAA,qCAAA,CAAA;AAAA,EACnC;AACA,EAAA,OAAO,IAAA;AACR;AAEA,SAAS,wBAAA,CAAyB,OAAgB,KAAA,EAA8B;AAC/E,EAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AAC1B,IAAA,OAAO,8BAA8B,KAAK,CAAA,mBAAA,CAAA;AAAA,EAC3C;AACA,EAAA,MAAM,MAAA,GAAS,KAAA;AACf,EAAA,IAAI,OAAO,MAAA,CAAO,KAAA,KAAU,YAAY,MAAA,CAAO,KAAA,CAAM,WAAW,CAAA,EAAG;AAClE,IAAA,OAAO,8BAA8B,KAAK,CAAA,kCAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,OAAO,WAAA,KAAgB,MAAA,IAAa,OAAO,MAAA,CAAO,gBAAgB,QAAA,EAAU;AAC/E,IAAA,OAAO,8BAA8B,KAAK,CAAA,2CAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,OAAO,QAAA,KAAa,MAAA,IAAa,OAAO,MAAA,CAAO,aAAa,QAAA,EAAU;AACzE,IAAA,OAAO,8BAA8B,KAAK,CAAA,wCAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,OAAO,UAAA,KAAe,MAAA,IAAa,CAAC,aAAA,CAAc,MAAA,CAAO,UAAU,CAAA,EAAG;AACzE,IAAA,OAAO,8BAA8B,KAAK,CAAA,2CAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,OAAO,MAAA,KAAW,MAAA,IAAa,CAAC,aAAA,CAAc,MAAA,CAAO,MAAM,CAAA,EAAG;AACjE,IAAA,OAAO,8BAA8B,KAAK,CAAA,uCAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,OAAO,oBAAA,KAAyB,MAAA,IAAa,OAAO,MAAA,CAAO,yBAAyB,SAAA,EAAW;AAClG,IAAA,OAAO,8BAA8B,KAAK,CAAA,qDAAA,CAAA;AAAA,EAC3C;AACA,EAAA,OAAO,IAAA;AACR;AAEA,SAAS,cAAc,KAAA,EAAkD;AACxE,EAAA,OAAO,KAAA,KAAU,QAAQ,OAAO,KAAA,KAAU,YAAY,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC3E;ACzIO,SAAS,gBAAgB,KAAA,EAAwB;AACvD,EAAA,IAAI,KAAA,KAAU,QAAW,OAAO,MAAA;AAChC,EAAA,IAAI,KAAA,KAAU,QAAQ,OAAO,KAAA,KAAU,UAAU,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAC5E,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACzB,IAAA,OAAO,IAAI,KAAA,CAAM,GAAA,CAAI,eAAe,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AAAA,EAChD;AACA,EAAA,MAAM,GAAA,GAAM,KAAA;AACZ,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,GAAG,EAAE,IAAA,EAAK;AACnC,EAAA,OAAO,CAAA,CAAA,EAAI,KACT,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG,IAAA,CAAK,UAAU,CAAC,CAAC,IAAI,eAAA,CAAgB,GAAA,CAAI,CAAC,CAAC,CAAC,EAAE,CAAA,CAC5D,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AACZ;AAOO,SAAS,iBAAiB,KAAA,EAAwC;AACxE,EAAA,MAAM,GAAA,GAAM,UAAA,CAAW,QAAQ,CAAA,CAAE,MAAA,CAAO,gBAAgB,KAAK,CAAC,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA;AAC5E,EAAA,OAAO,UAAU,GAAG,CAAA,CAAA;AACrB;;;ACVA,IAAM,mBAAA,GAAsB,KAAA;AAC5B,IAAM,WAAA,GAAc,KAAA;AAsCb,SAAS,yBACf,OAAA,EACuB;AACvB,EAAA,MAAM;AAAA,IACL,OAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA,GAAa,mBAAA;AAAA,IACb,OAAA,GAAU,OAAA;AAAA,IACV,WAAA,GAAc,KAAA;AAAA,IACd,aAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA,GAAY;AAAA,GACb,GAAI,OAAA;AAEJ,EAAA,OAAO;AAAA,IACN,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,SAAS,OAAA,CAAQ,OAAA;AAAA,IACjB,WAAA;AAAA,IACA,QAAA,EAAU,OAAO,GAAA,KAAQ;AACxB,MAAA,MAAM,OAAA,GAAU,GAAA,CAAI,QAAA,GAAW,UAAU,CAAA;AACzC,MAAA,MAAM,SAAA,GAAY,iBAAiB,OAAO,CAAA;AAC1C,MAAA,IAAI,CAAC,SAAA,EAAW;AACf,QAAA,OAAO,kBAAA;AAAA,UACN,OAAA;AAAA,UACA,aAAA;AAAA,UACA,oBAAA;AAAA,UACA,2CAA2C,UAAU,CAAA,EAAA,CAAA;AAAA,UACrD;AAAA,SACD;AAAA,MACD;AAEA,MAAA,IAAI,KAAA;AACJ,MAAA,IAAI;AACH,QAAA,KAAA,GAAQ,MAAM,WAAW,GAAG,CAAA;AAAA,MAC7B,SAAS,GAAA,EAAK;AACb,QAAA,OAAO,kBAAA;AAAA,UACN,OAAA;AAAA,UACA,aAAA;AAAA,UACA,oBAAA;AAAA,UACA,CAAA,kBAAA,EAAqB,WAAA,CAAY,GAAG,CAAC,CAAA,CAAA;AAAA,UACrC;AAAA,SACD;AAAA,MACD;AAEA,MAAA,IAAI,SAAA;AACJ,MAAA,IAAI;AACH,QAAA,SAAA,GAAY,UAAU,KAAK,CAAA;AAAA,MAC5B,CAAA,CAAA,MAAQ;AAAA,MAGR;AAEA,MAAA,IAAI,SAAA;AACJ,MAAA,IAAI;AACH,QAAA,SAAA,GAAY,MAAM,SAAA,CAAU,OAAA,CAAQ,YAAA,EAAc,KAAK,CAAA;AAAA,MACxD,SAAS,GAAA,EAAK;AACb,QAAA,OAAO,kBAAA;AAAA,UACN,OAAA;AAAA,UACA,aAAA;AAAA,UACA,mBAAA;AAAA,UACA,CAAA,uBAAA,EAA0B,WAAA,CAAY,GAAG,CAAC,CAAA,CAAA;AAAA,UAC1C,OAAA;AAAA,UACA;AAAA,SACD;AAAA,MACD;AAEA,MAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,SAAA,CAAU,QAAQ,CAAA;AAClD,MAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACf,QAAA,OAAO,kBAAA;AAAA,UACN,OAAA;AAAA,UACA,aAAA;AAAA,UACA,kBAAA;AAAA,UACA,CAAA,iCAAA,EAAoC,OAAO,KAAK,CAAA,CAAA;AAAA,UAChD,OAAA;AAAA,UACA,SAAA;AAAA,UACA;AAAA,SACD;AAAA,MACD;AAEA,MAAA,OAAO,mBAAA;AAAA,QACN,OAAA;AAAA,QACA,aAAA;AAAA,QACA,MAAA,CAAO,QAAA;AAAA,QACP,SAAA;AAAA,QACA,SAAA;AAAA,QACA,GAAA;AAAA,QACA;AAAA,OACD;AAAA,IACD;AAAA,GACD;AACD;AAUA,SAAS,iBACR,OAAA,EACyE;AACzE,EAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,UAAU,OAAO,IAAA;AACpD,EAAA,MAAM,OAAQ,OAAA,CAAuC,OAAA;AACrD,EAAA,IAAI,OAAO,SAAS,UAAA,EAAY;AAC/B,IAAA,OAAO,CAAC,IAAA,EAAM,KAAA,KAAW,OAAA,CAA8B,OAAA,CAAQ,MAAM,KAAK,CAAA;AAAA,EAC3E;AACA,EAAA,MAAM,QAAS,OAAA,CAAqC,QAAA;AACpD,EAAA,IAAI,OAAO,UAAU,UAAA,EAAY;AAChC,IAAA,OAAO,OAAO,MAAM,KAAA,MAAW;AAAA,MAC9B,QAAA,EAAU,MAAO,OAAA,CAA4B,QAAA,CAAS,MAAM,KAAK;AAAA,KAClE,CAAA;AAAA,EACD;AACA,EAAA,OAAO,IAAA;AACR;AAEA,SAAS,oBACR,OAAA,EACA,aAAA,EACA,UACA,SAAA,EACA,SAAA,EACA,KACA,WAAA,EACgB;AAChB,EAAA,MAAM,SAAA,GAAY,oBAAA,CAAqB,SAAA,EAAW,OAAO,CAAA;AACzD,EAAA,MAAM,MAAA,GAAS,WAAA,GACZ,WAAA,CAAY,QAAA,EAAU,GAAA,EAAK,SAAS,CAAA,GACpC,EAAE,MAAA,EAAQ,QAAA,CAAS,MAAA,EAAQ,MAAA,EAAQ,SAAS,MAAA,EAAO;AAEtD,EAAA,OAAO;AAAA,IACN,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,eAAe,OAAA,CAAQ,OAAA;AAAA,IACvB,MAAA,EAAQ,MAAA,CAAO,MAAA,IAAU,QAAA,CAAS,MAAA;AAAA,IAClC,MAAA,EAAQ,MAAA,CAAO,MAAA,IAAU,QAAA,CAAS,MAAA;AAAA,IAClC,QAAA,EAAU,MAAA,CAAO,QAAA,IAAY,QAAA,CAAS,QAAA;AAAA,IACtC,QAAA,EAAU;AAAA,MACT,GAAI,MAAA,CAAO,QAAA,IAAY,EAAC;AAAA,MACxB,WAAA,EAAa;AAAA,KACd;AAAA,IACA,gBAAA,EAAkB;AAAA,MACjB,UAAA,EAAY,MAAA;AAAA,MACZ,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,eAAe,OAAA,CAAQ,OAAA;AAAA,MACvB,YAAA,EAAc,CAAC,MAAM,CAAA;AAAA,MACrB,MAAA,EAAQ;AAAA,QACP,IAAA,EAAM,WAAA;AAAA,QACN,OAAA,EAAS,UAAU,UAAA,IAAc,aAAA;AAAA,QACjC,UAAU,cAAA,CAAe;AAAA,UACxB,cAAc,OAAA,CAAQ,YAAA;AAAA,UACtB,aAAa,OAAA,CAAQ,WAAA;AAAA,UACrB,SAAA;AAAA,UACA,YAAY,SAAA,CAAU,UAAA;AAAA,UACtB,YAAY,OAAA,CAAQ,UAAA;AAAA,UACpB,gBAAgB,SAAA,CAAU,cAAA;AAAA,UAC1B,sBAAsB,SAAA,CAAU,oBAAA;AAAA,UAChC,YAAY,SAAA,CAAU,UAAA;AAAA,UACtB,kBAAkB,QAAA,CAAS,gBAAA;AAAA,UAC3B,aAAa,QAAA,CAAS;AAAA,SACtB;AAAA;AACF;AACD,GACD;AACD;AAEA,SAAS,mBACR,OAAA,EACA,aAAA,EACA,OACA,MAAA,EACA,OAAA,EACA,WACA,SAAA,EACgB;AAChB,EAAA,IAAI,YAAY,OAAA,EAAS;AACxB,IAAA,MAAM,GAAA,GAAM,IAAI,KAAA,CAAM,MAAM,CAAA;AAC5B,IAAC,IAAgD,IAAA,GAAO,KAAA;AACxD,IAAA,MAAM,GAAA;AAAA,EACP;AAEA,EAAA,MAAM,YAAY,SAAA,GAAY,oBAAA,CAAqB,SAAA,EAAW,OAAO,IAAI,EAAC;AAE1E,EAAA,OAAO;AAAA,IACN,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,eAAe,OAAA,CAAQ,OAAA;AAAA,IACvB,MAAA,EAAQ,OAAA;AAAA,IACR,MAAA;AAAA,IACA,QAAA,EAAU;AAAA,MACT,OAAA,EAAS,2CAAA;AAAA,MACT,SAAA,EAAW;AAAA,QACV,EAAE,IAAA,EAAM,gBAAA,EAAkB,KAAA,EAAO,KAAA,EAAO,OAAO,cAAA,EAAe;AAAA,QAC9D,EAAE,IAAA,EAAM,cAAA,EAAgB,OAAO,OAAA,CAAQ,YAAA,EAAc,OAAO,eAAA;AAAgB,OAC7E;AAAA,MACA,iBAAA,EAAmB;AAAA,QAClB;AAAA,UACC,KAAA,EAAO,yBAAA;AAAA,UACP,WAAA,EACC;AAAA;AACF;AACD,KACD;AAAA,IACA,QAAA,EAAU;AAAA,MACT,QAAA,EAAU;AAAA,KACX;AAAA,IACA,gBAAA,EAAkB;AAAA,MACjB,UAAA,EAAY,MAAA;AAAA,MACZ,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,eAAe,OAAA,CAAQ,OAAA;AAAA,MACvB,YAAA,EAAc,CAAC,MAAM,CAAA;AAAA,MACrB,MAAA,EAAQ;AAAA,QACP,IAAA,EAAM,WAAA;AAAA,QACN,OAAA,EAAS,WAAW,UAAA,IAAc,aAAA;AAAA,QAClC,UAAU,cAAA,CAAe;AAAA,UACxB,cAAc,OAAA,CAAQ,YAAA;AAAA,UACtB,aAAa,OAAA,CAAQ,WAAA;AAAA,UACrB,SAAA;AAAA,UACA,YAAY,SAAA,EAAW,UAAA;AAAA,UACvB,YAAY,OAAA,CAAQ,UAAA;AAAA,UACpB,gBAAgB,SAAA,CAAU,cAAA;AAAA,UAC1B,sBAAsB,SAAA,CAAU,oBAAA;AAAA,UAChC,YAAY,SAAA,EAAW,UAAA;AAAA,UACvB,KAAA;AAAA,UACA,WAAA,EAAa;AAAA,SACb;AAAA;AACF;AACD,GACD;AACD;AAEA,SAAS,eAAe,GAAA,EAAuD;AAC9E,EAAA,MAAM,MAA+B,EAAC;AACtC,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AACzC,IAAA,IAAI,CAAA,KAAM,MAAA,EAAW,GAAA,CAAI,CAAC,CAAA,GAAI,CAAA;AAAA,EAC/B;AACA,EAAA,OAAO,GAAA;AACR;AAEA,SAAS,YAAY,GAAA,EAAsB;AAC1C,EAAA,IAAI,GAAA,YAAe,KAAA,EAAO,OAAO,GAAA,CAAI,OAAA;AACrC,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,GAAA;AACpC,EAAA,IAAI;AACH,IAAA,OAAO,IAAA,CAAK,UAAU,GAAG,CAAA;AAAA,EAC1B,CAAA,CAAA,MAAQ;AACP,IAAA,OAAO,OAAO,GAAG,CAAA;AAAA,EAClB;AACD;;;AC/RO,SAAS,sBAAsB,MAAA,EAA4C;AACjF,EAAA,OAAO;AAAA,IACN,MAAM,OAAA,CAAQ,IAAA,EAAc,KAAA,EAA6C;AACxE,MAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,QAAA,CAAS,MAAM,KAAK,CAAA;AAClD,MAAA,OAAO,EAAE,QAAA,EAAS;AAAA,IACnB;AAAA,GACD;AACD;;;ACgCO,SAAS,oBAAoB,IAAA,EAAiD;AACpF,EAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,IAAA,CAAK,OAAO,CAAA;AAC/C,EAAA,MAAM,UAAA,GAAa,KAAK,UAAA,IAAc,IAAA;AACtC,EAAA,MAAM,cAAc,IAAA,CAAK,KAAA;AACzB,EAAA,MAAM,OAAA,GAAU;AAAA,IACf,cAAA,EAAgB,kBAAA;AAAA,IAChB,MAAA,EAAQ,kBAAA;AAAA,IACR,GAAI,IAAA,CAAK,OAAA,IAAW;AAAC,GACtB;AAEA,EAAA,OAAO;AAAA,IACN,MAAM,OAAA,CAAQ,IAAA,EAAc,KAAA,EAA6C;AACxE,MAAA,MAAM,SAAA,GAAY,eAAe,UAAA,CAAW,KAAA;AAC5C,MAAA,IAAI,OAAO,cAAc,UAAA,EAAY;AACpC,QAAA,MAAM,IAAI,KAAA;AAAA,UACT;AAAA,SACD;AAAA,MACD;AAEA,MAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,SAAA,EAAY,iBAAA,CAAkB,IAAI,CAAC,CAAA,EACxD,UAAA,GAAa,kBAAA,GAAqB,EACnC,CAAA,CAAA;AACA,MAAA,MAAM,QAAA,GAAW,MAAM,SAAA,CAAU,GAAA,EAAK;AAAA,QACrC,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA;AAAA,QACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,OAAO;AAAA,OAC9B,CAAA;AAED,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AACjB,QAAA,MAAM,IAAA,GAAO,MAAM,YAAA,CAAa,QAAQ,CAAA;AACxC,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,SAAA,EAAY,QAAA,CAAS,MAAM,CAAA,IAAA,EAAO,GAAG,CAAA,EAAA,EAAK,QAAA,CAAS,IAAA,EAAM,GAAG,CAAC,CAAA,CAAE,CAAA;AAAA,MAChF;AAEA,MAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAElC,MAAA,OAAO;AAAA,QACN,UAAU,IAAA,CAAK,MAAA;AAAA,QACf,YAAY,IAAA,CAAK,WAAA;AAAA,QACjB,UAAA,EAAY,KAAK,UAAA,EAAY,OAAA;AAAA,QAC7B,YAAY,IAAA,CAAK;AAAA,OAClB;AAAA,IACD;AAAA,GACD;AACD;AAEA,SAAS,mBAAmB,CAAA,EAAmB;AAC9C,EAAA,OAAO,CAAA,CAAE,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAC5B;AAEA,SAAS,kBAAkB,CAAA,EAAmB;AAC7C,EAAA,OAAO,CAAA,CAAE,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAC5B;AAEA,eAAe,aAAa,QAAA,EAAqC;AAChE,EAAA,IAAI;AACH,IAAA,OAAO,MAAM,SAAS,IAAA,EAAK;AAAA,EAC5B,CAAA,CAAA,MAAQ;AACP,IAAA,OAAO,mBAAA;AAAA,EACR;AACD;AAEA,SAAS,QAAA,CAAS,GAAW,GAAA,EAAqB;AACjD,EAAA,OAAO,CAAA,CAAE,UAAU,GAAA,GAAM,CAAA,GAAI,GAAG,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,GAAG,CAAC,CAAA,MAAA,CAAA;AAChD","file":"index.js","sourcesContent":["import type { OpaPolicyBinding, OpaPolicyExecution } from \"./types\";\n\nexport interface BundleSelection {\n\tbundleRevision?: string;\n\t/**\n\t * Set to `\"ambiguous\"` when OPA reports multiple bundles and the binding\n\t * did not pick one with `bundleName`. The adapter records this on the\n\t * evidence so dashboards can flag policies that need explicit selectors.\n\t * `\"missing\"` is set when provenance was expected but absent.\n\t */\n\tbundleRevisionStatus?: \"ambiguous\" | \"missing\";\n}\n\n/**\n * Determine which OPA bundle revision applies to this decision.\n *\n * Rules (in order):\n * 1. If the executor already populated `execution.bundleRevision`, use it.\n * 2. If `binding.bundleName` is set, look it up in `provenance.bundles`.\n * 3. If exactly one bundle is reported, use its revision unambiguously.\n * 4. If multiple bundles are reported and no selector exists, mark\n * `bundleRevisionStatus: \"ambiguous\"`.\n * 5. If no provenance is reported at all, return `{}` — the caller decides\n * whether absence is meaningful (it is not, for executors that don't\n * carry provenance).\n */\nexport function selectBundleRevision(\n\texecution: OpaPolicyExecution,\n\tbinding: OpaPolicyBinding,\n): BundleSelection {\n\tif (typeof execution.bundleRevision === \"string\" && execution.bundleRevision.length > 0) {\n\t\treturn { bundleRevision: execution.bundleRevision };\n\t}\n\n\tconst bundles = readBundles(execution.provenance);\n\tif (!bundles) return {};\n\n\tconst names = Object.keys(bundles);\n\tif (names.length === 0) return {};\n\n\tif (binding.bundleName) {\n\t\tconst revision = bundles[binding.bundleName]?.revision;\n\t\treturn typeof revision === \"string\" && revision.length > 0\n\t\t\t? { bundleRevision: revision }\n\t\t\t: {};\n\t}\n\n\tif (names.length === 1) {\n\t\tconst only = names[0];\n\t\t// names.length === 1 guarantees names[0] is defined, but the\n\t\t// non-null assertion satisfies noUncheckedIndexedAccess if enabled.\n\t\tconst revision = only !== undefined ? bundles[only]?.revision : undefined;\n\t\treturn typeof revision === \"string\" && revision.length > 0\n\t\t\t? { bundleRevision: revision }\n\t\t\t: {};\n\t}\n\n\treturn { bundleRevisionStatus: \"ambiguous\" };\n}\n\nfunction readBundles(\n\tprovenance: Record<string, unknown> | undefined,\n): Record<string, { revision?: unknown }> | undefined {\n\tif (!provenance || typeof provenance !== \"object\") return undefined;\n\tconst b = (provenance as { bundles?: unknown }).bundles;\n\tif (!b || typeof b !== \"object\" || Array.isArray(b)) return undefined;\n\treturn b as Record<string, { revision?: unknown }>;\n}\n","import type { PolicyEvaluationResult } from \"@fabricorg/platform/policies\";\nimport type { OpaDecision } from \"./types\";\n\nconst POLICY_RESULTS: readonly PolicyEvaluationResult[] = [\"pass\", \"warn\", \"block\"];\n\nexport type OpaDecisionParseResult =\n\t| { ok: true; decision: OpaDecision }\n\t| { ok: false; error: string };\n\n/**\n * Hand-rolled validator for the Rego \"house style\" decision shape. Avoids a\n * runtime zod dependency to keep the adapter zero-dep.\n *\n * Accepts a raw OPA result and either returns the parsed `OpaDecision` or a\n * single human-readable error string describing the first violation. We don't\n * accumulate every error: when audit evidence has to record \"OPA returned\n * something invalid\", one precise reason is more useful than a list.\n */\nexport function parseOpaDecision(raw: unknown): OpaDecisionParseResult {\n\tif (raw === null || typeof raw !== \"object\") {\n\t\treturn { ok: false, error: \"decision must be an object\" };\n\t}\n\n\tconst d = raw as Record<string, unknown>;\n\n\tif (typeof d.result !== \"string\" || !POLICY_RESULTS.includes(d.result as PolicyEvaluationResult)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: `result must be \"pass\" | \"warn\" | \"block\" (got ${JSON.stringify(d.result)})`,\n\t\t};\n\t}\n\n\tif (d.reason !== undefined && typeof d.reason !== \"string\") {\n\t\treturn { ok: false, error: \"reason must be a string when present\" };\n\t}\n\n\tif (d.conditionResults !== undefined) {\n\t\tif (!Array.isArray(d.conditionResults)) {\n\t\t\treturn { ok: false, error: \"conditionResults must be an array when present\" };\n\t\t}\n\t\tfor (let i = 0; i < d.conditionResults.length; i += 1) {\n\t\t\tconst err = validateConditionResult(d.conditionResults[i], i);\n\t\t\tif (err) return { ok: false, error: err };\n\t\t}\n\t}\n\n\tif (d.guidance !== undefined) {\n\t\tconst err = validateGuidance(d.guidance);\n\t\tif (err) return { ok: false, error: err };\n\t}\n\n\tif (d.obligations !== undefined && !isPlainObject(d.obligations)) {\n\t\treturn { ok: false, error: \"obligations must be an object when present\" };\n\t}\n\n\treturn { ok: true, decision: d as unknown as OpaDecision };\n}\n\nfunction validateConditionResult(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `conditionResults[${index}] must be an object`;\n\t}\n\tconst c = value as Record<string, unknown>;\n\tif (typeof c.conditionId !== \"string\" || c.conditionId.length === 0) {\n\t\treturn `conditionResults[${index}].conditionId must be a non-empty string`;\n\t}\n\tif (typeof c.passed !== \"boolean\") {\n\t\treturn `conditionResults[${index}].passed must be a boolean`;\n\t}\n\tif (typeof c.result !== \"string\" || !POLICY_RESULTS.includes(c.result as PolicyEvaluationResult)) {\n\t\treturn `conditionResults[${index}].result must be \"pass\" | \"warn\" | \"block\"`;\n\t}\n\tif (c.reason !== undefined && typeof c.reason !== \"string\") {\n\t\treturn `conditionResults[${index}].reason must be a string when present`;\n\t}\n\treturn null;\n}\n\nfunction validateGuidance(value: unknown): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn \"guidance must be an object when present\";\n\t}\n\tconst guidance = value as Record<string, unknown>;\n\tif (guidance.summary !== undefined && typeof guidance.summary !== \"string\") {\n\t\treturn \"guidance.summary must be a string when present\";\n\t}\n\tif (!Array.isArray(guidance.factsUsed)) {\n\t\treturn \"guidance.factsUsed must be an array\";\n\t}\n\tfor (let i = 0; i < guidance.factsUsed.length; i += 1) {\n\t\tconst err = validatePolicyFact(guidance.factsUsed[i], i);\n\t\tif (err) return err;\n\t}\n\tif (!Array.isArray(guidance.correctiveActions)) {\n\t\treturn \"guidance.correctiveActions must be an array\";\n\t}\n\tfor (let i = 0; i < guidance.correctiveActions.length; i += 1) {\n\t\tconst err = validateCorrectiveAction(guidance.correctiveActions[i], i);\n\t\tif (err) return err;\n\t}\n\treturn null;\n}\n\nfunction validatePolicyFact(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `guidance.factsUsed[${index}] must be an object`;\n\t}\n\tconst fact = value as Record<string, unknown>;\n\tif (typeof fact.name !== \"string\" || fact.name.length === 0) {\n\t\treturn `guidance.factsUsed[${index}].name must be a non-empty string`;\n\t}\n\tif (fact.label !== undefined && typeof fact.label !== \"string\") {\n\t\treturn `guidance.factsUsed[${index}].label must be a string when present`;\n\t}\n\treturn null;\n}\n\nfunction validateCorrectiveAction(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `guidance.correctiveActions[${index}] must be an object`;\n\t}\n\tconst action = value as Record<string, unknown>;\n\tif (typeof action.label !== \"string\" || action.label.length === 0) {\n\t\treturn `guidance.correctiveActions[${index}].label must be a non-empty string`;\n\t}\n\tif (action.description !== undefined && typeof action.description !== \"string\") {\n\t\treturn `guidance.correctiveActions[${index}].description must be a string when present`;\n\t}\n\tif (action.actionId !== undefined && typeof action.actionId !== \"string\") {\n\t\treturn `guidance.correctiveActions[${index}].actionId must be a string when present`;\n\t}\n\tif (action.parameters !== undefined && !isPlainObject(action.parameters)) {\n\t\treturn `guidance.correctiveActions[${index}].parameters must be an object when present`;\n\t}\n\tif (action.target !== undefined && !isPlainObject(action.target)) {\n\t\treturn `guidance.correctiveActions[${index}].target must be an object when present`;\n\t}\n\tif (action.requiresConfirmation !== undefined && typeof action.requiresConfirmation !== \"boolean\") {\n\t\treturn `guidance.correctiveActions[${index}].requiresConfirmation must be a boolean when present`;\n\t}\n\treturn null;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","import { createHash } from \"node:crypto\";\n\n/**\n * Stable JSON stringify — sorts object keys recursively so two\n * structurally-equal inputs produce the same string regardless of property\n * insertion order. Required for hash determinism across builds of the same\n * `buildInput` function.\n */\nexport function stableStringify(value: unknown): string {\n\tif (value === undefined) return \"null\";\n\tif (value === null || typeof value !== \"object\") return JSON.stringify(value);\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map(stableStringify).join(\",\")}]`;\n\t}\n\tconst obj = value as Record<string, unknown>;\n\tconst keys = Object.keys(obj).sort();\n\treturn `{${keys\n\t\t.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`)\n\t\t.join(\",\")}}`;\n}\n\n/**\n * Default input hasher: SHA-256 over a stable stringification.\n * Format: `sha256:<hex>` — namespaced so future migrations to a different\n * algorithm can be detected by a prefix check in evidence dashboards.\n */\nexport function defaultHashInput(input: Record<string, unknown>): string {\n\tconst hex = createHash(\"sha256\").update(stableStringify(input)).digest(\"hex\");\n\treturn `sha256:${hex}`;\n}\n","import type {\n\tPolicyContext,\n\tPolicyEvaluator,\n\tPolicyOutcome,\n} from \"@fabricorg/platform/policies\";\n\nimport { selectBundleRevision } from \"./bundle-selector\";\nimport { parseOpaDecision } from \"./decision-schema\";\nimport { defaultHashInput } from \"./hash\";\nimport type {\n\tCreateOpaPolicyEvaluatorOptions,\n\tOpaDecision,\n\tOpaPolicyBinding,\n\tOpaPolicyClient,\n\tOpaPolicyExecution,\n\tOpaPolicyExecutor,\n\tOpaPolicyFailureKind,\n} from \"./types\";\n\nconst DEFAULT_SERVICE_KEY = \"opa\";\nconst ENGINE_NAME = \"opa\";\n\n/**\n * Build a Fabric `PolicyEvaluator` that delegates decision-making to an OPA\n * (Open Policy Agent) deployment.\n *\n * The adapter accepts either of two service shapes under\n * `ctx.services[serviceKey]`:\n *\n * - `OpaPolicyExecutor` (preferred) — `execute(path, input)` returning a rich\n * `OpaPolicyExecution` (decision plus `decisionId`, `bundleRevision`,\n * `opaVersion`, `provenance`). Ship one with {@link executorFromOpaHttp} or\n * {@link executorFromOpaClient}.\n * - `OpaPolicyClient` — `evaluate(path, input)` returning the raw decision\n * only. Compatible with the high-level `@open-policy-agent/opa` SDK at the\n * cost of OPA-side provenance.\n *\n * If both methods are present, `execute` is preferred.\n *\n * The evaluator:\n *\n * 1. Resolves the service from `ctx.services[serviceKey]`.\n * 2. Builds a JSON input snapshot via `buildInput(ctx)` — domain code that\n * snapshots facts the engine needs. OPA never reaches into the database\n * directly; all facts flow through this function.\n * 3. Calls OPA at `binding.decisionPath`.\n * 4. Validates the response against the house-style shape (`OpaDecision`).\n * 5. Maps the decision to a `PolicyOutcome` and attaches engine provenance\n * under `dispatchEvidence.engine` — `name`, optional `version`, and\n * metadata covering `decisionPath`, `regoPackage`, `inputHash`, plus (when\n * the executor surfaces them) `decisionId`, `bundleName`, `bundleRevision`,\n * `bundleRevisionStatus`, and the raw `provenance` block.\n *\n * Failures (missing client, build failure, network failure, malformed\n * response) are governed by `onError`. Default `\"block\"` honors Fabric's\n * default-deny posture and records the failure category under\n * `engine.metadata.error`.\n */\nexport function createOpaPolicyEvaluator<TDb = unknown>(\n\toptions: CreateOpaPolicyEvaluatorOptions<TDb>,\n): PolicyEvaluator<TDb> {\n\tconst {\n\t\tbinding,\n\t\tbuildInput,\n\t\tserviceKey = DEFAULT_SERVICE_KEY,\n\t\tonError = \"block\",\n\t\tpreviewSafe = false,\n\t\tengineVersion,\n\t\tmapDecision,\n\t\thashInput = defaultHashInput,\n\t} = options;\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tversion: binding.version,\n\t\tpreviewSafe,\n\t\tevaluate: async (ctx) => {\n\t\t\tconst service = ctx.services?.[serviceKey];\n\t\t\tconst transport = resolveTransport(service);\n\t\t\tif (!transport) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"client_unavailable\",\n\t\t\t\t\t`No OPA client/executor at ctx.services[\"${serviceKey}\"]`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet input: Record<string, unknown>;\n\t\t\ttry {\n\t\t\t\tinput = await buildInput(ctx);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"input_build_failed\",\n\t\t\t\t\t`buildInput threw: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet inputHash: string | undefined;\n\t\t\ttry {\n\t\t\t\tinputHash = hashInput(input);\n\t\t\t} catch {\n\t\t\t\t// hashing is best-effort — if a custom hasher throws, omit the\n\t\t\t\t// field rather than fail the policy.\n\t\t\t}\n\n\t\t\tlet execution: OpaPolicyExecution;\n\t\t\ttry {\n\t\t\t\texecution = await transport(binding.decisionPath, input);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"evaluation_failed\",\n\t\t\t\t\t`OPA evaluation failed: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst parsed = parseOpaDecision(execution.decision);\n\t\t\tif (!parsed.ok) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"invalid_response\",\n\t\t\t\t\t`OPA returned malformed decision: ${parsed.error}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t\texecution,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn buildSuccessOutcome(\n\t\t\t\tbinding,\n\t\t\t\tengineVersion,\n\t\t\t\tparsed.decision,\n\t\t\t\texecution,\n\t\t\t\tinputHash,\n\t\t\t\tctx,\n\t\t\t\tmapDecision,\n\t\t\t);\n\t\t},\n\t};\n}\n\n/**\n * Discriminates between the rich executor shape and the legacy client shape.\n * Returns a uniform `(path, input) => OpaPolicyExecution` transport, or\n * `null` if the service doesn't implement either contract.\n *\n * `execute` is preferred when both are present so a v0.1 client wrapped by a\n * richer executor still wins.\n */\nfunction resolveTransport(\n\tservice: unknown,\n): ((path: string, input: unknown) => Promise<OpaPolicyExecution>) | null {\n\tif (!service || typeof service !== \"object\") return null;\n\tconst exec = (service as Partial<OpaPolicyExecutor>).execute;\n\tif (typeof exec === \"function\") {\n\t\treturn (path, input) => (service as OpaPolicyExecutor).execute(path, input);\n\t}\n\tconst eval_ = (service as Partial<OpaPolicyClient>).evaluate;\n\tif (typeof eval_ === \"function\") {\n\t\treturn async (path, input) => ({\n\t\t\tdecision: await (service as OpaPolicyClient).evaluate(path, input),\n\t\t});\n\t}\n\treturn null;\n}\n\nfunction buildSuccessOutcome<TDb>(\n\tbinding: OpaPolicyBinding,\n\tengineVersion: string | undefined,\n\tdecision: OpaDecision,\n\texecution: OpaPolicyExecution,\n\tinputHash: string | undefined,\n\tctx: PolicyContext<TDb>,\n\tmapDecision: CreateOpaPolicyEvaluatorOptions<TDb>[\"mapDecision\"],\n): PolicyOutcome {\n\tconst selection = selectBundleRevision(execution, binding);\n\tconst mapped = mapDecision\n\t\t? mapDecision(decision, ctx, execution)\n\t\t: { result: decision.result, reason: decision.reason };\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: mapped.result ?? decision.result,\n\t\treason: mapped.reason ?? decision.reason,\n\t\tguidance: mapped.guidance ?? decision.guidance,\n\t\tmetadata: {\n\t\t\t...(mapped.metadata ?? {}),\n\t\t\topaDecision: decision,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: execution.opaVersion ?? engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\tdecisionId: execution.decisionId,\n\t\t\t\t\tbundleName: binding.bundleName,\n\t\t\t\t\tbundleRevision: selection.bundleRevision,\n\t\t\t\t\tbundleRevisionStatus: selection.bundleRevisionStatus,\n\t\t\t\t\tprovenance: execution.provenance,\n\t\t\t\t\tconditionResults: decision.conditionResults,\n\t\t\t\t\tobligations: decision.obligations,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction makeFailureOutcome(\n\tbinding: OpaPolicyBinding,\n\tengineVersion: string | undefined,\n\terror: OpaPolicyFailureKind,\n\treason: string,\n\tonError: \"block\" | \"throw\",\n\tinputHash?: string,\n\texecution?: OpaPolicyExecution,\n): PolicyOutcome {\n\tif (onError === \"throw\") {\n\t\tconst err = new Error(reason);\n\t\t(err as Error & { kind?: OpaPolicyFailureKind }).kind = error;\n\t\tthrow err;\n\t}\n\n\tconst selection = execution ? selectBundleRevision(execution, binding) : {};\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: \"block\",\n\t\treason,\n\t\tguidance: {\n\t\t\tsummary: \"OPA policy evaluation could not complete.\",\n\t\t\tfactsUsed: [\n\t\t\t\t{ name: \"opaFailureKind\", value: error, label: \"Failure kind\" },\n\t\t\t\t{ name: \"decisionPath\", value: binding.decisionPath, label: \"Decision path\" },\n\t\t\t],\n\t\t\tcorrectiveActions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Check OPA policy engine\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Verify the OPA service is reachable, serving the expected bundle, and returning the Fabric OPA decision shape.\",\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\tmetadata: {\n\t\t\topaError: error,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: execution?.opaVersion ?? engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\tdecisionId: execution?.decisionId,\n\t\t\t\t\tbundleName: binding.bundleName,\n\t\t\t\t\tbundleRevision: selection.bundleRevision,\n\t\t\t\t\tbundleRevisionStatus: selection.bundleRevisionStatus,\n\t\t\t\t\tprovenance: execution?.provenance,\n\t\t\t\t\terror,\n\t\t\t\t\terrorReason: reason,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction stripUndefined(obj: Record<string, unknown>): Record<string, unknown> {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(obj)) {\n\t\tif (v !== undefined) out[k] = v;\n\t}\n\treturn out;\n}\n\nfunction formatError(err: unknown): string {\n\tif (err instanceof Error) return err.message;\n\tif (typeof err === \"string\") return err;\n\ttry {\n\t\treturn JSON.stringify(err);\n\t} catch {\n\t\treturn String(err);\n\t}\n}\n","import type {\n\tOpaPolicyClient,\n\tOpaPolicyExecution,\n\tOpaPolicyExecutor,\n} from \"./types\";\n\n/**\n * Wrap an `OpaPolicyClient` (the high-level `@open-policy-agent/opa` SDK\n * shape) as an {@link OpaPolicyExecutor}. The resulting executor carries no\n * OPA-side provenance — the high-level SDK discards `decisionId` and\n * `provenance` from the response — but does centralize the\n * `(path, input) => execution` plumbing so hosts can choose at startup whether\n * to wire a client or a full executor.\n *\n * For full provenance (decisionId, bundleRevision, opaVersion), prefer\n * {@link executorFromOpaHttp}.\n */\nexport function executorFromOpaClient(client: OpaPolicyClient): OpaPolicyExecutor {\n\treturn {\n\t\tasync execute(path: string, input: unknown): Promise<OpaPolicyExecution> {\n\t\t\tconst decision = await client.evaluate(path, input);\n\t\t\treturn { decision };\n\t\t},\n\t};\n}\n","import type { OpaPolicyExecution, OpaPolicyExecutor } from \"./types\";\n\nexport interface OpaHttpExecutorOptions {\n\t/**\n\t * Base URL of the OPA server, e.g. `\"http://localhost:8181\"` or\n\t * `\"https://opa.internal.example.com\"`. Trailing slash is permitted; the\n\t * executor normalizes it.\n\t */\n\tbaseUrl: string;\n\t/**\n\t * Override for `globalThis.fetch`. Lets the host inject a fetch instance\n\t * with retries, mTLS, OpenTelemetry instrumentation, etc. Defaults to\n\t * `globalThis.fetch`.\n\t */\n\tfetch?: typeof globalThis.fetch;\n\t/** Extra request headers (e.g. `Authorization`). */\n\theaders?: Record<string, string>;\n\t/**\n\t * Request OPA-side provenance (`decision_id`, `provenance.version`,\n\t * `provenance.bundles[*].revision`) via `?provenance=true`. Defaults to\n\t * `true` — turning it off forfeits OPA's contribution to audit evidence\n\t * and is rarely what you want.\n\t */\n\tprovenance?: boolean;\n}\n\ninterface OpaHttpResponseBody {\n\tresult?: unknown;\n\tdecision_id?: string;\n\tprovenance?: {\n\t\tversion?: string;\n\t\tbuild_commit?: string;\n\t\tbuild_timestamp?: string;\n\t\tbuild_host?: string;\n\t\tbundles?: Record<string, { revision?: string }>;\n\t};\n}\n\n/**\n * Build an {@link OpaPolicyExecutor} that talks to OPA's REST API directly.\n *\n * POSTs to `{baseUrl}/v1/data/{path}?provenance=true` with body\n * `{ \"input\": ... }`. Parses the snake_case response and lifts:\n *\n * - `result` → `execution.decision`\n * - `decision_id` → `execution.decisionId`\n * - `provenance.version` → `execution.opaVersion`\n * - `provenance` (whole block) → `execution.provenance`\n *\n * Bundle revision selection happens in the factory, not the executor, because\n * it depends on `binding.bundleName`.\n *\n * Calling this in environments without `globalThis.fetch` (older Node) throws\n * at call time; pass `fetch: nodeFetch` or `fetch: undici-fetch` etc. via the\n * options to support those runtimes explicitly.\n */\nexport function executorFromOpaHttp(opts: OpaHttpExecutorOptions): OpaPolicyExecutor {\n\tconst baseUrl = stripTrailingSlash(opts.baseUrl);\n\tconst provenance = opts.provenance ?? true;\n\tconst customFetch = opts.fetch;\n\tconst headers = {\n\t\t\"content-type\": \"application/json\",\n\t\taccept: \"application/json\",\n\t\t...(opts.headers ?? {}),\n\t};\n\n\treturn {\n\t\tasync execute(path: string, input: unknown): Promise<OpaPolicyExecution> {\n\t\t\tconst fetchImpl = customFetch ?? globalThis.fetch;\n\t\t\tif (typeof fetchImpl !== \"function\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"executorFromOpaHttp: no fetch implementation available. Pass `fetch` in options or run on a runtime with `globalThis.fetch`.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst url = `${baseUrl}/v1/data/${stripLeadingSlash(path)}${\n\t\t\t\tprovenance ? \"?provenance=true\" : \"\"\n\t\t\t}`;\n\t\t\tconst response = await fetchImpl(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({ input }),\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst text = await safeReadText(response);\n\t\t\t\tthrow new Error(`OPA HTTP ${response.status} at ${url}: ${truncate(text, 500)}`);\n\t\t\t}\n\n\t\t\tconst body = (await response.json()) as OpaHttpResponseBody;\n\n\t\t\treturn {\n\t\t\t\tdecision: body.result,\n\t\t\t\tdecisionId: body.decision_id,\n\t\t\t\topaVersion: body.provenance?.version,\n\t\t\t\tprovenance: body.provenance as Record<string, unknown> | undefined,\n\t\t\t};\n\t\t},\n\t};\n}\n\nfunction stripTrailingSlash(s: string): string {\n\treturn s.replace(/\\/+$/, \"\");\n}\n\nfunction stripLeadingSlash(s: string): string {\n\treturn s.replace(/^\\/+/, \"\");\n}\n\nasync function safeReadText(response: Response): Promise<string> {\n\ttry {\n\t\treturn await response.text();\n\t} catch {\n\t\treturn \"<unreadable body>\";\n\t}\n}\n\nfunction truncate(s: string, max: number): string {\n\treturn s.length <= max ? s : `${s.slice(0, max)}…`;\n}\n"]}
package/package.json CHANGED
@@ -1,71 +1,72 @@
1
1
  {
2
- "name": "@fabricorg/policy-opa",
3
- "version": "0.2.0",
4
- "description": "Open Policy Agent (OPA) adapter for @fabricorg/platform. Wraps a Rego decision behind Fabric's PolicyEvaluator contract — Fabric keeps policyId.vN canonical for audit; engine evidence carries OPA provenance (decision path, input hash, bundle revision). Zero coupling to a specific OPA SDK; structurally typed client.",
5
- "keywords": [
6
- "fabric",
7
- "fabricorg",
8
- "policy",
9
- "opa",
10
- "open-policy-agent",
11
- "rego",
12
- "authorization",
13
- "policy-engine"
14
- ],
15
- "license": "MIT",
16
- "author": "Fabric",
17
- "repository": {
18
- "type": "git",
19
- "url": "https://github.com/Fabric-Pro/fabric-platform.git",
20
- "directory": "packages/policy-opa"
21
- },
22
- "homepage": "https://github.com/Fabric-Pro/fabric-platform#readme",
23
- "bugs": {
24
- "url": "https://github.com/Fabric-Pro/fabric-platform/issues"
25
- },
26
- "type": "module",
27
- "sideEffects": false,
28
- "main": "./dist/index.cjs",
29
- "types": "./dist/index.d.ts",
30
- "exports": {
31
- ".": {
32
- "import": {
33
- "types": "./dist/index.d.ts",
34
- "default": "./dist/index.js"
35
- },
36
- "require": {
37
- "types": "./dist/index.d.cts",
38
- "default": "./dist/index.cjs"
39
- }
40
- }
41
- },
42
- "files": [
43
- "dist",
44
- "README.md",
45
- "CHANGELOG.md",
46
- "LICENSE"
47
- ],
48
- "peerDependencies": {
49
- "@fabricorg/platform": "^0.3.2"
50
- },
51
- "dependencies": {},
52
- "devDependencies": {
53
- "@types/node": "^22.10.0",
54
- "tsup": "^8.5.0",
55
- "typescript": "^5.7.3",
56
- "vitest": "^4.1.5",
57
- "@fabricorg/platform": "0.3.2"
58
- },
59
- "engines": {
60
- "node": ">=20"
61
- },
62
- "publishConfig": {
63
- "access": "public"
64
- },
65
- "scripts": {
66
- "clean": "rm -rf dist tsconfig.tsbuildinfo",
67
- "build": "tsup",
68
- "type-check": "tsc --noEmit",
69
- "test": "vitest run --passWithNoTests"
70
- }
71
- }
2
+ "name": "@fabricorg/policy-opa",
3
+ "version": "0.3.0",
4
+ "description": "Open Policy Agent (OPA) adapter for @fabricorg/platform. Wraps a Rego decision behind Fabric's PolicyEvaluator contract — Fabric keeps policyId.vN canonical for audit; engine evidence carries OPA provenance (decision path, input hash, bundle revision). Zero coupling to a specific OPA SDK; structurally typed client.",
5
+ "keywords": [
6
+ "fabric",
7
+ "fabricorg",
8
+ "policy",
9
+ "opa",
10
+ "open-policy-agent",
11
+ "rego",
12
+ "authorization",
13
+ "policy-engine"
14
+ ],
15
+ "license": "MIT",
16
+ "author": "Fabric",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/Fabric-Pro/fabric-platform.git",
20
+ "directory": "packages/policy-opa"
21
+ },
22
+ "homepage": "https://github.com/Fabric-Pro/fabric-platform#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/Fabric-Pro/fabric-platform/issues"
25
+ },
26
+ "type": "module",
27
+ "sideEffects": false,
28
+ "main": "./dist/index.cjs",
29
+ "types": "./dist/index.d.ts",
30
+ "exports": {
31
+ ".": {
32
+ "import": {
33
+ "types": "./dist/index.d.ts",
34
+ "default": "./dist/index.js"
35
+ },
36
+ "require": {
37
+ "types": "./dist/index.d.cts",
38
+ "default": "./dist/index.cjs"
39
+ }
40
+ }
41
+ },
42
+ "files": [
43
+ "dist",
44
+ "README.md",
45
+ "CHANGELOG.md",
46
+ "LICENSE"
47
+ ],
48
+ "scripts": {
49
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
50
+ "build": "tsup",
51
+ "type-check": "tsc --noEmit",
52
+ "test": "vitest run --passWithNoTests",
53
+ "prepublishOnly": "pnpm clean && pnpm build && pnpm test"
54
+ },
55
+ "peerDependencies": {
56
+ "@fabricorg/platform": "^0.4.0"
57
+ },
58
+ "dependencies": {},
59
+ "devDependencies": {
60
+ "@fabricorg/platform": "workspace:*",
61
+ "@types/node": "^22.10.0",
62
+ "tsup": "^8.5.0",
63
+ "typescript": "^5.7.3",
64
+ "vitest": "^4.1.5"
65
+ },
66
+ "engines": {
67
+ "node": ">=20"
68
+ },
69
+ "publishConfig": {
70
+ "access": "public"
71
+ }
72
+ }