@dvmkit/sdk 0.4.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.
- package/README.md +100 -0
- package/dist/{chunk-TXX4GOUB.js → chunk-7ZUKL4IV.js} +1 -1
- package/dist/chunk-AFV77S4C.js +258 -0
- package/dist/{chunk-2VGWYG4P.js → chunk-B2IROPQF.js} +446 -81
- package/dist/chunk-BQJIFRAZ.js +36 -0
- package/dist/{chunk-PB4FYZET.js → chunk-EQLA4FFY.js} +54 -4
- package/dist/{chunk-74PUEZJ4.js → chunk-GFY5FRX3.js} +1 -1
- package/dist/{chunk-O3QDFPKM.js → chunk-HCLVYZUZ.js} +2 -2
- package/dist/{chunk-K2YX2VRA.js → chunk-HHBDBMEO.js} +170 -43
- package/dist/{chunk-O5AT6S5T.js → chunk-IV6Q7NRW.js} +25 -195
- package/dist/{chunk-W2EQGDF5.js → chunk-LE74UEV7.js} +49 -8
- package/dist/{chunk-CE7XEHYC.js → chunk-N5RZ5HVB.js} +1 -1
- package/dist/chunk-OFVV37XC.js +57 -0
- package/dist/{chunk-5LR6P7WN.js → chunk-OQA7IHI4.js} +133 -213
- package/dist/{chunk-3MHE725Z.js → chunk-PAIM66YA.js} +90 -1
- package/dist/{chunk-6DOGTAHA.js → chunk-QR2EF2NI.js} +9 -43
- package/dist/{chunk-KXZUCCEY.js → chunk-RCM3P2HE.js} +5 -56
- package/dist/{chunk-R4DQZFAL.js → chunk-UOCZXO2Z.js} +3 -3
- package/dist/content-retention-BTGSQRfP.d.ts +78 -0
- package/dist/{credit-menu-B8_p_vUz.d.ts → credit-menu-BAsrRu3z.d.ts} +98 -5
- package/dist/{fx-DuaYHvVn.d.ts → fx-BgDmyTdd.d.ts} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -3
- package/dist/internal/caller.d.ts +90 -22
- package/dist/internal/caller.js +40 -40
- package/dist/internal/index.js +1 -1
- package/dist/internal/server.d.ts +8 -99
- package/dist/internal/server.js +15 -11
- package/dist/{job-store-D6Rjj5Oi.d.ts → job-store-BVeF5_Jq.d.ts} +1 -1
- package/dist/{lightning-backend-BaeCPmx7.d.ts → lightning-backend-40fIzz1W.d.ts} +1 -1
- package/dist/{postgres-consumed-credential-store-CUQJKRSL.js → postgres-consumed-credential-store-BUVCAPLS.js} +13 -0
- package/dist/{postgres-job-store-VLXLWXUQ.js → postgres-job-store-VHLQBJZC.js} +3 -1
- package/dist/server/index.d.ts +28 -10
- package/dist/server/index.js +24 -10
- package/dist/{step-cache-Bi43A0JN.d.ts → step-cache-CPdH1hei.d.ts} +3 -3
- package/dist/{tempo-lifecycle-OTHV757Y.js → tempo-lifecycle-ZBBLFBMH.js} +5 -4
- package/dist/{tempo-wallet-32JWQZKQ.js → tempo-wallet-B5XXV3YH.js} +1 -1
- package/dist/testing/index.d.ts +9 -2
- package/dist/testing/index.js +6 -3
- package/dist/{usd-AZPVq4eU.d.ts → usd-AWlrwlM5.d.ts} +1 -1
- package/dist/{x402-CEDHGZDI.js → x402-R6HPBY5D.js} +5 -4
- package/package.json +3 -2
- package/recipes/postgres/financial-export-v1.sql +137 -0
|
@@ -1,191 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
ContentHoldError,
|
|
3
|
+
applyContentHoldMutation,
|
|
4
|
+
isTerminal
|
|
5
|
+
} from "./chunk-AFV77S4C.js";
|
|
6
|
+
import {
|
|
3
7
|
loggers
|
|
4
|
-
} from "./chunk-
|
|
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,
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
fundingReachableAt,
|
|
3
|
-
info,
|
|
4
3
|
listCredits,
|
|
5
4
|
maxAdvertisedMicro,
|
|
6
5
|
withinAdvertisedTolerance
|
|
7
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-B2IROPQF.js";
|
|
8
7
|
import {
|
|
9
8
|
authorizeProtectedRemoval,
|
|
10
9
|
isValidEvmPrivateKey,
|
|
@@ -31,7 +30,7 @@ import {
|
|
|
31
30
|
getLastKnownBtcRate,
|
|
32
31
|
msatsToUsdc,
|
|
33
32
|
usdcToMsats
|
|
34
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-PAIM66YA.js";
|
|
35
34
|
import {
|
|
36
35
|
X402_CHANNELS_FILE,
|
|
37
36
|
ensureConfigDir,
|
|
@@ -72,6 +71,42 @@ function x402WrongAssetHint(asset) {
|
|
|
72
71
|
return `This rail reads only ${asset.label} (${asset.address}) on ${asset.networkLabel}. ${wrongToken} USDC on a different chain is invisible here too \u2014 this wallet reads ${asset.networkLabel} alone. If you funded the wrong one, swap it to ${asset.label} on ${asset.networkLabel}, or bridge the funds across to ${asset.networkLabel}; either way they land where this rail can spend them.`;
|
|
73
72
|
}
|
|
74
73
|
|
|
74
|
+
// src/lib/output.ts
|
|
75
|
+
import { writeSync } from "fs";
|
|
76
|
+
var _traceId = null;
|
|
77
|
+
function setOutputTraceId(id) {
|
|
78
|
+
_traceId = id;
|
|
79
|
+
}
|
|
80
|
+
function getOutputTraceId() {
|
|
81
|
+
return _traceId;
|
|
82
|
+
}
|
|
83
|
+
function json(data) {
|
|
84
|
+
const out = _traceId !== null && typeof data === "object" && data !== null && !Array.isArray(data) && !("trace_id" in data) ? { trace_id: _traceId, ...data } : data;
|
|
85
|
+
writeAllSync(1, JSON.stringify(out) + "\n");
|
|
86
|
+
}
|
|
87
|
+
function info(msg) {
|
|
88
|
+
writeAllSync(2, msg + "\n");
|
|
89
|
+
}
|
|
90
|
+
function raw(msg) {
|
|
91
|
+
writeAllSync(1, msg + "\n");
|
|
92
|
+
}
|
|
93
|
+
function progress(event) {
|
|
94
|
+
writeAllSync(2, JSON.stringify(event) + "\n");
|
|
95
|
+
}
|
|
96
|
+
function writeAllSync(fd, text) {
|
|
97
|
+
const buf = Buffer.from(text, "utf8");
|
|
98
|
+
let offset = 0;
|
|
99
|
+
while (offset < buf.length) {
|
|
100
|
+
try {
|
|
101
|
+
offset += writeSync(fd, buf, offset, buf.length - offset);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
const code = err.code;
|
|
104
|
+
if (code === "EAGAIN" || code === "EINTR") continue;
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
75
110
|
// src/lib/btc-rate.ts
|
|
76
111
|
async function resolveBtcUsdRate(purpose) {
|
|
77
112
|
try {
|
|
@@ -600,18 +635,18 @@ function ensureX402ChannelFile() {
|
|
|
600
635
|
function loadFile() {
|
|
601
636
|
if (!existsSync(X402_CHANNELS_FILE)) return { ...EMPTY, channels: {}, pending: [], exact: [] };
|
|
602
637
|
try {
|
|
603
|
-
const
|
|
604
|
-
if (
|
|
638
|
+
const raw2 = JSON.parse(readFileSync(X402_CHANNELS_FILE, "utf8"));
|
|
639
|
+
if (raw2.version !== 1 || !raw2.channels || typeof raw2.channels !== "object" || Array.isArray(raw2.channels) || !Array.isArray(raw2.pending)) {
|
|
605
640
|
throw new Error("unsupported x402 channel store shape");
|
|
606
641
|
}
|
|
607
642
|
return {
|
|
608
643
|
version: 1,
|
|
609
|
-
channels:
|
|
610
|
-
pending:
|
|
644
|
+
channels: raw2.channels,
|
|
645
|
+
pending: raw2.pending,
|
|
611
646
|
// Tolerated rather than required, unlike its two siblings: every file
|
|
612
647
|
// written before lacks the key, and failing closed on it would
|
|
613
648
|
// read as a corrupt journal on a store that is perfectly intact.
|
|
614
|
-
exact: Array.isArray(
|
|
649
|
+
exact: Array.isArray(raw2.exact) ? raw2.exact : []
|
|
615
650
|
};
|
|
616
651
|
} catch (cause) {
|
|
617
652
|
throw new DvmError(
|
|
@@ -986,6 +1021,12 @@ async function priceableRate(btcRate) {
|
|
|
986
1021
|
export {
|
|
987
1022
|
resolveX402Asset,
|
|
988
1023
|
x402WrongAssetHint,
|
|
1024
|
+
setOutputTraceId,
|
|
1025
|
+
getOutputTraceId,
|
|
1026
|
+
json,
|
|
1027
|
+
info,
|
|
1028
|
+
raw,
|
|
1029
|
+
progress,
|
|
989
1030
|
resolveBtcUsdRate,
|
|
990
1031
|
tryResolveBtcUsdRate,
|
|
991
1032
|
staleRateNotice,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// src/lib/cast-auth/canonical-json.ts
|
|
2
|
+
function canonicalize(value) {
|
|
3
|
+
return JSON.stringify(sortDeep(value));
|
|
4
|
+
}
|
|
5
|
+
function canonicaliseForSigning(value) {
|
|
6
|
+
return new TextEncoder().encode(canonicalize(value));
|
|
7
|
+
}
|
|
8
|
+
function sortDeep(value) {
|
|
9
|
+
if (value === null) return null;
|
|
10
|
+
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
11
|
+
if (typeof value === "number") {
|
|
12
|
+
if (!Number.isFinite(value)) {
|
|
13
|
+
throw new TypeError(`canonicalize: non-finite number is not JSON-serialisable`);
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(value)) return value.map(sortDeep);
|
|
18
|
+
if (typeof value === "object") {
|
|
19
|
+
const sorted = {};
|
|
20
|
+
for (const key of Object.keys(value).sort()) {
|
|
21
|
+
const v = value[key];
|
|
22
|
+
if (v === void 0) continue;
|
|
23
|
+
sorted[key] = sortDeep(v);
|
|
24
|
+
}
|
|
25
|
+
return sorted;
|
|
26
|
+
}
|
|
27
|
+
throw new TypeError(`canonicalize: unsupported value of type ${typeof value}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/lib/cast-auth/verify.ts
|
|
31
|
+
import { schnorr } from "@noble/curves/secp256k1.js";
|
|
32
|
+
function verifyCanonicalSignedRequest(payload, signatureHex, pubkeyHex) {
|
|
33
|
+
if (!/^[0-9a-f]{64}$/i.test(pubkeyHex) || !/^[0-9a-f]{128}$/i.test(signatureHex)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const data = canonicaliseForSigning(payload);
|
|
37
|
+
const signature = hexToBytes(signatureHex);
|
|
38
|
+
const pubkey = hexToBytes(pubkeyHex);
|
|
39
|
+
try {
|
|
40
|
+
return schnorr.verify(signature, data, pubkey);
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function hexToBytes(hex) {
|
|
46
|
+
const out = new Uint8Array(hex.length / 2);
|
|
47
|
+
for (let i = 0; i < out.length; i++) {
|
|
48
|
+
out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export {
|
|
54
|
+
canonicalize,
|
|
55
|
+
canonicaliseForSigning,
|
|
56
|
+
verifyCanonicalSignedRequest
|
|
57
|
+
};
|