@fivenorth/loop-sdk 0.7.6 → 0.9.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.
Files changed (3) hide show
  1. package/README.md +24 -1
  2. package/dist/index.js +18 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -29,7 +29,7 @@ import { loop } from '@fivenorth/loop-sdk';
29
29
  Note that, If you don't want to implement a build process, you can include the file directly with `unpkg` such as
30
30
 
31
31
  ```javascript
32
- import { loop } from 'https://unpkg.com/@fivenorth/loop-sdk@0.1.1/dist';
32
+ import { loop } from 'https://unpkg.com/@fivenorth/loop-sdk@0.8.0/dist';
33
33
  ```
34
34
 
35
35
  An example of how we use it in that manner is on our [loopsdk demo](https://codepen.io/kureikain/pen/KwVGgLX)
@@ -42,6 +42,9 @@ 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
+ onTransactionUpdate: (payload) => {
46
+ console.log('Transaction update:', payload);
47
+ },
45
48
  options: {
46
49
  openMode: 'popup', // 'popup' (default) or 'tab'
47
50
  requestSigningMode: 'popup', // 'popup' (default) or 'tab'
@@ -60,6 +63,7 @@ loop.init({
60
63
  The `init` method takes a configuration object with the following properties:
61
64
  - `appName`: The name of your application, which will be displayed to the user in the Loop wallet.
62
65
  - `network`: The network to connect to. Can be `local`, `devnet`, or `mainnet`.
66
+ - `onTransactionUpdate`: Called when a transaction update is finalized (includes `update_id` and optional `update_data`).
63
67
  - `options`: Optional object containing:
64
68
  - `openMode`: Controls how Loop opens: `'popup'` (default) or `'tab'`.
65
69
  - `requestSigningMode`: Controls how signing/transaction requests open the wallet UI after you're connected: `'popup'` (default) or `'tab'`.
@@ -145,6 +149,24 @@ try {
145
149
  }
146
150
  ```
147
151
 
152
+ `onTransactionUpdate` fires once per transaction with a single payload that includes `command_id` and `submission_id`. On success it also includes `update_id` and `update_data` (ledger transaction tree); on failure it includes `status: "failed"` and `error.error_message`.
153
+
154
+ `submitTransaction` is the default async path. It returns the submission result first (including `command_id` and `submission_id`), then the ledger update arrives later via `onTransactionUpdate` with `update_id` and `update_data`.
155
+
156
+ To wait for the transaction result directly (opt-in), use:
157
+
158
+ ```javascript
159
+ await provider.submitAndWaitForTransaction(damlCommand, {
160
+ message: 'Transfer 10 CC to RetailStore',
161
+ });
162
+ ```
163
+
164
+ In wait mode, the final result is returned as a single `onTransactionUpdate` payload (command/submission IDs plus update data or failure status).
165
+
166
+ Note: `submitAndWaitForTransaction` errors do not always mean the transaction failed. A 4xx error (e.g., 400) indicates a definite failure. A 5xx/timeout can mean the ledger is slow or backed up; the transaction may still be committed later, so clients should continue to listen for updates rather than assume failure.
167
+
168
+ Deduplication: both async execute and execute-and-wait use a 1 hour deduplication window. If you retry within that window, resubmit the same `command_id` and `submission_id` so the request is idempotent.
169
+
148
170
  #### Sign a Message
149
171
 
150
172
  You can request the user to sign an arbitrary message:
@@ -173,6 +195,7 @@ await loop.wallet.transfer(
173
195
  {
174
196
  // Optional: show a custom message in the wallet prompt
175
197
  message: 'Send 5 CC to Alice',
198
+ executionMode: 'wait', // optional: 'async' (default) or 'wait'
176
199
  requestedAt: new Date().toISOString(), // optional
177
200
  executeBefore: new Date(Date.now() + 24*60*60*1000).toISOString(), // optional
178
201
  requestTimeout: 5 * 60 * 1000, // optional (ms), defaults to 5 minutes
package/dist/index.js CHANGED
@@ -2321,7 +2321,7 @@ var MessageType;
2321
2321
  MessageType2["HANDSHAKE_ACCEPT"] = "handshake_accept";
2322
2322
  MessageType2["HANDSHAKE_REJECT"] = "handshake_reject";
2323
2323
  MessageType2["RUN_TRANSACTION"] = "run_transaction";
2324
- MessageType2["RUN_TRANSACTION_RESPONSE"] = "run_transaction_response";
2324
+ MessageType2["TRANSACTION_COMPLETED"] = "transaction_completed";
2325
2325
  MessageType2["SIGN_RAW_MESSAGE"] = "sign_raw_message";
2326
2326
  MessageType2["SIGN_RAW_MESSAGE_RESPONSE"] = "sign_raw_message_response";
2327
2327
  MessageType2["REJECT_REQUEST"] = "reject_request";
@@ -2375,6 +2375,13 @@ class Provider {
2375
2375
  }
2376
2376
  handleResponse(message) {
2377
2377
  console.log("Received response:", message);
2378
+ if (message?.type === "transaction_completed" /* TRANSACTION_COMPLETED */ && (message?.payload?.update_id || message?.payload?.update_data || message?.payload?.status)) {
2379
+ if (message?.payload?.error_message) {
2380
+ message.payload.error = { error_message: message.payload.error_message };
2381
+ delete message.payload.error_message;
2382
+ }
2383
+ this.hooks?.onTransactionUpdate?.(message.payload, message);
2384
+ }
2378
2385
  if (message.request_id) {
2379
2386
  this.requests.set(message.request_id, message);
2380
2387
  }
@@ -2391,6 +2398,9 @@ class Provider {
2391
2398
  async submitTransaction(payload, options) {
2392
2399
  return this.sendRequest("run_transaction" /* RUN_TRANSACTION */, payload, options);
2393
2400
  }
2401
+ async submitAndWaitForTransaction(payload, options) {
2402
+ return this.sendRequest("run_transaction" /* RUN_TRANSACTION */, { ...payload, execution_mode: "wait" }, options);
2403
+ }
2394
2404
  async transfer(recipient, amount, instrument, options) {
2395
2405
  const amountStr = typeof amount === "number" ? amount.toString() : amount;
2396
2406
  const { requestedAt, executeBefore, requestTimeout } = options || {};
@@ -2420,7 +2430,8 @@ class Provider {
2420
2430
  execute_before: executeBeforeIso
2421
2431
  };
2422
2432
  const preparedPayload = await this.connection.prepareTransfer(this.auth_token, transferRequest);
2423
- return this.submitTransaction({
2433
+ const submitFn = options?.executionMode === "wait" ? this.submitAndWaitForTransaction.bind(this) : this.submitTransaction.bind(this);
2434
+ return submitFn({
2424
2435
  commands: preparedPayload.commands,
2425
2436
  disclosedContracts: preparedPayload.disclosedContracts,
2426
2437
  packageIdSelectionPreference: preparedPayload.packageIdSelectionPreference,
@@ -2705,6 +2716,7 @@ class LoopSDK {
2705
2716
  redirectUrl;
2706
2717
  onAccept = null;
2707
2718
  onReject = null;
2719
+ onTransactionUpdate = null;
2708
2720
  overlay = null;
2709
2721
  wallet;
2710
2722
  constructor() {
@@ -2717,6 +2729,7 @@ class LoopSDK {
2717
2729
  apiUrl,
2718
2730
  onAccept,
2719
2731
  onReject,
2732
+ onTransactionUpdate,
2720
2733
  options
2721
2734
  }) {
2722
2735
  if (typeof window === "undefined" || typeof document === "undefined" || typeof localStorage === "undefined") {
@@ -2725,6 +2738,7 @@ class LoopSDK {
2725
2738
  this.appName = appName;
2726
2739
  this.onAccept = onAccept || null;
2727
2740
  this.onReject = onReject || null;
2741
+ this.onTransactionUpdate = onTransactionUpdate || null;
2728
2742
  const resolvedOptions = {
2729
2743
  openMode: "popup",
2730
2744
  requestSigningMode: "popup",
@@ -3115,7 +3129,8 @@ class LoopSDK {
3115
3129
  this.closePopupIfExists();
3116
3130
  }, 800);
3117
3131
  }
3118
- }
3132
+ },
3133
+ onTransactionUpdate: this.onTransactionUpdate ?? undefined
3119
3134
  };
3120
3135
  }
3121
3136
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fivenorth/loop-sdk",
3
- "version": "0.7.6",
3
+ "version": "0.9.0",
4
4
  "author": "support@fivenorth.io",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",