@nexart/ai-execution 0.11.0 → 0.12.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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @nexart/ai-execution v0.11.0
1
+ # @nexart/ai-execution v0.12.0
2
2
 
3
3
  Tamper-evident records and Certified Execution Records (CER) for AI operations.
4
4
 
@@ -7,7 +7,7 @@ Tamper-evident records and Certified Execution Records (CER) for AI operations.
7
7
  | Component | Version |
8
8
  |---|---|
9
9
  | Service | — |
10
- | SDK | 0.11.0 |
10
+ | SDK | 0.12.0 |
11
11
  | Protocol | 1.2.0 |
12
12
 
13
13
  ## Why Not Just Store Logs?
@@ -213,6 +213,78 @@ const bundle = sealCer(snapshot, {
213
213
  // verifyCer(bundle).ok === true — declaration does not affect the result
214
214
  ```
215
215
 
216
+ ## CER Packages (v0.12.0+)
217
+
218
+ A **CER package** is a transport/export envelope that wraps a sealed `cer.ai.execution.v1` bundle with optional receipt, signature, and attestation metadata.
219
+
220
+ ```
221
+ {
222
+ "cer": { ...sealed cer.ai.execution.v1 bundle... },
223
+ "receipt": { ...optional attestation receipt... },
224
+ "signature": "base64url...",
225
+ "attestation": { ...optional attestation summary... },
226
+ "verificationEnvelope": { ...optional envelope metadata... },
227
+ "verificationEnvelopeSignature": "base64url..."
228
+ }
229
+ ```
230
+
231
+ **When to use package helpers vs raw bundle helpers**
232
+
233
+ | Use case | Recommended API |
234
+ |---|---|
235
+ | Creating, verifying, or archiving a CER locally | `certifyDecision`, `verifyCer`, `exportCer` / `importCer` (raw bundle) |
236
+ | Wrapping a CER for transport or external storage with optional metadata | `createCerPackage`, `exportCerPackage`, `importCerPackage` |
237
+ | Detecting whether an object is a package or a raw bundle | `isCerPackage` |
238
+ | Extracting the CER from a received package | `getCerFromPackage` |
239
+ | Verifying integrity of a received package's inner CER | `verifyCerPackage` |
240
+
241
+ The `cer` field inside a package is authoritative. Package helpers never mutate it, never re-hash it, and never inject package-level fields into the CER.
242
+
243
+ ### Creating and exporting a package
244
+
245
+ ```typescript
246
+ import { certifyDecision, createCerPackage, exportCerPackage } from '@nexart/ai-execution';
247
+
248
+ const cer = certifyDecision({
249
+ provider: 'openai',
250
+ model: 'gpt-4o',
251
+ prompt: 'Summarize.',
252
+ input: userQuery,
253
+ output: llmResponse,
254
+ parameters: { temperature: 0.7, maxTokens: 1024, topP: null, seed: null },
255
+ });
256
+
257
+ const pkg = createCerPackage({
258
+ cer,
259
+ receipt: myAttestationReceipt, // optional
260
+ signature: 'base64url...', // optional
261
+ });
262
+
263
+ const json = exportCerPackage(pkg); // stable canonical JSON
264
+ ```
265
+
266
+ ### Importing and verifying a package
267
+
268
+ ```typescript
269
+ import { importCerPackage, verifyCerPackage, getCerFromPackage } from '@nexart/ai-execution';
270
+
271
+ // importCerPackage parses + validates shape + verifies inner CER hash
272
+ const pkg = importCerPackage(receivedJsonString); // throws CerVerificationError on failure
273
+
274
+ // Alternatively: parse yourself then verify
275
+ const result = verifyCerPackage(parsedObj);
276
+ if (!result.ok) throw new Error(result.errors.join('; '));
277
+
278
+ const cer = getCerFromPackage(parsedObj); // throws if not a valid package
279
+ ```
280
+
281
+ **Design constraints of package helpers:**
282
+ - Additive only — no changes to CER hashing, canonicalization, or `verifyCer()` semantics
283
+ - `verifyCerPackage` only verifies the inner `cer` bundle; receipt/signature/envelope fields are opaque transport metadata not verified here
284
+ - All existing raw bundle flows (`importCer`, `exportCer`, `verifyCer`) are unchanged
285
+
286
+ ---
287
+
216
288
  ## Attestation
217
289
 
218
290
  Endpoint: `POST {nodeUrl}/api/attest`
@@ -635,6 +707,19 @@ Fixtures at `fixtures/vectors/` and `fixtures/golden/`. Cross-language implement
635
707
  | `exportCer(bundle)` | Serialize to canonical JSON string |
636
708
  | `importCer(json)` | Parse + verify from JSON string |
637
709
 
710
+ ### CER Package Helpers (v0.12.0+)
711
+
712
+ | Function | Description |
713
+ |---|---|
714
+ | `isCerPackage(value)` | Type guard: returns `true` if `value` is a CER package shape (`{ cer: { bundleType: 'cer.ai.execution.v1', ... }, ... }`). Structural check only — does not verify the inner CER hash. |
715
+ | `createCerPackage(params)` | Assemble a CER package from a sealed CER and optional transport fields (`receipt`, `signature`, `attestation`, `verificationEnvelope`, `verificationEnvelopeSignature`). Assembly only — does not re-hash or re-sign. |
716
+ | `getCerFromPackage(pkg)` | Extract and return the inner CER bundle. Throws `CerVerificationError` if `pkg` is not a valid package shape. |
717
+ | `exportCerPackage(pkg)` | Serialize a CER package to a stable canonical JSON string. |
718
+ | `importCerPackage(json)` | Parse a CER package JSON string, validate its shape, and verify the inner CER with `verifyCer()`. Throws `CerVerificationError` on any failure. |
719
+ | `verifyCerPackage(pkg)` | Verify the inner CER of a package using `verifyCer()`. Returns a `VerificationResult`. Conservative: only verifies the inner `cer` — does not verify receipt/signature/envelope. |
720
+
721
+ **Exported types:** `AiCerPackage`, `CreateCerPackageParams`
722
+
638
723
  ### Provider Drop-in (v0.6.0+)
639
724
 
640
725
  | Function | Description |
@@ -686,7 +771,7 @@ Priority when multiple failures exist: `CANONICALIZATION_ERROR` > `SCHEMA_ERROR`
686
771
 
687
772
  ## LangChain Integration
688
773
 
689
- `@nexart/ai-execution` includes a minimal LangChain helper surface (introduced v0.10.0, current v0.11.0). Certify the final input and output of any LangChain chain, agent, or runnable as a tamper-evident CER — no LangChain package dependency required.
774
+ `@nexart/ai-execution` includes a minimal LangChain helper surface (introduced v0.10.0, current v0.12.0). Certify the final input and output of any LangChain chain, agent, or runnable as a tamper-evident CER — no LangChain package dependency required.
690
775
 
691
776
  `certifyLangChainRun` operates in two modes depending on whether `nodeUrl` and `apiKey` are supplied:
692
777
 
@@ -957,7 +1042,8 @@ import type { CerContextSignal, CerContext } from '@nexart/ai-execution';
957
1042
  | v0.8.0 | Helper APIs: `exportVerifiableRedacted()` (post-seal re-seal with redacted snapshot + provenance metadata); `certifyAndAttestRun()` (one-call multi-step certify + optional per-step attestation with injectable mock); test determinism fix; all v0.1–v0.7 bundles verify identically |
958
1043
  | v0.9.0 | CER Protocol types: `CerVerificationResult`, `ReasonCode`, `CheckStatus`; `verifyAiCerBundleDetailed()`; `CertifyDecisionParams.createdAt` wired through; determinism bug fix |
959
1044
  | v0.10.0 | LangChain integration: `createLangChainCer()` (sync/local); `certifyLangChainRun()` dual-mode — local (sync) or node-attested (`Promise<LangChainAttestedResult>` when `nodeUrl`+`apiKey` supplied); `LangChainAttestedResult`, `AttestDecisionFn`; injectable `_attestFn` for test mocking. **Context signals:** optional `signals?: CerContextSignal[]` on `certifyDecision`, `certifyLangChainRun`, and `createLangChainCer` — sealed into `bundle.context` and included in `certificateHash` when non-empty; absent or empty = hash unchanged from pre-v0.10.0. New types: `CerContextSignal`, `CerContext`. New example: `examples/signals-cer.ts`. 413 total tests; all prior bundles verify identically |
960
- | **v0.11.0** | Version release. Ships all v0.10.0 features (LangChain integration + context signals) as the published package version. `cerSignals.test.js` added to the `npm test` script. No API, hash, or canonicalization changes |
1045
+ | v0.11.0 | Version release. Ships all v0.10.0 features (LangChain integration + context signals) as the published package version. `cerSignals.test.js` added to the `npm test` script. No API, hash, or canonicalization changes |
1046
+ | **v0.12.0** | CER package helpers: `isCerPackage`, `createCerPackage`, `getCerFromPackage`, `exportCerPackage`, `importCerPackage`, `verifyCerPackage`. New types: `AiCerPackage`, `CreateCerPackageParams`. Additive only — no changes to CER hashing, canonicalization, or verification semantics. 466 total tests; all prior bundles verify identically |
961
1047
  | v1.0.0 | Planned: API stabilization, freeze public API surface |
962
1048
 
963
1049
  ## Releasing
package/dist/index.cjs CHANGED
@@ -44,18 +44,23 @@ __export(src_exports, {
44
44
  certifyLangChainRun: () => certifyLangChainRun,
45
45
  computeInputHash: () => computeInputHash,
46
46
  computeOutputHash: () => computeOutputHash,
47
+ createCerPackage: () => createCerPackage,
47
48
  createClient: () => createClient,
48
49
  createLangChainCer: () => createLangChainCer,
49
50
  createSnapshot: () => createSnapshot,
50
51
  exportCer: () => exportCer,
52
+ exportCerPackage: () => exportCerPackage,
51
53
  exportVerifiableRedacted: () => exportVerifiableRedacted,
52
54
  fetchNodeKeys: () => fetchNodeKeys,
53
55
  getAttestationReceipt: () => getAttestationReceipt,
56
+ getCerFromPackage: () => getCerFromPackage,
54
57
  hasAttestation: () => hasAttestation,
55
58
  hashCanonicalJson: () => hashCanonicalJson,
56
59
  hashToolOutput: () => hashToolOutput,
57
60
  hashUtf8: () => hashUtf8,
58
61
  importCer: () => importCer,
62
+ importCerPackage: () => importCerPackage,
63
+ isCerPackage: () => isCerPackage,
59
64
  makeToolEvent: () => makeToolEvent,
60
65
  mapToAiefReason: () => mapToAiefReason,
61
66
  redactBeforeSeal: () => redactBeforeSeal,
@@ -72,6 +77,7 @@ __export(src_exports, {
72
77
  verifyAief: () => verifyAief,
73
78
  verifyBundleAttestation: () => verifyBundleAttestation,
74
79
  verifyCer: () => verifyCer,
80
+ verifyCerPackage: () => verifyCerPackage,
75
81
  verifyNodeReceiptSignature: () => verifyNodeReceiptSignature,
76
82
  verifyRunSummary: () => verifyRunSummary,
77
83
  verifySnapshot: () => verifySnapshot,
@@ -2737,6 +2743,67 @@ function certifyLangChainRun(input, _options) {
2737
2743
  }
2738
2744
  return createLangChainCer(input);
2739
2745
  }
2746
+
2747
+ // src/package.ts
2748
+ function isCerPackage(value) {
2749
+ if (typeof value !== "object" || value === null) return false;
2750
+ const pkg = value;
2751
+ if (typeof pkg["cer"] !== "object" || pkg["cer"] === null) return false;
2752
+ const cer = pkg["cer"];
2753
+ return cer["bundleType"] === "cer.ai.execution.v1";
2754
+ }
2755
+ function createCerPackage(params) {
2756
+ const pkg = { cer: params.cer };
2757
+ if (params.receipt !== void 0) pkg.receipt = params.receipt;
2758
+ if (params.signature !== void 0) pkg.signature = params.signature;
2759
+ if (params.attestation !== void 0) pkg.attestation = params.attestation;
2760
+ if (params.verificationEnvelope !== void 0) pkg.verificationEnvelope = params.verificationEnvelope;
2761
+ if (params.verificationEnvelopeSignature !== void 0) pkg.verificationEnvelopeSignature = params.verificationEnvelopeSignature;
2762
+ return pkg;
2763
+ }
2764
+ function getCerFromPackage(pkg) {
2765
+ if (!isCerPackage(pkg)) {
2766
+ throw new CerVerificationError([
2767
+ "getCerFromPackage: value is not a valid CER package (missing or invalid cer field)"
2768
+ ]);
2769
+ }
2770
+ return pkg.cer;
2771
+ }
2772
+ function exportCerPackage(pkg) {
2773
+ return toCanonicalJson(pkg);
2774
+ }
2775
+ function importCerPackage(json) {
2776
+ let parsed;
2777
+ try {
2778
+ parsed = JSON.parse(json);
2779
+ } catch (err2) {
2780
+ throw new CerVerificationError([
2781
+ `importCerPackage: invalid JSON: ${err2.message}`
2782
+ ]);
2783
+ }
2784
+ if (!isCerPackage(parsed)) {
2785
+ throw new CerVerificationError([
2786
+ "importCerPackage: parsed value is not a CER package (missing or invalid cer field)"
2787
+ ]);
2788
+ }
2789
+ const result = verifyCer(parsed.cer);
2790
+ if (!result.ok) {
2791
+ throw new CerVerificationError([
2792
+ `importCerPackage: inner CER failed verification: ${result.errors.join("; ")}`
2793
+ ]);
2794
+ }
2795
+ return parsed;
2796
+ }
2797
+ function verifyCerPackage(pkg) {
2798
+ if (!isCerPackage(pkg)) {
2799
+ return {
2800
+ ok: false,
2801
+ errors: ["verifyCerPackage: value is not a CER package (missing or invalid cer field)"],
2802
+ code: CerVerifyCode.SCHEMA_ERROR
2803
+ };
2804
+ }
2805
+ return verifyCer(pkg.cer);
2806
+ }
2740
2807
  // Annotate the CommonJS export names for ESM import in node:
2741
2808
  0 && (module.exports = {
2742
2809
  CerAttestationError,
@@ -2753,18 +2820,23 @@ function certifyLangChainRun(input, _options) {
2753
2820
  certifyLangChainRun,
2754
2821
  computeInputHash,
2755
2822
  computeOutputHash,
2823
+ createCerPackage,
2756
2824
  createClient,
2757
2825
  createLangChainCer,
2758
2826
  createSnapshot,
2759
2827
  exportCer,
2828
+ exportCerPackage,
2760
2829
  exportVerifiableRedacted,
2761
2830
  fetchNodeKeys,
2762
2831
  getAttestationReceipt,
2832
+ getCerFromPackage,
2763
2833
  hasAttestation,
2764
2834
  hashCanonicalJson,
2765
2835
  hashToolOutput,
2766
2836
  hashUtf8,
2767
2837
  importCer,
2838
+ importCerPackage,
2839
+ isCerPackage,
2768
2840
  makeToolEvent,
2769
2841
  mapToAiefReason,
2770
2842
  redactBeforeSeal,
@@ -2781,6 +2853,7 @@ function certifyLangChainRun(input, _options) {
2781
2853
  verifyAief,
2782
2854
  verifyBundleAttestation,
2783
2855
  verifyCer,
2856
+ verifyCerPackage,
2784
2857
  verifyNodeReceiptSignature,
2785
2858
  verifyRunSummary,
2786
2859
  verifySnapshot,