@urnetwork/sdk 2026.9.17-1048676710
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 +106 -0
- package/dist/api.d.ts +23 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/generated/index.d.ts +2 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/types.d.ts +639 -0
- package/dist/generated/types.d.ts.map +1 -0
- package/dist/index.cjs +1484 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1462 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +26 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/react/context.d.ts +33 -0
- package/dist/react/context.d.ts.map +1 -0
- package/dist/react/hooks/constants.d.ts +2 -0
- package/dist/react/hooks/constants.d.ts.map +1 -0
- package/dist/react/hooks/index.d.ts +7 -0
- package/dist/react/hooks/index.d.ts.map +1 -0
- package/dist/react/hooks/useAuthCodeLogin.d.ts +7 -0
- package/dist/react/hooks/useAuthCodeLogin.d.ts.map +1 -0
- package/dist/react/hooks/useAuthNetworkClient.d.ts +7 -0
- package/dist/react/hooks/useAuthNetworkClient.d.ts.map +1 -0
- package/dist/react/hooks/useCheckNetwork.d.ts +13 -0
- package/dist/react/hooks/useCheckNetwork.d.ts.map +1 -0
- package/dist/react/hooks/useProviderList.d.ts +10 -0
- package/dist/react/hooks/useProviderList.d.ts.map +1 -0
- package/dist/react/hooks/useRemoveNetworkClient.d.ts +6 -0
- package/dist/react/hooks/useRemoveNetworkClient.d.ts.map +1 -0
- package/dist/react/hooks/useVerifyUserAuth.d.ts +7 -0
- package/dist/react/hooks/useVerifyUserAuth.d.ts.map +1 -0
- package/dist/react/index.cjs +2050 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +2021 -0
- package/dist/react/index.js.map +1 -0
- package/dist/socket.d.ts +111 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/subprotocol.d.ts +27 -0
- package/dist/subprotocol.d.ts.map +1 -0
- package/dist/types.d.ts +616 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/fetch_retry.d.ts +10 -0
- package/dist/utils/fetch_retry.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/jwt.d.ts +7 -0
- package/dist/utils/jwt.d.ts.map +1 -0
- package/dist/utils/solana_pay.d.ts +17 -0
- package/dist/utils/solana_pay.d.ts.map +1 -0
- package/dist/wasm/sdk.wasm +4 -0
- package/dist/wasm/wasm_exec.js +575 -0
- package/package.json +58 -0
- package/wasm/sdk.wasm +4 -0
- package/wasm/wasm_exec.js +575 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1462 @@
|
|
|
1
|
+
let wasmInitialized = false;
|
|
2
|
+
let wasmInitPromise = null;
|
|
3
|
+
const runtimeGlobal = globalThis;
|
|
4
|
+
const isNode = () => Boolean(globalThis.process?.versions?.node);
|
|
5
|
+
async function readNodeFile(url) {
|
|
6
|
+
const moduleName = "node:fs/promises";
|
|
7
|
+
const fs = await import(moduleName);
|
|
8
|
+
return fs.readFile(new URL(url));
|
|
9
|
+
}
|
|
10
|
+
function packagedUrl(name) {
|
|
11
|
+
const rel = `../wasm/${name}`;
|
|
12
|
+
return new URL(rel, import.meta.url).href;
|
|
13
|
+
}
|
|
14
|
+
async function loadWasmExec(url) {
|
|
15
|
+
if (typeof runtimeGlobal.Go !== "undefined") {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const wasmExecUrl = url || packagedUrl("wasm_exec.js");
|
|
19
|
+
if (isNode()) {
|
|
20
|
+
if (wasmExecUrl.startsWith("file:")) {
|
|
21
|
+
await import(wasmExecUrl);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
const response = await fetch(wasmExecUrl);
|
|
25
|
+
if (!response.ok)
|
|
26
|
+
throw new Error("Could not load wasm_exec.js: HTTP " + response.status);
|
|
27
|
+
const moduleName = "node:vm";
|
|
28
|
+
const vm = await import(moduleName);
|
|
29
|
+
vm.runInThisContext(await response.text(), { filename: wasmExecUrl });
|
|
30
|
+
}
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const script = document.createElement("script");
|
|
35
|
+
script.src = wasmExecUrl;
|
|
36
|
+
script.onload = () => resolve();
|
|
37
|
+
script.onerror = () => reject(new Error(`Failed to load wasm_exec.js from ${wasmExecUrl}`));
|
|
38
|
+
document.head.appendChild(script);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
async function instantiateWasm(wasmUrl, go) {
|
|
42
|
+
let result;
|
|
43
|
+
if (isNode() && wasmUrl.startsWith("file:")) {
|
|
44
|
+
result = await WebAssembly.instantiate(await readNodeFile(wasmUrl), go.importObject);
|
|
45
|
+
return result.instance;
|
|
46
|
+
}
|
|
47
|
+
const response = await fetch(wasmUrl);
|
|
48
|
+
if (!response.ok)
|
|
49
|
+
throw new Error(`Could not load WASM: HTTP ${response.status}`);
|
|
50
|
+
if (WebAssembly.instantiateStreaming) {
|
|
51
|
+
try {
|
|
52
|
+
result = await WebAssembly.instantiateStreaming(response.clone(), go.importObject);
|
|
53
|
+
return result.instance;
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
console.warn("Streaming instantiation failed, falling back to fetch:", e);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const wasmBuffer = await response.arrayBuffer();
|
|
60
|
+
result = await WebAssembly.instantiate(wasmBuffer, go.importObject);
|
|
61
|
+
return result.instance;
|
|
62
|
+
}
|
|
63
|
+
async function initWasm(options = {}) {
|
|
64
|
+
if (wasmInitPromise) {
|
|
65
|
+
return wasmInitPromise;
|
|
66
|
+
}
|
|
67
|
+
if (wasmInitialized) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
wasmInitPromise = (async () => {
|
|
71
|
+
try {
|
|
72
|
+
await loadWasmExec(options.wasmExecUrl);
|
|
73
|
+
const go = new runtimeGlobal.Go();
|
|
74
|
+
const previousGlobals = new Set(Object.keys(globalThis));
|
|
75
|
+
let registeredGlobals = [];
|
|
76
|
+
const originalExit = go.exit;
|
|
77
|
+
go.exit = (code) => {
|
|
78
|
+
for (const timer of go._scheduledTimeouts?.values() || [])
|
|
79
|
+
clearTimeout(timer);
|
|
80
|
+
go._scheduledTimeouts?.clear();
|
|
81
|
+
wasmInitialized = false;
|
|
82
|
+
wasmInitPromise = null;
|
|
83
|
+
for (const key of registeredGlobals)
|
|
84
|
+
delete globalThis[key];
|
|
85
|
+
originalExit(code);
|
|
86
|
+
};
|
|
87
|
+
const wasmUrl = options.wasmUrl || packagedUrl("sdk.wasm");
|
|
88
|
+
const wasmInstance = await instantiateWasm(wasmUrl, go);
|
|
89
|
+
await new Promise((resolve, reject) => {
|
|
90
|
+
let ready = false;
|
|
91
|
+
let timer;
|
|
92
|
+
const expires = Date.now() + 30000;
|
|
93
|
+
const check = () => {
|
|
94
|
+
if (typeof runtimeGlobal.URnetworkNewPlatformDeviceRemote === "function" &&
|
|
95
|
+
typeof runtimeGlobal.URnetworkClose === "function") {
|
|
96
|
+
ready = true;
|
|
97
|
+
registeredGlobals = Object.keys(globalThis).filter(key => key.startsWith("URnetwork") && !previousGlobals.has(key));
|
|
98
|
+
resolve();
|
|
99
|
+
}
|
|
100
|
+
else if (Date.now() >= expires) {
|
|
101
|
+
reject(new Error("Go runtime did not register its SDK exports"));
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
timer = setTimeout(check, 5);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
Promise.resolve(go.run(wasmInstance)).then(() => {
|
|
108
|
+
clearTimeout(timer);
|
|
109
|
+
if (!ready)
|
|
110
|
+
reject(new Error("Go runtime exited before registering SDK exports"));
|
|
111
|
+
}, error => { clearTimeout(timer); reject(error); });
|
|
112
|
+
check();
|
|
113
|
+
});
|
|
114
|
+
wasmInitialized = true;
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
wasmInitPromise = null;
|
|
118
|
+
throw new Error(`Failed to initialize URnetwork WASM: ${error}`);
|
|
119
|
+
}
|
|
120
|
+
})();
|
|
121
|
+
return wasmInitPromise;
|
|
122
|
+
}
|
|
123
|
+
function isWasmInitialized() {
|
|
124
|
+
return wasmInitialized;
|
|
125
|
+
}
|
|
126
|
+
function getWasmGlobals() {
|
|
127
|
+
if (!wasmInitialized) {
|
|
128
|
+
throw new Error("WASM not initialized. Call initWasm() first.");
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
URnetworkNewProxyDeviceWithDefaults: runtimeGlobal.URnetworkNewProxyDeviceWithDefaults,
|
|
132
|
+
URnetworkNewPlatformDeviceRemote: runtimeGlobal.URnetworkNewPlatformDeviceRemote,
|
|
133
|
+
URnetworkNewExtensionDeviceRemote: runtimeGlobal.URnetworkNewExtensionDeviceRemote,
|
|
134
|
+
URnetworkNewLocationsViewController: runtimeGlobal.URnetworkNewLocationsViewController,
|
|
135
|
+
URnetworkNewAccountHost: runtimeGlobal.URnetworkNewAccountHost,
|
|
136
|
+
URnetworkColorHex: runtimeGlobal.URnetworkColorHex,
|
|
137
|
+
URnetworkClose: runtimeGlobal.URnetworkClose,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function bytes(value) {
|
|
142
|
+
if (!(value instanceof Uint8Array))
|
|
143
|
+
throw new TypeError("Expected Uint8Array");
|
|
144
|
+
return value.slice();
|
|
145
|
+
}
|
|
146
|
+
function deadline(value) {
|
|
147
|
+
const millis = value === null ? 0 : Number(value);
|
|
148
|
+
if (!Number.isSafeInteger(millis))
|
|
149
|
+
throw new RangeError("Expected epoch milliseconds or null");
|
|
150
|
+
return millis;
|
|
151
|
+
}
|
|
152
|
+
class Conn {
|
|
153
|
+
constructor(bridge, handle, network) {
|
|
154
|
+
this.released = false;
|
|
155
|
+
this.eof = false;
|
|
156
|
+
this.writes = Promise.resolve();
|
|
157
|
+
this.bridge = bridge;
|
|
158
|
+
this.handle = handle;
|
|
159
|
+
this.network = network;
|
|
160
|
+
this.readable = new ReadableStream({
|
|
161
|
+
pull: async (controller) => { const data = await this.read(); if (data === null)
|
|
162
|
+
controller.close();
|
|
163
|
+
else
|
|
164
|
+
controller.enqueue(data); },
|
|
165
|
+
cancel: async () => { if (network.startsWith("udp"))
|
|
166
|
+
await this.close();
|
|
167
|
+
else
|
|
168
|
+
await this.closeRead(); },
|
|
169
|
+
}, { highWaterMark: 0 });
|
|
170
|
+
this.writable = new WritableStream({
|
|
171
|
+
write: async (data) => { await this.write(data); },
|
|
172
|
+
close: async () => { if (network.startsWith("udp"))
|
|
173
|
+
await this.close();
|
|
174
|
+
else
|
|
175
|
+
await this.closeWrite(); },
|
|
176
|
+
abort: async () => { await this.close(); },
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
call(op, arg = null) {
|
|
180
|
+
if (this.released)
|
|
181
|
+
return Promise.reject(new Error("Socket is closed"));
|
|
182
|
+
return this.bridge.socketOperation(op, this.handle.id, arg);
|
|
183
|
+
}
|
|
184
|
+
waitClosed() { return this.call("socketClosed"); }
|
|
185
|
+
get localAddr() { return this.handle.localAddr ?? ""; }
|
|
186
|
+
get remoteAddr() { return this.handle.remoteAddr ?? ""; }
|
|
187
|
+
async read(maxBytes = 65535) {
|
|
188
|
+
if (!Number.isInteger(maxBytes) || maxBytes < 1 || maxBytes > 65535)
|
|
189
|
+
throw new RangeError("read size must be between 1 and 65535");
|
|
190
|
+
if (this.eof)
|
|
191
|
+
return null;
|
|
192
|
+
if (this.readError) {
|
|
193
|
+
const error = this.readError;
|
|
194
|
+
this.readError = undefined;
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
const result = await this.call("read", maxBytes);
|
|
198
|
+
this.eof = result.eof;
|
|
199
|
+
if (result.error)
|
|
200
|
+
this.readError = new Error(result.error);
|
|
201
|
+
if (this.network === "udp")
|
|
202
|
+
Object.assign(this.handle, await this.call("addresses"));
|
|
203
|
+
return result.eof && result.data.length === 0 ? null : result.data;
|
|
204
|
+
}
|
|
205
|
+
async write(value) {
|
|
206
|
+
const data = bytes(value);
|
|
207
|
+
if (this.network.startsWith("udp") && data.length > 65507)
|
|
208
|
+
throw new RangeError("UDP datagram exceeds 65507 bytes");
|
|
209
|
+
const operation = this.writes.then(() => this.writeBytes(data));
|
|
210
|
+
this.writes = operation.catch(() => { });
|
|
211
|
+
return operation;
|
|
212
|
+
}
|
|
213
|
+
async writeBytes(data) {
|
|
214
|
+
let written = 0;
|
|
215
|
+
do {
|
|
216
|
+
const chunk = data.subarray(written, written + 65535);
|
|
217
|
+
let result;
|
|
218
|
+
try {
|
|
219
|
+
result = await this.call("write", chunk);
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
throw Object.assign(error instanceof Error ? error : new Error(String(error)), { bytesWritten: written });
|
|
223
|
+
}
|
|
224
|
+
const n = typeof result === "number" ? result : result.bytesWritten;
|
|
225
|
+
written += n;
|
|
226
|
+
if (result.error)
|
|
227
|
+
throw Object.assign(new Error(result.error), { bytesWritten: written });
|
|
228
|
+
if (n !== chunk.length)
|
|
229
|
+
throw Object.assign(new Error("Short socket write"), { bytesWritten: written });
|
|
230
|
+
} while (written < data.length);
|
|
231
|
+
return written;
|
|
232
|
+
}
|
|
233
|
+
setDeadline(t) { return this.call("deadline", deadline(t)); }
|
|
234
|
+
setReadDeadline(t) { return this.call("readDeadline", deadline(t)); }
|
|
235
|
+
setWriteDeadline(t) { return this.call("writeDeadline", deadline(t)); }
|
|
236
|
+
closeRead() { return this.call("closeRead"); }
|
|
237
|
+
closeWrite() { return this.call("closeWrite"); }
|
|
238
|
+
async close() {
|
|
239
|
+
if (this.released)
|
|
240
|
+
return;
|
|
241
|
+
this.released = true;
|
|
242
|
+
await this.bridge.socketOperation("release", this.handle.id, null);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function attachSocketAPI(device) {
|
|
246
|
+
const bridge = device;
|
|
247
|
+
const dial = async (op, network, address, tls, options = {}) => {
|
|
248
|
+
if (!/^(tcp|udp)[46]?$/.test(network))
|
|
249
|
+
throw new TypeError("Unsupported socket network");
|
|
250
|
+
validateDialOptions(options);
|
|
251
|
+
options.signal?.throwIfAborted();
|
|
252
|
+
const handle = await bridge.socketOperation(op, 0, { network, address, tls, ...options });
|
|
253
|
+
if (options.signal?.aborted) {
|
|
254
|
+
await bridge.socketOperation("release", handle.id, null);
|
|
255
|
+
options.signal.throwIfAborted();
|
|
256
|
+
}
|
|
257
|
+
return new Conn(bridge, handle, network);
|
|
258
|
+
};
|
|
259
|
+
const result = Object.assign(device, {
|
|
260
|
+
dial: (network, address, options) => dial("dial", network, address, undefined, options),
|
|
261
|
+
dialTls: (network, address, tls, options) => dial("dialTls", network, address, tls, options),
|
|
262
|
+
});
|
|
263
|
+
return Object.assign(result, { directSockets: createDirectSockets(result) });
|
|
264
|
+
}
|
|
265
|
+
function validateDialOptions(options) {
|
|
266
|
+
if (options.timeoutMillis !== undefined && (!Number.isSafeInteger(options.timeoutMillis) || options.timeoutMillis < 0 || options.timeoutMillis > 2147483647))
|
|
267
|
+
throw new RangeError("timeoutMillis must be between 0 and 2147483647");
|
|
268
|
+
}
|
|
269
|
+
function invalidState(message) { return new DOMException(message, "InvalidStateError"); }
|
|
270
|
+
function unsupported(message) { throw new DOMException(message, "NotSupportedError"); }
|
|
271
|
+
function networkError(cause) {
|
|
272
|
+
return new DOMException(cause instanceof Error ? cause.message : String(cause), "NetworkError");
|
|
273
|
+
}
|
|
274
|
+
function uint(value, max, field) {
|
|
275
|
+
const n = Math.trunc(Number(value));
|
|
276
|
+
if (!Number.isFinite(n) || n < 0 || n > max)
|
|
277
|
+
throw new TypeError(field + " is out of range");
|
|
278
|
+
return n;
|
|
279
|
+
}
|
|
280
|
+
function destination(host, port) {
|
|
281
|
+
if (typeof host !== "string" || !host || /[\s/\[\]?#@]/.test(host))
|
|
282
|
+
throw new TypeError("Expected a hostname or unbracketed IP address");
|
|
283
|
+
const n = uint(port, 65535, "remotePort");
|
|
284
|
+
if (!n)
|
|
285
|
+
throw new TypeError("remotePort must be nonzero");
|
|
286
|
+
if (/^(?:22[4-9]|23\d)\./.test(host) || /^ff[\da-f]{0,2}:/i.test(host))
|
|
287
|
+
unsupported("Multicast sockets are not supported");
|
|
288
|
+
return (host.includes(":") ? "[" + host + "]" : host) + ":" + n;
|
|
289
|
+
}
|
|
290
|
+
function network(protocol, options) {
|
|
291
|
+
if (options.dnsQueryType !== undefined && options.dnsQueryType !== "ipv4" && options.dnsQueryType !== "ipv6")
|
|
292
|
+
throw new TypeError("Invalid dnsQueryType");
|
|
293
|
+
for (const field of ["sendBufferSize", "receiveBufferSize"]) {
|
|
294
|
+
if (options[field] !== undefined) {
|
|
295
|
+
if (!uint(options[field], 0xffffffff, field))
|
|
296
|
+
throw new TypeError(field + " must be nonzero");
|
|
297
|
+
unsupported("Per-socket " + field + " is not supported by the Device");
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return (protocol + (options.dnsQueryType === "ipv4" ? "4" : options.dnsQueryType === "ipv6" ? "6" : ""));
|
|
301
|
+
}
|
|
302
|
+
function copyBuffer(value) {
|
|
303
|
+
if (!(value instanceof ArrayBuffer) && !ArrayBuffer.isView(value))
|
|
304
|
+
throw new TypeError("Expected BufferSource");
|
|
305
|
+
const view = ArrayBuffer.isView(value) ? new Uint8Array(value.buffer, value.byteOffset, value.byteLength) : new Uint8Array(value);
|
|
306
|
+
if (!(view.buffer instanceof ArrayBuffer))
|
|
307
|
+
throw new TypeError("Shared buffers are not supported");
|
|
308
|
+
return view.slice();
|
|
309
|
+
}
|
|
310
|
+
function endpoint(address) {
|
|
311
|
+
const split = address.lastIndexOf(":");
|
|
312
|
+
let host = address.slice(0, split);
|
|
313
|
+
if (host.startsWith("[") && host.endsWith("]"))
|
|
314
|
+
host = host.slice(1, -1);
|
|
315
|
+
const port = Number(address.slice(split + 1));
|
|
316
|
+
if (split < 1 || !host || !Number.isInteger(port) || port < 0 || port > 65535)
|
|
317
|
+
throw new Error("Device returned an invalid socket address");
|
|
318
|
+
return { address: host, port };
|
|
319
|
+
}
|
|
320
|
+
class DirectSocket {
|
|
321
|
+
constructor(device, protocol, address, udp) {
|
|
322
|
+
this.readDone = false;
|
|
323
|
+
this.writeDone = false;
|
|
324
|
+
this.readStopped = false;
|
|
325
|
+
this.writeStopped = false;
|
|
326
|
+
this.reading = false;
|
|
327
|
+
this.writing = false;
|
|
328
|
+
this.failed = false;
|
|
329
|
+
this.settled = false;
|
|
330
|
+
this.udp = udp;
|
|
331
|
+
this.closed = new Promise((resolve, reject) => { this.resolveClosed = resolve; this.rejectClosed = reject; });
|
|
332
|
+
void this.closed.catch(() => { });
|
|
333
|
+
this.opened = Promise.resolve().then(() => device.dial(protocol, address)).then(async (conn) => {
|
|
334
|
+
this.conn = conn;
|
|
335
|
+
try {
|
|
336
|
+
this.info = this.streams();
|
|
337
|
+
void conn.waitClosed().then(() => {
|
|
338
|
+
if (!this.finishing)
|
|
339
|
+
this.fail(networkError("Socket closed by its Device"));
|
|
340
|
+
}, error => { if (!this.finishing)
|
|
341
|
+
this.fail(networkError(error)); });
|
|
342
|
+
return this.info;
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
await conn.close();
|
|
346
|
+
throw error;
|
|
347
|
+
}
|
|
348
|
+
}).catch(error => {
|
|
349
|
+
const failure = networkError(error);
|
|
350
|
+
this.settled = true;
|
|
351
|
+
this.rejectClosed(failure);
|
|
352
|
+
throw failure;
|
|
353
|
+
});
|
|
354
|
+
void this.opened.catch(() => { });
|
|
355
|
+
}
|
|
356
|
+
streams() {
|
|
357
|
+
const conn = this.conn;
|
|
358
|
+
const readable = this.udp
|
|
359
|
+
? new ReadableStream({
|
|
360
|
+
start: c => { this.readController = c; },
|
|
361
|
+
pull: c => this.pull(c), cancel: () => this.stopRead(),
|
|
362
|
+
}, { highWaterMark: 0 })
|
|
363
|
+
: new ReadableStream({
|
|
364
|
+
type: "bytes", autoAllocateChunkSize: 65535,
|
|
365
|
+
start: c => { this.readController = c; },
|
|
366
|
+
pull: c => this.pull(c), cancel: () => this.stopRead(),
|
|
367
|
+
}, { highWaterMark: 0 });
|
|
368
|
+
const writable = new WritableStream({
|
|
369
|
+
start: c => {
|
|
370
|
+
this.writeController = c;
|
|
371
|
+
c.signal.addEventListener("abort", () => { void this.stopWrite().catch(error => this.fail(networkError(error))); }, { once: true });
|
|
372
|
+
},
|
|
373
|
+
write: value => this.write(value),
|
|
374
|
+
close: () => this.stopWrite(),
|
|
375
|
+
abort: () => this.stopWrite(),
|
|
376
|
+
});
|
|
377
|
+
return {
|
|
378
|
+
readable, writable,
|
|
379
|
+
get remoteAddress() { return endpoint(conn.remoteAddr).address; },
|
|
380
|
+
get remotePort() { return endpoint(conn.remoteAddr).port; },
|
|
381
|
+
get localAddress() { return endpoint(conn.localAddr).address; },
|
|
382
|
+
get localPort() { return endpoint(conn.localAddr).port; },
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
async pull(controller) {
|
|
386
|
+
if (this.readDone)
|
|
387
|
+
return;
|
|
388
|
+
this.reading = true;
|
|
389
|
+
try {
|
|
390
|
+
const request = "byobRequest" in controller ? controller.byobRequest : null;
|
|
391
|
+
const data = await this.conn.read(Math.min(request?.view?.byteLength ?? 65535, 65535));
|
|
392
|
+
if (this.readDone)
|
|
393
|
+
return;
|
|
394
|
+
if (data === null) {
|
|
395
|
+
this.readDone = true;
|
|
396
|
+
this.readStopped = true;
|
|
397
|
+
controller.close();
|
|
398
|
+
if (request)
|
|
399
|
+
request.respond(0);
|
|
400
|
+
await this.finish();
|
|
401
|
+
}
|
|
402
|
+
else if ("byobRequest" in controller) {
|
|
403
|
+
if (!data.length)
|
|
404
|
+
return;
|
|
405
|
+
if (request?.view) {
|
|
406
|
+
new Uint8Array(request.view.buffer, request.view.byteOffset, request.view.byteLength).set(data);
|
|
407
|
+
request.respond(data.length);
|
|
408
|
+
}
|
|
409
|
+
else
|
|
410
|
+
controller.enqueue(data.slice());
|
|
411
|
+
}
|
|
412
|
+
else
|
|
413
|
+
controller.enqueue({ data: data.slice() });
|
|
414
|
+
}
|
|
415
|
+
catch (error) {
|
|
416
|
+
if (!this.readDone)
|
|
417
|
+
this.fail(networkError(error));
|
|
418
|
+
}
|
|
419
|
+
finally {
|
|
420
|
+
this.reading = false;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
async write(value) {
|
|
424
|
+
let data;
|
|
425
|
+
try {
|
|
426
|
+
if (this.udp) {
|
|
427
|
+
const message = value;
|
|
428
|
+
if (!message || typeof message !== "object")
|
|
429
|
+
throw new TypeError("Expected UDPMessage");
|
|
430
|
+
if (message.remoteAddress !== undefined || message.remotePort !== undefined || message.dnsQueryType !== undefined)
|
|
431
|
+
throw new TypeError("Connected UDP messages must not specify a destination");
|
|
432
|
+
data = copyBuffer(message.data);
|
|
433
|
+
}
|
|
434
|
+
else
|
|
435
|
+
data = copyBuffer(value);
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
this.failed = true;
|
|
439
|
+
this.failure = error;
|
|
440
|
+
await this.stopWrite();
|
|
441
|
+
throw error;
|
|
442
|
+
}
|
|
443
|
+
this.writing = true;
|
|
444
|
+
try {
|
|
445
|
+
await this.conn.write(data);
|
|
446
|
+
}
|
|
447
|
+
catch (error) {
|
|
448
|
+
if (this.writeController.signal.aborted)
|
|
449
|
+
throw this.writeController.signal.reason;
|
|
450
|
+
const failure = networkError(error);
|
|
451
|
+
if (error && typeof error === "object" && "bytesWritten" in error)
|
|
452
|
+
Object.assign(failure, { bytesWritten: error.bytesWritten });
|
|
453
|
+
this.fail(failure);
|
|
454
|
+
throw failure;
|
|
455
|
+
}
|
|
456
|
+
finally {
|
|
457
|
+
this.writing = false;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
stopRead() {
|
|
461
|
+
if (this.readStop)
|
|
462
|
+
return this.readStop;
|
|
463
|
+
if (this.readDone)
|
|
464
|
+
return this.finish();
|
|
465
|
+
this.readDone = true;
|
|
466
|
+
this.readStop = (async () => {
|
|
467
|
+
if (!this.udp)
|
|
468
|
+
await this.conn.closeRead();
|
|
469
|
+
else if (this.reading)
|
|
470
|
+
await this.conn.setReadDeadline(1);
|
|
471
|
+
})().then(() => { this.readStopped = true; return this.finish(); }, error => this.fail(networkError(error)));
|
|
472
|
+
return this.readStop;
|
|
473
|
+
}
|
|
474
|
+
stopWrite() {
|
|
475
|
+
if (this.writeStop)
|
|
476
|
+
return this.writeStop;
|
|
477
|
+
if (this.writeDone)
|
|
478
|
+
return this.finish();
|
|
479
|
+
this.writeDone = true;
|
|
480
|
+
this.writeStop = (async () => {
|
|
481
|
+
if (!this.udp)
|
|
482
|
+
await this.conn.closeWrite();
|
|
483
|
+
else if (this.writing)
|
|
484
|
+
await this.conn.setWriteDeadline(1);
|
|
485
|
+
})().then(() => { this.writeStopped = true; return this.finish(); }, error => this.fail(networkError(error)));
|
|
486
|
+
return this.writeStop;
|
|
487
|
+
}
|
|
488
|
+
fail(error) {
|
|
489
|
+
if (this.finishing)
|
|
490
|
+
return;
|
|
491
|
+
this.failed = true;
|
|
492
|
+
this.failure = error;
|
|
493
|
+
this.readDone = true;
|
|
494
|
+
this.writeDone = true;
|
|
495
|
+
this.readStopped = true;
|
|
496
|
+
this.writeStopped = true;
|
|
497
|
+
this.readController?.error(error);
|
|
498
|
+
this.writeController?.error(error);
|
|
499
|
+
void this.finish();
|
|
500
|
+
}
|
|
501
|
+
finish() {
|
|
502
|
+
if (!this.readDone || !this.writeDone || !this.readStopped || !this.writeStopped)
|
|
503
|
+
return Promise.resolve();
|
|
504
|
+
if (!this.finishing) {
|
|
505
|
+
this.finishing = Promise.resolve().then(() => this.conn.close()).then(() => {
|
|
506
|
+
this.settled = true;
|
|
507
|
+
if (this.failed)
|
|
508
|
+
this.rejectClosed(this.failure);
|
|
509
|
+
else
|
|
510
|
+
this.resolveClosed();
|
|
511
|
+
}, error => { this.settled = true; this.rejectClosed(networkError(error)); });
|
|
512
|
+
}
|
|
513
|
+
return this.finishing;
|
|
514
|
+
}
|
|
515
|
+
close() {
|
|
516
|
+
if (!this.info)
|
|
517
|
+
return Promise.reject(invalidState("Socket has not opened"));
|
|
518
|
+
if (this.settled)
|
|
519
|
+
return this.closed;
|
|
520
|
+
if (this.info.readable.locked || this.info.writable.locked)
|
|
521
|
+
return Promise.reject(invalidState("Release the reader and writer locks before closing the socket"));
|
|
522
|
+
void this.info.readable.cancel().catch(() => { });
|
|
523
|
+
void this.info.writable.abort().catch(() => { });
|
|
524
|
+
return this.closed;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
function createDirectSockets(device) {
|
|
528
|
+
return Object.freeze({
|
|
529
|
+
TCPSocket: class TCPSocket extends DirectSocket {
|
|
530
|
+
constructor(remoteAddress, remotePort, options = {}) {
|
|
531
|
+
const protocol = network("tcp", options);
|
|
532
|
+
if (options.keepAliveDelay !== undefined) {
|
|
533
|
+
if (uint(options.keepAliveDelay, 0xffffffff, "keepAliveDelay") < 1000)
|
|
534
|
+
throw new TypeError("keepAliveDelay must be at least 1000 ms");
|
|
535
|
+
unsupported("Per-socket TCP keep-alive is not supported by the Device");
|
|
536
|
+
}
|
|
537
|
+
if (options.noDelay !== undefined)
|
|
538
|
+
unsupported("Per-socket noDelay is not supported by the Device");
|
|
539
|
+
super(device, protocol, destination(remoteAddress, remotePort), false);
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
UDPSocket: class UDPSocket extends DirectSocket {
|
|
543
|
+
constructor(options = {}) {
|
|
544
|
+
const protocol = network("udp", options);
|
|
545
|
+
if ((options.remoteAddress === undefined) !== (options.remotePort === undefined))
|
|
546
|
+
throw new TypeError("remoteAddress and remotePort must be specified together");
|
|
547
|
+
if (options.localPort !== undefined && (options.localAddress === undefined || !uint(options.localPort, 65535, "localPort")))
|
|
548
|
+
throw new TypeError("localPort requires localAddress and must be nonzero");
|
|
549
|
+
if (options.localAddress !== undefined) {
|
|
550
|
+
if (options.remoteAddress !== undefined)
|
|
551
|
+
throw new TypeError("Local and remote binding options cannot be combined");
|
|
552
|
+
unsupported("Bound UDP sockets are reserved for the future listener API");
|
|
553
|
+
}
|
|
554
|
+
if (options.remoteAddress === undefined)
|
|
555
|
+
throw new TypeError("Connected UDP requires remoteAddress and remotePort");
|
|
556
|
+
if (options.ipv6Only !== undefined)
|
|
557
|
+
throw new TypeError("ipv6Only is only valid for bound UDP");
|
|
558
|
+
if (options.multicastTimeToLive !== undefined || options.multicastLoopback !== undefined || options.multicastAllowAddressSharing !== undefined)
|
|
559
|
+
unsupported("Multicast sockets are not supported");
|
|
560
|
+
super(device, protocol, destination(options.remoteAddress, options.remotePort), true);
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
class SubprotocolSubscription {
|
|
567
|
+
constructor(bridge, handle, id, listener) {
|
|
568
|
+
this.active = true;
|
|
569
|
+
this.bridge = bridge;
|
|
570
|
+
this.handle = handle;
|
|
571
|
+
this.subprotocolId = id;
|
|
572
|
+
this.closed = this.receive(listener);
|
|
573
|
+
void this.closed.catch(() => { });
|
|
574
|
+
}
|
|
575
|
+
async receive(listener) {
|
|
576
|
+
try {
|
|
577
|
+
while (this.active) {
|
|
578
|
+
const message = await this.bridge.subprotocolOperation("receive", this.handle, null);
|
|
579
|
+
if (!this.active)
|
|
580
|
+
break;
|
|
581
|
+
if (!(message.bytes instanceof Uint8Array))
|
|
582
|
+
throw new TypeError("Invalid subprotocol frame from WASM");
|
|
583
|
+
await listener({ subprotocolId: this.subprotocolId, sourceClientId: message.sourceClientId, bytes: message.bytes.slice() });
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
catch (error) {
|
|
587
|
+
if (this.active)
|
|
588
|
+
throw error;
|
|
589
|
+
}
|
|
590
|
+
finally {
|
|
591
|
+
await this.close();
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
requireActive() {
|
|
595
|
+
if (!this.active)
|
|
596
|
+
throw new Error("Subprotocol subscription is closed");
|
|
597
|
+
}
|
|
598
|
+
async send(destinationClientId, bytes) {
|
|
599
|
+
this.requireActive();
|
|
600
|
+
if (!(bytes instanceof Uint8Array))
|
|
601
|
+
throw new TypeError("Expected Uint8Array");
|
|
602
|
+
if (bytes.length > 65535)
|
|
603
|
+
throw new RangeError("Subprotocol frame exceeds 65535 bytes");
|
|
604
|
+
return this.bridge.subprotocolOperation("send", this.handle, { destinationClientId, bytes: bytes.slice() });
|
|
605
|
+
}
|
|
606
|
+
async querySubprotocols(destinationClientId, timeoutMillis = 10000) {
|
|
607
|
+
this.requireActive();
|
|
608
|
+
if (!Number.isSafeInteger(timeoutMillis) || timeoutMillis < 1 || timeoutMillis > 60000)
|
|
609
|
+
throw new RangeError("timeoutMillis must be between 1 and 60000");
|
|
610
|
+
return this.bridge.subprotocolOperation("query", this.handle, { destinationClientId, timeoutMillis });
|
|
611
|
+
}
|
|
612
|
+
close() {
|
|
613
|
+
this.active = false;
|
|
614
|
+
this.release ?? (this.release = this.bridge.subprotocolOperation("release", this.handle, null));
|
|
615
|
+
return this.release;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
function attachSubprotocolAPI(device) {
|
|
619
|
+
const bridge = device;
|
|
620
|
+
return Object.assign(device, {
|
|
621
|
+
async enableSubprotocol(id, listener) {
|
|
622
|
+
if (!Number.isInteger(id) || id < 1024 || id > 65535)
|
|
623
|
+
throw new RangeError("Application subprotocol id must be between 1024 and 65535");
|
|
624
|
+
if (typeof listener !== "function")
|
|
625
|
+
throw new TypeError("Expected subprotocol listener");
|
|
626
|
+
if (typeof bridge.subprotocolOperation !== "function")
|
|
627
|
+
throw new Error("Loaded WASM lacks subprotocol RPC support; rebuild the SDK");
|
|
628
|
+
const handle = await bridge.subprotocolOperation("open", 0, id);
|
|
629
|
+
return new SubprotocolSubscription(bridge, handle.id, id, listener);
|
|
630
|
+
},
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const PointsLeaderboardTier = {
|
|
635
|
+
Unknown: 0,
|
|
636
|
+
Top1: 1,
|
|
637
|
+
Top5: 2,
|
|
638
|
+
Top10: 3,
|
|
639
|
+
Top25: 4,
|
|
640
|
+
Top50: 5,
|
|
641
|
+
Rest: 6,
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
const abortError = (signal) => {
|
|
645
|
+
if (signal.reason !== undefined) {
|
|
646
|
+
return signal.reason;
|
|
647
|
+
}
|
|
648
|
+
if (typeof DOMException !== "undefined") {
|
|
649
|
+
return new DOMException("This operation was aborted", "AbortError");
|
|
650
|
+
}
|
|
651
|
+
const error = new Error("This operation was aborted");
|
|
652
|
+
error.name = "AbortError";
|
|
653
|
+
return error;
|
|
654
|
+
};
|
|
655
|
+
const sleep = (millis, signal) => new Promise((resolve, reject) => {
|
|
656
|
+
if (!signal) {
|
|
657
|
+
setTimeout(resolve, millis);
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
if (signal.aborted) {
|
|
661
|
+
reject(abortError(signal));
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
const onAbort = () => {
|
|
665
|
+
clearTimeout(timer);
|
|
666
|
+
reject(abortError(signal));
|
|
667
|
+
};
|
|
668
|
+
const timer = setTimeout(() => {
|
|
669
|
+
signal.removeEventListener("abort", onAbort);
|
|
670
|
+
resolve();
|
|
671
|
+
}, millis);
|
|
672
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
673
|
+
});
|
|
674
|
+
async function fetchWithGetRetry(input, init, options) {
|
|
675
|
+
const fetchImpl = globalThis.fetch;
|
|
676
|
+
const request = typeof Request !== "undefined" && input instanceof Request
|
|
677
|
+
? input
|
|
678
|
+
: undefined;
|
|
679
|
+
const method = (init?.method ?? request?.method ?? "GET").toUpperCase();
|
|
680
|
+
if (method !== "GET") {
|
|
681
|
+
return fetchImpl(input, init);
|
|
682
|
+
}
|
|
683
|
+
const signal = init?.signal ?? request?.signal ?? undefined;
|
|
684
|
+
const retryCount = 1;
|
|
685
|
+
const retryStatusCodes = [502, 503];
|
|
686
|
+
const retryMinTimeoutMillis = 100;
|
|
687
|
+
const retryMaxTimeoutMillis = 1000;
|
|
688
|
+
const maxAttempt = Math.max(0, retryCount);
|
|
689
|
+
let lastResponse;
|
|
690
|
+
let lastError;
|
|
691
|
+
for (let attempt = 0; attempt <= maxAttempt; attempt += 1) {
|
|
692
|
+
if (0 < attempt) {
|
|
693
|
+
const jitter = retryMinTimeoutMillis +
|
|
694
|
+
Math.random() *
|
|
695
|
+
Math.max(0, retryMaxTimeoutMillis - retryMinTimeoutMillis);
|
|
696
|
+
await sleep(jitter, signal);
|
|
697
|
+
}
|
|
698
|
+
try {
|
|
699
|
+
const response = await fetchImpl(input, init);
|
|
700
|
+
if (!retryStatusCodes.includes(response.status)) {
|
|
701
|
+
return response;
|
|
702
|
+
}
|
|
703
|
+
lastResponse = response;
|
|
704
|
+
lastError = undefined;
|
|
705
|
+
if (attempt < maxAttempt) {
|
|
706
|
+
try {
|
|
707
|
+
await response.body?.cancel();
|
|
708
|
+
}
|
|
709
|
+
catch {
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
catch (error) {
|
|
714
|
+
lastError = error;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
if (lastError !== undefined) {
|
|
718
|
+
throw lastError;
|
|
719
|
+
}
|
|
720
|
+
return lastResponse;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
class URNetworkAPI {
|
|
724
|
+
constructor(config) {
|
|
725
|
+
this.baseURL = config?.baseURL || "https://api.bringyour.com";
|
|
726
|
+
}
|
|
727
|
+
async safeJsonParse(response) {
|
|
728
|
+
const contentType = response.headers.get("content-type");
|
|
729
|
+
if (response.status === 204) {
|
|
730
|
+
return {};
|
|
731
|
+
}
|
|
732
|
+
if (contentType && contentType.includes("application/json")) {
|
|
733
|
+
try {
|
|
734
|
+
const text = await response.text();
|
|
735
|
+
if (!text || text.trim() === "") {
|
|
736
|
+
return {};
|
|
737
|
+
}
|
|
738
|
+
return JSON.parse(text);
|
|
739
|
+
}
|
|
740
|
+
catch (error) {
|
|
741
|
+
console.error("JSON parse error:", error);
|
|
742
|
+
throw new Error("Failed to parse response as JSON");
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
const text = await response.text();
|
|
746
|
+
throw new Error(`Expected JSON response but got: ${text.substring(0, 100)}`);
|
|
747
|
+
}
|
|
748
|
+
async authLogin(params) {
|
|
749
|
+
try {
|
|
750
|
+
const response = await fetch(`${this.baseURL}/auth/login`, {
|
|
751
|
+
method: "POST",
|
|
752
|
+
headers: {
|
|
753
|
+
"Content-Type": "application/json",
|
|
754
|
+
},
|
|
755
|
+
body: JSON.stringify({
|
|
756
|
+
user_auth: params.user_auth,
|
|
757
|
+
auth_jwt_type: params.auth_jwt_type,
|
|
758
|
+
auth_jwt: params.auth_jwt,
|
|
759
|
+
wallet_auth: params.wallet_auth,
|
|
760
|
+
}),
|
|
761
|
+
});
|
|
762
|
+
if (!response.ok) {
|
|
763
|
+
console.error("Password login failed:", response.status, response.statusText);
|
|
764
|
+
const errorData = await response.text();
|
|
765
|
+
console.error("Error response:", errorData);
|
|
766
|
+
return {
|
|
767
|
+
error: {
|
|
768
|
+
message: `HTTP error! status: ${response.status}`,
|
|
769
|
+
},
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
const data = await this.safeJsonParse(response);
|
|
773
|
+
return data;
|
|
774
|
+
}
|
|
775
|
+
catch (error) {
|
|
776
|
+
console.error("Login error:", error);
|
|
777
|
+
return {
|
|
778
|
+
error: {
|
|
779
|
+
message: error instanceof Error ? error.message : "Authentication failed",
|
|
780
|
+
},
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
async authLoginWithPassword(params) {
|
|
785
|
+
try {
|
|
786
|
+
const response = await fetch(`${this.baseURL}/auth/login-with-password`, {
|
|
787
|
+
method: "POST",
|
|
788
|
+
headers: {
|
|
789
|
+
"Content-Type": "application/json",
|
|
790
|
+
},
|
|
791
|
+
body: JSON.stringify({
|
|
792
|
+
user_auth: params.user_auth,
|
|
793
|
+
password: params.password,
|
|
794
|
+
}),
|
|
795
|
+
});
|
|
796
|
+
if (!response.ok) {
|
|
797
|
+
console.error("Password login failed:", response.status, response.statusText);
|
|
798
|
+
const errorData = await response.text();
|
|
799
|
+
console.error("Error response:", errorData);
|
|
800
|
+
return {
|
|
801
|
+
error: {
|
|
802
|
+
message: `HTTP error! status: ${response.status}`,
|
|
803
|
+
},
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
const data = await this.safeJsonParse(response);
|
|
807
|
+
return data;
|
|
808
|
+
}
|
|
809
|
+
catch (error) {
|
|
810
|
+
console.error("Password login error:", error);
|
|
811
|
+
return {
|
|
812
|
+
error: {
|
|
813
|
+
message: error instanceof Error
|
|
814
|
+
? error.message
|
|
815
|
+
: "Password authentication failed",
|
|
816
|
+
},
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
async networkCheck(params) {
|
|
821
|
+
try {
|
|
822
|
+
const response = await fetch(`${this.baseURL}/auth/network-check`, {
|
|
823
|
+
method: "POST",
|
|
824
|
+
headers: {
|
|
825
|
+
"Content-Type": "application/json",
|
|
826
|
+
},
|
|
827
|
+
body: JSON.stringify({
|
|
828
|
+
network_name: params.network_name,
|
|
829
|
+
}),
|
|
830
|
+
});
|
|
831
|
+
if (!response.ok) {
|
|
832
|
+
console.error("Network check failed:", response.status, response.statusText);
|
|
833
|
+
const errorData = await response.text();
|
|
834
|
+
console.error("Error response:", errorData);
|
|
835
|
+
return undefined;
|
|
836
|
+
}
|
|
837
|
+
return await this.safeJsonParse(response);
|
|
838
|
+
}
|
|
839
|
+
catch (error) {
|
|
840
|
+
console.error("Network check error:", error);
|
|
841
|
+
return undefined;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
async networkCreate(params) {
|
|
845
|
+
try {
|
|
846
|
+
if (!params.terms) {
|
|
847
|
+
return {
|
|
848
|
+
error: {
|
|
849
|
+
message: "Terms must be accepted to create a network.",
|
|
850
|
+
},
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
let requestParams = {
|
|
854
|
+
terms: params.terms,
|
|
855
|
+
guest_mode: false,
|
|
856
|
+
};
|
|
857
|
+
if (params.user_auth && params.password) {
|
|
858
|
+
requestParams.user_auth = params.user_auth;
|
|
859
|
+
requestParams.password = params.password;
|
|
860
|
+
}
|
|
861
|
+
if (params.auth_jwt && params.auth_jwt_type) {
|
|
862
|
+
requestParams.auth_jwt = params.auth_jwt;
|
|
863
|
+
requestParams.auth_jwt_type = params.auth_jwt_type;
|
|
864
|
+
}
|
|
865
|
+
if (params.wallet_auth) {
|
|
866
|
+
requestParams.wallet_auth = params.wallet_auth;
|
|
867
|
+
}
|
|
868
|
+
const response = await fetch(`${this.baseURL}/network/create`, {
|
|
869
|
+
method: "POST",
|
|
870
|
+
headers: {
|
|
871
|
+
"Content-Type": "application/json",
|
|
872
|
+
},
|
|
873
|
+
body: JSON.stringify(requestParams),
|
|
874
|
+
});
|
|
875
|
+
if (!response.ok) {
|
|
876
|
+
console.error("Network creation failed:", response.status, response.statusText);
|
|
877
|
+
const errorData = await response.text();
|
|
878
|
+
console.error("Error response:", errorData);
|
|
879
|
+
return {
|
|
880
|
+
error: {
|
|
881
|
+
message: `HTTP error! status: ${response.status}`,
|
|
882
|
+
},
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
const data = await this.safeJsonParse(response);
|
|
886
|
+
return data;
|
|
887
|
+
}
|
|
888
|
+
catch (error) {
|
|
889
|
+
console.error("Network creation error:", error);
|
|
890
|
+
return {
|
|
891
|
+
error: {
|
|
892
|
+
message: error instanceof Error ? error.message : "Network creation failed",
|
|
893
|
+
},
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
async authCodeLogin(params) {
|
|
898
|
+
try {
|
|
899
|
+
const response = await fetch(`${this.baseURL}/auth/code-login`, {
|
|
900
|
+
method: "POST",
|
|
901
|
+
headers: {
|
|
902
|
+
"Content-Type": "application/json",
|
|
903
|
+
},
|
|
904
|
+
body: JSON.stringify(params),
|
|
905
|
+
});
|
|
906
|
+
if (!response.ok) {
|
|
907
|
+
console.error("Auth code login failed:", response.status, response.statusText);
|
|
908
|
+
const errorData = await response.text();
|
|
909
|
+
console.error("Error response:", errorData);
|
|
910
|
+
return {
|
|
911
|
+
by_jwt: "",
|
|
912
|
+
error: {
|
|
913
|
+
message: errorData,
|
|
914
|
+
},
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
return await this.safeJsonParse(response);
|
|
918
|
+
}
|
|
919
|
+
catch (error) {
|
|
920
|
+
console.error("Network check error:", error);
|
|
921
|
+
return {
|
|
922
|
+
by_jwt: "",
|
|
923
|
+
error: {
|
|
924
|
+
message: error instanceof Error ? error.message : "Auth code login failed",
|
|
925
|
+
},
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
async networkProviderLocations() {
|
|
930
|
+
try {
|
|
931
|
+
const response = await fetchWithGetRetry(`${this.baseURL}/network/provider-locations`, {
|
|
932
|
+
method: "GET",
|
|
933
|
+
headers: {
|
|
934
|
+
"Content-Type": "application/json",
|
|
935
|
+
},
|
|
936
|
+
});
|
|
937
|
+
if (!response.ok) {
|
|
938
|
+
console.error("/network/provider-locations failed:", response.status, response.statusText);
|
|
939
|
+
const errorData = await response.text();
|
|
940
|
+
console.error("Error response:", errorData);
|
|
941
|
+
throw new Error(`Failed to fetch provider locations: ${response.status} ${response.statusText}`);
|
|
942
|
+
}
|
|
943
|
+
const data = await this.safeJsonParse(response);
|
|
944
|
+
return data;
|
|
945
|
+
}
|
|
946
|
+
catch (error) {
|
|
947
|
+
console.error("User auth verification error:", error);
|
|
948
|
+
throw error;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
async searchProviderLocations(params) {
|
|
952
|
+
try {
|
|
953
|
+
const response = await fetch(`${this.baseURL}/network/find-provider-locations`, {
|
|
954
|
+
method: "POST",
|
|
955
|
+
headers: {
|
|
956
|
+
"Content-Type": "application/json",
|
|
957
|
+
},
|
|
958
|
+
body: JSON.stringify(params),
|
|
959
|
+
});
|
|
960
|
+
if (!response.ok) {
|
|
961
|
+
console.error("network/find-provider-locations failed:", response.status, response.statusText);
|
|
962
|
+
const errorData = await response.text();
|
|
963
|
+
console.error("Error response:", errorData);
|
|
964
|
+
throw new Error(`Failed to search provider locations: ${response.status} ${response.statusText}`);
|
|
965
|
+
}
|
|
966
|
+
return await this.safeJsonParse(response);
|
|
967
|
+
}
|
|
968
|
+
catch (error) {
|
|
969
|
+
console.error("network/find-provider-locations error:", error);
|
|
970
|
+
throw error;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
async verifyUserAuth(params, adminToken) {
|
|
974
|
+
try {
|
|
975
|
+
const response = await fetch(`${this.baseURL}/auth/verify`, {
|
|
976
|
+
method: "POST",
|
|
977
|
+
headers: {
|
|
978
|
+
"Content-Type": "application/json",
|
|
979
|
+
Authorization: `Bearer ${adminToken}`,
|
|
980
|
+
},
|
|
981
|
+
body: JSON.stringify({
|
|
982
|
+
user_auth: params.user_auth,
|
|
983
|
+
verify_code: params.verify_code,
|
|
984
|
+
}),
|
|
985
|
+
});
|
|
986
|
+
if (!response.ok) {
|
|
987
|
+
console.error("User auth verification failed:", response.status, response.statusText);
|
|
988
|
+
const errorData = await response.text();
|
|
989
|
+
console.error("Error response:", errorData);
|
|
990
|
+
return {
|
|
991
|
+
error: {
|
|
992
|
+
message: `HTTP error! status: ${response.status}`,
|
|
993
|
+
},
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
const data = await this.safeJsonParse(response);
|
|
997
|
+
return data;
|
|
998
|
+
}
|
|
999
|
+
catch (error) {
|
|
1000
|
+
console.error("User auth verification error:", error);
|
|
1001
|
+
return {
|
|
1002
|
+
error: {
|
|
1003
|
+
message: error instanceof Error ? error.message : "Verification failed",
|
|
1004
|
+
},
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
async authNetworkClient(params, token, signal) {
|
|
1009
|
+
try {
|
|
1010
|
+
const response = await fetch(`${this.baseURL}/network/auth-client`, {
|
|
1011
|
+
method: "POST",
|
|
1012
|
+
headers: {
|
|
1013
|
+
"Content-Type": "application/json",
|
|
1014
|
+
Authorization: `Bearer ${token}`,
|
|
1015
|
+
},
|
|
1016
|
+
body: JSON.stringify(params),
|
|
1017
|
+
signal,
|
|
1018
|
+
});
|
|
1019
|
+
if (!response.ok) {
|
|
1020
|
+
console.error("Auth network client failed:", response.status, response.statusText);
|
|
1021
|
+
const errorData = await response.text();
|
|
1022
|
+
console.error("Error response:", errorData);
|
|
1023
|
+
return {
|
|
1024
|
+
proxy_config_result: null,
|
|
1025
|
+
error: {
|
|
1026
|
+
message: `HTTP error! status: ${response.status}`,
|
|
1027
|
+
client_limit_exceeded: false,
|
|
1028
|
+
},
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
return await this.safeJsonParse(response);
|
|
1032
|
+
}
|
|
1033
|
+
catch (error) {
|
|
1034
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1035
|
+
console.log("Auth network client request was cancelled");
|
|
1036
|
+
throw error;
|
|
1037
|
+
}
|
|
1038
|
+
console.error("Auth network client error:", error);
|
|
1039
|
+
return {
|
|
1040
|
+
proxy_config_result: null,
|
|
1041
|
+
error: {
|
|
1042
|
+
message: error instanceof Error
|
|
1043
|
+
? error.message
|
|
1044
|
+
: "Auth network client failed",
|
|
1045
|
+
client_limit_exceeded: false,
|
|
1046
|
+
},
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
async removeNetworkClient(params, token) {
|
|
1051
|
+
try {
|
|
1052
|
+
const response = await fetch(`${this.baseURL}/network/remove-client`, {
|
|
1053
|
+
method: "POST",
|
|
1054
|
+
headers: {
|
|
1055
|
+
"Content-Type": "application/json",
|
|
1056
|
+
Authorization: `Bearer ${token}`,
|
|
1057
|
+
},
|
|
1058
|
+
body: JSON.stringify(params),
|
|
1059
|
+
});
|
|
1060
|
+
if (!response.ok) {
|
|
1061
|
+
console.error("Network removed client failed failed:", response.status, response.statusText);
|
|
1062
|
+
const errorData = await response.text();
|
|
1063
|
+
console.error("Error response:", errorData);
|
|
1064
|
+
return {
|
|
1065
|
+
error: {
|
|
1066
|
+
message: `HTTP error! status: ${response.status}`,
|
|
1067
|
+
},
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
const data = await this.safeJsonParse(response);
|
|
1071
|
+
return data;
|
|
1072
|
+
}
|
|
1073
|
+
catch (error) {
|
|
1074
|
+
console.error("Remove network client error:", error);
|
|
1075
|
+
return {
|
|
1076
|
+
error: {
|
|
1077
|
+
message: error instanceof Error
|
|
1078
|
+
? error.message
|
|
1079
|
+
: "Remove network client failed",
|
|
1080
|
+
},
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
async createApiKey(params, token) {
|
|
1085
|
+
try {
|
|
1086
|
+
const response = await fetch(`${this.baseURL}/account/api-key`, {
|
|
1087
|
+
method: "POST",
|
|
1088
|
+
headers: {
|
|
1089
|
+
"Content-Type": "application/json",
|
|
1090
|
+
Authorization: `Bearer ${token}`,
|
|
1091
|
+
},
|
|
1092
|
+
body: JSON.stringify(params),
|
|
1093
|
+
});
|
|
1094
|
+
if (!response.ok) {
|
|
1095
|
+
console.error("Create API key failed:", response.status, response.statusText);
|
|
1096
|
+
const errorData = await response.text();
|
|
1097
|
+
console.error("Error response:", errorData);
|
|
1098
|
+
return {
|
|
1099
|
+
error: {
|
|
1100
|
+
message: `HTTP error! status: ${response.status}`,
|
|
1101
|
+
},
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
return await this.safeJsonParse(response);
|
|
1105
|
+
}
|
|
1106
|
+
catch (error) {
|
|
1107
|
+
console.error("Create API key error:", error);
|
|
1108
|
+
return {
|
|
1109
|
+
error: {
|
|
1110
|
+
message: error instanceof Error ? error.message : "Create API key failed",
|
|
1111
|
+
},
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
async listApiKeys(token) {
|
|
1116
|
+
try {
|
|
1117
|
+
const response = await fetchWithGetRetry(`${this.baseURL}/account/api-keys`, {
|
|
1118
|
+
method: "GET",
|
|
1119
|
+
headers: {
|
|
1120
|
+
"Content-Type": "application/json",
|
|
1121
|
+
Authorization: `Bearer ${token}`,
|
|
1122
|
+
},
|
|
1123
|
+
});
|
|
1124
|
+
if (!response.ok) {
|
|
1125
|
+
console.error("List API keys failed:", response.status, response.statusText);
|
|
1126
|
+
const errorData = await response.text();
|
|
1127
|
+
console.error("Error response:", errorData);
|
|
1128
|
+
return {
|
|
1129
|
+
error: {
|
|
1130
|
+
message: `HTTP error! status: ${response.status}`,
|
|
1131
|
+
},
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
const data = await this.safeJsonParse(response);
|
|
1135
|
+
return data;
|
|
1136
|
+
}
|
|
1137
|
+
catch (error) {
|
|
1138
|
+
console.error("List API keys error:", error);
|
|
1139
|
+
return {
|
|
1140
|
+
error: {
|
|
1141
|
+
message: error instanceof Error ? error.message : "List API keys failed",
|
|
1142
|
+
},
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
async deleteApiKey(params, token) {
|
|
1147
|
+
try {
|
|
1148
|
+
const response = await fetch(`${this.baseURL}/account/api-key/remove`, {
|
|
1149
|
+
method: "POST",
|
|
1150
|
+
headers: {
|
|
1151
|
+
"Content-Type": "application/json",
|
|
1152
|
+
Authorization: `Bearer ${token}`,
|
|
1153
|
+
},
|
|
1154
|
+
body: JSON.stringify(params),
|
|
1155
|
+
});
|
|
1156
|
+
if (!response.ok) {
|
|
1157
|
+
console.error("Delete API key failed:", response.status, response.statusText);
|
|
1158
|
+
const errorData = await response.text();
|
|
1159
|
+
console.error("Error response:", errorData);
|
|
1160
|
+
return {
|
|
1161
|
+
error: {
|
|
1162
|
+
message: `HTTP error! status: ${response.status}`,
|
|
1163
|
+
},
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
1166
|
+
return await this.safeJsonParse(response);
|
|
1167
|
+
}
|
|
1168
|
+
catch (error) {
|
|
1169
|
+
console.error("Delete API key error:", error);
|
|
1170
|
+
return {
|
|
1171
|
+
error: {
|
|
1172
|
+
message: error instanceof Error ? error.message : "Delete API key failed",
|
|
1173
|
+
},
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
function parseByJwtClientId(byJwt) {
|
|
1180
|
+
try {
|
|
1181
|
+
const parts = byJwt.split(".");
|
|
1182
|
+
if (parts.length !== 3) {
|
|
1183
|
+
throw new Error("Invalid JWT format: expected 3 parts separated by dots");
|
|
1184
|
+
}
|
|
1185
|
+
const payload = parts[1];
|
|
1186
|
+
const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
1187
|
+
const jsonPayload = decodeURIComponent(atob(base64)
|
|
1188
|
+
.split("")
|
|
1189
|
+
.map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
|
|
1190
|
+
.join(""));
|
|
1191
|
+
const claims = JSON.parse(jsonPayload);
|
|
1192
|
+
if (!claims.client_id) {
|
|
1193
|
+
throw new Error("byJwt does not contain claim client_id");
|
|
1194
|
+
}
|
|
1195
|
+
if (typeof claims.client_id !== "string") {
|
|
1196
|
+
throw new Error(`byJwt have invalid type for client_id: ${typeof claims.client_id}`);
|
|
1197
|
+
}
|
|
1198
|
+
if (!isValidUUID(claims.client_id)) {
|
|
1199
|
+
throw new Error(`client_id is not a valid UUID: ${claims.client_id}`);
|
|
1200
|
+
}
|
|
1201
|
+
return claims.client_id;
|
|
1202
|
+
}
|
|
1203
|
+
catch (error) {
|
|
1204
|
+
if (error instanceof Error) {
|
|
1205
|
+
throw error;
|
|
1206
|
+
}
|
|
1207
|
+
throw new Error(`Failed to parse JWT: ${String(error)}`);
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
function isValidUUID(str) {
|
|
1211
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1212
|
+
return uuidRegex.test(str);
|
|
1213
|
+
}
|
|
1214
|
+
function parseJWTClaims(jwt) {
|
|
1215
|
+
try {
|
|
1216
|
+
const parts = jwt.split(".");
|
|
1217
|
+
if (parts.length !== 3) {
|
|
1218
|
+
throw new Error("Invalid JWT format: expected 3 parts separated by dots");
|
|
1219
|
+
}
|
|
1220
|
+
const payload = parts[1];
|
|
1221
|
+
const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
1222
|
+
const jsonPayload = decodeURIComponent(atob(base64)
|
|
1223
|
+
.split("")
|
|
1224
|
+
.map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
|
|
1225
|
+
.join(""));
|
|
1226
|
+
return JSON.parse(jsonPayload);
|
|
1227
|
+
}
|
|
1228
|
+
catch (error) {
|
|
1229
|
+
if (error instanceof Error) {
|
|
1230
|
+
throw error;
|
|
1231
|
+
}
|
|
1232
|
+
throw new Error(`Failed to parse JWT: ${String(error)}`);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
const SOLANA_PAY_REFERENCE_BYTES = 32;
|
|
1237
|
+
const B58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
1238
|
+
function encodeBase58(bytes) {
|
|
1239
|
+
if (bytes.length === 0)
|
|
1240
|
+
return "";
|
|
1241
|
+
const digits = [0];
|
|
1242
|
+
for (const byte of bytes) {
|
|
1243
|
+
let carry = byte;
|
|
1244
|
+
for (let i = 0; i < digits.length; i++) {
|
|
1245
|
+
carry += digits[i] << 8;
|
|
1246
|
+
digits[i] = carry % 58;
|
|
1247
|
+
carry = (carry / 58) | 0;
|
|
1248
|
+
}
|
|
1249
|
+
while (carry > 0) {
|
|
1250
|
+
digits.push(carry % 58);
|
|
1251
|
+
carry = (carry / 58) | 0;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
while (digits.length > 0 && digits[digits.length - 1] === 0)
|
|
1255
|
+
digits.pop();
|
|
1256
|
+
let out = "";
|
|
1257
|
+
for (let i = 0; i < bytes.length && bytes[i] === 0; i++)
|
|
1258
|
+
out += B58_ALPHABET[0];
|
|
1259
|
+
for (let i = digits.length - 1; i >= 0; i--)
|
|
1260
|
+
out += B58_ALPHABET[digits[i]];
|
|
1261
|
+
return out;
|
|
1262
|
+
}
|
|
1263
|
+
function decodeBase58(s) {
|
|
1264
|
+
if (s.length === 0)
|
|
1265
|
+
return new Uint8Array(0);
|
|
1266
|
+
const bytes = [0];
|
|
1267
|
+
for (const ch of s) {
|
|
1268
|
+
const value = B58_ALPHABET.indexOf(ch);
|
|
1269
|
+
if (value < 0)
|
|
1270
|
+
return null;
|
|
1271
|
+
let carry = value;
|
|
1272
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1273
|
+
carry += bytes[i] * 58;
|
|
1274
|
+
bytes[i] = carry & 0xff;
|
|
1275
|
+
carry >>= 8;
|
|
1276
|
+
}
|
|
1277
|
+
while (carry > 0) {
|
|
1278
|
+
bytes.push(carry & 0xff);
|
|
1279
|
+
carry >>= 8;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
while (bytes.length > 0 && bytes[bytes.length - 1] === 0)
|
|
1283
|
+
bytes.pop();
|
|
1284
|
+
let leadingZeros = 0;
|
|
1285
|
+
for (let i = 0; i < s.length && s[i] === B58_ALPHABET[0]; i++)
|
|
1286
|
+
leadingZeros++;
|
|
1287
|
+
const out = new Uint8Array(leadingZeros + bytes.length);
|
|
1288
|
+
for (let i = 0; i < bytes.length; i++)
|
|
1289
|
+
out[leadingZeros + i] = bytes[bytes.length - 1 - i];
|
|
1290
|
+
return out;
|
|
1291
|
+
}
|
|
1292
|
+
function createPaymentReference() {
|
|
1293
|
+
const bytes = new Uint8Array(SOLANA_PAY_REFERENCE_BYTES);
|
|
1294
|
+
crypto.getRandomValues(bytes);
|
|
1295
|
+
return encodeBase58(bytes);
|
|
1296
|
+
}
|
|
1297
|
+
function isValidPaymentReference(s) {
|
|
1298
|
+
if (!s)
|
|
1299
|
+
return false;
|
|
1300
|
+
const decoded = decodeBase58(s);
|
|
1301
|
+
return decoded !== null && decoded.length === SOLANA_PAY_REFERENCE_BYTES;
|
|
1302
|
+
}
|
|
1303
|
+
function isBase58Address(s) {
|
|
1304
|
+
if (!s)
|
|
1305
|
+
return false;
|
|
1306
|
+
const decoded = decodeBase58(s);
|
|
1307
|
+
return decoded !== null && decoded.length === SOLANA_PAY_REFERENCE_BYTES;
|
|
1308
|
+
}
|
|
1309
|
+
function buildSolanaPaymentUrl(args) {
|
|
1310
|
+
if (!args)
|
|
1311
|
+
throw new Error("solana pay: no arguments");
|
|
1312
|
+
if (!isBase58Address(args.recipient)) {
|
|
1313
|
+
throw new Error("solana pay: recipient is not a base58 address");
|
|
1314
|
+
}
|
|
1315
|
+
if (!isBase58Address(args.splTokenMint)) {
|
|
1316
|
+
throw new Error("solana pay: spl token mint is not a base58 address");
|
|
1317
|
+
}
|
|
1318
|
+
if (!isValidPaymentReference(args.reference)) {
|
|
1319
|
+
throw new Error(`solana pay: reference must be base58 that decodes to ${SOLANA_PAY_REFERENCE_BYTES} bytes`);
|
|
1320
|
+
}
|
|
1321
|
+
if (!Number.isFinite(args.amountUsd) || args.amountUsd <= 0) {
|
|
1322
|
+
throw new Error(`solana pay: amount must be positive, got ${args.amountUsd}`);
|
|
1323
|
+
}
|
|
1324
|
+
const params = new URLSearchParams({
|
|
1325
|
+
amount: formatAmount(args.amountUsd),
|
|
1326
|
+
"spl-token": args.splTokenMint,
|
|
1327
|
+
reference: args.reference,
|
|
1328
|
+
});
|
|
1329
|
+
if (args.label)
|
|
1330
|
+
params.set("label", args.label);
|
|
1331
|
+
if (args.message)
|
|
1332
|
+
params.set("message", args.message);
|
|
1333
|
+
if (args.memo)
|
|
1334
|
+
params.set("memo", args.memo);
|
|
1335
|
+
return `solana:${args.recipient}?${params.toString()}`;
|
|
1336
|
+
}
|
|
1337
|
+
function formatAmount(n) {
|
|
1338
|
+
const s = String(n);
|
|
1339
|
+
if (!/[eE]/.test(s))
|
|
1340
|
+
return s;
|
|
1341
|
+
const [mantissa, expPart] = s.split(/[eE]/);
|
|
1342
|
+
const exp = parseInt(expPart, 10);
|
|
1343
|
+
const negative = mantissa.startsWith("-");
|
|
1344
|
+
const unsigned = negative ? mantissa.slice(1) : mantissa;
|
|
1345
|
+
const dot = unsigned.indexOf(".");
|
|
1346
|
+
const digits = unsigned.replace(".", "");
|
|
1347
|
+
const pointPos = (dot < 0 ? unsigned.length : dot) + exp;
|
|
1348
|
+
let out;
|
|
1349
|
+
if (pointPos <= 0) {
|
|
1350
|
+
out = "0." + "0".repeat(-pointPos) + digits;
|
|
1351
|
+
}
|
|
1352
|
+
else if (pointPos >= digits.length) {
|
|
1353
|
+
out = digits + "0".repeat(pointPos - digits.length);
|
|
1354
|
+
}
|
|
1355
|
+
else {
|
|
1356
|
+
out = digits.slice(0, pointPos) + "." + digits.slice(pointPos);
|
|
1357
|
+
}
|
|
1358
|
+
return (negative ? "-" : "") + out;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
class URNetwork {
|
|
1362
|
+
constructor() { }
|
|
1363
|
+
static async init(options = {}) {
|
|
1364
|
+
if (URNetwork.instance) {
|
|
1365
|
+
return URNetwork.instance;
|
|
1366
|
+
}
|
|
1367
|
+
await initWasm(options);
|
|
1368
|
+
const instance = new URNetwork();
|
|
1369
|
+
URNetwork.instance = instance;
|
|
1370
|
+
return instance;
|
|
1371
|
+
}
|
|
1372
|
+
static getInstance() {
|
|
1373
|
+
if (!URNetwork.instance) {
|
|
1374
|
+
throw new Error("SDK not initialized. Call URNetwork.init() first.");
|
|
1375
|
+
}
|
|
1376
|
+
return URNetwork.instance;
|
|
1377
|
+
}
|
|
1378
|
+
createProxyDevice(config, setupCallback) {
|
|
1379
|
+
const { URnetworkNewProxyDeviceWithDefaults } = getWasmGlobals();
|
|
1380
|
+
const proxy = URnetworkNewProxyDeviceWithDefaults(config, setupCallback
|
|
1381
|
+
? (device, result) => setupCallback(attachSocketAPI(device), result)
|
|
1382
|
+
: undefined);
|
|
1383
|
+
const getDevice = proxy.getDevice.bind(proxy);
|
|
1384
|
+
proxy.getDevice = () => attachSocketAPI(getDevice());
|
|
1385
|
+
return proxy;
|
|
1386
|
+
}
|
|
1387
|
+
createPlatformDeviceRemote(options) {
|
|
1388
|
+
const { URnetworkNewPlatformDeviceRemote } = getWasmGlobals();
|
|
1389
|
+
if (typeof URnetworkNewPlatformDeviceRemote !== "function") {
|
|
1390
|
+
throw new Error("URnetworkNewPlatformDeviceRemote is not exported by the loaded wasm. Rebuild the sdk wasm.");
|
|
1391
|
+
}
|
|
1392
|
+
const device = URnetworkNewPlatformDeviceRemote(options.apiUrl, options.platformUrl, options.byJwt, options.proxyUrl, options.signedProxyId, options.instanceId);
|
|
1393
|
+
if (!device) {
|
|
1394
|
+
throw new Error("Could not create the device remote.");
|
|
1395
|
+
}
|
|
1396
|
+
if (device.error) {
|
|
1397
|
+
throw new Error(String(device.error));
|
|
1398
|
+
}
|
|
1399
|
+
return attachSubprotocolAPI(attachSocketAPI(device));
|
|
1400
|
+
}
|
|
1401
|
+
createLocationsViewController(options) {
|
|
1402
|
+
const { URnetworkNewLocationsViewController } = getWasmGlobals();
|
|
1403
|
+
if (typeof URnetworkNewLocationsViewController !== "function") {
|
|
1404
|
+
throw new Error("URnetworkNewLocationsViewController is not exported by the loaded wasm. Rebuild the sdk wasm.");
|
|
1405
|
+
}
|
|
1406
|
+
const vc = URnetworkNewLocationsViewController(options.apiUrl, options.platformUrl, options.byJwt);
|
|
1407
|
+
if (!vc) {
|
|
1408
|
+
throw new Error("Could not open the locations view controller.");
|
|
1409
|
+
}
|
|
1410
|
+
if (vc.error) {
|
|
1411
|
+
throw new Error(String(vc.error));
|
|
1412
|
+
}
|
|
1413
|
+
return vc;
|
|
1414
|
+
}
|
|
1415
|
+
createAccountHost(options) {
|
|
1416
|
+
const { URnetworkNewAccountHost } = getWasmGlobals();
|
|
1417
|
+
if (typeof URnetworkNewAccountHost !== "function") {
|
|
1418
|
+
throw new Error("URnetworkNewAccountHost is not exported by the loaded wasm. Rebuild the sdk wasm.");
|
|
1419
|
+
}
|
|
1420
|
+
const host = URnetworkNewAccountHost(options.apiUrl, options.platformUrl, options.byJwt);
|
|
1421
|
+
if (!host) {
|
|
1422
|
+
throw new Error("Could not open the account host.");
|
|
1423
|
+
}
|
|
1424
|
+
if (host.error) {
|
|
1425
|
+
throw new Error(String(host.error));
|
|
1426
|
+
}
|
|
1427
|
+
return host;
|
|
1428
|
+
}
|
|
1429
|
+
colorHex(code) {
|
|
1430
|
+
const { URnetworkColorHex } = getWasmGlobals();
|
|
1431
|
+
if (typeof URnetworkColorHex !== "function") {
|
|
1432
|
+
return "";
|
|
1433
|
+
}
|
|
1434
|
+
return String(URnetworkColorHex(code) || "");
|
|
1435
|
+
}
|
|
1436
|
+
createExtensionDeviceRemote(options) {
|
|
1437
|
+
const { URnetworkNewExtensionDeviceRemote } = getWasmGlobals();
|
|
1438
|
+
if (typeof URnetworkNewExtensionDeviceRemote !== "function") {
|
|
1439
|
+
throw new Error("URnetworkNewExtensionDeviceRemote is not exported by the loaded wasm. Rebuild the sdk wasm.");
|
|
1440
|
+
}
|
|
1441
|
+
const device = URnetworkNewExtensionDeviceRemote(options.apiUrl, options.platformUrl, options.byJwt, options.instanceId, options.transport);
|
|
1442
|
+
if (!device) {
|
|
1443
|
+
throw new Error("Could not create the extension device remote.");
|
|
1444
|
+
}
|
|
1445
|
+
if (device.error) {
|
|
1446
|
+
throw new Error(String(device.error));
|
|
1447
|
+
}
|
|
1448
|
+
return attachSubprotocolAPI(attachSocketAPI(device));
|
|
1449
|
+
}
|
|
1450
|
+
close() {
|
|
1451
|
+
const { URnetworkClose } = getWasmGlobals();
|
|
1452
|
+
URnetworkClose();
|
|
1453
|
+
URNetwork.instance = null;
|
|
1454
|
+
}
|
|
1455
|
+
isInitialized() {
|
|
1456
|
+
return isWasmInitialized();
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
URNetwork.instance = null;
|
|
1460
|
+
|
|
1461
|
+
export { Conn, PointsLeaderboardTier, SOLANA_PAY_REFERENCE_BYTES, SubprotocolSubscription, URNetwork, URNetworkAPI, attachSocketAPI, attachSubprotocolAPI, buildSolanaPaymentUrl, createDirectSockets, createPaymentReference, decodeBase58, URNetwork as default, encodeBase58, isBase58Address, isValidPaymentReference, parseByJwtClientId, parseJWTClaims };
|
|
1462
|
+
//# sourceMappingURL=index.js.map
|