@nexart/ai-execution 0.6.0 → 0.7.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/wrap.ts","../../src/hash.ts","../../src/canonicalJson.ts","../../src/snapshot.ts","../../src/cer.ts"],"sourcesContent":["import * as crypto from 'crypto';\nimport type {\n ProviderConfig,\n WrappedExecutionParams,\n WrappedExecutionResult,\n} from '../types.js';\nimport { createSnapshot } from '../snapshot.js';\nimport { sealCer } from '../cer.js';\n\nexport function wrapProvider<TInput = unknown, TOutput = unknown>(\n config: ProviderConfig<TInput, TOutput>,\n) {\n return {\n async execute(params: WrappedExecutionParams & { providerInput: TInput }): Promise<WrappedExecutionResult> {\n const raw = await config.callFn(params.providerInput);\n const output = config.extractOutput(raw);\n const modelVersion = config.extractModelVersion\n ? config.extractModelVersion(raw)\n : (params.modelVersion ?? null);\n\n const snapshot = createSnapshot({\n executionId: params.executionId ?? crypto.randomUUID(),\n provider: config.provider,\n model: params.model,\n modelVersion,\n prompt: params.prompt,\n input: params.input,\n parameters: params.parameters,\n output,\n appId: params.appId,\n });\n\n const bundle = sealCer(snapshot, { meta: params.meta });\n\n return { output, snapshot, bundle };\n },\n };\n}\n","import * as crypto from 'crypto';\nimport { toCanonicalJson } from './canonicalJson.js';\n\nexport function sha256Hex(data: string | Uint8Array): string {\n const hash = crypto.createHash('sha256');\n if (typeof data === 'string') {\n hash.update(data, 'utf-8');\n } else {\n hash.update(data);\n }\n return hash.digest('hex');\n}\n\nexport function hashUtf8(value: string): string {\n return `sha256:${sha256Hex(value)}`;\n}\n\nexport function hashCanonicalJson(value: unknown): string {\n const canonical = toCanonicalJson(value);\n return `sha256:${sha256Hex(canonical)}`;\n}\n\nexport function computeInputHash(input: string | Record<string, unknown>): string {\n if (typeof input === 'string') {\n return hashUtf8(input);\n }\n return hashCanonicalJson(input);\n}\n\nexport function computeOutputHash(output: string | Record<string, unknown>): string {\n if (typeof output === 'string') {\n return hashUtf8(output);\n }\n return hashCanonicalJson(output);\n}\n","export function toCanonicalJson(value: unknown): string {\n return canonicalize(value);\n}\n\nfunction canonicalize(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false';\n }\n\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n throw new Error(`Non-finite number not allowed in canonical JSON: ${value}`);\n }\n return JSON.stringify(value);\n }\n\n if (typeof value === 'string') {\n return JSON.stringify(value);\n }\n\n if (Array.isArray(value)) {\n const items = value.map(item => canonicalize(item));\n return '[' + items.join(',') + ']';\n }\n\n if (typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const entries = keys.map(key => {\n const val = obj[key];\n if (val === undefined) {\n return null;\n }\n return JSON.stringify(key) + ':' + canonicalize(val);\n }).filter(e => e !== null);\n return '{' + entries.join(',') + '}';\n }\n\n throw new Error(`Unsupported type for canonical JSON: ${typeof value}`);\n}\n","import type { AiExecutionSnapshotV1, CreateSnapshotParams, VerificationResult, AiExecutionParameters } from './types.js';\nimport { CerVerifyCode } from './types.js';\nimport { computeInputHash, computeOutputHash } from './hash.js';\n\nconst PACKAGE_VERSION = '0.6.0';\n\nfunction validateParameters(params: AiExecutionParameters): string[] {\n const errors: string[] = [];\n\n if (typeof params.temperature !== 'number' || !Number.isFinite(params.temperature)) {\n errors.push(`parameters.temperature must be a finite number, got: ${params.temperature}`);\n }\n\n if (typeof params.maxTokens !== 'number' || !Number.isFinite(params.maxTokens)) {\n errors.push(`parameters.maxTokens must be a finite number, got: ${params.maxTokens}`);\n }\n\n if (params.topP !== null && (typeof params.topP !== 'number' || !Number.isFinite(params.topP))) {\n errors.push(`parameters.topP must be a finite number or null, got: ${params.topP}`);\n }\n\n if (params.seed !== null && (typeof params.seed !== 'number' || !Number.isFinite(params.seed))) {\n errors.push(`parameters.seed must be a finite number or null, got: ${params.seed}`);\n }\n\n return errors;\n}\n\nexport function createSnapshot(params: CreateSnapshotParams): AiExecutionSnapshotV1 {\n const paramErrors = validateParameters(params.parameters);\n if (paramErrors.length > 0) {\n throw new Error(`Invalid parameters: ${paramErrors.join('; ')}`);\n }\n\n const inputHash = computeInputHash(params.input);\n const outputHash = computeOutputHash(params.output);\n\n const snapshot: AiExecutionSnapshotV1 = {\n type: 'ai.execution.v1',\n protocolVersion: '1.2.0',\n executionSurface: 'ai',\n executionId: params.executionId,\n timestamp: params.timestamp ?? new Date().toISOString(),\n provider: params.provider,\n model: params.model,\n modelVersion: params.modelVersion ?? null,\n prompt: params.prompt,\n input: params.input,\n inputHash,\n parameters: {\n temperature: params.parameters.temperature,\n maxTokens: params.parameters.maxTokens,\n topP: params.parameters.topP ?? null,\n seed: params.parameters.seed ?? null,\n },\n output: params.output,\n outputHash,\n sdkVersion: params.sdkVersion ?? PACKAGE_VERSION,\n appId: params.appId ?? null,\n };\n\n if (params.runId !== undefined) snapshot.runId = params.runId ?? null;\n if (params.stepId !== undefined) snapshot.stepId = params.stepId ?? null;\n if (params.stepIndex !== undefined) snapshot.stepIndex = params.stepIndex ?? null;\n if (params.workflowId !== undefined) snapshot.workflowId = params.workflowId ?? null;\n if (params.conversationId !== undefined) snapshot.conversationId = params.conversationId ?? null;\n if (params.prevStepHash !== undefined) snapshot.prevStepHash = params.prevStepHash ?? null;\n\n return snapshot;\n}\n\nexport function verifySnapshot(snapshot: AiExecutionSnapshotV1): VerificationResult {\n const schemaErrors: string[] = [];\n const formatErrors: string[] = [];\n const inputHashErrors: string[] = [];\n const outputHashErrors: string[] = [];\n\n if (snapshot.type !== 'ai.execution.v1') {\n schemaErrors.push(`Expected type \"ai.execution.v1\", got \"${snapshot.type}\"`);\n }\n\n if (snapshot.protocolVersion !== '1.2.0') {\n schemaErrors.push(`Expected protocolVersion \"1.2.0\", got \"${snapshot.protocolVersion}\"`);\n }\n\n if (snapshot.executionSurface !== 'ai') {\n schemaErrors.push(`Expected executionSurface \"ai\", got \"${snapshot.executionSurface}\"`);\n }\n\n if (!snapshot.executionId || typeof snapshot.executionId !== 'string') {\n schemaErrors.push('executionId must be a non-empty string');\n }\n\n if (!snapshot.timestamp || typeof snapshot.timestamp !== 'string') {\n schemaErrors.push('timestamp must be a non-empty string');\n }\n\n if (!snapshot.provider || typeof snapshot.provider !== 'string') {\n schemaErrors.push('provider must be a non-empty string');\n }\n\n if (!snapshot.model || typeof snapshot.model !== 'string') {\n schemaErrors.push('model must be a non-empty string');\n }\n\n if (!snapshot.prompt || typeof snapshot.prompt !== 'string') {\n schemaErrors.push('prompt must be a non-empty string');\n }\n\n if (snapshot.input === undefined || snapshot.input === null) {\n schemaErrors.push('input must be a string or object');\n }\n\n if (snapshot.output === undefined || snapshot.output === null) {\n schemaErrors.push('output must be a string or object');\n }\n\n const paramErrors = validateParameters(snapshot.parameters);\n schemaErrors.push(...paramErrors);\n\n if (!snapshot.inputHash || !snapshot.inputHash.startsWith('sha256:')) {\n formatErrors.push(`inputHash must start with \"sha256:\", got \"${snapshot.inputHash}\"`);\n }\n\n if (!snapshot.outputHash || !snapshot.outputHash.startsWith('sha256:')) {\n formatErrors.push(`outputHash must start with \"sha256:\", got \"${snapshot.outputHash}\"`);\n }\n\n if (formatErrors.length === 0) {\n const expectedInputHash = computeInputHash(snapshot.input);\n if (snapshot.inputHash !== expectedInputHash) {\n inputHashErrors.push(`inputHash mismatch: expected ${expectedInputHash}, got ${snapshot.inputHash}`);\n }\n\n const expectedOutputHash = computeOutputHash(snapshot.output);\n if (snapshot.outputHash !== expectedOutputHash) {\n outputHashErrors.push(`outputHash mismatch: expected ${expectedOutputHash}, got ${snapshot.outputHash}`);\n }\n }\n\n const errors = [...schemaErrors, ...formatErrors, ...inputHashErrors, ...outputHashErrors];\n\n if (errors.length === 0) {\n return { ok: true, errors: [], code: CerVerifyCode.OK };\n }\n\n let code: typeof CerVerifyCode[keyof typeof CerVerifyCode];\n let details: string[];\n\n if (schemaErrors.length > 0) {\n code = CerVerifyCode.SCHEMA_ERROR;\n details = schemaErrors;\n } else if (formatErrors.length > 0) {\n code = CerVerifyCode.INVALID_SHA256_FORMAT;\n details = formatErrors;\n } else if (inputHashErrors.length > 0 && outputHashErrors.length > 0) {\n code = CerVerifyCode.SNAPSHOT_HASH_MISMATCH;\n details = [...inputHashErrors, ...outputHashErrors];\n } else if (inputHashErrors.length > 0) {\n code = CerVerifyCode.INPUT_HASH_MISMATCH;\n details = inputHashErrors;\n } else if (outputHashErrors.length > 0) {\n code = CerVerifyCode.OUTPUT_HASH_MISMATCH;\n details = outputHashErrors;\n } else {\n code = CerVerifyCode.UNKNOWN_ERROR;\n details = errors;\n }\n\n return { ok: false, errors, code, details };\n}\n","import type { AiExecutionSnapshotV1, CerAiExecutionBundle, CerMeta, VerificationResult } from './types.js';\nimport { CerVerifyCode } from './types.js';\nimport { toCanonicalJson } from './canonicalJson.js';\nimport { sha256Hex } from './hash.js';\nimport { verifySnapshot } from './snapshot.js';\n\ninterface CertificatePayload {\n bundleType: 'cer.ai.execution.v1';\n createdAt: string;\n snapshot: AiExecutionSnapshotV1;\n version: '0.1';\n}\n\nfunction computeCertificateHash(payload: CertificatePayload): string {\n const canonical = toCanonicalJson(payload);\n return `sha256:${sha256Hex(canonical)}`;\n}\n\nexport function sealCer(\n snapshot: AiExecutionSnapshotV1,\n options?: { createdAt?: string; meta?: CerMeta }\n): CerAiExecutionBundle {\n const createdAt = options?.createdAt ?? new Date().toISOString();\n\n const payload: CertificatePayload = {\n bundleType: 'cer.ai.execution.v1',\n createdAt,\n snapshot,\n version: '0.1',\n };\n\n const certificateHash = computeCertificateHash(payload);\n\n const bundle: CerAiExecutionBundle = {\n bundleType: 'cer.ai.execution.v1',\n certificateHash,\n createdAt,\n version: '0.1',\n snapshot,\n };\n\n if (options?.meta) {\n bundle.meta = options.meta;\n }\n\n return bundle;\n}\n\nexport function verifyCer(bundle: CerAiExecutionBundle): VerificationResult {\n const schemaErrors: string[] = [];\n const formatErrors: string[] = [];\n\n if (bundle.bundleType !== 'cer.ai.execution.v1') {\n schemaErrors.push(`Expected bundleType \"cer.ai.execution.v1\", got \"${bundle.bundleType}\"`);\n }\n\n if (bundle.version !== '0.1') {\n schemaErrors.push(`Expected version \"0.1\", got \"${bundle.version}\"`);\n }\n\n if (!bundle.createdAt || typeof bundle.createdAt !== 'string') {\n schemaErrors.push('createdAt must be a non-empty string');\n }\n\n if (!bundle.certificateHash || !bundle.certificateHash.startsWith('sha256:')) {\n formatErrors.push(`certificateHash must start with \"sha256:\", got \"${bundle.certificateHash}\"`);\n }\n\n if (!bundle.snapshot) {\n schemaErrors.push('snapshot is required');\n const allErrors = [...schemaErrors, ...formatErrors];\n return { ok: false, errors: allErrors, code: CerVerifyCode.SCHEMA_ERROR, details: schemaErrors };\n }\n\n let canonicalizationError: string | null = null;\n let snapshotResult: VerificationResult | null = null;\n\n try {\n snapshotResult = verifySnapshot(bundle.snapshot);\n } catch (err) {\n canonicalizationError = err instanceof Error ? err.message : String(err);\n }\n\n if (canonicalizationError !== null) {\n const errors = [...schemaErrors, ...formatErrors, canonicalizationError];\n return { ok: false, errors, code: CerVerifyCode.CANONICALIZATION_ERROR, details: [canonicalizationError] };\n }\n\n const snapshotErrors = snapshotResult!.errors;\n\n const certHashErrors: string[] = [];\n try {\n const payload: CertificatePayload = {\n bundleType: 'cer.ai.execution.v1',\n createdAt: bundle.createdAt,\n snapshot: bundle.snapshot,\n version: '0.1',\n };\n const expectedHash = computeCertificateHash(payload);\n if (bundle.certificateHash !== expectedHash) {\n certHashErrors.push(`certificateHash mismatch: expected ${expectedHash}, got ${bundle.certificateHash}`);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const errors = [...schemaErrors, ...formatErrors, ...snapshotErrors, msg];\n return { ok: false, errors, code: CerVerifyCode.CANONICALIZATION_ERROR, details: [msg] };\n }\n\n const errors = [...schemaErrors, ...formatErrors, ...snapshotErrors, ...certHashErrors];\n\n if (errors.length === 0) {\n return { ok: true, errors: [], code: CerVerifyCode.OK };\n }\n\n let code: typeof CerVerifyCode[keyof typeof CerVerifyCode];\n let details: string[];\n\n if (schemaErrors.length > 0) {\n code = CerVerifyCode.SCHEMA_ERROR;\n details = schemaErrors;\n } else if (formatErrors.length > 0) {\n code = CerVerifyCode.INVALID_SHA256_FORMAT;\n details = formatErrors;\n } else if (certHashErrors.length > 0 && snapshotErrors.length === 0) {\n code = CerVerifyCode.CERTIFICATE_HASH_MISMATCH;\n details = certHashErrors;\n } else if (snapshotResult && snapshotResult.code !== CerVerifyCode.OK) {\n code = snapshotResult.code;\n details = snapshotResult.details ?? snapshotErrors;\n } else if (certHashErrors.length > 0) {\n code = CerVerifyCode.CERTIFICATE_HASH_MISMATCH;\n details = certHashErrors;\n } else {\n code = CerVerifyCode.UNKNOWN_ERROR;\n details = errors;\n }\n\n return { ok: false, errors, code, details };\n}\n"],"mappings":"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","names":["crypto"]}
1
+ {"version":3,"sources":["../../src/providers/wrap.ts","../../src/hash.ts","../../src/canonicalJson.ts","../../src/snapshot.ts","../../src/cer.ts"],"sourcesContent":["import * as crypto from 'crypto';\nimport type {\n ProviderConfig,\n WrappedExecutionParams,\n WrappedExecutionResult,\n} from '../types.js';\nimport { createSnapshot } from '../snapshot.js';\nimport { sealCer } from '../cer.js';\n\nexport function wrapProvider<TInput = unknown, TOutput = unknown>(\n config: ProviderConfig<TInput, TOutput>,\n) {\n return {\n async execute(params: WrappedExecutionParams & { providerInput: TInput }): Promise<WrappedExecutionResult> {\n const raw = await config.callFn(params.providerInput);\n const output = config.extractOutput(raw);\n const modelVersion = config.extractModelVersion\n ? config.extractModelVersion(raw)\n : (params.modelVersion ?? null);\n\n const snapshot = createSnapshot({\n executionId: params.executionId ?? crypto.randomUUID(),\n provider: config.provider,\n model: params.model,\n modelVersion,\n prompt: params.prompt,\n input: params.input,\n parameters: params.parameters,\n output,\n appId: params.appId,\n });\n\n const bundle = sealCer(snapshot, { meta: params.meta });\n\n return { output, snapshot, bundle };\n },\n };\n}\n","import * as crypto from 'crypto';\nimport { toCanonicalJson } from './canonicalJson.js';\n\nexport function sha256Hex(data: string | Uint8Array): string {\n const hash = crypto.createHash('sha256');\n if (typeof data === 'string') {\n hash.update(data, 'utf-8');\n } else {\n hash.update(data);\n }\n return hash.digest('hex');\n}\n\nexport function hashUtf8(value: string): string {\n return `sha256:${sha256Hex(value)}`;\n}\n\nexport function hashCanonicalJson(value: unknown): string {\n const canonical = toCanonicalJson(value);\n return `sha256:${sha256Hex(canonical)}`;\n}\n\nexport function computeInputHash(input: string | Record<string, unknown>): string {\n if (typeof input === 'string') {\n return hashUtf8(input);\n }\n return hashCanonicalJson(input);\n}\n\nexport function computeOutputHash(output: string | Record<string, unknown>): string {\n if (typeof output === 'string') {\n return hashUtf8(output);\n }\n return hashCanonicalJson(output);\n}\n","export function toCanonicalJson(value: unknown): string {\n return canonicalize(value);\n}\n\nfunction canonicalize(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false';\n }\n\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n throw new Error(`Non-finite number not allowed in canonical JSON: ${value}`);\n }\n return JSON.stringify(value);\n }\n\n if (typeof value === 'string') {\n return JSON.stringify(value);\n }\n\n if (Array.isArray(value)) {\n const items = value.map(item => canonicalize(item));\n return '[' + items.join(',') + ']';\n }\n\n if (typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const entries = keys.map(key => {\n const val = obj[key];\n if (val === undefined) {\n return null;\n }\n return JSON.stringify(key) + ':' + canonicalize(val);\n }).filter(e => e !== null);\n return '{' + entries.join(',') + '}';\n }\n\n throw new Error(`Unsupported type for canonical JSON: ${typeof value}`);\n}\n","import type { AiExecutionSnapshotV1, CreateSnapshotParams, VerificationResult, AiExecutionParameters } from './types.js';\nimport { CerVerifyCode } from './types.js';\nimport { computeInputHash, computeOutputHash } from './hash.js';\n\nconst PACKAGE_VERSION = '0.7.0';\n\nfunction validateParameters(params: AiExecutionParameters): string[] {\n const errors: string[] = [];\n\n if (typeof params.temperature !== 'number' || !Number.isFinite(params.temperature)) {\n errors.push(`parameters.temperature must be a finite number, got: ${params.temperature}`);\n }\n\n if (typeof params.maxTokens !== 'number' || !Number.isFinite(params.maxTokens)) {\n errors.push(`parameters.maxTokens must be a finite number, got: ${params.maxTokens}`);\n }\n\n if (params.topP !== null && (typeof params.topP !== 'number' || !Number.isFinite(params.topP))) {\n errors.push(`parameters.topP must be a finite number or null, got: ${params.topP}`);\n }\n\n if (params.seed !== null && (typeof params.seed !== 'number' || !Number.isFinite(params.seed))) {\n errors.push(`parameters.seed must be a finite number or null, got: ${params.seed}`);\n }\n\n return errors;\n}\n\nexport function createSnapshot(params: CreateSnapshotParams): AiExecutionSnapshotV1 {\n const paramErrors = validateParameters(params.parameters);\n if (paramErrors.length > 0) {\n throw new Error(`Invalid parameters: ${paramErrors.join('; ')}`);\n }\n\n const inputHash = computeInputHash(params.input);\n const outputHash = computeOutputHash(params.output);\n\n const snapshot: AiExecutionSnapshotV1 = {\n type: 'ai.execution.v1',\n protocolVersion: '1.2.0',\n executionSurface: 'ai',\n executionId: params.executionId,\n timestamp: params.timestamp ?? new Date().toISOString(),\n provider: params.provider,\n model: params.model,\n modelVersion: params.modelVersion ?? null,\n prompt: params.prompt,\n input: params.input,\n inputHash,\n parameters: {\n temperature: params.parameters.temperature,\n maxTokens: params.parameters.maxTokens,\n topP: params.parameters.topP ?? null,\n seed: params.parameters.seed ?? null,\n },\n output: params.output,\n outputHash,\n sdkVersion: params.sdkVersion ?? PACKAGE_VERSION,\n appId: params.appId ?? null,\n };\n\n if (params.runId !== undefined) snapshot.runId = params.runId ?? null;\n if (params.stepId !== undefined) snapshot.stepId = params.stepId ?? null;\n if (params.stepIndex !== undefined) snapshot.stepIndex = params.stepIndex ?? null;\n if (params.workflowId !== undefined) snapshot.workflowId = params.workflowId ?? null;\n if (params.conversationId !== undefined) snapshot.conversationId = params.conversationId ?? null;\n if (params.prevStepHash !== undefined) snapshot.prevStepHash = params.prevStepHash ?? null;\n\n // v0.7.0: AIEF-06 tool/dependency evidence — included in certificateHash when present\n if (params.toolCalls !== undefined && params.toolCalls.length > 0) {\n snapshot.toolCalls = params.toolCalls;\n }\n\n return snapshot;\n}\n\nexport function verifySnapshot(snapshot: AiExecutionSnapshotV1): VerificationResult {\n const schemaErrors: string[] = [];\n const formatErrors: string[] = [];\n const inputHashErrors: string[] = [];\n const outputHashErrors: string[] = [];\n\n if (snapshot.type !== 'ai.execution.v1') {\n schemaErrors.push(`Expected type \"ai.execution.v1\", got \"${snapshot.type}\"`);\n }\n\n if (snapshot.protocolVersion !== '1.2.0') {\n schemaErrors.push(`Expected protocolVersion \"1.2.0\", got \"${snapshot.protocolVersion}\"`);\n }\n\n if (snapshot.executionSurface !== 'ai') {\n schemaErrors.push(`Expected executionSurface \"ai\", got \"${snapshot.executionSurface}\"`);\n }\n\n if (!snapshot.executionId || typeof snapshot.executionId !== 'string') {\n schemaErrors.push('executionId must be a non-empty string');\n }\n\n if (!snapshot.timestamp || typeof snapshot.timestamp !== 'string') {\n schemaErrors.push('timestamp must be a non-empty string');\n }\n\n if (!snapshot.provider || typeof snapshot.provider !== 'string') {\n schemaErrors.push('provider must be a non-empty string');\n }\n\n if (!snapshot.model || typeof snapshot.model !== 'string') {\n schemaErrors.push('model must be a non-empty string');\n }\n\n if (!snapshot.prompt || typeof snapshot.prompt !== 'string') {\n schemaErrors.push('prompt must be a non-empty string');\n }\n\n if (snapshot.input === undefined || snapshot.input === null) {\n schemaErrors.push('input must be a string or object');\n }\n\n if (snapshot.output === undefined || snapshot.output === null) {\n schemaErrors.push('output must be a string or object');\n }\n\n const paramErrors = validateParameters(snapshot.parameters);\n schemaErrors.push(...paramErrors);\n\n if (!snapshot.inputHash || !snapshot.inputHash.startsWith('sha256:')) {\n formatErrors.push(`inputHash must start with \"sha256:\", got \"${snapshot.inputHash}\"`);\n }\n\n if (!snapshot.outputHash || !snapshot.outputHash.startsWith('sha256:')) {\n formatErrors.push(`outputHash must start with \"sha256:\", got \"${snapshot.outputHash}\"`);\n }\n\n if (formatErrors.length === 0) {\n const expectedInputHash = computeInputHash(snapshot.input);\n if (snapshot.inputHash !== expectedInputHash) {\n inputHashErrors.push(`inputHash mismatch: expected ${expectedInputHash}, got ${snapshot.inputHash}`);\n }\n\n const expectedOutputHash = computeOutputHash(snapshot.output);\n if (snapshot.outputHash !== expectedOutputHash) {\n outputHashErrors.push(`outputHash mismatch: expected ${expectedOutputHash}, got ${snapshot.outputHash}`);\n }\n }\n\n const errors = [...schemaErrors, ...formatErrors, ...inputHashErrors, ...outputHashErrors];\n\n if (errors.length === 0) {\n return { ok: true, errors: [], code: CerVerifyCode.OK };\n }\n\n let code: typeof CerVerifyCode[keyof typeof CerVerifyCode];\n let details: string[];\n\n if (schemaErrors.length > 0) {\n code = CerVerifyCode.SCHEMA_ERROR;\n details = schemaErrors;\n } else if (formatErrors.length > 0) {\n code = CerVerifyCode.INVALID_SHA256_FORMAT;\n details = formatErrors;\n } else if (inputHashErrors.length > 0 && outputHashErrors.length > 0) {\n code = CerVerifyCode.SNAPSHOT_HASH_MISMATCH;\n details = [...inputHashErrors, ...outputHashErrors];\n } else if (inputHashErrors.length > 0) {\n code = CerVerifyCode.INPUT_HASH_MISMATCH;\n details = inputHashErrors;\n } else if (outputHashErrors.length > 0) {\n code = CerVerifyCode.OUTPUT_HASH_MISMATCH;\n details = outputHashErrors;\n } else {\n code = CerVerifyCode.UNKNOWN_ERROR;\n details = errors;\n }\n\n return { ok: false, errors, code, details };\n}\n","import type { AiExecutionSnapshotV1, CerAiExecutionBundle, CerMeta, BundleDeclaration, VerificationResult } from './types.js';\nimport { CerVerifyCode } from './types.js';\nimport { toCanonicalJson } from './canonicalJson.js';\nimport { sha256Hex } from './hash.js';\nimport { verifySnapshot } from './snapshot.js';\n\ninterface CertificatePayload {\n bundleType: 'cer.ai.execution.v1';\n createdAt: string;\n snapshot: AiExecutionSnapshotV1;\n version: '0.1';\n}\n\nfunction computeCertificateHash(payload: CertificatePayload): string {\n const canonical = toCanonicalJson(payload);\n return `sha256:${sha256Hex(canonical)}`;\n}\n\nexport function sealCer(\n snapshot: AiExecutionSnapshotV1,\n options?: { createdAt?: string; meta?: CerMeta; declaration?: BundleDeclaration }\n): CerAiExecutionBundle {\n const createdAt = options?.createdAt ?? new Date().toISOString();\n\n // certificateHash covers ONLY { bundleType, createdAt, snapshot, version }.\n // `declaration` and `meta` are intentionally excluded — they are non-evidentiary.\n const payload: CertificatePayload = {\n bundleType: 'cer.ai.execution.v1',\n createdAt,\n snapshot,\n version: '0.1',\n };\n\n const certificateHash = computeCertificateHash(payload);\n\n const bundle: CerAiExecutionBundle = {\n bundleType: 'cer.ai.execution.v1',\n certificateHash,\n createdAt,\n version: '0.1',\n snapshot,\n };\n\n if (options?.meta) {\n bundle.meta = options.meta;\n }\n\n // v0.7.0: attach declaration block AFTER hashing — excluded from certificateHash by design.\n if (options?.declaration) {\n bundle.declaration = options.declaration;\n }\n\n return bundle;\n}\n\nexport function verifyCer(bundle: CerAiExecutionBundle): VerificationResult {\n const schemaErrors: string[] = [];\n const formatErrors: string[] = [];\n\n if (bundle.bundleType !== 'cer.ai.execution.v1') {\n schemaErrors.push(`Expected bundleType \"cer.ai.execution.v1\", got \"${bundle.bundleType}\"`);\n }\n\n if (bundle.version !== '0.1') {\n schemaErrors.push(`Expected version \"0.1\", got \"${bundle.version}\"`);\n }\n\n if (!bundle.createdAt || typeof bundle.createdAt !== 'string') {\n schemaErrors.push('createdAt must be a non-empty string');\n }\n\n if (!bundle.certificateHash || !bundle.certificateHash.startsWith('sha256:')) {\n formatErrors.push(`certificateHash must start with \"sha256:\", got \"${bundle.certificateHash}\"`);\n }\n\n if (!bundle.snapshot) {\n schemaErrors.push('snapshot is required');\n const allErrors = [...schemaErrors, ...formatErrors];\n return { ok: false, errors: allErrors, code: CerVerifyCode.SCHEMA_ERROR, details: schemaErrors };\n }\n\n let canonicalizationError: string | null = null;\n let snapshotResult: VerificationResult | null = null;\n\n try {\n snapshotResult = verifySnapshot(bundle.snapshot);\n } catch (err) {\n canonicalizationError = err instanceof Error ? err.message : String(err);\n }\n\n if (canonicalizationError !== null) {\n const errors = [...schemaErrors, ...formatErrors, canonicalizationError];\n return { ok: false, errors, code: CerVerifyCode.CANONICALIZATION_ERROR, details: [canonicalizationError] };\n }\n\n const snapshotErrors = snapshotResult!.errors;\n\n const certHashErrors: string[] = [];\n try {\n const payload: CertificatePayload = {\n bundleType: 'cer.ai.execution.v1',\n createdAt: bundle.createdAt,\n snapshot: bundle.snapshot,\n version: '0.1',\n };\n const expectedHash = computeCertificateHash(payload);\n if (bundle.certificateHash !== expectedHash) {\n certHashErrors.push(`certificateHash mismatch: expected ${expectedHash}, got ${bundle.certificateHash}`);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const errors = [...schemaErrors, ...formatErrors, ...snapshotErrors, msg];\n return { ok: false, errors, code: CerVerifyCode.CANONICALIZATION_ERROR, details: [msg] };\n }\n\n const errors = [...schemaErrors, ...formatErrors, ...snapshotErrors, ...certHashErrors];\n\n if (errors.length === 0) {\n return { ok: true, errors: [], code: CerVerifyCode.OK };\n }\n\n let code: typeof CerVerifyCode[keyof typeof CerVerifyCode];\n let details: string[];\n\n if (schemaErrors.length > 0) {\n code = CerVerifyCode.SCHEMA_ERROR;\n details = schemaErrors;\n } else if (formatErrors.length > 0) {\n code = CerVerifyCode.INVALID_SHA256_FORMAT;\n details = formatErrors;\n } else if (certHashErrors.length > 0 && snapshotErrors.length === 0) {\n code = CerVerifyCode.CERTIFICATE_HASH_MISMATCH;\n details = certHashErrors;\n } else if (snapshotResult && snapshotResult.code !== CerVerifyCode.OK) {\n code = snapshotResult.code;\n details = snapshotResult.details ?? snapshotErrors;\n } else if (certHashErrors.length > 0) {\n code = CerVerifyCode.CERTIFICATE_HASH_MISMATCH;\n details = certHashErrors;\n } else {\n code = CerVerifyCode.UNKNOWN_ERROR;\n details = errors;\n }\n\n return { ok: false, errors, code, details };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,UAAwB;;;ACAxB,aAAwB;;;ACAjB,SAAS,gBAAgB,OAAwB;AACtD,SAAO,aAAa,KAAK;AAC3B;AAEA,SAAS,aAAa,OAAwB;AAC5C,MAAI,UAAU,MAAM;AAClB,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,UAAU,WAAW;AAC9B,WAAO,QAAQ,SAAS;AAAA,EAC1B;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI,CAAC,OAAO,SAAS,KAAK,GAAG;AAC3B,YAAM,IAAI,MAAM,oDAAoD,KAAK,EAAE;AAAA,IAC7E;AACA,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B;AAEA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,UAAM,QAAQ,MAAM,IAAI,UAAQ,aAAa,IAAI,CAAC;AAClD,WAAO,MAAM,MAAM,KAAK,GAAG,IAAI;AAAA,EACjC;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,MAAM;AACZ,UAAM,OAAO,OAAO,KAAK,GAAG,EAAE,KAAK;AACnC,UAAM,UAAU,KAAK,IAAI,SAAO;AAC9B,YAAM,MAAM,IAAI,GAAG;AACnB,UAAI,QAAQ,QAAW;AACrB,eAAO;AAAA,MACT;AACA,aAAO,KAAK,UAAU,GAAG,IAAI,MAAM,aAAa,GAAG;AAAA,IACrD,CAAC,EAAE,OAAO,OAAK,MAAM,IAAI;AACzB,WAAO,MAAM,QAAQ,KAAK,GAAG,IAAI;AAAA,EACnC;AAEA,QAAM,IAAI,MAAM,wCAAwC,OAAO,KAAK,EAAE;AACxE;;;ADxCO,SAAS,UAAU,MAAmC;AAC3D,QAAM,OAAc,kBAAW,QAAQ;AACvC,MAAI,OAAO,SAAS,UAAU;AAC5B,SAAK,OAAO,MAAM,OAAO;AAAA,EAC3B,OAAO;AACL,SAAK,OAAO,IAAI;AAAA,EAClB;AACA,SAAO,KAAK,OAAO,KAAK;AAC1B;AAEO,SAAS,SAAS,OAAuB;AAC9C,SAAO,UAAU,UAAU,KAAK,CAAC;AACnC;AAEO,SAAS,kBAAkB,OAAwB;AACxD,QAAM,YAAY,gBAAgB,KAAK;AACvC,SAAO,UAAU,UAAU,SAAS,CAAC;AACvC;AAEO,SAAS,iBAAiB,OAAiD;AAChF,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,SAAS,KAAK;AAAA,EACvB;AACA,SAAO,kBAAkB,KAAK;AAChC;AAEO,SAAS,kBAAkB,QAAkD;AAClF,MAAI,OAAO,WAAW,UAAU;AAC9B,WAAO,SAAS,MAAM;AAAA,EACxB;AACA,SAAO,kBAAkB,MAAM;AACjC;;;AE9BA,IAAM,kBAAkB;AAExB,SAAS,mBAAmB,QAAyC;AACnE,QAAM,SAAmB,CAAC;AAE1B,MAAI,OAAO,OAAO,gBAAgB,YAAY,CAAC,OAAO,SAAS,OAAO,WAAW,GAAG;AAClF,WAAO,KAAK,wDAAwD,OAAO,WAAW,EAAE;AAAA,EAC1F;AAEA,MAAI,OAAO,OAAO,cAAc,YAAY,CAAC,OAAO,SAAS,OAAO,SAAS,GAAG;AAC9E,WAAO,KAAK,sDAAsD,OAAO,SAAS,EAAE;AAAA,EACtF;AAEA,MAAI,OAAO,SAAS,SAAS,OAAO,OAAO,SAAS,YAAY,CAAC,OAAO,SAAS,OAAO,IAAI,IAAI;AAC9F,WAAO,KAAK,yDAAyD,OAAO,IAAI,EAAE;AAAA,EACpF;AAEA,MAAI,OAAO,SAAS,SAAS,OAAO,OAAO,SAAS,YAAY,CAAC,OAAO,SAAS,OAAO,IAAI,IAAI;AAC9F,WAAO,KAAK,yDAAyD,OAAO,IAAI,EAAE;AAAA,EACpF;AAEA,SAAO;AACT;AAEO,SAAS,eAAe,QAAqD;AAClF,QAAM,cAAc,mBAAmB,OAAO,UAAU;AACxD,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,IAAI,MAAM,uBAAuB,YAAY,KAAK,IAAI,CAAC,EAAE;AAAA,EACjE;AAEA,QAAM,YAAY,iBAAiB,OAAO,KAAK;AAC/C,QAAM,aAAa,kBAAkB,OAAO,MAAM;AAElD,QAAM,WAAkC;AAAA,IACtC,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,aAAa,OAAO;AAAA,IACpB,WAAW,OAAO,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACtD,UAAU,OAAO;AAAA,IACjB,OAAO,OAAO;AAAA,IACd,cAAc,OAAO,gBAAgB;AAAA,IACrC,QAAQ,OAAO;AAAA,IACf,OAAO,OAAO;AAAA,IACd;AAAA,IACA,YAAY;AAAA,MACV,aAAa,OAAO,WAAW;AAAA,MAC/B,WAAW,OAAO,WAAW;AAAA,MAC7B,MAAM,OAAO,WAAW,QAAQ;AAAA,MAChC,MAAM,OAAO,WAAW,QAAQ;AAAA,IAClC;AAAA,IACA,QAAQ,OAAO;AAAA,IACf;AAAA,IACA,YAAY,OAAO,cAAc;AAAA,IACjC,OAAO,OAAO,SAAS;AAAA,EACzB;AAEA,MAAI,OAAO,UAAU,OAAW,UAAS,QAAQ,OAAO,SAAS;AACjE,MAAI,OAAO,WAAW,OAAW,UAAS,SAAS,OAAO,UAAU;AACpE,MAAI,OAAO,cAAc,OAAW,UAAS,YAAY,OAAO,aAAa;AAC7E,MAAI,OAAO,eAAe,OAAW,UAAS,aAAa,OAAO,cAAc;AAChF,MAAI,OAAO,mBAAmB,OAAW,UAAS,iBAAiB,OAAO,kBAAkB;AAC5F,MAAI,OAAO,iBAAiB,OAAW,UAAS,eAAe,OAAO,gBAAgB;AAGtF,MAAI,OAAO,cAAc,UAAa,OAAO,UAAU,SAAS,GAAG;AACjE,aAAS,YAAY,OAAO;AAAA,EAC9B;AAEA,SAAO;AACT;;;AC7DA,SAAS,uBAAuB,SAAqC;AACnE,QAAM,YAAY,gBAAgB,OAAO;AACzC,SAAO,UAAU,UAAU,SAAS,CAAC;AACvC;AAEO,SAAS,QACd,UACA,SACsB;AACtB,QAAM,YAAY,SAAS,cAAa,oBAAI,KAAK,GAAE,YAAY;AAI/D,QAAM,UAA8B;AAAA,IAClC,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA,SAAS;AAAA,EACX;AAEA,QAAM,kBAAkB,uBAAuB,OAAO;AAEtD,QAAM,SAA+B;AAAA,IACnC,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT;AAAA,EACF;AAEA,MAAI,SAAS,MAAM;AACjB,WAAO,OAAO,QAAQ;AAAA,EACxB;AAGA,MAAI,SAAS,aAAa;AACxB,WAAO,cAAc,QAAQ;AAAA,EAC/B;AAEA,SAAO;AACT;;;AJ5CO,SAAS,aACd,QACA;AACA,SAAO;AAAA,IACL,MAAM,QAAQ,QAA6F;AACzG,YAAM,MAAM,MAAM,OAAO,OAAO,OAAO,aAAa;AACpD,YAAM,SAAS,OAAO,cAAc,GAAG;AACvC,YAAM,eAAe,OAAO,sBACxB,OAAO,oBAAoB,GAAG,IAC7B,OAAO,gBAAgB;AAE5B,YAAM,WAAW,eAAe;AAAA,QAC9B,aAAa,OAAO,eAAsB,mBAAW;AAAA,QACrD,UAAU,OAAO;AAAA,QACjB,OAAO,OAAO;AAAA,QACd;AAAA,QACA,QAAQ,OAAO;AAAA,QACf,OAAO,OAAO;AAAA,QACd,YAAY,OAAO;AAAA,QACnB;AAAA,QACA,OAAO,OAAO;AAAA,MAChB,CAAC;AAED,YAAM,SAAS,QAAQ,UAAU,EAAE,MAAM,OAAO,KAAK,CAAC;AAEtD,aAAO,EAAE,QAAQ,UAAU,OAAO;AAAA,IACpC;AAAA,EACF;AACF;","names":["crypto"]}
@@ -1,4 +1,4 @@
1
- import { q as ProviderConfig, W as WrappedExecutionParams, r as WrappedExecutionResult } from '../types-Cgb52dTx.cjs';
1
+ import { t as ProviderConfig, W as WrappedExecutionParams, v as WrappedExecutionResult } from '../types-CcqCDPrD.cjs';
2
2
 
3
3
  declare function wrapProvider<TInput = unknown, TOutput = unknown>(config: ProviderConfig<TInput, TOutput>): {
4
4
  execute(params: WrappedExecutionParams & {
@@ -1,4 +1,4 @@
1
- import { q as ProviderConfig, W as WrappedExecutionParams, r as WrappedExecutionResult } from '../types-Cgb52dTx.js';
1
+ import { t as ProviderConfig, W as WrappedExecutionParams, v as WrappedExecutionResult } from '../types-CcqCDPrD.js';
2
2
 
3
3
  declare function wrapProvider<TInput = unknown, TOutput = unknown>(config: ProviderConfig<TInput, TOutput>): {
4
4
  execute(params: WrappedExecutionParams & {
@@ -74,7 +74,7 @@ function computeOutputHash(output) {
74
74
  }
75
75
 
76
76
  // src/snapshot.ts
77
- var PACKAGE_VERSION = "0.6.0";
77
+ var PACKAGE_VERSION = "0.7.0";
78
78
  function validateParameters(params) {
79
79
  const errors = [];
80
80
  if (typeof params.temperature !== "number" || !Number.isFinite(params.temperature)) {
@@ -127,6 +127,9 @@ function createSnapshot(params) {
127
127
  if (params.workflowId !== void 0) snapshot.workflowId = params.workflowId ?? null;
128
128
  if (params.conversationId !== void 0) snapshot.conversationId = params.conversationId ?? null;
129
129
  if (params.prevStepHash !== void 0) snapshot.prevStepHash = params.prevStepHash ?? null;
130
+ if (params.toolCalls !== void 0 && params.toolCalls.length > 0) {
131
+ snapshot.toolCalls = params.toolCalls;
132
+ }
130
133
  return snapshot;
131
134
  }
132
135
 
@@ -154,6 +157,9 @@ function sealCer(snapshot, options) {
154
157
  if (options?.meta) {
155
158
  bundle.meta = options.meta;
156
159
  }
160
+ if (options?.declaration) {
161
+ bundle.declaration = options.declaration;
162
+ }
157
163
  return bundle;
158
164
  }
159
165
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/wrap.ts","../../src/hash.ts","../../src/canonicalJson.ts","../../src/snapshot.ts","../../src/cer.ts"],"sourcesContent":["import * as crypto from 'crypto';\nimport type {\n ProviderConfig,\n WrappedExecutionParams,\n WrappedExecutionResult,\n} from '../types.js';\nimport { createSnapshot } from '../snapshot.js';\nimport { sealCer } from '../cer.js';\n\nexport function wrapProvider<TInput = unknown, TOutput = unknown>(\n config: ProviderConfig<TInput, TOutput>,\n) {\n return {\n async execute(params: WrappedExecutionParams & { providerInput: TInput }): Promise<WrappedExecutionResult> {\n const raw = await config.callFn(params.providerInput);\n const output = config.extractOutput(raw);\n const modelVersion = config.extractModelVersion\n ? config.extractModelVersion(raw)\n : (params.modelVersion ?? null);\n\n const snapshot = createSnapshot({\n executionId: params.executionId ?? crypto.randomUUID(),\n provider: config.provider,\n model: params.model,\n modelVersion,\n prompt: params.prompt,\n input: params.input,\n parameters: params.parameters,\n output,\n appId: params.appId,\n });\n\n const bundle = sealCer(snapshot, { meta: params.meta });\n\n return { output, snapshot, bundle };\n },\n };\n}\n","import * as crypto from 'crypto';\nimport { toCanonicalJson } from './canonicalJson.js';\n\nexport function sha256Hex(data: string | Uint8Array): string {\n const hash = crypto.createHash('sha256');\n if (typeof data === 'string') {\n hash.update(data, 'utf-8');\n } else {\n hash.update(data);\n }\n return hash.digest('hex');\n}\n\nexport function hashUtf8(value: string): string {\n return `sha256:${sha256Hex(value)}`;\n}\n\nexport function hashCanonicalJson(value: unknown): string {\n const canonical = toCanonicalJson(value);\n return `sha256:${sha256Hex(canonical)}`;\n}\n\nexport function computeInputHash(input: string | Record<string, unknown>): string {\n if (typeof input === 'string') {\n return hashUtf8(input);\n }\n return hashCanonicalJson(input);\n}\n\nexport function computeOutputHash(output: string | Record<string, unknown>): string {\n if (typeof output === 'string') {\n return hashUtf8(output);\n }\n return hashCanonicalJson(output);\n}\n","export function toCanonicalJson(value: unknown): string {\n return canonicalize(value);\n}\n\nfunction canonicalize(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false';\n }\n\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n throw new Error(`Non-finite number not allowed in canonical JSON: ${value}`);\n }\n return JSON.stringify(value);\n }\n\n if (typeof value === 'string') {\n return JSON.stringify(value);\n }\n\n if (Array.isArray(value)) {\n const items = value.map(item => canonicalize(item));\n return '[' + items.join(',') + ']';\n }\n\n if (typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const entries = keys.map(key => {\n const val = obj[key];\n if (val === undefined) {\n return null;\n }\n return JSON.stringify(key) + ':' + canonicalize(val);\n }).filter(e => e !== null);\n return '{' + entries.join(',') + '}';\n }\n\n throw new Error(`Unsupported type for canonical JSON: ${typeof value}`);\n}\n","import type { AiExecutionSnapshotV1, CreateSnapshotParams, VerificationResult, AiExecutionParameters } from './types.js';\nimport { CerVerifyCode } from './types.js';\nimport { computeInputHash, computeOutputHash } from './hash.js';\n\nconst PACKAGE_VERSION = '0.6.0';\n\nfunction validateParameters(params: AiExecutionParameters): string[] {\n const errors: string[] = [];\n\n if (typeof params.temperature !== 'number' || !Number.isFinite(params.temperature)) {\n errors.push(`parameters.temperature must be a finite number, got: ${params.temperature}`);\n }\n\n if (typeof params.maxTokens !== 'number' || !Number.isFinite(params.maxTokens)) {\n errors.push(`parameters.maxTokens must be a finite number, got: ${params.maxTokens}`);\n }\n\n if (params.topP !== null && (typeof params.topP !== 'number' || !Number.isFinite(params.topP))) {\n errors.push(`parameters.topP must be a finite number or null, got: ${params.topP}`);\n }\n\n if (params.seed !== null && (typeof params.seed !== 'number' || !Number.isFinite(params.seed))) {\n errors.push(`parameters.seed must be a finite number or null, got: ${params.seed}`);\n }\n\n return errors;\n}\n\nexport function createSnapshot(params: CreateSnapshotParams): AiExecutionSnapshotV1 {\n const paramErrors = validateParameters(params.parameters);\n if (paramErrors.length > 0) {\n throw new Error(`Invalid parameters: ${paramErrors.join('; ')}`);\n }\n\n const inputHash = computeInputHash(params.input);\n const outputHash = computeOutputHash(params.output);\n\n const snapshot: AiExecutionSnapshotV1 = {\n type: 'ai.execution.v1',\n protocolVersion: '1.2.0',\n executionSurface: 'ai',\n executionId: params.executionId,\n timestamp: params.timestamp ?? new Date().toISOString(),\n provider: params.provider,\n model: params.model,\n modelVersion: params.modelVersion ?? null,\n prompt: params.prompt,\n input: params.input,\n inputHash,\n parameters: {\n temperature: params.parameters.temperature,\n maxTokens: params.parameters.maxTokens,\n topP: params.parameters.topP ?? null,\n seed: params.parameters.seed ?? null,\n },\n output: params.output,\n outputHash,\n sdkVersion: params.sdkVersion ?? PACKAGE_VERSION,\n appId: params.appId ?? null,\n };\n\n if (params.runId !== undefined) snapshot.runId = params.runId ?? null;\n if (params.stepId !== undefined) snapshot.stepId = params.stepId ?? null;\n if (params.stepIndex !== undefined) snapshot.stepIndex = params.stepIndex ?? null;\n if (params.workflowId !== undefined) snapshot.workflowId = params.workflowId ?? null;\n if (params.conversationId !== undefined) snapshot.conversationId = params.conversationId ?? null;\n if (params.prevStepHash !== undefined) snapshot.prevStepHash = params.prevStepHash ?? null;\n\n return snapshot;\n}\n\nexport function verifySnapshot(snapshot: AiExecutionSnapshotV1): VerificationResult {\n const schemaErrors: string[] = [];\n const formatErrors: string[] = [];\n const inputHashErrors: string[] = [];\n const outputHashErrors: string[] = [];\n\n if (snapshot.type !== 'ai.execution.v1') {\n schemaErrors.push(`Expected type \"ai.execution.v1\", got \"${snapshot.type}\"`);\n }\n\n if (snapshot.protocolVersion !== '1.2.0') {\n schemaErrors.push(`Expected protocolVersion \"1.2.0\", got \"${snapshot.protocolVersion}\"`);\n }\n\n if (snapshot.executionSurface !== 'ai') {\n schemaErrors.push(`Expected executionSurface \"ai\", got \"${snapshot.executionSurface}\"`);\n }\n\n if (!snapshot.executionId || typeof snapshot.executionId !== 'string') {\n schemaErrors.push('executionId must be a non-empty string');\n }\n\n if (!snapshot.timestamp || typeof snapshot.timestamp !== 'string') {\n schemaErrors.push('timestamp must be a non-empty string');\n }\n\n if (!snapshot.provider || typeof snapshot.provider !== 'string') {\n schemaErrors.push('provider must be a non-empty string');\n }\n\n if (!snapshot.model || typeof snapshot.model !== 'string') {\n schemaErrors.push('model must be a non-empty string');\n }\n\n if (!snapshot.prompt || typeof snapshot.prompt !== 'string') {\n schemaErrors.push('prompt must be a non-empty string');\n }\n\n if (snapshot.input === undefined || snapshot.input === null) {\n schemaErrors.push('input must be a string or object');\n }\n\n if (snapshot.output === undefined || snapshot.output === null) {\n schemaErrors.push('output must be a string or object');\n }\n\n const paramErrors = validateParameters(snapshot.parameters);\n schemaErrors.push(...paramErrors);\n\n if (!snapshot.inputHash || !snapshot.inputHash.startsWith('sha256:')) {\n formatErrors.push(`inputHash must start with \"sha256:\", got \"${snapshot.inputHash}\"`);\n }\n\n if (!snapshot.outputHash || !snapshot.outputHash.startsWith('sha256:')) {\n formatErrors.push(`outputHash must start with \"sha256:\", got \"${snapshot.outputHash}\"`);\n }\n\n if (formatErrors.length === 0) {\n const expectedInputHash = computeInputHash(snapshot.input);\n if (snapshot.inputHash !== expectedInputHash) {\n inputHashErrors.push(`inputHash mismatch: expected ${expectedInputHash}, got ${snapshot.inputHash}`);\n }\n\n const expectedOutputHash = computeOutputHash(snapshot.output);\n if (snapshot.outputHash !== expectedOutputHash) {\n outputHashErrors.push(`outputHash mismatch: expected ${expectedOutputHash}, got ${snapshot.outputHash}`);\n }\n }\n\n const errors = [...schemaErrors, ...formatErrors, ...inputHashErrors, ...outputHashErrors];\n\n if (errors.length === 0) {\n return { ok: true, errors: [], code: CerVerifyCode.OK };\n }\n\n let code: typeof CerVerifyCode[keyof typeof CerVerifyCode];\n let details: string[];\n\n if (schemaErrors.length > 0) {\n code = CerVerifyCode.SCHEMA_ERROR;\n details = schemaErrors;\n } else if (formatErrors.length > 0) {\n code = CerVerifyCode.INVALID_SHA256_FORMAT;\n details = formatErrors;\n } else if (inputHashErrors.length > 0 && outputHashErrors.length > 0) {\n code = CerVerifyCode.SNAPSHOT_HASH_MISMATCH;\n details = [...inputHashErrors, ...outputHashErrors];\n } else if (inputHashErrors.length > 0) {\n code = CerVerifyCode.INPUT_HASH_MISMATCH;\n details = inputHashErrors;\n } else if (outputHashErrors.length > 0) {\n code = CerVerifyCode.OUTPUT_HASH_MISMATCH;\n details = outputHashErrors;\n } else {\n code = CerVerifyCode.UNKNOWN_ERROR;\n details = errors;\n }\n\n return { ok: false, errors, code, details };\n}\n","import type { AiExecutionSnapshotV1, CerAiExecutionBundle, CerMeta, VerificationResult } from './types.js';\nimport { CerVerifyCode } from './types.js';\nimport { toCanonicalJson } from './canonicalJson.js';\nimport { sha256Hex } from './hash.js';\nimport { verifySnapshot } from './snapshot.js';\n\ninterface CertificatePayload {\n bundleType: 'cer.ai.execution.v1';\n createdAt: string;\n snapshot: AiExecutionSnapshotV1;\n version: '0.1';\n}\n\nfunction computeCertificateHash(payload: CertificatePayload): string {\n const canonical = toCanonicalJson(payload);\n return `sha256:${sha256Hex(canonical)}`;\n}\n\nexport function sealCer(\n snapshot: AiExecutionSnapshotV1,\n options?: { createdAt?: string; meta?: CerMeta }\n): CerAiExecutionBundle {\n const createdAt = options?.createdAt ?? new Date().toISOString();\n\n const payload: CertificatePayload = {\n bundleType: 'cer.ai.execution.v1',\n createdAt,\n snapshot,\n version: '0.1',\n };\n\n const certificateHash = computeCertificateHash(payload);\n\n const bundle: CerAiExecutionBundle = {\n bundleType: 'cer.ai.execution.v1',\n certificateHash,\n createdAt,\n version: '0.1',\n snapshot,\n };\n\n if (options?.meta) {\n bundle.meta = options.meta;\n }\n\n return bundle;\n}\n\nexport function verifyCer(bundle: CerAiExecutionBundle): VerificationResult {\n const schemaErrors: string[] = [];\n const formatErrors: string[] = [];\n\n if (bundle.bundleType !== 'cer.ai.execution.v1') {\n schemaErrors.push(`Expected bundleType \"cer.ai.execution.v1\", got \"${bundle.bundleType}\"`);\n }\n\n if (bundle.version !== '0.1') {\n schemaErrors.push(`Expected version \"0.1\", got \"${bundle.version}\"`);\n }\n\n if (!bundle.createdAt || typeof bundle.createdAt !== 'string') {\n schemaErrors.push('createdAt must be a non-empty string');\n }\n\n if (!bundle.certificateHash || !bundle.certificateHash.startsWith('sha256:')) {\n formatErrors.push(`certificateHash must start with \"sha256:\", got \"${bundle.certificateHash}\"`);\n }\n\n if (!bundle.snapshot) {\n schemaErrors.push('snapshot is required');\n const allErrors = [...schemaErrors, ...formatErrors];\n return { ok: false, errors: allErrors, code: CerVerifyCode.SCHEMA_ERROR, details: schemaErrors };\n }\n\n let canonicalizationError: string | null = null;\n let snapshotResult: VerificationResult | null = null;\n\n try {\n snapshotResult = verifySnapshot(bundle.snapshot);\n } catch (err) {\n canonicalizationError = err instanceof Error ? err.message : String(err);\n }\n\n if (canonicalizationError !== null) {\n const errors = [...schemaErrors, ...formatErrors, canonicalizationError];\n return { ok: false, errors, code: CerVerifyCode.CANONICALIZATION_ERROR, details: [canonicalizationError] };\n }\n\n const snapshotErrors = snapshotResult!.errors;\n\n const certHashErrors: string[] = [];\n try {\n const payload: CertificatePayload = {\n bundleType: 'cer.ai.execution.v1',\n createdAt: bundle.createdAt,\n snapshot: bundle.snapshot,\n version: '0.1',\n };\n const expectedHash = computeCertificateHash(payload);\n if (bundle.certificateHash !== expectedHash) {\n certHashErrors.push(`certificateHash mismatch: expected ${expectedHash}, got ${bundle.certificateHash}`);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const errors = [...schemaErrors, ...formatErrors, ...snapshotErrors, msg];\n return { ok: false, errors, code: CerVerifyCode.CANONICALIZATION_ERROR, details: [msg] };\n }\n\n const errors = [...schemaErrors, ...formatErrors, ...snapshotErrors, ...certHashErrors];\n\n if (errors.length === 0) {\n return { ok: true, errors: [], code: CerVerifyCode.OK };\n }\n\n let code: typeof CerVerifyCode[keyof typeof CerVerifyCode];\n let details: string[];\n\n if (schemaErrors.length > 0) {\n code = CerVerifyCode.SCHEMA_ERROR;\n details = schemaErrors;\n } else if (formatErrors.length > 0) {\n code = CerVerifyCode.INVALID_SHA256_FORMAT;\n details = formatErrors;\n } else if (certHashErrors.length > 0 && snapshotErrors.length === 0) {\n code = CerVerifyCode.CERTIFICATE_HASH_MISMATCH;\n details = certHashErrors;\n } else if (snapshotResult && snapshotResult.code !== CerVerifyCode.OK) {\n code = snapshotResult.code;\n details = snapshotResult.details ?? snapshotErrors;\n } else if (certHashErrors.length > 0) {\n code = CerVerifyCode.CERTIFICATE_HASH_MISMATCH;\n details = certHashErrors;\n } else {\n code = CerVerifyCode.UNKNOWN_ERROR;\n details = errors;\n }\n\n return { ok: false, errors, code, details };\n}\n"],"mappings":"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","names":["crypto"]}
1
+ {"version":3,"sources":["../../src/providers/wrap.ts","../../src/hash.ts","../../src/canonicalJson.ts","../../src/snapshot.ts","../../src/cer.ts"],"sourcesContent":["import * as crypto from 'crypto';\nimport type {\n ProviderConfig,\n WrappedExecutionParams,\n WrappedExecutionResult,\n} from '../types.js';\nimport { createSnapshot } from '../snapshot.js';\nimport { sealCer } from '../cer.js';\n\nexport function wrapProvider<TInput = unknown, TOutput = unknown>(\n config: ProviderConfig<TInput, TOutput>,\n) {\n return {\n async execute(params: WrappedExecutionParams & { providerInput: TInput }): Promise<WrappedExecutionResult> {\n const raw = await config.callFn(params.providerInput);\n const output = config.extractOutput(raw);\n const modelVersion = config.extractModelVersion\n ? config.extractModelVersion(raw)\n : (params.modelVersion ?? null);\n\n const snapshot = createSnapshot({\n executionId: params.executionId ?? crypto.randomUUID(),\n provider: config.provider,\n model: params.model,\n modelVersion,\n prompt: params.prompt,\n input: params.input,\n parameters: params.parameters,\n output,\n appId: params.appId,\n });\n\n const bundle = sealCer(snapshot, { meta: params.meta });\n\n return { output, snapshot, bundle };\n },\n };\n}\n","import * as crypto from 'crypto';\nimport { toCanonicalJson } from './canonicalJson.js';\n\nexport function sha256Hex(data: string | Uint8Array): string {\n const hash = crypto.createHash('sha256');\n if (typeof data === 'string') {\n hash.update(data, 'utf-8');\n } else {\n hash.update(data);\n }\n return hash.digest('hex');\n}\n\nexport function hashUtf8(value: string): string {\n return `sha256:${sha256Hex(value)}`;\n}\n\nexport function hashCanonicalJson(value: unknown): string {\n const canonical = toCanonicalJson(value);\n return `sha256:${sha256Hex(canonical)}`;\n}\n\nexport function computeInputHash(input: string | Record<string, unknown>): string {\n if (typeof input === 'string') {\n return hashUtf8(input);\n }\n return hashCanonicalJson(input);\n}\n\nexport function computeOutputHash(output: string | Record<string, unknown>): string {\n if (typeof output === 'string') {\n return hashUtf8(output);\n }\n return hashCanonicalJson(output);\n}\n","export function toCanonicalJson(value: unknown): string {\n return canonicalize(value);\n}\n\nfunction canonicalize(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false';\n }\n\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) {\n throw new Error(`Non-finite number not allowed in canonical JSON: ${value}`);\n }\n return JSON.stringify(value);\n }\n\n if (typeof value === 'string') {\n return JSON.stringify(value);\n }\n\n if (Array.isArray(value)) {\n const items = value.map(item => canonicalize(item));\n return '[' + items.join(',') + ']';\n }\n\n if (typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const entries = keys.map(key => {\n const val = obj[key];\n if (val === undefined) {\n return null;\n }\n return JSON.stringify(key) + ':' + canonicalize(val);\n }).filter(e => e !== null);\n return '{' + entries.join(',') + '}';\n }\n\n throw new Error(`Unsupported type for canonical JSON: ${typeof value}`);\n}\n","import type { AiExecutionSnapshotV1, CreateSnapshotParams, VerificationResult, AiExecutionParameters } from './types.js';\nimport { CerVerifyCode } from './types.js';\nimport { computeInputHash, computeOutputHash } from './hash.js';\n\nconst PACKAGE_VERSION = '0.7.0';\n\nfunction validateParameters(params: AiExecutionParameters): string[] {\n const errors: string[] = [];\n\n if (typeof params.temperature !== 'number' || !Number.isFinite(params.temperature)) {\n errors.push(`parameters.temperature must be a finite number, got: ${params.temperature}`);\n }\n\n if (typeof params.maxTokens !== 'number' || !Number.isFinite(params.maxTokens)) {\n errors.push(`parameters.maxTokens must be a finite number, got: ${params.maxTokens}`);\n }\n\n if (params.topP !== null && (typeof params.topP !== 'number' || !Number.isFinite(params.topP))) {\n errors.push(`parameters.topP must be a finite number or null, got: ${params.topP}`);\n }\n\n if (params.seed !== null && (typeof params.seed !== 'number' || !Number.isFinite(params.seed))) {\n errors.push(`parameters.seed must be a finite number or null, got: ${params.seed}`);\n }\n\n return errors;\n}\n\nexport function createSnapshot(params: CreateSnapshotParams): AiExecutionSnapshotV1 {\n const paramErrors = validateParameters(params.parameters);\n if (paramErrors.length > 0) {\n throw new Error(`Invalid parameters: ${paramErrors.join('; ')}`);\n }\n\n const inputHash = computeInputHash(params.input);\n const outputHash = computeOutputHash(params.output);\n\n const snapshot: AiExecutionSnapshotV1 = {\n type: 'ai.execution.v1',\n protocolVersion: '1.2.0',\n executionSurface: 'ai',\n executionId: params.executionId,\n timestamp: params.timestamp ?? new Date().toISOString(),\n provider: params.provider,\n model: params.model,\n modelVersion: params.modelVersion ?? null,\n prompt: params.prompt,\n input: params.input,\n inputHash,\n parameters: {\n temperature: params.parameters.temperature,\n maxTokens: params.parameters.maxTokens,\n topP: params.parameters.topP ?? null,\n seed: params.parameters.seed ?? null,\n },\n output: params.output,\n outputHash,\n sdkVersion: params.sdkVersion ?? PACKAGE_VERSION,\n appId: params.appId ?? null,\n };\n\n if (params.runId !== undefined) snapshot.runId = params.runId ?? null;\n if (params.stepId !== undefined) snapshot.stepId = params.stepId ?? null;\n if (params.stepIndex !== undefined) snapshot.stepIndex = params.stepIndex ?? null;\n if (params.workflowId !== undefined) snapshot.workflowId = params.workflowId ?? null;\n if (params.conversationId !== undefined) snapshot.conversationId = params.conversationId ?? null;\n if (params.prevStepHash !== undefined) snapshot.prevStepHash = params.prevStepHash ?? null;\n\n // v0.7.0: AIEF-06 tool/dependency evidence — included in certificateHash when present\n if (params.toolCalls !== undefined && params.toolCalls.length > 0) {\n snapshot.toolCalls = params.toolCalls;\n }\n\n return snapshot;\n}\n\nexport function verifySnapshot(snapshot: AiExecutionSnapshotV1): VerificationResult {\n const schemaErrors: string[] = [];\n const formatErrors: string[] = [];\n const inputHashErrors: string[] = [];\n const outputHashErrors: string[] = [];\n\n if (snapshot.type !== 'ai.execution.v1') {\n schemaErrors.push(`Expected type \"ai.execution.v1\", got \"${snapshot.type}\"`);\n }\n\n if (snapshot.protocolVersion !== '1.2.0') {\n schemaErrors.push(`Expected protocolVersion \"1.2.0\", got \"${snapshot.protocolVersion}\"`);\n }\n\n if (snapshot.executionSurface !== 'ai') {\n schemaErrors.push(`Expected executionSurface \"ai\", got \"${snapshot.executionSurface}\"`);\n }\n\n if (!snapshot.executionId || typeof snapshot.executionId !== 'string') {\n schemaErrors.push('executionId must be a non-empty string');\n }\n\n if (!snapshot.timestamp || typeof snapshot.timestamp !== 'string') {\n schemaErrors.push('timestamp must be a non-empty string');\n }\n\n if (!snapshot.provider || typeof snapshot.provider !== 'string') {\n schemaErrors.push('provider must be a non-empty string');\n }\n\n if (!snapshot.model || typeof snapshot.model !== 'string') {\n schemaErrors.push('model must be a non-empty string');\n }\n\n if (!snapshot.prompt || typeof snapshot.prompt !== 'string') {\n schemaErrors.push('prompt must be a non-empty string');\n }\n\n if (snapshot.input === undefined || snapshot.input === null) {\n schemaErrors.push('input must be a string or object');\n }\n\n if (snapshot.output === undefined || snapshot.output === null) {\n schemaErrors.push('output must be a string or object');\n }\n\n const paramErrors = validateParameters(snapshot.parameters);\n schemaErrors.push(...paramErrors);\n\n if (!snapshot.inputHash || !snapshot.inputHash.startsWith('sha256:')) {\n formatErrors.push(`inputHash must start with \"sha256:\", got \"${snapshot.inputHash}\"`);\n }\n\n if (!snapshot.outputHash || !snapshot.outputHash.startsWith('sha256:')) {\n formatErrors.push(`outputHash must start with \"sha256:\", got \"${snapshot.outputHash}\"`);\n }\n\n if (formatErrors.length === 0) {\n const expectedInputHash = computeInputHash(snapshot.input);\n if (snapshot.inputHash !== expectedInputHash) {\n inputHashErrors.push(`inputHash mismatch: expected ${expectedInputHash}, got ${snapshot.inputHash}`);\n }\n\n const expectedOutputHash = computeOutputHash(snapshot.output);\n if (snapshot.outputHash !== expectedOutputHash) {\n outputHashErrors.push(`outputHash mismatch: expected ${expectedOutputHash}, got ${snapshot.outputHash}`);\n }\n }\n\n const errors = [...schemaErrors, ...formatErrors, ...inputHashErrors, ...outputHashErrors];\n\n if (errors.length === 0) {\n return { ok: true, errors: [], code: CerVerifyCode.OK };\n }\n\n let code: typeof CerVerifyCode[keyof typeof CerVerifyCode];\n let details: string[];\n\n if (schemaErrors.length > 0) {\n code = CerVerifyCode.SCHEMA_ERROR;\n details = schemaErrors;\n } else if (formatErrors.length > 0) {\n code = CerVerifyCode.INVALID_SHA256_FORMAT;\n details = formatErrors;\n } else if (inputHashErrors.length > 0 && outputHashErrors.length > 0) {\n code = CerVerifyCode.SNAPSHOT_HASH_MISMATCH;\n details = [...inputHashErrors, ...outputHashErrors];\n } else if (inputHashErrors.length > 0) {\n code = CerVerifyCode.INPUT_HASH_MISMATCH;\n details = inputHashErrors;\n } else if (outputHashErrors.length > 0) {\n code = CerVerifyCode.OUTPUT_HASH_MISMATCH;\n details = outputHashErrors;\n } else {\n code = CerVerifyCode.UNKNOWN_ERROR;\n details = errors;\n }\n\n return { ok: false, errors, code, details };\n}\n","import type { AiExecutionSnapshotV1, CerAiExecutionBundle, CerMeta, BundleDeclaration, VerificationResult } from './types.js';\nimport { CerVerifyCode } from './types.js';\nimport { toCanonicalJson } from './canonicalJson.js';\nimport { sha256Hex } from './hash.js';\nimport { verifySnapshot } from './snapshot.js';\n\ninterface CertificatePayload {\n bundleType: 'cer.ai.execution.v1';\n createdAt: string;\n snapshot: AiExecutionSnapshotV1;\n version: '0.1';\n}\n\nfunction computeCertificateHash(payload: CertificatePayload): string {\n const canonical = toCanonicalJson(payload);\n return `sha256:${sha256Hex(canonical)}`;\n}\n\nexport function sealCer(\n snapshot: AiExecutionSnapshotV1,\n options?: { createdAt?: string; meta?: CerMeta; declaration?: BundleDeclaration }\n): CerAiExecutionBundle {\n const createdAt = options?.createdAt ?? new Date().toISOString();\n\n // certificateHash covers ONLY { bundleType, createdAt, snapshot, version }.\n // `declaration` and `meta` are intentionally excluded — they are non-evidentiary.\n const payload: CertificatePayload = {\n bundleType: 'cer.ai.execution.v1',\n createdAt,\n snapshot,\n version: '0.1',\n };\n\n const certificateHash = computeCertificateHash(payload);\n\n const bundle: CerAiExecutionBundle = {\n bundleType: 'cer.ai.execution.v1',\n certificateHash,\n createdAt,\n version: '0.1',\n snapshot,\n };\n\n if (options?.meta) {\n bundle.meta = options.meta;\n }\n\n // v0.7.0: attach declaration block AFTER hashing — excluded from certificateHash by design.\n if (options?.declaration) {\n bundle.declaration = options.declaration;\n }\n\n return bundle;\n}\n\nexport function verifyCer(bundle: CerAiExecutionBundle): VerificationResult {\n const schemaErrors: string[] = [];\n const formatErrors: string[] = [];\n\n if (bundle.bundleType !== 'cer.ai.execution.v1') {\n schemaErrors.push(`Expected bundleType \"cer.ai.execution.v1\", got \"${bundle.bundleType}\"`);\n }\n\n if (bundle.version !== '0.1') {\n schemaErrors.push(`Expected version \"0.1\", got \"${bundle.version}\"`);\n }\n\n if (!bundle.createdAt || typeof bundle.createdAt !== 'string') {\n schemaErrors.push('createdAt must be a non-empty string');\n }\n\n if (!bundle.certificateHash || !bundle.certificateHash.startsWith('sha256:')) {\n formatErrors.push(`certificateHash must start with \"sha256:\", got \"${bundle.certificateHash}\"`);\n }\n\n if (!bundle.snapshot) {\n schemaErrors.push('snapshot is required');\n const allErrors = [...schemaErrors, ...formatErrors];\n return { ok: false, errors: allErrors, code: CerVerifyCode.SCHEMA_ERROR, details: schemaErrors };\n }\n\n let canonicalizationError: string | null = null;\n let snapshotResult: VerificationResult | null = null;\n\n try {\n snapshotResult = verifySnapshot(bundle.snapshot);\n } catch (err) {\n canonicalizationError = err instanceof Error ? err.message : String(err);\n }\n\n if (canonicalizationError !== null) {\n const errors = [...schemaErrors, ...formatErrors, canonicalizationError];\n return { ok: false, errors, code: CerVerifyCode.CANONICALIZATION_ERROR, details: [canonicalizationError] };\n }\n\n const snapshotErrors = snapshotResult!.errors;\n\n const certHashErrors: string[] = [];\n try {\n const payload: CertificatePayload = {\n bundleType: 'cer.ai.execution.v1',\n createdAt: bundle.createdAt,\n snapshot: bundle.snapshot,\n version: '0.1',\n };\n const expectedHash = computeCertificateHash(payload);\n if (bundle.certificateHash !== expectedHash) {\n certHashErrors.push(`certificateHash mismatch: expected ${expectedHash}, got ${bundle.certificateHash}`);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const errors = [...schemaErrors, ...formatErrors, ...snapshotErrors, msg];\n return { ok: false, errors, code: CerVerifyCode.CANONICALIZATION_ERROR, details: [msg] };\n }\n\n const errors = [...schemaErrors, ...formatErrors, ...snapshotErrors, ...certHashErrors];\n\n if (errors.length === 0) {\n return { ok: true, errors: [], code: CerVerifyCode.OK };\n }\n\n let code: typeof CerVerifyCode[keyof typeof CerVerifyCode];\n let details: string[];\n\n if (schemaErrors.length > 0) {\n code = CerVerifyCode.SCHEMA_ERROR;\n details = schemaErrors;\n } else if (formatErrors.length > 0) {\n code = CerVerifyCode.INVALID_SHA256_FORMAT;\n details = formatErrors;\n } else if (certHashErrors.length > 0 && snapshotErrors.length === 0) {\n code = CerVerifyCode.CERTIFICATE_HASH_MISMATCH;\n details = certHashErrors;\n } else if (snapshotResult && snapshotResult.code !== CerVerifyCode.OK) {\n code = snapshotResult.code;\n details = snapshotResult.details ?? snapshotErrors;\n } else if (certHashErrors.length > 0) {\n code = CerVerifyCode.CERTIFICATE_HASH_MISMATCH;\n details = certHashErrors;\n } else {\n code = CerVerifyCode.UNKNOWN_ERROR;\n details = errors;\n }\n\n return { ok: false, errors, code, details };\n}\n"],"mappings":"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","names":["crypto"]}
@@ -4,6 +4,58 @@ interface AiExecutionParameters {
4
4
  topP: number | null;
5
5
  seed: number | null;
6
6
  }
7
+ /** AIEF-06 tool call evidence record. Include in snapshot.toolCalls. */
8
+ interface ToolEvent {
9
+ toolId: string;
10
+ at: string;
11
+ inputHash?: string;
12
+ outputHash: string;
13
+ evidenceRef?: string;
14
+ error?: string;
15
+ }
16
+ /**
17
+ * Declarative block attached to a bundle that describes its integrity scheme
18
+ * and protected set. EXCLUDED from certificateHash by design — purely informational.
19
+ * Satisfies AIEF-02 SHOULD requirement for self-describing artifacts.
20
+ */
21
+ interface BundleDeclaration {
22
+ stabilitySchemeId: string;
23
+ protectedSetId: string;
24
+ protectedFields: string[];
25
+ notes?: string;
26
+ }
27
+ /** Stable placeholder produced by redactBeforeSeal(). Preserves the original value's hash. */
28
+ interface RedactionEnvelope {
29
+ _redacted: true;
30
+ hash: string;
31
+ }
32
+ /** Exact AIEF §9.1 output shape returned by verifyAief(). */
33
+ interface AiefVerifyResult {
34
+ result: 'PASS' | 'FAIL';
35
+ reason: string | null;
36
+ checks: {
37
+ schemaSupported: boolean;
38
+ integrityValid: boolean;
39
+ protectedSetValid: boolean;
40
+ chainValid: boolean;
41
+ };
42
+ field?: string;
43
+ expected?: string;
44
+ observed?: string;
45
+ notes?: string[];
46
+ }
47
+ /** Result returned by verifyRunSummary(). */
48
+ interface RunSummaryVerifyResult {
49
+ ok: boolean;
50
+ code: CerVerifyCode;
51
+ errors: string[];
52
+ details?: string[];
53
+ breakAt?: number;
54
+ expectedPrev?: string;
55
+ observedPrev?: string;
56
+ }
57
+ /** Opt-in strictness profile. Does NOT affect certificateHash computation. */
58
+ type AiefProfile = 'flexible' | 'AIEF_L2' | 'AIEF_L3' | 'AIEF_L4';
7
59
  interface AiExecutionSnapshotV1 {
8
60
  type: 'ai.execution.v1';
9
61
  protocolVersion: '1.2.0';
@@ -27,6 +79,8 @@ interface AiExecutionSnapshotV1 {
27
79
  workflowId?: string | null;
28
80
  conversationId?: string | null;
29
81
  prevStepHash?: string | null;
82
+ /** v0.7.0 — AIEF-06 tool/dependency evidence. Included in certificateHash when present. */
83
+ toolCalls?: ToolEvent[];
30
84
  }
31
85
  interface CerMeta {
32
86
  source?: string;
@@ -40,6 +94,12 @@ interface CerAiExecutionBundle {
40
94
  version: '0.1';
41
95
  snapshot: AiExecutionSnapshotV1;
42
96
  meta?: CerMeta;
97
+ /**
98
+ * v0.7.0 — Optional declarative block describing the integrity scheme and protected set.
99
+ * EXCLUDED from certificateHash computation by design. Purely informational.
100
+ * Satisfies AIEF-02 SHOULD requirement for self-describing artifacts.
101
+ */
102
+ declaration?: BundleDeclaration;
43
103
  }
44
104
  declare const CerVerifyCode: {
45
105
  readonly OK: "OK";
@@ -55,6 +115,11 @@ declare const CerVerifyCode: {
55
115
  readonly ATTESTATION_KEY_NOT_FOUND: "ATTESTATION_KEY_NOT_FOUND";
56
116
  readonly ATTESTATION_INVALID_SIGNATURE: "ATTESTATION_INVALID_SIGNATURE";
57
117
  readonly ATTESTATION_KEY_FORMAT_UNSUPPORTED: "ATTESTATION_KEY_FORMAT_UNSUPPORTED";
118
+ readonly CHAIN_BREAK_DETECTED: "CHAIN_BREAK_DETECTED";
119
+ readonly INCOMPLETE_ARTIFACT: "INCOMPLETE_ARTIFACT";
120
+ readonly VERIFICATION_MATERIAL_UNAVAILABLE: "VERIFICATION_MATERIAL_UNAVAILABLE";
121
+ readonly TOOL_EVIDENCE_MISSING: "TOOL_EVIDENCE_MISSING";
122
+ readonly TOOL_OUTPUT_HASH_MISMATCH: "TOOL_OUTPUT_HASH_MISMATCH";
58
123
  };
59
124
  type CerVerifyCode = typeof CerVerifyCode[keyof typeof CerVerifyCode];
60
125
  interface VerificationResult {
@@ -81,6 +146,8 @@ interface CreateSnapshotParams {
81
146
  workflowId?: string | null;
82
147
  conversationId?: string | null;
83
148
  prevStepHash?: string | null;
149
+ /** v0.7.0 — AIEF-06 tool/dependency evidence records. */
150
+ toolCalls?: ToolEvent[];
84
151
  }
85
152
  interface AttestationResult {
86
153
  ok: boolean;
@@ -266,4 +333,4 @@ interface WrappedExecutionResult {
266
333
  bundle: CerAiExecutionBundle;
267
334
  }
268
335
 
269
- export { type AiExecutionSnapshotV1 as A, type CreateSnapshotParams as C, type NodeKeysDocument as N, type ProviderCallParams as P, type RunBuilderOptions as R, type StepParams as S, type VerificationResult as V, type WrappedExecutionParams as W, type CerMeta as a, type CerAiExecutionBundle as b, type CertifyDecisionParams as c, type RunSummary as d, type AttestOptions as e, type AttestationResult as f, type SanitizeStorageOptions as g, type AttestationReceipt as h, type NodeReceiptVerifyResult as i, type SignedAttestationReceipt as j, CerVerifyCode as k, type AiExecutionParameters as l, type AttestationReceiptResult as m, type ClientDefaults as n, type NexArtClient as o, type ProviderCallResult as p, type ProviderConfig as q, type WrappedExecutionResult as r };
336
+ export { type AiExecutionSnapshotV1 as A, type BundleDeclaration as B, type CreateSnapshotParams as C, type NodeKeysDocument as N, type ProviderCallParams as P, type RunBuilderOptions as R, type StepParams as S, type ToolEvent as T, type VerificationResult as V, type WrappedExecutionParams as W, type CerMeta as a, type CerAiExecutionBundle as b, type CertifyDecisionParams as c, type RunSummary as d, type AttestOptions as e, type AttestationResult as f, type SanitizeStorageOptions as g, type AttestationReceipt as h, type NodeReceiptVerifyResult as i, type SignedAttestationReceipt as j, CerVerifyCode as k, type AiefVerifyResult as l, type RunSummaryVerifyResult as m, type AiefProfile as n, type AiExecutionParameters as o, type AttestationReceiptResult as p, type ClientDefaults as q, type NexArtClient as r, type ProviderCallResult as s, type ProviderConfig as t, type RedactionEnvelope as u, type WrappedExecutionResult as v };
@@ -4,6 +4,58 @@ interface AiExecutionParameters {
4
4
  topP: number | null;
5
5
  seed: number | null;
6
6
  }
7
+ /** AIEF-06 tool call evidence record. Include in snapshot.toolCalls. */
8
+ interface ToolEvent {
9
+ toolId: string;
10
+ at: string;
11
+ inputHash?: string;
12
+ outputHash: string;
13
+ evidenceRef?: string;
14
+ error?: string;
15
+ }
16
+ /**
17
+ * Declarative block attached to a bundle that describes its integrity scheme
18
+ * and protected set. EXCLUDED from certificateHash by design — purely informational.
19
+ * Satisfies AIEF-02 SHOULD requirement for self-describing artifacts.
20
+ */
21
+ interface BundleDeclaration {
22
+ stabilitySchemeId: string;
23
+ protectedSetId: string;
24
+ protectedFields: string[];
25
+ notes?: string;
26
+ }
27
+ /** Stable placeholder produced by redactBeforeSeal(). Preserves the original value's hash. */
28
+ interface RedactionEnvelope {
29
+ _redacted: true;
30
+ hash: string;
31
+ }
32
+ /** Exact AIEF §9.1 output shape returned by verifyAief(). */
33
+ interface AiefVerifyResult {
34
+ result: 'PASS' | 'FAIL';
35
+ reason: string | null;
36
+ checks: {
37
+ schemaSupported: boolean;
38
+ integrityValid: boolean;
39
+ protectedSetValid: boolean;
40
+ chainValid: boolean;
41
+ };
42
+ field?: string;
43
+ expected?: string;
44
+ observed?: string;
45
+ notes?: string[];
46
+ }
47
+ /** Result returned by verifyRunSummary(). */
48
+ interface RunSummaryVerifyResult {
49
+ ok: boolean;
50
+ code: CerVerifyCode;
51
+ errors: string[];
52
+ details?: string[];
53
+ breakAt?: number;
54
+ expectedPrev?: string;
55
+ observedPrev?: string;
56
+ }
57
+ /** Opt-in strictness profile. Does NOT affect certificateHash computation. */
58
+ type AiefProfile = 'flexible' | 'AIEF_L2' | 'AIEF_L3' | 'AIEF_L4';
7
59
  interface AiExecutionSnapshotV1 {
8
60
  type: 'ai.execution.v1';
9
61
  protocolVersion: '1.2.0';
@@ -27,6 +79,8 @@ interface AiExecutionSnapshotV1 {
27
79
  workflowId?: string | null;
28
80
  conversationId?: string | null;
29
81
  prevStepHash?: string | null;
82
+ /** v0.7.0 — AIEF-06 tool/dependency evidence. Included in certificateHash when present. */
83
+ toolCalls?: ToolEvent[];
30
84
  }
31
85
  interface CerMeta {
32
86
  source?: string;
@@ -40,6 +94,12 @@ interface CerAiExecutionBundle {
40
94
  version: '0.1';
41
95
  snapshot: AiExecutionSnapshotV1;
42
96
  meta?: CerMeta;
97
+ /**
98
+ * v0.7.0 — Optional declarative block describing the integrity scheme and protected set.
99
+ * EXCLUDED from certificateHash computation by design. Purely informational.
100
+ * Satisfies AIEF-02 SHOULD requirement for self-describing artifacts.
101
+ */
102
+ declaration?: BundleDeclaration;
43
103
  }
44
104
  declare const CerVerifyCode: {
45
105
  readonly OK: "OK";
@@ -55,6 +115,11 @@ declare const CerVerifyCode: {
55
115
  readonly ATTESTATION_KEY_NOT_FOUND: "ATTESTATION_KEY_NOT_FOUND";
56
116
  readonly ATTESTATION_INVALID_SIGNATURE: "ATTESTATION_INVALID_SIGNATURE";
57
117
  readonly ATTESTATION_KEY_FORMAT_UNSUPPORTED: "ATTESTATION_KEY_FORMAT_UNSUPPORTED";
118
+ readonly CHAIN_BREAK_DETECTED: "CHAIN_BREAK_DETECTED";
119
+ readonly INCOMPLETE_ARTIFACT: "INCOMPLETE_ARTIFACT";
120
+ readonly VERIFICATION_MATERIAL_UNAVAILABLE: "VERIFICATION_MATERIAL_UNAVAILABLE";
121
+ readonly TOOL_EVIDENCE_MISSING: "TOOL_EVIDENCE_MISSING";
122
+ readonly TOOL_OUTPUT_HASH_MISMATCH: "TOOL_OUTPUT_HASH_MISMATCH";
58
123
  };
59
124
  type CerVerifyCode = typeof CerVerifyCode[keyof typeof CerVerifyCode];
60
125
  interface VerificationResult {
@@ -81,6 +146,8 @@ interface CreateSnapshotParams {
81
146
  workflowId?: string | null;
82
147
  conversationId?: string | null;
83
148
  prevStepHash?: string | null;
149
+ /** v0.7.0 — AIEF-06 tool/dependency evidence records. */
150
+ toolCalls?: ToolEvent[];
84
151
  }
85
152
  interface AttestationResult {
86
153
  ok: boolean;
@@ -266,4 +333,4 @@ interface WrappedExecutionResult {
266
333
  bundle: CerAiExecutionBundle;
267
334
  }
268
335
 
269
- export { type AiExecutionSnapshotV1 as A, type CreateSnapshotParams as C, type NodeKeysDocument as N, type ProviderCallParams as P, type RunBuilderOptions as R, type StepParams as S, type VerificationResult as V, type WrappedExecutionParams as W, type CerMeta as a, type CerAiExecutionBundle as b, type CertifyDecisionParams as c, type RunSummary as d, type AttestOptions as e, type AttestationResult as f, type SanitizeStorageOptions as g, type AttestationReceipt as h, type NodeReceiptVerifyResult as i, type SignedAttestationReceipt as j, CerVerifyCode as k, type AiExecutionParameters as l, type AttestationReceiptResult as m, type ClientDefaults as n, type NexArtClient as o, type ProviderCallResult as p, type ProviderConfig as q, type WrappedExecutionResult as r };
336
+ export { type AiExecutionSnapshotV1 as A, type BundleDeclaration as B, type CreateSnapshotParams as C, type NodeKeysDocument as N, type ProviderCallParams as P, type RunBuilderOptions as R, type StepParams as S, type ToolEvent as T, type VerificationResult as V, type WrappedExecutionParams as W, type CerMeta as a, type CerAiExecutionBundle as b, type CertifyDecisionParams as c, type RunSummary as d, type AttestOptions as e, type AttestationResult as f, type SanitizeStorageOptions as g, type AttestationReceipt as h, type NodeReceiptVerifyResult as i, type SignedAttestationReceipt as j, CerVerifyCode as k, type AiefVerifyResult as l, type RunSummaryVerifyResult as m, type AiefProfile as n, type AiExecutionParameters as o, type AttestationReceiptResult as p, type ClientDefaults as q, type NexArtClient as r, type ProviderCallResult as s, type ProviderConfig as t, type RedactionEnvelope as u, type WrappedExecutionResult as v };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexart/ai-execution",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "AI Execution Integrity — tamper-evident records and Certified Execution Records (CER) for AI operations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -32,7 +32,7 @@
32
32
  "scripts": {
33
33
  "build": "node \"$(node -p 'require.resolve(\"tsup/dist/cli-default\")')\"",
34
34
  "build:tsc": "node \"$(node -p 'require.resolve(\"typescript/bin/tsc\")')\"",
35
- "test": "node \"$(node -p 'require.resolve(\"typescript/bin/tsc\")')\" && node --test dist-tsc/__tests__/vectors.test.js dist-tsc/__tests__/fixtures.test.js dist-tsc/__tests__/v020.test.js dist-tsc/__tests__/v030.test.js dist-tsc/__tests__/v040.test.js dist-tsc/__tests__/v041.test.js dist-tsc/__tests__/v042.test.js dist-tsc/__tests__/v050.test.js dist-tsc/__tests__/v060.test.js",
35
+ "test": "node \"$(node -p 'require.resolve(\"typescript/bin/tsc\")')\" && node --test dist-tsc/__tests__/vectors.test.js dist-tsc/__tests__/fixtures.test.js dist-tsc/__tests__/v020.test.js dist-tsc/__tests__/v030.test.js dist-tsc/__tests__/v040.test.js dist-tsc/__tests__/v041.test.js dist-tsc/__tests__/v042.test.js dist-tsc/__tests__/v050.test.js dist-tsc/__tests__/v060.test.js dist-tsc/__tests__/v070.test.js",
36
36
  "release": "npm run build && npm run test && npm version patch && npm publish --access public",
37
37
  "prepublishOnly": "npm run build && npm run test"
38
38
  },