@wytness/sdk 0.2.0 → 0.2.1

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/dist/index.cjs CHANGED
@@ -192,15 +192,19 @@ var AuditClient = class {
192
192
  this.agentVersion = options.agentVersion ?? "0.1.0";
193
193
  this.humanOperatorId = options.humanOperatorId ?? "unknown";
194
194
  this._sessionId = (0, import_crypto3.randomUUID)();
195
- const keyPath = options.signingKeyPath ?? "./keys/signing.key";
196
- if ((0, import_fs2.existsSync)(keyPath)) {
197
- const raw = (0, import_fs2.readFileSync)(keyPath);
198
- this._secretKey = new Uint8Array(raw);
195
+ if (options.signingKey) {
196
+ this._secretKey = new Uint8Array(Buffer.from(options.signingKey, "base64"));
199
197
  } else {
200
- const kp = generateKeypair();
201
- this._secretKey = kp.secretKey;
202
- (0, import_fs2.mkdirSync)((0, import_path2.dirname)(keyPath), { recursive: true });
203
- (0, import_fs2.writeFileSync)(keyPath, Buffer.from(kp.secretKey));
198
+ const keyPath = options.signingKeyPath ?? "./keys/signing.key";
199
+ if ((0, import_fs2.existsSync)(keyPath)) {
200
+ const raw = (0, import_fs2.readFileSync)(keyPath);
201
+ this._secretKey = new Uint8Array(raw);
202
+ } else {
203
+ const kp = generateKeypair();
204
+ this._secretKey = kp.secretKey;
205
+ (0, import_fs2.mkdirSync)((0, import_path2.dirname)(keyPath), { recursive: true });
206
+ (0, import_fs2.writeFileSync)(keyPath, Buffer.from(kp.secretKey));
207
+ }
204
208
  }
205
209
  const fallback = options.fallbackLogPath ?? "./audit_fallback.jsonl";
206
210
  if (options.httpApiKey) {
@@ -216,12 +220,17 @@ var AuditClient = class {
216
220
  get sessionId() {
217
221
  return this._sessionId;
218
222
  }
223
+ /** Record an audit event. Never throws — errors are logged and swallowed. */
219
224
  record(event) {
220
- const d = { ...event };
221
- d["prev_event_hash"] = this._prevEventHash;
222
- d["signature"] = signEvent(d, this._secretKey);
223
- this._prevEventHash = computeEventHash(d);
224
- this._emit(d);
225
+ try {
226
+ const d = { ...event };
227
+ d["prev_event_hash"] = this._prevEventHash;
228
+ d["signature"] = signEvent(d, this._secretKey);
229
+ this._prevEventHash = computeEventHash(d);
230
+ this._emit(d);
231
+ } catch (e) {
232
+ console.error(`wytness: failed to record event: ${e}`);
233
+ }
225
234
  }
226
235
  };
227
236
 
@@ -238,41 +247,47 @@ function sanitise(params) {
238
247
  function hashValue(value) {
239
248
  return (0, import_crypto4.createHash)("sha256").update(JSON.stringify(value, null, 0)).digest("hex");
240
249
  }
250
+ function recordEvent(client, toolName, taskId, args, start, status, errorCode, result) {
251
+ const params = {};
252
+ args.forEach((arg, i) => {
253
+ params[`arg${i}`] = arg;
254
+ });
255
+ const event = AuditEventSchema.parse({
256
+ agent_id: client.agentId,
257
+ agent_version: client.agentVersion,
258
+ human_operator_id: client.humanOperatorId,
259
+ task_id: taskId,
260
+ session_id: client.sessionId,
261
+ tool_name: toolName,
262
+ tool_parameters: sanitise(params),
263
+ inputs_hash: hashValue(args),
264
+ outputs_hash: result != null ? hashValue(result) : "",
265
+ status,
266
+ error_code: errorCode,
267
+ duration_ms: Math.round(performance.now() - start)
268
+ });
269
+ client.record(event);
270
+ }
241
271
  function wrapFn(client, fn, toolName, taskId) {
242
272
  const wrapped = function(...args) {
243
273
  const start = performance.now();
244
- let status = "success";
245
- let errorCode = null;
246
274
  let result;
247
- const inputsHash = hashValue(args);
248
275
  try {
249
276
  result = fn.apply(this, args);
250
277
  } catch (e) {
251
- status = "failure";
252
- errorCode = e.constructor.name;
278
+ recordEvent(client, toolName, taskId, args, start, "failure", e.constructor.name, null);
253
279
  throw e;
254
- } finally {
255
- const durationMs = Math.round(performance.now() - start);
256
- const params = {};
257
- args.forEach((arg, i) => {
258
- params[`arg${i}`] = arg;
259
- });
260
- const event = AuditEventSchema.parse({
261
- agent_id: client.agentId,
262
- agent_version: client.agentVersion,
263
- human_operator_id: client.humanOperatorId,
264
- task_id: taskId,
265
- session_id: client.sessionId,
266
- tool_name: toolName,
267
- tool_parameters: sanitise(params),
268
- inputs_hash: inputsHash,
269
- outputs_hash: result != null ? hashValue(result) : "",
270
- status,
271
- error_code: errorCode,
272
- duration_ms: durationMs
280
+ }
281
+ if (result && typeof result.then === "function") {
282
+ return result.then((resolved) => {
283
+ recordEvent(client, toolName, taskId, args, start, "success", null, resolved);
284
+ return resolved;
285
+ }).catch((e) => {
286
+ recordEvent(client, toolName, taskId, args, start, "failure", e.constructor.name, null);
287
+ throw e;
273
288
  });
274
- client.record(event);
275
289
  }
290
+ recordEvent(client, toolName, taskId, args, start, "success", null, result);
276
291
  return result;
277
292
  };
278
293
  Object.defineProperty(wrapped, "name", { value: toolName });
package/dist/index.d.cts CHANGED
@@ -104,6 +104,7 @@ interface AuditClientOptions {
104
104
  agentId: string;
105
105
  agentVersion?: string;
106
106
  humanOperatorId?: string;
107
+ signingKey?: string;
107
108
  signingKeyPath?: string;
108
109
  fallbackLogPath?: string;
109
110
  httpApiKey?: string;
@@ -119,6 +120,7 @@ declare class AuditClient {
119
120
  private _emit;
120
121
  constructor(options: AuditClientOptions);
121
122
  get sessionId(): string;
123
+ /** Record an audit event. Never throws — errors are logged and swallowed. */
122
124
  record(event: AuditEvent): void;
123
125
  }
124
126
 
@@ -127,7 +129,7 @@ interface AuditToolOptions {
127
129
  taskId?: string;
128
130
  }
129
131
  /**
130
- * Wrap a function with audit logging.
132
+ * Wrap a function with audit logging. Works with both sync and async functions.
131
133
  *
132
134
  * Supports two calling styles:
133
135
  *
package/dist/index.d.ts CHANGED
@@ -104,6 +104,7 @@ interface AuditClientOptions {
104
104
  agentId: string;
105
105
  agentVersion?: string;
106
106
  humanOperatorId?: string;
107
+ signingKey?: string;
107
108
  signingKeyPath?: string;
108
109
  fallbackLogPath?: string;
109
110
  httpApiKey?: string;
@@ -119,6 +120,7 @@ declare class AuditClient {
119
120
  private _emit;
120
121
  constructor(options: AuditClientOptions);
121
122
  get sessionId(): string;
123
+ /** Record an audit event. Never throws — errors are logged and swallowed. */
122
124
  record(event: AuditEvent): void;
123
125
  }
124
126
 
@@ -127,7 +129,7 @@ interface AuditToolOptions {
127
129
  taskId?: string;
128
130
  }
129
131
  /**
130
- * Wrap a function with audit logging.
132
+ * Wrap a function with audit logging. Works with both sync and async functions.
131
133
  *
132
134
  * Supports two calling styles:
133
135
  *
package/dist/index.js CHANGED
@@ -147,15 +147,19 @@ var AuditClient = class {
147
147
  this.agentVersion = options.agentVersion ?? "0.1.0";
148
148
  this.humanOperatorId = options.humanOperatorId ?? "unknown";
149
149
  this._sessionId = randomUUID2();
150
- const keyPath = options.signingKeyPath ?? "./keys/signing.key";
151
- if (existsSync(keyPath)) {
152
- const raw = readFileSync(keyPath);
153
- this._secretKey = new Uint8Array(raw);
150
+ if (options.signingKey) {
151
+ this._secretKey = new Uint8Array(Buffer.from(options.signingKey, "base64"));
154
152
  } else {
155
- const kp = generateKeypair();
156
- this._secretKey = kp.secretKey;
157
- mkdirSync2(dirname2(keyPath), { recursive: true });
158
- writeFileSync(keyPath, Buffer.from(kp.secretKey));
153
+ const keyPath = options.signingKeyPath ?? "./keys/signing.key";
154
+ if (existsSync(keyPath)) {
155
+ const raw = readFileSync(keyPath);
156
+ this._secretKey = new Uint8Array(raw);
157
+ } else {
158
+ const kp = generateKeypair();
159
+ this._secretKey = kp.secretKey;
160
+ mkdirSync2(dirname2(keyPath), { recursive: true });
161
+ writeFileSync(keyPath, Buffer.from(kp.secretKey));
162
+ }
159
163
  }
160
164
  const fallback = options.fallbackLogPath ?? "./audit_fallback.jsonl";
161
165
  if (options.httpApiKey) {
@@ -171,12 +175,17 @@ var AuditClient = class {
171
175
  get sessionId() {
172
176
  return this._sessionId;
173
177
  }
178
+ /** Record an audit event. Never throws — errors are logged and swallowed. */
174
179
  record(event) {
175
- const d = { ...event };
176
- d["prev_event_hash"] = this._prevEventHash;
177
- d["signature"] = signEvent(d, this._secretKey);
178
- this._prevEventHash = computeEventHash(d);
179
- this._emit(d);
180
+ try {
181
+ const d = { ...event };
182
+ d["prev_event_hash"] = this._prevEventHash;
183
+ d["signature"] = signEvent(d, this._secretKey);
184
+ this._prevEventHash = computeEventHash(d);
185
+ this._emit(d);
186
+ } catch (e) {
187
+ console.error(`wytness: failed to record event: ${e}`);
188
+ }
180
189
  }
181
190
  };
182
191
 
@@ -193,41 +202,47 @@ function sanitise(params) {
193
202
  function hashValue(value) {
194
203
  return createHash2("sha256").update(JSON.stringify(value, null, 0)).digest("hex");
195
204
  }
205
+ function recordEvent(client, toolName, taskId, args, start, status, errorCode, result) {
206
+ const params = {};
207
+ args.forEach((arg, i) => {
208
+ params[`arg${i}`] = arg;
209
+ });
210
+ const event = AuditEventSchema.parse({
211
+ agent_id: client.agentId,
212
+ agent_version: client.agentVersion,
213
+ human_operator_id: client.humanOperatorId,
214
+ task_id: taskId,
215
+ session_id: client.sessionId,
216
+ tool_name: toolName,
217
+ tool_parameters: sanitise(params),
218
+ inputs_hash: hashValue(args),
219
+ outputs_hash: result != null ? hashValue(result) : "",
220
+ status,
221
+ error_code: errorCode,
222
+ duration_ms: Math.round(performance.now() - start)
223
+ });
224
+ client.record(event);
225
+ }
196
226
  function wrapFn(client, fn, toolName, taskId) {
197
227
  const wrapped = function(...args) {
198
228
  const start = performance.now();
199
- let status = "success";
200
- let errorCode = null;
201
229
  let result;
202
- const inputsHash = hashValue(args);
203
230
  try {
204
231
  result = fn.apply(this, args);
205
232
  } catch (e) {
206
- status = "failure";
207
- errorCode = e.constructor.name;
233
+ recordEvent(client, toolName, taskId, args, start, "failure", e.constructor.name, null);
208
234
  throw e;
209
- } finally {
210
- const durationMs = Math.round(performance.now() - start);
211
- const params = {};
212
- args.forEach((arg, i) => {
213
- params[`arg${i}`] = arg;
214
- });
215
- const event = AuditEventSchema.parse({
216
- agent_id: client.agentId,
217
- agent_version: client.agentVersion,
218
- human_operator_id: client.humanOperatorId,
219
- task_id: taskId,
220
- session_id: client.sessionId,
221
- tool_name: toolName,
222
- tool_parameters: sanitise(params),
223
- inputs_hash: inputsHash,
224
- outputs_hash: result != null ? hashValue(result) : "",
225
- status,
226
- error_code: errorCode,
227
- duration_ms: durationMs
235
+ }
236
+ if (result && typeof result.then === "function") {
237
+ return result.then((resolved) => {
238
+ recordEvent(client, toolName, taskId, args, start, "success", null, resolved);
239
+ return resolved;
240
+ }).catch((e) => {
241
+ recordEvent(client, toolName, taskId, args, start, "failure", e.constructor.name, null);
242
+ throw e;
228
243
  });
229
- client.record(event);
230
244
  }
245
+ recordEvent(client, toolName, taskId, args, start, "success", null, result);
231
246
  return result;
232
247
  };
233
248
  Object.defineProperty(wrapped, "name", { value: toolName });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wytness/sdk",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "TypeScript SDK for Wytness — audit logging for AI agents with cryptographic signing and chain integrity",
5
5
  "license": "MIT",
6
6
  "author": "Wytness <hello@wytness.dev>",