@dvmkit/sdk 0.1.0-rc.2 → 0.1.0-rc.4

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 (42) hide show
  1. package/README.md +10 -2
  2. package/dist/{revenue-reporter-GB4WKLDC.js → chunk-2ABMGUDS.js} +1 -0
  3. package/dist/chunk-2K6UXDAN.js +1557 -0
  4. package/dist/chunk-4UVRXDNY.js +21745 -0
  5. package/dist/chunk-66HGCPBU.js +25 -0
  6. package/dist/{chunk-DCNT4PJS.js → chunk-AAJNGQMC.js} +6 -258
  7. package/dist/{chunk-KQAJVVZT.js → chunk-AZBXSXQT.js} +27 -287
  8. package/dist/{chunk-H25M54MI.js → chunk-C3MTFLC6.js} +16 -0
  9. package/dist/chunk-EDU6COY2.js +1057 -0
  10. package/dist/{chunk-OJ5WFIB2.js → chunk-EXHBXA4U.js} +1 -1
  11. package/dist/chunk-F2L6KIMD.js +380 -0
  12. package/dist/{chunk-KXWROQGK.js → chunk-FUJ36YDV.js} +1 -24
  13. package/dist/chunk-GJD7PVWY.js +1090 -0
  14. package/dist/{tempo-charge-store-6GJEMNUU.js → chunk-JZWELPFH.js} +1 -0
  15. package/dist/{chunk-365P52XQ.js → chunk-LWUR4CGG.js} +2 -1
  16. package/dist/{tempo-session-store-FTEEGZXA.js → chunk-RU7SXHLO.js} +2 -1
  17. package/dist/{chunk-7IH5SG2A.js → chunk-TKA6ZP4M.js} +62 -41
  18. package/dist/chunk-TVI4V7GF.js +283 -0
  19. package/dist/{payout-reporter-4TNWRS5F.js → chunk-X3IKFWJA.js} +3 -2
  20. package/dist/chunk-XYTSDAPH.js +232 -0
  21. package/dist/{credit-ledger-RO4FGSHG.js → credit-ledger-ED6JXKVD.js} +2 -2
  22. package/dist/credit-menu-ClA1JyYW.d.ts +5076 -0
  23. package/dist/{ssrf-DZi-xJyn.d.ts → fx-ptKVFOwq.d.ts} +37 -119
  24. package/dist/index.d.ts +8 -66
  25. package/dist/index.js +11 -219
  26. package/dist/internal/index.d.ts +5896 -0
  27. package/dist/internal/index.js +6407 -0
  28. package/dist/{job-store-6gR4pZRP.d.ts → job-store-DxFqDPYq.d.ts} +1498 -12
  29. package/dist/{memory-credit-ledger-I2G64DDK.js → memory-credit-ledger-XJ5VQEVP.js} +3 -3
  30. package/dist/payout-reporter-3UB5WRCV.js +13 -0
  31. package/dist/revenue-reporter-JIKUPXOK.js +7 -0
  32. package/dist/server/index.d.ts +14 -3590
  33. package/dist/server/index.js +155 -20850
  34. package/dist/ssrf-DbFkpDv0.d.ts +118 -0
  35. package/dist/tempo-charge-store-RIFTALZK.js +8 -0
  36. package/dist/tempo-session-store-DALMRIWN.js +11 -0
  37. package/dist/testing/index.d.ts +3 -2
  38. package/dist/testing/index.js +3 -2
  39. package/dist/usd-Cha_j80I.d.ts +97 -0
  40. package/dist/x402-XXFQQAAD.js +81 -0
  41. package/package.json +6 -2
  42. package/dist/x402-35VLYFKZ.js +0 -1272
@@ -15,7 +15,7 @@ import {
15
15
  lotOwedSats,
16
16
  netOwedSats,
17
17
  x402SettlementPending
18
- } from "./chunk-365P52XQ.js";
18
+ } from "./chunk-LWUR4CGG.js";
19
19
 
20
20
  // src/sdk/server/memory-credit-ledger.ts
21
21
  import { randomUUID } from "crypto";
@@ -0,0 +1,380 @@
1
+ import {
2
+ formatFiat
3
+ } from "./chunk-AT6V3SY7.js";
4
+
5
+ // src/lib/errors.ts
6
+ var DvmError = class extends Error {
7
+ constructor(code, message, hint, data, display, proseSources) {
8
+ super(message);
9
+ this.code = code;
10
+ this.hint = hint;
11
+ this.data = data;
12
+ this.display = display;
13
+ this.proseSources = proseSources;
14
+ this.name = "DvmError";
15
+ }
16
+ code;
17
+ hint;
18
+ data;
19
+ display;
20
+ proseSources;
21
+ };
22
+ function providerProseSources(...sources) {
23
+ const provenance = {};
24
+ for (const source of sources) {
25
+ if (!source) continue;
26
+ for (const field of ["message", "hint", "display"]) {
27
+ if (typeof source[field] === "string") provenance[field] = "provider";
28
+ }
29
+ }
30
+ return Object.keys(provenance).length > 0 ? provenance : void 0;
31
+ }
32
+ function isAbortError(err) {
33
+ return err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
34
+ }
35
+ function transportErrorCode(err) {
36
+ let current = err;
37
+ const seen = /* @__PURE__ */ new Set();
38
+ for (let depth = 0; depth < 5 && isErrorLike(current) && !seen.has(current); depth++) {
39
+ seen.add(current);
40
+ const code = current.code;
41
+ if (typeof code === "string" && /^(?:E[A-Z0-9_]{1,63}|UND_ERR_[A-Z0-9_]{1,63})$/.test(code)) {
42
+ return code;
43
+ }
44
+ current = current.cause;
45
+ }
46
+ return void 0;
47
+ }
48
+ function isErrorLike(value) {
49
+ return (typeof value === "object" || typeof value === "function") && value !== null;
50
+ }
51
+
52
+ // src/lib/credit-implicit.ts
53
+ var IMPLICIT_CREDIT_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
54
+
55
+ // src/lib/fx-coingecko.ts
56
+ var COINGECKO_SIMPLE_PRICE_URL = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,usd-coin&vs_currencies=usd";
57
+ var COINGECKO_BTC_USD_URL = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd";
58
+ var DEFAULT_TIMEOUT_MS = 5e3;
59
+ var DEFAULT_USER_AGENT = "dvmkit-platform/1.0 (+https://dvmkit.com)";
60
+ async function fetchCoinGeckoSpot(opts) {
61
+ const body = await fetchCoinGeckoBody(opts, COINGECKO_SIMPLE_PRICE_URL);
62
+ const btc = body.bitcoin?.usd;
63
+ const usdc = body["usd-coin"]?.usd;
64
+ if (!isPositiveNumber(btc)) {
65
+ throw new Error("coingecko response missing bitcoin.usd");
66
+ }
67
+ if (!isPositiveNumber(usdc)) {
68
+ throw new Error("coingecko response missing usd-coin.usd");
69
+ }
70
+ return { btc_usd: btc, usdc_usd: usdc, as_of: (/* @__PURE__ */ new Date()).toISOString() };
71
+ }
72
+ async function fetchCoinGeckoBtcUsd(opts) {
73
+ const body = await fetchCoinGeckoBody(opts, COINGECKO_BTC_USD_URL);
74
+ const btc = body.bitcoin?.usd;
75
+ if (!isPositiveNumber(btc)) {
76
+ throw new Error("coingecko response missing bitcoin.usd");
77
+ }
78
+ return { btc_usd: btc, as_of: (/* @__PURE__ */ new Date()).toISOString() };
79
+ }
80
+ async function fetchCoinGeckoBody(opts, defaultUrl) {
81
+ const url = opts?.url ?? defaultUrl;
82
+ const fetchImpl = opts?.fetchImpl ?? fetch;
83
+ const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
84
+ const userAgent = opts?.userAgent ?? DEFAULT_USER_AGENT;
85
+ const res = await fetchImpl(url, {
86
+ headers: { "User-Agent": userAgent, Accept: "application/json" },
87
+ signal: AbortSignal.timeout(timeoutMs)
88
+ });
89
+ if (!res.ok) {
90
+ throw new Error(`coingecko returned HTTP ${res.status.toString()}`);
91
+ }
92
+ return await res.json();
93
+ }
94
+ function isPositiveNumber(v) {
95
+ return typeof v === "number" && Number.isFinite(v) && v > 0;
96
+ }
97
+
98
+ // src/lib/currency.ts
99
+ import { existsSync, readFileSync, writeFileSync } from "fs";
100
+ import { dirname } from "path";
101
+
102
+ // src/defaults.ts
103
+ import { homedir } from "os";
104
+ import { join } from "path";
105
+ var CONFIG_DIR = process.env.DVM_CONFIG_DIR ?? join(homedir(), ".dvm");
106
+ var CONFIG_FILE = join(CONFIG_DIR, "config.json");
107
+ var CONFIG_BACKUP_FILE = join(CONFIG_DIR, "config.json.bak");
108
+ var CONFIG_AUDIT_FILE = join(CONFIG_DIR, "config-audit.jsonl");
109
+ var CONFIG_PINNED_FILE = join(CONFIG_DIR, "config.json.pinned");
110
+ var JOBS_FILE = join(CONFIG_DIR, "jobs.json");
111
+ var REQUEST_INTENTS_DIR = join(CONFIG_DIR, "request-intents");
112
+ var FAVORITES_FILE = join(CONFIG_DIR, "favorites.json");
113
+ var MESSAGES_DIR = join(CONFIG_DIR, "messages");
114
+ var RECEIPTS_FILE = join(CONFIG_DIR, "receipts.jsonl");
115
+ var CREDITS_FILE = join(CONFIG_DIR, "credits.json");
116
+ var X402_CHANNELS_FILE = join(CONFIG_DIR, "x402-channels.json");
117
+ var TEMPO_CHANNELS_FILE = join(CONFIG_DIR, "tempo-channels.json");
118
+ var FEEDBACK_NUDGES_FILE = join(CONFIG_DIR, "feedback-nudges.json");
119
+ var RECOVERY_MNEMONIC_FILE = join(CONFIG_DIR, "recovery.mnemonic");
120
+ var WALLET_FILE = join(CONFIG_DIR, "wallet.json");
121
+ var AGENT_MNEMONIC_FILE = join(CONFIG_DIR, "wallet.mnemonic");
122
+ var IDENTITIES_FILE = join(CONFIG_DIR, "identities.json");
123
+ var PAIRINGS_DIR = join(CONFIG_DIR, "pairings");
124
+ var BUDGET_FILE = join(CONFIG_DIR, "budget.json");
125
+ var BTC_RATE_FILE = join(CONFIG_DIR, "btc-rate.json");
126
+ var ADMIN_DIR = join(CONFIG_DIR, "admin");
127
+ var PROXY_STATE_FILE = join(ADMIN_DIR, "proxy.json");
128
+ var BUILDER_CONFIG_DIR = process.env.DVMKIT_CONFIG_DIR ?? join(homedir(), ".dvmkit");
129
+ var BUILDER_FILE = join(BUILDER_CONFIG_DIR, "builder.json");
130
+ var BUILDER_MNEMONIC_FILE = join(BUILDER_CONFIG_DIR, "recovery.mnemonic");
131
+ var BUILDER_KEY_FILE = join(BUILDER_CONFIG_DIR, "builder.key");
132
+ var MELT_PENDING_LOG_FILE = join(BUILDER_CONFIG_DIR, "melt-pending.log");
133
+ var DRAIN_PARK_LOG_FILE = join(BUILDER_CONFIG_DIR, "drain-park.log");
134
+ var DRAIN_HOLD_STATE_FILE = join(BUILDER_CONFIG_DIR, "drain-hold.json");
135
+ var MELT_SUCCESS_FILE = join(BUILDER_CONFIG_DIR, "melt-success.json");
136
+
137
+ // src/lib/config-dir.ts
138
+ import { chmodSync, mkdirSync, statSync } from "fs";
139
+ var CONFIG_DIR_MODE = 448;
140
+ function ensureConfigDir() {
141
+ ensureConfigSubdir(CONFIG_DIR);
142
+ }
143
+ function ensureConfigSubdir(path) {
144
+ mkdirSync(path, { recursive: true, mode: CONFIG_DIR_MODE });
145
+ }
146
+
147
+ // src/lib/currency.ts
148
+ function msatsToUsd(msats, rate) {
149
+ return msats / 1e11 * rate;
150
+ }
151
+ function usdToMsats(usd, rate) {
152
+ return Math.round(usd / rate * 1e11);
153
+ }
154
+ function msatsToUsdCents(msats, btcPriceUsd) {
155
+ const usd = msatsToUsd(msats, btcPriceUsd);
156
+ return Math.round(usd * 100);
157
+ }
158
+ function msatsToUsdc(msats, btcUsdRate) {
159
+ const usd = msatsToUsd(msats, btcUsdRate);
160
+ return Math.ceil(usd * 1e6);
161
+ }
162
+ function usdcToMsats(usdc, btcUsdRate) {
163
+ return usdToMsats(usdc, btcUsdRate);
164
+ }
165
+ function formatSats(msats) {
166
+ if (msats === 0) return "0 sats";
167
+ if (msats < 1e3) return `${msats.toLocaleString("en-US")} msats`;
168
+ if (msats % 1e3 === 0) return `${(msats / 1e3).toLocaleString("en-US")} sats`;
169
+ return `${Math.round(msats / 1e3 * 100) / 100} sats`;
170
+ }
171
+ function formatAmount(msats, rate, opts) {
172
+ const usd = msatsToUsd(msats, rate);
173
+ const base = `~$${formatUsd(usd)} (${formatSats(msats)})`;
174
+ return opts?.anchor === false ? base : `${base} \u2014 ${costAnchor(usd)}`;
175
+ }
176
+ function formatPaymentAmount(msats, fiat, opts) {
177
+ if (!fiat || fiat.amount <= 0) return formatAmountBestEffort(msats, opts);
178
+ const base = `${formatFiat(fiat.amount, fiat.currency)} (${formatSats(msats)})`;
179
+ return opts?.anchor === false ? base : `${base} \u2014 ${costAnchor(fiat.amount, fiat.currency)}`;
180
+ }
181
+ var COST_ANCHOR_BANDS = {
182
+ usd: [0.01, 0.1, 1, 10],
183
+ eur: [0.01, 0.1, 1, 10],
184
+ gbp: [0.01, 0.1, 1, 10],
185
+ jpy: [1, 10, 100, 1500]
186
+ };
187
+ function costAnchor(amount, currency = "usd") {
188
+ const bands = COST_ANCHOR_BANDS[currency] ?? COST_ANCHOR_BANDS.usd;
189
+ if (amount < bands[0]) return "fraction of a cent";
190
+ if (amount <= bands[1]) return "comparable to an API call";
191
+ if (amount <= bands[2]) return "comparable to a ChatGPT query";
192
+ if (amount <= bands[3]) return "comparable to a coffee";
193
+ return "significant purchase \u2014 review carefully";
194
+ }
195
+ function monetaryJson(msats, rate) {
196
+ const usd = msatsToUsd(msats, rate);
197
+ return {
198
+ msats,
199
+ usd: Math.round(usd * 100) / 100,
200
+ anchor: costAnchor(usd),
201
+ display: formatAmount(msats, rate)
202
+ };
203
+ }
204
+ function formatUsd(usd) {
205
+ if (usd === 0) return "0.00";
206
+ if (usd >= 0.01) return usd.toFixed(2);
207
+ const digits = Math.max(2, -Math.floor(Math.log10(usd)) + 1);
208
+ return usd.toFixed(digits);
209
+ }
210
+ function formatUsdcMicrounits(microunits) {
211
+ const value = typeof microunits === "bigint" ? microunits : BigInt(microunits);
212
+ const whole = value / 1000000n;
213
+ const fraction = (value % 1000000n).toString().padStart(6, "0").replace(/0+$/, "");
214
+ return `${whole}.${fraction.padEnd(2, "0") || "00"}`;
215
+ }
216
+ function parseBudget(budget, rate) {
217
+ const value = assertValidBudget(budget);
218
+ return budget.startsWith("$") ? usdToMsats(value, rate) : value;
219
+ }
220
+ function assertValidBudget(budget) {
221
+ const value = budget.startsWith("$") ? parseFloat(budget.slice(1)) : parseInt(budget, 10);
222
+ if (isNaN(value)) throw new Error(`Invalid budget: ${budget}`);
223
+ return value;
224
+ }
225
+ async function fetchBtcUsdRate() {
226
+ if (memRate && Date.now() - memTime < CACHE_TTL) {
227
+ return memRate;
228
+ }
229
+ const disk = readDiskCache();
230
+ if (disk) {
231
+ memRate = disk;
232
+ memTime = Date.now();
233
+ return disk;
234
+ }
235
+ const rate = await fetchFromApi();
236
+ memRate = rate;
237
+ memTime = Date.now();
238
+ writeDiskCache(rate);
239
+ return rate;
240
+ }
241
+ function getLastKnownBtcRate() {
242
+ if (memRate && memTime > 0) return { rate: memRate, cachedAt: memTime };
243
+ return readDiskCacheStale();
244
+ }
245
+ function formatStaleness(cachedAt, now = Date.now()) {
246
+ const ageMs = Math.max(0, now - cachedAt);
247
+ const seconds = Math.floor(ageMs / 1e3);
248
+ if (seconds < 60) return `${seconds}s ago`;
249
+ const minutes = Math.floor(seconds / 60);
250
+ if (minutes < 60) return `${minutes} min ago`;
251
+ const hours = Math.floor(minutes / 60);
252
+ if (hours < 24) return `${hours} hour${hours === 1 ? "" : "s"} ago`;
253
+ const days = Math.floor(hours / 24);
254
+ return `${days} day${days === 1 ? "" : "s"} ago`;
255
+ }
256
+ function formatAmountBestEffort(msats, opts) {
257
+ const m = msats ?? 0;
258
+ const cached = getLastKnownBtcRate();
259
+ if (cached === null) return `${Math.round(m / 1e3)} sats`;
260
+ const base = formatAmount(m, cached.rate, opts);
261
+ if (Date.now() - cached.cachedAt < CACHE_TTL) return base;
262
+ return `${base} (rate cached ${formatStaleness(cached.cachedAt)})`;
263
+ }
264
+ var CACHE_TTL = 5 * 60 * 1e3;
265
+ var CACHE_FILE = BTC_RATE_FILE;
266
+ var memRate = null;
267
+ var memTime = 0;
268
+ function readDiskCache() {
269
+ try {
270
+ if (!existsSync(CACHE_FILE)) return null;
271
+ const data = JSON.parse(readFileSync(CACHE_FILE, "utf-8"));
272
+ if (Date.now() - data.timestamp >= CACHE_TTL) return null;
273
+ if (!isPlausibleBtcUsdRate(data.rate)) return null;
274
+ return data.rate;
275
+ } catch {
276
+ return null;
277
+ }
278
+ }
279
+ function readDiskCacheStale() {
280
+ try {
281
+ if (!existsSync(CACHE_FILE)) return null;
282
+ const data = JSON.parse(readFileSync(CACHE_FILE, "utf-8"));
283
+ if (!isPlausibleBtcUsdRate(data.rate)) return null;
284
+ return { rate: data.rate, cachedAt: data.timestamp };
285
+ } catch {
286
+ return null;
287
+ }
288
+ }
289
+ function writeDiskCache(rate) {
290
+ try {
291
+ ensureConfigSubdir(dirname(CACHE_FILE));
292
+ writeFileSync(CACHE_FILE, JSON.stringify({ rate, timestamp: Date.now() }));
293
+ } catch {
294
+ }
295
+ }
296
+ var MAX_PLAUSIBLE_BTC_USD = 1e7;
297
+ function isPlausibleBtcUsdRate(rate) {
298
+ return typeof rate === "number" && Number.isFinite(rate) && rate > 0 && rate < MAX_PLAUSIBLE_BTC_USD;
299
+ }
300
+ async function fetchFromApi() {
301
+ const spot = await fetchCoinGeckoBtcUsd();
302
+ const rate = spot.btc_usd;
303
+ if (!isPlausibleBtcUsdRate(rate)) {
304
+ throw new Error(`implausible BTC/USD rate from upstream: ${String(rate)}`);
305
+ }
306
+ return rate;
307
+ }
308
+
309
+ // src/lib/payment-rails/rpc.ts
310
+ function resolveRpcOverride(envValue, bundled) {
311
+ const override = envValue?.trim() ?? "";
312
+ return override.length > 0 ? { url: override, source: "override" } : { url: bundled, source: "bundled" };
313
+ }
314
+ function resolveRpcHttpTransportOptions(source, envValue) {
315
+ if (source !== "override" || !envValue?.trim()) return void 0;
316
+ let parsed;
317
+ try {
318
+ parsed = JSON.parse(envValue);
319
+ } catch {
320
+ throw new Error("RPC headers must be a JSON object of non-empty string values.");
321
+ }
322
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
323
+ throw new Error("RPC headers must be a JSON object of non-empty string values.");
324
+ const headers = {};
325
+ for (const [name, value] of Object.entries(parsed)) {
326
+ if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name) || typeof value !== "string" || value.length === 0 || /[\r\n]/.test(value))
327
+ throw new Error("RPC headers must be a JSON object of non-empty string values.");
328
+ headers[name] = value;
329
+ }
330
+ if (Object.keys(headers).length === 0)
331
+ throw new Error("RPC headers must be a JSON object of non-empty string values.");
332
+ return { fetchOptions: { headers } };
333
+ }
334
+
335
+ export {
336
+ DvmError,
337
+ providerProseSources,
338
+ isAbortError,
339
+ transportErrorCode,
340
+ IMPLICIT_CREDIT_TTL_MS,
341
+ CONFIG_FILE,
342
+ CONFIG_BACKUP_FILE,
343
+ CONFIG_AUDIT_FILE,
344
+ CONFIG_PINNED_FILE,
345
+ RECEIPTS_FILE,
346
+ CREDITS_FILE,
347
+ X402_CHANNELS_FILE,
348
+ TEMPO_CHANNELS_FILE,
349
+ WALLET_FILE,
350
+ AGENT_MNEMONIC_FILE,
351
+ IDENTITIES_FILE,
352
+ BUDGET_FILE,
353
+ BUILDER_CONFIG_DIR,
354
+ BUILDER_FILE,
355
+ BUILDER_KEY_FILE,
356
+ ensureConfigDir,
357
+ COINGECKO_SIMPLE_PRICE_URL,
358
+ fetchCoinGeckoSpot,
359
+ fetchCoinGeckoBtcUsd,
360
+ msatsToUsd,
361
+ usdToMsats,
362
+ msatsToUsdCents,
363
+ msatsToUsdc,
364
+ usdcToMsats,
365
+ formatSats,
366
+ formatAmount,
367
+ formatPaymentAmount,
368
+ costAnchor,
369
+ monetaryJson,
370
+ formatUsd,
371
+ formatUsdcMicrounits,
372
+ parseBudget,
373
+ assertValidBudget,
374
+ fetchBtcUsdRate,
375
+ getLastKnownBtcRate,
376
+ formatStaleness,
377
+ formatAmountBestEffort,
378
+ resolveRpcOverride,
379
+ resolveRpcHttpTransportOptions
380
+ };
@@ -45,30 +45,7 @@ function isOpaqueToken(segment) {
45
45
  return false;
46
46
  }
47
47
 
48
- // src/lib/caller-loggers.ts
49
- var callerLoggers = buildNoopLoggers();
50
- function initCallerLoggers(nextLoggers) {
51
- callerLoggers = nextLoggers;
52
- }
53
- function buildNoopLoggers() {
54
- const noopLogger = {
55
- // eslint-disable-next-line @typescript-eslint/no-empty-function -- standalone caller has no exporter
56
- info() {
57
- },
58
- async span(_name, _attrs, fn) {
59
- return fn();
60
- }
61
- };
62
- return {
63
- cashu: noopLogger,
64
- lightning: noopLogger,
65
- x402: noopLogger
66
- };
67
- }
68
-
69
48
  export {
70
49
  redactUrl,
71
- redactUrlsInText,
72
- callerLoggers,
73
- initCallerLoggers
50
+ redactUrlsInText
74
51
  };