@fivenorth/loop-sdk 0.3.0 → 0.4.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/README.md +7 -0
- package/dist/index.js +51 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,6 +42,10 @@ Before you can connect, you need to initialize the SDK. This is typically done o
|
|
|
42
42
|
loop.init({
|
|
43
43
|
appName: 'My Awesome dApp',
|
|
44
44
|
network: 'local', // or 'devnet', 'mainnet'
|
|
45
|
+
options: {
|
|
46
|
+
openMode: 'popup', // 'popup' (default) or 'tab'
|
|
47
|
+
redirectUrl: 'https://myapp.com/after-connect', // optional redirect after approval
|
|
48
|
+
},
|
|
45
49
|
onAccept: (provider) => {
|
|
46
50
|
console.log('Connected!', provider);
|
|
47
51
|
// You can now use the provider to interact with the wallet
|
|
@@ -55,6 +59,9 @@ loop.init({
|
|
|
55
59
|
The `init` method takes a configuration object with the following properties:
|
|
56
60
|
- `appName`: The name of your application, which will be displayed to the user in the Loop wallet.
|
|
57
61
|
- `network`: The network to connect to. Can be `local`, `devnet`, or `mainnet`.
|
|
62
|
+
- `options`: Optional object containing:
|
|
63
|
+
- `openMode`: Controls how Loop opens: `'popup'` (default) or `'tab'`.
|
|
64
|
+
- `redirectUrl`: Optional redirect URL the wallet will navigate back to after successful approval. If omitted, user stays on Loop dashboard.
|
|
58
65
|
- `onAccept`: A callback function that is called when the user accepts the connection. It receives a `provider` object.
|
|
59
66
|
- `onReject`: A callback function that is called when the user rejects the connection.
|
|
60
67
|
|
package/dist/index.js
CHANGED
|
@@ -2165,13 +2165,15 @@ class Connection {
|
|
|
2165
2165
|
throw new Error("Session verification failed.");
|
|
2166
2166
|
}
|
|
2167
2167
|
const data = await response.json();
|
|
2168
|
+
const email = data?.email;
|
|
2168
2169
|
if (!data?.party_id || !data?.public_key) {
|
|
2169
2170
|
throw new Error("Invalid session verification response.");
|
|
2170
2171
|
}
|
|
2171
2172
|
const account = {
|
|
2172
2173
|
party_id: data?.party_id,
|
|
2173
2174
|
auth_token: authToken,
|
|
2174
|
-
public_key: data?.public_key
|
|
2175
|
+
public_key: data?.public_key,
|
|
2176
|
+
email
|
|
2175
2177
|
};
|
|
2176
2178
|
return account;
|
|
2177
2179
|
}
|
|
@@ -2205,8 +2207,25 @@ class RejectRequestError extends Error {
|
|
|
2205
2207
|
}
|
|
2206
2208
|
|
|
2207
2209
|
// src/provider.ts
|
|
2210
|
+
function generateUUID() {
|
|
2211
|
+
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => {
|
|
2212
|
+
const gCrypto = globalThis.crypto;
|
|
2213
|
+
if (!gCrypto?.getRandomValues) {
|
|
2214
|
+
const n2 = Number(c);
|
|
2215
|
+
return (n2 ^ Math.random() * 16 >> n2 / 4).toString(16);
|
|
2216
|
+
}
|
|
2217
|
+
const arr = gCrypto.getRandomValues(new Uint8Array(1));
|
|
2218
|
+
const byte = arr[0];
|
|
2219
|
+
const n = Number(c);
|
|
2220
|
+
return (n ^ (byte & 15) >> n / 4).toString(16);
|
|
2221
|
+
});
|
|
2222
|
+
}
|
|
2208
2223
|
function generateRequestId() {
|
|
2209
|
-
|
|
2224
|
+
const gCrypto = globalThis.crypto;
|
|
2225
|
+
if (gCrypto?.randomUUID) {
|
|
2226
|
+
return gCrypto.randomUUID();
|
|
2227
|
+
}
|
|
2228
|
+
return generateUUID();
|
|
2210
2229
|
}
|
|
2211
2230
|
|
|
2212
2231
|
class Provider {
|
|
@@ -2290,16 +2309,31 @@ class LoopSDK {
|
|
|
2290
2309
|
provider = null;
|
|
2291
2310
|
openMode = "popup";
|
|
2292
2311
|
popupWindow = null;
|
|
2312
|
+
redirectUrl;
|
|
2293
2313
|
onAccept = null;
|
|
2294
2314
|
onReject = null;
|
|
2295
2315
|
overlay = null;
|
|
2296
2316
|
ticketId = null;
|
|
2297
2317
|
constructor() {}
|
|
2298
|
-
init({
|
|
2318
|
+
init({
|
|
2319
|
+
appName,
|
|
2320
|
+
network,
|
|
2321
|
+
walletUrl,
|
|
2322
|
+
apiUrl,
|
|
2323
|
+
onAccept,
|
|
2324
|
+
onReject,
|
|
2325
|
+
options
|
|
2326
|
+
}) {
|
|
2299
2327
|
this.appName = appName;
|
|
2300
2328
|
this.onAccept = onAccept || null;
|
|
2301
2329
|
this.onReject = onReject || null;
|
|
2302
|
-
|
|
2330
|
+
const resolvedOptions = {
|
|
2331
|
+
openMode: "popup",
|
|
2332
|
+
redirectUrl: undefined,
|
|
2333
|
+
...options ?? {}
|
|
2334
|
+
};
|
|
2335
|
+
this.openMode = resolvedOptions.openMode;
|
|
2336
|
+
this.redirectUrl = resolvedOptions.redirectUrl;
|
|
2303
2337
|
this.connection = new Connection({ network, walletUrl, apiUrl });
|
|
2304
2338
|
}
|
|
2305
2339
|
async connect() {
|
|
@@ -2338,7 +2372,12 @@ class LoopSDK {
|
|
|
2338
2372
|
}
|
|
2339
2373
|
if (ticketId && canReuseTicket) {
|
|
2340
2374
|
this.ticketId = ticketId;
|
|
2341
|
-
const
|
|
2375
|
+
const url = new URL("/.connect/", this.connection.walletUrl);
|
|
2376
|
+
url.searchParams.set("ticketId", ticketId);
|
|
2377
|
+
if (this.redirectUrl) {
|
|
2378
|
+
url.searchParams.set("redirectUrl", this.redirectUrl);
|
|
2379
|
+
}
|
|
2380
|
+
const connectUrl = url.toString();
|
|
2342
2381
|
this.showQrCode(connectUrl);
|
|
2343
2382
|
this.connection.connectWebSocket(ticketId, this.handleWebSocketMessage.bind(this));
|
|
2344
2383
|
return;
|
|
@@ -2353,7 +2392,12 @@ class LoopSDK {
|
|
|
2353
2392
|
const { ticket_id: ticketId } = await this.connection.getTicket(this.appName, sessionId, this.version);
|
|
2354
2393
|
this.ticketId = ticketId;
|
|
2355
2394
|
localStorage.setItem("loop_connect", JSON.stringify({ sessionId, ticketId }));
|
|
2356
|
-
const
|
|
2395
|
+
const url = new URL("/.connect/", this.connection.walletUrl);
|
|
2396
|
+
url.searchParams.set("ticketId", ticketId);
|
|
2397
|
+
if (this.redirectUrl) {
|
|
2398
|
+
url.searchParams.set("redirectUrl", this.redirectUrl);
|
|
2399
|
+
}
|
|
2400
|
+
const connectUrl = url.toString();
|
|
2357
2401
|
this.showQrCode(connectUrl);
|
|
2358
2402
|
this.connection.connectWebSocket(ticketId, this.handleWebSocketMessage.bind(this));
|
|
2359
2403
|
} catch (error) {
|
|
@@ -2382,9 +2426,6 @@ class LoopSDK {
|
|
|
2382
2426
|
this.hideQrCode();
|
|
2383
2427
|
this.connection?.connectWebSocket(connectionInfo.ticketId, this.handleWebSocketMessage.bind(this));
|
|
2384
2428
|
console.log("[LoopSDK] HANDSHAKE_ACCEPT: closing popup (if exists)");
|
|
2385
|
-
if (this.popupWindow && !this.popupWindow.closed) {
|
|
2386
|
-
this.popupWindow.close();
|
|
2387
|
-
}
|
|
2388
2429
|
this.popupWindow = null;
|
|
2389
2430
|
} catch (error) {
|
|
2390
2431
|
console.error("Failed to update local storage with auth token.", error);
|
|
@@ -2444,7 +2485,7 @@ class LoopSDK {
|
|
|
2444
2485
|
overlay.style.left = "0";
|
|
2445
2486
|
overlay.style.width = "100%";
|
|
2446
2487
|
overlay.style.height = "100%";
|
|
2447
|
-
overlay.style.backgroundColor = "rgba(0,0,0,0.
|
|
2488
|
+
overlay.style.backgroundColor = "rgba(0,0,0,0.9)";
|
|
2448
2489
|
overlay.style.display = "flex";
|
|
2449
2490
|
overlay.style.justifyContent = "center";
|
|
2450
2491
|
overlay.style.alignItems = "center";
|