@bounded-sh/client 0.0.13 → 0.0.14

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 (28) hide show
  1. package/dist/auth/providers/offchain-auth-provider.d.ts +7 -13
  2. package/dist/index.js +214 -250
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +214 -250
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/{index.native-BYEVhmbt.mjs → index.native-B4qib0WI.mjs} +217 -253
  7. package/dist/index.native-B4qib0WI.mjs.map +1 -0
  8. package/dist/{index.native-CcBTbnBg.js → index.native-fDOSSF3W.js} +217 -253
  9. package/dist/index.native-fDOSSF3W.js.map +1 -0
  10. package/dist/index.native.js +1 -1
  11. package/dist/index.native.mjs +1 -1
  12. package/dist/{phantom-wallet-provider-Cn6MzUUo.js → phantom-wallet-provider-B4iCTaUq.js} +2 -2
  13. package/dist/{phantom-wallet-provider-Cn6MzUUo.js.map → phantom-wallet-provider-B4iCTaUq.js.map} +1 -1
  14. package/dist/{phantom-wallet-provider-D_AzfLq0.mjs → phantom-wallet-provider-DGvW6ecv.mjs} +2 -2
  15. package/dist/{phantom-wallet-provider-D_AzfLq0.mjs.map → phantom-wallet-provider-DGvW6ecv.mjs.map} +1 -1
  16. package/dist/{privy-wallet-provider-DtWAtbUl.js → privy-wallet-provider-B3FEM7RO.js} +3 -3
  17. package/dist/{privy-wallet-provider-DtWAtbUl.js.map → privy-wallet-provider-B3FEM7RO.js.map} +1 -1
  18. package/dist/{privy-wallet-provider-AC4xL6bN.mjs → privy-wallet-provider-CpA0SzjA.mjs} +3 -3
  19. package/dist/{privy-wallet-provider-AC4xL6bN.mjs.map → privy-wallet-provider-CpA0SzjA.mjs.map} +1 -1
  20. package/dist/{solana-mobile-wallet-provider-X6BM07gm.mjs → solana-mobile-wallet-provider-B-Ue0EG9.mjs} +3 -3
  21. package/dist/solana-mobile-wallet-provider-B-Ue0EG9.mjs.map +1 -0
  22. package/dist/{solana-mobile-wallet-provider-Cos9gu7k.js → solana-mobile-wallet-provider-CWidNUHT.js} +3 -3
  23. package/dist/solana-mobile-wallet-provider-CWidNUHT.js.map +1 -0
  24. package/package.json +2 -2
  25. package/dist/index.native-BYEVhmbt.mjs.map +0 -1
  26. package/dist/index.native-CcBTbnBg.js.map +0 -1
  27. package/dist/solana-mobile-wallet-provider-Cos9gu7k.js.map +0 -1
  28. package/dist/solana-mobile-wallet-provider-X6BM07gm.mjs.map +0 -1
@@ -33,24 +33,18 @@ export declare class OffchainAuthProvider implements AuthProvider {
33
33
  signMessage(message: string): Promise<string>;
34
34
  signMessageMock(message: string): Promise<string>;
35
35
  private showUnsupportedTransactionModal;
36
- private getUnsupportedModalHTML;
37
36
  private showTransactionModal;
38
37
  private closeModal;
39
- /**
40
- * Escape a value for safe interpolation into an HTML string.
41
- *
42
- * Transaction messages are attacker-influenceable (they originate from
43
- * server responses / app-supplied data), so every value derived from them
44
- * MUST be escaped before being placed into innerHTML. Without this, a field
45
- * key/value, path segment, document id, or raw message containing markup
46
- * such as `<img src=x onerror=...>` would execute in the dApp origin and
47
- * could exfiltrate the stored session (idToken/refreshToken).
48
- */
49
- private escapeHtml;
38
+ private createElement;
39
+ private appendTextElement;
40
+ private buildModalShell;
41
+ private buildInfoBox;
42
+ private buildUnsupportedModalContent;
50
43
  private formatPath;
51
44
  private formatFieldValue;
52
45
  private getActionDescription;
53
- private getModalHTML;
46
+ private buildTransactionModalContent;
47
+ private buildInstructionElement;
54
48
  private getModalStyles;
55
49
  private generateMockSignature;
56
50
  }
package/dist/index.js CHANGED
@@ -11147,39 +11147,8 @@ async function get(path, opts = {}) {
11147
11147
  }
11148
11148
  // Create a new request promise and store it
11149
11149
  const requestPromise = (async () => {
11150
- var _a;
11151
11150
  try {
11152
- // For realtime chains, prefer WebSocket reads (lower latency, already connected)
11153
- const config = await getConfig();
11154
11151
  const pathIsDocument = normalizedPath.split("/").length % 2 === 0;
11155
- if (((_a = config.chain) === null || _a === void 0 ? void 0 : _a.startsWith('realtime_')) && !config.isServer && !opts.prompt && !opts.shape && !opts.cursor && !opts.includeSubPaths && !opts.filter && !opts.sort) {
11156
- try {
11157
- const { wsGet, wsQuery, hasActiveConnection } = await Promise.resolve().then(function () { return subscriptionV2; });
11158
- if (hasActiveConnection()) {
11159
- if (pathIsDocument) {
11160
- const wsResult = await wsGet(normalizedPath);
11161
- const responseData = normalizeReadResult(wsResult, true);
11162
- if (!opts.bypassCache) {
11163
- getCache[cacheKey] = { data: responseData, expiresAt: now + GET_CACHE_TTL };
11164
- }
11165
- return responseData;
11166
- }
11167
- else if (!opts.limit) {
11168
- const wsResult = await wsQuery(normalizedPath, {
11169
- filter: undefined,
11170
- sort: undefined,
11171
- includeSubPaths: opts.includeSubPaths,
11172
- });
11173
- const responseData = normalizeReadResult(wsResult, false);
11174
- if (!opts.bypassCache) {
11175
- getCache[cacheKey] = { data: responseData, expiresAt: now + GET_CACHE_TTL };
11176
- }
11177
- return responseData;
11178
- }
11179
- }
11180
- }
11181
- catch ( /* fall through to HTTP */_b) { /* fall through to HTTP */ }
11182
- }
11183
11152
  // Cache miss or bypass - proceed with HTTP API request
11184
11153
  let response;
11185
11154
  // Build common query params
@@ -11432,7 +11401,7 @@ async function set(path, document, options) {
11432
11401
  return result;
11433
11402
  }
11434
11403
  async function setMany(many, options) {
11435
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
11404
+ var _a, _b, _c, _d, _e, _f, _g;
11436
11405
  // Returns the data that was set, or undefined if the document was already set.
11437
11406
  try {
11438
11407
  const config = await getConfig();
@@ -11469,40 +11438,13 @@ async function setMany(many, options) {
11469
11438
  }
11470
11439
  let setResponse;
11471
11440
  try {
11472
- // For realtime chains, prefer WebSocket if a connection is active (lower latency)
11473
- const useWs = ((_c = config.chain) === null || _c === void 0 ? void 0 : _c.startsWith('realtime_')) && !config.isServer;
11474
- if (useWs) {
11475
- try {
11476
- const { wsSet, hasActiveConnection } = await Promise.resolve().then(function () { return subscriptionV2; });
11477
- if (hasActiveConnection()) {
11478
- // Connection is active — send via WS. If this throws, the write
11479
- // may have been applied server-side (ack lost). Do NOT fall through
11480
- // to HTTP, as that would double-apply non-idempotent ops (Increment).
11481
- const wsResult = await wsSet(documents);
11482
- setResponse = { data: wsResult, status: 200 };
11483
- }
11484
- }
11485
- catch (wsError) {
11486
- // Only fall through to HTTP if the request was never sent (connection not available).
11487
- // If the request was sent and ack was lost (timeout), the server may have
11488
- // applied it — re-sending via HTTP risks double-write for non-idempotent ops.
11489
- const msg = (_d = wsError === null || wsError === void 0 ? void 0 : wsError.message) !== null && _d !== void 0 ? _d : '';
11490
- const neverSent = msg.includes('not available') || msg.includes('connection timeout');
11491
- if (!neverSent) {
11492
- throw wsError;
11493
- }
11494
- // Safe to retry via HTTP — request was never sent
11495
- }
11496
- }
11497
- if (!setResponse) {
11498
- setResponse = await makeApiRequest('PUT', `items`, { documents }, options === null || options === void 0 ? void 0 : options._overrides);
11499
- }
11441
+ setResponse = await makeApiRequest('PUT', `items`, { documents }, options === null || options === void 0 ? void 0 : options._overrides);
11500
11442
  }
11501
11443
  catch (error) {
11502
11444
  if ((error === null || error === void 0 ? void 0 : error.statusCode) === 402 && (error === null || error === void 0 ? void 0 : error.error) === 'INSUFFICIENT_BALANCE') {
11503
- const deficitLamports = Number((_e = error.deficitLamports) !== null && _e !== void 0 ? _e : 0);
11504
- const deficitSol = Number((_f = error.deficitSol) !== null && _f !== void 0 ? _f : deficitLamports / 1000000000);
11505
- throw new InsufficientBalanceError(String((_g = error.address) !== null && _g !== void 0 ? _g : ''), Number((_h = error.balanceLamports) !== null && _h !== void 0 ? _h : 0), Number((_j = error.estimatedCostLamports) !== null && _j !== void 0 ? _j : 0), deficitLamports, deficitSol);
11445
+ const deficitLamports = Number((_c = error.deficitLamports) !== null && _c !== void 0 ? _c : 0);
11446
+ const deficitSol = Number((_d = error.deficitSol) !== null && _d !== void 0 ? _d : deficitLamports / 1000000000);
11447
+ throw new InsufficientBalanceError(String((_e = error.address) !== null && _e !== void 0 ? _e : ''), Number((_f = error.balanceLamports) !== null && _f !== void 0 ? _f : 0), Number((_g = error.estimatedCostLamports) !== null && _g !== void 0 ? _g : 0), deficitLamports, deficitSol);
11506
11448
  }
11507
11449
  throw error;
11508
11450
  }
@@ -11549,7 +11491,7 @@ async function setMany(many, options) {
11549
11491
  else if (setResponse.data &&
11550
11492
  typeof setResponse.data === 'object' &&
11551
11493
  setResponse.data.success === true) {
11552
- const _k = setResponse.data, { success: _success } = _k, rest = __rest$1(_k, ["success"]);
11494
+ const _h = setResponse.data, { success: _success } = _h, rest = __rest$1(_h, ["success"]);
11553
11495
  return Object.assign(Object.assign(Object.assign({}, documents.map(d => d.document)), rest), { transactionId: null });
11554
11496
  }
11555
11497
  else {
@@ -13077,23 +13019,6 @@ async function wsGetMany(paths) {
13077
13019
  }));
13078
13020
  }
13079
13021
 
13080
- var subscriptionV2 = /*#__PURE__*/Object.freeze({
13081
- __proto__: null,
13082
- clearCacheV2: clearCacheV2,
13083
- closeAllSubscriptionsV2: closeAllSubscriptionsV2,
13084
- getCachedDataV2: getCachedDataV2,
13085
- hasActiveConnection: hasActiveConnection,
13086
- reconnectWithNewAuthV2: reconnectWithNewAuthV2,
13087
- subscribeV2: subscribeV2,
13088
- wsDelete: wsDelete,
13089
- wsGet: wsGet,
13090
- wsGetMany: wsGetMany,
13091
- wsIntent: wsIntent,
13092
- wsIntentReliable: wsIntentReliable,
13093
- wsQuery: wsQuery,
13094
- wsSet: wsSet
13095
- });
13096
-
13097
13022
  /**
13098
13023
  * WebSocket Subscription Module
13099
13024
  *
@@ -14904,7 +14829,7 @@ class OffchainAuthProvider {
14904
14829
  // Create modal container
14905
14830
  this.modalContainer = document.createElement("div");
14906
14831
  this.modalContainer.id = "poofnet-unsupported-modal";
14907
- this.modalContainer.innerHTML = this.getUnsupportedModalHTML();
14832
+ this.modalContainer.appendChild(this.buildUnsupportedModalContent());
14908
14833
  document.body.appendChild(this.modalContainer);
14909
14834
  // Add styles
14910
14835
  const style = document.createElement("style");
@@ -14960,38 +14885,6 @@ class OffchainAuthProvider {
14960
14885
  document.addEventListener("keydown", escHandler);
14961
14886
  });
14962
14887
  }
14963
- getUnsupportedModalHTML() {
14964
- return `
14965
- <div class="poofnet-modal-overlay">
14966
- <div class="poofnet-modal-content">
14967
- <button id="poofnet-close-btn" class="poofnet-close-btn" aria-label="Close">
14968
- <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
14969
- <path d="M1 1L13 13M1 13L13 1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
14970
- </svg>
14971
- </button>
14972
- <div class="poofnet-modal-header">
14973
- <div class="poofnet-modal-icon">⚠️</div>
14974
- <h2 class="poofnet-modal-title">Transaction Not Supported</h2>
14975
- <p class="poofnet-modal-subtitle">Poofnet Simulated Blockchain</p>
14976
- </div>
14977
-
14978
- <div class="poofnet-modal-body">
14979
- <div class="poofnet-info-box" style="background: #fef3c7;">
14980
- <span class="poofnet-info-icon">ℹ️</span>
14981
- <span class="poofnet-info-text" style="color: #92400e;">
14982
- Poofnet is a simulated blockchain and does not support real Solana transactions.
14983
- Deploy your project to mainnet to test real transactions.
14984
- </span>
14985
- </div>
14986
- </div>
14987
-
14988
- <div class="poofnet-modal-footer">
14989
- <button id="poofnet-cancel-btn" class="poofnet-btn poofnet-btn-cancel" style="flex: 1;">Close</button>
14990
- </div>
14991
- </div>
14992
- </div>
14993
- `;
14994
- }
14995
14888
  async showTransactionModal(message) {
14996
14889
  return new Promise((resolve) => {
14997
14890
  // Parse the transaction message for display
@@ -15005,7 +14898,7 @@ class OffchainAuthProvider {
15005
14898
  // Create modal container
15006
14899
  this.modalContainer = document.createElement("div");
15007
14900
  this.modalContainer.id = "poofnet-tx-modal";
15008
- this.modalContainer.innerHTML = this.getModalHTML(parsed, message);
14901
+ this.modalContainer.appendChild(this.buildTransactionModalContent(parsed, message));
15009
14902
  document.body.appendChild(this.modalContainer);
15010
14903
  // Add styles
15011
14904
  const style = document.createElement("style");
@@ -15088,24 +14981,59 @@ class OffchainAuthProvider {
15088
14981
  }, 200);
15089
14982
  }
15090
14983
  }
15091
- /**
15092
- * Escape a value for safe interpolation into an HTML string.
15093
- *
15094
- * Transaction messages are attacker-influenceable (they originate from
15095
- * server responses / app-supplied data), so every value derived from them
15096
- * MUST be escaped before being placed into innerHTML. Without this, a field
15097
- * key/value, path segment, document id, or raw message containing markup
15098
- * such as `<img src=x onerror=...>` would execute in the dApp origin and
15099
- * could exfiltrate the stored session (idToken/refreshToken).
15100
- */
15101
- escapeHtml(value) {
15102
- const str = value === null || value === undefined ? "" : String(value);
15103
- return str
15104
- .replace(/&/g, "&amp;")
15105
- .replace(/</g, "&lt;")
15106
- .replace(/>/g, "&gt;")
15107
- .replace(/"/g, "&quot;")
15108
- .replace(/'/g, "&#39;");
14984
+ createElement(tag, className, text) {
14985
+ const el = document.createElement(tag);
14986
+ if (className)
14987
+ el.className = className;
14988
+ if (text !== undefined)
14989
+ el.textContent = text;
14990
+ return el;
14991
+ }
14992
+ appendTextElement(parent, tag, className, text) {
14993
+ const el = this.createElement(tag, className, text);
14994
+ parent.appendChild(el);
14995
+ return el;
14996
+ }
14997
+ buildModalShell(icon, title) {
14998
+ const overlay = this.createElement("div", "poofnet-modal-overlay");
14999
+ const content = this.createElement("div", "poofnet-modal-content");
15000
+ overlay.appendChild(content);
15001
+ const close = this.createElement("button", "poofnet-close-btn", "×");
15002
+ close.id = "poofnet-close-btn";
15003
+ close.setAttribute("aria-label", "Close");
15004
+ close.type = "button";
15005
+ content.appendChild(close);
15006
+ const header = this.createElement("div", "poofnet-modal-header");
15007
+ this.appendTextElement(header, "div", "poofnet-modal-icon", icon);
15008
+ this.appendTextElement(header, "h2", "poofnet-modal-title", title);
15009
+ this.appendTextElement(header, "p", "poofnet-modal-subtitle", "Poofnet Simulated Blockchain");
15010
+ content.appendChild(header);
15011
+ const body = this.createElement("div", "poofnet-modal-body");
15012
+ content.appendChild(body);
15013
+ const footer = this.createElement("div", "poofnet-modal-footer");
15014
+ content.appendChild(footer);
15015
+ return { overlay, body, footer };
15016
+ }
15017
+ buildInfoBox(text, warning = false) {
15018
+ const info = this.createElement("div", "poofnet-info-box");
15019
+ if (warning)
15020
+ info.style.background = "#fef3c7";
15021
+ this.appendTextElement(info, "span", "poofnet-info-icon", "ℹ️");
15022
+ const infoText = this.createElement("span", "poofnet-info-text", text);
15023
+ if (warning)
15024
+ infoText.style.color = "#92400e";
15025
+ info.appendChild(infoText);
15026
+ return info;
15027
+ }
15028
+ buildUnsupportedModalContent() {
15029
+ const { overlay, body, footer } = this.buildModalShell("⚠️", "Transaction Not Supported");
15030
+ body.appendChild(this.buildInfoBox("Poofnet is a simulated blockchain and does not support real Solana transactions. Deploy your project to mainnet to test real transactions.", true));
15031
+ const close = this.createElement("button", "poofnet-btn poofnet-btn-cancel", "Close");
15032
+ close.id = "poofnet-cancel-btn";
15033
+ close.type = "button";
15034
+ close.style.flex = "1";
15035
+ footer.appendChild(close);
15036
+ return overlay;
15109
15037
  }
15110
15038
  formatPath(path) {
15111
15039
  const parts = path.split("/").filter(Boolean);
@@ -15138,59 +15066,11 @@ class OffchainAuthProvider {
15138
15066
  return `Delete from ${collection}`;
15139
15067
  return isNew ? `Create in ${collection}` : `Update ${collection}`;
15140
15068
  }
15141
- getModalHTML(parsed, rawMessage) {
15069
+ buildTransactionModalContent(parsed, rawMessage) {
15142
15070
  const instructions = parsed.instructions || [];
15143
15071
  // Group instructions by type for summary
15144
15072
  const sets = instructions.filter((i) => i.type === "set");
15145
15073
  const deletes = instructions.filter((i) => i.type === "delete");
15146
- const instructionsList = instructions
15147
- .map((inst) => {
15148
- const { collection, documentId } = this.formatPath(inst.path);
15149
- const isDelete = inst.type === "delete";
15150
- const icon = isDelete ? "🗑️" : "✏️";
15151
- const actionClass = isDelete
15152
- ? "poofnet-action-delete"
15153
- : "poofnet-action-set";
15154
- // Format data fields for display
15155
- let fieldsHtml = "";
15156
- if (inst.data && !isDelete) {
15157
- const fields = Object.entries(inst.data)
15158
- .filter(([key]) => !key.startsWith("_")) // Hide internal fields
15159
- .slice(0, 4);
15160
- if (fields.length > 0) {
15161
- fieldsHtml = `
15162
- <div class="poofnet-fields">
15163
- ${fields
15164
- .map(([key, value]) => `
15165
- <div class="poofnet-field">
15166
- <span class="poofnet-field-key">${this.escapeHtml(key)}:</span>
15167
- <span class="poofnet-field-value">${this.escapeHtml(this.formatFieldValue(value))}</span>
15168
- </div>
15169
- `)
15170
- .join("")}
15171
- ${Object.keys(inst.data).filter((k) => !k.startsWith("_"))
15172
- .length > 4
15173
- ? `<div class="poofnet-field-more">+${Object.keys(inst.data).filter((k) => !k.startsWith("_")).length - 4} more fields</div>`
15174
- : ""}
15175
- </div>
15176
- `;
15177
- }
15178
- }
15179
- return `
15180
- <div class="poofnet-instruction ${actionClass}">
15181
- <div class="poofnet-instruction-header">
15182
- <span class="poofnet-instruction-icon">${icon}</span>
15183
- <span class="poofnet-instruction-action">${isDelete ? "Delete" : "Save"}</span>
15184
- <span class="poofnet-instruction-collection">${this.escapeHtml(collection)}</span>
15185
- </div>
15186
- ${documentId
15187
- ? `<div class="poofnet-instruction-id">ID: ${this.escapeHtml(documentId)}</div>`
15188
- : ""}
15189
- ${fieldsHtml}
15190
- </div>
15191
- `;
15192
- })
15193
- .join("");
15194
15074
  // Create summary text
15195
15075
  let summaryText = "";
15196
15076
  if (sets.length > 0 && deletes.length > 0) {
@@ -15202,50 +15082,65 @@ class OffchainAuthProvider {
15202
15082
  else if (deletes.length > 0) {
15203
15083
  summaryText = `${deletes.length} delete${deletes.length > 1 ? "s" : ""}`;
15204
15084
  }
15205
- return `
15206
- <div class="poofnet-modal-overlay">
15207
- <div class="poofnet-modal-content">
15208
- <button id="poofnet-close-btn" class="poofnet-close-btn" aria-label="Close">
15209
- <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
15210
- <path d="M1 1L13 13M1 13L13 1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
15211
- </svg>
15212
- </button>
15213
- <div class="poofnet-modal-header">
15214
- <div class="poofnet-modal-icon">🔐</div>
15215
- <h2 class="poofnet-modal-title">Confirm Transaction</h2>
15216
- <p class="poofnet-modal-subtitle">Poofnet Simulated Blockchain</p>
15217
- </div>
15218
-
15219
- <div class="poofnet-modal-body">
15220
- ${instructions.length > 0
15221
- ? `
15222
- ${summaryText
15223
- ? `<div class="poofnet-summary">${summaryText}</div>`
15224
- : ""}
15225
- <div class="poofnet-instructions-list">
15226
- ${instructionsList}
15227
- </div>
15228
- `
15229
- : `
15230
- <div class="poofnet-section">
15231
- <h3 class="poofnet-section-title">Message</h3>
15232
- <pre class="poofnet-raw-message">${this.escapeHtml(rawMessage.slice(0, 200))}${rawMessage.length > 200 ? "..." : ""}</pre>
15233
- </div>
15234
- `}
15235
-
15236
- <div class="poofnet-info-box">
15237
- <span class="poofnet-info-icon">ℹ️</span>
15238
- <span class="poofnet-info-text">This is a simulated transaction. No real fees will be charged.</span>
15239
- </div>
15240
- </div>
15241
-
15242
- <div class="poofnet-modal-footer">
15243
- <button id="poofnet-cancel-btn" class="poofnet-btn poofnet-btn-cancel">Cancel</button>
15244
- <button id="poofnet-confirm-btn" class="poofnet-btn poofnet-btn-confirm">Confirm</button>
15245
- </div>
15246
- </div>
15247
- </div>
15248
- `;
15085
+ const { overlay, body, footer } = this.buildModalShell("🔐", "Confirm Transaction");
15086
+ if (instructions.length > 0) {
15087
+ if (summaryText) {
15088
+ this.appendTextElement(body, "div", "poofnet-summary", summaryText);
15089
+ }
15090
+ const list = this.createElement("div", "poofnet-instructions-list");
15091
+ for (const inst of instructions) {
15092
+ list.appendChild(this.buildInstructionElement(inst));
15093
+ }
15094
+ body.appendChild(list);
15095
+ }
15096
+ else {
15097
+ const section = this.createElement("div", "poofnet-section");
15098
+ this.appendTextElement(section, "h3", "poofnet-section-title", "Message");
15099
+ const raw = this.createElement("pre", "poofnet-raw-message", rawMessage.slice(0, 200) + (rawMessage.length > 200 ? "..." : ""));
15100
+ section.appendChild(raw);
15101
+ body.appendChild(section);
15102
+ }
15103
+ body.appendChild(this.buildInfoBox("This is a simulated transaction. No real fees will be charged."));
15104
+ const cancel = this.createElement("button", "poofnet-btn poofnet-btn-cancel", "Cancel");
15105
+ cancel.id = "poofnet-cancel-btn";
15106
+ cancel.type = "button";
15107
+ footer.appendChild(cancel);
15108
+ const confirm = this.createElement("button", "poofnet-btn poofnet-btn-confirm", "Confirm");
15109
+ confirm.id = "poofnet-confirm-btn";
15110
+ confirm.type = "button";
15111
+ footer.appendChild(confirm);
15112
+ return overlay;
15113
+ }
15114
+ buildInstructionElement(inst) {
15115
+ const { collection, documentId } = this.formatPath(inst.path);
15116
+ const isDelete = inst.type === "delete";
15117
+ const card = this.createElement("div", `poofnet-instruction ${isDelete ? "poofnet-action-delete" : "poofnet-action-set"}`);
15118
+ const header = this.createElement("div", "poofnet-instruction-header");
15119
+ this.appendTextElement(header, "span", "poofnet-instruction-icon", isDelete ? "🗑️" : "✏️");
15120
+ this.appendTextElement(header, "span", "poofnet-instruction-action", isDelete ? "Delete" : "Save");
15121
+ this.appendTextElement(header, "span", "poofnet-instruction-collection", collection);
15122
+ card.appendChild(header);
15123
+ if (documentId) {
15124
+ this.appendTextElement(card, "div", "poofnet-instruction-id", `ID: ${documentId}`);
15125
+ }
15126
+ if (inst.data && !isDelete) {
15127
+ const fieldKeys = Object.keys(inst.data).filter((key) => !key.startsWith("_"));
15128
+ const visibleFields = fieldKeys.slice(0, 4);
15129
+ if (visibleFields.length > 0) {
15130
+ const fields = this.createElement("div", "poofnet-fields");
15131
+ for (const key of visibleFields) {
15132
+ const row = this.createElement("div", "poofnet-field");
15133
+ this.appendTextElement(row, "span", "poofnet-field-key", `${key}:`);
15134
+ this.appendTextElement(row, "span", "poofnet-field-value", this.formatFieldValue(inst.data[key]));
15135
+ fields.appendChild(row);
15136
+ }
15137
+ if (fieldKeys.length > 4) {
15138
+ this.appendTextElement(fields, "div", "poofnet-field-more", `+${fieldKeys.length - 4} more fields`);
15139
+ }
15140
+ card.appendChild(fields);
15141
+ }
15142
+ }
15143
+ return card;
15249
15144
  }
15250
15145
  getModalStyles() {
15251
15146
  return `
@@ -18581,9 +18476,7 @@ const emailProviderSingleton = new EmailAuthProvider();
18581
18476
  function openEmailModal() {
18582
18477
  return new Promise((resolve) => {
18583
18478
  var _a;
18584
- const root = document.createElement('div');
18585
- root.id = 'bounded-auth-modal';
18586
- root.innerHTML = MODAL_HTML;
18479
+ const root = createEmailModalTree();
18587
18480
  const style = document.createElement('style');
18588
18481
  style.textContent = MODAL_CSS;
18589
18482
  root.appendChild(style);
@@ -18671,26 +18564,97 @@ function openEmailModal() {
18671
18564
  });
18672
18565
  });
18673
18566
  }
18674
- const MODAL_HTML = `
18675
- <div class="ba-overlay">
18676
- <div class="ba-card" role="dialog" aria-modal="true" aria-label="Sign in">
18677
- <button id="ba-close" class="ba-x" aria-label="Close">&times;</button>
18678
- <div class="ba-brand"><span class="ba-dot"></span> Sign in</div>
18679
- <div id="ba-email-step">
18680
- <label class="ba-label" for="ba-email">Email</label>
18681
- <input id="ba-email" class="ba-input" type="email" inputmode="email" autocomplete="email" placeholder="you@example.com" />
18682
- <button id="ba-email-btn" class="ba-btn">Continue</button>
18683
- </div>
18684
- <div id="ba-otp-step" class="hidden">
18685
- <label class="ba-label" for="ba-otp">Enter the code sent to <span id="ba-sent-to" class="ba-em"></span></label>
18686
- <input id="ba-otp" class="ba-input ba-code" inputmode="numeric" autocomplete="one-time-code" maxlength="8" placeholder="······" />
18687
- <button id="ba-otp-btn" class="ba-btn">Verify &amp; continue</button>
18688
- <button id="ba-back" class="ba-link">Use a different email</button>
18689
- </div>
18690
- <div id="ba-msg" class="ba-msg"></div>
18691
- <div class="ba-foot">Secured by Bounded</div>
18692
- </div>
18693
- </div>`;
18567
+ function createEmailModalTree() {
18568
+ const root = document.createElement('div');
18569
+ root.id = 'bounded-auth-modal';
18570
+ const overlay = document.createElement('div');
18571
+ overlay.className = 'ba-overlay';
18572
+ root.appendChild(overlay);
18573
+ const card = document.createElement('div');
18574
+ card.className = 'ba-card';
18575
+ card.setAttribute('role', 'dialog');
18576
+ card.setAttribute('aria-modal', 'true');
18577
+ card.setAttribute('aria-label', 'Sign in');
18578
+ overlay.appendChild(card);
18579
+ const close = document.createElement('button');
18580
+ close.id = 'ba-close';
18581
+ close.className = 'ba-x';
18582
+ close.setAttribute('aria-label', 'Close');
18583
+ close.type = 'button';
18584
+ close.textContent = '×';
18585
+ card.appendChild(close);
18586
+ const brand = document.createElement('div');
18587
+ brand.className = 'ba-brand';
18588
+ const dot = document.createElement('span');
18589
+ dot.className = 'ba-dot';
18590
+ brand.appendChild(dot);
18591
+ brand.appendChild(document.createTextNode(' Sign in'));
18592
+ card.appendChild(brand);
18593
+ const emailStep = document.createElement('div');
18594
+ emailStep.id = 'ba-email-step';
18595
+ card.appendChild(emailStep);
18596
+ const emailLabel = document.createElement('label');
18597
+ emailLabel.className = 'ba-label';
18598
+ emailLabel.htmlFor = 'ba-email';
18599
+ emailLabel.textContent = 'Email';
18600
+ emailStep.appendChild(emailLabel);
18601
+ const emailInput = document.createElement('input');
18602
+ emailInput.id = 'ba-email';
18603
+ emailInput.className = 'ba-input';
18604
+ emailInput.type = 'email';
18605
+ emailInput.inputMode = 'email';
18606
+ emailInput.autocomplete = 'email';
18607
+ emailInput.placeholder = 'you@example.com';
18608
+ emailStep.appendChild(emailInput);
18609
+ const emailButton = document.createElement('button');
18610
+ emailButton.id = 'ba-email-btn';
18611
+ emailButton.className = 'ba-btn';
18612
+ emailButton.type = 'button';
18613
+ emailButton.textContent = 'Continue';
18614
+ emailStep.appendChild(emailButton);
18615
+ const otpStep = document.createElement('div');
18616
+ otpStep.id = 'ba-otp-step';
18617
+ otpStep.className = 'hidden';
18618
+ card.appendChild(otpStep);
18619
+ const otpLabel = document.createElement('label');
18620
+ otpLabel.className = 'ba-label';
18621
+ otpLabel.htmlFor = 'ba-otp';
18622
+ otpLabel.appendChild(document.createTextNode('Enter the code sent to '));
18623
+ const sentTo = document.createElement('span');
18624
+ sentTo.id = 'ba-sent-to';
18625
+ sentTo.className = 'ba-em';
18626
+ otpLabel.appendChild(sentTo);
18627
+ otpStep.appendChild(otpLabel);
18628
+ const otpInput = document.createElement('input');
18629
+ otpInput.id = 'ba-otp';
18630
+ otpInput.className = 'ba-input ba-code';
18631
+ otpInput.inputMode = 'numeric';
18632
+ otpInput.autocomplete = 'one-time-code';
18633
+ otpInput.maxLength = 8;
18634
+ otpInput.placeholder = '······';
18635
+ otpStep.appendChild(otpInput);
18636
+ const otpButton = document.createElement('button');
18637
+ otpButton.id = 'ba-otp-btn';
18638
+ otpButton.className = 'ba-btn';
18639
+ otpButton.type = 'button';
18640
+ otpButton.textContent = 'Verify & continue';
18641
+ otpStep.appendChild(otpButton);
18642
+ const backButton = document.createElement('button');
18643
+ backButton.id = 'ba-back';
18644
+ backButton.className = 'ba-link';
18645
+ backButton.type = 'button';
18646
+ backButton.textContent = 'Use a different email';
18647
+ otpStep.appendChild(backButton);
18648
+ const msg = document.createElement('div');
18649
+ msg.id = 'ba-msg';
18650
+ msg.className = 'ba-msg';
18651
+ card.appendChild(msg);
18652
+ const foot = document.createElement('div');
18653
+ foot.className = 'ba-foot';
18654
+ foot.textContent = 'Secured by Bounded';
18655
+ card.appendChild(foot);
18656
+ return root;
18657
+ }
18694
18658
  const MODAL_CSS = `
18695
18659
  #bounded-auth-modal .ba-overlay{position:fixed;inset:0;background:rgba(8,10,18,.62);backdrop-filter:blur(4px);
18696
18660
  display:flex;align-items:center;justify-content:center;z-index:2147483000;opacity:1;transition:opacity .16s ease;
@@ -21428,7 +21392,7 @@ async function awaitSignInGestureAndSign(theme, signFn, noResultError = 'MWA ret
21428
21392
  ].join('; ');
21429
21393
  const closeBtn = document.createElement('button');
21430
21394
  closeBtn.setAttribute('aria-label', 'Close');
21431
- closeBtn.textContent = '×'; // × (multiplication sign), set via textContent to avoid any innerHTML usage
21395
+ closeBtn.textContent = '×';
21432
21396
  closeBtn.style.cssText = [
21433
21397
  'position: absolute',
21434
21398
  'top: 12px',