routstrd 0.4.10 → 0.4.11
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 +33 -14
- package/SECURITY.md +0 -1
- package/SKILL.md +242 -52
- package/dist/daemon/index.js +1855 -400
- package/dist/index.js +2441 -908
- package/package.json +3 -2
- package/src/daemon/http/index.ts +5 -11
- package/src/daemon/http/request-body.ts +67 -0
- package/src/daemon/wallet/coco-client.ts +20 -5
- package/src/daemon/wallet/trusted-mints.ts +87 -0
- package/src/integrations/pi.ts +137 -32
- package/src/integrations/registry.ts +14 -0
- package/src/tui/usage/render.ts +161 -22
- package/src/TUI refactor.md +0 -113
package/dist/index.js
CHANGED
|
@@ -47459,6 +47459,47 @@ function legacyCocodPidPath() {
|
|
|
47459
47459
|
}
|
|
47460
47460
|
var init_paths = () => {};
|
|
47461
47461
|
|
|
47462
|
+
// src/daemon/wallet/trusted-mints.ts
|
|
47463
|
+
function safeNormalizeMintUrl(mintUrl) {
|
|
47464
|
+
try {
|
|
47465
|
+
return normalizeMintUrl(mintUrl);
|
|
47466
|
+
} catch {
|
|
47467
|
+
return mintUrl;
|
|
47468
|
+
}
|
|
47469
|
+
}
|
|
47470
|
+
async function seedTrustedMints(wallet, defaultMintUrl, options = {}) {
|
|
47471
|
+
const seeds = options.seeds ?? DEFAULT_TRUSTED_MINT_URLS;
|
|
47472
|
+
const target = safeNormalizeMintUrl(defaultMintUrl);
|
|
47473
|
+
const trusted = new Set(wallet.trustedMints.map(safeNormalizeMintUrl));
|
|
47474
|
+
const attempted = new Set;
|
|
47475
|
+
for (const seed of [defaultMintUrl, ...seeds]) {
|
|
47476
|
+
const mintUrl = safeNormalizeMintUrl(seed);
|
|
47477
|
+
if (attempted.has(mintUrl))
|
|
47478
|
+
continue;
|
|
47479
|
+
attempted.add(mintUrl);
|
|
47480
|
+
if (trusted.has(mintUrl))
|
|
47481
|
+
continue;
|
|
47482
|
+
const isDefault = mintUrl === target;
|
|
47483
|
+
try {
|
|
47484
|
+
options.onProgress?.(`Adding ${isDefault ? "default" : "trusted"} mint: ${mintUrl}`);
|
|
47485
|
+
await wallet.addMint(mintUrl);
|
|
47486
|
+
trusted.add(mintUrl);
|
|
47487
|
+
} catch (error) {
|
|
47488
|
+
if (isDefault)
|
|
47489
|
+
throw error;
|
|
47490
|
+
options.onError?.(`Could not add trusted mint ${mintUrl}`, error);
|
|
47491
|
+
}
|
|
47492
|
+
}
|
|
47493
|
+
}
|
|
47494
|
+
var DEFAULT_MINT_URL = "https://mint.cubabitcoin.org", DEFAULT_TRUSTED_MINT_URLS;
|
|
47495
|
+
var init_trusted_mints = __esm(() => {
|
|
47496
|
+
init_dist();
|
|
47497
|
+
DEFAULT_TRUSTED_MINT_URLS = [
|
|
47498
|
+
DEFAULT_MINT_URL,
|
|
47499
|
+
"https://mint.minibits.cash/Bitcoin"
|
|
47500
|
+
];
|
|
47501
|
+
});
|
|
47502
|
+
|
|
47462
47503
|
// src/daemon/wallet/coco-client.ts
|
|
47463
47504
|
import { Database } from "bun:sqlite";
|
|
47464
47505
|
import {
|
|
@@ -48100,10 +48141,15 @@ async function createCocoClient(options = {}) {
|
|
|
48100
48141
|
const trustedMints = await coco.mint.getAllTrustedMints();
|
|
48101
48142
|
const configuredDefault = walletConfig.defaultMintUrl;
|
|
48102
48143
|
const defaultMintUrl = normalizeMintUrl(configuredDefault || trustedMints[0]?.mintUrl || DEFAULT_MINT_URL);
|
|
48103
|
-
|
|
48104
|
-
|
|
48105
|
-
|
|
48106
|
-
}
|
|
48144
|
+
await seedTrustedMints({
|
|
48145
|
+
trustedMints: trustedMints.map((mint) => mint.mintUrl),
|
|
48146
|
+
addMint: (mintUrl) => coco.mint.addMint(mintUrl, { trusted: true })
|
|
48147
|
+
}, defaultMintUrl, {
|
|
48148
|
+
onProgress: startupProgress,
|
|
48149
|
+
onError: (message, error) => logger.warn(message, {
|
|
48150
|
+
error: error instanceof Error ? error.message : String(error)
|
|
48151
|
+
})
|
|
48152
|
+
});
|
|
48107
48153
|
walletConfig.defaultMintUrl = defaultMintUrl;
|
|
48108
48154
|
if (configuredDefault !== defaultMintUrl) {
|
|
48109
48155
|
saveConfig(walletConfig, configFile);
|
|
@@ -48518,7 +48564,7 @@ async function createCocoClient(options = {}) {
|
|
|
48518
48564
|
}
|
|
48519
48565
|
};
|
|
48520
48566
|
}
|
|
48521
|
-
var NPC_DEFAULT_BASE_URL = "https://npubx.cash", STALE_SOCKET_ERROR_CODES, STARTUP_LOG_PREFIX2 = "[routstrd:start]",
|
|
48567
|
+
var NPC_DEFAULT_BASE_URL = "https://npubx.cash", STALE_SOCKET_ERROR_CODES, STARTUP_LOG_PREFIX2 = "[routstrd:start]", surfacingRecoveryProgress = false, RECOVERY_STALL_MARKERS, SAFE_COCO_LOG_FIELDS, EXPIRED_MINT_OBSERVATION_DEADLINE_MS = 15000, PENDING_MINT_SWEEP_INTERVAL_MS = 15000, PENDING_MINT_CHECK_TIMEOUT_MS = 1e4, PENDING_MINT_SWEEP_DEADLINE_MS = 30000, PENDING_MINT_STOP_DRAIN_MS = 1e4;
|
|
48522
48568
|
var init_coco_client = __esm(() => {
|
|
48523
48569
|
init_dist();
|
|
48524
48570
|
init_dist2();
|
|
@@ -48529,6 +48575,8 @@ var init_coco_client = __esm(() => {
|
|
|
48529
48575
|
init_receive_dedup();
|
|
48530
48576
|
init_logger();
|
|
48531
48577
|
init_paths();
|
|
48578
|
+
init_trusted_mints();
|
|
48579
|
+
init_trusted_mints();
|
|
48532
48580
|
STALE_SOCKET_ERROR_CODES = new Set([
|
|
48533
48581
|
"ECONNREFUSED",
|
|
48534
48582
|
"ENOENT",
|
|
@@ -48623,6 +48671,56 @@ var init_opencode = __esm(() => {
|
|
|
48623
48671
|
import { existsSync as existsSync8, mkdirSync as mkdirSync5 } from "fs";
|
|
48624
48672
|
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
48625
48673
|
import { dirname as dirname4 } from "path";
|
|
48674
|
+
function deriveThinkingFields(model) {
|
|
48675
|
+
const reasoning = model.reasoning;
|
|
48676
|
+
if (!reasoning)
|
|
48677
|
+
return null;
|
|
48678
|
+
const supported = (reasoning.supported_efforts ?? []).filter((effort) => typeof effort === "string").map((effort) => effort.trim().toLowerCase()).filter(Boolean);
|
|
48679
|
+
if (supported.length === 0)
|
|
48680
|
+
return null;
|
|
48681
|
+
const allowed = new Set(supported);
|
|
48682
|
+
if (reasoning.mandatory === true)
|
|
48683
|
+
allowed.delete("none");
|
|
48684
|
+
const thinkingLevelMap = {};
|
|
48685
|
+
for (const level of PI_THINKING_LEVELS) {
|
|
48686
|
+
const value = THINKING_LEVEL_VALUES[level];
|
|
48687
|
+
thinkingLevelMap[level] = allowed.has(value) ? value : null;
|
|
48688
|
+
}
|
|
48689
|
+
return { reasoning: true, thinkingLevelMap };
|
|
48690
|
+
}
|
|
48691
|
+
function buildPiModelEntry(model, previous) {
|
|
48692
|
+
const entry = { id: model.id };
|
|
48693
|
+
if (model.context_length !== undefined && model.context_length > 0) {
|
|
48694
|
+
entry.contextWindow = model.context_length;
|
|
48695
|
+
}
|
|
48696
|
+
if (model.name) {
|
|
48697
|
+
entry.name = model.name;
|
|
48698
|
+
}
|
|
48699
|
+
const mods = model.architecture?.input_modalities ?? [];
|
|
48700
|
+
const input = [];
|
|
48701
|
+
if (mods.includes("text"))
|
|
48702
|
+
input.push("text");
|
|
48703
|
+
if (mods.includes("image"))
|
|
48704
|
+
input.push("image");
|
|
48705
|
+
entry.input = input;
|
|
48706
|
+
const derived = deriveThinkingFields(model);
|
|
48707
|
+
if (derived) {
|
|
48708
|
+
entry.reasoning = derived.reasoning;
|
|
48709
|
+
entry.thinkingLevelMap = derived.thinkingLevelMap;
|
|
48710
|
+
} else {
|
|
48711
|
+
if (previous?.reasoning !== undefined)
|
|
48712
|
+
entry.reasoning = previous.reasoning;
|
|
48713
|
+
if (previous?.thinkingLevelMap !== undefined) {
|
|
48714
|
+
entry.thinkingLevelMap = previous.thinkingLevelMap;
|
|
48715
|
+
}
|
|
48716
|
+
}
|
|
48717
|
+
if (isDeepSeekModel(model.id)) {
|
|
48718
|
+
entry.compat = { ...previous?.compat ?? {}, supportsDeveloperRole: false };
|
|
48719
|
+
} else if (previous?.compat !== undefined) {
|
|
48720
|
+
entry.compat = previous.compat;
|
|
48721
|
+
}
|
|
48722
|
+
return entry;
|
|
48723
|
+
}
|
|
48626
48724
|
async function installPiIntegration(config, apiKey, integrationConfig) {
|
|
48627
48725
|
const { name, configPath } = integrationConfig;
|
|
48628
48726
|
console.log(`
|
|
@@ -48651,30 +48749,7 @@ Installing routstr models in pi models.json...`);
|
|
|
48651
48749
|
return;
|
|
48652
48750
|
}
|
|
48653
48751
|
const existingModels = new Map((piConfig.providers["routstr"]?.models ?? []).map((m2) => [m2.id, m2]));
|
|
48654
|
-
const providerModels = models.map((model) =>
|
|
48655
|
-
const previous = existingModels.get(model.id);
|
|
48656
|
-
const entry = { id: model.id };
|
|
48657
|
-
if (model.context_length !== undefined && model.context_length > 0) {
|
|
48658
|
-
entry.contextWindow = model.context_length;
|
|
48659
|
-
}
|
|
48660
|
-
if (model.name) {
|
|
48661
|
-
entry.name = model.name;
|
|
48662
|
-
}
|
|
48663
|
-
const mods = model.architecture?.input_modalities ?? [];
|
|
48664
|
-
const input = [];
|
|
48665
|
-
if (mods.includes("text"))
|
|
48666
|
-
input.push("text");
|
|
48667
|
-
if (mods.includes("image"))
|
|
48668
|
-
input.push("image");
|
|
48669
|
-
entry.input = input;
|
|
48670
|
-
if (previous?.reasoning !== undefined)
|
|
48671
|
-
entry.reasoning = previous.reasoning;
|
|
48672
|
-
if (previous?.thinkingLevelMap !== undefined)
|
|
48673
|
-
entry.thinkingLevelMap = previous.thinkingLevelMap;
|
|
48674
|
-
if (previous?.compat !== undefined)
|
|
48675
|
-
entry.compat = previous.compat;
|
|
48676
|
-
return entry;
|
|
48677
|
-
});
|
|
48752
|
+
const providerModels = models.map((model) => buildPiModelEntry(model, existingModels.get(model.id)));
|
|
48678
48753
|
piConfig.providers["routstr"] = {
|
|
48679
48754
|
baseUrl,
|
|
48680
48755
|
api: "openai-completions",
|
|
@@ -48687,8 +48762,27 @@ Installing routstr models in pi models.json...`);
|
|
|
48687
48762
|
console.error("Failed to install models in pi models.json:", error);
|
|
48688
48763
|
}
|
|
48689
48764
|
}
|
|
48765
|
+
var PI_THINKING_LEVELS, THINKING_LEVEL_VALUES, isDeepSeekModel = (id) => id.startsWith("deepseek");
|
|
48690
48766
|
var init_pi = __esm(() => {
|
|
48691
48767
|
init_daemon_client();
|
|
48768
|
+
PI_THINKING_LEVELS = [
|
|
48769
|
+
"off",
|
|
48770
|
+
"minimal",
|
|
48771
|
+
"low",
|
|
48772
|
+
"medium",
|
|
48773
|
+
"high",
|
|
48774
|
+
"xhigh",
|
|
48775
|
+
"max"
|
|
48776
|
+
];
|
|
48777
|
+
THINKING_LEVEL_VALUES = {
|
|
48778
|
+
off: "none",
|
|
48779
|
+
minimal: "minimal",
|
|
48780
|
+
low: "low",
|
|
48781
|
+
medium: "medium",
|
|
48782
|
+
high: "high",
|
|
48783
|
+
xhigh: "xhigh",
|
|
48784
|
+
max: "max"
|
|
48785
|
+
};
|
|
48692
48786
|
});
|
|
48693
48787
|
|
|
48694
48788
|
// src/integrations/openclaw.ts
|
|
@@ -61014,7 +61108,7 @@ var package_default;
|
|
|
61014
61108
|
var init_package = __esm(() => {
|
|
61015
61109
|
package_default = {
|
|
61016
61110
|
name: "routstrd",
|
|
61017
|
-
version: "0.4.
|
|
61111
|
+
version: "0.4.11",
|
|
61018
61112
|
module: "src/index.ts",
|
|
61019
61113
|
type: "module",
|
|
61020
61114
|
private: false,
|
|
@@ -61037,6 +61131,7 @@ var init_package = __esm(() => {
|
|
|
61037
61131
|
monitor: "bun src/index.ts monitor",
|
|
61038
61132
|
lint: "tsc --noEmit",
|
|
61039
61133
|
test: "bun test",
|
|
61134
|
+
smoke: "scripts/smoke/chat-completions.sh",
|
|
61040
61135
|
build: "bun build src/index.ts --target=bun --outfile=dist/index.js --external better-sqlite3 && bun build src/daemon/index.ts --target=bun --outfile=dist/daemon/index.js --external better-sqlite3",
|
|
61041
61136
|
"build:binary": "bun build --compile --no-compile-autoload-dotenv --no-compile-autoload-bunfig src/index.ts --outfile=dist/routstrd",
|
|
61042
61137
|
prepublishOnly: "bun run build"
|
|
@@ -61052,7 +61147,7 @@ var init_package = __esm(() => {
|
|
|
61052
61147
|
"@cashu/cashu-ts": "^4.3.0",
|
|
61053
61148
|
"@cashu/coco-core": "^1.0.1",
|
|
61054
61149
|
"@cashu/coco-sqlite-bun": "^1.0.1",
|
|
61055
|
-
"@routstr/sdk": "^0.4.
|
|
61150
|
+
"@routstr/sdk": "^0.4.6",
|
|
61056
61151
|
"@scure/bip39": "^2.2.0",
|
|
61057
61152
|
"applesauce-core": "^5.1.0",
|
|
61058
61153
|
"applesauce-relay": "^5.1.0",
|
|
@@ -99690,7 +99785,7 @@ var init_hpke_noble = __esm(() => {
|
|
|
99690
99785
|
priv2 = Symbol();
|
|
99691
99786
|
});
|
|
99692
99787
|
|
|
99693
|
-
// node_modules/ehbp/dist/esm/protocol.js
|
|
99788
|
+
// node_modules/tinfoil/node_modules/ehbp/dist/esm/protocol.js
|
|
99694
99789
|
var PROTOCOL, HPKE_CONFIG;
|
|
99695
99790
|
var init_protocol = __esm(() => {
|
|
99696
99791
|
PROTOCOL = {
|
|
@@ -99708,7 +99803,7 @@ var init_protocol = __esm(() => {
|
|
|
99708
99803
|
};
|
|
99709
99804
|
});
|
|
99710
99805
|
|
|
99711
|
-
// node_modules/ehbp/dist/esm/derive.js
|
|
99806
|
+
// node_modules/tinfoil/node_modules/ehbp/dist/esm/derive.js
|
|
99712
99807
|
async function deriveResponseKeys(exportedSecret, requestEnc, responseNonce) {
|
|
99713
99808
|
if (exportedSecret.length !== EXPORT_LENGTH) {
|
|
99714
99809
|
throw new Error(`exported secret must be ${EXPORT_LENGTH} bytes, got ${exportedSecret.length}`);
|
|
@@ -99744,11 +99839,6 @@ function computeNonce(nonceBase, seq) {
|
|
|
99744
99839
|
}
|
|
99745
99840
|
return nonce;
|
|
99746
99841
|
}
|
|
99747
|
-
async function encryptChunk(km, seq, plaintext) {
|
|
99748
|
-
const nonce = computeNonce(km.nonceBase, seq);
|
|
99749
|
-
const ciphertext = await aead.Seal(km.keyBytes, nonce, new Uint8Array(0), plaintext);
|
|
99750
|
-
return ciphertext;
|
|
99751
|
-
}
|
|
99752
99842
|
async function decryptChunk(km, seq, ciphertext) {
|
|
99753
99843
|
const nonce = computeNonce(km.nonceBase, seq);
|
|
99754
99844
|
const plaintext = await aead.Open(km.keyBytes, nonce, new Uint8Array(0), ciphertext);
|
|
@@ -99779,7 +99869,7 @@ var init_derive = __esm(() => {
|
|
|
99779
99869
|
RESPONSE_NONCE_LABEL = new TextEncoder().encode("nonce");
|
|
99780
99870
|
});
|
|
99781
99871
|
|
|
99782
|
-
// node_modules/ehbp/dist/esm/errors.js
|
|
99872
|
+
// node_modules/tinfoil/node_modules/ehbp/dist/esm/errors.js
|
|
99783
99873
|
var EhbpError, KeyConfigMismatchError, ProtocolError, DecryptionError;
|
|
99784
99874
|
var init_errors = __esm(() => {
|
|
99785
99875
|
EhbpError = class EhbpError extends Error {
|
|
@@ -99812,7 +99902,7 @@ var init_errors = __esm(() => {
|
|
|
99812
99902
|
};
|
|
99813
99903
|
});
|
|
99814
99904
|
|
|
99815
|
-
// node_modules/ehbp/dist/esm/request-options.js
|
|
99905
|
+
// node_modules/tinfoil/node_modules/ehbp/dist/esm/request-options.js
|
|
99816
99906
|
function forwardedRequestInit(source) {
|
|
99817
99907
|
const forwarded = {};
|
|
99818
99908
|
if (!source) {
|
|
@@ -99846,7 +99936,7 @@ var init_request_options = __esm(() => {
|
|
|
99846
99936
|
];
|
|
99847
99937
|
});
|
|
99848
99938
|
|
|
99849
|
-
// node_modules/ehbp/dist/esm/identity.js
|
|
99939
|
+
// node_modules/tinfoil/node_modules/ehbp/dist/esm/identity.js
|
|
99850
99940
|
function createSuite() {
|
|
99851
99941
|
return new CipherSuite(KEM_DHKEM_X25519_HKDF_SHA256, KDF_HKDF_SHA256, AEAD_AES_256_GCM);
|
|
99852
99942
|
}
|
|
@@ -100132,7 +100222,7 @@ var init_identity = __esm(() => {
|
|
|
100132
100222
|
MAX_RESPONSE_CHUNK_BYTES = 64 * 1024 * 1024;
|
|
100133
100223
|
});
|
|
100134
100224
|
|
|
100135
|
-
// node_modules/ehbp/dist/esm/client.js
|
|
100225
|
+
// node_modules/tinfoil/node_modules/ehbp/dist/esm/client.js
|
|
100136
100226
|
class Transport {
|
|
100137
100227
|
serverIdentity;
|
|
100138
100228
|
serverHost;
|
|
@@ -100283,9 +100373,6 @@ class Transport {
|
|
|
100283
100373
|
return this.request(url2, { ...init, method: "DELETE" });
|
|
100284
100374
|
}
|
|
100285
100375
|
}
|
|
100286
|
-
async function createTransport(serverURL, init) {
|
|
100287
|
-
return Transport.create(serverURL, init);
|
|
100288
|
-
}
|
|
100289
100376
|
var MAX_PROBLEM_DETAILS_BYTES;
|
|
100290
100377
|
var init_client3 = __esm(() => {
|
|
100291
100378
|
init_identity();
|
|
@@ -100296,35 +100383,7 @@ var init_client3 = __esm(() => {
|
|
|
100296
100383
|
MAX_PROBLEM_DETAILS_BYTES = 64 * 1024;
|
|
100297
100384
|
});
|
|
100298
100385
|
|
|
100299
|
-
// node_modules/ehbp/dist/esm/index.js
|
|
100300
|
-
var exports_esm = {};
|
|
100301
|
-
__export(exports_esm, {
|
|
100302
|
-
serializeSessionRecoveryToken: () => serializeSessionRecoveryToken,
|
|
100303
|
-
hexToBytes: () => hexToBytes11,
|
|
100304
|
-
extractSessionRecoveryToken: () => extractSessionRecoveryToken,
|
|
100305
|
-
encryptChunk: () => encryptChunk,
|
|
100306
|
-
deserializeSessionRecoveryToken: () => deserializeSessionRecoveryToken,
|
|
100307
|
-
deriveResponseKeys: () => deriveResponseKeys,
|
|
100308
|
-
decryptResponseWithToken: () => decryptResponseWithToken,
|
|
100309
|
-
decryptChunk: () => decryptChunk,
|
|
100310
|
-
createTransport: () => createTransport,
|
|
100311
|
-
computeNonce: () => computeNonce,
|
|
100312
|
-
bytesToHex: () => bytesToHex11,
|
|
100313
|
-
Transport: () => Transport,
|
|
100314
|
-
RESPONSE_NONCE_LENGTH: () => RESPONSE_NONCE_LENGTH,
|
|
100315
|
-
ProtocolError: () => ProtocolError,
|
|
100316
|
-
PROTOCOL: () => PROTOCOL,
|
|
100317
|
-
KeyConfigMismatchError: () => KeyConfigMismatchError,
|
|
100318
|
-
Identity: () => Identity,
|
|
100319
|
-
HPKE_REQUEST_INFO: () => HPKE_REQUEST_INFO,
|
|
100320
|
-
HPKE_CONFIG: () => HPKE_CONFIG,
|
|
100321
|
-
EhbpError: () => EhbpError,
|
|
100322
|
-
EXPORT_LENGTH: () => EXPORT_LENGTH,
|
|
100323
|
-
EXPORT_LABEL: () => EXPORT_LABEL,
|
|
100324
|
-
DecryptionError: () => DecryptionError,
|
|
100325
|
-
AES_GCM_NONCE_LENGTH: () => AES_GCM_NONCE_LENGTH,
|
|
100326
|
-
AES256_KEY_LENGTH: () => AES256_KEY_LENGTH
|
|
100327
|
-
});
|
|
100386
|
+
// node_modules/tinfoil/node_modules/ehbp/dist/esm/index.js
|
|
100328
100387
|
var init_esm5 = __esm(() => {
|
|
100329
100388
|
init_identity();
|
|
100330
100389
|
init_identity();
|
|
@@ -130139,6 +130198,650 @@ var init_dist16 = __esm(() => {
|
|
|
130139
130198
|
init_openai();
|
|
130140
130199
|
});
|
|
130141
130200
|
|
|
130201
|
+
// node_modules/ehbp/dist/esm/protocol.js
|
|
130202
|
+
var PROTOCOL2, HPKE_CONFIG2;
|
|
130203
|
+
var init_protocol2 = __esm(() => {
|
|
130204
|
+
PROTOCOL2 = {
|
|
130205
|
+
ENCAPSULATED_KEY_HEADER: "Ehbp-Encapsulated-Key",
|
|
130206
|
+
RESPONSE_NONCE_HEADER: "Ehbp-Response-Nonce",
|
|
130207
|
+
KEYS_MEDIA_TYPE: "application/ohttp-keys",
|
|
130208
|
+
KEYS_PATH: "/.well-known/hpke-keys",
|
|
130209
|
+
PROBLEM_JSON_MEDIA_TYPE: "application/problem+json",
|
|
130210
|
+
KEY_CONFIG_PROBLEM_TYPE: "urn:ietf:params:ehbp:error:key-config"
|
|
130211
|
+
};
|
|
130212
|
+
HPKE_CONFIG2 = {
|
|
130213
|
+
KEM: 32,
|
|
130214
|
+
KDF: 1,
|
|
130215
|
+
AEAD: 2
|
|
130216
|
+
};
|
|
130217
|
+
});
|
|
130218
|
+
|
|
130219
|
+
// node_modules/ehbp/dist/esm/derive.js
|
|
130220
|
+
async function deriveResponseKeys2(exportedSecret, requestEnc, responseNonce) {
|
|
130221
|
+
if (exportedSecret.length !== EXPORT_LENGTH2) {
|
|
130222
|
+
throw new Error(`exported secret must be ${EXPORT_LENGTH2} bytes, got ${exportedSecret.length}`);
|
|
130223
|
+
}
|
|
130224
|
+
if (requestEnc.length !== REQUEST_ENC_LENGTH2) {
|
|
130225
|
+
throw new Error(`request enc must be ${REQUEST_ENC_LENGTH2} bytes, got ${requestEnc.length}`);
|
|
130226
|
+
}
|
|
130227
|
+
if (responseNonce.length !== RESPONSE_NONCE_LENGTH2) {
|
|
130228
|
+
throw new Error(`response nonce must be ${RESPONSE_NONCE_LENGTH2} bytes, got ${responseNonce.length}`);
|
|
130229
|
+
}
|
|
130230
|
+
const salt = new Uint8Array(requestEnc.length + responseNonce.length);
|
|
130231
|
+
salt.set(requestEnc, 0);
|
|
130232
|
+
salt.set(responseNonce, requestEnc.length);
|
|
130233
|
+
const prk = await kdf2.Extract(salt, exportedSecret);
|
|
130234
|
+
const keyBytes = await kdf2.Expand(prk, RESPONSE_KEY_LABEL2, AES256_KEY_LENGTH2);
|
|
130235
|
+
const nonceBase = await kdf2.Expand(prk, RESPONSE_NONCE_LABEL2, AES_GCM_NONCE_LENGTH2);
|
|
130236
|
+
return { keyBytes, nonceBase };
|
|
130237
|
+
}
|
|
130238
|
+
function computeNonce2(nonceBase, seq) {
|
|
130239
|
+
if (nonceBase.length !== AES_GCM_NONCE_LENGTH2) {
|
|
130240
|
+
throw new Error(`nonce base must be ${AES_GCM_NONCE_LENGTH2} bytes`);
|
|
130241
|
+
}
|
|
130242
|
+
if (!Number.isInteger(seq) || seq < 0 || seq >= 4294967296) {
|
|
130243
|
+
throw new Error(`sequence number must be an integer in range [0, 2^32): got ${seq}`);
|
|
130244
|
+
}
|
|
130245
|
+
const nonce = new Uint8Array(AES_GCM_NONCE_LENGTH2);
|
|
130246
|
+
nonce.set(nonceBase);
|
|
130247
|
+
for (let i6 = 0;i6 < 8; i6++) {
|
|
130248
|
+
const shift = i6 * 8;
|
|
130249
|
+
if (shift < 32) {
|
|
130250
|
+
nonce[AES_GCM_NONCE_LENGTH2 - 1 - i6] ^= seq >>> shift & 255;
|
|
130251
|
+
}
|
|
130252
|
+
}
|
|
130253
|
+
return nonce;
|
|
130254
|
+
}
|
|
130255
|
+
async function encryptChunk2(km, seq, plaintext) {
|
|
130256
|
+
const nonce = computeNonce2(km.nonceBase, seq);
|
|
130257
|
+
const ciphertext = await aead2.Seal(km.keyBytes, nonce, new Uint8Array(0), plaintext);
|
|
130258
|
+
return ciphertext;
|
|
130259
|
+
}
|
|
130260
|
+
async function decryptChunk2(km, seq, ciphertext) {
|
|
130261
|
+
const nonce = computeNonce2(km.nonceBase, seq);
|
|
130262
|
+
const plaintext = await aead2.Open(km.keyBytes, nonce, new Uint8Array(0), ciphertext);
|
|
130263
|
+
return plaintext;
|
|
130264
|
+
}
|
|
130265
|
+
function hexToBytes13(hex7) {
|
|
130266
|
+
if (hex7.length % 2 !== 0) {
|
|
130267
|
+
throw new Error("Hex string must have even length");
|
|
130268
|
+
}
|
|
130269
|
+
if (!/^[0-9a-fA-F]*$/.test(hex7)) {
|
|
130270
|
+
throw new Error("Invalid hex character");
|
|
130271
|
+
}
|
|
130272
|
+
const bytes6 = new Uint8Array(hex7.length / 2);
|
|
130273
|
+
for (let i6 = 0;i6 < bytes6.length; i6++) {
|
|
130274
|
+
bytes6[i6] = parseInt(hex7.substring(i6 * 2, i6 * 2 + 2), 16);
|
|
130275
|
+
}
|
|
130276
|
+
return bytes6;
|
|
130277
|
+
}
|
|
130278
|
+
function bytesToHex15(bytes6) {
|
|
130279
|
+
return Array.from(bytes6).map((b2) => b2.toString(16).padStart(2, "0")).join("");
|
|
130280
|
+
}
|
|
130281
|
+
var kdf2, aead2, HPKE_REQUEST_INFO2 = "ehbp request", EXPORT_LABEL2 = "ehbp response", EXPORT_LENGTH2 = 32, RESPONSE_NONCE_LENGTH2 = 32, AES256_KEY_LENGTH2 = 32, AES_GCM_NONCE_LENGTH2 = 12, REQUEST_ENC_LENGTH2 = 32, RESPONSE_KEY_LABEL2, RESPONSE_NONCE_LABEL2;
|
|
130282
|
+
var init_derive2 = __esm(() => {
|
|
130283
|
+
init_hpke_noble();
|
|
130284
|
+
kdf2 = KDF_HKDF_SHA256();
|
|
130285
|
+
aead2 = AEAD_AES_256_GCM();
|
|
130286
|
+
RESPONSE_KEY_LABEL2 = new TextEncoder().encode("key");
|
|
130287
|
+
RESPONSE_NONCE_LABEL2 = new TextEncoder().encode("nonce");
|
|
130288
|
+
});
|
|
130289
|
+
|
|
130290
|
+
// node_modules/ehbp/dist/esm/errors.js
|
|
130291
|
+
var EhbpError2, KeyConfigMismatchError2, ProtocolError2, DecryptionError2;
|
|
130292
|
+
var init_errors6 = __esm(() => {
|
|
130293
|
+
EhbpError2 = class EhbpError2 extends Error {
|
|
130294
|
+
constructor(message, options) {
|
|
130295
|
+
super(message);
|
|
130296
|
+
this.name = "EhbpError";
|
|
130297
|
+
if (options?.cause)
|
|
130298
|
+
this.cause = options.cause;
|
|
130299
|
+
}
|
|
130300
|
+
};
|
|
130301
|
+
KeyConfigMismatchError2 = class KeyConfigMismatchError2 extends EhbpError2 {
|
|
130302
|
+
title;
|
|
130303
|
+
constructor(title) {
|
|
130304
|
+
super(title || "Server key configuration mismatch");
|
|
130305
|
+
this.name = "KeyConfigMismatchError";
|
|
130306
|
+
this.title = title || "";
|
|
130307
|
+
}
|
|
130308
|
+
};
|
|
130309
|
+
ProtocolError2 = class ProtocolError2 extends EhbpError2 {
|
|
130310
|
+
constructor(message, options) {
|
|
130311
|
+
super(message, options);
|
|
130312
|
+
this.name = "ProtocolError";
|
|
130313
|
+
}
|
|
130314
|
+
};
|
|
130315
|
+
DecryptionError2 = class DecryptionError2 extends EhbpError2 {
|
|
130316
|
+
constructor(message, options) {
|
|
130317
|
+
super(message, options);
|
|
130318
|
+
this.name = "DecryptionError";
|
|
130319
|
+
}
|
|
130320
|
+
};
|
|
130321
|
+
});
|
|
130322
|
+
|
|
130323
|
+
// node_modules/ehbp/dist/esm/request-options.js
|
|
130324
|
+
function forwardedRequestInit2(source) {
|
|
130325
|
+
const forwarded = {};
|
|
130326
|
+
if (!source) {
|
|
130327
|
+
return forwarded;
|
|
130328
|
+
}
|
|
130329
|
+
const record2 = source;
|
|
130330
|
+
const target = forwarded;
|
|
130331
|
+
for (const key of FORWARDED_INIT_KEYS2) {
|
|
130332
|
+
const value = record2[key];
|
|
130333
|
+
if (value !== undefined) {
|
|
130334
|
+
target[key] = value;
|
|
130335
|
+
}
|
|
130336
|
+
}
|
|
130337
|
+
if (forwarded.mode === "navigate") {
|
|
130338
|
+
delete forwarded.mode;
|
|
130339
|
+
}
|
|
130340
|
+
return forwarded;
|
|
130341
|
+
}
|
|
130342
|
+
var FORWARDED_INIT_KEYS2;
|
|
130343
|
+
var init_request_options2 = __esm(() => {
|
|
130344
|
+
FORWARDED_INIT_KEYS2 = [
|
|
130345
|
+
"cache",
|
|
130346
|
+
"credentials",
|
|
130347
|
+
"integrity",
|
|
130348
|
+
"keepalive",
|
|
130349
|
+
"mode",
|
|
130350
|
+
"redirect",
|
|
130351
|
+
"referrer",
|
|
130352
|
+
"referrerPolicy",
|
|
130353
|
+
"signal"
|
|
130354
|
+
];
|
|
130355
|
+
});
|
|
130356
|
+
|
|
130357
|
+
// node_modules/ehbp/dist/esm/identity.js
|
|
130358
|
+
function createSuite2() {
|
|
130359
|
+
return new CipherSuite(KEM_DHKEM_X25519_HKDF_SHA256, KDF_HKDF_SHA256, AEAD_AES_256_GCM);
|
|
130360
|
+
}
|
|
130361
|
+
|
|
130362
|
+
class Identity3 {
|
|
130363
|
+
suite;
|
|
130364
|
+
publicKey;
|
|
130365
|
+
privateKey;
|
|
130366
|
+
constructor(suite, publicKey, privateKey) {
|
|
130367
|
+
this.suite = suite;
|
|
130368
|
+
this.publicKey = publicKey;
|
|
130369
|
+
this.privateKey = privateKey;
|
|
130370
|
+
}
|
|
130371
|
+
static async generate() {
|
|
130372
|
+
const suite = createSuite2();
|
|
130373
|
+
const { publicKey, privateKey } = await suite.GenerateKeyPair(true);
|
|
130374
|
+
return new Identity3(suite, publicKey, privateKey);
|
|
130375
|
+
}
|
|
130376
|
+
static async fromJSON(json3) {
|
|
130377
|
+
const data = JSON.parse(json3);
|
|
130378
|
+
const suite = createSuite2();
|
|
130379
|
+
const publicKey = await suite.DeserializePublicKey(new Uint8Array(data.publicKey));
|
|
130380
|
+
const privateKey = await suite.DeserializePrivateKey(new Uint8Array(data.privateKey), true);
|
|
130381
|
+
return new Identity3(suite, publicKey, privateKey);
|
|
130382
|
+
}
|
|
130383
|
+
async toJSON() {
|
|
130384
|
+
const publicKeyBytes = await this.suite.SerializePublicKey(this.publicKey);
|
|
130385
|
+
const privateKeyBytes = await this.suite.SerializePrivateKey(this.privateKey);
|
|
130386
|
+
return JSON.stringify({
|
|
130387
|
+
publicKey: Array.from(publicKeyBytes),
|
|
130388
|
+
privateKey: Array.from(privateKeyBytes)
|
|
130389
|
+
});
|
|
130390
|
+
}
|
|
130391
|
+
getPublicKey() {
|
|
130392
|
+
return this.publicKey;
|
|
130393
|
+
}
|
|
130394
|
+
async getPublicKeyHex() {
|
|
130395
|
+
const exported = await this.suite.SerializePublicKey(this.publicKey);
|
|
130396
|
+
return bytesToHex15(exported);
|
|
130397
|
+
}
|
|
130398
|
+
getPrivateKey() {
|
|
130399
|
+
return this.privateKey;
|
|
130400
|
+
}
|
|
130401
|
+
async marshalConfig() {
|
|
130402
|
+
const kemId = HPKE_CONFIG2.KEM;
|
|
130403
|
+
const kdfId = HPKE_CONFIG2.KDF;
|
|
130404
|
+
const aeadId = HPKE_CONFIG2.AEAD;
|
|
130405
|
+
const publicKeyBytes = await this.suite.SerializePublicKey(this.publicKey);
|
|
130406
|
+
const keyId = 0;
|
|
130407
|
+
const publicKeySize = publicKeyBytes.length;
|
|
130408
|
+
const cipherSuitesSize = 2 + 2;
|
|
130409
|
+
const buffer = new Uint8Array(1 + 2 + publicKeySize + 2 + cipherSuitesSize);
|
|
130410
|
+
let offset = 0;
|
|
130411
|
+
buffer[offset++] = keyId;
|
|
130412
|
+
buffer[offset++] = kemId >> 8 & 255;
|
|
130413
|
+
buffer[offset++] = kemId & 255;
|
|
130414
|
+
buffer.set(publicKeyBytes, offset);
|
|
130415
|
+
offset += publicKeySize;
|
|
130416
|
+
buffer[offset++] = cipherSuitesSize >> 8 & 255;
|
|
130417
|
+
buffer[offset++] = cipherSuitesSize & 255;
|
|
130418
|
+
buffer[offset++] = kdfId >> 8 & 255;
|
|
130419
|
+
buffer[offset++] = kdfId & 255;
|
|
130420
|
+
buffer[offset++] = aeadId >> 8 & 255;
|
|
130421
|
+
buffer[offset++] = aeadId & 255;
|
|
130422
|
+
return buffer;
|
|
130423
|
+
}
|
|
130424
|
+
static async unmarshalPublicConfig(data) {
|
|
130425
|
+
let offset = 0;
|
|
130426
|
+
const keyId = data[offset++];
|
|
130427
|
+
const kemId = data[offset++] << 8 | data[offset++];
|
|
130428
|
+
const publicKeySize = 32;
|
|
130429
|
+
const publicKeyBytes = data.slice(offset, offset + publicKeySize);
|
|
130430
|
+
offset += publicKeySize;
|
|
130431
|
+
const cipherSuitesLength = data[offset++] << 8 | data[offset++];
|
|
130432
|
+
const suites = [];
|
|
130433
|
+
const cipherSuitesEnd = offset + cipherSuitesLength;
|
|
130434
|
+
while (offset < cipherSuitesEnd) {
|
|
130435
|
+
const kdfId = data[offset++] << 8 | data[offset++];
|
|
130436
|
+
const aeadId = data[offset++] << 8 | data[offset++];
|
|
130437
|
+
suites.push({ kdfId, aeadId });
|
|
130438
|
+
}
|
|
130439
|
+
if (suites.length === 0) {
|
|
130440
|
+
throw new ProtocolError2("No cipher suites found in config");
|
|
130441
|
+
}
|
|
130442
|
+
const firstSuite = suites[0];
|
|
130443
|
+
if (firstSuite.kdfId !== HPKE_CONFIG2.KDF || firstSuite.aeadId !== HPKE_CONFIG2.AEAD) {
|
|
130444
|
+
throw new ProtocolError2(`Unsupported cipher suite: KDF=0x${firstSuite.kdfId.toString(16)}, AEAD=0x${firstSuite.aeadId.toString(16)}`);
|
|
130445
|
+
}
|
|
130446
|
+
return Identity3.fromPublicKeyBytes(publicKeyBytes);
|
|
130447
|
+
}
|
|
130448
|
+
static async fromPublicKeyHex(publicKeyHex) {
|
|
130449
|
+
const publicKeyBytes = hexToBytes13(publicKeyHex);
|
|
130450
|
+
if (publicKeyBytes.length !== 32) {
|
|
130451
|
+
throw new ProtocolError2(`Invalid public key length: expected 32, got ${publicKeyBytes.length}`);
|
|
130452
|
+
}
|
|
130453
|
+
return Identity3.fromPublicKeyBytes(publicKeyBytes);
|
|
130454
|
+
}
|
|
130455
|
+
static async fromPublicKeyBytes(publicKeyBytes) {
|
|
130456
|
+
const suite = createSuite2();
|
|
130457
|
+
const publicKey = await suite.DeserializePublicKey(publicKeyBytes);
|
|
130458
|
+
const placeholderPrivateKey = await suite.DeserializePrivateKey(new Uint8Array(32), false);
|
|
130459
|
+
return new Identity3(suite, publicKey, placeholderPrivateKey);
|
|
130460
|
+
}
|
|
130461
|
+
async encryptRequestWithContext(request) {
|
|
130462
|
+
const body = await request.arrayBuffer();
|
|
130463
|
+
if (body.byteLength === 0) {
|
|
130464
|
+
return {
|
|
130465
|
+
request: new Request(request.url, {
|
|
130466
|
+
...forwardedRequestInit2(request),
|
|
130467
|
+
method: request.method,
|
|
130468
|
+
headers: request.headers,
|
|
130469
|
+
body: null
|
|
130470
|
+
}),
|
|
130471
|
+
context: null
|
|
130472
|
+
};
|
|
130473
|
+
}
|
|
130474
|
+
const infoBytes = new TextEncoder().encode(HPKE_REQUEST_INFO2);
|
|
130475
|
+
const { encapsulatedSecret, ctx } = await this.suite.SetupSender(this.publicKey, {
|
|
130476
|
+
info: infoBytes
|
|
130477
|
+
});
|
|
130478
|
+
const context = {
|
|
130479
|
+
senderContext: ctx,
|
|
130480
|
+
requestEnc: encapsulatedSecret
|
|
130481
|
+
};
|
|
130482
|
+
const headers = new Headers(request.headers);
|
|
130483
|
+
headers.set(PROTOCOL2.ENCAPSULATED_KEY_HEADER, bytesToHex15(context.requestEnc));
|
|
130484
|
+
const encrypted = await ctx.Seal(new Uint8Array(body));
|
|
130485
|
+
const chunkLength = new Uint8Array(4);
|
|
130486
|
+
new DataView(chunkLength.buffer).setUint32(0, encrypted.byteLength, false);
|
|
130487
|
+
const chunkedData = new Uint8Array(4 + encrypted.byteLength);
|
|
130488
|
+
chunkedData.set(chunkLength, 0);
|
|
130489
|
+
chunkedData.set(encrypted, 4);
|
|
130490
|
+
return {
|
|
130491
|
+
request: new Request(request.url, {
|
|
130492
|
+
...forwardedRequestInit2(request),
|
|
130493
|
+
method: request.method,
|
|
130494
|
+
headers,
|
|
130495
|
+
body: chunkedData,
|
|
130496
|
+
duplex: "half"
|
|
130497
|
+
}),
|
|
130498
|
+
context
|
|
130499
|
+
};
|
|
130500
|
+
}
|
|
130501
|
+
async decryptResponseWithContext(response, context) {
|
|
130502
|
+
const token = await extractSessionRecoveryToken2(context);
|
|
130503
|
+
return decryptResponseWithToken2(response, token);
|
|
130504
|
+
}
|
|
130505
|
+
}
|
|
130506
|
+
async function extractSessionRecoveryToken2(context) {
|
|
130507
|
+
const exportLabelBytes = new TextEncoder().encode(EXPORT_LABEL2);
|
|
130508
|
+
const exportedSecret = new Uint8Array(await context.senderContext.Export(exportLabelBytes, EXPORT_LENGTH2));
|
|
130509
|
+
return {
|
|
130510
|
+
exportedSecret,
|
|
130511
|
+
requestEnc: new Uint8Array(context.requestEnc)
|
|
130512
|
+
};
|
|
130513
|
+
}
|
|
130514
|
+
function serializeSessionRecoveryToken2(token) {
|
|
130515
|
+
return JSON.stringify({
|
|
130516
|
+
exportedSecret: bytesToHex15(token.exportedSecret),
|
|
130517
|
+
requestEnc: bytesToHex15(token.requestEnc)
|
|
130518
|
+
});
|
|
130519
|
+
}
|
|
130520
|
+
function deserializeSessionRecoveryToken2(json3) {
|
|
130521
|
+
const parsed = JSON.parse(json3);
|
|
130522
|
+
return {
|
|
130523
|
+
exportedSecret: hexToBytes13(parsed.exportedSecret),
|
|
130524
|
+
requestEnc: hexToBytes13(parsed.requestEnc)
|
|
130525
|
+
};
|
|
130526
|
+
}
|
|
130527
|
+
async function decryptResponseWithToken2(response, token, onStreamError, onStreamComplete) {
|
|
130528
|
+
const responseNonceHex = response.headers.get(PROTOCOL2.RESPONSE_NONCE_HEADER);
|
|
130529
|
+
if (!response.body && !responseNonceHex) {
|
|
130530
|
+
return response;
|
|
130531
|
+
}
|
|
130532
|
+
if (!responseNonceHex) {
|
|
130533
|
+
throw new ProtocolError2(`Missing ${PROTOCOL2.RESPONSE_NONCE_HEADER} header`);
|
|
130534
|
+
}
|
|
130535
|
+
const responseNonce = hexToBytes13(responseNonceHex);
|
|
130536
|
+
if (responseNonce.length !== RESPONSE_NONCE_LENGTH2) {
|
|
130537
|
+
throw new ProtocolError2(`Invalid response nonce length`);
|
|
130538
|
+
}
|
|
130539
|
+
if (!response.body) {
|
|
130540
|
+
onStreamComplete?.();
|
|
130541
|
+
return response;
|
|
130542
|
+
}
|
|
130543
|
+
const km = await deriveResponseKeys2(token.exportedSecret, token.requestEnc, responseNonce);
|
|
130544
|
+
const decryptedStream = createDecryptStream2(response.body, km, onStreamError, onStreamComplete);
|
|
130545
|
+
const headers = new Headers(response.headers);
|
|
130546
|
+
headers.delete("content-length");
|
|
130547
|
+
headers.delete("transfer-encoding");
|
|
130548
|
+
return new Response(decryptedStream, {
|
|
130549
|
+
status: response.status,
|
|
130550
|
+
statusText: response.statusText,
|
|
130551
|
+
headers
|
|
130552
|
+
});
|
|
130553
|
+
}
|
|
130554
|
+
function createDecryptStream2(body, km, onStreamError, onStreamComplete) {
|
|
130555
|
+
let buffer = new Uint8Array(0);
|
|
130556
|
+
let seq = 0;
|
|
130557
|
+
const reader = body.getReader();
|
|
130558
|
+
let consumerCancelled = false;
|
|
130559
|
+
return new ReadableStream({
|
|
130560
|
+
async pull(controller) {
|
|
130561
|
+
const fail = (error53) => {
|
|
130562
|
+
try {
|
|
130563
|
+
onStreamError?.();
|
|
130564
|
+
} catch {}
|
|
130565
|
+
try {
|
|
130566
|
+
controller.error(error53);
|
|
130567
|
+
} finally {
|
|
130568
|
+
reader.cancel(error53).catch(() => {});
|
|
130569
|
+
}
|
|
130570
|
+
};
|
|
130571
|
+
while (true) {
|
|
130572
|
+
if (buffer.length >= 4) {
|
|
130573
|
+
const chunkLength = (buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]) >>> 0;
|
|
130574
|
+
if (chunkLength === 0) {
|
|
130575
|
+
buffer = buffer.slice(4);
|
|
130576
|
+
continue;
|
|
130577
|
+
}
|
|
130578
|
+
if (chunkLength > MAX_RESPONSE_CHUNK_BYTES2) {
|
|
130579
|
+
fail(new ProtocolError2("response chunk exceeds maximum allowed size"));
|
|
130580
|
+
return;
|
|
130581
|
+
}
|
|
130582
|
+
if (buffer.length >= 4 + chunkLength) {
|
|
130583
|
+
const ciphertext = buffer.slice(4, 4 + chunkLength);
|
|
130584
|
+
buffer = buffer.slice(4 + chunkLength);
|
|
130585
|
+
try {
|
|
130586
|
+
const plaintext = await decryptChunk2(km, seq++, ciphertext);
|
|
130587
|
+
controller.enqueue(plaintext);
|
|
130588
|
+
return;
|
|
130589
|
+
} catch (error53) {
|
|
130590
|
+
fail(new DecryptionError2(`Decryption failed at chunk ${seq - 1}`, { cause: error53 }));
|
|
130591
|
+
return;
|
|
130592
|
+
}
|
|
130593
|
+
}
|
|
130594
|
+
}
|
|
130595
|
+
let result;
|
|
130596
|
+
try {
|
|
130597
|
+
result = await reader.read();
|
|
130598
|
+
} catch (error53) {
|
|
130599
|
+
if (consumerCancelled) {
|
|
130600
|
+
return;
|
|
130601
|
+
}
|
|
130602
|
+
fail(error53 instanceof Error ? error53 : new Error("Encrypted response read failed", {
|
|
130603
|
+
cause: error53
|
|
130604
|
+
}));
|
|
130605
|
+
return;
|
|
130606
|
+
}
|
|
130607
|
+
const { done, value } = result;
|
|
130608
|
+
if (done) {
|
|
130609
|
+
if (consumerCancelled) {
|
|
130610
|
+
return;
|
|
130611
|
+
}
|
|
130612
|
+
if (buffer.length !== 0) {
|
|
130613
|
+
fail(new ProtocolError2("truncated encrypted response chunk"));
|
|
130614
|
+
} else {
|
|
130615
|
+
onStreamComplete?.();
|
|
130616
|
+
controller.close();
|
|
130617
|
+
}
|
|
130618
|
+
return;
|
|
130619
|
+
}
|
|
130620
|
+
const newBuffer = new Uint8Array(buffer.length + value.length);
|
|
130621
|
+
newBuffer.set(buffer);
|
|
130622
|
+
newBuffer.set(value, buffer.length);
|
|
130623
|
+
buffer = newBuffer;
|
|
130624
|
+
}
|
|
130625
|
+
},
|
|
130626
|
+
cancel(reason) {
|
|
130627
|
+
consumerCancelled = true;
|
|
130628
|
+
return reader.cancel(reason);
|
|
130629
|
+
}
|
|
130630
|
+
});
|
|
130631
|
+
}
|
|
130632
|
+
var MAX_RESPONSE_CHUNK_BYTES2;
|
|
130633
|
+
var init_identity2 = __esm(() => {
|
|
130634
|
+
init_hpke();
|
|
130635
|
+
init_hpke_noble();
|
|
130636
|
+
init_protocol2();
|
|
130637
|
+
init_derive2();
|
|
130638
|
+
init_errors6();
|
|
130639
|
+
init_request_options2();
|
|
130640
|
+
MAX_RESPONSE_CHUNK_BYTES2 = 64 * 1024 * 1024;
|
|
130641
|
+
});
|
|
130642
|
+
|
|
130643
|
+
// node_modules/ehbp/dist/esm/client.js
|
|
130644
|
+
class Transport2 {
|
|
130645
|
+
serverIdentity;
|
|
130646
|
+
serverHost;
|
|
130647
|
+
_lastSessionRecoveryToken;
|
|
130648
|
+
requestGeneration = 0;
|
|
130649
|
+
constructor(serverIdentity, serverHost) {
|
|
130650
|
+
this.serverIdentity = serverIdentity;
|
|
130651
|
+
this.serverHost = serverHost;
|
|
130652
|
+
}
|
|
130653
|
+
getSessionRecoveryToken() {
|
|
130654
|
+
if (!this._lastSessionRecoveryToken) {
|
|
130655
|
+
throw new Error("No session recovery token available \u2014 no request has been made yet");
|
|
130656
|
+
}
|
|
130657
|
+
return this._lastSessionRecoveryToken;
|
|
130658
|
+
}
|
|
130659
|
+
static async create(serverURL, init) {
|
|
130660
|
+
const url3 = new URL(serverURL);
|
|
130661
|
+
const serverHost = url3.host;
|
|
130662
|
+
const keysURL = new URL(PROTOCOL2.KEYS_PATH, serverURL);
|
|
130663
|
+
const response = await fetch(keysURL.toString(), init);
|
|
130664
|
+
if (!response.ok) {
|
|
130665
|
+
throw new Error(`Failed to get server public key: ${response.status}`);
|
|
130666
|
+
}
|
|
130667
|
+
const contentType = response.headers.get("content-type");
|
|
130668
|
+
if (contentType !== PROTOCOL2.KEYS_MEDIA_TYPE) {
|
|
130669
|
+
throw new Error(`Invalid content type: ${contentType}`);
|
|
130670
|
+
}
|
|
130671
|
+
const keysData = new Uint8Array(await response.arrayBuffer());
|
|
130672
|
+
const serverIdentity = await Identity3.unmarshalPublicConfig(keysData);
|
|
130673
|
+
return new Transport2(serverIdentity, serverHost);
|
|
130674
|
+
}
|
|
130675
|
+
static isProblemJSONContentType(contentType) {
|
|
130676
|
+
if (!contentType) {
|
|
130677
|
+
return false;
|
|
130678
|
+
}
|
|
130679
|
+
const mediaType = contentType.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
130680
|
+
return mediaType === PROTOCOL2.PROBLEM_JSON_MEDIA_TYPE;
|
|
130681
|
+
}
|
|
130682
|
+
static async checkKeyConfigMismatch(response) {
|
|
130683
|
+
if (response.status !== 422)
|
|
130684
|
+
return;
|
|
130685
|
+
if (!Transport2.isProblemJSONContentType(response.headers.get("content-type")))
|
|
130686
|
+
return;
|
|
130687
|
+
let problem;
|
|
130688
|
+
try {
|
|
130689
|
+
const clone2 = response.clone();
|
|
130690
|
+
if (!clone2.body)
|
|
130691
|
+
return;
|
|
130692
|
+
const reader = clone2.body.getReader();
|
|
130693
|
+
const chunks = [];
|
|
130694
|
+
let length2 = 0;
|
|
130695
|
+
while (true) {
|
|
130696
|
+
const { done, value } = await reader.read();
|
|
130697
|
+
if (done)
|
|
130698
|
+
break;
|
|
130699
|
+
length2 += value.byteLength;
|
|
130700
|
+
if (length2 > MAX_PROBLEM_DETAILS_BYTES2) {
|
|
130701
|
+
reader.cancel().catch(() => {});
|
|
130702
|
+
return;
|
|
130703
|
+
}
|
|
130704
|
+
chunks.push(value);
|
|
130705
|
+
}
|
|
130706
|
+
const body = new Uint8Array(length2);
|
|
130707
|
+
let offset = 0;
|
|
130708
|
+
for (const chunk of chunks) {
|
|
130709
|
+
body.set(chunk, offset);
|
|
130710
|
+
offset += chunk.byteLength;
|
|
130711
|
+
}
|
|
130712
|
+
problem = JSON.parse(new TextDecoder().decode(body));
|
|
130713
|
+
} catch {
|
|
130714
|
+
return;
|
|
130715
|
+
}
|
|
130716
|
+
if (problem?.type === PROTOCOL2.KEY_CONFIG_PROBLEM_TYPE) {
|
|
130717
|
+
throw new KeyConfigMismatchError2(typeof problem.title === "string" ? problem.title : undefined);
|
|
130718
|
+
}
|
|
130719
|
+
}
|
|
130720
|
+
static async shouldDecryptResponse(response) {
|
|
130721
|
+
if (response.headers.has(PROTOCOL2.RESPONSE_NONCE_HEADER)) {
|
|
130722
|
+
return true;
|
|
130723
|
+
}
|
|
130724
|
+
await Transport2.checkKeyConfigMismatch(response);
|
|
130725
|
+
if (!response.ok) {
|
|
130726
|
+
return false;
|
|
130727
|
+
}
|
|
130728
|
+
throw new ProtocolError2(`Missing ${PROTOCOL2.RESPONSE_NONCE_HEADER} header`);
|
|
130729
|
+
}
|
|
130730
|
+
getServerIdentity() {
|
|
130731
|
+
return this.serverIdentity;
|
|
130732
|
+
}
|
|
130733
|
+
getServerPublicKey() {
|
|
130734
|
+
return this.serverIdentity.getPublicKey();
|
|
130735
|
+
}
|
|
130736
|
+
async getServerPublicKeyHex() {
|
|
130737
|
+
return this.serverIdentity.getPublicKeyHex();
|
|
130738
|
+
}
|
|
130739
|
+
async request(input, init) {
|
|
130740
|
+
const generation = ++this.requestGeneration;
|
|
130741
|
+
this._lastSessionRecoveryToken = undefined;
|
|
130742
|
+
const inputUrl = input instanceof Request ? input.url : String(input);
|
|
130743
|
+
if (inputUrl.startsWith("data:") || inputUrl.startsWith("blob:")) {
|
|
130744
|
+
return fetch(input, init);
|
|
130745
|
+
}
|
|
130746
|
+
const normalizedRequest = new Request(input, init);
|
|
130747
|
+
const requestBodyBytes = await normalizedRequest.arrayBuffer();
|
|
130748
|
+
const requestBody = requestBodyBytes.byteLength > 0 ? requestBodyBytes : null;
|
|
130749
|
+
const url3 = new URL(normalizedRequest.url);
|
|
130750
|
+
url3.host = this.serverHost;
|
|
130751
|
+
const request = new Request(url3.toString(), {
|
|
130752
|
+
...forwardedRequestInit2(normalizedRequest),
|
|
130753
|
+
method: normalizedRequest.method,
|
|
130754
|
+
headers: normalizedRequest.headers,
|
|
130755
|
+
body: requestBody,
|
|
130756
|
+
duplex: "half"
|
|
130757
|
+
});
|
|
130758
|
+
const { request: encryptedRequest, context } = await this.serverIdentity.encryptRequestWithContext(request);
|
|
130759
|
+
const token = context ? await extractSessionRecoveryToken2(context) : undefined;
|
|
130760
|
+
const response = await fetch(encryptedRequest);
|
|
130761
|
+
if (!token) {
|
|
130762
|
+
return response;
|
|
130763
|
+
}
|
|
130764
|
+
const shouldDecrypt = await Transport2.shouldDecryptResponse(response);
|
|
130765
|
+
if (!shouldDecrypt) {
|
|
130766
|
+
return response;
|
|
130767
|
+
}
|
|
130768
|
+
let streamTerminated = false;
|
|
130769
|
+
const clearToken = () => {
|
|
130770
|
+
streamTerminated = true;
|
|
130771
|
+
if (this.requestGeneration === generation) {
|
|
130772
|
+
this._lastSessionRecoveryToken = undefined;
|
|
130773
|
+
}
|
|
130774
|
+
};
|
|
130775
|
+
const decryptedResponse = await decryptResponseWithToken2(response, token, clearToken, clearToken);
|
|
130776
|
+
if (this.requestGeneration === generation) {
|
|
130777
|
+
this._lastSessionRecoveryToken = streamTerminated ? undefined : token;
|
|
130778
|
+
}
|
|
130779
|
+
return decryptedResponse;
|
|
130780
|
+
}
|
|
130781
|
+
async get(url3, init) {
|
|
130782
|
+
return this.request(url3, { ...init, method: "GET" });
|
|
130783
|
+
}
|
|
130784
|
+
async post(url3, body, init) {
|
|
130785
|
+
return this.request(url3, { ...init, method: "POST", body });
|
|
130786
|
+
}
|
|
130787
|
+
async put(url3, body, init) {
|
|
130788
|
+
return this.request(url3, { ...init, method: "PUT", body });
|
|
130789
|
+
}
|
|
130790
|
+
async delete(url3, init) {
|
|
130791
|
+
return this.request(url3, { ...init, method: "DELETE" });
|
|
130792
|
+
}
|
|
130793
|
+
}
|
|
130794
|
+
async function createTransport2(serverURL, init) {
|
|
130795
|
+
return Transport2.create(serverURL, init);
|
|
130796
|
+
}
|
|
130797
|
+
var MAX_PROBLEM_DETAILS_BYTES2;
|
|
130798
|
+
var init_client5 = __esm(() => {
|
|
130799
|
+
init_identity2();
|
|
130800
|
+
init_identity2();
|
|
130801
|
+
init_protocol2();
|
|
130802
|
+
init_request_options2();
|
|
130803
|
+
init_errors6();
|
|
130804
|
+
MAX_PROBLEM_DETAILS_BYTES2 = 64 * 1024;
|
|
130805
|
+
});
|
|
130806
|
+
|
|
130807
|
+
// node_modules/ehbp/dist/esm/index.js
|
|
130808
|
+
var exports_esm = {};
|
|
130809
|
+
__export(exports_esm, {
|
|
130810
|
+
serializeSessionRecoveryToken: () => serializeSessionRecoveryToken2,
|
|
130811
|
+
hexToBytes: () => hexToBytes13,
|
|
130812
|
+
extractSessionRecoveryToken: () => extractSessionRecoveryToken2,
|
|
130813
|
+
encryptChunk: () => encryptChunk2,
|
|
130814
|
+
deserializeSessionRecoveryToken: () => deserializeSessionRecoveryToken2,
|
|
130815
|
+
deriveResponseKeys: () => deriveResponseKeys2,
|
|
130816
|
+
decryptResponseWithToken: () => decryptResponseWithToken2,
|
|
130817
|
+
decryptChunk: () => decryptChunk2,
|
|
130818
|
+
createTransport: () => createTransport2,
|
|
130819
|
+
computeNonce: () => computeNonce2,
|
|
130820
|
+
bytesToHex: () => bytesToHex15,
|
|
130821
|
+
Transport: () => Transport2,
|
|
130822
|
+
RESPONSE_NONCE_LENGTH: () => RESPONSE_NONCE_LENGTH2,
|
|
130823
|
+
ProtocolError: () => ProtocolError2,
|
|
130824
|
+
PROTOCOL: () => PROTOCOL2,
|
|
130825
|
+
KeyConfigMismatchError: () => KeyConfigMismatchError2,
|
|
130826
|
+
Identity: () => Identity3,
|
|
130827
|
+
HPKE_REQUEST_INFO: () => HPKE_REQUEST_INFO2,
|
|
130828
|
+
HPKE_CONFIG: () => HPKE_CONFIG2,
|
|
130829
|
+
EhbpError: () => EhbpError2,
|
|
130830
|
+
EXPORT_LENGTH: () => EXPORT_LENGTH2,
|
|
130831
|
+
EXPORT_LABEL: () => EXPORT_LABEL2,
|
|
130832
|
+
DecryptionError: () => DecryptionError2,
|
|
130833
|
+
AES_GCM_NONCE_LENGTH: () => AES_GCM_NONCE_LENGTH2,
|
|
130834
|
+
AES256_KEY_LENGTH: () => AES256_KEY_LENGTH2
|
|
130835
|
+
});
|
|
130836
|
+
var init_esm6 = __esm(() => {
|
|
130837
|
+
init_identity2();
|
|
130838
|
+
init_identity2();
|
|
130839
|
+
init_client5();
|
|
130840
|
+
init_protocol2();
|
|
130841
|
+
init_errors6();
|
|
130842
|
+
init_derive2();
|
|
130843
|
+
});
|
|
130844
|
+
|
|
130142
130845
|
// node_modules/@routstr/sdk/dist/index.mjs
|
|
130143
130846
|
function makeConsoleLogger(prefix) {
|
|
130144
130847
|
const fmt = (args) => prefix ? [prefix, ...args] : args;
|
|
@@ -130256,6 +130959,10 @@ function selectMintWithBalance(balances, units, amount, excludeMints = []) {
|
|
|
130256
130959
|
function isKeyNotFoundResponse(status, body) {
|
|
130257
130960
|
return status === 401 && typeof body === "string" && body.includes("Key not found");
|
|
130258
130961
|
}
|
|
130962
|
+
function isOpenAiJsonBodyPath(pathname) {
|
|
130963
|
+
const path2 = (pathname.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
130964
|
+
return OPENAI_JSON_BODY_PATHS.some((suffix) => path2.endsWith(suffix));
|
|
130965
|
+
}
|
|
130259
130966
|
function newUserCacheSecret2() {
|
|
130260
130967
|
try {
|
|
130261
130968
|
const bytes6 = new Uint8Array(32);
|
|
@@ -130624,7 +131331,7 @@ async function isEhbpKeyConfigMismatchResponse(response, protocol) {
|
|
|
130624
131331
|
}
|
|
130625
131332
|
}
|
|
130626
131333
|
async function fetchTinfoilEhbpOnce(context, options, normalized, ehbp, userCacheSecret) {
|
|
130627
|
-
const { Identity:
|
|
131334
|
+
const { Identity: Identity4, PROTOCOL: PROTOCOL3, decryptResponseWithToken: decryptResponseWithToken3, extractSessionRecoveryToken: extractSessionRecoveryToken3 } = ehbp;
|
|
130628
131335
|
const resolved = resolveOptions(options);
|
|
130629
131336
|
const baseURL = context.client.getBaseURL() ?? resolved.baseUrl;
|
|
130630
131337
|
const enclaveURL = context.client.getEnclaveURL();
|
|
@@ -130652,7 +131359,7 @@ async function fetchTinfoilEhbpOnce(context, options, normalized, ehbp, userCach
|
|
|
130652
131359
|
}
|
|
130653
131360
|
}
|
|
130654
131361
|
}
|
|
130655
|
-
const serverIdentity = await
|
|
131362
|
+
const serverIdentity = await Identity4.fromPublicKeyHex(context.verification.hpkePublicKey);
|
|
130656
131363
|
const request = new Request(targetUrl.toString(), {
|
|
130657
131364
|
method,
|
|
130658
131365
|
headers,
|
|
@@ -130667,18 +131374,18 @@ async function fetchTinfoilEhbpOnce(context, options, normalized, ehbp, userCach
|
|
|
130667
131374
|
if (!requestContext) {
|
|
130668
131375
|
return response;
|
|
130669
131376
|
}
|
|
130670
|
-
if (await isEhbpKeyConfigMismatchResponse(response,
|
|
131377
|
+
if (await isEhbpKeyConfigMismatchResponse(response, PROTOCOL3)) {
|
|
130671
131378
|
throw new ehbp.KeyConfigMismatchError("EHBP key configuration mismatch");
|
|
130672
131379
|
}
|
|
130673
|
-
if (!response.headers.get(
|
|
131380
|
+
if (!response.headers.get(PROTOCOL3.RESPONSE_NONCE_HEADER)) {
|
|
130674
131381
|
return response;
|
|
130675
131382
|
}
|
|
130676
|
-
const token = await
|
|
130677
|
-
return await
|
|
131383
|
+
const token = await extractSessionRecoveryToken3(requestContext);
|
|
131384
|
+
return await decryptResponseWithToken3(response, token);
|
|
130678
131385
|
}
|
|
130679
131386
|
async function fetchTinfoilPreservingPlaintextErrors(options, input, init) {
|
|
130680
131387
|
const context = await prepareTinfoilClient(options);
|
|
130681
|
-
const ehbp = await Promise.resolve().then(() => (
|
|
131388
|
+
const ehbp = await Promise.resolve().then(() => (init_esm6(), exports_esm));
|
|
130682
131389
|
const normalized = normalizeFetchArgs(input, init);
|
|
130683
131390
|
const userCacheSecret = await resolveUserCacheSecret2({
|
|
130684
131391
|
explicit: options.userCacheSecret,
|
|
@@ -130771,6 +131478,10 @@ function getImageResolutionFromDataUrl(dataUrl) {
|
|
|
130771
131478
|
function calculateImageTokens(width, height, detail = "auto") {
|
|
130772
131479
|
if (detail === "low")
|
|
130773
131480
|
return 85;
|
|
131481
|
+
if (detail === "original") {
|
|
131482
|
+
const patches = Math.ceil(width / IMAGE_PATCH_PX) * Math.ceil(height / IMAGE_PATCH_PX);
|
|
131483
|
+
return Math.ceil(Math.min(patches, MAX_IMAGE_PATCHES) * 1.2);
|
|
131484
|
+
}
|
|
130774
131485
|
let w5 = width;
|
|
130775
131486
|
let h5 = height;
|
|
130776
131487
|
if (w5 > 2048 || h5 > 2048) {
|
|
@@ -130798,6 +131509,233 @@ function calculateImageTokens(width, height, detail = "auto") {
|
|
|
130798
131509
|
const numTiles = tilesWidth * tilesHeight;
|
|
130799
131510
|
return 85 + 170 * numTiles;
|
|
130800
131511
|
}
|
|
131512
|
+
function worstCaseImageTokensForDetail(detail) {
|
|
131513
|
+
if (detail === "low")
|
|
131514
|
+
return 85;
|
|
131515
|
+
if (detail === "original")
|
|
131516
|
+
return MAX_ORIGINAL_IMAGE_TOKENS;
|
|
131517
|
+
return MAX_TILED_IMAGE_TOKENS;
|
|
131518
|
+
}
|
|
131519
|
+
function estimateImageTokensForUrl(url3, detail) {
|
|
131520
|
+
if (!url3 || typeof url3 !== "string")
|
|
131521
|
+
return 0;
|
|
131522
|
+
if (url3.startsWith("data:")) {
|
|
131523
|
+
const res = getImageResolutionFromDataUrl(url3);
|
|
131524
|
+
if (res) {
|
|
131525
|
+
return calculateImageTokens(res.width, res.height, detail);
|
|
131526
|
+
}
|
|
131527
|
+
return worstCaseImageTokensForDetail(detail);
|
|
131528
|
+
}
|
|
131529
|
+
return worstCaseImageTokensForDetail(detail);
|
|
131530
|
+
}
|
|
131531
|
+
function estimateInputImageTokens(item) {
|
|
131532
|
+
const detail = typeof item?.detail === "string" && item?.detail ? item.detail : "auto";
|
|
131533
|
+
const url3 = typeof item?.image_url === "string" ? item.image_url : item?.image_url?.url;
|
|
131534
|
+
const fromUrl = estimateImageTokensForUrl(url3, detail);
|
|
131535
|
+
if (fromUrl > 0 || !item?.file_id)
|
|
131536
|
+
return fromUrl;
|
|
131537
|
+
return worstCaseImageTokensForDetail(detail);
|
|
131538
|
+
}
|
|
131539
|
+
function countImageTokensInMessages(apiMessages) {
|
|
131540
|
+
let total = 0;
|
|
131541
|
+
for (const msg of apiMessages ?? []) {
|
|
131542
|
+
const content2 = msg?.content;
|
|
131543
|
+
if (!Array.isArray(content2))
|
|
131544
|
+
continue;
|
|
131545
|
+
for (const part of content2) {
|
|
131546
|
+
if (!part || typeof part !== "object")
|
|
131547
|
+
continue;
|
|
131548
|
+
if (part.type === "image_url") {
|
|
131549
|
+
const detail = typeof part.image_url?.detail === "string" && part.image_url?.detail ? part.image_url.detail : "auto";
|
|
131550
|
+
const url3 = typeof part.image_url === "string" ? part.image_url : part.image_url?.url;
|
|
131551
|
+
total += estimateImageTokensForUrl(url3, detail);
|
|
131552
|
+
} else if (part.type === "input_image") {
|
|
131553
|
+
total += estimateInputImageTokens(part);
|
|
131554
|
+
}
|
|
131555
|
+
}
|
|
131556
|
+
}
|
|
131557
|
+
return total;
|
|
131558
|
+
}
|
|
131559
|
+
function countImageTokensInResponsesInput(input) {
|
|
131560
|
+
if (!Array.isArray(input))
|
|
131561
|
+
return 0;
|
|
131562
|
+
let total = 0;
|
|
131563
|
+
for (const item of input) {
|
|
131564
|
+
if (!item || typeof item !== "object")
|
|
131565
|
+
continue;
|
|
131566
|
+
if (item.type === "input_image") {
|
|
131567
|
+
total += estimateInputImageTokens(item);
|
|
131568
|
+
continue;
|
|
131569
|
+
}
|
|
131570
|
+
if (Array.isArray(item.content)) {
|
|
131571
|
+
for (const part of item.content) {
|
|
131572
|
+
if (part && typeof part === "object" && part.type === "input_image") {
|
|
131573
|
+
total += estimateInputImageTokens(part);
|
|
131574
|
+
}
|
|
131575
|
+
}
|
|
131576
|
+
}
|
|
131577
|
+
}
|
|
131578
|
+
return total;
|
|
131579
|
+
}
|
|
131580
|
+
function safeStringifyCompact(value) {
|
|
131581
|
+
try {
|
|
131582
|
+
return JSON.stringify(value);
|
|
131583
|
+
} catch {
|
|
131584
|
+
return null;
|
|
131585
|
+
}
|
|
131586
|
+
}
|
|
131587
|
+
function textLength(value) {
|
|
131588
|
+
if (typeof value === "string")
|
|
131589
|
+
return value.length;
|
|
131590
|
+
if (value !== null && typeof value === "object") {
|
|
131591
|
+
return safeStringifyCompact(value)?.length ?? 0;
|
|
131592
|
+
}
|
|
131593
|
+
return 0;
|
|
131594
|
+
}
|
|
131595
|
+
function countMessageTextChars(apiMessages) {
|
|
131596
|
+
let total = 0;
|
|
131597
|
+
for (const msg of apiMessages ?? []) {
|
|
131598
|
+
if (!msg || typeof msg !== "object")
|
|
131599
|
+
continue;
|
|
131600
|
+
const content2 = msg.content;
|
|
131601
|
+
if (typeof content2 === "string") {
|
|
131602
|
+
total += content2.length;
|
|
131603
|
+
} else if (Array.isArray(content2)) {
|
|
131604
|
+
for (const part of content2) {
|
|
131605
|
+
if (part && typeof part === "object" && part.type === "text") {
|
|
131606
|
+
total += textLength(part.text);
|
|
131607
|
+
}
|
|
131608
|
+
}
|
|
131609
|
+
}
|
|
131610
|
+
const toolCalls = msg.tool_calls;
|
|
131611
|
+
if (Array.isArray(toolCalls)) {
|
|
131612
|
+
for (const call of toolCalls) {
|
|
131613
|
+
const fn3 = call?.function;
|
|
131614
|
+
if (!fn3 || typeof fn3 !== "object")
|
|
131615
|
+
continue;
|
|
131616
|
+
total += textLength(fn3.name);
|
|
131617
|
+
total += textLength(fn3.arguments);
|
|
131618
|
+
}
|
|
131619
|
+
}
|
|
131620
|
+
}
|
|
131621
|
+
return total;
|
|
131622
|
+
}
|
|
131623
|
+
function countResponsesInputTextChars(input) {
|
|
131624
|
+
if (!Array.isArray(input))
|
|
131625
|
+
return 0;
|
|
131626
|
+
let total = 0;
|
|
131627
|
+
for (const item of input) {
|
|
131628
|
+
if (!item || typeof item !== "object")
|
|
131629
|
+
continue;
|
|
131630
|
+
const itemType = item.type;
|
|
131631
|
+
if (itemType === "input_text") {
|
|
131632
|
+
total += textLength(item.text);
|
|
131633
|
+
continue;
|
|
131634
|
+
}
|
|
131635
|
+
if (itemType === "function_call") {
|
|
131636
|
+
total += textLength(item.arguments);
|
|
131637
|
+
continue;
|
|
131638
|
+
}
|
|
131639
|
+
if (itemType === "function_call_output") {
|
|
131640
|
+
total += textLength(item.output);
|
|
131641
|
+
continue;
|
|
131642
|
+
}
|
|
131643
|
+
if (itemType === "reasoning") {
|
|
131644
|
+
const summary = item.summary;
|
|
131645
|
+
if (Array.isArray(summary)) {
|
|
131646
|
+
for (const part of summary) {
|
|
131647
|
+
if (part && typeof part === "object") {
|
|
131648
|
+
total += textLength(part.text);
|
|
131649
|
+
}
|
|
131650
|
+
}
|
|
131651
|
+
}
|
|
131652
|
+
}
|
|
131653
|
+
const content2 = item.content;
|
|
131654
|
+
if (typeof content2 === "string") {
|
|
131655
|
+
total += content2.length;
|
|
131656
|
+
} else if (Array.isArray(content2)) {
|
|
131657
|
+
for (const part of content2) {
|
|
131658
|
+
if (!part || typeof part !== "object")
|
|
131659
|
+
continue;
|
|
131660
|
+
total += textLength(part.text);
|
|
131661
|
+
if (typeof part.refusal === "string") {
|
|
131662
|
+
total += part.refusal.length;
|
|
131663
|
+
}
|
|
131664
|
+
}
|
|
131665
|
+
}
|
|
131666
|
+
}
|
|
131667
|
+
return total;
|
|
131668
|
+
}
|
|
131669
|
+
function sumStringChars(node) {
|
|
131670
|
+
if (typeof node === "string")
|
|
131671
|
+
return node.length;
|
|
131672
|
+
if (Array.isArray(node)) {
|
|
131673
|
+
return node.reduce((total, item) => total + sumStringChars(item), 0);
|
|
131674
|
+
}
|
|
131675
|
+
if (node && typeof node === "object") {
|
|
131676
|
+
let total = 0;
|
|
131677
|
+
for (const [key, value] of Object.entries(node)) {
|
|
131678
|
+
total += key.length + sumStringChars(value);
|
|
131679
|
+
}
|
|
131680
|
+
return total;
|
|
131681
|
+
}
|
|
131682
|
+
return 0;
|
|
131683
|
+
}
|
|
131684
|
+
function countPromptTokenIds(node) {
|
|
131685
|
+
if (typeof node === "number" && Number.isInteger(node))
|
|
131686
|
+
return 1;
|
|
131687
|
+
if (Array.isArray(node)) {
|
|
131688
|
+
return node.reduce((total, item) => total + countPromptTokenIds(item), 0);
|
|
131689
|
+
}
|
|
131690
|
+
return 0;
|
|
131691
|
+
}
|
|
131692
|
+
function estimateNodePromptTokens(body) {
|
|
131693
|
+
return Math.floor(sumStringChars(body) / 3) + countPromptTokenIds(body?.prompt);
|
|
131694
|
+
}
|
|
131695
|
+
function nodeGateSats(model2, satsPricing, requestBody, imageTokens) {
|
|
131696
|
+
const maxCost = satsPricing?.max_cost;
|
|
131697
|
+
if (typeof maxCost !== "number" || !Number.isFinite(maxCost))
|
|
131698
|
+
return 0;
|
|
131699
|
+
const toleranceFactor = 1 - NODE_TOLERANCE_PERCENT / 100;
|
|
131700
|
+
const promptPrice = typeof satsPricing.prompt === "number" ? satsPricing.prompt : 0;
|
|
131701
|
+
const completionPrice = typeof satsPricing.completion === "number" ? satsPricing.completion : 0;
|
|
131702
|
+
let gateMsats = Math.max(1, Math.floor(maxCost * 1000 * toleranceFactor));
|
|
131703
|
+
let promptAllowanceSats = typeof satsPricing.max_prompt_cost === "number" ? satsPricing.max_prompt_cost * toleranceFactor : 0;
|
|
131704
|
+
const topProvider = model2?.top_provider;
|
|
131705
|
+
const providerContextLength = topProvider?.context_length;
|
|
131706
|
+
const providerMaxCompletion = topProvider?.max_completion_tokens;
|
|
131707
|
+
let promptTokenLimit;
|
|
131708
|
+
if (topProvider && (providerContextLength || providerMaxCompletion)) {
|
|
131709
|
+
if (providerContextLength && providerMaxCompletion) {
|
|
131710
|
+
promptTokenLimit = Math.max(0, providerContextLength - providerMaxCompletion);
|
|
131711
|
+
} else if (providerContextLength) {
|
|
131712
|
+
promptTokenLimit = providerContextLength;
|
|
131713
|
+
} else {
|
|
131714
|
+
promptTokenLimit = 0;
|
|
131715
|
+
}
|
|
131716
|
+
} else if (model2?.context_length) {
|
|
131717
|
+
promptTokenLimit = model2.context_length;
|
|
131718
|
+
}
|
|
131719
|
+
if (promptTokenLimit !== undefined) {
|
|
131720
|
+
promptAllowanceSats = promptTokenLimit * promptPrice * toleranceFactor;
|
|
131721
|
+
}
|
|
131722
|
+
const promptTokens = estimateNodePromptTokens(requestBody) + (Array.isArray(requestBody?.messages) ? imageTokens : 0);
|
|
131723
|
+
if (promptTokens > 0) {
|
|
131724
|
+
const unusedPromptBudget = promptAllowanceSats - promptTokens * promptPrice;
|
|
131725
|
+
if (unusedPromptBudget > 0) {
|
|
131726
|
+
gateMsats -= Math.floor(unusedPromptBudget * 1000);
|
|
131727
|
+
}
|
|
131728
|
+
}
|
|
131729
|
+
const rawMaxTokens = requestBody?.max_tokens;
|
|
131730
|
+
const parsedMaxTokens = typeof rawMaxTokens === "number" ? rawMaxTokens : typeof rawMaxTokens === "string" && rawMaxTokens.trim() !== "" ? Number(rawMaxTokens) : NaN;
|
|
131731
|
+
if (Number.isFinite(parsedMaxTokens) && parsedMaxTokens > 0 && typeof satsPricing?.max_completion_cost === "number" && completionPrice > 0 && !isTinfoilModel(model2.id)) {
|
|
131732
|
+
const unusedCompletionBudget = satsPricing.max_completion_cost * toleranceFactor - parsedMaxTokens * completionPrice;
|
|
131733
|
+
if (unusedCompletionBudget > 0) {
|
|
131734
|
+
gateMsats -= Math.floor(unusedCompletionBudget * 1000);
|
|
131735
|
+
}
|
|
131736
|
+
}
|
|
131737
|
+
return Math.max(gateMsats, 1) / 1000;
|
|
131738
|
+
}
|
|
130801
131739
|
function extractCostBreakdown(costObj) {
|
|
130802
131740
|
if (!costObj || typeof costObj !== "object")
|
|
130803
131741
|
return {};
|
|
@@ -131936,584 +132874,7 @@ var consoleLogger, InsufficientBalanceError, ProviderError, FailoverError, Provi
|
|
|
131936
132874
|
return cachedModels.length > 0 ? cachedModels : [];
|
|
131937
132875
|
}
|
|
131938
132876
|
}
|
|
131939
|
-
},
|
|
131940
|
-
static instance = null;
|
|
131941
|
-
static getInstance() {
|
|
131942
|
-
if (!_AuditLogger.instance) {
|
|
131943
|
-
_AuditLogger.instance = new _AuditLogger;
|
|
131944
|
-
}
|
|
131945
|
-
return _AuditLogger.instance;
|
|
131946
|
-
}
|
|
131947
|
-
async log(entry) {
|
|
131948
|
-
const fullEntry = {
|
|
131949
|
-
...entry,
|
|
131950
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
131951
|
-
};
|
|
131952
|
-
const logLine = JSON.stringify(fullEntry) + `
|
|
131953
|
-
`;
|
|
131954
|
-
if (typeof window === "undefined") {
|
|
131955
|
-
try {
|
|
131956
|
-
const fs = await import("fs");
|
|
131957
|
-
const path2 = await import("path");
|
|
131958
|
-
const logPath = path2.join(process.cwd(), "audit.log");
|
|
131959
|
-
fs.appendFileSync(logPath, logLine);
|
|
131960
|
-
} catch (error53) {
|
|
131961
|
-
console.error("[AuditLogger] Failed to write to file:", error53);
|
|
131962
|
-
}
|
|
131963
|
-
} else {
|
|
131964
|
-
console.log("[AUDIT]", logLine.trim());
|
|
131965
|
-
}
|
|
131966
|
-
}
|
|
131967
|
-
async logBalanceSnapshot(action, amounts, options) {
|
|
131968
|
-
await this.log({
|
|
131969
|
-
action,
|
|
131970
|
-
totalBalance: amounts.totalBalance,
|
|
131971
|
-
providerBalances: amounts.providerBalances,
|
|
131972
|
-
mintBalances: amounts.mintBalances,
|
|
131973
|
-
amount: options?.amount,
|
|
131974
|
-
mintUrl: options?.mintUrl,
|
|
131975
|
-
baseUrl: options?.baseUrl,
|
|
131976
|
-
status: options?.status ?? "success",
|
|
131977
|
-
details: options?.details
|
|
131978
|
-
});
|
|
131979
|
-
}
|
|
131980
|
-
}, auditLogger, CashuSpender = class _CashuSpender {
|
|
131981
|
-
constructor(walletAdapter, storageAdapter, _discoveryAdapter, balanceManager, logger4) {
|
|
131982
|
-
this.walletAdapter = walletAdapter;
|
|
131983
|
-
this.storageAdapter = storageAdapter;
|
|
131984
|
-
this._discoveryAdapter = _discoveryAdapter;
|
|
131985
|
-
this.balanceManager = balanceManager;
|
|
131986
|
-
this.logger = (logger4 ?? consoleLogger).child("CashuSpender");
|
|
131987
|
-
}
|
|
131988
|
-
walletAdapter;
|
|
131989
|
-
storageAdapter;
|
|
131990
|
-
_discoveryAdapter;
|
|
131991
|
-
balanceManager;
|
|
131992
|
-
_isBusy = false;
|
|
131993
|
-
debugLevel = "WARN";
|
|
131994
|
-
logger;
|
|
131995
|
-
static MAX_REFUND_RETRIES = 3;
|
|
131996
|
-
static REFUND_RETRY_INTERVAL_MS = 120000;
|
|
131997
|
-
_refundRetryInterval = null;
|
|
131998
|
-
async receiveToken(token) {
|
|
131999
|
-
try {
|
|
132000
|
-
const result = await this.walletAdapter.receiveToken(token);
|
|
132001
|
-
return result;
|
|
132002
|
-
} catch (error53) {
|
|
132003
|
-
const errorMessage = error53 instanceof Error ? error53.message : String(error53);
|
|
132004
|
-
if (errorMessage.includes("Failed to fetch mint")) {
|
|
132005
|
-
const cachedTokens = this.storageAdapter.getCachedReceiveTokens();
|
|
132006
|
-
const existingIndex = cachedTokens.findIndex((t) => t.token === token);
|
|
132007
|
-
if (existingIndex === -1) {
|
|
132008
|
-
const { amount: amount2, unit: unit2 } = this._decodeTokenAmount(token);
|
|
132009
|
-
this.storageAdapter.setCachedReceiveTokens([
|
|
132010
|
-
...cachedTokens,
|
|
132011
|
-
{
|
|
132012
|
-
token,
|
|
132013
|
-
amount: amount2,
|
|
132014
|
-
unit: unit2,
|
|
132015
|
-
createdAt: Date.now()
|
|
132016
|
-
}
|
|
132017
|
-
]);
|
|
132018
|
-
}
|
|
132019
|
-
}
|
|
132020
|
-
const { amount, unit } = this._decodeTokenAmount(token);
|
|
132021
|
-
return { success: false, amount, unit, message: errorMessage };
|
|
132022
|
-
}
|
|
132023
|
-
}
|
|
132024
|
-
_decodeTokenAmount(token) {
|
|
132025
|
-
try {
|
|
132026
|
-
const metadata = ur3(token);
|
|
132027
|
-
const unit = metadata.unit || "sat";
|
|
132028
|
-
return { amount: metadata.amount, unit };
|
|
132029
|
-
} catch {
|
|
132030
|
-
return { amount: 0, unit: "sat" };
|
|
132031
|
-
}
|
|
132032
|
-
}
|
|
132033
|
-
async _getBalanceState() {
|
|
132034
|
-
if (this.balanceManager) {
|
|
132035
|
-
return this.balanceManager.getBalanceState();
|
|
132036
|
-
}
|
|
132037
|
-
const mintBalances = await this.walletAdapter.getBalances();
|
|
132038
|
-
const units = this.walletAdapter.getMintUnits();
|
|
132039
|
-
let totalMintBalance = 0;
|
|
132040
|
-
const normalizedMintBalances = {};
|
|
132041
|
-
for (const url3 in mintBalances) {
|
|
132042
|
-
const balance = mintBalances[url3];
|
|
132043
|
-
const unit = units[url3];
|
|
132044
|
-
const balanceInSats = getBalanceInSats(balance, unit);
|
|
132045
|
-
normalizedMintBalances[url3] = balanceInSats;
|
|
132046
|
-
totalMintBalance += balanceInSats;
|
|
132047
|
-
}
|
|
132048
|
-
const providerBalances = {};
|
|
132049
|
-
let totalProviderBalance = 0;
|
|
132050
|
-
const apiKeys = this.storageAdapter.getAllApiKeys();
|
|
132051
|
-
for (const apiKey of apiKeys) {
|
|
132052
|
-
if (!providerBalances[apiKey.baseUrl]) {
|
|
132053
|
-
providerBalances[apiKey.baseUrl] = 0;
|
|
132054
|
-
}
|
|
132055
|
-
providerBalances[apiKey.baseUrl] += apiKey.balance;
|
|
132056
|
-
totalProviderBalance += apiKey.balance;
|
|
132057
|
-
}
|
|
132058
|
-
return {
|
|
132059
|
-
totalBalance: totalMintBalance + totalProviderBalance,
|
|
132060
|
-
providerBalances,
|
|
132061
|
-
mintBalances: normalizedMintBalances
|
|
132062
|
-
};
|
|
132063
|
-
}
|
|
132064
|
-
async _logTransaction(action, options) {
|
|
132065
|
-
const balanceState = await this._getBalanceState();
|
|
132066
|
-
await auditLogger.logBalanceSnapshot(action, balanceState, options);
|
|
132067
|
-
}
|
|
132068
|
-
get isBusy() {
|
|
132069
|
-
return this._isBusy;
|
|
132070
|
-
}
|
|
132071
|
-
getDebugLevel() {
|
|
132072
|
-
return this.debugLevel;
|
|
132073
|
-
}
|
|
132074
|
-
setDebugLevel(level) {
|
|
132075
|
-
this.debugLevel = level;
|
|
132076
|
-
}
|
|
132077
|
-
_log(level, ...args) {
|
|
132078
|
-
const levelPriority = {
|
|
132079
|
-
DEBUG: 0,
|
|
132080
|
-
WARN: 1,
|
|
132081
|
-
ERROR: 2
|
|
132082
|
-
};
|
|
132083
|
-
if (levelPriority[level] >= levelPriority[this.debugLevel]) {
|
|
132084
|
-
switch (level) {
|
|
132085
|
-
case "DEBUG":
|
|
132086
|
-
this.logger.log(...args);
|
|
132087
|
-
break;
|
|
132088
|
-
case "WARN":
|
|
132089
|
-
this.logger.warn(...args);
|
|
132090
|
-
break;
|
|
132091
|
-
case "ERROR":
|
|
132092
|
-
this.logger.error(...args);
|
|
132093
|
-
break;
|
|
132094
|
-
}
|
|
132095
|
-
}
|
|
132096
|
-
}
|
|
132097
|
-
async spend(options) {
|
|
132098
|
-
const {
|
|
132099
|
-
mintUrl,
|
|
132100
|
-
amount,
|
|
132101
|
-
baseUrl,
|
|
132102
|
-
reuseToken = false,
|
|
132103
|
-
p2pkPubkey,
|
|
132104
|
-
excludeMints = [],
|
|
132105
|
-
retryCount = 0
|
|
132106
|
-
} = options;
|
|
132107
|
-
this._isBusy = true;
|
|
132108
|
-
try {
|
|
132109
|
-
const result = await this._spendInternal({
|
|
132110
|
-
mintUrl,
|
|
132111
|
-
amount,
|
|
132112
|
-
baseUrl,
|
|
132113
|
-
reuseToken,
|
|
132114
|
-
p2pkPubkey,
|
|
132115
|
-
excludeMints,
|
|
132116
|
-
retryCount
|
|
132117
|
-
});
|
|
132118
|
-
if (result.status === "failed" || !result.token) {
|
|
132119
|
-
const errorMsg = result.error || `Insufficient balance. Need ${amount} sats.`;
|
|
132120
|
-
if (this._isNetworkError(errorMsg)) {
|
|
132121
|
-
throw new Error(`Your mint ${mintUrl} is unreachable or is blocking your IP. Please try again later or switch mints.`);
|
|
132122
|
-
}
|
|
132123
|
-
if (result.errorDetails) {
|
|
132124
|
-
throw new InsufficientBalanceError(result.errorDetails.required, result.errorDetails.available, result.errorDetails.maxMintBalance, result.errorDetails.maxMintUrl);
|
|
132125
|
-
}
|
|
132126
|
-
throw new Error(errorMsg);
|
|
132127
|
-
}
|
|
132128
|
-
return result;
|
|
132129
|
-
} finally {
|
|
132130
|
-
this._isBusy = false;
|
|
132131
|
-
}
|
|
132132
|
-
}
|
|
132133
|
-
_isNetworkError(message) {
|
|
132134
|
-
return isNetworkErrorMessage(message) || message.includes("Your mint") && message.includes("unreachable");
|
|
132135
|
-
}
|
|
132136
|
-
async _spendInternal(options) {
|
|
132137
|
-
let {
|
|
132138
|
-
mintUrl,
|
|
132139
|
-
amount,
|
|
132140
|
-
baseUrl,
|
|
132141
|
-
reuseToken,
|
|
132142
|
-
p2pkPubkey,
|
|
132143
|
-
excludeMints,
|
|
132144
|
-
retryCount
|
|
132145
|
-
} = options;
|
|
132146
|
-
this._log("DEBUG", `[CashuSpender] _spendInternal: amount=${amount}, mintUrl=${mintUrl}, baseUrl=${baseUrl}, reuseToken=${reuseToken}`);
|
|
132147
|
-
let adjustedAmount = Math.ceil(amount);
|
|
132148
|
-
if (!adjustedAmount || isNaN(adjustedAmount)) {
|
|
132149
|
-
this._log("ERROR", `[CashuSpender] _spendInternal: Invalid amount: ${amount}`);
|
|
132150
|
-
return {
|
|
132151
|
-
token: null,
|
|
132152
|
-
status: "failed",
|
|
132153
|
-
balance: 0,
|
|
132154
|
-
error: "Please enter a valid amount"
|
|
132155
|
-
};
|
|
132156
|
-
}
|
|
132157
|
-
if (reuseToken && baseUrl) {
|
|
132158
|
-
this._log("DEBUG", `[CashuSpender] _spendInternal: Attempting to reuse token for ${baseUrl}`);
|
|
132159
|
-
const existingResult = await this._tryReuseToken(baseUrl, adjustedAmount, mintUrl);
|
|
132160
|
-
if (existingResult) {
|
|
132161
|
-
this._log("DEBUG", `[CashuSpender] _spendInternal: Successfully reused token, balance: ${existingResult.balance}`);
|
|
132162
|
-
return existingResult;
|
|
132163
|
-
}
|
|
132164
|
-
this._log("DEBUG", `[CashuSpender] _spendInternal: Could not reuse token, will create new token`);
|
|
132165
|
-
}
|
|
132166
|
-
const balanceState = await this._getBalanceState();
|
|
132167
|
-
const totalAvailableBalance = balanceState.totalBalance;
|
|
132168
|
-
this._log("DEBUG", `[CashuSpender] _spendInternal: totalAvailableBalance=${totalAvailableBalance}, adjustedAmount=${adjustedAmount}`);
|
|
132169
|
-
if (totalAvailableBalance < adjustedAmount) {
|
|
132170
|
-
this._log("ERROR", `[CashuSpender] _spendInternal: Insufficient balance, have=${totalAvailableBalance}, need=${adjustedAmount}`);
|
|
132171
|
-
return this._createInsufficientBalanceError(adjustedAmount, balanceState.mintBalances, totalAvailableBalance);
|
|
132172
|
-
}
|
|
132173
|
-
let token = null;
|
|
132174
|
-
let selectedMintUrl;
|
|
132175
|
-
let spentAmount = adjustedAmount;
|
|
132176
|
-
if (this.balanceManager) {
|
|
132177
|
-
const tokenResult = await this.balanceManager.createProviderToken({
|
|
132178
|
-
mintUrl,
|
|
132179
|
-
baseUrl,
|
|
132180
|
-
amount: adjustedAmount,
|
|
132181
|
-
p2pkPubkey,
|
|
132182
|
-
excludeMints,
|
|
132183
|
-
retryCount
|
|
132184
|
-
});
|
|
132185
|
-
if (!tokenResult.success || !tokenResult.token) {
|
|
132186
|
-
if ((tokenResult.error || "").includes("Insufficient balance")) {
|
|
132187
|
-
return this._createInsufficientBalanceError(adjustedAmount, balanceState.mintBalances, totalAvailableBalance);
|
|
132188
|
-
}
|
|
132189
|
-
return {
|
|
132190
|
-
token: null,
|
|
132191
|
-
status: "failed",
|
|
132192
|
-
balance: 0,
|
|
132193
|
-
error: tokenResult.error || "Failed to create token"
|
|
132194
|
-
};
|
|
132195
|
-
}
|
|
132196
|
-
token = tokenResult.token;
|
|
132197
|
-
selectedMintUrl = tokenResult.selectedMintUrl;
|
|
132198
|
-
spentAmount = tokenResult.amountSpent || adjustedAmount;
|
|
132199
|
-
} else {
|
|
132200
|
-
try {
|
|
132201
|
-
token = await this.walletAdapter.sendToken(mintUrl, adjustedAmount, p2pkPubkey);
|
|
132202
|
-
selectedMintUrl = mintUrl;
|
|
132203
|
-
} catch (error53) {
|
|
132204
|
-
const errorMsg = error53 instanceof Error ? error53.message : String(error53);
|
|
132205
|
-
return {
|
|
132206
|
-
token: null,
|
|
132207
|
-
status: "failed",
|
|
132208
|
-
balance: 0,
|
|
132209
|
-
error: `Error generating token: ${errorMsg}`
|
|
132210
|
-
};
|
|
132211
|
-
}
|
|
132212
|
-
}
|
|
132213
|
-
if (token) {
|
|
132214
|
-
this._log("DEBUG", `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`);
|
|
132215
|
-
}
|
|
132216
|
-
this._logTransaction("spend", {
|
|
132217
|
-
amount: spentAmount,
|
|
132218
|
-
mintUrl: selectedMintUrl || mintUrl,
|
|
132219
|
-
baseUrl,
|
|
132220
|
-
status: "success"
|
|
132221
|
-
});
|
|
132222
|
-
this._log("DEBUG", `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`);
|
|
132223
|
-
const units = this.walletAdapter.getMintUnits();
|
|
132224
|
-
return {
|
|
132225
|
-
token,
|
|
132226
|
-
status: "success",
|
|
132227
|
-
balance: spentAmount,
|
|
132228
|
-
unit: (selectedMintUrl ? units[selectedMintUrl] : units[mintUrl]) || "sat",
|
|
132229
|
-
selectedMintUrl: selectedMintUrl || mintUrl
|
|
132230
|
-
};
|
|
132231
|
-
}
|
|
132232
|
-
async _tryReuseToken(baseUrl, amount, mintUrl) {
|
|
132233
|
-
const apiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
|
|
132234
|
-
if (!apiKeyEntry)
|
|
132235
|
-
return null;
|
|
132236
|
-
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
132237
|
-
const balanceForBaseUrl = apiKeyDistribution.find((b2) => b2.baseUrl === baseUrl)?.amount || 0;
|
|
132238
|
-
this._log("DEBUG", "Reusing API key", balanceForBaseUrl, amount);
|
|
132239
|
-
if (balanceForBaseUrl > amount) {
|
|
132240
|
-
const units = this.walletAdapter.getMintUnits();
|
|
132241
|
-
const unit = units[mintUrl] || "sat";
|
|
132242
|
-
return {
|
|
132243
|
-
token: apiKeyEntry.key,
|
|
132244
|
-
status: "success",
|
|
132245
|
-
balance: balanceForBaseUrl,
|
|
132246
|
-
unit
|
|
132247
|
-
};
|
|
132248
|
-
}
|
|
132249
|
-
if (this.balanceManager) {
|
|
132250
|
-
const topUpAmount = Math.ceil(amount * 1.2 - balanceForBaseUrl);
|
|
132251
|
-
const topUpResult = await this.balanceManager.topUp({
|
|
132252
|
-
mintUrl,
|
|
132253
|
-
baseUrl,
|
|
132254
|
-
amount: topUpAmount,
|
|
132255
|
-
token: apiKeyEntry.key
|
|
132256
|
-
});
|
|
132257
|
-
this._log("DEBUG", "TOPUP ", topUpResult);
|
|
132258
|
-
if (topUpResult.success && topUpResult.toppedUpAmount) {
|
|
132259
|
-
const newBalance = balanceForBaseUrl + topUpResult.toppedUpAmount;
|
|
132260
|
-
const units = this.walletAdapter.getMintUnits();
|
|
132261
|
-
const unit = units[mintUrl] || "sat";
|
|
132262
|
-
this._logTransaction("topup", {
|
|
132263
|
-
amount: topUpResult.toppedUpAmount,
|
|
132264
|
-
mintUrl,
|
|
132265
|
-
baseUrl,
|
|
132266
|
-
status: "success"
|
|
132267
|
-
});
|
|
132268
|
-
return {
|
|
132269
|
-
token: apiKeyEntry.key,
|
|
132270
|
-
status: "success",
|
|
132271
|
-
balance: newBalance,
|
|
132272
|
-
unit
|
|
132273
|
-
};
|
|
132274
|
-
}
|
|
132275
|
-
const providerBalance = await this._getProviderTokenBalance(baseUrl, apiKeyEntry.key);
|
|
132276
|
-
this._log("DEBUG", providerBalance);
|
|
132277
|
-
if (providerBalance <= 0) {
|
|
132278
|
-
this.storageAdapter.removeApiKey(baseUrl);
|
|
132279
|
-
}
|
|
132280
|
-
}
|
|
132281
|
-
return null;
|
|
132282
|
-
}
|
|
132283
|
-
async refundXcashuTokens(mintUrl, excludeBaseUrls) {
|
|
132284
|
-
const results = [];
|
|
132285
|
-
const xcashuTokens = this.storageAdapter.getXcashuTokens();
|
|
132286
|
-
const excludedUrls = new Set(excludeBaseUrls || []);
|
|
132287
|
-
for (const [baseUrl, tokens] of Object.entries(xcashuTokens)) {
|
|
132288
|
-
if (excludedUrls.has(baseUrl))
|
|
132289
|
-
continue;
|
|
132290
|
-
for (const xcashuToken of tokens) {
|
|
132291
|
-
try {
|
|
132292
|
-
if (!this.balanceManager) {
|
|
132293
|
-
throw new Error("BalanceManager not available for xcashu refund");
|
|
132294
|
-
}
|
|
132295
|
-
const fetchResult = await this.balanceManager.fetchRefundToken(baseUrl, xcashuToken.token, true);
|
|
132296
|
-
if (!fetchResult.success && fetchResult.status === 425) {
|
|
132297
|
-
results.push({
|
|
132298
|
-
baseUrl,
|
|
132299
|
-
token: xcashuToken.token,
|
|
132300
|
-
success: false,
|
|
132301
|
-
error: fetchResult.error
|
|
132302
|
-
});
|
|
132303
|
-
this._log("WARN", `[CashuSpender] refundXcashuTokens: 425 "Refund is pending" for ${baseUrl}; leaving token in store, tryCount untouched`);
|
|
132304
|
-
continue;
|
|
132305
|
-
}
|
|
132306
|
-
if (!fetchResult.success && fetchResult.parsedError?.type === CoreErrorType.TOKEN_ALREADY_SPENT) {
|
|
132307
|
-
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
132308
|
-
results.push({
|
|
132309
|
-
baseUrl,
|
|
132310
|
-
token: xcashuToken.token,
|
|
132311
|
-
success: false,
|
|
132312
|
-
error: fetchResult.error
|
|
132313
|
-
});
|
|
132314
|
-
this._log("WARN", `[CashuSpender] refundXcashuTokens: token_already_spent for ${baseUrl}; removing permanently-spent xcashu token from store`);
|
|
132315
|
-
continue;
|
|
132316
|
-
}
|
|
132317
|
-
if (!fetchResult.success && fetchResult.parsedError && isHandledRedemptionError(fetchResult.parsedError)) {
|
|
132318
|
-
const directReceive = await this.receiveToken(xcashuToken.token);
|
|
132319
|
-
if (directReceive.success) {
|
|
132320
|
-
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
132321
|
-
results.push({
|
|
132322
|
-
baseUrl,
|
|
132323
|
-
token: xcashuToken.token,
|
|
132324
|
-
success: true
|
|
132325
|
-
});
|
|
132326
|
-
this._log("DEBUG", `[CashuSpender] refundXcashuTokens: provider returned ${fetchResult.parsedError.type}/${fetchResult.parsedError.code}; recovered original token directly, amount=${directReceive.amount}`);
|
|
132327
|
-
continue;
|
|
132328
|
-
}
|
|
132329
|
-
this._log("WARN", `[CashuSpender] refundXcashuTokens: provider returned ${fetchResult.parsedError.type}/${fetchResult.parsedError.code}; direct original-token recovery also failed: ${directReceive.message ?? "unknown error"}`);
|
|
132330
|
-
}
|
|
132331
|
-
if (!fetchResult.success && fetchResult.status === 404 && (fetchResult.error || "").includes("Refund not found")) {
|
|
132332
|
-
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
132333
|
-
const newTryCount = currentTryCount + 1;
|
|
132334
|
-
if (newTryCount >= _CashuSpender.MAX_REFUND_RETRIES) {
|
|
132335
|
-
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
132336
|
-
this._log("WARN", `[CashuSpender] refundXcashuTokens: 404 "Refund not found" for ${baseUrl} after ${newTryCount} retries; removing unrefundable xcashu token from store`);
|
|
132337
|
-
} else {
|
|
132338
|
-
this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
|
|
132339
|
-
this._log("WARN", `[CashuSpender] refundXcashuTokens: 404 "Refund not found" for ${baseUrl}; tryCount=${newTryCount}/${_CashuSpender.MAX_REFUND_RETRIES}, will retry in ${_CashuSpender.REFUND_RETRY_INTERVAL_MS / 1000}s`);
|
|
132340
|
-
this._startRefundRetryInterval(mintUrl);
|
|
132341
|
-
}
|
|
132342
|
-
results.push({
|
|
132343
|
-
baseUrl,
|
|
132344
|
-
token: xcashuToken.token,
|
|
132345
|
-
success: false,
|
|
132346
|
-
error: fetchResult.error
|
|
132347
|
-
});
|
|
132348
|
-
continue;
|
|
132349
|
-
}
|
|
132350
|
-
if (!fetchResult.success || !fetchResult.token) {
|
|
132351
|
-
throw new Error(fetchResult.error || "Failed to fetch refund token from provider");
|
|
132352
|
-
}
|
|
132353
|
-
const receiveResult = await this.receiveToken(fetchResult.token);
|
|
132354
|
-
if (receiveResult.success) {
|
|
132355
|
-
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
132356
|
-
results.push({
|
|
132357
|
-
baseUrl,
|
|
132358
|
-
token: xcashuToken.token,
|
|
132359
|
-
success: true
|
|
132360
|
-
});
|
|
132361
|
-
this._log("DEBUG", `[CashuSpender] refundXcashuTokens: Successfully refunded xcashu token for ${baseUrl}, amount=${receiveResult.amount}`);
|
|
132362
|
-
} else {
|
|
132363
|
-
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
132364
|
-
const newTryCount = currentTryCount + 1;
|
|
132365
|
-
this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
|
|
132366
|
-
results.push({
|
|
132367
|
-
baseUrl,
|
|
132368
|
-
token: xcashuToken.token,
|
|
132369
|
-
success: false,
|
|
132370
|
-
error: receiveResult.message ?? "Refund failed"
|
|
132371
|
-
});
|
|
132372
|
-
this._log("DEBUG", `[CashuSpender] refundXcashuTokens: Failed to receive refund token for ${baseUrl}, incremented tryCount to ${newTryCount}: ${receiveResult.message}`);
|
|
132373
|
-
}
|
|
132374
|
-
} catch (error53) {
|
|
132375
|
-
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
132376
|
-
const newTryCount = currentTryCount + 1;
|
|
132377
|
-
this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
|
|
132378
|
-
const errorMessage = error53 instanceof Error ? error53.message : String(error53);
|
|
132379
|
-
results.push({
|
|
132380
|
-
baseUrl,
|
|
132381
|
-
token: xcashuToken.token,
|
|
132382
|
-
success: false,
|
|
132383
|
-
error: errorMessage
|
|
132384
|
-
});
|
|
132385
|
-
this._log("ERROR", `[CashuSpender] refundXcashuTokens: Exception during refund for ${baseUrl}: ${errorMessage}, incremented tryCount to ${newTryCount}`);
|
|
132386
|
-
}
|
|
132387
|
-
}
|
|
132388
|
-
}
|
|
132389
|
-
return results;
|
|
132390
|
-
}
|
|
132391
|
-
_startRefundRetryInterval(mintUrl) {
|
|
132392
|
-
if (this._refundRetryInterval)
|
|
132393
|
-
return;
|
|
132394
|
-
this._log("DEBUG", `[CashuSpender] Starting refund retry interval (every ${_CashuSpender.REFUND_RETRY_INTERVAL_MS / 1000}s)`);
|
|
132395
|
-
this._refundRetryInterval = setInterval(async () => {
|
|
132396
|
-
const remainingTokens = this.storageAdapter.getXcashuTokens();
|
|
132397
|
-
const hasTokens = Object.values(remainingTokens).some((tokens) => tokens.length > 0);
|
|
132398
|
-
if (!hasTokens) {
|
|
132399
|
-
this._stopRefundRetryInterval();
|
|
132400
|
-
return;
|
|
132401
|
-
}
|
|
132402
|
-
try {
|
|
132403
|
-
await this.refundXcashuTokens(mintUrl);
|
|
132404
|
-
} catch (error53) {
|
|
132405
|
-
this._log("ERROR", `[CashuSpender] Refund retry interval error: ${error53 instanceof Error ? error53.message : String(error53)}`);
|
|
132406
|
-
}
|
|
132407
|
-
}, _CashuSpender.REFUND_RETRY_INTERVAL_MS);
|
|
132408
|
-
}
|
|
132409
|
-
_stopRefundRetryInterval() {
|
|
132410
|
-
if (this._refundRetryInterval) {
|
|
132411
|
-
clearInterval(this._refundRetryInterval);
|
|
132412
|
-
this._refundRetryInterval = null;
|
|
132413
|
-
this._log("DEBUG", `[CashuSpender] Stopped refund retry interval`);
|
|
132414
|
-
}
|
|
132415
|
-
}
|
|
132416
|
-
async refundProviders(mintUrl, forceRefund) {
|
|
132417
|
-
const results = [];
|
|
132418
|
-
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
132419
|
-
for (const apiKeyEntry of apiKeyDistribution) {
|
|
132420
|
-
const apiKeyEntryFull = this.storageAdapter.getApiKey(apiKeyEntry.baseUrl);
|
|
132421
|
-
if (apiKeyEntryFull && this.balanceManager) {
|
|
132422
|
-
try {
|
|
132423
|
-
const balanceResult = await this.balanceManager.getTokenBalance(apiKeyEntryFull.key, apiKeyEntry.baseUrl);
|
|
132424
|
-
if (balanceResult.isInvalidApiKey) {
|
|
132425
|
-
this.logger.warn(`refundProviders: ${apiKeyEntry.baseUrl} returned invalid API key; removing local key and treating as success`);
|
|
132426
|
-
this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);
|
|
132427
|
-
results.push({
|
|
132428
|
-
baseUrl: apiKeyEntry.baseUrl,
|
|
132429
|
-
success: true
|
|
132430
|
-
});
|
|
132431
|
-
continue;
|
|
132432
|
-
}
|
|
132433
|
-
if (balanceResult.amount >= 0 && !balanceResult.balanceUnknown) {
|
|
132434
|
-
const balanceSat = balanceResult.unit === "msat" ? Math.floor(balanceResult.amount / 1000) : balanceResult.amount;
|
|
132435
|
-
const reservedSat = balanceResult.unit === "msat" ? Math.floor(balanceResult.reserved / 1000) : balanceResult.reserved;
|
|
132436
|
-
this.storageAdapter.updateApiKeyBalance(apiKeyEntry.baseUrl, balanceSat, reservedSat);
|
|
132437
|
-
} else {
|
|
132438
|
-
this.logger.warn(`refundProviders: balance refresh for ${apiKeyEntry.baseUrl} returned negative amount; keeping stale local balance=${apiKeyEntryFull.balance}`);
|
|
132439
|
-
}
|
|
132440
|
-
} catch (error53) {
|
|
132441
|
-
this.logger.warn(`refundProviders: balance refresh threw for ${apiKeyEntry.baseUrl}; proceeding with stale local balance`, error53);
|
|
132442
|
-
}
|
|
132443
|
-
const refreshedEntry = this.storageAdapter.getApiKey(apiKeyEntry.baseUrl);
|
|
132444
|
-
if (!refreshedEntry) {
|
|
132445
|
-
continue;
|
|
132446
|
-
}
|
|
132447
|
-
const refundResult = await this.balanceManager.refundApiKey({
|
|
132448
|
-
mintUrl,
|
|
132449
|
-
baseUrl: apiKeyEntry.baseUrl,
|
|
132450
|
-
apiKey: refreshedEntry.key,
|
|
132451
|
-
forceRefund
|
|
132452
|
-
});
|
|
132453
|
-
if (refundResult.success) {
|
|
132454
|
-
this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);
|
|
132455
|
-
} else {
|
|
132456
|
-
const currentEntry = this.storageAdapter.getApiKey(apiKeyEntry.baseUrl);
|
|
132457
|
-
this.logger.warn(`refundProviders: refund failed for ${apiKeyEntry.baseUrl}; currentEntry=${Boolean(currentEntry)} balance=${currentEntry?.balance ?? "none"}. Touching lastUsed to rate-limit retries.`);
|
|
132458
|
-
if (currentEntry) {
|
|
132459
|
-
this.storageAdapter.touchApiKeyLastUsed(apiKeyEntry.baseUrl);
|
|
132460
|
-
}
|
|
132461
|
-
}
|
|
132462
|
-
results.push({
|
|
132463
|
-
baseUrl: apiKeyEntry.baseUrl,
|
|
132464
|
-
success: refundResult.success
|
|
132465
|
-
});
|
|
132466
|
-
} else {
|
|
132467
|
-
this.logger.warn(`refundProviders: cannot refund ${apiKeyEntry.baseUrl}; apiKeyEntryFull=${Boolean(apiKeyEntryFull)} balanceManager=${Boolean(this.balanceManager)}`);
|
|
132468
|
-
results.push({
|
|
132469
|
-
baseUrl: apiKeyEntry.baseUrl,
|
|
132470
|
-
success: false
|
|
132471
|
-
});
|
|
132472
|
-
}
|
|
132473
|
-
}
|
|
132474
|
-
return results;
|
|
132475
|
-
}
|
|
132476
|
-
_createInsufficientBalanceError(required2, normalizedBalances, availableBalance) {
|
|
132477
|
-
let maxBalance = 0;
|
|
132478
|
-
let maxMintUrl = "";
|
|
132479
|
-
for (const mintUrl in normalizedBalances) {
|
|
132480
|
-
const balanceInSats = normalizedBalances[mintUrl];
|
|
132481
|
-
if (balanceInSats > maxBalance) {
|
|
132482
|
-
maxBalance = balanceInSats;
|
|
132483
|
-
maxMintUrl = mintUrl;
|
|
132484
|
-
}
|
|
132485
|
-
}
|
|
132486
|
-
const error53 = new InsufficientBalanceError(required2, availableBalance ?? maxBalance, maxBalance, maxMintUrl);
|
|
132487
|
-
return {
|
|
132488
|
-
token: null,
|
|
132489
|
-
status: "failed",
|
|
132490
|
-
balance: 0,
|
|
132491
|
-
error: error53.message,
|
|
132492
|
-
errorDetails: {
|
|
132493
|
-
required: required2,
|
|
132494
|
-
available: availableBalance ?? maxBalance,
|
|
132495
|
-
maxMintBalance: maxBalance,
|
|
132496
|
-
maxMintUrl
|
|
132497
|
-
}
|
|
132498
|
-
};
|
|
132499
|
-
}
|
|
132500
|
-
async _getProviderTokenBalance(baseUrl, token) {
|
|
132501
|
-
try {
|
|
132502
|
-
const response = await fetch(`${baseUrl}v1/wallet/info`, {
|
|
132503
|
-
headers: {
|
|
132504
|
-
Authorization: `Bearer ${token}`
|
|
132505
|
-
}
|
|
132506
|
-
});
|
|
132507
|
-
if (response.ok) {
|
|
132508
|
-
const data = await response.json();
|
|
132509
|
-
return data.balance / 1000;
|
|
132510
|
-
}
|
|
132511
|
-
} catch {
|
|
132512
|
-
return 0;
|
|
132513
|
-
}
|
|
132514
|
-
return 0;
|
|
132515
|
-
}
|
|
132516
|
-
}, BalanceManager = class _BalanceManager {
|
|
132877
|
+
}, CashuSpender, BalanceManager = class _BalanceManager {
|
|
132517
132878
|
constructor(walletAdapter, storageAdapter, discoveryAdapter, cashuSpender, logger4) {
|
|
132518
132879
|
this.walletAdapter = walletAdapter;
|
|
132519
132880
|
this.storageAdapter = storageAdapter;
|
|
@@ -132617,7 +132978,7 @@ var consoleLogger, InsufficientBalanceError, ProviderError, FailoverError, Provi
|
|
|
132617
132978
|
if (!forceRefund) {
|
|
132618
132979
|
const apiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
|
|
132619
132980
|
if (apiKeyEntry?.lastUsed) {
|
|
132620
|
-
const fiveMinutesAgo = Date.now() -
|
|
132981
|
+
const fiveMinutesAgo = Date.now() - 5 * 60 * 1000;
|
|
132621
132982
|
if (apiKeyEntry.lastUsed > fiveMinutesAgo) {
|
|
132622
132983
|
this.logger.log(`refundApiKey: skipping ${baseUrl} - used ${Math.round((Date.now() - apiKeyEntry.lastUsed) / 1000)}s ago`);
|
|
132623
132984
|
return {
|
|
@@ -133267,7 +133628,7 @@ var consoleLogger, InsufficientBalanceError, ProviderError, FailoverError, Provi
|
|
|
133267
133628
|
} catch {
|
|
133268
133629
|
return trimmed.includes(TOR_ONION_SUFFIX);
|
|
133269
133630
|
}
|
|
133270
|
-
}, USER_CACHE_SECRET_FIELD2 = "user_cache_secret", USER_CACHE_SECRET_ENV2 = "TINFOIL_USER_CACHE_SECRET", USER_CACHE_SECRET_PATHS2, USER_CACHE_SECRET_DIR_NAME2 = ".tinfoil", USER_CACHE_SECRET_FILE_NAME2 = "user_cache_secret", ephemeralUserCacheSecret2, warnedEphemeral = false, defaultUserCacheSecretPromise, customPathSecretPromises, TINFOIL_MODEL_PREFIX = "tinfoil-", clientCache, normalizeBaseUrl2 = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`, fetchProviderInfo = async (adapter, baseUrl, logger4) => {
|
|
133631
|
+
}, OPENAI_JSON_BODY_PATHS, USER_CACHE_SECRET_FIELD2 = "user_cache_secret", USER_CACHE_SECRET_ENV2 = "TINFOIL_USER_CACHE_SECRET", USER_CACHE_SECRET_PATHS2, USER_CACHE_SECRET_DIR_NAME2 = ".tinfoil", USER_CACHE_SECRET_FILE_NAME2 = "user_cache_secret", ephemeralUserCacheSecret2, warnedEphemeral = false, defaultUserCacheSecretPromise, customPathSecretPromises, TINFOIL_MODEL_PREFIX = "tinfoil-", clientCache, normalizeBaseUrl2 = (baseUrl) => baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`, fetchProviderInfo = async (adapter, baseUrl, logger4) => {
|
|
133271
133632
|
const normalized = normalizeBaseUrl2(baseUrl);
|
|
133272
133633
|
const cached2 = adapter.getCachedProviderInfo()[normalized];
|
|
133273
133634
|
if (cached2)
|
|
@@ -133287,7 +133648,7 @@ var consoleLogger, InsufficientBalanceError, ProviderError, FailoverError, Provi
|
|
|
133287
133648
|
logger4.warn(`Failed to fetch provider info from ${normalized}:`, error53);
|
|
133288
133649
|
return null;
|
|
133289
133650
|
}
|
|
133290
|
-
}, ProviderManager = class _ProviderManager {
|
|
133651
|
+
}, IMAGE_PATCH_PX = 32, MAX_IMAGE_PATCHES = 30000, MAX_TILED_IMAGE_TOKENS = 765, MAX_ORIGINAL_IMAGE_TOKENS, NODE_TOLERANCE_PERCENT = 1, ProviderManager = class _ProviderManager {
|
|
133291
133652
|
constructor(discoveryAdapter, store, logger4) {
|
|
133292
133653
|
this.discoveryAdapter = discoveryAdapter;
|
|
133293
133654
|
this.instanceId = `pm_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -133529,35 +133890,45 @@ ${ranking}`);
|
|
|
133529
133890
|
}
|
|
133530
133891
|
return providerMints.includes(mintUrl);
|
|
133531
133892
|
}
|
|
133532
|
-
getRequiredSatsForModel(model2, apiMessages, maxTokens) {
|
|
133893
|
+
getRequiredSatsForModel(model2, apiMessages, maxTokens, requestBody) {
|
|
133533
133894
|
try {
|
|
133895
|
+
const body = requestBody ?? {};
|
|
133534
133896
|
let imageTokens = 0;
|
|
133535
|
-
|
|
133536
|
-
|
|
133537
|
-
|
|
133538
|
-
|
|
133539
|
-
|
|
133540
|
-
|
|
133541
|
-
|
|
133542
|
-
|
|
133543
|
-
|
|
133544
|
-
|
|
133545
|
-
|
|
133546
|
-
|
|
133547
|
-
|
|
133548
|
-
|
|
133549
|
-
|
|
133550
|
-
|
|
133897
|
+
let textChars = 0;
|
|
133898
|
+
let sawPromptShape = false;
|
|
133899
|
+
let textEstimateUnknown = false;
|
|
133900
|
+
if (Array.isArray(apiMessages) && apiMessages.length > 0) {
|
|
133901
|
+
sawPromptShape = true;
|
|
133902
|
+
imageTokens += countImageTokensInMessages(apiMessages);
|
|
133903
|
+
textChars += countMessageTextChars(apiMessages);
|
|
133904
|
+
}
|
|
133905
|
+
const responsesInput = body.input;
|
|
133906
|
+
if (!sawPromptShape) {
|
|
133907
|
+
if (Array.isArray(responsesInput)) {
|
|
133908
|
+
sawPromptShape = true;
|
|
133909
|
+
imageTokens += countImageTokensInResponsesInput(responsesInput);
|
|
133910
|
+
textChars += countResponsesInputTextChars(responsesInput);
|
|
133911
|
+
} else if (typeof responsesInput === "string") {
|
|
133912
|
+
sawPromptShape = true;
|
|
133913
|
+
textChars += responsesInput.length;
|
|
133914
|
+
}
|
|
133915
|
+
}
|
|
133916
|
+
const instructions = body.instructions;
|
|
133917
|
+
if (typeof instructions === "string" && instructions) {
|
|
133918
|
+
sawPromptShape = true;
|
|
133919
|
+
textChars += instructions.length;
|
|
133920
|
+
}
|
|
133921
|
+
const tools = body.tools;
|
|
133922
|
+
if (Array.isArray(tools) && tools.length > 0) {
|
|
133923
|
+
sawPromptShape = true;
|
|
133924
|
+
const serialized = safeStringifyCompact(tools);
|
|
133925
|
+
if (serialized === null) {
|
|
133926
|
+
textEstimateUnknown = true;
|
|
133927
|
+
} else {
|
|
133928
|
+
textChars += serialized.length;
|
|
133551
133929
|
}
|
|
133552
133930
|
}
|
|
133553
|
-
const
|
|
133554
|
-
if (Array.isArray(m2?.content)) {
|
|
133555
|
-
const filtered = m2.content.filter((p2) => !(p2 && typeof p2 === "object" && p2.type === "image_url"));
|
|
133556
|
-
return { ...m2, content: filtered };
|
|
133557
|
-
}
|
|
133558
|
-
return m2;
|
|
133559
|
-
}) : undefined;
|
|
133560
|
-
const approximateTokens = apiMessagesNoImages ? Math.ceil(JSON.stringify(apiMessagesNoImages, null, 2).length / 2.84) : 1e4;
|
|
133931
|
+
const approximateTokens = textEstimateUnknown ? 1e4 : sawPromptShape ? Math.ceil(textChars / 2.84) : 1e4;
|
|
133561
133932
|
const totalInputTokens = approximateTokens + imageTokens;
|
|
133562
133933
|
const sp = model2?.sats_pricing;
|
|
133563
133934
|
if (!sp) {
|
|
@@ -133572,11 +133943,17 @@ ${ranking}`);
|
|
|
133572
133943
|
if (maxTokens !== undefined && sp.completion && !isTinfoilModel(model2.id)) {
|
|
133573
133944
|
completionCost = sp.completion * maxTokens;
|
|
133574
133945
|
}
|
|
133575
|
-
const
|
|
133946
|
+
const componentEstimate = (promptCosts + completionCost + requestFee) * 1.05;
|
|
133947
|
+
const gateEstimate = nodeGateSats(model2, sp, body, imageTokens) * 1.05;
|
|
133948
|
+
let totalEstimatedCosts = Math.max(componentEstimate, gateEstimate);
|
|
133949
|
+
if (typeof sp.max_cost === "number" && totalEstimatedCosts > sp.max_cost) {
|
|
133950
|
+
return sp.max_cost;
|
|
133951
|
+
}
|
|
133576
133952
|
return totalEstimatedCosts;
|
|
133577
133953
|
} catch (e41) {
|
|
133578
133954
|
this.logger.error("getRequiredSatsForModel error:", e41);
|
|
133579
|
-
|
|
133955
|
+
const sp = model2?.sats_pricing;
|
|
133956
|
+
return sp?.max_cost ?? 50;
|
|
133580
133957
|
}
|
|
133581
133958
|
}
|
|
133582
133959
|
}, canUseLocalStorage = () => {
|
|
@@ -134629,7 +135006,6 @@ ${ranking}`);
|
|
|
134629
135006
|
const satsSpent = await this._handlePostResponseBalanceUpdate({
|
|
134630
135007
|
token: prepared.tokenUsed,
|
|
134631
135008
|
baseUrl: prepared.baseUrlUsed,
|
|
134632
|
-
mintUrl: params.mintUrl,
|
|
134633
135009
|
initialTokenBalance: prepared.tokenBalanceInSats,
|
|
134634
135010
|
initialTokenBalanceUnknown: prepared.tokenBalanceUnknown,
|
|
134635
135011
|
fallbackSatsSpent: usage?.satsCost,
|
|
@@ -134685,17 +135061,22 @@ ${ranking}`);
|
|
|
134685
135061
|
messageCount: requestMessages.length,
|
|
134686
135062
|
maxTokens: requestMaxTokens
|
|
134687
135063
|
});
|
|
134688
|
-
requiredSats = this.providerManager.getRequiredSatsForModel(selectedModel, requestMessages, requestMaxTokens);
|
|
135064
|
+
requiredSats = this.providerManager.getRequiredSatsForModel(selectedModel, requestMessages, requestMaxTokens, requestBodyForPricing);
|
|
134689
135065
|
}
|
|
134690
135066
|
}
|
|
134691
135067
|
let requestBody = body;
|
|
134692
135068
|
if (body && typeof body === "object") {
|
|
134693
135069
|
const bodyObj = body;
|
|
134694
|
-
if (!bodyObj.stream) {
|
|
135070
|
+
if (isOpenAiJsonBodyPath(requestPath) && !bodyObj.stream) {
|
|
134695
135071
|
requestBody = { ...bodyObj, stream: false };
|
|
134696
135072
|
}
|
|
134697
135073
|
}
|
|
134698
135074
|
const baseHeaders = this._buildBaseHeaders();
|
|
135075
|
+
for (const [name16, value] of Object.entries(headers)) {
|
|
135076
|
+
if (name16.toLowerCase() === "x-routstr-model-path") {
|
|
135077
|
+
baseHeaders["x-routstr-model-path"] = value;
|
|
135078
|
+
}
|
|
135079
|
+
}
|
|
134699
135080
|
const tinfoilEnabled = Boolean(modelId && isTinfoilModel(modelId));
|
|
134700
135081
|
if (tinfoilEnabled) {
|
|
134701
135082
|
this._log("DEBUG", `[RoutstrClient] Attesting Tinfoil model ${modelId} before spend`);
|
|
@@ -135201,7 +135582,7 @@ ${ranking}`);
|
|
|
135201
135582
|
this._log("DEBUG", `[RoutstrClient] _handleErrorResponse: Failing over to next provider: ${nextProvider}, model: ${selectedModel.id}`);
|
|
135202
135583
|
const newModel = await this.providerManager.getModelForProvider(nextProvider, selectedModel.id) ?? selectedModel;
|
|
135203
135584
|
const messagesForPricing = Array.isArray(body?.messages) ? body.messages : [];
|
|
135204
|
-
const newRequiredSats = this.providerManager.getRequiredSatsForModel(newModel, messagesForPricing, params.maxTokens);
|
|
135585
|
+
const newRequiredSats = this.providerManager.getRequiredSatsForModel(newModel, messagesForPricing, params.maxTokens, body && typeof body === "object" ? body : undefined);
|
|
135205
135586
|
if (params.tinfoilEnabled) {
|
|
135206
135587
|
this._log("DEBUG", `[RoutstrClient] _handleErrorResponse: Attesting Tinfoil failover provider ${nextProvider} before spend`);
|
|
135207
135588
|
await prepareTinfoilClient({ baseUrl: nextProvider });
|
|
@@ -135326,7 +135707,6 @@ ${ranking}`);
|
|
|
135326
135707
|
const {
|
|
135327
135708
|
token,
|
|
135328
135709
|
baseUrl,
|
|
135329
|
-
mintUrl,
|
|
135330
135710
|
initialTokenBalance,
|
|
135331
135711
|
initialTokenBalanceUnknown,
|
|
135332
135712
|
fallbackSatsSpent,
|
|
@@ -135860,14 +136240,536 @@ var init_dist17 = __esm(() => {
|
|
|
135860
136240
|
]);
|
|
135861
136241
|
MAX_EVENT_FUTURE_DRIFT_SECONDS = 15 * 60;
|
|
135862
136242
|
DISCOVERY_KINDS = [38421, 38423, 38425];
|
|
135863
|
-
|
|
135864
|
-
|
|
136243
|
+
CashuSpender = class _CashuSpender {
|
|
136244
|
+
constructor(walletAdapter, storageAdapter, _discoveryAdapter, balanceManager, logger4) {
|
|
136245
|
+
this.walletAdapter = walletAdapter;
|
|
136246
|
+
this.storageAdapter = storageAdapter;
|
|
136247
|
+
this._discoveryAdapter = _discoveryAdapter;
|
|
136248
|
+
this.balanceManager = balanceManager;
|
|
136249
|
+
this.logger = (logger4 ?? consoleLogger).child("CashuSpender");
|
|
136250
|
+
}
|
|
136251
|
+
walletAdapter;
|
|
136252
|
+
storageAdapter;
|
|
136253
|
+
_discoveryAdapter;
|
|
136254
|
+
balanceManager;
|
|
136255
|
+
_isBusy = false;
|
|
136256
|
+
debugLevel = "WARN";
|
|
136257
|
+
logger;
|
|
136258
|
+
static MAX_REFUND_RETRIES = 3;
|
|
136259
|
+
static REFUND_RETRY_INTERVAL_MS = 2 * 60 * 1000;
|
|
136260
|
+
_refundRetryInterval = null;
|
|
136261
|
+
async receiveToken(token) {
|
|
136262
|
+
try {
|
|
136263
|
+
const result = await this.walletAdapter.receiveToken(token);
|
|
136264
|
+
return result;
|
|
136265
|
+
} catch (error53) {
|
|
136266
|
+
const errorMessage = error53 instanceof Error ? error53.message : String(error53);
|
|
136267
|
+
if (errorMessage.includes("Failed to fetch mint")) {
|
|
136268
|
+
const cachedTokens = this.storageAdapter.getCachedReceiveTokens();
|
|
136269
|
+
const existingIndex = cachedTokens.findIndex((t) => t.token === token);
|
|
136270
|
+
if (existingIndex === -1) {
|
|
136271
|
+
const { amount: amount2, unit: unit2 } = this._decodeTokenAmount(token);
|
|
136272
|
+
this.storageAdapter.setCachedReceiveTokens([
|
|
136273
|
+
...cachedTokens,
|
|
136274
|
+
{
|
|
136275
|
+
token,
|
|
136276
|
+
amount: amount2,
|
|
136277
|
+
unit: unit2,
|
|
136278
|
+
createdAt: Date.now()
|
|
136279
|
+
}
|
|
136280
|
+
]);
|
|
136281
|
+
}
|
|
136282
|
+
}
|
|
136283
|
+
const { amount, unit } = this._decodeTokenAmount(token);
|
|
136284
|
+
return { success: false, amount, unit, message: errorMessage };
|
|
136285
|
+
}
|
|
136286
|
+
}
|
|
136287
|
+
_decodeTokenAmount(token) {
|
|
136288
|
+
try {
|
|
136289
|
+
const metadata = ur3(token);
|
|
136290
|
+
const unit = metadata.unit || "sat";
|
|
136291
|
+
return { amount: metadata.amount, unit };
|
|
136292
|
+
} catch {
|
|
136293
|
+
return { amount: 0, unit: "sat" };
|
|
136294
|
+
}
|
|
136295
|
+
}
|
|
136296
|
+
async _getBalanceState() {
|
|
136297
|
+
if (this.balanceManager) {
|
|
136298
|
+
return this.balanceManager.getBalanceState();
|
|
136299
|
+
}
|
|
136300
|
+
const mintBalances = await this.walletAdapter.getBalances();
|
|
136301
|
+
const units = this.walletAdapter.getMintUnits();
|
|
136302
|
+
let totalMintBalance = 0;
|
|
136303
|
+
const normalizedMintBalances = {};
|
|
136304
|
+
for (const url3 in mintBalances) {
|
|
136305
|
+
const balance = mintBalances[url3];
|
|
136306
|
+
const unit = units[url3];
|
|
136307
|
+
const balanceInSats = getBalanceInSats(balance, unit);
|
|
136308
|
+
normalizedMintBalances[url3] = balanceInSats;
|
|
136309
|
+
totalMintBalance += balanceInSats;
|
|
136310
|
+
}
|
|
136311
|
+
const providerBalances = {};
|
|
136312
|
+
let totalProviderBalance = 0;
|
|
136313
|
+
const apiKeys = this.storageAdapter.getAllApiKeys();
|
|
136314
|
+
for (const apiKey of apiKeys) {
|
|
136315
|
+
if (!providerBalances[apiKey.baseUrl]) {
|
|
136316
|
+
providerBalances[apiKey.baseUrl] = 0;
|
|
136317
|
+
}
|
|
136318
|
+
providerBalances[apiKey.baseUrl] += apiKey.balance;
|
|
136319
|
+
totalProviderBalance += apiKey.balance;
|
|
136320
|
+
}
|
|
136321
|
+
return {
|
|
136322
|
+
totalBalance: totalMintBalance + totalProviderBalance,
|
|
136323
|
+
providerBalances,
|
|
136324
|
+
mintBalances: normalizedMintBalances
|
|
136325
|
+
};
|
|
136326
|
+
}
|
|
136327
|
+
get isBusy() {
|
|
136328
|
+
return this._isBusy;
|
|
136329
|
+
}
|
|
136330
|
+
getDebugLevel() {
|
|
136331
|
+
return this.debugLevel;
|
|
136332
|
+
}
|
|
136333
|
+
setDebugLevel(level) {
|
|
136334
|
+
this.debugLevel = level;
|
|
136335
|
+
}
|
|
136336
|
+
_log(level, ...args) {
|
|
136337
|
+
const levelPriority = {
|
|
136338
|
+
DEBUG: 0,
|
|
136339
|
+
WARN: 1,
|
|
136340
|
+
ERROR: 2
|
|
136341
|
+
};
|
|
136342
|
+
if (levelPriority[level] >= levelPriority[this.debugLevel]) {
|
|
136343
|
+
switch (level) {
|
|
136344
|
+
case "DEBUG":
|
|
136345
|
+
this.logger.log(...args);
|
|
136346
|
+
break;
|
|
136347
|
+
case "WARN":
|
|
136348
|
+
this.logger.warn(...args);
|
|
136349
|
+
break;
|
|
136350
|
+
case "ERROR":
|
|
136351
|
+
this.logger.error(...args);
|
|
136352
|
+
break;
|
|
136353
|
+
}
|
|
136354
|
+
}
|
|
136355
|
+
}
|
|
136356
|
+
async spend(options) {
|
|
136357
|
+
const {
|
|
136358
|
+
mintUrl,
|
|
136359
|
+
amount,
|
|
136360
|
+
baseUrl,
|
|
136361
|
+
reuseToken = false,
|
|
136362
|
+
p2pkPubkey,
|
|
136363
|
+
excludeMints = [],
|
|
136364
|
+
retryCount = 0
|
|
136365
|
+
} = options;
|
|
136366
|
+
this._isBusy = true;
|
|
136367
|
+
try {
|
|
136368
|
+
const result = await this._spendInternal({
|
|
136369
|
+
mintUrl,
|
|
136370
|
+
amount,
|
|
136371
|
+
baseUrl,
|
|
136372
|
+
reuseToken,
|
|
136373
|
+
p2pkPubkey,
|
|
136374
|
+
excludeMints,
|
|
136375
|
+
retryCount
|
|
136376
|
+
});
|
|
136377
|
+
if (result.status === "failed" || !result.token) {
|
|
136378
|
+
const errorMsg = result.error || `Insufficient balance. Need ${amount} sats.`;
|
|
136379
|
+
if (this._isNetworkError(errorMsg)) {
|
|
136380
|
+
throw new Error(`Your mint ${mintUrl} is unreachable or is blocking your IP. Please try again later or switch mints.`);
|
|
136381
|
+
}
|
|
136382
|
+
if (result.errorDetails) {
|
|
136383
|
+
throw new InsufficientBalanceError(result.errorDetails.required, result.errorDetails.available, result.errorDetails.maxMintBalance, result.errorDetails.maxMintUrl);
|
|
136384
|
+
}
|
|
136385
|
+
throw new Error(errorMsg);
|
|
136386
|
+
}
|
|
136387
|
+
return result;
|
|
136388
|
+
} finally {
|
|
136389
|
+
this._isBusy = false;
|
|
136390
|
+
}
|
|
136391
|
+
}
|
|
136392
|
+
_isNetworkError(message) {
|
|
136393
|
+
return isNetworkErrorMessage(message) || message.includes("Your mint") && message.includes("unreachable");
|
|
136394
|
+
}
|
|
136395
|
+
async _spendInternal(options) {
|
|
136396
|
+
let {
|
|
136397
|
+
mintUrl,
|
|
136398
|
+
amount,
|
|
136399
|
+
baseUrl,
|
|
136400
|
+
reuseToken,
|
|
136401
|
+
p2pkPubkey,
|
|
136402
|
+
excludeMints,
|
|
136403
|
+
retryCount
|
|
136404
|
+
} = options;
|
|
136405
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: amount=${amount}, mintUrl=${mintUrl}, baseUrl=${baseUrl}, reuseToken=${reuseToken}`);
|
|
136406
|
+
let adjustedAmount = Math.ceil(amount);
|
|
136407
|
+
if (!adjustedAmount || isNaN(adjustedAmount)) {
|
|
136408
|
+
this._log("ERROR", `[CashuSpender] _spendInternal: Invalid amount: ${amount}`);
|
|
136409
|
+
return {
|
|
136410
|
+
token: null,
|
|
136411
|
+
status: "failed",
|
|
136412
|
+
balance: 0,
|
|
136413
|
+
error: "Please enter a valid amount"
|
|
136414
|
+
};
|
|
136415
|
+
}
|
|
136416
|
+
if (reuseToken && baseUrl) {
|
|
136417
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: Attempting to reuse token for ${baseUrl}`);
|
|
136418
|
+
const existingResult = await this._tryReuseToken(baseUrl, adjustedAmount, mintUrl);
|
|
136419
|
+
if (existingResult) {
|
|
136420
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: Successfully reused token, balance: ${existingResult.balance}`);
|
|
136421
|
+
return existingResult;
|
|
136422
|
+
}
|
|
136423
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: Could not reuse token, will create new token`);
|
|
136424
|
+
}
|
|
136425
|
+
const balanceState = await this._getBalanceState();
|
|
136426
|
+
const totalAvailableBalance = balanceState.totalBalance;
|
|
136427
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: totalAvailableBalance=${totalAvailableBalance}, adjustedAmount=${adjustedAmount}`);
|
|
136428
|
+
if (totalAvailableBalance < adjustedAmount) {
|
|
136429
|
+
this._log("ERROR", `[CashuSpender] _spendInternal: Insufficient balance, have=${totalAvailableBalance}, need=${adjustedAmount}`);
|
|
136430
|
+
return this._createInsufficientBalanceError(adjustedAmount, balanceState.mintBalances, totalAvailableBalance);
|
|
136431
|
+
}
|
|
136432
|
+
let token = null;
|
|
136433
|
+
let selectedMintUrl;
|
|
136434
|
+
let spentAmount = adjustedAmount;
|
|
136435
|
+
if (this.balanceManager) {
|
|
136436
|
+
const tokenResult = await this.balanceManager.createProviderToken({
|
|
136437
|
+
mintUrl,
|
|
136438
|
+
baseUrl,
|
|
136439
|
+
amount: adjustedAmount,
|
|
136440
|
+
p2pkPubkey,
|
|
136441
|
+
excludeMints,
|
|
136442
|
+
retryCount
|
|
136443
|
+
});
|
|
136444
|
+
if (!tokenResult.success || !tokenResult.token) {
|
|
136445
|
+
if ((tokenResult.error || "").includes("Insufficient balance")) {
|
|
136446
|
+
return this._createInsufficientBalanceError(adjustedAmount, balanceState.mintBalances, totalAvailableBalance);
|
|
136447
|
+
}
|
|
136448
|
+
return {
|
|
136449
|
+
token: null,
|
|
136450
|
+
status: "failed",
|
|
136451
|
+
balance: 0,
|
|
136452
|
+
error: tokenResult.error || "Failed to create token"
|
|
136453
|
+
};
|
|
136454
|
+
}
|
|
136455
|
+
token = tokenResult.token;
|
|
136456
|
+
selectedMintUrl = tokenResult.selectedMintUrl;
|
|
136457
|
+
spentAmount = tokenResult.amountSpent || adjustedAmount;
|
|
136458
|
+
} else {
|
|
136459
|
+
try {
|
|
136460
|
+
token = await this.walletAdapter.sendToken(mintUrl, adjustedAmount, p2pkPubkey);
|
|
136461
|
+
selectedMintUrl = mintUrl;
|
|
136462
|
+
} catch (error53) {
|
|
136463
|
+
const errorMsg = error53 instanceof Error ? error53.message : String(error53);
|
|
136464
|
+
return {
|
|
136465
|
+
token: null,
|
|
136466
|
+
status: "failed",
|
|
136467
|
+
balance: 0,
|
|
136468
|
+
error: `Error generating token: ${errorMsg}`
|
|
136469
|
+
};
|
|
136470
|
+
}
|
|
136471
|
+
}
|
|
136472
|
+
if (token) {
|
|
136473
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`);
|
|
136474
|
+
}
|
|
136475
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`);
|
|
136476
|
+
const units = this.walletAdapter.getMintUnits();
|
|
136477
|
+
return {
|
|
136478
|
+
token,
|
|
136479
|
+
status: "success",
|
|
136480
|
+
balance: spentAmount,
|
|
136481
|
+
unit: (selectedMintUrl ? units[selectedMintUrl] : units[mintUrl]) || "sat",
|
|
136482
|
+
selectedMintUrl: selectedMintUrl || mintUrl
|
|
136483
|
+
};
|
|
136484
|
+
}
|
|
136485
|
+
async _tryReuseToken(baseUrl, amount, mintUrl) {
|
|
136486
|
+
const apiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
|
|
136487
|
+
if (!apiKeyEntry)
|
|
136488
|
+
return null;
|
|
136489
|
+
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
136490
|
+
const balanceForBaseUrl = apiKeyDistribution.find((b2) => b2.baseUrl === baseUrl)?.amount || 0;
|
|
136491
|
+
this._log("DEBUG", "Reusing API key", balanceForBaseUrl, amount);
|
|
136492
|
+
if (balanceForBaseUrl > amount) {
|
|
136493
|
+
const units = this.walletAdapter.getMintUnits();
|
|
136494
|
+
const unit = units[mintUrl] || "sat";
|
|
136495
|
+
return {
|
|
136496
|
+
token: apiKeyEntry.key,
|
|
136497
|
+
status: "success",
|
|
136498
|
+
balance: balanceForBaseUrl,
|
|
136499
|
+
unit
|
|
136500
|
+
};
|
|
136501
|
+
}
|
|
136502
|
+
if (this.balanceManager) {
|
|
136503
|
+
const topUpAmount = Math.ceil(amount * 1.2 - balanceForBaseUrl);
|
|
136504
|
+
const topUpResult = await this.balanceManager.topUp({
|
|
136505
|
+
mintUrl,
|
|
136506
|
+
baseUrl,
|
|
136507
|
+
amount: topUpAmount,
|
|
136508
|
+
token: apiKeyEntry.key
|
|
136509
|
+
});
|
|
136510
|
+
this._log("DEBUG", "TOPUP ", topUpResult);
|
|
136511
|
+
if (topUpResult.success && topUpResult.toppedUpAmount) {
|
|
136512
|
+
const newBalance = balanceForBaseUrl + topUpResult.toppedUpAmount;
|
|
136513
|
+
const units = this.walletAdapter.getMintUnits();
|
|
136514
|
+
const unit = units[mintUrl] || "sat";
|
|
136515
|
+
return {
|
|
136516
|
+
token: apiKeyEntry.key,
|
|
136517
|
+
status: "success",
|
|
136518
|
+
balance: newBalance,
|
|
136519
|
+
unit
|
|
136520
|
+
};
|
|
136521
|
+
}
|
|
136522
|
+
const providerBalance = await this._getProviderTokenBalance(baseUrl, apiKeyEntry.key);
|
|
136523
|
+
this._log("DEBUG", providerBalance);
|
|
136524
|
+
if (providerBalance <= 0) {
|
|
136525
|
+
this.storageAdapter.removeApiKey(baseUrl);
|
|
136526
|
+
}
|
|
136527
|
+
}
|
|
136528
|
+
return null;
|
|
136529
|
+
}
|
|
136530
|
+
async refundXcashuTokens(mintUrl, excludeBaseUrls) {
|
|
136531
|
+
const results = [];
|
|
136532
|
+
const xcashuTokens = this.storageAdapter.getXcashuTokens();
|
|
136533
|
+
const excludedUrls = new Set(excludeBaseUrls || []);
|
|
136534
|
+
for (const [baseUrl, tokens] of Object.entries(xcashuTokens)) {
|
|
136535
|
+
if (excludedUrls.has(baseUrl))
|
|
136536
|
+
continue;
|
|
136537
|
+
for (const xcashuToken of tokens) {
|
|
136538
|
+
try {
|
|
136539
|
+
if (!this.balanceManager) {
|
|
136540
|
+
throw new Error("BalanceManager not available for xcashu refund");
|
|
136541
|
+
}
|
|
136542
|
+
const fetchResult = await this.balanceManager.fetchRefundToken(baseUrl, xcashuToken.token, true);
|
|
136543
|
+
if (!fetchResult.success && fetchResult.status === 425) {
|
|
136544
|
+
results.push({
|
|
136545
|
+
baseUrl,
|
|
136546
|
+
token: xcashuToken.token,
|
|
136547
|
+
success: false,
|
|
136548
|
+
error: fetchResult.error
|
|
136549
|
+
});
|
|
136550
|
+
this._log("WARN", `[CashuSpender] refundXcashuTokens: 425 "Refund is pending" for ${baseUrl}; leaving token in store, tryCount untouched`);
|
|
136551
|
+
continue;
|
|
136552
|
+
}
|
|
136553
|
+
if (!fetchResult.success && fetchResult.parsedError?.type === CoreErrorType.TOKEN_ALREADY_SPENT) {
|
|
136554
|
+
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
136555
|
+
results.push({
|
|
136556
|
+
baseUrl,
|
|
136557
|
+
token: xcashuToken.token,
|
|
136558
|
+
success: false,
|
|
136559
|
+
error: fetchResult.error
|
|
136560
|
+
});
|
|
136561
|
+
this._log("WARN", `[CashuSpender] refundXcashuTokens: token_already_spent for ${baseUrl}; removing permanently-spent xcashu token from store`);
|
|
136562
|
+
continue;
|
|
136563
|
+
}
|
|
136564
|
+
if (!fetchResult.success && fetchResult.parsedError && isHandledRedemptionError(fetchResult.parsedError)) {
|
|
136565
|
+
const directReceive = await this.receiveToken(xcashuToken.token);
|
|
136566
|
+
if (directReceive.success) {
|
|
136567
|
+
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
136568
|
+
results.push({
|
|
136569
|
+
baseUrl,
|
|
136570
|
+
token: xcashuToken.token,
|
|
136571
|
+
success: true
|
|
136572
|
+
});
|
|
136573
|
+
this._log("DEBUG", `[CashuSpender] refundXcashuTokens: provider returned ${fetchResult.parsedError.type}/${fetchResult.parsedError.code}; recovered original token directly, amount=${directReceive.amount}`);
|
|
136574
|
+
continue;
|
|
136575
|
+
}
|
|
136576
|
+
this._log("WARN", `[CashuSpender] refundXcashuTokens: provider returned ${fetchResult.parsedError.type}/${fetchResult.parsedError.code}; direct original-token recovery also failed: ${directReceive.message ?? "unknown error"}`);
|
|
136577
|
+
}
|
|
136578
|
+
if (!fetchResult.success && fetchResult.status === 404 && (fetchResult.error || "").includes("Refund not found")) {
|
|
136579
|
+
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
136580
|
+
const newTryCount = currentTryCount + 1;
|
|
136581
|
+
if (newTryCount >= _CashuSpender.MAX_REFUND_RETRIES) {
|
|
136582
|
+
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
136583
|
+
this._log("WARN", `[CashuSpender] refundXcashuTokens: 404 "Refund not found" for ${baseUrl} after ${newTryCount} retries; removing unrefundable xcashu token from store`);
|
|
136584
|
+
} else {
|
|
136585
|
+
this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
|
|
136586
|
+
this._log("WARN", `[CashuSpender] refundXcashuTokens: 404 "Refund not found" for ${baseUrl}; tryCount=${newTryCount}/${_CashuSpender.MAX_REFUND_RETRIES}, will retry in ${_CashuSpender.REFUND_RETRY_INTERVAL_MS / 1000}s`);
|
|
136587
|
+
this._startRefundRetryInterval(mintUrl);
|
|
136588
|
+
}
|
|
136589
|
+
results.push({
|
|
136590
|
+
baseUrl,
|
|
136591
|
+
token: xcashuToken.token,
|
|
136592
|
+
success: false,
|
|
136593
|
+
error: fetchResult.error
|
|
136594
|
+
});
|
|
136595
|
+
continue;
|
|
136596
|
+
}
|
|
136597
|
+
if (!fetchResult.success || !fetchResult.token) {
|
|
136598
|
+
throw new Error(fetchResult.error || "Failed to fetch refund token from provider");
|
|
136599
|
+
}
|
|
136600
|
+
const receiveResult = await this.receiveToken(fetchResult.token);
|
|
136601
|
+
if (receiveResult.success) {
|
|
136602
|
+
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
136603
|
+
results.push({
|
|
136604
|
+
baseUrl,
|
|
136605
|
+
token: xcashuToken.token,
|
|
136606
|
+
success: true
|
|
136607
|
+
});
|
|
136608
|
+
this._log("DEBUG", `[CashuSpender] refundXcashuTokens: Successfully refunded xcashu token for ${baseUrl}, amount=${receiveResult.amount}`);
|
|
136609
|
+
} else {
|
|
136610
|
+
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
136611
|
+
const newTryCount = currentTryCount + 1;
|
|
136612
|
+
this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
|
|
136613
|
+
results.push({
|
|
136614
|
+
baseUrl,
|
|
136615
|
+
token: xcashuToken.token,
|
|
136616
|
+
success: false,
|
|
136617
|
+
error: receiveResult.message ?? "Refund failed"
|
|
136618
|
+
});
|
|
136619
|
+
this._log("DEBUG", `[CashuSpender] refundXcashuTokens: Failed to receive refund token for ${baseUrl}, incremented tryCount to ${newTryCount}: ${receiveResult.message}`);
|
|
136620
|
+
}
|
|
136621
|
+
} catch (error53) {
|
|
136622
|
+
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
136623
|
+
const newTryCount = currentTryCount + 1;
|
|
136624
|
+
this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
|
|
136625
|
+
const errorMessage = error53 instanceof Error ? error53.message : String(error53);
|
|
136626
|
+
results.push({
|
|
136627
|
+
baseUrl,
|
|
136628
|
+
token: xcashuToken.token,
|
|
136629
|
+
success: false,
|
|
136630
|
+
error: errorMessage
|
|
136631
|
+
});
|
|
136632
|
+
this._log("ERROR", `[CashuSpender] refundXcashuTokens: Exception during refund for ${baseUrl}: ${errorMessage}, incremented tryCount to ${newTryCount}`);
|
|
136633
|
+
}
|
|
136634
|
+
}
|
|
136635
|
+
}
|
|
136636
|
+
return results;
|
|
136637
|
+
}
|
|
136638
|
+
_startRefundRetryInterval(mintUrl) {
|
|
136639
|
+
if (this._refundRetryInterval)
|
|
136640
|
+
return;
|
|
136641
|
+
this._log("DEBUG", `[CashuSpender] Starting refund retry interval (every ${_CashuSpender.REFUND_RETRY_INTERVAL_MS / 1000}s)`);
|
|
136642
|
+
this._refundRetryInterval = setInterval(async () => {
|
|
136643
|
+
const remainingTokens = this.storageAdapter.getXcashuTokens();
|
|
136644
|
+
const hasTokens = Object.values(remainingTokens).some((tokens) => tokens.length > 0);
|
|
136645
|
+
if (!hasTokens) {
|
|
136646
|
+
this._stopRefundRetryInterval();
|
|
136647
|
+
return;
|
|
136648
|
+
}
|
|
136649
|
+
try {
|
|
136650
|
+
await this.refundXcashuTokens(mintUrl);
|
|
136651
|
+
} catch (error53) {
|
|
136652
|
+
this._log("ERROR", `[CashuSpender] Refund retry interval error: ${error53 instanceof Error ? error53.message : String(error53)}`);
|
|
136653
|
+
}
|
|
136654
|
+
}, _CashuSpender.REFUND_RETRY_INTERVAL_MS);
|
|
136655
|
+
}
|
|
136656
|
+
_stopRefundRetryInterval() {
|
|
136657
|
+
if (this._refundRetryInterval) {
|
|
136658
|
+
clearInterval(this._refundRetryInterval);
|
|
136659
|
+
this._refundRetryInterval = null;
|
|
136660
|
+
this._log("DEBUG", `[CashuSpender] Stopped refund retry interval`);
|
|
136661
|
+
}
|
|
136662
|
+
}
|
|
136663
|
+
async refundProviders(mintUrl, forceRefund) {
|
|
136664
|
+
const results = [];
|
|
136665
|
+
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
136666
|
+
for (const apiKeyEntry of apiKeyDistribution) {
|
|
136667
|
+
const apiKeyEntryFull = this.storageAdapter.getApiKey(apiKeyEntry.baseUrl);
|
|
136668
|
+
if (apiKeyEntryFull && this.balanceManager) {
|
|
136669
|
+
try {
|
|
136670
|
+
const balanceResult = await this.balanceManager.getTokenBalance(apiKeyEntryFull.key, apiKeyEntry.baseUrl);
|
|
136671
|
+
if (balanceResult.isInvalidApiKey) {
|
|
136672
|
+
this.logger.warn(`refundProviders: ${apiKeyEntry.baseUrl} returned invalid API key; removing local key and treating as success`);
|
|
136673
|
+
this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);
|
|
136674
|
+
results.push({
|
|
136675
|
+
baseUrl: apiKeyEntry.baseUrl,
|
|
136676
|
+
success: true
|
|
136677
|
+
});
|
|
136678
|
+
continue;
|
|
136679
|
+
}
|
|
136680
|
+
if (balanceResult.amount >= 0 && !balanceResult.balanceUnknown) {
|
|
136681
|
+
const balanceSat = balanceResult.unit === "msat" ? Math.floor(balanceResult.amount / 1000) : balanceResult.amount;
|
|
136682
|
+
const reservedSat = balanceResult.unit === "msat" ? Math.floor(balanceResult.reserved / 1000) : balanceResult.reserved;
|
|
136683
|
+
this.storageAdapter.updateApiKeyBalance(apiKeyEntry.baseUrl, balanceSat, reservedSat);
|
|
136684
|
+
} else {
|
|
136685
|
+
this.logger.warn(`refundProviders: balance refresh for ${apiKeyEntry.baseUrl} returned negative amount; keeping stale local balance=${apiKeyEntryFull.balance}`);
|
|
136686
|
+
}
|
|
136687
|
+
} catch (error53) {
|
|
136688
|
+
this.logger.warn(`refundProviders: balance refresh threw for ${apiKeyEntry.baseUrl}; proceeding with stale local balance`, error53);
|
|
136689
|
+
}
|
|
136690
|
+
const refreshedEntry = this.storageAdapter.getApiKey(apiKeyEntry.baseUrl);
|
|
136691
|
+
if (!refreshedEntry) {
|
|
136692
|
+
continue;
|
|
136693
|
+
}
|
|
136694
|
+
const refundResult = await this.balanceManager.refundApiKey({
|
|
136695
|
+
mintUrl,
|
|
136696
|
+
baseUrl: apiKeyEntry.baseUrl,
|
|
136697
|
+
apiKey: refreshedEntry.key,
|
|
136698
|
+
forceRefund
|
|
136699
|
+
});
|
|
136700
|
+
if (refundResult.success) {
|
|
136701
|
+
this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);
|
|
136702
|
+
} else {
|
|
136703
|
+
const currentEntry = this.storageAdapter.getApiKey(apiKeyEntry.baseUrl);
|
|
136704
|
+
this.logger.warn(`refundProviders: refund failed for ${apiKeyEntry.baseUrl}; currentEntry=${Boolean(currentEntry)} balance=${currentEntry?.balance ?? "none"}. Touching lastUsed to rate-limit retries.`);
|
|
136705
|
+
if (currentEntry) {
|
|
136706
|
+
this.storageAdapter.touchApiKeyLastUsed(apiKeyEntry.baseUrl);
|
|
136707
|
+
}
|
|
136708
|
+
}
|
|
136709
|
+
results.push({
|
|
136710
|
+
baseUrl: apiKeyEntry.baseUrl,
|
|
136711
|
+
success: refundResult.success
|
|
136712
|
+
});
|
|
136713
|
+
} else {
|
|
136714
|
+
this.logger.warn(`refundProviders: cannot refund ${apiKeyEntry.baseUrl}; apiKeyEntryFull=${Boolean(apiKeyEntryFull)} balanceManager=${Boolean(this.balanceManager)}`);
|
|
136715
|
+
results.push({
|
|
136716
|
+
baseUrl: apiKeyEntry.baseUrl,
|
|
136717
|
+
success: false
|
|
136718
|
+
});
|
|
136719
|
+
}
|
|
136720
|
+
}
|
|
136721
|
+
return results;
|
|
136722
|
+
}
|
|
136723
|
+
_createInsufficientBalanceError(required2, normalizedBalances, availableBalance) {
|
|
136724
|
+
let maxBalance = 0;
|
|
136725
|
+
let maxMintUrl = "";
|
|
136726
|
+
for (const mintUrl in normalizedBalances) {
|
|
136727
|
+
const balanceInSats = normalizedBalances[mintUrl];
|
|
136728
|
+
if (balanceInSats > maxBalance) {
|
|
136729
|
+
maxBalance = balanceInSats;
|
|
136730
|
+
maxMintUrl = mintUrl;
|
|
136731
|
+
}
|
|
136732
|
+
}
|
|
136733
|
+
const error53 = new InsufficientBalanceError(required2, availableBalance ?? maxBalance, maxBalance, maxMintUrl);
|
|
136734
|
+
return {
|
|
136735
|
+
token: null,
|
|
136736
|
+
status: "failed",
|
|
136737
|
+
balance: 0,
|
|
136738
|
+
error: error53.message,
|
|
136739
|
+
errorDetails: {
|
|
136740
|
+
required: required2,
|
|
136741
|
+
available: availableBalance ?? maxBalance,
|
|
136742
|
+
maxMintBalance: maxBalance,
|
|
136743
|
+
maxMintUrl
|
|
136744
|
+
}
|
|
136745
|
+
};
|
|
136746
|
+
}
|
|
136747
|
+
async _getProviderTokenBalance(baseUrl, token) {
|
|
136748
|
+
try {
|
|
136749
|
+
const response = await fetch(`${baseUrl}v1/wallet/info`, {
|
|
136750
|
+
headers: {
|
|
136751
|
+
Authorization: `Bearer ${token}`
|
|
136752
|
+
}
|
|
136753
|
+
});
|
|
136754
|
+
if (response.ok) {
|
|
136755
|
+
const data = await response.json();
|
|
136756
|
+
return data.balance / 1000;
|
|
136757
|
+
}
|
|
136758
|
+
} catch {
|
|
136759
|
+
return 0;
|
|
136760
|
+
}
|
|
136761
|
+
return 0;
|
|
136762
|
+
}
|
|
136763
|
+
};
|
|
136764
|
+
OPENAI_JSON_BODY_PATHS = [
|
|
135865
136765
|
"/chat/completions",
|
|
135866
136766
|
"/completions",
|
|
135867
136767
|
"/responses"
|
|
135868
136768
|
];
|
|
136769
|
+
USER_CACHE_SECRET_PATHS2 = OPENAI_JSON_BODY_PATHS;
|
|
135869
136770
|
customPathSecretPromises = /* @__PURE__ */ new Map;
|
|
135870
136771
|
clientCache = /* @__PURE__ */ new Map;
|
|
136772
|
+
MAX_ORIGINAL_IMAGE_TOKENS = Math.ceil(MAX_IMAGE_PATCHES * 1.2);
|
|
135871
136773
|
NON_CRITICAL_KEYS = /* @__PURE__ */ new Set(["modelsFromAllProviders"]);
|
|
135872
136774
|
localStorageDriver = {
|
|
135873
136775
|
async getItem(key, defaultValue) {
|
|
@@ -136340,20 +137242,20 @@ __export(exports_utils3, {
|
|
|
136340
137242
|
numberToBytesLE: () => numberToBytesLE6,
|
|
136341
137243
|
numberToBytesBE: () => numberToBytesBE7,
|
|
136342
137244
|
hexToNumber: () => hexToNumber7,
|
|
136343
|
-
hexToBytes: () =>
|
|
137245
|
+
hexToBytes: () => hexToBytes14,
|
|
136344
137246
|
equalBytes: () => equalBytes8,
|
|
136345
137247
|
ensureBytes: () => ensureBytes4,
|
|
136346
137248
|
createHmacDrbg: () => createHmacDrbg6,
|
|
136347
137249
|
concatBytes: () => concatBytes14,
|
|
136348
137250
|
bytesToNumberLE: () => bytesToNumberLE6,
|
|
136349
137251
|
bytesToNumberBE: () => bytesToNumberBE6,
|
|
136350
|
-
bytesToHex: () =>
|
|
137252
|
+
bytesToHex: () => bytesToHex16,
|
|
136351
137253
|
bitSet: () => bitSet3,
|
|
136352
137254
|
bitMask: () => bitMask6,
|
|
136353
137255
|
bitLen: () => bitLen6,
|
|
136354
137256
|
bitGet: () => bitGet3
|
|
136355
137257
|
});
|
|
136356
|
-
function
|
|
137258
|
+
function bytesToHex16(bytes7) {
|
|
136357
137259
|
if (!u8a8(bytes7))
|
|
136358
137260
|
throw new Error("Uint8Array expected");
|
|
136359
137261
|
let hex7 = "";
|
|
@@ -136371,7 +137273,7 @@ function hexToNumber7(hex7) {
|
|
|
136371
137273
|
throw new Error("hex string expected, got " + typeof hex7);
|
|
136372
137274
|
return BigInt(hex7 === "" ? "0" : `0x${hex7}`);
|
|
136373
137275
|
}
|
|
136374
|
-
function
|
|
137276
|
+
function hexToBytes14(hex7) {
|
|
136375
137277
|
if (typeof hex7 !== "string")
|
|
136376
137278
|
throw new Error("hex string expected, got " + typeof hex7);
|
|
136377
137279
|
const len = hex7.length;
|
|
@@ -136389,27 +137291,27 @@ function hexToBytes13(hex7) {
|
|
|
136389
137291
|
return array2;
|
|
136390
137292
|
}
|
|
136391
137293
|
function bytesToNumberBE6(bytes7) {
|
|
136392
|
-
return hexToNumber7(
|
|
137294
|
+
return hexToNumber7(bytesToHex16(bytes7));
|
|
136393
137295
|
}
|
|
136394
137296
|
function bytesToNumberLE6(bytes7) {
|
|
136395
137297
|
if (!u8a8(bytes7))
|
|
136396
137298
|
throw new Error("Uint8Array expected");
|
|
136397
|
-
return hexToNumber7(
|
|
137299
|
+
return hexToNumber7(bytesToHex16(Uint8Array.from(bytes7).reverse()));
|
|
136398
137300
|
}
|
|
136399
137301
|
function numberToBytesBE7(n, len) {
|
|
136400
|
-
return
|
|
137302
|
+
return hexToBytes14(n.toString(16).padStart(len * 2, "0"));
|
|
136401
137303
|
}
|
|
136402
137304
|
function numberToBytesLE6(n, len) {
|
|
136403
137305
|
return numberToBytesBE7(n, len).reverse();
|
|
136404
137306
|
}
|
|
136405
137307
|
function numberToVarBytesBE3(n) {
|
|
136406
|
-
return
|
|
137308
|
+
return hexToBytes14(numberToHexUnpadded6(n));
|
|
136407
137309
|
}
|
|
136408
137310
|
function ensureBytes4(title, hex7, expectedLength) {
|
|
136409
137311
|
let res;
|
|
136410
137312
|
if (typeof hex7 === "string") {
|
|
136411
137313
|
try {
|
|
136412
|
-
res =
|
|
137314
|
+
res = hexToBytes14(hex7);
|
|
136413
137315
|
} catch (e41) {
|
|
136414
137316
|
throw new Error(`${title} must be valid hex string, got "${hex7}". Cause: ${e41}`);
|
|
136415
137317
|
}
|
|
@@ -136975,7 +137877,7 @@ function weierstrassPoints3(opts) {
|
|
|
136975
137877
|
const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
|
|
136976
137878
|
if (lengths && typeof key !== "bigint") {
|
|
136977
137879
|
if (key instanceof Uint8Array)
|
|
136978
|
-
key =
|
|
137880
|
+
key = bytesToHex16(key);
|
|
136979
137881
|
if (typeof key !== "string" || !lengths.includes(key.length))
|
|
136980
137882
|
throw new Error("Invalid key");
|
|
136981
137883
|
key = key.padStart(nByteLength * 2, "0");
|
|
@@ -137266,7 +138168,7 @@ function weierstrassPoints3(opts) {
|
|
|
137266
138168
|
return toBytes9(Point5, this, isCompressed);
|
|
137267
138169
|
}
|
|
137268
138170
|
toHex(isCompressed = true) {
|
|
137269
|
-
return
|
|
138171
|
+
return bytesToHex16(this.toRawBytes(isCompressed));
|
|
137270
138172
|
}
|
|
137271
138173
|
}
|
|
137272
138174
|
Point5.BASE = new Point5(CURVE.Gx, CURVE.Gy, Fp5.ONE);
|
|
@@ -137344,7 +138246,7 @@ function weierstrass6(curveDef) {
|
|
|
137344
138246
|
}
|
|
137345
138247
|
}
|
|
137346
138248
|
});
|
|
137347
|
-
const numToNByteStr = (num3) =>
|
|
138249
|
+
const numToNByteStr = (num3) => bytesToHex16(numberToBytesBE7(num3, CURVE.nByteLength));
|
|
137348
138250
|
function isBiggerThanHalfOrder(number10) {
|
|
137349
138251
|
const HALF = CURVE_ORDER >> _1n31;
|
|
137350
138252
|
return number10 > HALF;
|
|
@@ -137405,13 +138307,13 @@ function weierstrass6(curveDef) {
|
|
|
137405
138307
|
return this.hasHighS() ? new Signature(this.r, modN3(-this.s), this.recovery) : this;
|
|
137406
138308
|
}
|
|
137407
138309
|
toDERRawBytes() {
|
|
137408
|
-
return
|
|
138310
|
+
return hexToBytes14(this.toDERHex());
|
|
137409
138311
|
}
|
|
137410
138312
|
toDERHex() {
|
|
137411
138313
|
return DER6.hexFromSig({ r: this.r, s: this.s });
|
|
137412
138314
|
}
|
|
137413
138315
|
toCompactRawBytes() {
|
|
137414
|
-
return
|
|
138316
|
+
return hexToBytes14(this.toCompactHex());
|
|
137415
138317
|
}
|
|
137416
138318
|
toCompactHex() {
|
|
137417
138319
|
return numToNByteStr(this.r) + numToNByteStr(this.s);
|
|
@@ -137906,7 +138808,7 @@ var init_cryptoNode7 = __esm(() => {
|
|
|
137906
138808
|
});
|
|
137907
138809
|
|
|
137908
138810
|
// node_modules/applesauce-sqlite/node_modules/applesauce-core/node_modules/nostr-tools/node_modules/@noble/hashes/esm/utils.js
|
|
137909
|
-
function
|
|
138811
|
+
function bytesToHex17(bytes7) {
|
|
137910
138812
|
if (!u8a9(bytes7))
|
|
137911
138813
|
throw new Error("Uint8Array expected");
|
|
137912
138814
|
let hex7 = "";
|
|
@@ -137915,7 +138817,7 @@ function bytesToHex16(bytes7) {
|
|
|
137915
138817
|
}
|
|
137916
138818
|
return hex7;
|
|
137917
138819
|
}
|
|
137918
|
-
function
|
|
138820
|
+
function hexToBytes15(hex7) {
|
|
137919
138821
|
if (typeof hex7 !== "string")
|
|
137920
138822
|
throw new Error("hex string expected, got " + typeof hex7);
|
|
137921
138823
|
const len = hex7.length;
|
|
@@ -138597,7 +139499,7 @@ function genBech325(encoding2) {
|
|
|
138597
139499
|
return { encode: encode5, decode: decode5, decodeToBytes, decodeUnsafe, fromWords, fromWordsUnsafe, toWords };
|
|
138598
139500
|
}
|
|
138599
139501
|
var gcd5 = (a, b2) => !b2 ? a : gcd5(b2, a % b2), radix2carry5 = (from7, to) => from7 + (to - gcd5(from7, to)), base165, base325, base32hex5, base32crockford5, base648, base64url7, genBase585 = (abc) => chain5(radix7(58), alphabet5(abc), join14("")), base585, base58flickr5, base58xrp5, XMR_BLOCK_LEN3, base58xmr3, BECH_ALPHABET5, POLYMOD_GENERATORS5, bech325, bech32m5, utf83, hex7, CODERS3, coderTypeError3;
|
|
138600
|
-
var
|
|
139502
|
+
var init_esm7 = __esm(() => {
|
|
138601
139503
|
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
138602
139504
|
base165 = chain5(radix25(4), alphabet5("0123456789ABCDEF"), join14(""));
|
|
138603
139505
|
base325 = chain5(radix25(5), alphabet5("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), padding5(5), join14(""));
|
|
@@ -138693,7 +139595,7 @@ function output8(out, instance) {
|
|
|
138693
139595
|
var init__assert8 = () => {};
|
|
138694
139596
|
|
|
138695
139597
|
// node_modules/applesauce-sqlite/node_modules/applesauce-core/node_modules/nostr-tools/node_modules/@noble/ciphers/esm/utils.js
|
|
138696
|
-
function
|
|
139598
|
+
function bytesToHex18(bytes9) {
|
|
138697
139599
|
bytes8(bytes9);
|
|
138698
139600
|
let hex8 = "";
|
|
138699
139601
|
for (let i6 = 0;i6 < bytes9.length; i6++) {
|
|
@@ -138710,7 +139612,7 @@ function asciiToBase165(char) {
|
|
|
138710
139612
|
return char - (asciis5._a - 10);
|
|
138711
139613
|
return;
|
|
138712
139614
|
}
|
|
138713
|
-
function
|
|
139615
|
+
function hexToBytes16(hex8) {
|
|
138714
139616
|
if (typeof hex8 !== "string")
|
|
138715
139617
|
throw new Error("hex string expected, got " + typeof hex8);
|
|
138716
139618
|
const hl = hex8.length;
|
|
@@ -140340,7 +141242,7 @@ function serializeEvent6(evt) {
|
|
|
140340
141242
|
}
|
|
140341
141243
|
function getEventHash6(event3) {
|
|
140342
141244
|
let eventHash = sha25611(utf8Encoder9.encode(serializeEvent6(event3)));
|
|
140343
|
-
return
|
|
141245
|
+
return bytesToHex17(eventHash);
|
|
140344
141246
|
}
|
|
140345
141247
|
function isRegularKind5(kind) {
|
|
140346
141248
|
return kind < 1e4 && kind !== 0 && kind !== 3;
|
|
@@ -140505,7 +141407,7 @@ function decode5(code) {
|
|
|
140505
141407
|
return {
|
|
140506
141408
|
type: "nprofile",
|
|
140507
141409
|
data: {
|
|
140508
|
-
pubkey:
|
|
141410
|
+
pubkey: bytesToHex17(tlv[0][0]),
|
|
140509
141411
|
relays: tlv[1] ? tlv[1].map((d2) => utf8Decoder7.decode(d2)) : []
|
|
140510
141412
|
}
|
|
140511
141413
|
};
|
|
@@ -140523,10 +141425,10 @@ function decode5(code) {
|
|
|
140523
141425
|
return {
|
|
140524
141426
|
type: "nevent",
|
|
140525
141427
|
data: {
|
|
140526
|
-
id:
|
|
141428
|
+
id: bytesToHex17(tlv[0][0]),
|
|
140527
141429
|
relays: tlv[1] ? tlv[1].map((d2) => utf8Decoder7.decode(d2)) : [],
|
|
140528
|
-
author: tlv[2]?.[0] ?
|
|
140529
|
-
kind: tlv[3]?.[0] ? parseInt(
|
|
141430
|
+
author: tlv[2]?.[0] ? bytesToHex17(tlv[2][0]) : undefined,
|
|
141431
|
+
kind: tlv[3]?.[0] ? parseInt(bytesToHex17(tlv[3][0]), 16) : undefined
|
|
140530
141432
|
}
|
|
140531
141433
|
};
|
|
140532
141434
|
}
|
|
@@ -140546,8 +141448,8 @@ function decode5(code) {
|
|
|
140546
141448
|
type: "naddr",
|
|
140547
141449
|
data: {
|
|
140548
141450
|
identifier: utf8Decoder7.decode(tlv[0][0]),
|
|
140549
|
-
pubkey:
|
|
140550
|
-
kind: parseInt(
|
|
141451
|
+
pubkey: bytesToHex17(tlv[2][0]),
|
|
141452
|
+
kind: parseInt(bytesToHex17(tlv[3][0]), 16),
|
|
140551
141453
|
relays: tlv[1] ? tlv[1].map((d2) => utf8Decoder7.decode(d2)) : []
|
|
140552
141454
|
}
|
|
140553
141455
|
};
|
|
@@ -140556,7 +141458,7 @@ function decode5(code) {
|
|
|
140556
141458
|
return { type: prefix, data };
|
|
140557
141459
|
case "npub":
|
|
140558
141460
|
case "note":
|
|
140559
|
-
return { type: prefix, data:
|
|
141461
|
+
return { type: prefix, data: bytesToHex17(data) };
|
|
140560
141462
|
default:
|
|
140561
141463
|
throw new Error(`unknown prefix ${prefix}`);
|
|
140562
141464
|
}
|
|
@@ -140580,10 +141482,10 @@ function nsecEncode3(key) {
|
|
|
140580
141482
|
return encodeBytes3("nsec", key);
|
|
140581
141483
|
}
|
|
140582
141484
|
function npubEncode4(hex8) {
|
|
140583
|
-
return encodeBytes3("npub",
|
|
141485
|
+
return encodeBytes3("npub", hexToBytes15(hex8));
|
|
140584
141486
|
}
|
|
140585
141487
|
function noteEncode3(hex8) {
|
|
140586
|
-
return encodeBytes3("note",
|
|
141488
|
+
return encodeBytes3("note", hexToBytes15(hex8));
|
|
140587
141489
|
}
|
|
140588
141490
|
function encodeBech323(prefix, data) {
|
|
140589
141491
|
let words = bech325.toWords(data);
|
|
@@ -140594,7 +141496,7 @@ function encodeBytes3(prefix, bytes9) {
|
|
|
140594
141496
|
}
|
|
140595
141497
|
function nprofileEncode3(profile3) {
|
|
140596
141498
|
let data = encodeTLV3({
|
|
140597
|
-
0: [
|
|
141499
|
+
0: [hexToBytes15(profile3.pubkey)],
|
|
140598
141500
|
1: (profile3.relays || []).map((url3) => utf8Encoder9.encode(url3))
|
|
140599
141501
|
});
|
|
140600
141502
|
return encodeBech323("nprofile", data);
|
|
@@ -140605,9 +141507,9 @@ function neventEncode3(event3) {
|
|
|
140605
141507
|
kindArray = integerToUint8Array3(event3.kind);
|
|
140606
141508
|
}
|
|
140607
141509
|
let data = encodeTLV3({
|
|
140608
|
-
0: [
|
|
141510
|
+
0: [hexToBytes15(event3.id)],
|
|
140609
141511
|
1: (event3.relays || []).map((url3) => utf8Encoder9.encode(url3)),
|
|
140610
|
-
2: event3.author ? [
|
|
141512
|
+
2: event3.author ? [hexToBytes15(event3.author)] : [],
|
|
140611
141513
|
3: kindArray ? [new Uint8Array(kindArray)] : []
|
|
140612
141514
|
});
|
|
140613
141515
|
return encodeBech323("nevent", data);
|
|
@@ -140618,7 +141520,7 @@ function naddrEncode3(addr) {
|
|
|
140618
141520
|
let data = encodeTLV3({
|
|
140619
141521
|
0: [utf8Encoder9.encode(addr.identifier)],
|
|
140620
141522
|
1: (addr.relays || []).map((url3) => utf8Encoder9.encode(url3)),
|
|
140621
|
-
2: [
|
|
141523
|
+
2: [hexToBytes15(addr.pubkey)],
|
|
140622
141524
|
3: [new Uint8Array(kind)]
|
|
140623
141525
|
});
|
|
140624
141526
|
return encodeBech323("naddr", data);
|
|
@@ -140637,7 +141539,7 @@ function encodeTLV3(tlv) {
|
|
|
140637
141539
|
return concatBytes15(...entries);
|
|
140638
141540
|
}
|
|
140639
141541
|
function encrypt7(secretKey, pubkey, text) {
|
|
140640
|
-
const privkey = secretKey instanceof Uint8Array ?
|
|
141542
|
+
const privkey = secretKey instanceof Uint8Array ? bytesToHex17(secretKey) : secretKey;
|
|
140641
141543
|
const key = secp256k15.getSharedSecret(privkey, "02" + pubkey);
|
|
140642
141544
|
const normalizedKey = getNormalizedX3(key);
|
|
140643
141545
|
let iv = Uint8Array.from(randomBytes11(16));
|
|
@@ -140648,7 +141550,7 @@ function encrypt7(secretKey, pubkey, text) {
|
|
|
140648
141550
|
return `${ctb64}?iv=${ivb64}`;
|
|
140649
141551
|
}
|
|
140650
141552
|
function decrypt6(secretKey, pubkey, data) {
|
|
140651
|
-
const privkey = secretKey instanceof Uint8Array ?
|
|
141553
|
+
const privkey = secretKey instanceof Uint8Array ? bytesToHex17(secretKey) : secretKey;
|
|
140652
141554
|
let [ctb64, ivb64] = data.split("?iv=");
|
|
140653
141555
|
let key = secp256k15.getSharedSecret(privkey, "02" + pubkey);
|
|
140654
141556
|
let normalizedKey = getNormalizedX3(key);
|
|
@@ -140837,7 +141739,7 @@ function minePow3(unsigned, difficulty) {
|
|
|
140837
141739
|
return event3;
|
|
140838
141740
|
}
|
|
140839
141741
|
function fastEventHash2(evt) {
|
|
140840
|
-
return
|
|
141742
|
+
return bytesToHex17(sha25611(utf8Encoder9.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]))));
|
|
140841
141743
|
}
|
|
140842
141744
|
function getConversationKey3(privkeyA, pubkeyB) {
|
|
140843
141745
|
const sharedX = secp256k15.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
|
|
@@ -141585,7 +142487,7 @@ function validateEventMethodTag3(event3, method) {
|
|
|
141585
142487
|
}
|
|
141586
142488
|
function hashPayload5(payload) {
|
|
141587
142489
|
const hash8 = sha25611(utf8Encoder9.encode(JSON.stringify(payload)));
|
|
141588
|
-
return
|
|
142490
|
+
return bytesToHex17(hash8);
|
|
141589
142491
|
}
|
|
141590
142492
|
function validateEventPayloadTag3(event3, payload) {
|
|
141591
142493
|
const payloadTag = event3.tags.find((t) => t[0] === "payload");
|
|
@@ -141672,13 +142574,13 @@ var __defProp4, __export4 = (target, all) => {
|
|
|
141672
142574
|
return schnorr5.utils.randomPrivateKey();
|
|
141673
142575
|
}
|
|
141674
142576
|
getPublicKey(secretKey) {
|
|
141675
|
-
return
|
|
142577
|
+
return bytesToHex17(schnorr5.getPublicKey(secretKey));
|
|
141676
142578
|
}
|
|
141677
142579
|
finalizeEvent(t, secretKey) {
|
|
141678
142580
|
const event3 = t;
|
|
141679
|
-
event3.pubkey =
|
|
142581
|
+
event3.pubkey = bytesToHex17(schnorr5.getPublicKey(secretKey));
|
|
141680
142582
|
event3.id = getEventHash6(event3);
|
|
141681
|
-
event3.sig =
|
|
142583
|
+
event3.sig = bytesToHex17(schnorr5.sign(getEventHash6(event3), secretKey));
|
|
141682
142584
|
event3[verifiedSymbol8] = true;
|
|
141683
142585
|
return event3;
|
|
141684
142586
|
}
|
|
@@ -142301,7 +143203,7 @@ var __defProp4, __export4 = (target, all) => {
|
|
|
142301
143203
|
insert(timestamp, id) {
|
|
142302
143204
|
if (this.sealed)
|
|
142303
143205
|
throw Error("already sealed");
|
|
142304
|
-
const idb =
|
|
143206
|
+
const idb = hexToBytes16(id);
|
|
142305
143207
|
if (idb.byteLength !== ID_SIZE4)
|
|
142306
143208
|
throw Error("bad id size for added item");
|
|
142307
143209
|
this.items.push({ timestamp, id: idb });
|
|
@@ -142394,10 +143296,10 @@ var __defProp4, __export4 = (target, all) => {
|
|
|
142394
143296
|
let output9 = new WrappedBuffer4;
|
|
142395
143297
|
output9.extend(new Uint8Array([PROTOCOL_VERSION4]));
|
|
142396
143298
|
this.splitRange(0, this.storage.size(), this._bound(Number.MAX_VALUE), output9);
|
|
142397
|
-
return
|
|
143299
|
+
return bytesToHex18(output9.unwrap());
|
|
142398
143300
|
}
|
|
142399
143301
|
reconcile(queryMsg, onhave, onneed) {
|
|
142400
|
-
const query2 = new WrappedBuffer4(
|
|
143302
|
+
const query2 = new WrappedBuffer4(hexToBytes16(queryMsg));
|
|
142401
143303
|
this.lastTimestampIn = this.lastTimestampOut = 0;
|
|
142402
143304
|
let fullOutput = new WrappedBuffer4;
|
|
142403
143305
|
fullOutput.extend(new Uint8Array([PROTOCOL_VERSION4]));
|
|
@@ -142440,22 +143342,22 @@ var __defProp4, __export4 = (target, all) => {
|
|
|
142440
143342
|
let theirElems = {};
|
|
142441
143343
|
for (let i22 = 0;i22 < numIds; i22++) {
|
|
142442
143344
|
let e41 = getBytes5(query2, ID_SIZE4);
|
|
142443
|
-
theirElems[
|
|
143345
|
+
theirElems[bytesToHex18(e41)] = e41;
|
|
142444
143346
|
}
|
|
142445
143347
|
skip2 = true;
|
|
142446
143348
|
this.storage.iterate(lower, upper, (item) => {
|
|
142447
143349
|
let k5 = item.id;
|
|
142448
|
-
const id =
|
|
143350
|
+
const id = bytesToHex18(k5);
|
|
142449
143351
|
if (!theirElems[id]) {
|
|
142450
143352
|
onhave?.(id);
|
|
142451
143353
|
} else {
|
|
142452
|
-
delete theirElems[
|
|
143354
|
+
delete theirElems[bytesToHex18(k5)];
|
|
142453
143355
|
}
|
|
142454
143356
|
return true;
|
|
142455
143357
|
});
|
|
142456
143358
|
if (onneed) {
|
|
142457
143359
|
for (let v4 of Object.values(theirElems)) {
|
|
142458
|
-
onneed(
|
|
143360
|
+
onneed(bytesToHex18(v4));
|
|
142459
143361
|
}
|
|
142460
143362
|
}
|
|
142461
143363
|
} else {
|
|
@@ -142473,7 +143375,7 @@ var __defProp4, __export4 = (target, all) => {
|
|
|
142473
143375
|
prevIndex = upper;
|
|
142474
143376
|
prevBound = currBound;
|
|
142475
143377
|
}
|
|
142476
|
-
return fullOutput.length === 1 ? null :
|
|
143378
|
+
return fullOutput.length === 1 ? null : bytesToHex18(fullOutput.unwrap());
|
|
142477
143379
|
}
|
|
142478
143380
|
splitRange(lower, upper, upperBound, o) {
|
|
142479
143381
|
let numElems = upper - lower;
|
|
@@ -142626,17 +143528,17 @@ var __defProp4, __export4 = (target, all) => {
|
|
|
142626
143528
|
this.subscription.close();
|
|
142627
143529
|
}
|
|
142628
143530
|
}, nip98_exports3, _authorizationScheme5 = "Nostr ";
|
|
142629
|
-
var
|
|
143531
|
+
var init_esm8 = __esm(() => {
|
|
142630
143532
|
init_secp256k15();
|
|
142631
143533
|
init_utils22();
|
|
142632
143534
|
init_sha2566();
|
|
142633
143535
|
init_utils22();
|
|
142634
143536
|
init_utils22();
|
|
142635
|
-
|
|
143537
|
+
init_esm7();
|
|
142636
143538
|
init_utils22();
|
|
142637
143539
|
init_secp256k15();
|
|
142638
143540
|
init_aes4();
|
|
142639
|
-
|
|
143541
|
+
init_esm7();
|
|
142640
143542
|
init_utils22();
|
|
142641
143543
|
init_sha2566();
|
|
142642
143544
|
init_chacha3();
|
|
@@ -142646,13 +143548,13 @@ var init_esm7 = __esm(() => {
|
|
|
142646
143548
|
init_hmac8();
|
|
142647
143549
|
init_sha2566();
|
|
142648
143550
|
init_utils22();
|
|
142649
|
-
|
|
142650
|
-
|
|
143551
|
+
init_esm7();
|
|
143552
|
+
init_esm7();
|
|
142651
143553
|
init_utils23();
|
|
142652
143554
|
init_sha2566();
|
|
142653
143555
|
init_sha2566();
|
|
142654
143556
|
init_utils22();
|
|
142655
|
-
|
|
143557
|
+
init_esm7();
|
|
142656
143558
|
__defProp4 = Object.defineProperty;
|
|
142657
143559
|
verifiedSymbol8 = Symbol("verified");
|
|
142658
143560
|
utils_exports3 = {};
|
|
@@ -142660,8 +143562,8 @@ var init_esm7 = __esm(() => {
|
|
|
142660
143562
|
Queue: () => Queue2,
|
|
142661
143563
|
QueueNode: () => QueueNode2,
|
|
142662
143564
|
binarySearch: () => binarySearch4,
|
|
142663
|
-
bytesToHex: () =>
|
|
142664
|
-
hexToBytes: () =>
|
|
143565
|
+
bytesToHex: () => bytesToHex17,
|
|
143566
|
+
hexToBytes: () => hexToBytes15,
|
|
142665
143567
|
insertEventIntoAscendingList: () => insertEventIntoAscendingList4,
|
|
142666
143568
|
insertEventIntoDescendingList: () => insertEventIntoDescendingList4,
|
|
142667
143569
|
normalizeURL: () => normalizeURL4,
|
|
@@ -143026,20 +143928,20 @@ function serializeEvent7(evt) {
|
|
|
143026
143928
|
}
|
|
143027
143929
|
function getEventHash7(event3) {
|
|
143028
143930
|
let eventHash = sha25611(utf8Encoder10.encode(serializeEvent7(event3)));
|
|
143029
|
-
return
|
|
143931
|
+
return bytesToHex17(eventHash);
|
|
143030
143932
|
}
|
|
143031
143933
|
var verifiedSymbol9, isRecord7 = (obj2) => obj2 instanceof Object, utf8Decoder8, utf8Encoder10, JS7 = class {
|
|
143032
143934
|
generateSecretKey() {
|
|
143033
143935
|
return schnorr5.utils.randomPrivateKey();
|
|
143034
143936
|
}
|
|
143035
143937
|
getPublicKey(secretKey) {
|
|
143036
|
-
return
|
|
143938
|
+
return bytesToHex17(schnorr5.getPublicKey(secretKey));
|
|
143037
143939
|
}
|
|
143038
143940
|
finalizeEvent(t, secretKey) {
|
|
143039
143941
|
const event3 = t;
|
|
143040
|
-
event3.pubkey =
|
|
143942
|
+
event3.pubkey = bytesToHex17(schnorr5.getPublicKey(secretKey));
|
|
143041
143943
|
event3.id = getEventHash7(event3);
|
|
143042
|
-
event3.sig =
|
|
143944
|
+
event3.sig = bytesToHex17(schnorr5.sign(getEventHash7(event3), secretKey));
|
|
143043
143945
|
event3[verifiedSymbol9] = true;
|
|
143044
143946
|
return event3;
|
|
143045
143947
|
}
|
|
@@ -143165,7 +144067,7 @@ function getReplaceableIdentifier2(event3) {
|
|
|
143165
144067
|
}
|
|
143166
144068
|
var EventStoreSymbol2, EventUIDSymbol2, ReplaceableAddressSymbol2, FromCacheSymbol2, ReplaceableIdentifierSymbol2;
|
|
143167
144069
|
var init_event3 = __esm(() => {
|
|
143168
|
-
|
|
144070
|
+
init_esm8();
|
|
143169
144071
|
init_kinds2();
|
|
143170
144072
|
init_utils24();
|
|
143171
144073
|
EventStoreSymbol2 = Symbol.for("event-store");
|
|
@@ -143247,7 +144149,7 @@ var processTags2 = (tags3, ...fns) => {
|
|
|
143247
144149
|
|
|
143248
144150
|
// node_modules/applesauce-sqlite/node_modules/applesauce-core/node_modules/nostr-tools/lib/esm/nip19.js
|
|
143249
144151
|
function npubEncode5(hex8) {
|
|
143250
|
-
return encodeBytes4("npub",
|
|
144152
|
+
return encodeBytes4("npub", hexToBytes15(hex8));
|
|
143251
144153
|
}
|
|
143252
144154
|
function encodeBech324(prefix, data) {
|
|
143253
144155
|
let words = bech325.toWords(data);
|
|
@@ -143258,7 +144160,7 @@ function encodeBytes4(prefix, bytes9) {
|
|
|
143258
144160
|
}
|
|
143259
144161
|
function nprofileEncode4(profile3) {
|
|
143260
144162
|
let data = encodeTLV4({
|
|
143261
|
-
0: [
|
|
144163
|
+
0: [hexToBytes15(profile3.pubkey)],
|
|
143262
144164
|
1: (profile3.relays || []).map((url3) => utf8Encoder12.encode(url3))
|
|
143263
144165
|
});
|
|
143264
144166
|
return encodeBech324("nprofile", data);
|
|
@@ -143279,7 +144181,7 @@ function encodeTLV4(tlv) {
|
|
|
143279
144181
|
var utf8Decoder10, utf8Encoder12, Bech32MaxSize4 = 5000;
|
|
143280
144182
|
var init_nip19 = __esm(() => {
|
|
143281
144183
|
init_utils22();
|
|
143282
|
-
|
|
144184
|
+
init_esm7();
|
|
143283
144185
|
init_utils22();
|
|
143284
144186
|
utf8Decoder10 = new TextDecoder("utf-8");
|
|
143285
144187
|
utf8Encoder12 = new TextEncoder;
|
|
@@ -145955,7 +146857,7 @@ var init_models3 = __esm(() => {
|
|
|
145955
146857
|
|
|
145956
146858
|
// node_modules/applesauce-sqlite/node_modules/applesauce-core/dist/operations/client.js
|
|
145957
146859
|
var NEVER_ATTACH_CLIENT_TAG2;
|
|
145958
|
-
var
|
|
146860
|
+
var init_client6 = __esm(() => {
|
|
145959
146861
|
init_event3();
|
|
145960
146862
|
init_pointers2();
|
|
145961
146863
|
init_tags2();
|
|
@@ -145969,7 +146871,7 @@ var init_hidden_content4 = __esm(() => {
|
|
|
145969
146871
|
|
|
145970
146872
|
// node_modules/applesauce-sqlite/node_modules/applesauce-core/dist/operations/index.js
|
|
145971
146873
|
var init_operations2 = __esm(() => {
|
|
145972
|
-
|
|
146874
|
+
init_client6();
|
|
145973
146875
|
init_content5();
|
|
145974
146876
|
init_encrypted_content5();
|
|
145975
146877
|
init_event4();
|
|
@@ -146492,7 +147394,28 @@ function makeConsoleLogger2(prefix) {
|
|
|
146492
147394
|
child: (p2) => makeConsoleLogger2(prefix ? `${prefix}:${p2}` : p2)
|
|
146493
147395
|
};
|
|
146494
147396
|
}
|
|
146495
|
-
|
|
147397
|
+
function isInvalidTokenError2(parsed) {
|
|
147398
|
+
return parsed.type === CoreErrorType2.INVALID_TOKEN && parsed.code === CoreErrorCode2.INVALID_CASHU_TOKEN;
|
|
147399
|
+
}
|
|
147400
|
+
function isCashuRedemptionError2(parsed) {
|
|
147401
|
+
return parsed.type === CoreErrorType2.CASHU_ERROR && (parsed.code === CoreErrorCode2.CASHU_TOKEN_REDEMPTION_FAILED || parsed.code === CoreErrorCode2.CASHU_TOKEN_ZERO_VALUE);
|
|
147402
|
+
}
|
|
147403
|
+
function isTokenConsumedError2(parsed) {
|
|
147404
|
+
return parsed.type === CoreErrorType2.TOKEN_CONSUMED && parsed.code === CoreErrorCode2.CASHU_TOKEN_CONSUMED;
|
|
147405
|
+
}
|
|
147406
|
+
function isCoreInternalError2(parsed) {
|
|
147407
|
+
return parsed.type === CoreErrorType2.API_ERROR && parsed.code === CoreErrorCode2.INTERNAL_ERROR;
|
|
147408
|
+
}
|
|
147409
|
+
function isHandledRedemptionError2(parsed) {
|
|
147410
|
+
return isInvalidTokenError2(parsed) || isCashuRedemptionError2(parsed) || isTokenConsumedError2(parsed) || isCoreInternalError2(parsed);
|
|
147411
|
+
}
|
|
147412
|
+
function isNetworkErrorMessage2(message) {
|
|
147413
|
+
return message.includes("NetworkError when attempting to fetch resource") || message.includes("Failed to fetch") || message.includes("Load failed") || message.includes("Unable to connect") || message.includes("Was there a typo in the url or port") || message.includes("ERR_TLS_CERT_ALTNAME_INVALID") || message.includes("ERR_TLS_CERT_NOT_YET_VALID") || message.includes("ERR_TLS_CERT_EXPIRED") || message.includes("UNABLE_TO_VERIFY_LEAF_SIGNATURE") || message.includes("SELF_SIGNED_CERT_IN_CHAIN");
|
|
147414
|
+
}
|
|
147415
|
+
function getBalanceInSats2(balance, unit) {
|
|
147416
|
+
return unit === "msat" ? balance / 1000 : balance;
|
|
147417
|
+
}
|
|
147418
|
+
var consoleLogger2, InsufficientBalanceError2, ProviderBootstrapError2, NoProvidersAvailableError2, CoreErrorType2, CoreErrorCode2, DEFAULT_NOSTR_RELAYS2, POSITIVE_REVIEW_LABELS2, NEGATIVE_REVIEW_LABELS2, PROVIDER_FETCH_TIMEOUT_MS2 = 1e4, NOSTR_QUERY_TIMEOUT_MS2 = 5000, MAX_EVENT_FUTURE_DRIFT_SECONDS2, DISCOVERY_KINDS2, PRUNE_CHUNK_SIZE2 = 500, ModelManager2 = class _ModelManager2 {
|
|
146496
147419
|
constructor(adapter, config2 = {}) {
|
|
146497
147420
|
this.adapter = adapter;
|
|
146498
147421
|
this.providerDirectoryUrl = config2.providerDirectoryUrl || "https://api.routstr.com/v1/providers/";
|
|
@@ -147197,48 +148120,7 @@ var consoleLogger2, ProviderBootstrapError2, NoProvidersAvailableError2, DEFAULT
|
|
|
147197
148120
|
return cachedModels.length > 0 ? cachedModels : [];
|
|
147198
148121
|
}
|
|
147199
148122
|
}
|
|
147200
|
-
},
|
|
147201
|
-
static instance = null;
|
|
147202
|
-
static getInstance() {
|
|
147203
|
-
if (!_AuditLogger2.instance) {
|
|
147204
|
-
_AuditLogger2.instance = new _AuditLogger2;
|
|
147205
|
-
}
|
|
147206
|
-
return _AuditLogger2.instance;
|
|
147207
|
-
}
|
|
147208
|
-
async log(entry) {
|
|
147209
|
-
const fullEntry = {
|
|
147210
|
-
...entry,
|
|
147211
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
147212
|
-
};
|
|
147213
|
-
const logLine = JSON.stringify(fullEntry) + `
|
|
147214
|
-
`;
|
|
147215
|
-
if (typeof window === "undefined") {
|
|
147216
|
-
try {
|
|
147217
|
-
const fs = await import("fs");
|
|
147218
|
-
const path2 = await import("path");
|
|
147219
|
-
const logPath = path2.join(process.cwd(), "audit.log");
|
|
147220
|
-
fs.appendFileSync(logPath, logLine);
|
|
147221
|
-
} catch (error53) {
|
|
147222
|
-
console.error("[AuditLogger] Failed to write to file:", error53);
|
|
147223
|
-
}
|
|
147224
|
-
} else {
|
|
147225
|
-
console.log("[AUDIT]", logLine.trim());
|
|
147226
|
-
}
|
|
147227
|
-
}
|
|
147228
|
-
async logBalanceSnapshot(action, amounts, options) {
|
|
147229
|
-
await this.log({
|
|
147230
|
-
action,
|
|
147231
|
-
totalBalance: amounts.totalBalance,
|
|
147232
|
-
providerBalances: amounts.providerBalances,
|
|
147233
|
-
mintBalances: amounts.mintBalances,
|
|
147234
|
-
amount: options?.amount,
|
|
147235
|
-
mintUrl: options?.mintUrl,
|
|
147236
|
-
baseUrl: options?.baseUrl,
|
|
147237
|
-
status: options?.status ?? "success",
|
|
147238
|
-
details: options?.details
|
|
147239
|
-
});
|
|
147240
|
-
}
|
|
147241
|
-
}, auditLogger2, createBunPersistentEventDatabase = async (dbPath) => {
|
|
148123
|
+
}, CashuSpender2, MAX_IMAGE_PATCHES2 = 30000, MAX_ORIGINAL_IMAGE_TOKENS2, createBunPersistentEventDatabase = async (dbPath) => {
|
|
147242
148124
|
const { BunSqliteEventDatabase: BunSqliteEventDatabase2 } = await Promise.resolve().then(() => (init_bun(), exports_bun));
|
|
147243
148125
|
return new BunSqliteEventDatabase2(dbPath);
|
|
147244
148126
|
}, BunModelManager;
|
|
@@ -147248,6 +148130,20 @@ var init_bun2 = __esm(() => {
|
|
|
147248
148130
|
init_helpers();
|
|
147249
148131
|
init_cashu_ts_es3();
|
|
147250
148132
|
consoleLogger2 = makeConsoleLogger2();
|
|
148133
|
+
InsufficientBalanceError2 = class extends Error {
|
|
148134
|
+
constructor(required2, available, maxMintBalance = 0, maxMintUrl = "", customMessage) {
|
|
148135
|
+
super(customMessage ?? `Insufficient balance: need ${required2} sats, have ${available} sats available. ` + (maxMintBalance > 0 ? `Largest mint balance: ${maxMintBalance} sats from ${maxMintUrl}` : ""));
|
|
148136
|
+
this.required = required2;
|
|
148137
|
+
this.available = available;
|
|
148138
|
+
this.maxMintBalance = maxMintBalance;
|
|
148139
|
+
this.maxMintUrl = maxMintUrl;
|
|
148140
|
+
this.name = "InsufficientBalanceError";
|
|
148141
|
+
}
|
|
148142
|
+
required;
|
|
148143
|
+
available;
|
|
148144
|
+
maxMintBalance;
|
|
148145
|
+
maxMintUrl;
|
|
148146
|
+
};
|
|
147251
148147
|
ProviderBootstrapError2 = class extends Error {
|
|
147252
148148
|
constructor(failedProviders, message) {
|
|
147253
148149
|
super(message || `Failed to bootstrap providers. Tried: ${failedProviders.join(", ")}`);
|
|
@@ -147262,6 +148158,32 @@ var init_bun2 = __esm(() => {
|
|
|
147262
148158
|
this.name = "NoProvidersAvailableError";
|
|
147263
148159
|
}
|
|
147264
148160
|
};
|
|
148161
|
+
CoreErrorType2 = {
|
|
148162
|
+
TOKEN_ALREADY_SPENT: "token_already_spent",
|
|
148163
|
+
INVALID_TOKEN: "invalid_token",
|
|
148164
|
+
MINT_ERROR: "mint_error",
|
|
148165
|
+
MINT_UNREACHABLE: "mint_unreachable",
|
|
148166
|
+
CASHU_ERROR: "cashu_error",
|
|
148167
|
+
INSUFFICIENT_QUOTA: "insufficient_quota",
|
|
148168
|
+
MINIMUM_BALANCE_REQUIRED: "minimum_balance_required",
|
|
148169
|
+
TOKEN_CONSUMED: "token_consumed",
|
|
148170
|
+
API_ERROR: "api_error",
|
|
148171
|
+
PAYMENT_ERROR: "payment_error"
|
|
148172
|
+
};
|
|
148173
|
+
CoreErrorCode2 = {
|
|
148174
|
+
TOKEN_ALREADY_SPENT: "cashu_token_already_spent",
|
|
148175
|
+
INVALID_CASHU_TOKEN: "invalid_cashu_token",
|
|
148176
|
+
CASHU_TOKEN_SWAP_FEES_EXCEED_AMOUNT: "cashu_token_swap_fees_exceed_amount",
|
|
148177
|
+
CASHU_FOREIGN_MINT_SWAP_FAILED: "cashu_foreign_mint_swap_failed",
|
|
148178
|
+
CASHU_MINT_UNREACHABLE: "cashu_mint_unreachable",
|
|
148179
|
+
CASHU_TOKEN_REDEMPTION_FAILED: "cashu_token_redemption_failed",
|
|
148180
|
+
CASHU_TOKEN_ZERO_VALUE: "cashu_token_zero_value",
|
|
148181
|
+
CASHU_TOKEN_CONSUMED: "cashu_token_consumed",
|
|
148182
|
+
INTERNAL_ERROR: "internal_error",
|
|
148183
|
+
INVALID_API_KEY: "invalid_api_key",
|
|
148184
|
+
INSUFFICIENT_BALANCE: "insufficient_balance",
|
|
148185
|
+
BALANCE_LIMIT_EXCEEDED: "balance_limit_exceeded"
|
|
148186
|
+
};
|
|
147265
148187
|
DEFAULT_NOSTR_RELAYS2 = [
|
|
147266
148188
|
"wss://relay.damus.io",
|
|
147267
148189
|
"wss://nos.lol",
|
|
@@ -147276,7 +148198,528 @@ var init_bun2 = __esm(() => {
|
|
|
147276
148198
|
]);
|
|
147277
148199
|
MAX_EVENT_FUTURE_DRIFT_SECONDS2 = 15 * 60;
|
|
147278
148200
|
DISCOVERY_KINDS2 = [38421, 38423, 38425];
|
|
147279
|
-
|
|
148201
|
+
CashuSpender2 = class _CashuSpender2 {
|
|
148202
|
+
constructor(walletAdapter, storageAdapter, _discoveryAdapter, balanceManager, logger6) {
|
|
148203
|
+
this.walletAdapter = walletAdapter;
|
|
148204
|
+
this.storageAdapter = storageAdapter;
|
|
148205
|
+
this._discoveryAdapter = _discoveryAdapter;
|
|
148206
|
+
this.balanceManager = balanceManager;
|
|
148207
|
+
this.logger = (logger6 ?? consoleLogger2).child("CashuSpender");
|
|
148208
|
+
}
|
|
148209
|
+
walletAdapter;
|
|
148210
|
+
storageAdapter;
|
|
148211
|
+
_discoveryAdapter;
|
|
148212
|
+
balanceManager;
|
|
148213
|
+
_isBusy = false;
|
|
148214
|
+
debugLevel = "WARN";
|
|
148215
|
+
logger;
|
|
148216
|
+
static MAX_REFUND_RETRIES = 3;
|
|
148217
|
+
static REFUND_RETRY_INTERVAL_MS = 2 * 60 * 1000;
|
|
148218
|
+
_refundRetryInterval = null;
|
|
148219
|
+
async receiveToken(token) {
|
|
148220
|
+
try {
|
|
148221
|
+
const result = await this.walletAdapter.receiveToken(token);
|
|
148222
|
+
return result;
|
|
148223
|
+
} catch (error53) {
|
|
148224
|
+
const errorMessage = error53 instanceof Error ? error53.message : String(error53);
|
|
148225
|
+
if (errorMessage.includes("Failed to fetch mint")) {
|
|
148226
|
+
const cachedTokens = this.storageAdapter.getCachedReceiveTokens();
|
|
148227
|
+
const existingIndex = cachedTokens.findIndex((t) => t.token === token);
|
|
148228
|
+
if (existingIndex === -1) {
|
|
148229
|
+
const { amount: amount2, unit: unit2 } = this._decodeTokenAmount(token);
|
|
148230
|
+
this.storageAdapter.setCachedReceiveTokens([
|
|
148231
|
+
...cachedTokens,
|
|
148232
|
+
{
|
|
148233
|
+
token,
|
|
148234
|
+
amount: amount2,
|
|
148235
|
+
unit: unit2,
|
|
148236
|
+
createdAt: Date.now()
|
|
148237
|
+
}
|
|
148238
|
+
]);
|
|
148239
|
+
}
|
|
148240
|
+
}
|
|
148241
|
+
const { amount, unit } = this._decodeTokenAmount(token);
|
|
148242
|
+
return { success: false, amount, unit, message: errorMessage };
|
|
148243
|
+
}
|
|
148244
|
+
}
|
|
148245
|
+
_decodeTokenAmount(token) {
|
|
148246
|
+
try {
|
|
148247
|
+
const metadata = ur3(token);
|
|
148248
|
+
const unit = metadata.unit || "sat";
|
|
148249
|
+
return { amount: metadata.amount, unit };
|
|
148250
|
+
} catch {
|
|
148251
|
+
return { amount: 0, unit: "sat" };
|
|
148252
|
+
}
|
|
148253
|
+
}
|
|
148254
|
+
async _getBalanceState() {
|
|
148255
|
+
if (this.balanceManager) {
|
|
148256
|
+
return this.balanceManager.getBalanceState();
|
|
148257
|
+
}
|
|
148258
|
+
const mintBalances = await this.walletAdapter.getBalances();
|
|
148259
|
+
const units = this.walletAdapter.getMintUnits();
|
|
148260
|
+
let totalMintBalance = 0;
|
|
148261
|
+
const normalizedMintBalances = {};
|
|
148262
|
+
for (const url4 in mintBalances) {
|
|
148263
|
+
const balance = mintBalances[url4];
|
|
148264
|
+
const unit = units[url4];
|
|
148265
|
+
const balanceInSats = getBalanceInSats2(balance, unit);
|
|
148266
|
+
normalizedMintBalances[url4] = balanceInSats;
|
|
148267
|
+
totalMintBalance += balanceInSats;
|
|
148268
|
+
}
|
|
148269
|
+
const providerBalances = {};
|
|
148270
|
+
let totalProviderBalance = 0;
|
|
148271
|
+
const apiKeys = this.storageAdapter.getAllApiKeys();
|
|
148272
|
+
for (const apiKey of apiKeys) {
|
|
148273
|
+
if (!providerBalances[apiKey.baseUrl]) {
|
|
148274
|
+
providerBalances[apiKey.baseUrl] = 0;
|
|
148275
|
+
}
|
|
148276
|
+
providerBalances[apiKey.baseUrl] += apiKey.balance;
|
|
148277
|
+
totalProviderBalance += apiKey.balance;
|
|
148278
|
+
}
|
|
148279
|
+
return {
|
|
148280
|
+
totalBalance: totalMintBalance + totalProviderBalance,
|
|
148281
|
+
providerBalances,
|
|
148282
|
+
mintBalances: normalizedMintBalances
|
|
148283
|
+
};
|
|
148284
|
+
}
|
|
148285
|
+
get isBusy() {
|
|
148286
|
+
return this._isBusy;
|
|
148287
|
+
}
|
|
148288
|
+
getDebugLevel() {
|
|
148289
|
+
return this.debugLevel;
|
|
148290
|
+
}
|
|
148291
|
+
setDebugLevel(level) {
|
|
148292
|
+
this.debugLevel = level;
|
|
148293
|
+
}
|
|
148294
|
+
_log(level, ...args) {
|
|
148295
|
+
const levelPriority = {
|
|
148296
|
+
DEBUG: 0,
|
|
148297
|
+
WARN: 1,
|
|
148298
|
+
ERROR: 2
|
|
148299
|
+
};
|
|
148300
|
+
if (levelPriority[level] >= levelPriority[this.debugLevel]) {
|
|
148301
|
+
switch (level) {
|
|
148302
|
+
case "DEBUG":
|
|
148303
|
+
this.logger.log(...args);
|
|
148304
|
+
break;
|
|
148305
|
+
case "WARN":
|
|
148306
|
+
this.logger.warn(...args);
|
|
148307
|
+
break;
|
|
148308
|
+
case "ERROR":
|
|
148309
|
+
this.logger.error(...args);
|
|
148310
|
+
break;
|
|
148311
|
+
}
|
|
148312
|
+
}
|
|
148313
|
+
}
|
|
148314
|
+
async spend(options) {
|
|
148315
|
+
const {
|
|
148316
|
+
mintUrl,
|
|
148317
|
+
amount,
|
|
148318
|
+
baseUrl,
|
|
148319
|
+
reuseToken = false,
|
|
148320
|
+
p2pkPubkey,
|
|
148321
|
+
excludeMints = [],
|
|
148322
|
+
retryCount = 0
|
|
148323
|
+
} = options;
|
|
148324
|
+
this._isBusy = true;
|
|
148325
|
+
try {
|
|
148326
|
+
const result = await this._spendInternal({
|
|
148327
|
+
mintUrl,
|
|
148328
|
+
amount,
|
|
148329
|
+
baseUrl,
|
|
148330
|
+
reuseToken,
|
|
148331
|
+
p2pkPubkey,
|
|
148332
|
+
excludeMints,
|
|
148333
|
+
retryCount
|
|
148334
|
+
});
|
|
148335
|
+
if (result.status === "failed" || !result.token) {
|
|
148336
|
+
const errorMsg = result.error || `Insufficient balance. Need ${amount} sats.`;
|
|
148337
|
+
if (this._isNetworkError(errorMsg)) {
|
|
148338
|
+
throw new Error(`Your mint ${mintUrl} is unreachable or is blocking your IP. Please try again later or switch mints.`);
|
|
148339
|
+
}
|
|
148340
|
+
if (result.errorDetails) {
|
|
148341
|
+
throw new InsufficientBalanceError2(result.errorDetails.required, result.errorDetails.available, result.errorDetails.maxMintBalance, result.errorDetails.maxMintUrl);
|
|
148342
|
+
}
|
|
148343
|
+
throw new Error(errorMsg);
|
|
148344
|
+
}
|
|
148345
|
+
return result;
|
|
148346
|
+
} finally {
|
|
148347
|
+
this._isBusy = false;
|
|
148348
|
+
}
|
|
148349
|
+
}
|
|
148350
|
+
_isNetworkError(message) {
|
|
148351
|
+
return isNetworkErrorMessage2(message) || message.includes("Your mint") && message.includes("unreachable");
|
|
148352
|
+
}
|
|
148353
|
+
async _spendInternal(options) {
|
|
148354
|
+
let {
|
|
148355
|
+
mintUrl,
|
|
148356
|
+
amount,
|
|
148357
|
+
baseUrl,
|
|
148358
|
+
reuseToken,
|
|
148359
|
+
p2pkPubkey,
|
|
148360
|
+
excludeMints,
|
|
148361
|
+
retryCount
|
|
148362
|
+
} = options;
|
|
148363
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: amount=${amount}, mintUrl=${mintUrl}, baseUrl=${baseUrl}, reuseToken=${reuseToken}`);
|
|
148364
|
+
let adjustedAmount = Math.ceil(amount);
|
|
148365
|
+
if (!adjustedAmount || isNaN(adjustedAmount)) {
|
|
148366
|
+
this._log("ERROR", `[CashuSpender] _spendInternal: Invalid amount: ${amount}`);
|
|
148367
|
+
return {
|
|
148368
|
+
token: null,
|
|
148369
|
+
status: "failed",
|
|
148370
|
+
balance: 0,
|
|
148371
|
+
error: "Please enter a valid amount"
|
|
148372
|
+
};
|
|
148373
|
+
}
|
|
148374
|
+
if (reuseToken && baseUrl) {
|
|
148375
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: Attempting to reuse token for ${baseUrl}`);
|
|
148376
|
+
const existingResult = await this._tryReuseToken(baseUrl, adjustedAmount, mintUrl);
|
|
148377
|
+
if (existingResult) {
|
|
148378
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: Successfully reused token, balance: ${existingResult.balance}`);
|
|
148379
|
+
return existingResult;
|
|
148380
|
+
}
|
|
148381
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: Could not reuse token, will create new token`);
|
|
148382
|
+
}
|
|
148383
|
+
const balanceState = await this._getBalanceState();
|
|
148384
|
+
const totalAvailableBalance = balanceState.totalBalance;
|
|
148385
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: totalAvailableBalance=${totalAvailableBalance}, adjustedAmount=${adjustedAmount}`);
|
|
148386
|
+
if (totalAvailableBalance < adjustedAmount) {
|
|
148387
|
+
this._log("ERROR", `[CashuSpender] _spendInternal: Insufficient balance, have=${totalAvailableBalance}, need=${adjustedAmount}`);
|
|
148388
|
+
return this._createInsufficientBalanceError(adjustedAmount, balanceState.mintBalances, totalAvailableBalance);
|
|
148389
|
+
}
|
|
148390
|
+
let token = null;
|
|
148391
|
+
let selectedMintUrl;
|
|
148392
|
+
let spentAmount = adjustedAmount;
|
|
148393
|
+
if (this.balanceManager) {
|
|
148394
|
+
const tokenResult = await this.balanceManager.createProviderToken({
|
|
148395
|
+
mintUrl,
|
|
148396
|
+
baseUrl,
|
|
148397
|
+
amount: adjustedAmount,
|
|
148398
|
+
p2pkPubkey,
|
|
148399
|
+
excludeMints,
|
|
148400
|
+
retryCount
|
|
148401
|
+
});
|
|
148402
|
+
if (!tokenResult.success || !tokenResult.token) {
|
|
148403
|
+
if ((tokenResult.error || "").includes("Insufficient balance")) {
|
|
148404
|
+
return this._createInsufficientBalanceError(adjustedAmount, balanceState.mintBalances, totalAvailableBalance);
|
|
148405
|
+
}
|
|
148406
|
+
return {
|
|
148407
|
+
token: null,
|
|
148408
|
+
status: "failed",
|
|
148409
|
+
balance: 0,
|
|
148410
|
+
error: tokenResult.error || "Failed to create token"
|
|
148411
|
+
};
|
|
148412
|
+
}
|
|
148413
|
+
token = tokenResult.token;
|
|
148414
|
+
selectedMintUrl = tokenResult.selectedMintUrl;
|
|
148415
|
+
spentAmount = tokenResult.amountSpent || adjustedAmount;
|
|
148416
|
+
} else {
|
|
148417
|
+
try {
|
|
148418
|
+
token = await this.walletAdapter.sendToken(mintUrl, adjustedAmount, p2pkPubkey);
|
|
148419
|
+
selectedMintUrl = mintUrl;
|
|
148420
|
+
} catch (error53) {
|
|
148421
|
+
const errorMsg = error53 instanceof Error ? error53.message : String(error53);
|
|
148422
|
+
return {
|
|
148423
|
+
token: null,
|
|
148424
|
+
status: "failed",
|
|
148425
|
+
balance: 0,
|
|
148426
|
+
error: `Error generating token: ${errorMsg}`
|
|
148427
|
+
};
|
|
148428
|
+
}
|
|
148429
|
+
}
|
|
148430
|
+
if (token) {
|
|
148431
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`);
|
|
148432
|
+
}
|
|
148433
|
+
this._log("DEBUG", `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`);
|
|
148434
|
+
const units = this.walletAdapter.getMintUnits();
|
|
148435
|
+
return {
|
|
148436
|
+
token,
|
|
148437
|
+
status: "success",
|
|
148438
|
+
balance: spentAmount,
|
|
148439
|
+
unit: (selectedMintUrl ? units[selectedMintUrl] : units[mintUrl]) || "sat",
|
|
148440
|
+
selectedMintUrl: selectedMintUrl || mintUrl
|
|
148441
|
+
};
|
|
148442
|
+
}
|
|
148443
|
+
async _tryReuseToken(baseUrl, amount, mintUrl) {
|
|
148444
|
+
const apiKeyEntry = this.storageAdapter.getApiKey(baseUrl);
|
|
148445
|
+
if (!apiKeyEntry)
|
|
148446
|
+
return null;
|
|
148447
|
+
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
148448
|
+
const balanceForBaseUrl = apiKeyDistribution.find((b2) => b2.baseUrl === baseUrl)?.amount || 0;
|
|
148449
|
+
this._log("DEBUG", "Reusing API key", balanceForBaseUrl, amount);
|
|
148450
|
+
if (balanceForBaseUrl > amount) {
|
|
148451
|
+
const units = this.walletAdapter.getMintUnits();
|
|
148452
|
+
const unit = units[mintUrl] || "sat";
|
|
148453
|
+
return {
|
|
148454
|
+
token: apiKeyEntry.key,
|
|
148455
|
+
status: "success",
|
|
148456
|
+
balance: balanceForBaseUrl,
|
|
148457
|
+
unit
|
|
148458
|
+
};
|
|
148459
|
+
}
|
|
148460
|
+
if (this.balanceManager) {
|
|
148461
|
+
const topUpAmount = Math.ceil(amount * 1.2 - balanceForBaseUrl);
|
|
148462
|
+
const topUpResult = await this.balanceManager.topUp({
|
|
148463
|
+
mintUrl,
|
|
148464
|
+
baseUrl,
|
|
148465
|
+
amount: topUpAmount,
|
|
148466
|
+
token: apiKeyEntry.key
|
|
148467
|
+
});
|
|
148468
|
+
this._log("DEBUG", "TOPUP ", topUpResult);
|
|
148469
|
+
if (topUpResult.success && topUpResult.toppedUpAmount) {
|
|
148470
|
+
const newBalance = balanceForBaseUrl + topUpResult.toppedUpAmount;
|
|
148471
|
+
const units = this.walletAdapter.getMintUnits();
|
|
148472
|
+
const unit = units[mintUrl] || "sat";
|
|
148473
|
+
return {
|
|
148474
|
+
token: apiKeyEntry.key,
|
|
148475
|
+
status: "success",
|
|
148476
|
+
balance: newBalance,
|
|
148477
|
+
unit
|
|
148478
|
+
};
|
|
148479
|
+
}
|
|
148480
|
+
const providerBalance = await this._getProviderTokenBalance(baseUrl, apiKeyEntry.key);
|
|
148481
|
+
this._log("DEBUG", providerBalance);
|
|
148482
|
+
if (providerBalance <= 0) {
|
|
148483
|
+
this.storageAdapter.removeApiKey(baseUrl);
|
|
148484
|
+
}
|
|
148485
|
+
}
|
|
148486
|
+
return null;
|
|
148487
|
+
}
|
|
148488
|
+
async refundXcashuTokens(mintUrl, excludeBaseUrls) {
|
|
148489
|
+
const results = [];
|
|
148490
|
+
const xcashuTokens = this.storageAdapter.getXcashuTokens();
|
|
148491
|
+
const excludedUrls = new Set(excludeBaseUrls || []);
|
|
148492
|
+
for (const [baseUrl, tokens] of Object.entries(xcashuTokens)) {
|
|
148493
|
+
if (excludedUrls.has(baseUrl))
|
|
148494
|
+
continue;
|
|
148495
|
+
for (const xcashuToken of tokens) {
|
|
148496
|
+
try {
|
|
148497
|
+
if (!this.balanceManager) {
|
|
148498
|
+
throw new Error("BalanceManager not available for xcashu refund");
|
|
148499
|
+
}
|
|
148500
|
+
const fetchResult = await this.balanceManager.fetchRefundToken(baseUrl, xcashuToken.token, true);
|
|
148501
|
+
if (!fetchResult.success && fetchResult.status === 425) {
|
|
148502
|
+
results.push({
|
|
148503
|
+
baseUrl,
|
|
148504
|
+
token: xcashuToken.token,
|
|
148505
|
+
success: false,
|
|
148506
|
+
error: fetchResult.error
|
|
148507
|
+
});
|
|
148508
|
+
this._log("WARN", `[CashuSpender] refundXcashuTokens: 425 "Refund is pending" for ${baseUrl}; leaving token in store, tryCount untouched`);
|
|
148509
|
+
continue;
|
|
148510
|
+
}
|
|
148511
|
+
if (!fetchResult.success && fetchResult.parsedError?.type === CoreErrorType2.TOKEN_ALREADY_SPENT) {
|
|
148512
|
+
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
148513
|
+
results.push({
|
|
148514
|
+
baseUrl,
|
|
148515
|
+
token: xcashuToken.token,
|
|
148516
|
+
success: false,
|
|
148517
|
+
error: fetchResult.error
|
|
148518
|
+
});
|
|
148519
|
+
this._log("WARN", `[CashuSpender] refundXcashuTokens: token_already_spent for ${baseUrl}; removing permanently-spent xcashu token from store`);
|
|
148520
|
+
continue;
|
|
148521
|
+
}
|
|
148522
|
+
if (!fetchResult.success && fetchResult.parsedError && isHandledRedemptionError2(fetchResult.parsedError)) {
|
|
148523
|
+
const directReceive = await this.receiveToken(xcashuToken.token);
|
|
148524
|
+
if (directReceive.success) {
|
|
148525
|
+
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
148526
|
+
results.push({
|
|
148527
|
+
baseUrl,
|
|
148528
|
+
token: xcashuToken.token,
|
|
148529
|
+
success: true
|
|
148530
|
+
});
|
|
148531
|
+
this._log("DEBUG", `[CashuSpender] refundXcashuTokens: provider returned ${fetchResult.parsedError.type}/${fetchResult.parsedError.code}; recovered original token directly, amount=${directReceive.amount}`);
|
|
148532
|
+
continue;
|
|
148533
|
+
}
|
|
148534
|
+
this._log("WARN", `[CashuSpender] refundXcashuTokens: provider returned ${fetchResult.parsedError.type}/${fetchResult.parsedError.code}; direct original-token recovery also failed: ${directReceive.message ?? "unknown error"}`);
|
|
148535
|
+
}
|
|
148536
|
+
if (!fetchResult.success && fetchResult.status === 404 && (fetchResult.error || "").includes("Refund not found")) {
|
|
148537
|
+
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
148538
|
+
const newTryCount = currentTryCount + 1;
|
|
148539
|
+
if (newTryCount >= _CashuSpender2.MAX_REFUND_RETRIES) {
|
|
148540
|
+
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
148541
|
+
this._log("WARN", `[CashuSpender] refundXcashuTokens: 404 "Refund not found" for ${baseUrl} after ${newTryCount} retries; removing unrefundable xcashu token from store`);
|
|
148542
|
+
} else {
|
|
148543
|
+
this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
|
|
148544
|
+
this._log("WARN", `[CashuSpender] refundXcashuTokens: 404 "Refund not found" for ${baseUrl}; tryCount=${newTryCount}/${_CashuSpender2.MAX_REFUND_RETRIES}, will retry in ${_CashuSpender2.REFUND_RETRY_INTERVAL_MS / 1000}s`);
|
|
148545
|
+
this._startRefundRetryInterval(mintUrl);
|
|
148546
|
+
}
|
|
148547
|
+
results.push({
|
|
148548
|
+
baseUrl,
|
|
148549
|
+
token: xcashuToken.token,
|
|
148550
|
+
success: false,
|
|
148551
|
+
error: fetchResult.error
|
|
148552
|
+
});
|
|
148553
|
+
continue;
|
|
148554
|
+
}
|
|
148555
|
+
if (!fetchResult.success || !fetchResult.token) {
|
|
148556
|
+
throw new Error(fetchResult.error || "Failed to fetch refund token from provider");
|
|
148557
|
+
}
|
|
148558
|
+
const receiveResult = await this.receiveToken(fetchResult.token);
|
|
148559
|
+
if (receiveResult.success) {
|
|
148560
|
+
this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);
|
|
148561
|
+
results.push({
|
|
148562
|
+
baseUrl,
|
|
148563
|
+
token: xcashuToken.token,
|
|
148564
|
+
success: true
|
|
148565
|
+
});
|
|
148566
|
+
this._log("DEBUG", `[CashuSpender] refundXcashuTokens: Successfully refunded xcashu token for ${baseUrl}, amount=${receiveResult.amount}`);
|
|
148567
|
+
} else {
|
|
148568
|
+
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
148569
|
+
const newTryCount = currentTryCount + 1;
|
|
148570
|
+
this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
|
|
148571
|
+
results.push({
|
|
148572
|
+
baseUrl,
|
|
148573
|
+
token: xcashuToken.token,
|
|
148574
|
+
success: false,
|
|
148575
|
+
error: receiveResult.message ?? "Refund failed"
|
|
148576
|
+
});
|
|
148577
|
+
this._log("DEBUG", `[CashuSpender] refundXcashuTokens: Failed to receive refund token for ${baseUrl}, incremented tryCount to ${newTryCount}: ${receiveResult.message}`);
|
|
148578
|
+
}
|
|
148579
|
+
} catch (error53) {
|
|
148580
|
+
const currentTryCount = xcashuToken.tryCount ?? 0;
|
|
148581
|
+
const newTryCount = currentTryCount + 1;
|
|
148582
|
+
this.storageAdapter.updateXcashuTokenTryCount(xcashuToken.token, newTryCount);
|
|
148583
|
+
const errorMessage = error53 instanceof Error ? error53.message : String(error53);
|
|
148584
|
+
results.push({
|
|
148585
|
+
baseUrl,
|
|
148586
|
+
token: xcashuToken.token,
|
|
148587
|
+
success: false,
|
|
148588
|
+
error: errorMessage
|
|
148589
|
+
});
|
|
148590
|
+
this._log("ERROR", `[CashuSpender] refundXcashuTokens: Exception during refund for ${baseUrl}: ${errorMessage}, incremented tryCount to ${newTryCount}`);
|
|
148591
|
+
}
|
|
148592
|
+
}
|
|
148593
|
+
}
|
|
148594
|
+
return results;
|
|
148595
|
+
}
|
|
148596
|
+
_startRefundRetryInterval(mintUrl) {
|
|
148597
|
+
if (this._refundRetryInterval)
|
|
148598
|
+
return;
|
|
148599
|
+
this._log("DEBUG", `[CashuSpender] Starting refund retry interval (every ${_CashuSpender2.REFUND_RETRY_INTERVAL_MS / 1000}s)`);
|
|
148600
|
+
this._refundRetryInterval = setInterval(async () => {
|
|
148601
|
+
const remainingTokens = this.storageAdapter.getXcashuTokens();
|
|
148602
|
+
const hasTokens = Object.values(remainingTokens).some((tokens) => tokens.length > 0);
|
|
148603
|
+
if (!hasTokens) {
|
|
148604
|
+
this._stopRefundRetryInterval();
|
|
148605
|
+
return;
|
|
148606
|
+
}
|
|
148607
|
+
try {
|
|
148608
|
+
await this.refundXcashuTokens(mintUrl);
|
|
148609
|
+
} catch (error53) {
|
|
148610
|
+
this._log("ERROR", `[CashuSpender] Refund retry interval error: ${error53 instanceof Error ? error53.message : String(error53)}`);
|
|
148611
|
+
}
|
|
148612
|
+
}, _CashuSpender2.REFUND_RETRY_INTERVAL_MS);
|
|
148613
|
+
}
|
|
148614
|
+
_stopRefundRetryInterval() {
|
|
148615
|
+
if (this._refundRetryInterval) {
|
|
148616
|
+
clearInterval(this._refundRetryInterval);
|
|
148617
|
+
this._refundRetryInterval = null;
|
|
148618
|
+
this._log("DEBUG", `[CashuSpender] Stopped refund retry interval`);
|
|
148619
|
+
}
|
|
148620
|
+
}
|
|
148621
|
+
async refundProviders(mintUrl, forceRefund) {
|
|
148622
|
+
const results = [];
|
|
148623
|
+
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
148624
|
+
for (const apiKeyEntry of apiKeyDistribution) {
|
|
148625
|
+
const apiKeyEntryFull = this.storageAdapter.getApiKey(apiKeyEntry.baseUrl);
|
|
148626
|
+
if (apiKeyEntryFull && this.balanceManager) {
|
|
148627
|
+
try {
|
|
148628
|
+
const balanceResult = await this.balanceManager.getTokenBalance(apiKeyEntryFull.key, apiKeyEntry.baseUrl);
|
|
148629
|
+
if (balanceResult.isInvalidApiKey) {
|
|
148630
|
+
this.logger.warn(`refundProviders: ${apiKeyEntry.baseUrl} returned invalid API key; removing local key and treating as success`);
|
|
148631
|
+
this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);
|
|
148632
|
+
results.push({
|
|
148633
|
+
baseUrl: apiKeyEntry.baseUrl,
|
|
148634
|
+
success: true
|
|
148635
|
+
});
|
|
148636
|
+
continue;
|
|
148637
|
+
}
|
|
148638
|
+
if (balanceResult.amount >= 0 && !balanceResult.balanceUnknown) {
|
|
148639
|
+
const balanceSat = balanceResult.unit === "msat" ? Math.floor(balanceResult.amount / 1000) : balanceResult.amount;
|
|
148640
|
+
const reservedSat = balanceResult.unit === "msat" ? Math.floor(balanceResult.reserved / 1000) : balanceResult.reserved;
|
|
148641
|
+
this.storageAdapter.updateApiKeyBalance(apiKeyEntry.baseUrl, balanceSat, reservedSat);
|
|
148642
|
+
} else {
|
|
148643
|
+
this.logger.warn(`refundProviders: balance refresh for ${apiKeyEntry.baseUrl} returned negative amount; keeping stale local balance=${apiKeyEntryFull.balance}`);
|
|
148644
|
+
}
|
|
148645
|
+
} catch (error53) {
|
|
148646
|
+
this.logger.warn(`refundProviders: balance refresh threw for ${apiKeyEntry.baseUrl}; proceeding with stale local balance`, error53);
|
|
148647
|
+
}
|
|
148648
|
+
const refreshedEntry = this.storageAdapter.getApiKey(apiKeyEntry.baseUrl);
|
|
148649
|
+
if (!refreshedEntry) {
|
|
148650
|
+
continue;
|
|
148651
|
+
}
|
|
148652
|
+
const refundResult = await this.balanceManager.refundApiKey({
|
|
148653
|
+
mintUrl,
|
|
148654
|
+
baseUrl: apiKeyEntry.baseUrl,
|
|
148655
|
+
apiKey: refreshedEntry.key,
|
|
148656
|
+
forceRefund
|
|
148657
|
+
});
|
|
148658
|
+
if (refundResult.success) {
|
|
148659
|
+
this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);
|
|
148660
|
+
} else {
|
|
148661
|
+
const currentEntry = this.storageAdapter.getApiKey(apiKeyEntry.baseUrl);
|
|
148662
|
+
this.logger.warn(`refundProviders: refund failed for ${apiKeyEntry.baseUrl}; currentEntry=${Boolean(currentEntry)} balance=${currentEntry?.balance ?? "none"}. Touching lastUsed to rate-limit retries.`);
|
|
148663
|
+
if (currentEntry) {
|
|
148664
|
+
this.storageAdapter.touchApiKeyLastUsed(apiKeyEntry.baseUrl);
|
|
148665
|
+
}
|
|
148666
|
+
}
|
|
148667
|
+
results.push({
|
|
148668
|
+
baseUrl: apiKeyEntry.baseUrl,
|
|
148669
|
+
success: refundResult.success
|
|
148670
|
+
});
|
|
148671
|
+
} else {
|
|
148672
|
+
this.logger.warn(`refundProviders: cannot refund ${apiKeyEntry.baseUrl}; apiKeyEntryFull=${Boolean(apiKeyEntryFull)} balanceManager=${Boolean(this.balanceManager)}`);
|
|
148673
|
+
results.push({
|
|
148674
|
+
baseUrl: apiKeyEntry.baseUrl,
|
|
148675
|
+
success: false
|
|
148676
|
+
});
|
|
148677
|
+
}
|
|
148678
|
+
}
|
|
148679
|
+
return results;
|
|
148680
|
+
}
|
|
148681
|
+
_createInsufficientBalanceError(required2, normalizedBalances, availableBalance) {
|
|
148682
|
+
let maxBalance = 0;
|
|
148683
|
+
let maxMintUrl = "";
|
|
148684
|
+
for (const mintUrl in normalizedBalances) {
|
|
148685
|
+
const balanceInSats = normalizedBalances[mintUrl];
|
|
148686
|
+
if (balanceInSats > maxBalance) {
|
|
148687
|
+
maxBalance = balanceInSats;
|
|
148688
|
+
maxMintUrl = mintUrl;
|
|
148689
|
+
}
|
|
148690
|
+
}
|
|
148691
|
+
const error53 = new InsufficientBalanceError2(required2, availableBalance ?? maxBalance, maxBalance, maxMintUrl);
|
|
148692
|
+
return {
|
|
148693
|
+
token: null,
|
|
148694
|
+
status: "failed",
|
|
148695
|
+
balance: 0,
|
|
148696
|
+
error: error53.message,
|
|
148697
|
+
errorDetails: {
|
|
148698
|
+
required: required2,
|
|
148699
|
+
available: availableBalance ?? maxBalance,
|
|
148700
|
+
maxMintBalance: maxBalance,
|
|
148701
|
+
maxMintUrl
|
|
148702
|
+
}
|
|
148703
|
+
};
|
|
148704
|
+
}
|
|
148705
|
+
async _getProviderTokenBalance(baseUrl, token) {
|
|
148706
|
+
try {
|
|
148707
|
+
const response = await fetch(`${baseUrl}v1/wallet/info`, {
|
|
148708
|
+
headers: {
|
|
148709
|
+
Authorization: `Bearer ${token}`
|
|
148710
|
+
}
|
|
148711
|
+
});
|
|
148712
|
+
if (response.ok) {
|
|
148713
|
+
const data = await response.json();
|
|
148714
|
+
return data.balance / 1000;
|
|
148715
|
+
}
|
|
148716
|
+
} catch {
|
|
148717
|
+
return 0;
|
|
148718
|
+
}
|
|
148719
|
+
return 0;
|
|
148720
|
+
}
|
|
148721
|
+
};
|
|
148722
|
+
MAX_ORIGINAL_IMAGE_TOKENS2 = Math.ceil(MAX_IMAGE_PATCHES2 * 1.2);
|
|
147280
148723
|
BunModelManager = class extends ModelManager2 {
|
|
147281
148724
|
constructor(adapter, config2 = {}) {
|
|
147282
148725
|
super(adapter, {
|
|
@@ -151495,20 +152938,20 @@ __export(exports_utils4, {
|
|
|
151495
152938
|
numberToBytesLE: () => numberToBytesLE7,
|
|
151496
152939
|
numberToBytesBE: () => numberToBytesBE8,
|
|
151497
152940
|
hexToNumber: () => hexToNumber8,
|
|
151498
|
-
hexToBytes: () =>
|
|
152941
|
+
hexToBytes: () => hexToBytes17,
|
|
151499
152942
|
equalBytes: () => equalBytes10,
|
|
151500
152943
|
ensureBytes: () => ensureBytes5,
|
|
151501
152944
|
createHmacDrbg: () => createHmacDrbg7,
|
|
151502
152945
|
concatBytes: () => concatBytes17,
|
|
151503
152946
|
bytesToNumberLE: () => bytesToNumberLE7,
|
|
151504
152947
|
bytesToNumberBE: () => bytesToNumberBE7,
|
|
151505
|
-
bytesToHex: () =>
|
|
152948
|
+
bytesToHex: () => bytesToHex19,
|
|
151506
152949
|
bitSet: () => bitSet4,
|
|
151507
152950
|
bitMask: () => bitMask7,
|
|
151508
152951
|
bitLen: () => bitLen7,
|
|
151509
152952
|
bitGet: () => bitGet4
|
|
151510
152953
|
});
|
|
151511
|
-
function
|
|
152954
|
+
function bytesToHex19(bytes10) {
|
|
151512
152955
|
if (!u8a11(bytes10))
|
|
151513
152956
|
throw new Error("Uint8Array expected");
|
|
151514
152957
|
let hex8 = "";
|
|
@@ -151526,7 +152969,7 @@ function hexToNumber8(hex8) {
|
|
|
151526
152969
|
throw new Error("hex string expected, got " + typeof hex8);
|
|
151527
152970
|
return BigInt(hex8 === "" ? "0" : `0x${hex8}`);
|
|
151528
152971
|
}
|
|
151529
|
-
function
|
|
152972
|
+
function hexToBytes17(hex8) {
|
|
151530
152973
|
if (typeof hex8 !== "string")
|
|
151531
152974
|
throw new Error("hex string expected, got " + typeof hex8);
|
|
151532
152975
|
const len = hex8.length;
|
|
@@ -151544,27 +152987,27 @@ function hexToBytes16(hex8) {
|
|
|
151544
152987
|
return array2;
|
|
151545
152988
|
}
|
|
151546
152989
|
function bytesToNumberBE7(bytes10) {
|
|
151547
|
-
return hexToNumber8(
|
|
152990
|
+
return hexToNumber8(bytesToHex19(bytes10));
|
|
151548
152991
|
}
|
|
151549
152992
|
function bytesToNumberLE7(bytes10) {
|
|
151550
152993
|
if (!u8a11(bytes10))
|
|
151551
152994
|
throw new Error("Uint8Array expected");
|
|
151552
|
-
return hexToNumber8(
|
|
152995
|
+
return hexToNumber8(bytesToHex19(Uint8Array.from(bytes10).reverse()));
|
|
151553
152996
|
}
|
|
151554
152997
|
function numberToBytesBE8(n, len) {
|
|
151555
|
-
return
|
|
152998
|
+
return hexToBytes17(n.toString(16).padStart(len * 2, "0"));
|
|
151556
152999
|
}
|
|
151557
153000
|
function numberToBytesLE7(n, len) {
|
|
151558
153001
|
return numberToBytesBE8(n, len).reverse();
|
|
151559
153002
|
}
|
|
151560
153003
|
function numberToVarBytesBE4(n) {
|
|
151561
|
-
return
|
|
153004
|
+
return hexToBytes17(numberToHexUnpadded7(n));
|
|
151562
153005
|
}
|
|
151563
153006
|
function ensureBytes5(title, hex8, expectedLength) {
|
|
151564
153007
|
let res;
|
|
151565
153008
|
if (typeof hex8 === "string") {
|
|
151566
153009
|
try {
|
|
151567
|
-
res =
|
|
153010
|
+
res = hexToBytes17(hex8);
|
|
151568
153011
|
} catch (e57) {
|
|
151569
153012
|
throw new Error(`${title} must be valid hex string, got "${hex8}". Cause: ${e57}`);
|
|
151570
153013
|
}
|
|
@@ -152130,7 +153573,7 @@ function weierstrassPoints4(opts) {
|
|
|
152130
153573
|
const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
|
|
152131
153574
|
if (lengths && typeof key !== "bigint") {
|
|
152132
153575
|
if (key instanceof Uint8Array)
|
|
152133
|
-
key =
|
|
153576
|
+
key = bytesToHex19(key);
|
|
152134
153577
|
if (typeof key !== "string" || !lengths.includes(key.length))
|
|
152135
153578
|
throw new Error("Invalid key");
|
|
152136
153579
|
key = key.padStart(nByteLength * 2, "0");
|
|
@@ -152421,7 +153864,7 @@ function weierstrassPoints4(opts) {
|
|
|
152421
153864
|
return toBytes12(Point6, this, isCompressed);
|
|
152422
153865
|
}
|
|
152423
153866
|
toHex(isCompressed = true) {
|
|
152424
|
-
return
|
|
153867
|
+
return bytesToHex19(this.toRawBytes(isCompressed));
|
|
152425
153868
|
}
|
|
152426
153869
|
}
|
|
152427
153870
|
Point6.BASE = new Point6(CURVE.Gx, CURVE.Gy, Fp6.ONE);
|
|
@@ -152499,7 +153942,7 @@ function weierstrass7(curveDef) {
|
|
|
152499
153942
|
}
|
|
152500
153943
|
}
|
|
152501
153944
|
});
|
|
152502
|
-
const numToNByteStr = (num3) =>
|
|
153945
|
+
const numToNByteStr = (num3) => bytesToHex19(numberToBytesBE8(num3, CURVE.nByteLength));
|
|
152503
153946
|
function isBiggerThanHalfOrder(number13) {
|
|
152504
153947
|
const HALF = CURVE_ORDER >> _1n36;
|
|
152505
153948
|
return number13 > HALF;
|
|
@@ -152560,13 +154003,13 @@ function weierstrass7(curveDef) {
|
|
|
152560
154003
|
return this.hasHighS() ? new Signature(this.r, modN4(-this.s), this.recovery) : this;
|
|
152561
154004
|
}
|
|
152562
154005
|
toDERRawBytes() {
|
|
152563
|
-
return
|
|
154006
|
+
return hexToBytes17(this.toDERHex());
|
|
152564
154007
|
}
|
|
152565
154008
|
toDERHex() {
|
|
152566
154009
|
return DER7.hexFromSig({ r: this.r, s: this.s });
|
|
152567
154010
|
}
|
|
152568
154011
|
toCompactRawBytes() {
|
|
152569
|
-
return
|
|
154012
|
+
return hexToBytes17(this.toCompactHex());
|
|
152570
154013
|
}
|
|
152571
154014
|
toCompactHex() {
|
|
152572
154015
|
return numToNByteStr(this.r) + numToNByteStr(this.s);
|
|
@@ -153061,7 +154504,7 @@ var init_cryptoNode9 = __esm(() => {
|
|
|
153061
154504
|
});
|
|
153062
154505
|
|
|
153063
154506
|
// node_modules/applesauce-wallet-connect/node_modules/applesauce-core/node_modules/nostr-tools/node_modules/@noble/hashes/esm/utils.js
|
|
153064
|
-
function
|
|
154507
|
+
function bytesToHex20(bytes10) {
|
|
153065
154508
|
if (!u8a12(bytes10))
|
|
153066
154509
|
throw new Error("Uint8Array expected");
|
|
153067
154510
|
let hex8 = "";
|
|
@@ -153070,7 +154513,7 @@ function bytesToHex19(bytes10) {
|
|
|
153070
154513
|
}
|
|
153071
154514
|
return hex8;
|
|
153072
154515
|
}
|
|
153073
|
-
function
|
|
154516
|
+
function hexToBytes18(hex8) {
|
|
153074
154517
|
if (typeof hex8 !== "string")
|
|
153075
154518
|
throw new Error("hex string expected, got " + typeof hex8);
|
|
153076
154519
|
const len = hex8.length;
|
|
@@ -153752,7 +155195,7 @@ function genBech326(encoding2) {
|
|
|
153752
155195
|
return { encode: encode5, decode: decode7, decodeToBytes, decodeUnsafe, fromWords, fromWordsUnsafe, toWords };
|
|
153753
155196
|
}
|
|
153754
155197
|
var gcd6 = (a, b3) => !b3 ? a : gcd6(b3, a % b3), radix2carry6 = (from8, to) => from8 + (to - gcd6(from8, to)), base166, base326, base32hex6, base32crockford6, base649, base64url8, genBase586 = (abc) => chain6(radix8(58), alphabet6(abc), join15("")), base586, base58flickr6, base58xrp6, XMR_BLOCK_LEN4, base58xmr4, BECH_ALPHABET6, POLYMOD_GENERATORS6, bech326, bech32m6, utf84, hex8, CODERS4, coderTypeError4;
|
|
153755
|
-
var
|
|
155198
|
+
var init_esm9 = __esm(() => {
|
|
153756
155199
|
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
153757
155200
|
base166 = chain6(radix26(4), alphabet6("0123456789ABCDEF"), join15(""));
|
|
153758
155201
|
base326 = chain6(radix26(5), alphabet6("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"), padding6(5), join15(""));
|
|
@@ -153848,7 +155291,7 @@ function output11(out, instance) {
|
|
|
153848
155291
|
var init__assert11 = () => {};
|
|
153849
155292
|
|
|
153850
155293
|
// node_modules/applesauce-wallet-connect/node_modules/applesauce-core/node_modules/nostr-tools/node_modules/@noble/ciphers/esm/utils.js
|
|
153851
|
-
function
|
|
155294
|
+
function bytesToHex21(bytes12) {
|
|
153852
155295
|
bytes11(bytes12);
|
|
153853
155296
|
let hex9 = "";
|
|
153854
155297
|
for (let i8 = 0;i8 < bytes12.length; i8++) {
|
|
@@ -153865,7 +155308,7 @@ function asciiToBase166(char) {
|
|
|
153865
155308
|
return char - (asciis6._a - 10);
|
|
153866
155309
|
return;
|
|
153867
155310
|
}
|
|
153868
|
-
function
|
|
155311
|
+
function hexToBytes19(hex9) {
|
|
153869
155312
|
if (typeof hex9 !== "string")
|
|
153870
155313
|
throw new Error("hex string expected, got " + typeof hex9);
|
|
153871
155314
|
const hl = hex9.length;
|
|
@@ -155495,7 +156938,7 @@ function serializeEvent8(evt) {
|
|
|
155495
156938
|
}
|
|
155496
156939
|
function getEventHash8(event7) {
|
|
155497
156940
|
let eventHash = sha25613(utf8Encoder13.encode(serializeEvent8(event7)));
|
|
155498
|
-
return
|
|
156941
|
+
return bytesToHex20(eventHash);
|
|
155499
156942
|
}
|
|
155500
156943
|
function isRegularKind7(kind) {
|
|
155501
156944
|
return kind < 1e4 && kind !== 0 && kind !== 3;
|
|
@@ -155660,7 +157103,7 @@ function decode7(code) {
|
|
|
155660
157103
|
return {
|
|
155661
157104
|
type: "nprofile",
|
|
155662
157105
|
data: {
|
|
155663
|
-
pubkey:
|
|
157106
|
+
pubkey: bytesToHex20(tlv[0][0]),
|
|
155664
157107
|
relays: tlv[1] ? tlv[1].map((d2) => utf8Decoder11.decode(d2)) : []
|
|
155665
157108
|
}
|
|
155666
157109
|
};
|
|
@@ -155678,10 +157121,10 @@ function decode7(code) {
|
|
|
155678
157121
|
return {
|
|
155679
157122
|
type: "nevent",
|
|
155680
157123
|
data: {
|
|
155681
|
-
id:
|
|
157124
|
+
id: bytesToHex20(tlv[0][0]),
|
|
155682
157125
|
relays: tlv[1] ? tlv[1].map((d2) => utf8Decoder11.decode(d2)) : [],
|
|
155683
|
-
author: tlv[2]?.[0] ?
|
|
155684
|
-
kind: tlv[3]?.[0] ? parseInt(
|
|
157126
|
+
author: tlv[2]?.[0] ? bytesToHex20(tlv[2][0]) : undefined,
|
|
157127
|
+
kind: tlv[3]?.[0] ? parseInt(bytesToHex20(tlv[3][0]), 16) : undefined
|
|
155685
157128
|
}
|
|
155686
157129
|
};
|
|
155687
157130
|
}
|
|
@@ -155701,8 +157144,8 @@ function decode7(code) {
|
|
|
155701
157144
|
type: "naddr",
|
|
155702
157145
|
data: {
|
|
155703
157146
|
identifier: utf8Decoder11.decode(tlv[0][0]),
|
|
155704
|
-
pubkey:
|
|
155705
|
-
kind: parseInt(
|
|
157147
|
+
pubkey: bytesToHex20(tlv[2][0]),
|
|
157148
|
+
kind: parseInt(bytesToHex20(tlv[3][0]), 16),
|
|
155706
157149
|
relays: tlv[1] ? tlv[1].map((d2) => utf8Decoder11.decode(d2)) : []
|
|
155707
157150
|
}
|
|
155708
157151
|
};
|
|
@@ -155711,7 +157154,7 @@ function decode7(code) {
|
|
|
155711
157154
|
return { type: prefix, data };
|
|
155712
157155
|
case "npub":
|
|
155713
157156
|
case "note":
|
|
155714
|
-
return { type: prefix, data:
|
|
157157
|
+
return { type: prefix, data: bytesToHex20(data) };
|
|
155715
157158
|
default:
|
|
155716
157159
|
throw new Error(`unknown prefix ${prefix}`);
|
|
155717
157160
|
}
|
|
@@ -155735,10 +157178,10 @@ function nsecEncode5(key) {
|
|
|
155735
157178
|
return encodeBytes5("nsec", key);
|
|
155736
157179
|
}
|
|
155737
157180
|
function npubEncode6(hex9) {
|
|
155738
|
-
return encodeBytes5("npub",
|
|
157181
|
+
return encodeBytes5("npub", hexToBytes18(hex9));
|
|
155739
157182
|
}
|
|
155740
157183
|
function noteEncode5(hex9) {
|
|
155741
|
-
return encodeBytes5("note",
|
|
157184
|
+
return encodeBytes5("note", hexToBytes18(hex9));
|
|
155742
157185
|
}
|
|
155743
157186
|
function encodeBech325(prefix, data) {
|
|
155744
157187
|
let words = bech326.toWords(data);
|
|
@@ -155749,7 +157192,7 @@ function encodeBytes5(prefix, bytes12) {
|
|
|
155749
157192
|
}
|
|
155750
157193
|
function nprofileEncode5(profile6) {
|
|
155751
157194
|
let data = encodeTLV5({
|
|
155752
|
-
0: [
|
|
157195
|
+
0: [hexToBytes18(profile6.pubkey)],
|
|
155753
157196
|
1: (profile6.relays || []).map((url4) => utf8Encoder13.encode(url4))
|
|
155754
157197
|
});
|
|
155755
157198
|
return encodeBech325("nprofile", data);
|
|
@@ -155760,9 +157203,9 @@ function neventEncode5(event7) {
|
|
|
155760
157203
|
kindArray = integerToUint8Array4(event7.kind);
|
|
155761
157204
|
}
|
|
155762
157205
|
let data = encodeTLV5({
|
|
155763
|
-
0: [
|
|
157206
|
+
0: [hexToBytes18(event7.id)],
|
|
155764
157207
|
1: (event7.relays || []).map((url4) => utf8Encoder13.encode(url4)),
|
|
155765
|
-
2: event7.author ? [
|
|
157208
|
+
2: event7.author ? [hexToBytes18(event7.author)] : [],
|
|
155766
157209
|
3: kindArray ? [new Uint8Array(kindArray)] : []
|
|
155767
157210
|
});
|
|
155768
157211
|
return encodeBech325("nevent", data);
|
|
@@ -155773,7 +157216,7 @@ function naddrEncode5(addr) {
|
|
|
155773
157216
|
let data = encodeTLV5({
|
|
155774
157217
|
0: [utf8Encoder13.encode(addr.identifier)],
|
|
155775
157218
|
1: (addr.relays || []).map((url4) => utf8Encoder13.encode(url4)),
|
|
155776
|
-
2: [
|
|
157219
|
+
2: [hexToBytes18(addr.pubkey)],
|
|
155777
157220
|
3: [new Uint8Array(kind)]
|
|
155778
157221
|
});
|
|
155779
157222
|
return encodeBech325("naddr", data);
|
|
@@ -155792,7 +157235,7 @@ function encodeTLV5(tlv) {
|
|
|
155792
157235
|
return concatBytes18(...entries);
|
|
155793
157236
|
}
|
|
155794
157237
|
function encrypt9(secretKey, pubkey2, text) {
|
|
155795
|
-
const privkey = secretKey instanceof Uint8Array ?
|
|
157238
|
+
const privkey = secretKey instanceof Uint8Array ? bytesToHex20(secretKey) : secretKey;
|
|
155796
157239
|
const key = secp256k16.getSharedSecret(privkey, "02" + pubkey2);
|
|
155797
157240
|
const normalizedKey = getNormalizedX4(key);
|
|
155798
157241
|
let iv = Uint8Array.from(randomBytes13(16));
|
|
@@ -155803,7 +157246,7 @@ function encrypt9(secretKey, pubkey2, text) {
|
|
|
155803
157246
|
return `${ctb64}?iv=${ivb64}`;
|
|
155804
157247
|
}
|
|
155805
157248
|
function decrypt8(secretKey, pubkey2, data) {
|
|
155806
|
-
const privkey = secretKey instanceof Uint8Array ?
|
|
157249
|
+
const privkey = secretKey instanceof Uint8Array ? bytesToHex20(secretKey) : secretKey;
|
|
155807
157250
|
let [ctb64, ivb64] = data.split("?iv=");
|
|
155808
157251
|
let key = secp256k16.getSharedSecret(privkey, "02" + pubkey2);
|
|
155809
157252
|
let normalizedKey = getNormalizedX4(key);
|
|
@@ -155992,7 +157435,7 @@ function minePow4(unsigned, difficulty) {
|
|
|
155992
157435
|
return event7;
|
|
155993
157436
|
}
|
|
155994
157437
|
function fastEventHash3(evt) {
|
|
155995
|
-
return
|
|
157438
|
+
return bytesToHex20(sha25613(utf8Encoder13.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]))));
|
|
155996
157439
|
}
|
|
155997
157440
|
function getConversationKey4(privkeyA, pubkeyB) {
|
|
155998
157441
|
const sharedX = secp256k16.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
|
|
@@ -156740,7 +158183,7 @@ function validateEventMethodTag4(event7, method) {
|
|
|
156740
158183
|
}
|
|
156741
158184
|
function hashPayload6(payload) {
|
|
156742
158185
|
const hash10 = sha25613(utf8Encoder13.encode(JSON.stringify(payload)));
|
|
156743
|
-
return
|
|
158186
|
+
return bytesToHex20(hash10);
|
|
156744
158187
|
}
|
|
156745
158188
|
function validateEventPayloadTag4(event7, payload) {
|
|
156746
158189
|
const payloadTag = event7.tags.find((t) => t[0] === "payload");
|
|
@@ -156827,13 +158270,13 @@ var __defProp5, __export5 = (target, all) => {
|
|
|
156827
158270
|
return schnorr6.utils.randomPrivateKey();
|
|
156828
158271
|
}
|
|
156829
158272
|
getPublicKey(secretKey) {
|
|
156830
|
-
return
|
|
158273
|
+
return bytesToHex20(schnorr6.getPublicKey(secretKey));
|
|
156831
158274
|
}
|
|
156832
158275
|
finalizeEvent(t, secretKey) {
|
|
156833
158276
|
const event7 = t;
|
|
156834
|
-
event7.pubkey =
|
|
158277
|
+
event7.pubkey = bytesToHex20(schnorr6.getPublicKey(secretKey));
|
|
156835
158278
|
event7.id = getEventHash8(event7);
|
|
156836
|
-
event7.sig =
|
|
158279
|
+
event7.sig = bytesToHex20(schnorr6.sign(getEventHash8(event7), secretKey));
|
|
156837
158280
|
event7[verifiedSymbol11] = true;
|
|
156838
158281
|
return event7;
|
|
156839
158282
|
}
|
|
@@ -157456,7 +158899,7 @@ var __defProp5, __export5 = (target, all) => {
|
|
|
157456
158899
|
insert(timestamp, id) {
|
|
157457
158900
|
if (this.sealed)
|
|
157458
158901
|
throw Error("already sealed");
|
|
157459
|
-
const idb =
|
|
158902
|
+
const idb = hexToBytes19(id);
|
|
157460
158903
|
if (idb.byteLength !== ID_SIZE5)
|
|
157461
158904
|
throw Error("bad id size for added item");
|
|
157462
158905
|
this.items.push({ timestamp, id: idb });
|
|
@@ -157549,10 +158992,10 @@ var __defProp5, __export5 = (target, all) => {
|
|
|
157549
158992
|
let output12 = new WrappedBuffer5;
|
|
157550
158993
|
output12.extend(new Uint8Array([PROTOCOL_VERSION5]));
|
|
157551
158994
|
this.splitRange(0, this.storage.size(), this._bound(Number.MAX_VALUE), output12);
|
|
157552
|
-
return
|
|
158995
|
+
return bytesToHex21(output12.unwrap());
|
|
157553
158996
|
}
|
|
157554
158997
|
reconcile(queryMsg, onhave, onneed) {
|
|
157555
|
-
const query2 = new WrappedBuffer5(
|
|
158998
|
+
const query2 = new WrappedBuffer5(hexToBytes19(queryMsg));
|
|
157556
158999
|
this.lastTimestampIn = this.lastTimestampOut = 0;
|
|
157557
159000
|
let fullOutput = new WrappedBuffer5;
|
|
157558
159001
|
fullOutput.extend(new Uint8Array([PROTOCOL_VERSION5]));
|
|
@@ -157595,22 +159038,22 @@ var __defProp5, __export5 = (target, all) => {
|
|
|
157595
159038
|
let theirElems = {};
|
|
157596
159039
|
for (let i22 = 0;i22 < numIds; i22++) {
|
|
157597
159040
|
let e57 = getBytes6(query2, ID_SIZE5);
|
|
157598
|
-
theirElems[
|
|
159041
|
+
theirElems[bytesToHex21(e57)] = e57;
|
|
157599
159042
|
}
|
|
157600
159043
|
skip3 = true;
|
|
157601
159044
|
this.storage.iterate(lower, upper, (item) => {
|
|
157602
159045
|
let k6 = item.id;
|
|
157603
|
-
const id =
|
|
159046
|
+
const id = bytesToHex21(k6);
|
|
157604
159047
|
if (!theirElems[id]) {
|
|
157605
159048
|
onhave?.(id);
|
|
157606
159049
|
} else {
|
|
157607
|
-
delete theirElems[
|
|
159050
|
+
delete theirElems[bytesToHex21(k6)];
|
|
157608
159051
|
}
|
|
157609
159052
|
return true;
|
|
157610
159053
|
});
|
|
157611
159054
|
if (onneed) {
|
|
157612
159055
|
for (let v4 of Object.values(theirElems)) {
|
|
157613
|
-
onneed(
|
|
159056
|
+
onneed(bytesToHex21(v4));
|
|
157614
159057
|
}
|
|
157615
159058
|
}
|
|
157616
159059
|
} else {
|
|
@@ -157628,7 +159071,7 @@ var __defProp5, __export5 = (target, all) => {
|
|
|
157628
159071
|
prevIndex = upper;
|
|
157629
159072
|
prevBound = currBound;
|
|
157630
159073
|
}
|
|
157631
|
-
return fullOutput.length === 1 ? null :
|
|
159074
|
+
return fullOutput.length === 1 ? null : bytesToHex21(fullOutput.unwrap());
|
|
157632
159075
|
}
|
|
157633
159076
|
splitRange(lower, upper, upperBound, o) {
|
|
157634
159077
|
let numElems = upper - lower;
|
|
@@ -157781,17 +159224,17 @@ var __defProp5, __export5 = (target, all) => {
|
|
|
157781
159224
|
this.subscription.close();
|
|
157782
159225
|
}
|
|
157783
159226
|
}, nip98_exports4, _authorizationScheme6 = "Nostr ";
|
|
157784
|
-
var
|
|
159227
|
+
var init_esm10 = __esm(() => {
|
|
157785
159228
|
init_secp256k16();
|
|
157786
159229
|
init_utils27();
|
|
157787
159230
|
init_sha2568();
|
|
157788
159231
|
init_utils27();
|
|
157789
159232
|
init_utils27();
|
|
157790
|
-
|
|
159233
|
+
init_esm9();
|
|
157791
159234
|
init_utils27();
|
|
157792
159235
|
init_secp256k16();
|
|
157793
159236
|
init_aes5();
|
|
157794
|
-
|
|
159237
|
+
init_esm9();
|
|
157795
159238
|
init_utils27();
|
|
157796
159239
|
init_sha2568();
|
|
157797
159240
|
init_chacha4();
|
|
@@ -157801,13 +159244,13 @@ var init_esm9 = __esm(() => {
|
|
|
157801
159244
|
init_hmac10();
|
|
157802
159245
|
init_sha2568();
|
|
157803
159246
|
init_utils27();
|
|
157804
|
-
|
|
157805
|
-
|
|
159247
|
+
init_esm9();
|
|
159248
|
+
init_esm9();
|
|
157806
159249
|
init_utils28();
|
|
157807
159250
|
init_sha2568();
|
|
157808
159251
|
init_sha2568();
|
|
157809
159252
|
init_utils27();
|
|
157810
|
-
|
|
159253
|
+
init_esm9();
|
|
157811
159254
|
__defProp5 = Object.defineProperty;
|
|
157812
159255
|
verifiedSymbol11 = Symbol("verified");
|
|
157813
159256
|
utils_exports4 = {};
|
|
@@ -157815,8 +159258,8 @@ var init_esm9 = __esm(() => {
|
|
|
157815
159258
|
Queue: () => Queue3,
|
|
157816
159259
|
QueueNode: () => QueueNode3,
|
|
157817
159260
|
binarySearch: () => binarySearch6,
|
|
157818
|
-
bytesToHex: () =>
|
|
157819
|
-
hexToBytes: () =>
|
|
159261
|
+
bytesToHex: () => bytesToHex20,
|
|
159262
|
+
hexToBytes: () => hexToBytes18,
|
|
157820
159263
|
insertEventIntoAscendingList: () => insertEventIntoAscendingList6,
|
|
157821
159264
|
insertEventIntoDescendingList: () => insertEventIntoDescendingList6,
|
|
157822
159265
|
normalizeURL: () => normalizeURL6,
|
|
@@ -158181,20 +159624,20 @@ function serializeEvent9(evt) {
|
|
|
158181
159624
|
}
|
|
158182
159625
|
function getEventHash9(event7) {
|
|
158183
159626
|
let eventHash = sha25613(utf8Encoder14.encode(serializeEvent9(event7)));
|
|
158184
|
-
return
|
|
159627
|
+
return bytesToHex20(eventHash);
|
|
158185
159628
|
}
|
|
158186
159629
|
var verifiedSymbol12, isRecord10 = (obj2) => obj2 instanceof Object, utf8Decoder12, utf8Encoder14, JS9 = class {
|
|
158187
159630
|
generateSecretKey() {
|
|
158188
159631
|
return schnorr6.utils.randomPrivateKey();
|
|
158189
159632
|
}
|
|
158190
159633
|
getPublicKey(secretKey) {
|
|
158191
|
-
return
|
|
159634
|
+
return bytesToHex20(schnorr6.getPublicKey(secretKey));
|
|
158192
159635
|
}
|
|
158193
159636
|
finalizeEvent(t, secretKey) {
|
|
158194
159637
|
const event7 = t;
|
|
158195
|
-
event7.pubkey =
|
|
159638
|
+
event7.pubkey = bytesToHex20(schnorr6.getPublicKey(secretKey));
|
|
158196
159639
|
event7.id = getEventHash9(event7);
|
|
158197
|
-
event7.sig =
|
|
159640
|
+
event7.sig = bytesToHex20(schnorr6.sign(getEventHash9(event7), secretKey));
|
|
158198
159641
|
event7[verifiedSymbol12] = true;
|
|
158199
159642
|
return event7;
|
|
158200
159643
|
}
|
|
@@ -158330,7 +159773,7 @@ function getTagValue3(event7, name16) {
|
|
|
158330
159773
|
}
|
|
158331
159774
|
var EventStoreSymbol3, EventUIDSymbol3, ReplaceableAddressSymbol3, FromCacheSymbol3, ReplaceableIdentifierSymbol3;
|
|
158332
159775
|
var init_event7 = __esm(() => {
|
|
158333
|
-
|
|
159776
|
+
init_esm10();
|
|
158334
159777
|
init_kinds3();
|
|
158335
159778
|
init_pure3();
|
|
158336
159779
|
init_utils29();
|
|
@@ -158481,7 +159924,7 @@ var processTags3 = (tags5, ...fns) => {
|
|
|
158481
159924
|
|
|
158482
159925
|
// node_modules/applesauce-wallet-connect/node_modules/applesauce-core/node_modules/nostr-tools/lib/esm/nip19.js
|
|
158483
159926
|
function npubEncode7(hex9) {
|
|
158484
|
-
return encodeBytes6("npub",
|
|
159927
|
+
return encodeBytes6("npub", hexToBytes18(hex9));
|
|
158485
159928
|
}
|
|
158486
159929
|
function encodeBech326(prefix, data) {
|
|
158487
159930
|
let words = bech326.toWords(data);
|
|
@@ -158492,7 +159935,7 @@ function encodeBytes6(prefix, bytes12) {
|
|
|
158492
159935
|
}
|
|
158493
159936
|
function nprofileEncode6(profile6) {
|
|
158494
159937
|
let data = encodeTLV6({
|
|
158495
|
-
0: [
|
|
159938
|
+
0: [hexToBytes18(profile6.pubkey)],
|
|
158496
159939
|
1: (profile6.relays || []).map((url4) => utf8Encoder16.encode(url4))
|
|
158497
159940
|
});
|
|
158498
159941
|
return encodeBech326("nprofile", data);
|
|
@@ -158513,7 +159956,7 @@ function encodeTLV6(tlv) {
|
|
|
158513
159956
|
var utf8Decoder14, utf8Encoder16, Bech32MaxSize6 = 5000;
|
|
158514
159957
|
var init_nip192 = __esm(() => {
|
|
158515
159958
|
init_utils27();
|
|
158516
|
-
|
|
159959
|
+
init_esm9();
|
|
158517
159960
|
init_utils27();
|
|
158518
159961
|
utf8Decoder14 = new TextDecoder("utf-8");
|
|
158519
159962
|
utf8Encoder16 = new TextEncoder;
|
|
@@ -159657,7 +161100,7 @@ function isNIP04Encrypted(ciphertext) {
|
|
|
159657
161100
|
return ciphertext[l2 - 28] == "?" && ciphertext[l2 - 27] == "i" && ciphertext[l2 - 26] == "v" && ciphertext[l2 - 25] == "=";
|
|
159658
161101
|
}
|
|
159659
161102
|
var init_encryption = __esm(() => {
|
|
159660
|
-
|
|
161103
|
+
init_esm10();
|
|
159661
161104
|
});
|
|
159662
161105
|
|
|
159663
161106
|
// node_modules/applesauce-wallet-connect/dist/helpers/encryption.js
|
|
@@ -161972,7 +163415,7 @@ var init_models4 = __esm(() => {
|
|
|
161972
163415
|
|
|
161973
163416
|
// node_modules/applesauce-wallet-connect/node_modules/applesauce-core/dist/operations/client.js
|
|
161974
163417
|
var NEVER_ATTACH_CLIENT_TAG3;
|
|
161975
|
-
var
|
|
163418
|
+
var init_client7 = __esm(() => {
|
|
161976
163419
|
init_event7();
|
|
161977
163420
|
init_pointers3();
|
|
161978
163421
|
init_tags3();
|
|
@@ -161986,7 +163429,7 @@ var init_hidden_content6 = __esm(() => {
|
|
|
161986
163429
|
|
|
161987
163430
|
// node_modules/applesauce-wallet-connect/node_modules/applesauce-core/dist/operations/index.js
|
|
161988
163431
|
var init_operations3 = __esm(() => {
|
|
161989
|
-
|
|
163432
|
+
init_client7();
|
|
161990
163433
|
init_content6();
|
|
161991
163434
|
init_encrypted_content8();
|
|
161992
163435
|
init_event8();
|
|
@@ -162016,7 +163459,7 @@ function createWalletError(code, message) {
|
|
|
162016
163459
|
case "NOT_IMPLEMENTED":
|
|
162017
163460
|
return new NotImplementedError(message);
|
|
162018
163461
|
case "INSUFFICIENT_BALANCE":
|
|
162019
|
-
return new
|
|
163462
|
+
return new InsufficientBalanceError3(message);
|
|
162020
163463
|
case "QUOTA_EXCEEDED":
|
|
162021
163464
|
return new QuotaExceededError(message);
|
|
162022
163465
|
case "RESTRICTED":
|
|
@@ -162037,7 +163480,7 @@ function createWalletError(code, message) {
|
|
|
162037
163480
|
return new OtherError(message);
|
|
162038
163481
|
}
|
|
162039
163482
|
}
|
|
162040
|
-
var WalletBaseError, RateLimitedError, NotImplementedError,
|
|
163483
|
+
var WalletBaseError, RateLimitedError, NotImplementedError, InsufficientBalanceError3, QuotaExceededError, RestrictedError, UnauthorizedError, InternalError, UnsupportedEncryptionError, PaymentFailedError, NotFoundError2, OtherError;
|
|
162041
163484
|
var init_error5 = __esm(() => {
|
|
162042
163485
|
WalletBaseError = class WalletBaseError extends Error {
|
|
162043
163486
|
constructor(message) {
|
|
@@ -162051,7 +163494,7 @@ var init_error5 = __esm(() => {
|
|
|
162051
163494
|
NotImplementedError = class NotImplementedError extends WalletBaseError {
|
|
162052
163495
|
code = "NOT_IMPLEMENTED";
|
|
162053
163496
|
};
|
|
162054
|
-
|
|
163497
|
+
InsufficientBalanceError3 = class InsufficientBalanceError3 extends WalletBaseError {
|
|
162055
163498
|
code = "INSUFFICIENT_BALANCE";
|
|
162056
163499
|
};
|
|
162057
163500
|
QuotaExceededError = class QuotaExceededError extends WalletBaseError {
|
|
@@ -163523,6 +164966,35 @@ var init_usage_summary = __esm(() => {
|
|
|
163523
164966
|
};
|
|
163524
164967
|
});
|
|
163525
164968
|
|
|
164969
|
+
// src/daemon/http/request-body.ts
|
|
164970
|
+
function isOpenAiJsonBodyPath2(pathname) {
|
|
164971
|
+
const path2 = (pathname.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
164972
|
+
return OPENAI_JSON_BODY_PATH_SUFFIXES.some((suffix) => path2.endsWith(suffix));
|
|
164973
|
+
}
|
|
164974
|
+
function applyDefaultOutputTokenLimit(pathname, body, maxTokens) {
|
|
164975
|
+
if (!(maxTokens > 0) || !isOpenAiJsonBodyPath2(pathname)) {
|
|
164976
|
+
return false;
|
|
164977
|
+
}
|
|
164978
|
+
if (pathname.split("?")[0].replace(/\/+$/, "").endsWith("/responses")) {
|
|
164979
|
+
if (typeof body.max_output_tokens === "number")
|
|
164980
|
+
return false;
|
|
164981
|
+
body.max_output_tokens = maxTokens;
|
|
164982
|
+
return true;
|
|
164983
|
+
}
|
|
164984
|
+
if (typeof body.max_tokens === "number")
|
|
164985
|
+
return false;
|
|
164986
|
+
body.max_tokens = maxTokens;
|
|
164987
|
+
return true;
|
|
164988
|
+
}
|
|
164989
|
+
var OPENAI_JSON_BODY_PATH_SUFFIXES;
|
|
164990
|
+
var init_request_body = __esm(() => {
|
|
164991
|
+
OPENAI_JSON_BODY_PATH_SUFFIXES = [
|
|
164992
|
+
"/chat/completions",
|
|
164993
|
+
"/completions",
|
|
164994
|
+
"/responses"
|
|
164995
|
+
];
|
|
164996
|
+
});
|
|
164997
|
+
|
|
163526
164998
|
// src/daemon/http/index.ts
|
|
163527
164999
|
import { randomBytes as randomBytes14 } from "crypto";
|
|
163528
165000
|
import { Readable } from "stream";
|
|
@@ -164752,16 +166224,7 @@ function createDaemonRequestHandler(deps) {
|
|
|
164752
166224
|
sendJson(res, 400, { error: "Missing required 'model' field." });
|
|
164753
166225
|
return;
|
|
164754
166226
|
}
|
|
164755
|
-
|
|
164756
|
-
const isResponsesPath = url5.pathname.includes("/responses");
|
|
164757
|
-
if (isResponsesPath) {
|
|
164758
|
-
if (typeof bodyObj.max_output_tokens !== "number") {
|
|
164759
|
-
bodyObj.max_output_tokens = deps.maxTokens;
|
|
164760
|
-
}
|
|
164761
|
-
} else if (typeof bodyObj.max_tokens !== "number") {
|
|
164762
|
-
bodyObj.max_tokens = deps.maxTokens;
|
|
164763
|
-
}
|
|
164764
|
-
}
|
|
166227
|
+
applyDefaultOutputTokenLimit(url5.pathname, bodyObj, deps.maxTokens);
|
|
164765
166228
|
const forcedProvider = url5.searchParams.get("provider") || req.headers["x-routstr-provider"] || deps.provider || undefined;
|
|
164766
166229
|
const incomingHeaders = {};
|
|
164767
166230
|
for (const [key, value] of Object.entries(req.headers)) {
|
|
@@ -164874,6 +166337,7 @@ var init_http = __esm(() => {
|
|
|
164874
166337
|
init_wallet();
|
|
164875
166338
|
init_clients();
|
|
164876
166339
|
init_usage_summary();
|
|
166340
|
+
init_request_body();
|
|
164877
166341
|
HOP_BY_HOP_HEADERS = new Set([
|
|
164878
166342
|
"connection",
|
|
164879
166343
|
"keep-alive",
|
|
@@ -166193,46 +167657,111 @@ function truncateNpub(npub) {
|
|
|
166193
167657
|
return npub;
|
|
166194
167658
|
return npub.slice(0, 10) + "\u2026" + npub.slice(-6);
|
|
166195
167659
|
}
|
|
167660
|
+
function tokenSegments(entry) {
|
|
167661
|
+
const cacheRead = Math.max(0, entry.cacheReadInputTokens || 0);
|
|
167662
|
+
const cacheWrite = Math.max(0, entry.cacheCreationInputTokens || 0);
|
|
167663
|
+
const prompt = Math.max(0, entry.promptTokens || 0);
|
|
167664
|
+
const output12 = Math.max(0, entry.completionTokens || 0);
|
|
167665
|
+
const cached2 = cacheRead + cacheWrite;
|
|
167666
|
+
const uncachedInput = prompt >= cached2 ? prompt - cached2 : prompt;
|
|
167667
|
+
const notCached = cacheWrite + uncachedInput;
|
|
167668
|
+
const input = cacheRead + notCached;
|
|
167669
|
+
return { cacheRead, notCached, input, output: output12, total: input + output12 };
|
|
167670
|
+
}
|
|
167671
|
+
function renderStackedBar(segments, trackWidth) {
|
|
167672
|
+
const track = Math.max(0, Math.floor(trackWidth));
|
|
167673
|
+
if (track === 0)
|
|
167674
|
+
return "";
|
|
167675
|
+
const values2 = segments.map((segment) => Math.max(0, segment.value));
|
|
167676
|
+
const total = values2.reduce((sum, value) => sum + value, 0);
|
|
167677
|
+
if (total <= 0)
|
|
167678
|
+
return " ".repeat(track);
|
|
167679
|
+
const exact = values2.map((value) => value / total * track);
|
|
167680
|
+
const cells = exact.map((value) => Math.floor(value));
|
|
167681
|
+
let remaining = track - cells.reduce((sum, value) => sum + value, 0);
|
|
167682
|
+
const remainders = exact.map((value, index) => ({ index, frac: value - Math.floor(value) })).sort((a, b3) => b3.frac - a.frac);
|
|
167683
|
+
for (let i10 = 0;i10 < remainders.length && remaining > 0; i10++, remaining--) {
|
|
167684
|
+
cells[remainders[i10].index] += 1;
|
|
167685
|
+
}
|
|
167686
|
+
const bar = segments.map((segment, i10) => cells[i10] > 0 ? `${segment.color}${"\u2588".repeat(cells[i10])}` : "").join("");
|
|
167687
|
+
return bar.length > 0 ? bar + COLORS.reset : " ".repeat(track);
|
|
167688
|
+
}
|
|
166196
167689
|
function renderRecent(stats, width, naming) {
|
|
166197
167690
|
const recentEntries = stats.entries.slice(0, 50);
|
|
166198
167691
|
if (recentEntries.length === 0)
|
|
166199
167692
|
return renderBox(["No recent entries"], width, "Recent Requests");
|
|
166200
|
-
const timeCol =
|
|
166201
|
-
const
|
|
166202
|
-
const
|
|
166203
|
-
const
|
|
167693
|
+
const timeCol = 8;
|
|
167694
|
+
const costCol = 12;
|
|
167695
|
+
const minBarWidth = "CACHE HIT".length;
|
|
167696
|
+
const maxBarWidth = 20;
|
|
167697
|
+
const minProviderCol = 12;
|
|
167698
|
+
const minModelCol = 10;
|
|
167699
|
+
const minClientCol = 6;
|
|
166204
167700
|
const hasOwnerInfo = naming.npubs.length > 0 || naming.ownersByClientId.size > 0;
|
|
166205
167701
|
const clientLabels = recentEntries.map((entry) => hasOwnerInfo ? resolveClientLabel(entry.client, naming) : entry.client || "unknown");
|
|
166206
167702
|
const maxLabelLen = clientLabels.reduce((max, label) => Math.max(max, label.length), 6);
|
|
166207
|
-
const
|
|
167703
|
+
const tokenRows = recentEntries.map((entry) => tokenSegments(entry));
|
|
167704
|
+
const inputTexts = tokenRows.map((row) => formatNumber2(row.input));
|
|
167705
|
+
const outputTexts = tokenRows.map((row) => formatNumber2(row.output));
|
|
167706
|
+
const inputCol = Math.max(...inputTexts.map((text) => text.length));
|
|
167707
|
+
const outputCol = Math.max(...outputTexts.map((text) => text.length));
|
|
167708
|
+
const inOutCol = inputCol + outputCol + " - ".length;
|
|
166208
167709
|
const innerWidth = Math.max(0, width - 4);
|
|
166209
|
-
|
|
166210
|
-
|
|
167710
|
+
let modelCol = 18;
|
|
167711
|
+
let clientCol = hasOwnerInfo ? Math.min(32, Math.max(14, maxLabelLen)) : 14;
|
|
167712
|
+
let barWidth = maxBarWidth;
|
|
167713
|
+
let showProvider = false;
|
|
167714
|
+
let providerCol = 0;
|
|
167715
|
+
const usedWidth = () => timeCol + modelCol + (barWidth + 1 + inOutCol) + costCol + clientCol + (showProvider ? providerCol + 1 : 0) + 4;
|
|
167716
|
+
if (innerWidth - usedWidth() > minProviderCol + 1) {
|
|
167717
|
+
showProvider = true;
|
|
167718
|
+
providerCol = innerWidth - usedWidth();
|
|
167719
|
+
}
|
|
167720
|
+
while (usedWidth() > innerWidth && barWidth > minBarWidth)
|
|
167721
|
+
barWidth -= 1;
|
|
167722
|
+
while (usedWidth() > innerWidth && providerCol > minProviderCol)
|
|
167723
|
+
providerCol -= 1;
|
|
167724
|
+
while (usedWidth() > innerWidth && modelCol > minModelCol)
|
|
167725
|
+
modelCol -= 1;
|
|
167726
|
+
while (usedWidth() > innerWidth && clientCol > minClientCol)
|
|
167727
|
+
clientCol -= 1;
|
|
167728
|
+
const tokensCol = barWidth + 1 + inOutCol;
|
|
166211
167729
|
const lines = [];
|
|
166212
|
-
|
|
166213
|
-
|
|
167730
|
+
const header = [
|
|
167731
|
+
"TIME".padEnd(timeCol),
|
|
167732
|
+
"MODEL".padEnd(modelCol),
|
|
167733
|
+
"CACHE HIT".padEnd(tokensCol - inOutCol) + "IN".padEnd(inputCol) + " - " + "OUT".padStart(outputCol),
|
|
167734
|
+
"COST".padStart(costCol),
|
|
167735
|
+
...showProvider ? ["BASE:PROVIDER".padEnd(providerCol)] : [],
|
|
167736
|
+
"CLIENT".padEnd(clientCol)
|
|
167737
|
+
];
|
|
167738
|
+
lines.push(`${COLORS.bold}${header.join(" ")}${COLORS.reset}`);
|
|
167739
|
+
lines.push(COLORS.dim + "\u2500".repeat(innerWidth) + COLORS.reset);
|
|
166214
167740
|
for (let i10 = 0;i10 < recentEntries.length; i10++) {
|
|
166215
167741
|
const entry = recentEntries[i10];
|
|
166216
167742
|
const time6 = formatTime(entry.timestamp).slice(0, 8);
|
|
166217
167743
|
const model4 = entry.modelId.slice(0, modelCol).padEnd(modelCol);
|
|
166218
|
-
const
|
|
166219
|
-
|
|
166220
|
-
|
|
166221
|
-
|
|
166222
|
-
|
|
166223
|
-
].
|
|
167744
|
+
const segments = tokenRows[i10];
|
|
167745
|
+
const bar = renderStackedBar([
|
|
167746
|
+
{ value: segments.cacheRead, color: TOKEN_BAR_COLORS.cacheRead },
|
|
167747
|
+
{ value: segments.notCached, color: TOKEN_BAR_COLORS.notCached }
|
|
167748
|
+
], barWidth);
|
|
167749
|
+
const tokens = `${bar} ${inputTexts[i10].padEnd(inputCol)} - ${outputTexts[i10].padStart(outputCol)}`;
|
|
166224
167750
|
const totalSats = typeof entry.totalMsats === "number" ? entry.totalMsats / 1000 : entry.satsCost;
|
|
166225
|
-
const cost =
|
|
166226
|
-
formatCost(msatsToSats(entry.inputMsats)),
|
|
166227
|
-
formatCost(msatsToSats(entry.outputMsats)),
|
|
166228
|
-
formatCost(totalSats)
|
|
166229
|
-
].join("/");
|
|
167751
|
+
const cost = `${formatCost(totalSats)} sats`.padStart(costCol);
|
|
166230
167752
|
const baseUrl = (entry.baseUrl || "unknown").replace("https://", "").replace("http://", "");
|
|
166231
167753
|
const provider = `${baseUrl}:${entry.provider || "unknown"}`.slice(0, providerCol).padEnd(providerCol);
|
|
166232
167754
|
const clientLabel = clientLabels[i10].slice(0, clientCol).padEnd(clientCol);
|
|
166233
167755
|
const clientColor = CLIENT_COLORS[entry.client || "unknown"] || CLIENT_COLORS.default || COLORS.white;
|
|
166234
167756
|
const modelColor = MODEL_COLORS[entry.modelId] || MODEL_COLORS.default;
|
|
166235
|
-
lines.push(
|
|
167757
|
+
lines.push([
|
|
167758
|
+
`${COLORS.dim}${time6}${COLORS.reset}`,
|
|
167759
|
+
`${modelColor}${model4}${COLORS.reset}`,
|
|
167760
|
+
tokens,
|
|
167761
|
+
`${COLORS.green}${cost.padEnd(costCol)}${COLORS.reset}`,
|
|
167762
|
+
...showProvider ? [`${COLORS.dim}${provider}${COLORS.reset}`] : [],
|
|
167763
|
+
`${clientColor}${clientLabel}${COLORS.reset}`
|
|
167764
|
+
].join(" "));
|
|
166236
167765
|
}
|
|
166237
167766
|
return renderBox(lines, width, `Recent Requests (${stats.entries.length} shown)`);
|
|
166238
167767
|
}
|
|
@@ -166258,12 +167787,16 @@ function renderTabContent(activeTab, stats, balance, status, width, naming) {
|
|
|
166258
167787
|
return "Unknown tab";
|
|
166259
167788
|
}
|
|
166260
167789
|
}
|
|
166261
|
-
var _sectionMaxLabelLen;
|
|
167790
|
+
var _sectionMaxLabelLen, TOKEN_BAR_COLORS;
|
|
166262
167791
|
var init_render = __esm(() => {
|
|
166263
167792
|
init_constants2();
|
|
166264
167793
|
init_data();
|
|
166265
167794
|
init_state();
|
|
166266
167795
|
_sectionMaxLabelLen = new Map;
|
|
167796
|
+
TOKEN_BAR_COLORS = {
|
|
167797
|
+
cacheRead: COLORS.green,
|
|
167798
|
+
notCached: COLORS.red
|
|
167799
|
+
};
|
|
166267
167800
|
});
|
|
166268
167801
|
|
|
166269
167802
|
// src/tui/usage/app.ts
|