@intentproof/sdk 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +0 -25
- package/NOTICE +16 -0
- package/README.md +40 -406
- package/dist/canon.d.ts +11 -0
- package/dist/canon.js +17 -0
- package/dist/client.d.ts +21 -0
- package/dist/client.js +114 -0
- package/dist/exporter.d.ts +12 -0
- package/dist/exporter.js +68 -0
- package/dist/index.d.ts +3 -524
- package/dist/index.js +22 -1118
- package/dist/instrumentation.d.ts +6 -0
- package/dist/instrumentation.js +129 -0
- package/dist/outbox.d.ts +11 -0
- package/dist/outbox.js +53 -0
- package/dist/signing.d.ts +6 -0
- package/dist/signing.js +55 -0
- package/package.json +40 -71
- package/dist/index.cjs +0 -1171
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -524
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function runWithCorrelationId<T>(id: string, fn: () => T): T;
|
|
2
|
+
export declare function pushSubjectMapping(sourceId: string, subjectType: string, subjectId: string): void;
|
|
3
|
+
export declare function wrap<T extends (...args: any[]) => any>(options: {
|
|
4
|
+
intent: string;
|
|
5
|
+
action: string;
|
|
6
|
+
}, fn: T): (...args: Parameters<T>) => Promise<ReturnType<T>>;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runWithCorrelationId = runWithCorrelationId;
|
|
4
|
+
exports.pushSubjectMapping = pushSubjectMapping;
|
|
5
|
+
exports.wrap = wrap;
|
|
6
|
+
const async_hooks_1 = require("async_hooks");
|
|
7
|
+
const ulid_1 = require("ulid");
|
|
8
|
+
const client_1 = require("./client");
|
|
9
|
+
const signing_1 = require("./signing");
|
|
10
|
+
const correlationStorage = new async_hooks_1.AsyncLocalStorage();
|
|
11
|
+
function runWithCorrelationId(id, fn) {
|
|
12
|
+
return correlationStorage.run(id, fn);
|
|
13
|
+
}
|
|
14
|
+
function pushSubjectMapping(sourceId, subjectType, subjectId) {
|
|
15
|
+
void sourceId;
|
|
16
|
+
void subjectType;
|
|
17
|
+
void subjectId;
|
|
18
|
+
}
|
|
19
|
+
function isoTimestamp(ms) {
|
|
20
|
+
return new Date(ms).toISOString();
|
|
21
|
+
}
|
|
22
|
+
function untrustedPayload(inputs, output, status) {
|
|
23
|
+
if (inputs.length > 0) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return status === 'ok' && output !== null && output !== undefined;
|
|
27
|
+
}
|
|
28
|
+
function toError(value) {
|
|
29
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
30
|
+
}
|
|
31
|
+
function logExecutionRecordFailure(recordError) {
|
|
32
|
+
const msg = recordError instanceof Error ? recordError.message : String(recordError);
|
|
33
|
+
console.warn(`[intentproof] execution record failed: ${msg}`);
|
|
34
|
+
}
|
|
35
|
+
/** Attach a recording failure without replacing an existing customer cause. */
|
|
36
|
+
function attachRecordingFailureCause(thrownError, recordError) {
|
|
37
|
+
const recording = toError(recordError);
|
|
38
|
+
const priorCause = thrownError.cause;
|
|
39
|
+
if (priorCause === undefined) {
|
|
40
|
+
thrownError.cause = recording;
|
|
41
|
+
return thrownError;
|
|
42
|
+
}
|
|
43
|
+
if (recording.cause === undefined) {
|
|
44
|
+
recording.cause = priorCause;
|
|
45
|
+
}
|
|
46
|
+
thrownError.cause = recording;
|
|
47
|
+
return thrownError;
|
|
48
|
+
}
|
|
49
|
+
function wrap(options, fn) {
|
|
50
|
+
return async function (...args) {
|
|
51
|
+
const t0 = Date.now();
|
|
52
|
+
const correlationId = correlationStorage.getStore() || 'req_' + (0, ulid_1.ulid)();
|
|
53
|
+
const eventId = (0, ulid_1.ulid)();
|
|
54
|
+
let result;
|
|
55
|
+
let status = 'ok';
|
|
56
|
+
let errorObj = null;
|
|
57
|
+
let thrownError;
|
|
58
|
+
let didThrow = false;
|
|
59
|
+
try {
|
|
60
|
+
result = await fn(...args);
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
didThrow = true;
|
|
64
|
+
status = 'error';
|
|
65
|
+
errorObj = { message: e?.message ?? String(e) };
|
|
66
|
+
thrownError = e;
|
|
67
|
+
}
|
|
68
|
+
const t1 = Date.now();
|
|
69
|
+
try {
|
|
70
|
+
const outbox = (0, client_1.getOutbox)();
|
|
71
|
+
let chainPos = 1;
|
|
72
|
+
let prevHash = signing_1.SENTINEL_PREV_HASH;
|
|
73
|
+
const state = outbox.getChainState(correlationId);
|
|
74
|
+
if (state) {
|
|
75
|
+
chainPos = state.position + 1;
|
|
76
|
+
prevHash = state.hash;
|
|
77
|
+
}
|
|
78
|
+
const event = {
|
|
79
|
+
schema: 'intentproof.event.v1',
|
|
80
|
+
event_id: eventId,
|
|
81
|
+
tenant_id: (0, client_1.getTenantId)(),
|
|
82
|
+
instance_id: (0, client_1.getInstanceId)(),
|
|
83
|
+
correlation_id: correlationId,
|
|
84
|
+
provenance_class: 'sdk_attested_evidence',
|
|
85
|
+
prev_event_hash: prevHash,
|
|
86
|
+
chain_position: chainPos,
|
|
87
|
+
intent: options.intent,
|
|
88
|
+
action: options.action,
|
|
89
|
+
status,
|
|
90
|
+
started_at: isoTimestamp(t0),
|
|
91
|
+
completed_at: isoTimestamp(t1),
|
|
92
|
+
duration_ms: t1 - t0,
|
|
93
|
+
inputs: args,
|
|
94
|
+
output: status === 'ok' ? result : null,
|
|
95
|
+
error: errorObj,
|
|
96
|
+
attributes: {},
|
|
97
|
+
untrusted_payload: untrustedPayload(args, result, status),
|
|
98
|
+
spec_version: '1.0.0',
|
|
99
|
+
sdk_version: client_1.SDK_VERSION,
|
|
100
|
+
};
|
|
101
|
+
const signed = await (0, signing_1.signEvent)(event, (0, client_1.getPrivateKey)(), (0, client_1.getInstanceId)());
|
|
102
|
+
const hash = (0, signing_1.eventContentHash)(signed);
|
|
103
|
+
outbox.append(eventId, signed);
|
|
104
|
+
outbox.setChainState(correlationId, chainPos, hash);
|
|
105
|
+
const exporter = (0, client_1.getExporter)();
|
|
106
|
+
if (exporter) {
|
|
107
|
+
exporter.enqueue(signed);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (recordError) {
|
|
111
|
+
if (didThrow) {
|
|
112
|
+
if (thrownError instanceof Error) {
|
|
113
|
+
throw attachRecordingFailureCause(thrownError, recordError);
|
|
114
|
+
}
|
|
115
|
+
if (thrownError !== undefined) {
|
|
116
|
+
const err = new Error(String(thrownError));
|
|
117
|
+
err.cause = recordError;
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
120
|
+
throw undefined;
|
|
121
|
+
}
|
|
122
|
+
logExecutionRecordFailure(recordError);
|
|
123
|
+
}
|
|
124
|
+
if (didThrow) {
|
|
125
|
+
throw thrownError;
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
};
|
|
129
|
+
}
|
package/dist/outbox.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class Outbox {
|
|
2
|
+
private db;
|
|
3
|
+
constructor(dbPath: string);
|
|
4
|
+
append(eventId: string, body: any): void;
|
|
5
|
+
getEvents(): any[];
|
|
6
|
+
getChainState(correlationId: string): {
|
|
7
|
+
position: number;
|
|
8
|
+
hash: string;
|
|
9
|
+
} | null;
|
|
10
|
+
setChainState(correlationId: string, position: number, hash: string): void;
|
|
11
|
+
}
|
package/dist/outbox.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Outbox = void 0;
|
|
7
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
8
|
+
class Outbox {
|
|
9
|
+
db;
|
|
10
|
+
constructor(dbPath) {
|
|
11
|
+
this.db = new better_sqlite3_1.default(dbPath);
|
|
12
|
+
this.db.pragma('journal_mode = WAL');
|
|
13
|
+
this.db.exec(`
|
|
14
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
15
|
+
event_id TEXT PRIMARY KEY,
|
|
16
|
+
body JSON NOT NULL
|
|
17
|
+
);
|
|
18
|
+
`);
|
|
19
|
+
this.db.exec(`
|
|
20
|
+
CREATE TABLE IF NOT EXISTS chains (
|
|
21
|
+
correlation_id TEXT PRIMARY KEY,
|
|
22
|
+
last_position INTEGER NOT NULL,
|
|
23
|
+
last_hash TEXT NOT NULL
|
|
24
|
+
);
|
|
25
|
+
`);
|
|
26
|
+
}
|
|
27
|
+
append(eventId, body) {
|
|
28
|
+
const stmt = this.db.prepare('INSERT INTO events (event_id, body) VALUES (?, ?)');
|
|
29
|
+
stmt.run(eventId, JSON.stringify(body));
|
|
30
|
+
}
|
|
31
|
+
getEvents() {
|
|
32
|
+
const stmt = this.db.prepare('SELECT body FROM events');
|
|
33
|
+
return stmt.all().map((r) => JSON.parse(r.body));
|
|
34
|
+
}
|
|
35
|
+
getChainState(correlationId) {
|
|
36
|
+
const stmt = this.db.prepare('SELECT last_position, last_hash FROM chains WHERE correlation_id = ?');
|
|
37
|
+
const row = stmt.get(correlationId);
|
|
38
|
+
if (!row)
|
|
39
|
+
return null;
|
|
40
|
+
return { position: row.last_position, hash: row.last_hash };
|
|
41
|
+
}
|
|
42
|
+
setChainState(correlationId, position, hash) {
|
|
43
|
+
const stmt = this.db.prepare(`
|
|
44
|
+
INSERT INTO chains (correlation_id, last_position, last_hash)
|
|
45
|
+
VALUES (?, ?, ?)
|
|
46
|
+
ON CONFLICT(correlation_id) DO UPDATE SET
|
|
47
|
+
last_position = excluded.last_position,
|
|
48
|
+
last_hash = excluded.last_hash
|
|
49
|
+
`);
|
|
50
|
+
stmt.run(correlationId, position, hash);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.Outbox = Outbox;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const SENTINEL_PREV_HASH = "sha256:0000000000000000000000000000000000000000000000000000000000000000";
|
|
2
|
+
export declare function canonicalizeEvent(event: Record<string, unknown>): string;
|
|
3
|
+
export declare function eventContentHash(event: Record<string, unknown>): string;
|
|
4
|
+
export declare function signEvent(event: Record<string, unknown>, privateKey: Uint8Array, instanceId: string): Promise<Record<string, unknown>>;
|
|
5
|
+
export declare function verifyEventSignature(event: Record<string, unknown>, publicKey: Uint8Array): Promise<boolean>;
|
|
6
|
+
export declare function loadPrivateKey(rawB64: string): Uint8Array;
|
package/dist/signing.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SENTINEL_PREV_HASH = void 0;
|
|
4
|
+
exports.canonicalizeEvent = canonicalizeEvent;
|
|
5
|
+
exports.eventContentHash = eventContentHash;
|
|
6
|
+
exports.signEvent = signEvent;
|
|
7
|
+
exports.verifyEventSignature = verifyEventSignature;
|
|
8
|
+
exports.loadPrivateKey = loadPrivateKey;
|
|
9
|
+
const ed25519_1 = require("@noble/ed25519");
|
|
10
|
+
const canon_1 = require("./canon");
|
|
11
|
+
exports.SENTINEL_PREV_HASH = 'sha256:0000000000000000000000000000000000000000000000000000000000000000';
|
|
12
|
+
function canonicalizeEvent(event) {
|
|
13
|
+
const unsigned = { ...event };
|
|
14
|
+
delete unsigned.signature;
|
|
15
|
+
return (0, canon_1.canonicalizeIntentProof)(unsigned);
|
|
16
|
+
}
|
|
17
|
+
function eventContentHash(event) {
|
|
18
|
+
const canonical = canonicalizeEvent(event);
|
|
19
|
+
const digest = require('crypto')
|
|
20
|
+
.createHash('sha256')
|
|
21
|
+
.update(canonical, 'utf8')
|
|
22
|
+
.digest('hex');
|
|
23
|
+
return `sha256:${digest}`;
|
|
24
|
+
}
|
|
25
|
+
async function signEvent(event, privateKey, instanceId) {
|
|
26
|
+
const canonical = canonicalizeEvent(event);
|
|
27
|
+
const digest = require('crypto').createHash('sha256').update(canonical, 'utf8').digest();
|
|
28
|
+
const signature = await (0, ed25519_1.signAsync)(new Uint8Array(digest), privateKey);
|
|
29
|
+
return {
|
|
30
|
+
...event,
|
|
31
|
+
signature: {
|
|
32
|
+
alg: 'ed25519',
|
|
33
|
+
key_id: `${instanceId}:k1`,
|
|
34
|
+
value: Buffer.from(signature).toString('base64'),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async function verifyEventSignature(event, publicKey) {
|
|
39
|
+
const sigBlock = event.signature;
|
|
40
|
+
if (!sigBlock?.value) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
const canonical = canonicalizeEvent(event);
|
|
44
|
+
const digest = require('crypto').createHash('sha256').update(canonical, 'utf8').digest();
|
|
45
|
+
try {
|
|
46
|
+
const sig = Buffer.from(sigBlock.value, 'base64');
|
|
47
|
+
return await (0, ed25519_1.verifyAsync)(sig, digest, publicKey);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function loadPrivateKey(rawB64) {
|
|
54
|
+
return new Uint8Array(Buffer.from(rawB64.trim(), 'base64'));
|
|
55
|
+
}
|
package/package.json
CHANGED
|
@@ -1,84 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentproof/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"license": "Apache-2.0",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "https://github.com/IntentProof/intentproof-sdk-node",
|
|
11
|
-
"directory": "packages/sdk"
|
|
12
|
-
},
|
|
13
|
-
"keywords": [
|
|
14
|
-
"IntentProof",
|
|
15
|
-
"intentproof",
|
|
16
|
-
"execution-events",
|
|
17
|
-
"telemetry",
|
|
18
|
-
"audit",
|
|
19
|
-
"typescript"
|
|
20
|
-
],
|
|
21
|
-
"type": "module",
|
|
22
|
-
"main": "./dist/index.cjs",
|
|
23
|
-
"module": "./dist/index.js",
|
|
24
|
-
"types": "./dist/index.d.ts",
|
|
25
|
-
"exports": {
|
|
26
|
-
".": {
|
|
27
|
-
"import": {
|
|
28
|
-
"types": "./dist/index.d.ts",
|
|
29
|
-
"default": "./dist/index.js"
|
|
30
|
-
},
|
|
31
|
-
"require": {
|
|
32
|
-
"types": "./dist/index.d.cts",
|
|
33
|
-
"default": "./dist/index.cjs"
|
|
34
|
-
},
|
|
35
|
-
"default": "./dist/index.js"
|
|
36
|
-
}
|
|
37
|
-
},
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Node.js SDK for signed IntentProof execution events",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
38
7
|
"files": [
|
|
39
8
|
"dist",
|
|
9
|
+
"README.md",
|
|
40
10
|
"LICENSE",
|
|
41
|
-
"
|
|
11
|
+
"NOTICE"
|
|
42
12
|
],
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
"ajv": "^8.17.1",
|
|
46
|
-
"ajv-formats": "^3.0.1"
|
|
13
|
+
"directories": {
|
|
14
|
+
"test": "tests"
|
|
47
15
|
},
|
|
48
16
|
"scripts": {
|
|
49
|
-
"build": "
|
|
50
|
-
"
|
|
51
|
-
"test": "
|
|
52
|
-
"test:coverage": "
|
|
53
|
-
"test:watch": "vitest",
|
|
54
|
-
"typecheck": "tsc --noEmit",
|
|
55
|
-
"lint": "eslint . --max-warnings 0",
|
|
56
|
-
"format": "prettier --write . ../../README.md",
|
|
57
|
-
"format:check": "prettier --check . ../../README.md",
|
|
58
|
-
"publint": "publint",
|
|
59
|
-
"sync-readme": "cp ../../README.md README.md",
|
|
60
|
-
"prepack": "npm run sync-readme",
|
|
61
|
-
"generate:types": "bash ../../scripts/generate-schema-types.sh",
|
|
62
|
-
"verify:types": "bash ../../scripts/verify-generated-types.sh",
|
|
63
|
-
"ci": "npm run sync-readme && bash ../../scripts/check-sdk-spec-pin.sh \"${INTENTPROOF_SPEC_ROOT:?}\" && bash ../../scripts/check-no-bundled-schema.sh && bash ../../scripts/check-no-handwritten-model-types.sh && npm run verify:types && npm run typecheck && npm run lint && npm run format:check && npm run test:coverage && npm run build && npm run publint"
|
|
17
|
+
"build": "tsc -p tsconfig.json",
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"test": "TS_NODE_PREFER_TS_EXTS=true node -r ts-node/register --test tests/*.test.ts",
|
|
20
|
+
"test:coverage": "npm run build && node --experimental-test-coverage --test-coverage-include='dist/**/*.js' --test-coverage-exclude='dist/index.js' --test-coverage-lines=95 --test-coverage-branches=95 --test-coverage-functions=95 -r ts-node/register -r ./tests/preload-dist.cjs --test tests/*.test.ts"
|
|
64
21
|
},
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"
|
|
76
|
-
"
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/IntentProof/intentproof-sdk-node.git"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"provenance": true,
|
|
29
|
+
"registry": "https://registry.npmjs.org"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"intentproof",
|
|
33
|
+
"provenance",
|
|
34
|
+
"sdk"
|
|
35
|
+
],
|
|
36
|
+
"author": "IntentProof",
|
|
37
|
+
"license": "Apache-2.0",
|
|
38
|
+
"type": "commonjs",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@noble/ed25519": "^3.1.0",
|
|
41
|
+
"better-sqlite3": "^12.0.0",
|
|
42
|
+
"json-canonicalize": "^2.0.0",
|
|
77
43
|
"typescript": "^6.0.3",
|
|
78
|
-
"
|
|
79
|
-
"vitest": "^4.1.5"
|
|
44
|
+
"ulid": "^3.0.2"
|
|
80
45
|
},
|
|
81
|
-
"
|
|
82
|
-
"
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
48
|
+
"@types/node": "^25.7.0",
|
|
49
|
+
"ajv": "^8.20.0",
|
|
50
|
+
"ajv-formats": "^3.0.1",
|
|
51
|
+
"ts-node": "^10.9.2"
|
|
83
52
|
}
|
|
84
53
|
}
|