@dvmkit/sdk 0.5.0-rc.1 → 0.6.0-rc.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.
Files changed (32) hide show
  1. package/README.md +100 -0
  2. package/dist/chunk-AFV77S4C.js +258 -0
  3. package/dist/chunk-BQJIFRAZ.js +36 -0
  4. package/dist/{chunk-PB4FYZET.js → chunk-EQLA4FFY.js} +54 -4
  5. package/dist/{chunk-TZ2WKCDD.js → chunk-HCLVYZUZ.js} +2 -2
  6. package/dist/{chunk-EYTHFFFU.js → chunk-HHBDBMEO.js} +159 -34
  7. package/dist/{chunk-O5AT6S5T.js → chunk-IV6Q7NRW.js} +25 -195
  8. package/dist/{chunk-Z4KLECAC.js → chunk-N5RZ5HVB.js} +1 -1
  9. package/dist/{chunk-TUA7PYH7.js → chunk-OQA7IHI4.js} +124 -124
  10. package/dist/{chunk-6DOGTAHA.js → chunk-QR2EF2NI.js} +9 -43
  11. package/dist/{chunk-A4YFWZ7R.js → chunk-RCM3P2HE.js} +1 -1
  12. package/dist/content-retention-BTGSQRfP.d.ts +78 -0
  13. package/dist/{credit-menu-CAfqe8IY.d.ts → credit-menu-BAsrRu3z.d.ts} +98 -5
  14. package/dist/{fx-D9nsN3n4.d.ts → fx-BgDmyTdd.d.ts} +1 -1
  15. package/dist/index.d.ts +5 -5
  16. package/dist/index.js +3 -3
  17. package/dist/internal/caller.d.ts +16 -15
  18. package/dist/internal/caller.js +7 -5
  19. package/dist/internal/server.d.ts +8 -99
  20. package/dist/internal/server.js +12 -9
  21. package/dist/{job-store-Bx-VFRjg.d.ts → job-store-BVeF5_Jq.d.ts} +1 -1
  22. package/dist/{lightning-backend-BAx2Y8pP.d.ts → lightning-backend-40fIzz1W.d.ts} +1 -1
  23. package/dist/{postgres-consumed-credential-store-CUQJKRSL.js → postgres-consumed-credential-store-BUVCAPLS.js} +13 -0
  24. package/dist/{postgres-job-store-VLXLWXUQ.js → postgres-job-store-VHLQBJZC.js} +3 -1
  25. package/dist/server/index.d.ts +28 -10
  26. package/dist/server/index.js +22 -9
  27. package/dist/{step-cache-QG_h5-3G.d.ts → step-cache-CPdH1hei.d.ts} +2 -2
  28. package/dist/testing/index.d.ts +9 -2
  29. package/dist/testing/index.js +6 -3
  30. package/dist/{usd-EwRqCPF-.d.ts → usd-AWlrwlM5.d.ts} +1 -1
  31. package/package.json +3 -2
  32. package/recipes/postgres/financial-export-v1.sql +137 -0
@@ -1,191 +1,15 @@
1
1
  import {
2
- StepCache,
2
+ ContentHoldError,
3
+ applyContentHoldMutation,
4
+ isTerminal
5
+ } from "./chunk-AFV77S4C.js";
6
+ import {
3
7
  loggers
4
- } from "./chunk-6DOGTAHA.js";
8
+ } from "./chunk-QR2EF2NI.js";
5
9
  import {
6
10
  redactUrl
7
11
  } from "./chunk-FUJ36YDV.js";
8
12
 
9
- // src/sdk/server/job.ts
10
- function toJobRecord(job) {
11
- return {
12
- id: job.id,
13
- tags: job.tags,
14
- capability: job.capability,
15
- input: job.input,
16
- params: job.params,
17
- requesterId: job.requesterId,
18
- requesterTokenHash: job.requesterTokenHash,
19
- requesterToken: job.requesterToken,
20
- requestFingerprint: job.requestFingerprint,
21
- requesterPubkey: job.requesterPubkey,
22
- requestId: job.requestId,
23
- authRequestPath: job.authRequestPath,
24
- status: job.status,
25
- summary: job.summary,
26
- timingKnown: job.timingKnown,
27
- endedBy: job.endedBy,
28
- terminalAtMs: job.terminalAtMs,
29
- callerWaitMs: job.callerWaitMs,
30
- awaitingInputAtMs: job.awaitingInputAtMs,
31
- messages: job.messages,
32
- seq: job.seq,
33
- paidMsats: job.paidMsats,
34
- paymentMint: job.paymentMint,
35
- paymentRail: job.paymentRail,
36
- paymentTxHash: job.paymentTxHash,
37
- paymentTransactionHash: job.paymentTransactionHash,
38
- nativeAmount: job.nativeAmount,
39
- nativeAsset: job.nativeAsset,
40
- cashuFlow: job.cashuFlow,
41
- costAmountMicro: job.costAmountMicro,
42
- costCurrency: job.costCurrency,
43
- costRevision: job.costRevision,
44
- creditId: job.creditId,
45
- drawId: job.drawId,
46
- fundingReceipt: job.fundingReceipt,
47
- fundingCredit: job.fundingCredit,
48
- receivedProofs: job.receivedProofs,
49
- pendingPaymentMsats: job.pendingPaymentMsats,
50
- pendingMppChallengeIds: job.pendingMppChallengeIds,
51
- pendingX402Nonce: job.pendingX402Nonce,
52
- pendingX402AmountUsdcMicro: job.pendingX402AmountUsdcMicro,
53
- pendingPaymentFiatMicro: job.pendingPaymentFiatMicro,
54
- pendingPaymentFiatCurrency: job.pendingPaymentFiatCurrency,
55
- askedTopUpMicro: job.askedTopUpMicro,
56
- askedTopUpCurrency: job.askedTopUpCurrency,
57
- topUpCapUnenforcedReason: job.topUpCapUnenforcedReason,
58
- requiredMsats: job.requiredMsats,
59
- receipt: job.receipt,
60
- stepCache: job.stepCache.serialize(),
61
- state: job.state,
62
- createdAt: job.createdAt,
63
- lastActivityAt: job.lastActivityAt
64
- };
65
- }
66
- function fromJobRecord(record) {
67
- return {
68
- id: record.id,
69
- tags: record.tags,
70
- capability: record.capability,
71
- input: record.input,
72
- params: record.params,
73
- requesterId: record.requesterId,
74
- requesterTokenHash: record.requesterTokenHash,
75
- status: record.status,
76
- summary: record.summary,
77
- timingKnown: record.timingKnown,
78
- endedBy: record.endedBy,
79
- terminalAtMs: record.terminalAtMs,
80
- callerWaitMs: record.callerWaitMs,
81
- awaitingInputAtMs: record.awaitingInputAtMs,
82
- messages: [...record.messages],
83
- seq: record.seq,
84
- paidMsats: record.paidMsats,
85
- paymentMint: record.paymentMint,
86
- paymentRail: record.paymentRail,
87
- paymentTxHash: record.paymentTxHash,
88
- paymentTransactionHash: record.paymentTransactionHash,
89
- nativeAmount: record.nativeAmount,
90
- nativeAsset: record.nativeAsset,
91
- cashuFlow: record.cashuFlow,
92
- costAmountMicro: record.costAmountMicro,
93
- costCurrency: record.costCurrency,
94
- costRevision: record.costRevision,
95
- creditId: record.creditId,
96
- drawId: record.drawId,
97
- fundingReceipt: record.fundingReceipt,
98
- fundingCredit: record.fundingCredit,
99
- receivedProofs: [...record.receivedProofs],
100
- pendingPaymentMsats: record.pendingPaymentMsats,
101
- pendingMppChallengeIds: record.pendingMppChallengeIds ? [...record.pendingMppChallengeIds] : void 0,
102
- requesterToken: record.requesterToken,
103
- requestFingerprint: record.requestFingerprint,
104
- requesterPubkey: record.requesterPubkey,
105
- requestId: record.requestId,
106
- authRequestPath: record.authRequestPath,
107
- pendingX402Nonce: record.pendingX402Nonce,
108
- pendingX402AmountUsdcMicro: record.pendingX402AmountUsdcMicro,
109
- pendingPaymentFiatMicro: record.pendingPaymentFiatMicro,
110
- pendingPaymentFiatCurrency: record.pendingPaymentFiatCurrency,
111
- askedTopUpMicro: record.askedTopUpMicro,
112
- askedTopUpCurrency: record.askedTopUpCurrency,
113
- topUpCapUnenforcedReason: record.topUpCapUnenforcedReason,
114
- requiredMsats: record.requiredMsats,
115
- receipt: record.receipt,
116
- listeners: /* @__PURE__ */ new Set(),
117
- abort: new AbortController(),
118
- messageAppender: void 0,
119
- messageAppenderTail: void 0,
120
- stepCache: StepCache.deserialize(record.stepCache),
121
- state: record.state,
122
- pendingPrompts: /* @__PURE__ */ new Map(),
123
- pendingPayment: null,
124
- replayHighSeq: null,
125
- replayProviderSkip: 0,
126
- replayPaymentIndex: 0,
127
- createdAt: record.createdAt,
128
- lastActivityAt: record.lastActivityAt
129
- };
130
- }
131
- function abortJob(job, reason) {
132
- job.abort.abort(new JobCancelledError(reason));
133
- }
134
- var JobCancelledError = class extends Error {
135
- constructor(message = "Job cancelled") {
136
- super(message);
137
- this.name = "JobCancelledError";
138
- }
139
- };
140
- function providerMessage(job, type, content) {
141
- if (job.replayProviderSkip > 0) {
142
- job.replayProviderSkip--;
143
- return;
144
- }
145
- const msg = localMessage(job, "provider", type, content);
146
- if (type === "payment-request") {
147
- const paymentRequest = content;
148
- const pendingPaymentDelta = typeof paymentRequest.amount_msats === "number" ? paymentRequest.amount_msats : void 0;
149
- const pendingMppChallengeIds = paymentRequest.tempo?.challenges?.map((challenge) => challenge.id).filter((id) => typeof id === "string");
150
- job.messageAppender?.(msg, {
151
- awaitingInput: job.status === "awaiting-input",
152
- pendingPaymentDelta,
153
- pendingMppChallengeIds,
154
- pendingX402Nonce: typeof paymentRequest.x402?.nonce === "string" ? paymentRequest.x402.nonce : void 0,
155
- pendingX402AmountUsdcMicro: typeof paymentRequest.x402?.required_usdc_micro === "string" ? paymentRequest.x402.required_usdc_micro : void 0,
156
- // read off the job rather than the content — the fiat envelope
157
- // is ledger state, not part of the wire shape, and `requestPayment` has
158
- // already pinned it on the job by the time this fires (same ordering the
159
- // `pendingPaymentMsats` comment above describes).
160
- pendingPaymentFiatMicro: job.pendingPaymentFiatMicro,
161
- pendingPaymentFiatCurrency: job.pendingPaymentFiatCurrency
162
- });
163
- return;
164
- }
165
- job.messageAppender?.(msg, type === "prompt" ? { awaitingInput: job.status === "awaiting-input" } : void 0);
166
- }
167
- function localMessage(job, from, type, content) {
168
- job.seq++;
169
- const msg = {
170
- seq: job.seq,
171
- from,
172
- timestamp: Math.floor(Date.now() / 1e3),
173
- type,
174
- content
175
- };
176
- job.messages.push(msg);
177
- for (const listener of job.listeners) {
178
- listener(msg);
179
- }
180
- return msg;
181
- }
182
- function isTerminal(status) {
183
- return status === "completed" || status === "failed" || status === "cancelled";
184
- }
185
- function isYieldMessage(msg) {
186
- return msg.type === "prompt" || msg.type === "payment-request" || msg.type === "working" || msg.type === "complete" || msg.type === "cancel";
187
- }
188
-
189
13
  // src/sdk/server/job-store.ts
190
14
  function accumulateAskedTopUp(prior, ask) {
191
15
  const poisoned = (reason) => ({
@@ -219,6 +43,7 @@ function isStaleJobReapable(store) {
219
43
 
220
44
  // src/sdk/server/memory-job-store.ts
221
45
  var MemoryJobStore = class {
46
+ contentHolds = /* @__PURE__ */ new Map();
222
47
  data = /* @__PURE__ */ new Map();
223
48
  messages = /* @__PURE__ */ new Map();
224
49
  nextSeq = /* @__PURE__ */ new Map();
@@ -290,6 +115,7 @@ var MemoryJobStore = class {
290
115
  }
291
116
  const snapshot = structuredClone(record);
292
117
  if (existing) snapshot.createdAt = existing.createdAt;
118
+ if (existing && isTerminal(existing.status)) snapshot.lastActivityAt = existing.lastActivityAt;
293
119
  if (existing?.receipt) snapshot.receipt = existing.receipt;
294
120
  snapshot.timingKnown = existing ? existing.timingKnown ?? false : record.timingKnown ?? true;
295
121
  applyTiming(snapshot, existing, Date.now());
@@ -302,6 +128,7 @@ var MemoryJobStore = class {
302
128
  return Promise.resolve();
303
129
  }
304
130
  delete(id) {
131
+ this.contentHolds.delete(id);
305
132
  this.data.delete(id);
306
133
  this.messages.delete(id);
307
134
  this.nextSeq.delete(id);
@@ -317,7 +144,7 @@ var MemoryJobStore = class {
317
144
  }
318
145
  redactJob(args) {
319
146
  const record = this.data.get(args.jobId);
320
- if (!record || record.redactedAt !== void 0 || !isTerminal(record.status) || record.lastActivityAt !== args.expectedLastActivityAt) {
147
+ if (!record || record.redactedAt !== void 0 || !isTerminal(record.status) || this.contentHolds.get(args.jobId)?.holds.some((hold) => hold.cleared_at === null) || record.lastActivityAt !== args.expectedLastActivityAt) {
321
148
  return Promise.resolve(false);
322
149
  }
323
150
  record.input = "";
@@ -340,6 +167,17 @@ var MemoryJobStore = class {
340
167
  this.messages.delete(args.jobId);
341
168
  return Promise.resolve(true);
342
169
  }
170
+ getContentSnapshot(jobId) {
171
+ const job = this.data.get(jobId);
172
+ return Promise.resolve(job ? structuredClone({ job, history: this.contentHolds.get(jobId) ?? { holds: [], events: [] } }) : void 0);
173
+ }
174
+ mutateContentHold(jobId, mutation) {
175
+ const job = this.data.get(jobId);
176
+ if (!job) return Promise.reject(new ContentHoldError("job_not_found"));
177
+ const history = applyContentHoldMutation(job, this.contentHolds.get(jobId) ?? { holds: [], events: [] }, mutation);
178
+ this.contentHolds.set(jobId, history);
179
+ return Promise.resolve(structuredClone(history));
180
+ }
343
181
  claimReceiptSeq(jobId) {
344
182
  if (!this.data.has(jobId)) {
345
183
  return Promise.reject(new Error(`claimReceiptSeq: job ${jobId} not found`));
@@ -394,7 +232,7 @@ var MemoryJobStore = class {
394
232
  record.askedTopUpCurrency = asked.currency;
395
233
  record.topUpCapUnenforcedReason = asked.reason;
396
234
  }
397
- record.lastActivityAt = Date.now();
235
+ if (!isTerminal(record.status)) record.lastActivityAt = Date.now();
398
236
  if (seq > record.seq) record.seq = seq;
399
237
  this.notify(jobId, fullMessage);
400
238
  return Promise.resolve(seq);
@@ -407,7 +245,7 @@ var MemoryJobStore = class {
407
245
  const seq = this.allocateSeq(jobId);
408
246
  const fullMessage = { ...message, seq };
409
247
  this.messagesFor(jobId).push({ message: fullMessage, status: "pending-verification" });
410
- record.lastActivityAt = Date.now();
248
+ if (!isTerminal(record.status)) record.lastActivityAt = Date.now();
411
249
  if (seq > record.seq) record.seq = seq;
412
250
  this.fireNotifyOnly(jobId);
413
251
  return Promise.resolve(seq);
@@ -456,7 +294,7 @@ var MemoryJobStore = class {
456
294
  record.pendingX402AmountUsdcMicro = void 0;
457
295
  }
458
296
  }
459
- record.lastActivityAt = Date.now();
297
+ if (!isTerminal(record.status)) record.lastActivityAt = Date.now();
460
298
  this.notify(jobId, stored.message);
461
299
  return Promise.resolve({
462
300
  counters: snapshotCounters(record),
@@ -521,7 +359,7 @@ var MemoryJobStore = class {
521
359
  if (record?.status !== "awaiting-input") return Promise.resolve(false);
522
360
  applyTiming(record, structuredClone(record), Date.now(), "processing");
523
361
  record.status = "processing";
524
- record.lastActivityAt = Date.now();
362
+ if (!isTerminal(record.status)) record.lastActivityAt = Date.now();
525
363
  return Promise.resolve(true);
526
364
  }
527
365
  async tryReactivationLock(jobId, fn) {
@@ -704,14 +542,6 @@ function mergeSignals(a, b) {
704
542
  }
705
543
 
706
544
  export {
707
- toJobRecord,
708
- fromJobRecord,
709
- abortJob,
710
- JobCancelledError,
711
- providerMessage,
712
- localMessage,
713
- isTerminal,
714
- isYieldMessage,
715
545
  accumulateAskedTopUp,
716
546
  UNCAPPABLE_ASK_TOTAL,
717
547
  isJobRetentionStore,
@@ -4,7 +4,7 @@ import {
4
4
  signedRequestHeaderMatchesDomain,
5
5
  signedRequestStatementHeader,
6
6
  testOnlySignedRequestDomain
7
- } from "./chunk-A4YFWZ7R.js";
7
+ } from "./chunk-RCM3P2HE.js";
8
8
  import {
9
9
  diagnosticConsole
10
10
  } from "./chunk-ETXDTUJO.js";
@@ -953,6 +953,112 @@ function generateEphemeralReceiptKey() {
953
953
  return { secret: bytesToHex(secretKey), pubkey: bytesToHex(publicKey) };
954
954
  }
955
955
 
956
+ // src/lib/wallet-agent/keypair.ts
957
+ import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1.js";
958
+ var PRIVKEY_HEX_RE = /^[0-9a-f]{64}$/i;
959
+ function derivePubkeyFromPrivkey(privkey) {
960
+ if (!PRIVKEY_HEX_RE.test(privkey)) {
961
+ throw new DvmError(
962
+ "invalid_privkey",
963
+ "Privkey must be 64 hex characters (32 bytes).",
964
+ "Provide a valid secp256k1 private key as a 64-char hex string."
965
+ );
966
+ }
967
+ const bytes = hexToBytes2(privkey);
968
+ if (!secp256k12.utils.isValidSecretKey(bytes)) {
969
+ throw new DvmError(
970
+ "invalid_privkey",
971
+ "Privkey is not a valid secp256k1 scalar (zero or out of curve order).",
972
+ "Generate a fresh key with: dvm wallet init"
973
+ );
974
+ }
975
+ const pub = secp256k12.getPublicKey(bytes);
976
+ return bytesToHex2(pub);
977
+ }
978
+ function bytesToHex2(bytes) {
979
+ return Buffer.from(bytes).toString("hex");
980
+ }
981
+ function hexToBytes2(hex) {
982
+ return Uint8Array.from(Buffer.from(hex, "hex"));
983
+ }
984
+
985
+ // src/lib/wallet-agent/sign.ts
986
+ import { schnorr as schnorr2 } from "@noble/curves/secp256k1.js";
987
+ var PUBKEY_COMPRESSED_HEX_RE = /^0[23][0-9a-f]{64}$/i;
988
+ var PUBKEY_XONLY_HEX_RE = /^[0-9a-f]{64}$/i;
989
+ var SIG_HEX_RE = /^[0-9a-f]{128}$/i;
990
+ function signChallenge(privkeyHex, challenge) {
991
+ if (!PRIVKEY_HEX_RE.test(privkeyHex)) {
992
+ throw new DvmError(
993
+ "invalid_privkey",
994
+ "Privkey must be 64 hex characters (32 bytes).",
995
+ "Provide a valid secp256k1 private key as a 64-char hex string."
996
+ );
997
+ }
998
+ if (challenge.length !== 32) {
999
+ throw new DvmError(
1000
+ "invalid_challenge",
1001
+ `Challenge must be exactly 32 bytes; got ${challenge.length}.`,
1002
+ "Pass the SHA-256 digest output (32 bytes)."
1003
+ );
1004
+ }
1005
+ const sig = schnorr2.sign(challenge, hexToBytes3(privkeyHex));
1006
+ return bytesToHex3(sig);
1007
+ }
1008
+ function verifyChallenge(pubkeyHex, challenge, sigHex) {
1009
+ if (!SIG_HEX_RE.test(sigHex)) return false;
1010
+ if (challenge.length !== 32) return false;
1011
+ let xonly;
1012
+ if (PUBKEY_COMPRESSED_HEX_RE.test(pubkeyHex)) {
1013
+ xonly = hexToBytes3(pubkeyHex.slice(2));
1014
+ } else if (PUBKEY_XONLY_HEX_RE.test(pubkeyHex)) {
1015
+ xonly = hexToBytes3(pubkeyHex);
1016
+ } else {
1017
+ return false;
1018
+ }
1019
+ try {
1020
+ return schnorr2.verify(hexToBytes3(sigHex), challenge, xonly);
1021
+ } catch {
1022
+ return false;
1023
+ }
1024
+ }
1025
+ function hexToBytes3(hex) {
1026
+ return Uint8Array.from(Buffer.from(hex, "hex"));
1027
+ }
1028
+ function bytesToHex3(bytes) {
1029
+ return Buffer.from(bytes).toString("hex");
1030
+ }
1031
+
1032
+ // src/lib/cashu/admin-auth.ts
1033
+ import { randomBytes } from "crypto";
1034
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
1035
+ var ADMIN_AUTH_NONCE_TTL_SECONDS = 300;
1036
+ var ADMIN_AUTH_CLOCK_SKEW_SECONDS = 30;
1037
+ var ADMIN_STATE_UNAVAILABLE = "admin_state_unavailable";
1038
+ function buildAdminChallenge(args) {
1039
+ const msg = `dvmkit-admin:${args.method}:${args.path}:${args.dvmId}:${args.nonceHex}:${args.unixSeconds}`;
1040
+ return sha2562(new TextEncoder().encode(msg));
1041
+ }
1042
+ function buildAdminAuthHeader(args) {
1043
+ const nowMs = args.now ? args.now() : Date.now();
1044
+ const unixSeconds = Math.floor(nowMs / 1e3);
1045
+ const nonceBytes = args.randomNonce ? args.randomNonce() : Uint8Array.from(randomBytes(16));
1046
+ const nonceHex = Buffer.from(nonceBytes).toString("hex");
1047
+ const challenge = buildAdminChallenge({
1048
+ method: args.method,
1049
+ path: args.path,
1050
+ dvmId: args.dvmId,
1051
+ nonceHex,
1052
+ unixSeconds
1053
+ });
1054
+ const sigHex = signChallenge(args.privkeyHex, challenge);
1055
+ return {
1056
+ header: `P2PK ${nonceHex}.${unixSeconds}.${sigHex}`,
1057
+ nonceHex,
1058
+ unixSeconds
1059
+ };
1060
+ }
1061
+
956
1062
  // src/lib/builder-identity.ts
957
1063
  import {
958
1064
  chmodSync as chmodSync3,
@@ -964,8 +1070,8 @@ import {
964
1070
  unlinkSync as unlinkSync4,
965
1071
  writeFileSync as writeFileSync5
966
1072
  } from "fs";
967
- import { schnorr as schnorr2 } from "@noble/curves/secp256k1.js";
968
- import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
1073
+ import { schnorr as schnorr3 } from "@noble/curves/secp256k1.js";
1074
+ import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
969
1075
 
970
1076
  // src/lib/builder-store.ts
971
1077
  import {
@@ -1070,8 +1176,8 @@ function migrateV1Store(parsed) {
1070
1176
 
1071
1177
  // src/lib/builder-identity.ts
1072
1178
  function generateIdentity() {
1073
- const { secretKey, publicKey } = schnorr2.keygen();
1074
- return { pubkey: bytesToHex2(publicKey), secret: bytesToHex2(secretKey) };
1179
+ const { secretKey, publicKey } = schnorr3.keygen();
1180
+ return { pubkey: bytesToHex4(publicKey), secret: bytesToHex4(secretKey) };
1075
1181
  }
1076
1182
  function loadIdentitySecret() {
1077
1183
  if (!existsSync5(BUILDER_KEY_FILE)) return null;
@@ -1114,7 +1220,7 @@ function writeIdentity(keypair, opts = {}) {
1114
1220
  setIdentityPubkey(keypair.pubkey);
1115
1221
  }
1116
1222
  function hashCapabilities(capabilities) {
1117
- return bytesToHex2(sha2562(canonicaliseForSigning(capabilities)));
1223
+ return bytesToHex4(sha2563(canonicaliseForSigning(capabilities)));
1118
1224
  }
1119
1225
  function buildAttestation(args) {
1120
1226
  return {
@@ -1127,14 +1233,14 @@ function buildAttestation(args) {
1127
1233
  };
1128
1234
  }
1129
1235
  function signAttestation(payload, secretHex) {
1130
- const secretBytes = hexToBytes2(secretHex);
1236
+ const secretBytes = hexToBytes4(secretHex);
1131
1237
  const canonicalBytes = canonicaliseForSigning(payload);
1132
- return bytesToHex2(schnorr2.sign(canonicalBytes, secretBytes));
1238
+ return bytesToHex4(schnorr3.sign(canonicalBytes, secretBytes));
1133
1239
  }
1134
1240
  function verifyAttestation(payload, signatureHex, pubkeyHex) {
1135
1241
  try {
1136
1242
  const canonicalBytes = canonicaliseForSigning(payload);
1137
- return schnorr2.verify(hexToBytes2(signatureHex), canonicalBytes, hexToBytes2(pubkeyHex));
1243
+ return schnorr3.verify(hexToBytes4(signatureHex), canonicalBytes, hexToBytes4(pubkeyHex));
1138
1244
  } catch {
1139
1245
  return false;
1140
1246
  }
@@ -1157,12 +1263,12 @@ function warnAndTightenLooseKeyMode() {
1157
1263
  } catch {
1158
1264
  }
1159
1265
  }
1160
- function bytesToHex2(bytes) {
1266
+ function bytesToHex4(bytes) {
1161
1267
  let s = "";
1162
1268
  for (const b of bytes) s += b.toString(16).padStart(2, "0");
1163
1269
  return s;
1164
1270
  }
1165
- function hexToBytes2(hex) {
1271
+ function hexToBytes4(hex) {
1166
1272
  if (hex.length % 2 !== 0) {
1167
1273
  throw new Error(`hex string has odd length: ${String(hex.length)}`);
1168
1274
  }
@@ -1462,112 +1568,6 @@ function parseTraceparent(header) {
1462
1568
  return { traceId, parentSpanId, flags: parseInt(flagsHex, 16) };
1463
1569
  }
1464
1570
 
1465
- // src/lib/wallet-agent/keypair.ts
1466
- import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1.js";
1467
- var PRIVKEY_HEX_RE = /^[0-9a-f]{64}$/i;
1468
- function derivePubkeyFromPrivkey(privkey) {
1469
- if (!PRIVKEY_HEX_RE.test(privkey)) {
1470
- throw new DvmError(
1471
- "invalid_privkey",
1472
- "Privkey must be 64 hex characters (32 bytes).",
1473
- "Provide a valid secp256k1 private key as a 64-char hex string."
1474
- );
1475
- }
1476
- const bytes = hexToBytes3(privkey);
1477
- if (!secp256k12.utils.isValidSecretKey(bytes)) {
1478
- throw new DvmError(
1479
- "invalid_privkey",
1480
- "Privkey is not a valid secp256k1 scalar (zero or out of curve order).",
1481
- "Generate a fresh key with: dvm wallet init"
1482
- );
1483
- }
1484
- const pub = secp256k12.getPublicKey(bytes);
1485
- return bytesToHex3(pub);
1486
- }
1487
- function bytesToHex3(bytes) {
1488
- return Buffer.from(bytes).toString("hex");
1489
- }
1490
- function hexToBytes3(hex) {
1491
- return Uint8Array.from(Buffer.from(hex, "hex"));
1492
- }
1493
-
1494
- // src/lib/wallet-agent/sign.ts
1495
- import { schnorr as schnorr3 } from "@noble/curves/secp256k1.js";
1496
- var PUBKEY_COMPRESSED_HEX_RE = /^0[23][0-9a-f]{64}$/i;
1497
- var PUBKEY_XONLY_HEX_RE = /^[0-9a-f]{64}$/i;
1498
- var SIG_HEX_RE = /^[0-9a-f]{128}$/i;
1499
- function signChallenge(privkeyHex, challenge) {
1500
- if (!PRIVKEY_HEX_RE.test(privkeyHex)) {
1501
- throw new DvmError(
1502
- "invalid_privkey",
1503
- "Privkey must be 64 hex characters (32 bytes).",
1504
- "Provide a valid secp256k1 private key as a 64-char hex string."
1505
- );
1506
- }
1507
- if (challenge.length !== 32) {
1508
- throw new DvmError(
1509
- "invalid_challenge",
1510
- `Challenge must be exactly 32 bytes; got ${challenge.length}.`,
1511
- "Pass the SHA-256 digest output (32 bytes)."
1512
- );
1513
- }
1514
- const sig = schnorr3.sign(challenge, hexToBytes4(privkeyHex));
1515
- return bytesToHex4(sig);
1516
- }
1517
- function verifyChallenge(pubkeyHex, challenge, sigHex) {
1518
- if (!SIG_HEX_RE.test(sigHex)) return false;
1519
- if (challenge.length !== 32) return false;
1520
- let xonly;
1521
- if (PUBKEY_COMPRESSED_HEX_RE.test(pubkeyHex)) {
1522
- xonly = hexToBytes4(pubkeyHex.slice(2));
1523
- } else if (PUBKEY_XONLY_HEX_RE.test(pubkeyHex)) {
1524
- xonly = hexToBytes4(pubkeyHex);
1525
- } else {
1526
- return false;
1527
- }
1528
- try {
1529
- return schnorr3.verify(hexToBytes4(sigHex), challenge, xonly);
1530
- } catch {
1531
- return false;
1532
- }
1533
- }
1534
- function hexToBytes4(hex) {
1535
- return Uint8Array.from(Buffer.from(hex, "hex"));
1536
- }
1537
- function bytesToHex4(bytes) {
1538
- return Buffer.from(bytes).toString("hex");
1539
- }
1540
-
1541
- // src/lib/cashu/admin-auth.ts
1542
- import { randomBytes } from "crypto";
1543
- import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
1544
- var ADMIN_AUTH_NONCE_TTL_SECONDS = 300;
1545
- var ADMIN_AUTH_CLOCK_SKEW_SECONDS = 30;
1546
- var ADMIN_STATE_UNAVAILABLE = "admin_state_unavailable";
1547
- function buildAdminChallenge(args) {
1548
- const msg = `dvmkit-admin:${args.method}:${args.path}:${args.dvmId}:${args.nonceHex}:${args.unixSeconds}`;
1549
- return sha2563(new TextEncoder().encode(msg));
1550
- }
1551
- function buildAdminAuthHeader(args) {
1552
- const nowMs = args.now ? args.now() : Date.now();
1553
- const unixSeconds = Math.floor(nowMs / 1e3);
1554
- const nonceBytes = args.randomNonce ? args.randomNonce() : Uint8Array.from(randomBytes(16));
1555
- const nonceHex = Buffer.from(nonceBytes).toString("hex");
1556
- const challenge = buildAdminChallenge({
1557
- method: args.method,
1558
- path: args.path,
1559
- dvmId: args.dvmId,
1560
- nonceHex,
1561
- unixSeconds
1562
- });
1563
- const sigHex = signChallenge(args.privkeyHex, challenge);
1564
- return {
1565
- header: `P2PK ${nonceHex}.${unixSeconds}.${sigHex}`,
1566
- nonceHex,
1567
- unixSeconds
1568
- };
1569
- }
1570
-
1571
1571
  // src/lib/monotonic-clock.ts
1572
1572
  function createMonotonicClock() {
1573
1573
  let anchorWallMs = Date.now();
@@ -1662,6 +1662,14 @@ export {
1662
1662
  receiptPubkeyFromSecret,
1663
1663
  deriveReceiptKeypair,
1664
1664
  generateEphemeralReceiptKey,
1665
+ PRIVKEY_HEX_RE,
1666
+ derivePubkeyFromPrivkey,
1667
+ verifyChallenge,
1668
+ ADMIN_AUTH_NONCE_TTL_SECONDS,
1669
+ ADMIN_AUTH_CLOCK_SKEW_SECONDS,
1670
+ ADMIN_STATE_UNAVAILABLE,
1671
+ buildAdminChallenge,
1672
+ buildAdminAuthHeader,
1665
1673
  generateIdentity,
1666
1674
  loadIdentitySecret,
1667
1675
  writeIdentity,
@@ -1685,13 +1693,5 @@ export {
1685
1693
  receiptFailureDetail,
1686
1694
  isPublicRequestId,
1687
1695
  parseTraceparent,
1688
- PRIVKEY_HEX_RE,
1689
- derivePubkeyFromPrivkey,
1690
- verifyChallenge,
1691
- ADMIN_AUTH_NONCE_TTL_SECONDS,
1692
- ADMIN_AUTH_CLOCK_SKEW_SECONDS,
1693
- ADMIN_STATE_UNAVAILABLE,
1694
- buildAdminChallenge,
1695
- buildAdminAuthHeader,
1696
1696
  createMonotonicClock
1697
1697
  };
@@ -10,39 +10,6 @@ import {
10
10
  projectSpanRow
11
11
  } from "./chunk-ETXDTUJO.js";
12
12
 
13
- // src/sdk/step-cache.ts
14
- var StepCache = class _StepCache {
15
- cache = /* @__PURE__ */ new Map();
16
- has(id) {
17
- return this.cache.has(id);
18
- }
19
- get(id) {
20
- return this.getRecord(id).value;
21
- }
22
- getRecord(id) {
23
- const record = this.cache.get(id);
24
- if (record === void 0) throw new Error(`StepCache: no cached result for step "${id}"`);
25
- return record;
26
- }
27
- set(id, value, costs) {
28
- this.cache.set(id, {
29
- id,
30
- value,
31
- ...costs !== void 0 && costs.length > 0 ? { costs: costs.map(({ amount, currency }) => ({ amount, currency })) } : {}
32
- });
33
- }
34
- serialize() {
35
- return [...this.cache.values()];
36
- }
37
- static deserialize(records) {
38
- const cache = new _StepCache();
39
- for (const { id, value, costs } of records) {
40
- cache.set(id, value, costs);
41
- }
42
- return cache;
43
- }
44
- };
45
-
46
13
  // src/sdk/logger.ts
47
14
  function createConsoleLogger(_jobId) {
48
15
  return {
@@ -373,15 +340,15 @@ async function withSpan(opts, fn) {
373
340
 
374
341
  // src/observability/datasets.ts
375
342
  var SPANS_DATASETS = [
376
- { name: "platform", retentionDays: 90 },
377
- { name: "cashu", retentionDays: 90 },
378
- { name: "lightning", retentionDays: 90 },
379
- { name: "stripe", retentionDays: 90 },
380
- { name: "x402", retentionDays: 90 },
381
- { name: "tempo", retentionDays: 90 },
382
- { name: "isolate", retentionDays: 90 },
383
- { name: "audit", retentionDays: 365 },
384
- { name: "cron", retentionDays: 30 }
343
+ { name: "platform", retentionDays: 730 },
344
+ { name: "cashu", retentionDays: 730 },
345
+ { name: "lightning", retentionDays: 730 },
346
+ { name: "stripe", retentionDays: 730 },
347
+ { name: "x402", retentionDays: 730 },
348
+ { name: "tempo", retentionDays: 730 },
349
+ { name: "isolate", retentionDays: 730 },
350
+ { name: "audit", retentionDays: 730 },
351
+ { name: "cron", retentionDays: 730 }
385
352
  ];
386
353
  var DATASET_NAMES = new Set(SPANS_DATASETS.map((d) => d.name));
387
354
 
@@ -485,7 +452,6 @@ function buildNoopLoggers() {
485
452
  }
486
453
 
487
454
  export {
488
- StepCache,
489
455
  createConsoleLogger,
490
456
  createStdoutLogger,
491
457
  createNoopLogger,