@nexart/ai-execution 0.4.0 → 0.4.2
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 +73 -7
- package/dist/index.cjs +208 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -3
- package/dist/index.d.ts +14 -3
- package/dist/index.mjs +204 -41
- package/dist/index.mjs.map +1 -1
- package/dist/providers/anthropic.cjs +1 -1
- package/dist/providers/anthropic.cjs.map +1 -1
- package/dist/providers/anthropic.d.cts +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/anthropic.mjs +1 -1
- package/dist/providers/anthropic.mjs.map +1 -1
- package/dist/providers/openai.cjs +1 -1
- package/dist/providers/openai.cjs.map +1 -1
- package/dist/providers/openai.d.cts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.mjs +1 -1
- package/dist/providers/openai.mjs.map +1 -1
- package/dist/providers/wrap.cjs +1 -1
- package/dist/providers/wrap.cjs.map +1 -1
- package/dist/providers/wrap.d.cts +1 -1
- package/dist/providers/wrap.d.ts +1 -1
- package/dist/providers/wrap.mjs +1 -1
- package/dist/providers/wrap.mjs.map +1 -1
- package/dist/{types-DF29BsH5.d.cts → types-Cnm2G_rg.d.cts} +26 -1
- package/dist/{types-DF29BsH5.d.ts → types-Cnm2G_rg.d.ts} +26 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hash.ts","../../src/canonicalJson.ts","../../src/snapshot.ts","../../src/cer.ts","../../src/providers/openai.ts"],"sourcesContent":["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 { computeInputHash, computeOutputHash } from './hash.js';\n\nconst PACKAGE_VERSION = '0.4.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 errors: string[] = [];\n\n if (snapshot.type !== 'ai.execution.v1') {\n errors.push(`Expected type \"ai.execution.v1\", got \"${snapshot.type}\"`);\n }\n\n if (snapshot.protocolVersion !== '1.2.0') {\n errors.push(`Expected protocolVersion \"1.2.0\", got \"${snapshot.protocolVersion}\"`);\n }\n\n if (snapshot.executionSurface !== 'ai') {\n errors.push(`Expected executionSurface \"ai\", got \"${snapshot.executionSurface}\"`);\n }\n\n if (!snapshot.executionId || typeof snapshot.executionId !== 'string') {\n errors.push('executionId must be a non-empty string');\n }\n\n if (!snapshot.timestamp || typeof snapshot.timestamp !== 'string') {\n errors.push('timestamp must be a non-empty string');\n }\n\n if (!snapshot.provider || typeof snapshot.provider !== 'string') {\n errors.push('provider must be a non-empty string');\n }\n\n if (!snapshot.model || typeof snapshot.model !== 'string') {\n errors.push('model must be a non-empty string');\n }\n\n if (!snapshot.prompt || typeof snapshot.prompt !== 'string') {\n errors.push('prompt must be a non-empty string');\n }\n\n if (snapshot.input === undefined || snapshot.input === null) {\n errors.push('input must be a string or object');\n }\n\n if (snapshot.output === undefined || snapshot.output === null) {\n errors.push('output must be a string or object');\n }\n\n const paramErrors = validateParameters(snapshot.parameters);\n errors.push(...paramErrors);\n\n if (!snapshot.inputHash || !snapshot.inputHash.startsWith('sha256:')) {\n errors.push(`inputHash must start with \"sha256:\", got \"${snapshot.inputHash}\"`);\n }\n\n if (!snapshot.outputHash || !snapshot.outputHash.startsWith('sha256:')) {\n errors.push(`outputHash must start with \"sha256:\", got \"${snapshot.outputHash}\"`);\n }\n\n const expectedInputHash = computeInputHash(snapshot.input);\n if (snapshot.inputHash !== expectedInputHash) {\n errors.push(`inputHash mismatch: expected ${expectedInputHash}, got ${snapshot.inputHash}`);\n }\n\n const expectedOutputHash = computeOutputHash(snapshot.output);\n if (snapshot.outputHash !== expectedOutputHash) {\n errors.push(`outputHash mismatch: expected ${expectedOutputHash}, got ${snapshot.outputHash}`);\n }\n\n return { ok: errors.length === 0, errors };\n}\n","import type { AiExecutionSnapshotV1, CerAiExecutionBundle, CerMeta, VerificationResult } 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 errors: string[] = [];\n\n if (bundle.bundleType !== 'cer.ai.execution.v1') {\n errors.push(`Expected bundleType \"cer.ai.execution.v1\", got \"${bundle.bundleType}\"`);\n }\n\n if (bundle.version !== '0.1') {\n errors.push(`Expected version \"0.1\", got \"${bundle.version}\"`);\n }\n\n if (!bundle.createdAt || typeof bundle.createdAt !== 'string') {\n errors.push('createdAt must be a non-empty string');\n }\n\n if (!bundle.certificateHash || !bundle.certificateHash.startsWith('sha256:')) {\n errors.push(`certificateHash must start with \"sha256:\", got \"${bundle.certificateHash}\"`);\n }\n\n if (!bundle.snapshot) {\n errors.push('snapshot is required');\n return { ok: false, errors };\n }\n\n const snapshotResult = verifySnapshot(bundle.snapshot);\n errors.push(...snapshotResult.errors);\n\n const payload: CertificatePayload = {\n bundleType: 'cer.ai.execution.v1',\n createdAt: bundle.createdAt,\n snapshot: bundle.snapshot,\n version: '0.1',\n };\n\n const expectedHash = computeCertificateHash(payload);\n if (bundle.certificateHash !== expectedHash) {\n errors.push(`certificateHash mismatch: expected ${expectedHash}, got ${bundle.certificateHash}`);\n }\n\n return { ok: errors.length === 0, errors };\n}\n","import type { AiExecutionSnapshotV1, CerAiExecutionBundle } from '../types.js';\nimport { createSnapshot } from '../snapshot.js';\nimport { sealCer } from '../cer.js';\nimport * as crypto from 'crypto';\n\nexport interface OpenAIChatParams {\n prompt: string;\n input: string;\n model?: string;\n modelVersion?: string | null;\n parameters?: {\n temperature?: number;\n maxTokens?: number;\n topP?: number | null;\n seed?: number | null;\n };\n appId?: string | null;\n apiKey?: string;\n}\n\nexport interface OpenAIChatResult {\n output: string;\n snapshot: AiExecutionSnapshotV1;\n bundle: CerAiExecutionBundle;\n}\n\nexport async function runOpenAIChatExecution(params: OpenAIChatParams): Promise<OpenAIChatResult> {\n const apiKey = params.apiKey || process.env.OPENAI_API_KEY;\n if (!apiKey) {\n throw new Error(\n 'Missing OpenAI API key. Set OPENAI_API_KEY environment variable or pass apiKey in params.'\n );\n }\n\n const model = params.model ?? 'gpt-4o';\n const temperature = params.parameters?.temperature ?? 0.7;\n const maxTokens = params.parameters?.maxTokens ?? 1024;\n const topP = params.parameters?.topP ?? null;\n const seed = params.parameters?.seed ?? null;\n\n const requestBody: Record<string, unknown> = {\n model,\n messages: [\n { role: 'system', content: params.prompt },\n { role: 'user', content: params.input },\n ],\n temperature,\n max_tokens: maxTokens,\n };\n\n if (topP !== null) {\n requestBody.top_p = topP;\n }\n if (seed !== null) {\n requestBody.seed = seed;\n }\n\n const response = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`OpenAI API error (${response.status}): ${errorText}`);\n }\n\n const json = await response.json() as {\n choices: Array<{ message: { content: string } }>;\n model: string;\n };\n\n const output = json.choices[0]?.message?.content ?? '';\n\n const snapshot = createSnapshot({\n executionId: crypto.randomUUID(),\n provider: 'openai',\n model,\n modelVersion: params.modelVersion ?? json.model ?? null,\n prompt: params.prompt,\n input: params.input,\n parameters: {\n temperature,\n maxTokens,\n topP,\n seed,\n },\n output,\n appId: params.appId ?? null,\n });\n\n const bundle = sealCer(snapshot);\n\n return { output, snapshot, bundle };\n}\n"],"mappings":"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","names":["crypto"]}
|
|
1
|
+
{"version":3,"sources":["../../src/hash.ts","../../src/canonicalJson.ts","../../src/snapshot.ts","../../src/cer.ts","../../src/providers/openai.ts"],"sourcesContent":["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.4.2';\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","import type { AiExecutionSnapshotV1, CerAiExecutionBundle } from '../types.js';\nimport { createSnapshot } from '../snapshot.js';\nimport { sealCer } from '../cer.js';\nimport * as crypto from 'crypto';\n\nexport interface OpenAIChatParams {\n prompt: string;\n input: string;\n model?: string;\n modelVersion?: string | null;\n parameters?: {\n temperature?: number;\n maxTokens?: number;\n topP?: number | null;\n seed?: number | null;\n };\n appId?: string | null;\n apiKey?: string;\n}\n\nexport interface OpenAIChatResult {\n output: string;\n snapshot: AiExecutionSnapshotV1;\n bundle: CerAiExecutionBundle;\n}\n\nexport async function runOpenAIChatExecution(params: OpenAIChatParams): Promise<OpenAIChatResult> {\n const apiKey = params.apiKey || process.env.OPENAI_API_KEY;\n if (!apiKey) {\n throw new Error(\n 'Missing OpenAI API key. Set OPENAI_API_KEY environment variable or pass apiKey in params.'\n );\n }\n\n const model = params.model ?? 'gpt-4o';\n const temperature = params.parameters?.temperature ?? 0.7;\n const maxTokens = params.parameters?.maxTokens ?? 1024;\n const topP = params.parameters?.topP ?? null;\n const seed = params.parameters?.seed ?? null;\n\n const requestBody: Record<string, unknown> = {\n model,\n messages: [\n { role: 'system', content: params.prompt },\n { role: 'user', content: params.input },\n ],\n temperature,\n max_tokens: maxTokens,\n };\n\n if (topP !== null) {\n requestBody.top_p = topP;\n }\n if (seed !== null) {\n requestBody.seed = seed;\n }\n\n const response = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`OpenAI API error (${response.status}): ${errorText}`);\n }\n\n const json = await response.json() as {\n choices: Array<{ message: { content: string } }>;\n model: string;\n };\n\n const output = json.choices[0]?.message?.content ?? '';\n\n const snapshot = createSnapshot({\n executionId: crypto.randomUUID(),\n provider: 'openai',\n model,\n modelVersion: params.modelVersion ?? json.model ?? null,\n prompt: params.prompt,\n input: params.input,\n parameters: {\n temperature,\n maxTokens,\n topP,\n seed,\n },\n output,\n appId: params.appId ?? null,\n });\n\n const bundle = sealCer(snapshot);\n\n return { output, snapshot, bundle };\n}\n"],"mappings":"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","names":["crypto"]}
|
package/dist/providers/wrap.cjs
CHANGED
|
@@ -108,7 +108,7 @@ function computeOutputHash(output) {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
// src/snapshot.ts
|
|
111
|
-
var PACKAGE_VERSION = "0.4.
|
|
111
|
+
var PACKAGE_VERSION = "0.4.2";
|
|
112
112
|
function validateParameters(params) {
|
|
113
113
|
const errors = [];
|
|
114
114
|
if (typeof params.temperature !== "number" || !Number.isFinite(params.temperature)) {
|
|
@@ -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 { computeInputHash, computeOutputHash } from './hash.js';\n\nconst PACKAGE_VERSION = '0.4.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 errors: string[] = [];\n\n if (snapshot.type !== 'ai.execution.v1') {\n errors.push(`Expected type \"ai.execution.v1\", got \"${snapshot.type}\"`);\n }\n\n if (snapshot.protocolVersion !== '1.2.0') {\n errors.push(`Expected protocolVersion \"1.2.0\", got \"${snapshot.protocolVersion}\"`);\n }\n\n if (snapshot.executionSurface !== 'ai') {\n errors.push(`Expected executionSurface \"ai\", got \"${snapshot.executionSurface}\"`);\n }\n\n if (!snapshot.executionId || typeof snapshot.executionId !== 'string') {\n errors.push('executionId must be a non-empty string');\n }\n\n if (!snapshot.timestamp || typeof snapshot.timestamp !== 'string') {\n errors.push('timestamp must be a non-empty string');\n }\n\n if (!snapshot.provider || typeof snapshot.provider !== 'string') {\n errors.push('provider must be a non-empty string');\n }\n\n if (!snapshot.model || typeof snapshot.model !== 'string') {\n errors.push('model must be a non-empty string');\n }\n\n if (!snapshot.prompt || typeof snapshot.prompt !== 'string') {\n errors.push('prompt must be a non-empty string');\n }\n\n if (snapshot.input === undefined || snapshot.input === null) {\n errors.push('input must be a string or object');\n }\n\n if (snapshot.output === undefined || snapshot.output === null) {\n errors.push('output must be a string or object');\n }\n\n const paramErrors = validateParameters(snapshot.parameters);\n errors.push(...paramErrors);\n\n if (!snapshot.inputHash || !snapshot.inputHash.startsWith('sha256:')) {\n errors.push(`inputHash must start with \"sha256:\", got \"${snapshot.inputHash}\"`);\n }\n\n if (!snapshot.outputHash || !snapshot.outputHash.startsWith('sha256:')) {\n errors.push(`outputHash must start with \"sha256:\", got \"${snapshot.outputHash}\"`);\n }\n\n const expectedInputHash = computeInputHash(snapshot.input);\n if (snapshot.inputHash !== expectedInputHash) {\n errors.push(`inputHash mismatch: expected ${expectedInputHash}, got ${snapshot.inputHash}`);\n }\n\n const expectedOutputHash = computeOutputHash(snapshot.output);\n if (snapshot.outputHash !== expectedOutputHash) {\n errors.push(`outputHash mismatch: expected ${expectedOutputHash}, got ${snapshot.outputHash}`);\n }\n\n return { ok: errors.length === 0, errors };\n}\n","import type { AiExecutionSnapshotV1, CerAiExecutionBundle, CerMeta, VerificationResult } 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 errors: string[] = [];\n\n if (bundle.bundleType !== 'cer.ai.execution.v1') {\n errors.push(`Expected bundleType \"cer.ai.execution.v1\", got \"${bundle.bundleType}\"`);\n }\n\n if (bundle.version !== '0.1') {\n errors.push(`Expected version \"0.1\", got \"${bundle.version}\"`);\n }\n\n if (!bundle.createdAt || typeof bundle.createdAt !== 'string') {\n errors.push('createdAt must be a non-empty string');\n }\n\n if (!bundle.certificateHash || !bundle.certificateHash.startsWith('sha256:')) {\n errors.push(`certificateHash must start with \"sha256:\", got \"${bundle.certificateHash}\"`);\n }\n\n if (!bundle.snapshot) {\n errors.push('snapshot is required');\n return { ok: false, errors };\n }\n\n const snapshotResult = verifySnapshot(bundle.snapshot);\n errors.push(...snapshotResult.errors);\n\n const payload: CertificatePayload = {\n bundleType: 'cer.ai.execution.v1',\n createdAt: bundle.createdAt,\n snapshot: bundle.snapshot,\n version: '0.1',\n };\n\n const expectedHash = computeCertificateHash(payload);\n if (bundle.certificateHash !== expectedHash) {\n errors.push(`certificateHash mismatch: expected ${expectedHash}, got ${bundle.certificateHash}`);\n }\n\n return { ok: errors.length === 0, errors };\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.4.2';\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;AAEtF,SAAO;AACT;;;ACxDA,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;AAE/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;AAEA,SAAO;AACT;;;AJrCO,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 { P as ProviderConfig, W as WrappedExecutionParams,
|
|
1
|
+
import { P as ProviderConfig, W as WrappedExecutionParams, k as WrappedExecutionResult } from '../types-Cnm2G_rg.cjs';
|
|
2
2
|
|
|
3
3
|
declare function wrapProvider<TInput = unknown, TOutput = unknown>(config: ProviderConfig<TInput, TOutput>): {
|
|
4
4
|
execute(params: WrappedExecutionParams & {
|
package/dist/providers/wrap.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as ProviderConfig, W as WrappedExecutionParams,
|
|
1
|
+
import { P as ProviderConfig, W as WrappedExecutionParams, k as WrappedExecutionResult } from '../types-Cnm2G_rg.js';
|
|
2
2
|
|
|
3
3
|
declare function wrapProvider<TInput = unknown, TOutput = unknown>(config: ProviderConfig<TInput, TOutput>): {
|
|
4
4
|
execute(params: WrappedExecutionParams & {
|
package/dist/providers/wrap.mjs
CHANGED
|
@@ -74,7 +74,7 @@ function computeOutputHash(output) {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
// src/snapshot.ts
|
|
77
|
-
var PACKAGE_VERSION = "0.4.
|
|
77
|
+
var PACKAGE_VERSION = "0.4.2";
|
|
78
78
|
function validateParameters(params) {
|
|
79
79
|
const errors = [];
|
|
80
80
|
if (typeof params.temperature !== "number" || !Number.isFinite(params.temperature)) {
|
|
@@ -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 { computeInputHash, computeOutputHash } from './hash.js';\n\nconst PACKAGE_VERSION = '0.4.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 errors: string[] = [];\n\n if (snapshot.type !== 'ai.execution.v1') {\n errors.push(`Expected type \"ai.execution.v1\", got \"${snapshot.type}\"`);\n }\n\n if (snapshot.protocolVersion !== '1.2.0') {\n errors.push(`Expected protocolVersion \"1.2.0\", got \"${snapshot.protocolVersion}\"`);\n }\n\n if (snapshot.executionSurface !== 'ai') {\n errors.push(`Expected executionSurface \"ai\", got \"${snapshot.executionSurface}\"`);\n }\n\n if (!snapshot.executionId || typeof snapshot.executionId !== 'string') {\n errors.push('executionId must be a non-empty string');\n }\n\n if (!snapshot.timestamp || typeof snapshot.timestamp !== 'string') {\n errors.push('timestamp must be a non-empty string');\n }\n\n if (!snapshot.provider || typeof snapshot.provider !== 'string') {\n errors.push('provider must be a non-empty string');\n }\n\n if (!snapshot.model || typeof snapshot.model !== 'string') {\n errors.push('model must be a non-empty string');\n }\n\n if (!snapshot.prompt || typeof snapshot.prompt !== 'string') {\n errors.push('prompt must be a non-empty string');\n }\n\n if (snapshot.input === undefined || snapshot.input === null) {\n errors.push('input must be a string or object');\n }\n\n if (snapshot.output === undefined || snapshot.output === null) {\n errors.push('output must be a string or object');\n }\n\n const paramErrors = validateParameters(snapshot.parameters);\n errors.push(...paramErrors);\n\n if (!snapshot.inputHash || !snapshot.inputHash.startsWith('sha256:')) {\n errors.push(`inputHash must start with \"sha256:\", got \"${snapshot.inputHash}\"`);\n }\n\n if (!snapshot.outputHash || !snapshot.outputHash.startsWith('sha256:')) {\n errors.push(`outputHash must start with \"sha256:\", got \"${snapshot.outputHash}\"`);\n }\n\n const expectedInputHash = computeInputHash(snapshot.input);\n if (snapshot.inputHash !== expectedInputHash) {\n errors.push(`inputHash mismatch: expected ${expectedInputHash}, got ${snapshot.inputHash}`);\n }\n\n const expectedOutputHash = computeOutputHash(snapshot.output);\n if (snapshot.outputHash !== expectedOutputHash) {\n errors.push(`outputHash mismatch: expected ${expectedOutputHash}, got ${snapshot.outputHash}`);\n }\n\n return { ok: errors.length === 0, errors };\n}\n","import type { AiExecutionSnapshotV1, CerAiExecutionBundle, CerMeta, VerificationResult } 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 errors: string[] = [];\n\n if (bundle.bundleType !== 'cer.ai.execution.v1') {\n errors.push(`Expected bundleType \"cer.ai.execution.v1\", got \"${bundle.bundleType}\"`);\n }\n\n if (bundle.version !== '0.1') {\n errors.push(`Expected version \"0.1\", got \"${bundle.version}\"`);\n }\n\n if (!bundle.createdAt || typeof bundle.createdAt !== 'string') {\n errors.push('createdAt must be a non-empty string');\n }\n\n if (!bundle.certificateHash || !bundle.certificateHash.startsWith('sha256:')) {\n errors.push(`certificateHash must start with \"sha256:\", got \"${bundle.certificateHash}\"`);\n }\n\n if (!bundle.snapshot) {\n errors.push('snapshot is required');\n return { ok: false, errors };\n }\n\n const snapshotResult = verifySnapshot(bundle.snapshot);\n errors.push(...snapshotResult.errors);\n\n const payload: CertificatePayload = {\n bundleType: 'cer.ai.execution.v1',\n createdAt: bundle.createdAt,\n snapshot: bundle.snapshot,\n version: '0.1',\n };\n\n const expectedHash = computeCertificateHash(payload);\n if (bundle.certificateHash !== expectedHash) {\n errors.push(`certificateHash mismatch: expected ${expectedHash}, got ${bundle.certificateHash}`);\n }\n\n return { ok: errors.length === 0, errors };\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.4.2';\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"]}
|
|
@@ -41,9 +41,23 @@ interface CerAiExecutionBundle {
|
|
|
41
41
|
snapshot: AiExecutionSnapshotV1;
|
|
42
42
|
meta?: CerMeta;
|
|
43
43
|
}
|
|
44
|
+
declare const CerVerifyCode: {
|
|
45
|
+
readonly OK: "OK";
|
|
46
|
+
readonly CERTIFICATE_HASH_MISMATCH: "CERTIFICATE_HASH_MISMATCH";
|
|
47
|
+
readonly SNAPSHOT_HASH_MISMATCH: "SNAPSHOT_HASH_MISMATCH";
|
|
48
|
+
readonly INPUT_HASH_MISMATCH: "INPUT_HASH_MISMATCH";
|
|
49
|
+
readonly OUTPUT_HASH_MISMATCH: "OUTPUT_HASH_MISMATCH";
|
|
50
|
+
readonly INVALID_SHA256_FORMAT: "INVALID_SHA256_FORMAT";
|
|
51
|
+
readonly CANONICALIZATION_ERROR: "CANONICALIZATION_ERROR";
|
|
52
|
+
readonly SCHEMA_ERROR: "SCHEMA_ERROR";
|
|
53
|
+
readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
|
|
54
|
+
};
|
|
55
|
+
type CerVerifyCode = typeof CerVerifyCode[keyof typeof CerVerifyCode];
|
|
44
56
|
interface VerificationResult {
|
|
45
57
|
ok: boolean;
|
|
46
58
|
errors: string[];
|
|
59
|
+
code: CerVerifyCode;
|
|
60
|
+
details?: string[];
|
|
47
61
|
}
|
|
48
62
|
interface CreateSnapshotParams {
|
|
49
63
|
executionId: string;
|
|
@@ -73,6 +87,17 @@ interface AttestationResult {
|
|
|
73
87
|
errors?: string[];
|
|
74
88
|
raw?: unknown;
|
|
75
89
|
}
|
|
90
|
+
type AttestationReceipt = {
|
|
91
|
+
attestationId: string;
|
|
92
|
+
certificateHash: string;
|
|
93
|
+
nodeRuntimeHash: string;
|
|
94
|
+
protocolVersion: string;
|
|
95
|
+
nodeId?: string;
|
|
96
|
+
attestedAt?: string;
|
|
97
|
+
};
|
|
98
|
+
type AttestationReceiptResult = {
|
|
99
|
+
receipt: AttestationReceipt;
|
|
100
|
+
};
|
|
76
101
|
interface AttestOptions {
|
|
77
102
|
nodeUrl: string;
|
|
78
103
|
apiKey: string;
|
|
@@ -152,4 +177,4 @@ interface WrappedExecutionResult {
|
|
|
152
177
|
bundle: CerAiExecutionBundle;
|
|
153
178
|
}
|
|
154
179
|
|
|
155
|
-
export type
|
|
180
|
+
export { type AiExecutionSnapshotV1 as A, type CreateSnapshotParams as C, type ProviderConfig 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 AttestationReceipt as g, CerVerifyCode as h, type AiExecutionParameters as i, type AttestationReceiptResult as j, type WrappedExecutionResult as k };
|
|
@@ -41,9 +41,23 @@ interface CerAiExecutionBundle {
|
|
|
41
41
|
snapshot: AiExecutionSnapshotV1;
|
|
42
42
|
meta?: CerMeta;
|
|
43
43
|
}
|
|
44
|
+
declare const CerVerifyCode: {
|
|
45
|
+
readonly OK: "OK";
|
|
46
|
+
readonly CERTIFICATE_HASH_MISMATCH: "CERTIFICATE_HASH_MISMATCH";
|
|
47
|
+
readonly SNAPSHOT_HASH_MISMATCH: "SNAPSHOT_HASH_MISMATCH";
|
|
48
|
+
readonly INPUT_HASH_MISMATCH: "INPUT_HASH_MISMATCH";
|
|
49
|
+
readonly OUTPUT_HASH_MISMATCH: "OUTPUT_HASH_MISMATCH";
|
|
50
|
+
readonly INVALID_SHA256_FORMAT: "INVALID_SHA256_FORMAT";
|
|
51
|
+
readonly CANONICALIZATION_ERROR: "CANONICALIZATION_ERROR";
|
|
52
|
+
readonly SCHEMA_ERROR: "SCHEMA_ERROR";
|
|
53
|
+
readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
|
|
54
|
+
};
|
|
55
|
+
type CerVerifyCode = typeof CerVerifyCode[keyof typeof CerVerifyCode];
|
|
44
56
|
interface VerificationResult {
|
|
45
57
|
ok: boolean;
|
|
46
58
|
errors: string[];
|
|
59
|
+
code: CerVerifyCode;
|
|
60
|
+
details?: string[];
|
|
47
61
|
}
|
|
48
62
|
interface CreateSnapshotParams {
|
|
49
63
|
executionId: string;
|
|
@@ -73,6 +87,17 @@ interface AttestationResult {
|
|
|
73
87
|
errors?: string[];
|
|
74
88
|
raw?: unknown;
|
|
75
89
|
}
|
|
90
|
+
type AttestationReceipt = {
|
|
91
|
+
attestationId: string;
|
|
92
|
+
certificateHash: string;
|
|
93
|
+
nodeRuntimeHash: string;
|
|
94
|
+
protocolVersion: string;
|
|
95
|
+
nodeId?: string;
|
|
96
|
+
attestedAt?: string;
|
|
97
|
+
};
|
|
98
|
+
type AttestationReceiptResult = {
|
|
99
|
+
receipt: AttestationReceipt;
|
|
100
|
+
};
|
|
76
101
|
interface AttestOptions {
|
|
77
102
|
nodeUrl: string;
|
|
78
103
|
apiKey: string;
|
|
@@ -152,4 +177,4 @@ interface WrappedExecutionResult {
|
|
|
152
177
|
bundle: CerAiExecutionBundle;
|
|
153
178
|
}
|
|
154
179
|
|
|
155
|
-
export type
|
|
180
|
+
export { type AiExecutionSnapshotV1 as A, type CreateSnapshotParams as C, type ProviderConfig 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 AttestationReceipt as g, CerVerifyCode as h, type AiExecutionParameters as i, type AttestationReceiptResult as j, type WrappedExecutionResult as k };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexart/ai-execution",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
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": "tsup",
|
|
34
34
|
"build:tsc": "tsc",
|
|
35
|
-
"test": "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",
|
|
35
|
+
"test": "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",
|
|
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
|
},
|