shinjuku-shielded 0.3.59 → 0.3.60
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/manifest.json +4 -4
- package/package.json +3 -3
- package/shinjuku-wallet.mjs +113 -16
package/manifest.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "carbon-shielded-wallet/bundle-manifest/v1",
|
|
3
3
|
"file": "shinjuku-wallet.mjs",
|
|
4
|
-
"sha256": "
|
|
5
|
-
"bytes":
|
|
6
|
-
"sourceCommit": "
|
|
4
|
+
"sha256": "ad143a47257fa8b5e147ba3f6b662576794b06184abbedce42fd4f74993d9b7e",
|
|
5
|
+
"bytes": 12161659,
|
|
6
|
+
"sourceCommit": "187538a77af6d819ea08912f6406834a8e144e22",
|
|
7
7
|
"sourceDirty": false,
|
|
8
8
|
"installRecordMatchesLockfile": true,
|
|
9
9
|
"releaseRule": "valid only when two fresh npm ci --ignore-scripts builds on different OSes give the same sha256; installRecordMatchesLockfile true means every entry npm installed equals its package-lock.json entry and every entry not marked optional, devOptional included, is installed: an optional entry (a package for another platform) may be absent",
|
|
@@ -1282,5 +1282,5 @@
|
|
|
1282
1282
|
"version": "1.8.0"
|
|
1283
1283
|
}
|
|
1284
1284
|
],
|
|
1285
|
-
"publishedAt": "2026-10-
|
|
1285
|
+
"publishedAt": "2026-10-22T05:12:25.176Z"
|
|
1286
1286
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shinjuku-shielded",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.60",
|
|
4
4
|
"mcpName": "io.github.ShinjukuStaition/shinjuku-mcp",
|
|
5
5
|
"description": "Shinjuku Shielded, the private x402 facilitator on Solana: the self-custody wallet CLI and its MCP server. Shield, pay, and unshield USDC from any MCP agent, under caps you set.",
|
|
6
|
-
"shinjukuRelease": "
|
|
7
|
-
"shinjukuSha256": "
|
|
6
|
+
"shinjukuRelease": "ad143a47",
|
|
7
|
+
"shinjukuSha256": "ad143a47257fa8b5e147ba3f6b662576794b06184abbedce42fd4f74993d9b7e",
|
|
8
8
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
9
9
|
"author": "Shinjuku Shielded",
|
|
10
10
|
"homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
|
package/shinjuku-wallet.mjs
CHANGED
|
@@ -42630,7 +42630,15 @@ function warmOnions({ onions = routedOnions(), fetchImpl = globalThis.fetch, tim
|
|
|
42630
42630
|
}
|
|
42631
42631
|
return () => controller.abort();
|
|
42632
42632
|
}
|
|
42633
|
-
function raceOnions(onions, {
|
|
42633
|
+
function raceOnions(onions, {
|
|
42634
|
+
fetchImpl = globalThis.fetch,
|
|
42635
|
+
timeoutMs = RACE_TIMEOUT_MS,
|
|
42636
|
+
path = "/api/health",
|
|
42637
|
+
onNone,
|
|
42638
|
+
spares = [],
|
|
42639
|
+
spareAfterMs = SPARE_AFTER_MS,
|
|
42640
|
+
onSpares
|
|
42641
|
+
} = {}) {
|
|
42634
42642
|
const controller = new AbortController();
|
|
42635
42643
|
const signal = AbortSignal.any([controller.signal, AbortSignal.timeout(timeoutMs)]);
|
|
42636
42644
|
const probe = (onion) => Promise.resolve().then(() => fetchImpl(`${onion}${path}`, onionInit({ redirect: "error", signal, headers: { accept: "application/json" } }))).then((response) => {
|
|
@@ -42639,11 +42647,46 @@ function raceOnions(onions, { fetchImpl = globalThis.fetch, timeoutMs = RACE_TIM
|
|
|
42639
42647
|
if (!response?.ok) throw new Error(`onion answered ${response?.status}`);
|
|
42640
42648
|
return onion;
|
|
42641
42649
|
});
|
|
42642
|
-
|
|
42643
|
-
|
|
42644
|
-
|
|
42645
|
-
|
|
42646
|
-
|
|
42650
|
+
let startSpares = () => {
|
|
42651
|
+
};
|
|
42652
|
+
let spareTimer;
|
|
42653
|
+
const winner = new Promise((resolve38) => {
|
|
42654
|
+
let open3 = 0;
|
|
42655
|
+
let done = false;
|
|
42656
|
+
let sparesStarted = spares.length === 0;
|
|
42657
|
+
const settle = (onion) => {
|
|
42658
|
+
if (done) return;
|
|
42659
|
+
done = true;
|
|
42660
|
+
resolve38(onion);
|
|
42661
|
+
};
|
|
42662
|
+
const failed = () => {
|
|
42663
|
+
open3 -= 1;
|
|
42664
|
+
if (open3 > 0 || done) return;
|
|
42665
|
+
if (!sparesStarted && !signal.aborted) return startSpares();
|
|
42666
|
+
if (!controller.signal.aborted) onNone?.();
|
|
42667
|
+
settle(onions[0]);
|
|
42668
|
+
};
|
|
42669
|
+
const start = (onion) => {
|
|
42670
|
+
open3 += 1;
|
|
42671
|
+
probe(onion).then(settle, failed);
|
|
42672
|
+
};
|
|
42673
|
+
startSpares = () => {
|
|
42674
|
+
if (sparesStarted || done || signal.aborted) return;
|
|
42675
|
+
sparesStarted = true;
|
|
42676
|
+
clearTimeout(spareTimer);
|
|
42677
|
+
onSpares?.();
|
|
42678
|
+
for (const onion of spares) start(onion);
|
|
42679
|
+
};
|
|
42680
|
+
if (!sparesStarted) {
|
|
42681
|
+
spareTimer = setTimeout(() => startSpares(), spareAfterMs);
|
|
42682
|
+
spareTimer.unref?.();
|
|
42683
|
+
}
|
|
42684
|
+
for (const onion of onions) start(onion);
|
|
42685
|
+
}).finally(() => {
|
|
42686
|
+
clearTimeout(spareTimer);
|
|
42687
|
+
controller.abort();
|
|
42688
|
+
});
|
|
42689
|
+
return { winner, abort: () => controller.abort(), startSpares: () => startSpares() };
|
|
42647
42690
|
}
|
|
42648
42691
|
function facilitatorOrigins(argv2) {
|
|
42649
42692
|
const origins = /* @__PURE__ */ new Set();
|
|
@@ -42692,7 +42735,8 @@ async function routeFacilitatorsOverOnion(argv2, {
|
|
|
42692
42735
|
fetchImpl = globalThis.fetch,
|
|
42693
42736
|
err = (text3) => process.stderr.write(text3),
|
|
42694
42737
|
raceTimeoutMs = RACE_TIMEOUT_MS,
|
|
42695
|
-
routeWaitMs = ROUTE_WAIT_MS
|
|
42738
|
+
routeWaitMs = ROUTE_WAIT_MS,
|
|
42739
|
+
spareAfterMs = SPARE_AFTER_MS
|
|
42696
42740
|
} = {}) {
|
|
42697
42741
|
const routes = /* @__PURE__ */ new Map();
|
|
42698
42742
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -42700,17 +42744,29 @@ async function routeFacilitatorsOverOnion(argv2, {
|
|
|
42700
42744
|
for (const origin of named.length > 0 ? named : [DEFAULT_FACILITATOR_ORIGIN]) {
|
|
42701
42745
|
const pinned = PINNED_FACILITATOR_ONIONS[origin];
|
|
42702
42746
|
const onions = (pinned ?? [await publishedOnion(origin, fetchImpl)]).filter((onion) => onion && V3_ONION.test(onion));
|
|
42747
|
+
const spares = pinned ? (PINNED_SPARE_ONIONS[origin] ?? []).filter((onion) => V3_ONION.test(onion)) : [];
|
|
42703
42748
|
if (onions.length > 0) {
|
|
42704
42749
|
const key = onions.join(" ");
|
|
42705
42750
|
if (!groups.has(key)) {
|
|
42706
|
-
|
|
42707
|
-
|
|
42751
|
+
const spareHosts = spares.map((onion) => `${new URL(onion).host.slice(0, 8)}...`).join(", ");
|
|
42752
|
+
const group = {
|
|
42753
|
+
onions: [...onions, ...spares],
|
|
42754
|
+
live: onions.length,
|
|
42755
|
+
spares,
|
|
42756
|
+
waitMs: routeWaitMs,
|
|
42757
|
+
onSpares: () => err(`tor: no onion of ${origin} has answered yet; its ${spares.length} spare onions ${spareHosts} join (Tor may still be fetching the onion addresses)
|
|
42758
|
+
`),
|
|
42759
|
+
onNone: () => err(`tor: no onion of ${origin} answered its start probe (${liveOnions(group).length} tried); its requests go to its onions in turn and wait for them (Tor may still be building circuits)
|
|
42760
|
+
`)
|
|
42761
|
+
};
|
|
42762
|
+
groups.set(key, group);
|
|
42708
42763
|
}
|
|
42709
42764
|
routes.set(origin, groups.get(key));
|
|
42710
42765
|
routes.set(payHostOf(origin), groups.get(key));
|
|
42711
42766
|
const hosts = onions.map((onion) => `${new URL(onion).host.slice(0, 8)}...`).join(", ");
|
|
42712
42767
|
const source = pinned ? "pinned in this wallet" : `published by ${origin}`;
|
|
42713
|
-
|
|
42768
|
+
const spareNote = spares.length > 0 ? `; ${spares.length} spares join if none answers in ${Math.round(spareAfterMs / 1e3)} s` : "";
|
|
42769
|
+
err(`tor: ${origin} is reached over its onion service ${hosts} (${onions.length > 1 ? `${source}; the first to answer serves this run` : source}${spareNote}), so no Tor exit and no front such as Cloudflare sees these requests
|
|
42714
42770
|
`);
|
|
42715
42771
|
} else {
|
|
42716
42772
|
err(`tor: ${origin} publishes no onion service; its requests go through a Tor exit, which sees the host name (TLS hides the content)
|
|
@@ -42734,12 +42790,18 @@ async function routeFacilitatorsOverOnion(argv2, {
|
|
|
42734
42790
|
aborts.push(warmOnions({ onions: group.onions, fetchImpl }));
|
|
42735
42791
|
continue;
|
|
42736
42792
|
}
|
|
42737
|
-
const
|
|
42793
|
+
const spares = group.spares ?? [];
|
|
42794
|
+
const race = raceOnions(liveOnions(group), {
|
|
42738
42795
|
fetchImpl,
|
|
42739
42796
|
timeoutMs: raceTimeoutMs,
|
|
42740
42797
|
...group.path ? { path: group.path } : {},
|
|
42741
|
-
...group.onNone ? { onNone: group.onNone } : {}
|
|
42798
|
+
...group.onNone ? { onNone: group.onNone } : {},
|
|
42799
|
+
...spares.length > 0 ? { spares, spareAfterMs, onSpares: () => {
|
|
42800
|
+
group.live = group.onions.length;
|
|
42801
|
+
group.onSpares?.();
|
|
42802
|
+
} } : {}
|
|
42742
42803
|
});
|
|
42804
|
+
group.startSpares = race.startSpares;
|
|
42743
42805
|
group.pending = race.winner.then((onion) => {
|
|
42744
42806
|
group.winner = onion;
|
|
42745
42807
|
group.pending = void 0;
|
|
@@ -42760,7 +42822,11 @@ async function routeFacilitatorsOverOnion(argv2, {
|
|
|
42760
42822
|
const group = url && routes.get(url.origin);
|
|
42761
42823
|
if (!group) return original(input, init);
|
|
42762
42824
|
const send3 = (onion) => {
|
|
42763
|
-
if (onion === void 0)
|
|
42825
|
+
if (onion === void 0) {
|
|
42826
|
+
group.startSpares?.();
|
|
42827
|
+
const live = liveOnions(group);
|
|
42828
|
+
onion = live[(group.sent = (group.sent ?? 0) + 1) % live.length];
|
|
42829
|
+
}
|
|
42764
42830
|
const target = `${onion}${url.pathname}${url.search}`;
|
|
42765
42831
|
return original(input instanceof Request ? new Request(target, input) : target, onionInit(init));
|
|
42766
42832
|
};
|
|
@@ -42782,7 +42848,7 @@ async function routeFacilitatorsOverOnion(argv2, {
|
|
|
42782
42848
|
}
|
|
42783
42849
|
};
|
|
42784
42850
|
}
|
|
42785
|
-
var SITE_ONIONS, PINNED_FACILITATOR_ONIONS, HISTORY_ONIONS, PINNED_HISTORY_ONIONS, HISTORY_PROBE_PATH, FACILITATOR_FLAGS, V3_ONION, DISCOVERY_TIMEOUT_MS, WARM_TIMEOUT_MS, RACE_TIMEOUT_MS, ROUTE_WAIT_MS, routedGroups, routedOnions, routedOrigins, onionsOfOrigin, routesOverOnion, GLOBAL_DISPATCHER, onionDispatchers;
|
|
42851
|
+
var SITE_ONIONS, SITE_SPARE_ONIONS, PINNED_FACILITATOR_ONIONS, PINNED_SPARE_ONIONS, HISTORY_ONIONS, PINNED_HISTORY_ONIONS, HISTORY_PROBE_PATH, FACILITATOR_FLAGS, V3_ONION, DISCOVERY_TIMEOUT_MS, WARM_TIMEOUT_MS, RACE_TIMEOUT_MS, ROUTE_WAIT_MS, SPARE_AFTER_MS, routedGroups, liveOnions, routedOnions, routedOrigins, onionsOfOrigin, routesOverOnion, GLOBAL_DISPATCHER, onionDispatchers;
|
|
42786
42852
|
var init_facilitatorOnion = __esm({
|
|
42787
42853
|
"wallet/src/net/facilitatorOnion.mjs"() {
|
|
42788
42854
|
"use strict";
|
|
@@ -42791,11 +42857,20 @@ var init_facilitatorOnion = __esm({
|
|
|
42791
42857
|
"http://2kfhlfuyuwvhmibjrpxqsg4nrbcxasjgjq7kmnfzgfwzptkhhznz3dad.onion",
|
|
42792
42858
|
"http://chhgw7nfggqhhjawz54bpsiihdow66s2yvkh6ccnugpcdmhhww6xkkqd.onion"
|
|
42793
42859
|
]);
|
|
42860
|
+
SITE_SPARE_ONIONS = Object.freeze([
|
|
42861
|
+
"http://ntr5qkdfgff4gspwderjnqtkzekyhb5a4j76ov4dqncxmcb53gdsmmid.onion",
|
|
42862
|
+
"http://vofhhl336r4bnwn7hid2uvqaa72wx66xkdu2yt4n54xljsxwn2yds6qd.onion"
|
|
42863
|
+
]);
|
|
42794
42864
|
PINNED_FACILITATOR_ONIONS = Object.freeze({
|
|
42795
42865
|
"https://shinjukustaition.com": SITE_ONIONS,
|
|
42796
42866
|
"https://www.shinjukustaition.com": SITE_ONIONS,
|
|
42797
42867
|
"https://pay.shinjukustaition.com": SITE_ONIONS
|
|
42798
42868
|
});
|
|
42869
|
+
PINNED_SPARE_ONIONS = Object.freeze({
|
|
42870
|
+
"https://shinjukustaition.com": SITE_SPARE_ONIONS,
|
|
42871
|
+
"https://www.shinjukustaition.com": SITE_SPARE_ONIONS,
|
|
42872
|
+
"https://pay.shinjukustaition.com": SITE_SPARE_ONIONS
|
|
42873
|
+
});
|
|
42799
42874
|
HISTORY_ONIONS = Object.freeze([
|
|
42800
42875
|
"http://d6xg3phhurxhzqcsgh2mh52yf744labhrnd7mducwynlertfsjzyslqd.onion",
|
|
42801
42876
|
"http://3yccoinnouxbjx3emvdxwhbu56cq4de7sfwgvcp4xb7hveccnpurcrid.onion",
|
|
@@ -42810,8 +42885,10 @@ var init_facilitatorOnion = __esm({
|
|
|
42810
42885
|
WARM_TIMEOUT_MS = 3e4;
|
|
42811
42886
|
RACE_TIMEOUT_MS = 9e4;
|
|
42812
42887
|
ROUTE_WAIT_MS = 15e3;
|
|
42888
|
+
SPARE_AFTER_MS = ROUTE_WAIT_MS;
|
|
42813
42889
|
routedGroups = [];
|
|
42814
|
-
|
|
42890
|
+
liveOnions = (group) => group.onions.slice(0, group.live ?? group.onions.length);
|
|
42891
|
+
routedOnions = () => [...new Set(routedGroups.flatMap((group) => group.winner ? [group.winner] : liveOnions(group)))];
|
|
42815
42892
|
routedOrigins = /* @__PURE__ */ new Map();
|
|
42816
42893
|
onionsOfOrigin = (origin) => routedOrigins.get(origin) ?? PINNED_FACILITATOR_ONIONS[origin] ?? [];
|
|
42817
42894
|
routesOverOnion = (origin) => routedOrigins.has(origin);
|
|
@@ -118627,8 +118704,12 @@ ${canonical5}`;
|
|
|
118627
118704
|
const linkReads = readOpenLinkHeld(store);
|
|
118628
118705
|
const finishing = finishSentDeposits(store);
|
|
118629
118706
|
const finishDeadline = finishing.length ? balanceStartedAt + balanceRefreshWaitMs : void 0;
|
|
118707
|
+
let finishedHere = [];
|
|
118630
118708
|
if (finishing.length) {
|
|
118631
|
-
const finished = Promise.all(finishing).then((outcomes) =>
|
|
118709
|
+
const finished = Promise.all(finishing).then((outcomes) => {
|
|
118710
|
+
finishedHere = outcomes.filter((outcome2) => outcome2?.stage === "done" || outcome2?.stage === "partly_shielded");
|
|
118711
|
+
return finishedHere.length ? refreshShared().then(() => "done") : "passed";
|
|
118712
|
+
}).catch(() => "failed");
|
|
118632
118713
|
const outcome = await Promise.race([
|
|
118633
118714
|
finished,
|
|
118634
118715
|
new Promise((resolve38) => {
|
|
@@ -118780,6 +118861,22 @@ ${canonical5}`;
|
|
|
118780
118861
|
} catch {
|
|
118781
118862
|
landingAtomic = 0n;
|
|
118782
118863
|
}
|
|
118864
|
+
if (landingAtomic === 0n && shieldedAtomic === null && !refresh.refreshError && finishedHere.length) {
|
|
118865
|
+
for (const outcome of finishedHere) {
|
|
118866
|
+
const id = outcome.record?.id;
|
|
118867
|
+
const round = outcome.record?.round ?? 1;
|
|
118868
|
+
let amount = payMeAmounts.get(`${id}:${round}`);
|
|
118869
|
+
if (amount === void 0) {
|
|
118870
|
+
try {
|
|
118871
|
+
const deposit = store.readWal(`deposit-${outcome.record?.depositId ?? payMeRoundDepositId(id, round)}`);
|
|
118872
|
+
if (/^[1-9][0-9]*$/.test(String(deposit?.amountAtomic ?? ""))) amount = BigInt(deposit.amountAtomic);
|
|
118873
|
+
} catch {
|
|
118874
|
+
amount = void 0;
|
|
118875
|
+
}
|
|
118876
|
+
}
|
|
118877
|
+
if (typeof amount === "bigint" && amount > 0n) landingAtomic += amount;
|
|
118878
|
+
}
|
|
118879
|
+
}
|
|
118783
118880
|
const landedNext = landingAtomic > 0n && !refresh.refreshError ? `${usdcText2(landingAtomic)} USDC you added landed on chain and is being counted (landingAtomic, not in balanceAtomic yet): call wallet_balance again in ${POLL_SECONDS3} s; that call waits up to ${waitSeconds} s for it. Tell the user it needs no step from them` : void 0;
|
|
118784
118881
|
if (landedNext) next = landedNext;
|
|
118785
118882
|
const stalled = [...resumeRefusals].map(([requestId, error2]) => `"${requestId}" (${error2})`);
|