@spirobel/monero-wallet-api 0.5.4 → 0.6.0
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/dist/actionlog/actionLogOpened.d.ts +96 -1
- package/dist/actionlog/actionLogOpened.js +386 -1
- package/dist/actionlog/actionLogTypes.d.ts +114 -0
- package/dist/actionlog/actionLogTypes.js +198 -0
- package/dist/actionlog/backend/idbBackend.d.ts +13 -0
- package/dist/actionlog/backend/idbBackend.js +109 -0
- package/dist/actionlog/backend/jsonlBackend.d.ts +19 -0
- package/dist/actionlog/backend/jsonlBackend.js +110 -0
- package/dist/actionlog/backend/memoryBackend.d.ts +11 -0
- package/dist/actionlog/backend/memoryBackend.js +31 -0
- package/dist/actionlog/backend/sqliteBackend.d.ts +14 -0
- package/dist/actionlog/backend/sqliteBackend.js +96 -0
- package/dist/actionlog/backend.d.ts +12 -0
- package/dist/actionlog/backend.js +1 -0
- package/dist/actionlog/idbBackend.d.ts +19 -0
- package/dist/actionlog/idbBackend.js +98 -0
- package/dist/actionlog/jsonlBackend.d.ts +19 -0
- package/dist/actionlog/jsonlBackend.js +75 -0
- package/dist/actionlog/memoryBackend.d.ts +14 -0
- package/dist/actionlog/memoryBackend.js +38 -0
- package/dist/actionlog/openMaps.d.ts +11 -0
- package/dist/actionlog/openMaps.js +32 -0
- package/dist/actionlog/sqliteBackend.d.ts +18 -0
- package/dist/actionlog/sqliteBackend.js +105 -0
- package/dist/actionlog/toolContext.d.ts +36 -0
- package/dist/actionlog/toolContext.js +1 -0
- package/dist/actionlog/types.d.ts +62 -0
- package/dist/actionlog/types.js +62 -0
- package/dist/api.d.ts +4 -0
- package/dist/api.js +3 -0
- package/dist/io/sleep.d.ts +1 -1
- package/dist/io/sleep.js +16 -1
- package/dist/scanning-syncing/backgroundWorker.d.ts +2 -0
- package/dist/scanning-syncing/backgroundWorker.js +92 -10
- package/dist/scanning-syncing/blocksbuffer/blocksBufferFetchLoop.js +33 -2
- package/dist/scanning-syncing/blocksbuffer/blocksbufferCoordination.js +2 -2
- package/dist/scanning-syncing/connectionStatus.d.ts +8 -0
- package/dist/scanning-syncing/connectionStatus.js +50 -0
- package/dist/scanning-syncing/connectionStatusOpened.d.ts +3 -1
- package/dist/scanning-syncing/connectionStatusOpened.js +22 -14
- package/dist/scanning-syncing/openWallet.d.ts +4 -1
- package/dist/scanning-syncing/openWallet.js +3 -0
- package/dist/scanning-syncing/scanresult/scanCache.d.ts +5 -1
- package/dist/scanning-syncing/scanresult/scanCache.js +11 -2
- package/dist/scanning-syncing/scanresult/scanCacheOpened.d.ts +56 -5
- package/dist/scanning-syncing/scanresult/scanCacheOpened.js +422 -83
- package/dist/scanning-syncing/scanresult/scanCoordination.d.ts +7 -3
- package/dist/scanning-syncing/scanresult/scanCoordination.js +126 -28
- package/dist/scanning-syncing/scanresult/scanLoop.d.ts +1 -2
- package/dist/scanning-syncing/scanresult/scanLoop.js +0 -13
- package/dist/scanning-syncing/scanresult/scanResult.js +17 -12
- package/dist/scanning-syncing/scanresult/scanStats.js +8 -5
- package/dist/scanning-syncing/worker-entrypoints/worker.js +1 -1
- package/dist/scanning-syncing/worker-mains/coordinator-main.d.ts +1 -0
- package/dist/scanning-syncing/worker-mains/coordinator-main.js +16 -1
- package/dist/scanning-syncing/worker-mains/cpubound-main.js +3 -2
- package/dist/scanning-syncing/worker-mains/worker.js +45 -2
- package/dist/tools/calls/001.d.ts +20 -0
- package/dist/tools/calls/001.js +236 -0
- package/dist/tools/calls/002-content.d.ts +46 -0
- package/dist/tools/calls/002-content.js +135 -0
- package/dist/tools/calls/002-fail-cleanup.d.ts +27 -0
- package/dist/tools/calls/002-fail-cleanup.js +60 -0
- package/dist/tools/calls/002.d.ts +64 -0
- package/dist/tools/calls/002.js +353 -0
- package/dist/tools/content.d.ts +22 -0
- package/dist/tools/content.js +41 -0
- package/dist/tools/counterparty.d.ts +3 -0
- package/dist/tools/counterparty.js +1 -0
- package/dist/tools/download-public-suffix.d.ts +1 -0
- package/dist/tools/download-public-suffix.js +20 -0
- package/dist/tools/globals.d.ts +196 -0
- package/dist/tools/globals.js +14 -0
- package/dist/tools/monero-tools-content.d.ts +29 -0
- package/dist/tools/monero-tools-content.js +80 -0
- package/dist/tools/monero-tools.d.ts +27 -52
- package/dist/tools/monero-tools.js +127 -222
- package/dist/tools/public-suffix-list.d.ts +1 -0
- package/dist/tools/public-suffix-list.js +10336 -0
- package/dist/tools/runtimeMessages.d.ts +4 -0
- package/dist/tools/runtimeMessages.js +18 -0
- package/dist/tools/toolActionLogContext.d.ts +33 -0
- package/dist/tools/toolActionLogContext.js +1 -0
- package/dist/tools/toolArm.d.ts +47 -0
- package/dist/tools/toolArm.js +1 -0
- package/dist/tools/ui.d.ts +2 -0
- package/dist/tools/ui.js +1 -0
- package/dist/tools/worker.d.ts +1 -0
- package/dist/tools/worker.js +1 -0
- package/dist/wasm-processing/wasmFile.js +2 -2
- package/package.json +8 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type PortMessageByKind, type ToolArm } from "../globals";
|
|
2
|
+
export type CreateAndShareViewOnlyWalletTool = {
|
|
3
|
+
tool_id: "002";
|
|
4
|
+
payload: CreateAndShareViewOnlyWalletToolPayload;
|
|
5
|
+
};
|
|
6
|
+
export type CreateAndShareViewOnlyWalletToolPayload = {
|
|
7
|
+
wallet_slot: number;
|
|
8
|
+
};
|
|
9
|
+
export type ShareViewkeyPayload = PortMessageByKind["shareViewkey"];
|
|
10
|
+
export type ShareViewkeyResult = {
|
|
11
|
+
ok: boolean;
|
|
12
|
+
successUrl: string | null;
|
|
13
|
+
error?: string;
|
|
14
|
+
};
|
|
15
|
+
export type ShareViewkey002Pruned = {
|
|
16
|
+
viewkey: string;
|
|
17
|
+
primary_address: string;
|
|
18
|
+
wallet_slot: number;
|
|
19
|
+
};
|
|
20
|
+
/** mco surface used to save view wallet on share success */
|
|
21
|
+
export type ShareViewMco = {
|
|
22
|
+
wallets: {
|
|
23
|
+
primary_address: string;
|
|
24
|
+
wallet_slot?: number;
|
|
25
|
+
wallet_name?: string;
|
|
26
|
+
}[];
|
|
27
|
+
addViewWallet: (primary_address: string, view_key: string, fields?: {
|
|
28
|
+
wallet_name?: string;
|
|
29
|
+
wallet_slot?: number;
|
|
30
|
+
}) => Promise<void>;
|
|
31
|
+
setWalletName: (primary_address: string, name?: string) => Promise<void>;
|
|
32
|
+
setWalletSlot: (primary_address: string, slot?: number) => Promise<void>;
|
|
33
|
+
};
|
|
34
|
+
export type HandleShareOpts = {
|
|
35
|
+
successUrl?: string;
|
|
36
|
+
};
|
|
37
|
+
declare function execute_route(mco: ShareViewMco, opts?: HandleShareOpts): (req: Request) => Promise<Response>;
|
|
38
|
+
export type FailedShareViewRestore = {
|
|
39
|
+
viewkey: string;
|
|
40
|
+
primary_address: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
tool_invo: {
|
|
43
|
+
invocation_id: string;
|
|
44
|
+
context_domain: string;
|
|
45
|
+
context_href: string;
|
|
46
|
+
destination_domain: string;
|
|
47
|
+
found_in: "link" | "linkText";
|
|
48
|
+
link: string;
|
|
49
|
+
linkText: string;
|
|
50
|
+
timestamp: number;
|
|
51
|
+
valid: "valid" | "invalid" | "unverified";
|
|
52
|
+
tool: {
|
|
53
|
+
tool_id: string;
|
|
54
|
+
payload: {
|
|
55
|
+
wallet_slot?: number;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
type Tool002CounterpartyExtra = {
|
|
61
|
+
execute_route: typeof execute_route;
|
|
62
|
+
};
|
|
63
|
+
declare const tool002: ToolArm<CreateAndShareViewOnlyWalletToolPayload, Tool002CounterpartyExtra>;
|
|
64
|
+
export default tool002;
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { getExtensionRuntime, sendToBackground, sendToPort, TOOL_MAGIC_STRING, } from "../globals";
|
|
2
|
+
function recognize_parse(args) {
|
|
3
|
+
const wallet_slot = args[5];
|
|
4
|
+
if (wallet_slot && !isNaN(parseInt(wallet_slot))) {
|
|
5
|
+
return {
|
|
6
|
+
tool_id: "002",
|
|
7
|
+
payload: { wallet_slot: parseInt(wallet_slot) },
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
function make(payload) {
|
|
13
|
+
const wallet_slot = Number(payload.wallet_slot) || 0;
|
|
14
|
+
return `${TOOL_MAGIC_STRING}002_create_and_share_viewkey_slot_${wallet_slot}`;
|
|
15
|
+
}
|
|
16
|
+
/** valid if both domains are the same. */
|
|
17
|
+
function validate_check(invo) {
|
|
18
|
+
if (invo.tool.tool_id !== "002")
|
|
19
|
+
return "unverified";
|
|
20
|
+
if (invo.context_domain == invo.destination_domain)
|
|
21
|
+
return "valid";
|
|
22
|
+
return "invalid";
|
|
23
|
+
}
|
|
24
|
+
/** posts the viewkey. the invocation must be valid. */
|
|
25
|
+
async function shareViewKey002(payload) {
|
|
26
|
+
const invo = payload.tool_invo;
|
|
27
|
+
if (invo.tool.tool_id !== "002")
|
|
28
|
+
return { ok: false, successUrl: null, error: "not 002" };
|
|
29
|
+
if (invo.valid !== "valid")
|
|
30
|
+
return { ok: false, successUrl: null, error: "invocation not valid" };
|
|
31
|
+
const link = invo[invo.found_in];
|
|
32
|
+
const invo_link = new URL(link);
|
|
33
|
+
const shareVKUrl = `${invo_link.origin}/monerochan002/`;
|
|
34
|
+
try {
|
|
35
|
+
const result = await fetch(shareVKUrl, {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: { "Content-Type": "application/json" },
|
|
38
|
+
body: JSON.stringify({
|
|
39
|
+
viewkey: payload.viewkey,
|
|
40
|
+
primary_address: payload.primary_address,
|
|
41
|
+
wallet_slot: invo.tool.payload.wallet_slot,
|
|
42
|
+
}),
|
|
43
|
+
});
|
|
44
|
+
if (result.ok) {
|
|
45
|
+
const data = (await result.json());
|
|
46
|
+
if (!data || typeof data !== "object" || data.ok !== true) {
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
successUrl: null,
|
|
50
|
+
error: "counterparty rejected share",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const successUrl = typeof data.successUrl === "string" && data.successUrl.length
|
|
54
|
+
? data.successUrl
|
|
55
|
+
: null;
|
|
56
|
+
return { ok: true, successUrl };
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
ok: false,
|
|
60
|
+
successUrl: null,
|
|
61
|
+
error: `share post failed ${result.status}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
return {
|
|
66
|
+
ok: false,
|
|
67
|
+
successUrl: null,
|
|
68
|
+
error: e instanceof Error ? e.message : String(e),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function potentialSuccessRedirect002(payload) {
|
|
73
|
+
const shareVKresult = await shareViewKey002(payload);
|
|
74
|
+
if (shareVKresult.ok) {
|
|
75
|
+
if (shareVKresult.successUrl) {
|
|
76
|
+
window.location.href = shareVKresult.successUrl;
|
|
77
|
+
window.location.reload();
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
return shareVKresult;
|
|
82
|
+
}
|
|
83
|
+
function execute_deliver(invo) {
|
|
84
|
+
const rt = getExtensionRuntime();
|
|
85
|
+
if (!rt)
|
|
86
|
+
return;
|
|
87
|
+
const port = rt.connect({ name: invo.invocation_id });
|
|
88
|
+
port.onMessage.addListener((msg) => {
|
|
89
|
+
const m = msg;
|
|
90
|
+
if (m.kind !== "shareViewkey" || !m.payload)
|
|
91
|
+
return;
|
|
92
|
+
const payload = m.payload;
|
|
93
|
+
void (async () => {
|
|
94
|
+
try {
|
|
95
|
+
const result = await potentialSuccessRedirect002(payload);
|
|
96
|
+
if (result) {
|
|
97
|
+
void sendToBackground("shareViewkeyFAILED", {
|
|
98
|
+
...payload,
|
|
99
|
+
error: result.error,
|
|
100
|
+
}).catch(() => { });
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
void sendToBackground("shareViewkeyOK", {
|
|
104
|
+
invocationId: invo.invocation_id,
|
|
105
|
+
}).catch(() => { });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
void sendToBackground("shareViewkeyFAILED", {
|
|
110
|
+
...payload,
|
|
111
|
+
error: e instanceof Error ? e.message : String(e),
|
|
112
|
+
}).catch(() => { });
|
|
113
|
+
}
|
|
114
|
+
})();
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async function handle002ShareRequest(req, wallets, parsed_cb, successUrl) {
|
|
118
|
+
try {
|
|
119
|
+
const json_body = await req.json();
|
|
120
|
+
const { viewkey, primary_address, wallet_slot } = json_body;
|
|
121
|
+
if (typeof viewkey !== "string" ||
|
|
122
|
+
viewkey.trim().length === 0 ||
|
|
123
|
+
typeof primary_address !== "string" ||
|
|
124
|
+
primary_address.trim().length === 0 ||
|
|
125
|
+
typeof wallet_slot !== "number") {
|
|
126
|
+
return { ok: false, successUrl: null };
|
|
127
|
+
}
|
|
128
|
+
const foundSlot = wallets.find((wallet) => wallet.wallet_slot === wallet_slot);
|
|
129
|
+
if (foundSlot) {
|
|
130
|
+
if (foundSlot.primary_address !== primary_address) {
|
|
131
|
+
return { ok: false, successUrl: null };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
await parsed_cb({ viewkey, primary_address, wallet_slot });
|
|
135
|
+
return {
|
|
136
|
+
ok: true,
|
|
137
|
+
successUrl: successUrl ?? null,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return { ok: false, successUrl: null };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async function handleShare(req, mco, opts) {
|
|
145
|
+
const res = await handle002ShareRequest(req, mco.wallets, async ({ primary_address, viewkey, wallet_slot }) => {
|
|
146
|
+
const pa = primary_address.trim();
|
|
147
|
+
const vk = viewkey.trim();
|
|
148
|
+
const existing = mco.wallets.find((w) => w.primary_address === pa);
|
|
149
|
+
const wallet_name = existing?.wallet_name ?? "unnamed wallet " + wallet_slot;
|
|
150
|
+
if (existing) {
|
|
151
|
+
await mco.setWalletName(pa, wallet_name);
|
|
152
|
+
await mco.setWalletSlot(pa, wallet_slot);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
await mco.addViewWallet(pa, vk, { wallet_name, wallet_slot });
|
|
156
|
+
}
|
|
157
|
+
}, opts?.successUrl);
|
|
158
|
+
return Response.json(res);
|
|
159
|
+
}
|
|
160
|
+
function execute_route(mco, opts) {
|
|
161
|
+
return (req) => handleShare(req, mco, opts);
|
|
162
|
+
}
|
|
163
|
+
function flatFromParsed(invo) {
|
|
164
|
+
const p = invo.tool.payload;
|
|
165
|
+
return {
|
|
166
|
+
invocationId: invo.invocation_id,
|
|
167
|
+
toolId: "002",
|
|
168
|
+
wallet_slot: p.wallet_slot,
|
|
169
|
+
context_domain: invo.context_domain,
|
|
170
|
+
destination_domain: invo.destination_domain,
|
|
171
|
+
context_href: invo.context_href,
|
|
172
|
+
found_in: invo.found_in,
|
|
173
|
+
link: invo.link,
|
|
174
|
+
linkText: invo.linkText,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/** first toolCall state transition: session_start invoked. */
|
|
178
|
+
async function invoke_write(ctx, invo) {
|
|
179
|
+
if (invo.tool.tool_id !== "002")
|
|
180
|
+
return;
|
|
181
|
+
const flat = flatFromParsed(invo);
|
|
182
|
+
await ctx.log.append({
|
|
183
|
+
type: "session_start",
|
|
184
|
+
stage: "invoked",
|
|
185
|
+
...flat,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/** second toolCall state transition: validate_result validated. */
|
|
189
|
+
async function validate_write(ctx, invo) {
|
|
190
|
+
if (invo.tool.tool_id !== "002")
|
|
191
|
+
return;
|
|
192
|
+
const flat = flatFromParsed(invo);
|
|
193
|
+
await ctx.log.append({
|
|
194
|
+
type: "validate_result",
|
|
195
|
+
stage: "validated",
|
|
196
|
+
...flat,
|
|
197
|
+
valid: invo.valid,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
function alreadyAccepted(type) {
|
|
201
|
+
return (type === "accept" ||
|
|
202
|
+
type === "execute_start" ||
|
|
203
|
+
type === "execute_error" ||
|
|
204
|
+
type === "execute_result" ||
|
|
205
|
+
type === "dismiss" ||
|
|
206
|
+
type === "aborted");
|
|
207
|
+
}
|
|
208
|
+
function isTerminalTipType(type) {
|
|
209
|
+
// accept and execute_start count as terminal for dismiss: the user accepted,
|
|
210
|
+
// execution is in flight, a late dismiss must not flip the entry
|
|
211
|
+
return (type === "dismiss" ||
|
|
212
|
+
type === "accept" ||
|
|
213
|
+
type === "execute_start" ||
|
|
214
|
+
type === "execute_result" ||
|
|
215
|
+
type === "aborted");
|
|
216
|
+
}
|
|
217
|
+
/** the content payload from this invocation. missing valid is unverified. */
|
|
218
|
+
function invoFromOpen(invocationId, open) {
|
|
219
|
+
return {
|
|
220
|
+
tool: {
|
|
221
|
+
tool_id: "002",
|
|
222
|
+
payload: { wallet_slot: open.wallet_slot ?? 0 },
|
|
223
|
+
},
|
|
224
|
+
destination_domain: open.destination_domain ?? "",
|
|
225
|
+
context_domain: open.context_domain ?? "",
|
|
226
|
+
found_in: open.found_in ?? "link",
|
|
227
|
+
link: open.link ?? "",
|
|
228
|
+
linkText: open.linkText ?? "",
|
|
229
|
+
timestamp: Date.now(),
|
|
230
|
+
invocation_id: invocationId,
|
|
231
|
+
context_href: open.context_href ?? "",
|
|
232
|
+
valid: open.valid ?? "unverified",
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/** third toolCall state transition: accept accepted. */
|
|
236
|
+
async function accept_yes(ctx, invocationId, _args) {
|
|
237
|
+
const invo = await ctx.log.invocation(invocationId);
|
|
238
|
+
if (!invo || alreadyAccepted(invo.lastType))
|
|
239
|
+
return;
|
|
240
|
+
const open = ctx.log.invocations("active").find((o) => o.invocationId === invocationId) ?? null;
|
|
241
|
+
if (!open)
|
|
242
|
+
return;
|
|
243
|
+
await ctx.log.append({
|
|
244
|
+
type: "accept",
|
|
245
|
+
stage: "accepted",
|
|
246
|
+
...flatFromParsed(invoFromOpen(invocationId, open)),
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/** fourth toolCall state transition: execute_start executed. execute_error executed if no port. */
|
|
250
|
+
async function execute_run(ctx, invocationId, args) {
|
|
251
|
+
const open = ctx.log.invocations("active").find((o) => o.invocationId === invocationId) ?? null;
|
|
252
|
+
if (!open)
|
|
253
|
+
return;
|
|
254
|
+
const tool_invo = invoFromOpen(invocationId, open);
|
|
255
|
+
const flat = flatFromParsed(tool_invo);
|
|
256
|
+
const port = ctx.getPort(invocationId);
|
|
257
|
+
if (!port) {
|
|
258
|
+
await ctx.log.append({
|
|
259
|
+
type: "execute_error",
|
|
260
|
+
stage: "executed",
|
|
261
|
+
...flat,
|
|
262
|
+
ok: false,
|
|
263
|
+
error: "no content script port",
|
|
264
|
+
});
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
sendToPort(port, "shareViewkey", {
|
|
268
|
+
viewkey: String(args.viewkey ?? ""),
|
|
269
|
+
primary_address: String(args.primary_address ?? ""),
|
|
270
|
+
tool_invo,
|
|
271
|
+
});
|
|
272
|
+
await ctx.log.append({
|
|
273
|
+
type: "execute_start",
|
|
274
|
+
stage: "executed",
|
|
275
|
+
...flat,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
/** fifth toolCall state transition: execute_error executed. */
|
|
279
|
+
async function execute_fail(ctx, payload) {
|
|
280
|
+
const p = payload;
|
|
281
|
+
await ctx.log.append({
|
|
282
|
+
type: "execute_error",
|
|
283
|
+
stage: "executed",
|
|
284
|
+
...flatFromParsed(p.tool_invo),
|
|
285
|
+
ok: false,
|
|
286
|
+
error: p.error ?? "share failed",
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
/** fifth toolCall state transition: execute_result executed. */
|
|
290
|
+
async function execute_ok(ctx, payload) {
|
|
291
|
+
const invo = await ctx.log.invocation(payload.invocationId);
|
|
292
|
+
if (!invo)
|
|
293
|
+
return;
|
|
294
|
+
await ctx.log.append({
|
|
295
|
+
type: "execute_result",
|
|
296
|
+
stage: "executed",
|
|
297
|
+
invocationId: payload.invocationId,
|
|
298
|
+
toolId: "002",
|
|
299
|
+
ok: true,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
/** toolCall state transition: dismiss accepted. */
|
|
303
|
+
async function accept_no(ctx, invocationId) {
|
|
304
|
+
const invo = await ctx.log.invocation(invocationId);
|
|
305
|
+
if (!invo || isTerminalTipType(invo.lastType))
|
|
306
|
+
return;
|
|
307
|
+
await ctx.log.append({
|
|
308
|
+
type: "dismiss",
|
|
309
|
+
stage: "accepted",
|
|
310
|
+
invocationId,
|
|
311
|
+
toolId: "002",
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
/** toolCall state transition: aborted. */
|
|
315
|
+
async function execute_abort(ctx, invocationId) {
|
|
316
|
+
const invo = await ctx.log.invocation(invocationId);
|
|
317
|
+
if (!invo || isTerminalTipType(invo.lastType))
|
|
318
|
+
return;
|
|
319
|
+
await ctx.log.append({
|
|
320
|
+
type: "aborted",
|
|
321
|
+
stage: invo.stage,
|
|
322
|
+
invocationId,
|
|
323
|
+
toolId: "002",
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
const tool002 = {
|
|
327
|
+
permissions: ["share_view"],
|
|
328
|
+
ui: {
|
|
329
|
+
openTitle: "view-only wallet share",
|
|
330
|
+
acceptLabel: "ACCEPT",
|
|
331
|
+
dismissLabel: "DISMISS",
|
|
332
|
+
},
|
|
333
|
+
content: {
|
|
334
|
+
recognize_parse,
|
|
335
|
+
validate_check,
|
|
336
|
+
execute_deliver,
|
|
337
|
+
},
|
|
338
|
+
worker: {
|
|
339
|
+
invoke_write,
|
|
340
|
+
validate_write,
|
|
341
|
+
accept_yes,
|
|
342
|
+
accept_no,
|
|
343
|
+
execute_run,
|
|
344
|
+
execute_abort,
|
|
345
|
+
execute_ok,
|
|
346
|
+
execute_fail,
|
|
347
|
+
},
|
|
348
|
+
counterparty: {
|
|
349
|
+
make,
|
|
350
|
+
execute_route,
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
export default tool002;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type ExtensionRuntime = {
|
|
2
|
+
sendMessage: (msg: unknown) => Promise<unknown>;
|
|
3
|
+
connect: (info: {
|
|
4
|
+
name: string;
|
|
5
|
+
}) => {
|
|
6
|
+
onMessage: {
|
|
7
|
+
addListener: (cb: (msg: unknown) => void) => void;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
type ExtensionBrowser = {
|
|
12
|
+
runtime: ExtensionRuntime;
|
|
13
|
+
};
|
|
14
|
+
declare global {
|
|
15
|
+
var browser: ExtensionBrowser;
|
|
16
|
+
var chrome: ExtensionBrowser;
|
|
17
|
+
}
|
|
18
|
+
/** send toolCall and openSidebar to worker. after the check, toolCall message to worker again to persist validity status,
|
|
19
|
+
* potential second round of communication with backend. */
|
|
20
|
+
export declare function interceptToolLinkCallback(e: Event): void;
|
|
21
|
+
export declare function installToolLinkEventInterception(): void;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// do not import api.ts (indexedDB top-level await). tools/monero-tools.ts is 001+002 only.
|
|
2
|
+
import { checkToolInvocationValidity, parseToolInvocation, tools, } from "./monero-tools";
|
|
3
|
+
import { sendToBackground } from "./globals";
|
|
4
|
+
if (typeof chrome !== "undefined" && typeof browser === "undefined") {
|
|
5
|
+
globalThis.browser = chrome;
|
|
6
|
+
}
|
|
7
|
+
function processTargetLink(element) {
|
|
8
|
+
if (!element || element.tagName !== "A")
|
|
9
|
+
return false;
|
|
10
|
+
const href = element.href || element.getAttribute("href") || "";
|
|
11
|
+
const text = element.textContent || element.innerText || "";
|
|
12
|
+
//invo id created here
|
|
13
|
+
return parseToolInvocation(href, text, location);
|
|
14
|
+
}
|
|
15
|
+
/** send toolCall and openSidebar to worker. after the check, toolCall message to worker again to persist validity status,
|
|
16
|
+
* potential second round of communication with backend. */
|
|
17
|
+
export function interceptToolLinkCallback(e) {
|
|
18
|
+
if (!(e.target instanceof Element))
|
|
19
|
+
return;
|
|
20
|
+
const link = e.target.closest("a");
|
|
21
|
+
const monerotoolLink = processTargetLink(link);
|
|
22
|
+
if (!link || !monerotoolLink)
|
|
23
|
+
return;
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
e.stopImmediatePropagation();
|
|
26
|
+
void sendToBackground("toolCall", monerotoolLink).catch(() => { });
|
|
27
|
+
void sendToBackground("openSidebar", null).catch(() => { });
|
|
28
|
+
checkToolInvocationValidity(monerotoolLink).then((result) => {
|
|
29
|
+
monerotoolLink.valid = result;
|
|
30
|
+
// save validity status, invo id still the same so event added to this same invo id
|
|
31
|
+
void sendToBackground("toolCall", monerotoolLink).catch(() => { });
|
|
32
|
+
const id = monerotoolLink.tool.tool_id;
|
|
33
|
+
// if there is a second stage communication with the backend it happens here via the message port (same tab / circuit compartmentalization)
|
|
34
|
+
tools[id]?.content.execute_deliver?.(monerotoolLink);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export function installToolLinkEventInterception() {
|
|
38
|
+
document.addEventListener("click", interceptToolLinkCallback, true);
|
|
39
|
+
document.addEventListener("touchend", interceptToolLinkCallback, true);
|
|
40
|
+
document.addEventListener("keydown", interceptToolLinkCallback, true);
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { tools, createToolLink, TOOL_IDS } from "./monero-tools";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const listUrl = "https://publicsuffix.org/list/public_suffix_list.dat";
|
|
2
|
+
const outPath = new URL("./public-suffix-list.ts", import.meta.url);
|
|
3
|
+
const response = await fetch(listUrl);
|
|
4
|
+
if (!response.ok) {
|
|
5
|
+
throw new Error(`download failed: ${response.status}`);
|
|
6
|
+
}
|
|
7
|
+
const rules = [];
|
|
8
|
+
for (const raw of (await response.text()).split(/\r?\n/)) {
|
|
9
|
+
const line = raw.trim();
|
|
10
|
+
if (!line || line.startsWith("//"))
|
|
11
|
+
continue;
|
|
12
|
+
if (line.includes("===BEGIN"))
|
|
13
|
+
continue;
|
|
14
|
+
rules.push(line);
|
|
15
|
+
}
|
|
16
|
+
const body = rules.map((rule) => ` ${JSON.stringify(rule)},`).join("\n");
|
|
17
|
+
const source = `// generated by download-public-suffix.ts\nexport const publicSuffixRules = [\n${body}\n] as const;\n`;
|
|
18
|
+
await Bun.write(outPath, source);
|
|
19
|
+
console.log(`${rules.length} rules -> ${outPath.pathname}`);
|
|
20
|
+
export {};
|