@haex-space/vault-sdk 3.0.0 → 3.2.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 (45) hide show
  1. package/dist/{client-dpJHb3FP.d.ts → client-GeColu97.d.mts} +270 -2
  2. package/dist/{client-BXtzUBWv.d.mts → client-z1jTcuQE.d.ts} +270 -2
  3. package/dist/index.d.mts +93 -6
  4. package/dist/index.d.ts +93 -6
  5. package/dist/index.js +301 -45
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +298 -46
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/node.d.mts +1 -1
  10. package/dist/node.d.ts +1 -1
  11. package/dist/nuxt.js +34 -7
  12. package/dist/nuxt.js.map +1 -1
  13. package/dist/nuxt.mjs +34 -7
  14. package/dist/nuxt.mjs.map +1 -1
  15. package/dist/react.d.mts +2 -2
  16. package/dist/react.d.ts +2 -2
  17. package/dist/react.js +294 -44
  18. package/dist/react.js.map +1 -1
  19. package/dist/react.mjs +294 -44
  20. package/dist/react.mjs.map +1 -1
  21. package/dist/runtime/nuxt.plugin.client.d.mts +2 -2
  22. package/dist/runtime/nuxt.plugin.client.d.ts +2 -2
  23. package/dist/runtime/nuxt.plugin.client.js +294 -48
  24. package/dist/runtime/nuxt.plugin.client.js.map +1 -1
  25. package/dist/runtime/nuxt.plugin.client.mjs +294 -48
  26. package/dist/runtime/nuxt.plugin.client.mjs.map +1 -1
  27. package/dist/svelte.d.mts +2 -2
  28. package/dist/svelte.d.ts +2 -2
  29. package/dist/svelte.js +294 -44
  30. package/dist/svelte.js.map +1 -1
  31. package/dist/svelte.mjs +294 -44
  32. package/dist/svelte.mjs.map +1 -1
  33. package/dist/{types-DmCSegdY.d.mts → types-CDMBvvjl.d.mts} +2 -0
  34. package/dist/{types-DmCSegdY.d.ts → types-CDMBvvjl.d.ts} +2 -0
  35. package/dist/vite.js +33 -6
  36. package/dist/vite.js.map +1 -1
  37. package/dist/vite.mjs +33 -6
  38. package/dist/vite.mjs.map +1 -1
  39. package/dist/vue.d.mts +2 -2
  40. package/dist/vue.d.ts +2 -2
  41. package/dist/vue.js +294 -44
  42. package/dist/vue.js.map +1 -1
  43. package/dist/vue.mjs +294 -44
  44. package/dist/vue.mjs.map +1 -1
  45. package/package.json +2 -1
package/dist/svelte.mjs CHANGED
@@ -267,7 +267,24 @@ var HAEXSPACE_MESSAGE_TYPES = {
267
267
  /** Debug message for development/troubleshooting */
268
268
  DEBUG: "haexspace:debug",
269
269
  /** Console forwarding from extension iframe */
270
- CONSOLE_FORWARD: "console.forward"
270
+ CONSOLE_FORWARD: "console.forward",
271
+ /**
272
+ * Sent from main window to iframe on the shared window listener, carrying
273
+ * one `MessagePort` in `event.ports[0]`. Once received, the SDK switches
274
+ * to port-based messaging and never reads the window listener again.
275
+ *
276
+ * Payload: `{ type: PORT_INIT }` — no data. The port itself is the payload.
277
+ */
278
+ PORT_INIT: "haexspace:port:init",
279
+ /**
280
+ * Sent from SDK to main window *over the MessagePort* after the port is
281
+ * installed. Main uses this to mark the iframe as ready and flush any
282
+ * events buffered during the handshake window. Only valid on the port —
283
+ * a READY sent over window.postMessage is ignored.
284
+ *
285
+ * Payload: `{ type: PORT_READY }` — no data.
286
+ */
287
+ PORT_READY: "haexspace:port:ready"
271
288
  };
272
289
 
273
290
  // src/polyfills/debug.ts
@@ -631,6 +648,40 @@ var SHELL_COMMANDS = {
631
648
  close: "extension_shell_close"
632
649
  };
633
650
 
651
+ // src/commands/passwords.ts
652
+ var PASSWORD_COMMANDS = {
653
+ /** List items (no secrets) within the extension's tag scope */
654
+ list: "extension_password_list",
655
+ /** Read full item including secrets, by id */
656
+ read: "extension_password_read",
657
+ /** Create item — must include >=1 tag in scope */
658
+ create: "extension_password_create",
659
+ /** Update item — keeps >=1 tag in scope */
660
+ update: "extension_password_update",
661
+ /** Delete item — must be in scope */
662
+ delete: "extension_password_delete"
663
+ };
664
+
665
+ // src/commands/mail.ts
666
+ var MAIL_COMMANDS = {
667
+ /** LIST mailboxes + optional STATUS counts */
668
+ listMailboxes: "extension_mail_list_mailboxes",
669
+ /** Lightweight envelope fetch for list views */
670
+ fetchEnvelopes: "extension_mail_fetch_envelopes",
671
+ /** Full message fetch (envelope + body + attachment metadata) */
672
+ fetchMessage: "extension_mail_fetch_message",
673
+ /** Set or unset IMAP flags on a UID set */
674
+ setFlags: "extension_mail_set_flags",
675
+ /** MOVE messages between mailboxes (COPY+EXPUNGE fallback) */
676
+ moveMessages: "extension_mail_move_messages",
677
+ /** APPEND a base64-encoded RFC822 message into a mailbox */
678
+ appendMessage: "extension_mail_append_message",
679
+ /** SMTP send. Returns the assigned Message-ID. */
680
+ sendMessage: "extension_mail_send_message",
681
+ /** Build RFC822 bytes without sending (for Drafts via APPEND) */
682
+ buildRfc822: "extension_mail_build_rfc822"
683
+ };
684
+
634
685
  // src/api/storage.ts
635
686
  var StorageAPI = class {
636
687
  constructor(client) {
@@ -654,6 +705,12 @@ var StorageAPI = class {
654
705
  };
655
706
 
656
707
  // src/api/database.ts
708
+ function quoteIdent(identifier) {
709
+ if (identifier.startsWith('"') && identifier.endsWith('"')) {
710
+ return identifier;
711
+ }
712
+ return `"${identifier.replace(/"/g, '""')}"`;
713
+ }
657
714
  var DatabaseAPI = class {
658
715
  constructor(client) {
659
716
  this.client = client;
@@ -684,11 +741,11 @@ var DatabaseAPI = class {
684
741
  });
685
742
  }
686
743
  async createTable(tableName, columns) {
687
- const query = `CREATE TABLE IF NOT EXISTS ${tableName} (${columns})`;
744
+ const query = `CREATE TABLE IF NOT EXISTS ${quoteIdent(tableName)} (${columns})`;
688
745
  await this.execute(query);
689
746
  }
690
747
  async dropTable(tableName) {
691
- const query = `DROP TABLE IF EXISTS ${tableName}`;
748
+ const query = `DROP TABLE IF EXISTS ${quoteIdent(tableName)}`;
692
749
  await this.execute(query);
693
750
  }
694
751
  /**
@@ -717,18 +774,17 @@ var DatabaseAPI = class {
717
774
  async insert(tableName, data) {
718
775
  const keys = Object.keys(data);
719
776
  const values = Object.values(data);
777
+ const quotedCols = keys.map(quoteIdent).join(", ");
720
778
  const placeholders = keys.map(() => "?").join(", ");
721
- const query = `INSERT INTO ${tableName} (${keys.join(
722
- ", "
723
- )}) VALUES (${placeholders})`;
779
+ const query = `INSERT INTO ${quoteIdent(tableName)} (${quotedCols}) VALUES (${placeholders})`;
724
780
  const result = await this.execute(query, values);
725
781
  return result.lastInsertId ?? -1;
726
782
  }
727
783
  async update(tableName, data, where, whereParams) {
728
784
  const keys = Object.keys(data);
729
785
  const values = Object.values(data);
730
- const setClause = keys.map((key) => `${key} = ?`).join(", ");
731
- const query = `UPDATE ${tableName} SET ${setClause} WHERE ${where}`;
786
+ const setClause = keys.map((key) => `${quoteIdent(key)} = ?`).join(", ");
787
+ const query = `UPDATE ${quoteIdent(tableName)} SET ${setClause} WHERE ${where}`;
732
788
  const result = await this.execute(query, [
733
789
  ...values,
734
790
  ...whereParams || []
@@ -736,12 +792,12 @@ var DatabaseAPI = class {
736
792
  return result.rowsAffected;
737
793
  }
738
794
  async delete(tableName, where, whereParams) {
739
- const query = `DELETE FROM ${tableName} WHERE ${where}`;
795
+ const query = `DELETE FROM ${quoteIdent(tableName)} WHERE ${where}`;
740
796
  const result = await this.execute(query, whereParams);
741
797
  return result.rowsAffected;
742
798
  }
743
799
  async count(tableName, where, whereParams) {
744
- const query = where ? `SELECT COUNT(*) as count FROM ${tableName} WHERE ${where}` : `SELECT COUNT(*) as count FROM ${tableName}`;
800
+ const query = where ? `SELECT COUNT(*) as count FROM ${quoteIdent(tableName)} WHERE ${where}` : `SELECT COUNT(*) as count FROM ${quoteIdent(tableName)}`;
745
801
  const result = await this.queryOne(query, whereParams);
746
802
  return result?.count ?? 0;
747
803
  }
@@ -1563,6 +1619,140 @@ var ShellAPI = class {
1563
1619
  }
1564
1620
  };
1565
1621
 
1622
+ // src/api/passwords.ts
1623
+ var PasswordsAPI = class {
1624
+ constructor(client) {
1625
+ this.client = client;
1626
+ }
1627
+ /** List items in scope — summaries only, no secrets. */
1628
+ async listAsync() {
1629
+ return this.client.request(
1630
+ PASSWORD_COMMANDS.list,
1631
+ {}
1632
+ );
1633
+ }
1634
+ /** Read a single item by id with full secrets. */
1635
+ async readAsync(itemId) {
1636
+ return this.client.request(PASSWORD_COMMANDS.read, {
1637
+ itemId
1638
+ });
1639
+ }
1640
+ /**
1641
+ * Create a new password item. `input.tags` must contain at least one
1642
+ * tag within the extension's permission scope, otherwise the write
1643
+ * is rejected as a security violation.
1644
+ *
1645
+ * Returns the new item id.
1646
+ */
1647
+ async createAsync(input) {
1648
+ return this.client.request(PASSWORD_COMMANDS.create, { input });
1649
+ }
1650
+ /**
1651
+ * Update an existing item. The item must already be in scope, and
1652
+ * the new tag set must keep at least one tag in scope (extensions
1653
+ * cannot orphan an item out of their own reach).
1654
+ */
1655
+ async updateAsync(itemId, input) {
1656
+ return this.client.request(PASSWORD_COMMANDS.update, {
1657
+ itemId,
1658
+ input
1659
+ });
1660
+ }
1661
+ /** Delete an item by id. Item must be in scope. */
1662
+ async deleteAsync(itemId) {
1663
+ return this.client.request(PASSWORD_COMMANDS.delete, { itemId });
1664
+ }
1665
+ };
1666
+
1667
+ // src/api/mail.ts
1668
+ var MailAPI = class {
1669
+ constructor(client) {
1670
+ this.client = client;
1671
+ }
1672
+ /**
1673
+ * LIST mailboxes for an IMAP account. Pass `includeStatus=true` for
1674
+ * EXISTS/UNSEEN/UIDVALIDITY/UIDNEXT per box (one extra round-trip
1675
+ * per mailbox — fine for typical accounts, expensive for large
1676
+ * trees).
1677
+ */
1678
+ async listMailboxesAsync(imap, options = {}) {
1679
+ return this.client.request(MAIL_COMMANDS.listMailboxes, {
1680
+ imap,
1681
+ reference: options.reference,
1682
+ pattern: options.pattern,
1683
+ includeStatus: options.includeStatus
1684
+ });
1685
+ }
1686
+ /** Fetch lightweight envelopes for a mailbox + range (for list views). */
1687
+ async fetchEnvelopesAsync(imap, mailbox, range) {
1688
+ return this.client.request(
1689
+ MAIL_COMMANDS.fetchEnvelopes,
1690
+ { imap, mailbox, range }
1691
+ );
1692
+ }
1693
+ /** Fetch a full message (envelope + body + attachment metadata) by UID. */
1694
+ async fetchMessageAsync(imap, mailbox, uid) {
1695
+ return this.client.request(MAIL_COMMANDS.fetchMessage, {
1696
+ imap,
1697
+ mailbox,
1698
+ uid
1699
+ });
1700
+ }
1701
+ /**
1702
+ * Set or unset IMAP flags. Use `flags=["\\Seen"]` + `add=true` to
1703
+ * mark messages as read; `add=false` removes the flag(s).
1704
+ */
1705
+ async setFlagsAsync(imap, mailbox, uids, flags, add) {
1706
+ return this.client.request(MAIL_COMMANDS.setFlags, {
1707
+ imap,
1708
+ mailbox,
1709
+ uids,
1710
+ flags,
1711
+ add
1712
+ });
1713
+ }
1714
+ /** Move messages between mailboxes. Falls back to COPY+EXPUNGE on servers without MOVE. */
1715
+ async moveMessagesAsync(imap, sourceMailbox, destinationMailbox, uids) {
1716
+ return this.client.request(MAIL_COMMANDS.moveMessages, {
1717
+ imap,
1718
+ sourceMailbox,
1719
+ destinationMailbox,
1720
+ uids
1721
+ });
1722
+ }
1723
+ /**
1724
+ * APPEND a base64-encoded RFC822 message into a mailbox. Combine
1725
+ * with `buildRfc822Async` to save drafts, or with the bytes returned
1726
+ * after `sendMessageAsync` to mirror the sent copy into "Sent".
1727
+ */
1728
+ async appendMessageAsync(imap, mailbox, rfc822Base64, flags) {
1729
+ return this.client.request(MAIL_COMMANDS.appendMessage, {
1730
+ imap,
1731
+ mailbox,
1732
+ rfc822Base64,
1733
+ flags
1734
+ });
1735
+ }
1736
+ /** Send a message via SMTP. Returns the assigned Message-ID (no angle brackets). */
1737
+ async sendMessageAsync(smtp, message) {
1738
+ return this.client.request(MAIL_COMMANDS.sendMessage, {
1739
+ smtp,
1740
+ message
1741
+ });
1742
+ }
1743
+ /**
1744
+ * Build RFC822 bytes for a message without sending — useful for
1745
+ * drafts that get APPENDed to a "Drafts" folder. Permission-wise
1746
+ * this is a fetch operation (no SMTP host involved).
1747
+ */
1748
+ async buildRfc822Async(imapHost, message) {
1749
+ return this.client.request(MAIL_COMMANDS.buildRfc822, {
1750
+ imapHost,
1751
+ message
1752
+ });
1753
+ }
1754
+ };
1755
+
1566
1756
  // src/client/tableName.ts
1567
1757
  function validatePublicKey(publicKey) {
1568
1758
  if (!publicKey || typeof publicKey !== "string" || publicKey.trim() === "") {
@@ -1649,6 +1839,7 @@ function parseTableName(fullTableName) {
1649
1839
  }
1650
1840
 
1651
1841
  // src/client/init.ts
1842
+ var PORT_HANDSHAKE_TIMEOUT_MS = 1e4;
1652
1843
  function isInIframe() {
1653
1844
  return window.self !== window.top;
1654
1845
  }
@@ -1905,17 +2096,20 @@ async function initIframeMode(ctx, log, messageHandler, request) {
1905
2096
  if (!isInIframe()) {
1906
2097
  throw new HaexVaultSdkError("NOT_IN_IFRAME" /* NOT_IN_IFRAME */, "errors.not_in_iframe");
1907
2098
  }
2099
+ const port = await waitForHostPortAsync(log);
1908
2100
  ctx.handlers.messageHandler = messageHandler;
1909
- window.addEventListener("message", messageHandler);
2101
+ port.addEventListener("message", messageHandler);
2102
+ port.start();
2103
+ port.postMessage({ type: HAEXSPACE_MESSAGE_TYPES.PORT_READY });
1910
2104
  ctx.state.isNativeWindow = false;
1911
2105
  ctx.state.initialized = true;
1912
- log("HaexVault SDK initialized in iframe mode");
2106
+ log("HaexVault SDK initialized in iframe mode (MessagePort transport)");
1913
2107
  if (ctx.config.manifest) {
1914
2108
  ctx.state.extensionInfo = {
1915
2109
  publicKey: ctx.config.manifest.publicKey,
1916
2110
  name: ctx.config.manifest.name,
1917
2111
  version: ctx.config.manifest.version,
1918
- displayName: ctx.config.manifest.name
2112
+ displayName: ctx.config.manifest.displayName ?? ctx.config.manifest.name
1919
2113
  };
1920
2114
  log("Extension info loaded from manifest:", ctx.state.extensionInfo);
1921
2115
  }
@@ -1923,7 +2117,42 @@ async function initIframeMode(ctx, log, messageHandler, request) {
1923
2117
  const context2 = await request(EXTENSION_COMMANDS.getContext);
1924
2118
  ctx.state.context = context2;
1925
2119
  log("Application context received:", context2);
1926
- return { context: context2 };
2120
+ return { context: context2, port };
2121
+ }
2122
+ function waitForHostPortAsync(log) {
2123
+ return new Promise((resolve, reject) => {
2124
+ let settled = false;
2125
+ const cleanup = () => {
2126
+ window.removeEventListener("message", handler);
2127
+ };
2128
+ const timeoutId = setTimeout(() => {
2129
+ if (settled) return;
2130
+ settled = true;
2131
+ cleanup();
2132
+ reject(
2133
+ new HaexVaultSdkError(
2134
+ "TIMEOUT" /* TIMEOUT */,
2135
+ "errors.port_handshake_timeout",
2136
+ { timeout: PORT_HANDSHAKE_TIMEOUT_MS }
2137
+ )
2138
+ );
2139
+ }, PORT_HANDSHAKE_TIMEOUT_MS);
2140
+ const handler = (event) => {
2141
+ const type = event.data?.type;
2142
+ if (type !== HAEXSPACE_MESSAGE_TYPES.PORT_INIT) return;
2143
+ const port = event.ports[0];
2144
+ if (!port) {
2145
+ log("PORT_INIT received but event.ports is empty \u2014 ignoring");
2146
+ return;
2147
+ }
2148
+ if (settled) return;
2149
+ settled = true;
2150
+ clearTimeout(timeoutId);
2151
+ cleanup();
2152
+ resolve(port);
2153
+ };
2154
+ window.addEventListener("message", handler);
2155
+ });
1927
2156
  }
1928
2157
  function sendDebugInfo(config) {
1929
2158
  if (!config.debug) return;
@@ -1947,7 +2176,15 @@ postMessage error: ${e}`);
1947
2176
  function generateRequestId(counter) {
1948
2177
  return `req_${counter}`;
1949
2178
  }
1950
- function sendPostMessage(method, params, requestId, config, extensionInfo2, pendingRequests) {
2179
+ function sendPostMessage(method, params, requestId, config, extensionInfo2, pendingRequests, port) {
2180
+ if (!port) {
2181
+ return Promise.reject(
2182
+ new HaexVaultSdkError(
2183
+ "EXTENSION_NOT_INITIALIZED" /* EXTENSION_NOT_INITIALIZED */,
2184
+ "errors.port_not_connected"
2185
+ )
2186
+ );
2187
+ }
1951
2188
  const request = {
1952
2189
  method,
1953
2190
  params,
@@ -1963,17 +2200,16 @@ function sendPostMessage(method, params, requestId, config, extensionInfo2, pend
1963
2200
  );
1964
2201
  }, config.timeout);
1965
2202
  pendingRequests.set(requestId, { resolve, reject, timeout });
1966
- const targetOrigin = "*";
1967
2203
  if (config.debug) {
1968
2204
  console.log("[SDK Debug] ========== Sending Request ==========");
1969
2205
  console.log("[SDK Debug] Request ID:", requestId);
1970
2206
  console.log("[SDK Debug] Method:", request.method);
1971
2207
  console.log("[SDK Debug] Params:", request.params);
1972
- console.log("[SDK Debug] Target origin:", targetOrigin);
2208
+ console.log("[SDK Debug] Transport: MessagePort");
1973
2209
  console.log("[SDK Debug] Extension info:", extensionInfo2);
1974
2210
  console.log("[SDK Debug] ========================================");
1975
2211
  }
1976
- window.parent.postMessage({ id: requestId, ...request }, targetOrigin);
2212
+ port.postMessage({ id: requestId, ...request });
1977
2213
  });
1978
2214
  }
1979
2215
  async function sendInvoke(method, params, config, _log) {
@@ -1992,11 +2228,6 @@ function createMessageHandler(config, pendingRequests, extensionInfo2, onEvent)
1992
2228
  return (event) => {
1993
2229
  if (config.debug) {
1994
2230
  console.log("[SDK Debug] ========== Message Received ==========");
1995
- console.log("[SDK Debug] Event origin:", event.origin);
1996
- console.log(
1997
- "[SDK Debug] Event source:",
1998
- event.source === window.parent ? "parent window" : "unknown"
1999
- );
2000
2231
  console.log("[SDK Debug] Event data:", event.data);
2001
2232
  console.log("[SDK Debug] Extension info loaded:", !!extensionInfo2());
2002
2233
  console.log(
@@ -2004,12 +2235,6 @@ function createMessageHandler(config, pendingRequests, extensionInfo2, onEvent)
2004
2235
  pendingRequests.size
2005
2236
  );
2006
2237
  }
2007
- if (event.source !== window.parent) {
2008
- if (config.debug) {
2009
- console.error("[SDK Debug] \u274C REJECTED: Message not from parent window!");
2010
- }
2011
- return;
2012
- }
2013
2238
  const data = event.data;
2014
2239
  if ("id" in data && pendingRequests.has(data.id)) {
2015
2240
  if (config.debug) {
@@ -2075,11 +2300,10 @@ function processEvent(event, log, eventListeners, onContextChanged, onExternalRe
2075
2300
  emitEvent(event, log, eventListeners);
2076
2301
  }
2077
2302
  function emitEvent(event, log, eventListeners) {
2078
- console.log("[HaexVault SDK] emitEvent called with:", event.type, event);
2079
- console.log("[HaexVault SDK] Registered event types:", Array.from(eventListeners.keys()));
2080
- log("Event received:", event);
2303
+ log("emitEvent called with:", event.type, event);
2304
+ log("Registered event types:", Array.from(eventListeners.keys()));
2081
2305
  const listeners = eventListeners.get(event.type);
2082
- console.log("[HaexVault SDK] Listeners for", event.type, ":", listeners?.size ?? 0);
2306
+ log("Listeners for", event.type, ":", listeners?.size ?? 0);
2083
2307
  if (listeners) {
2084
2308
  listeners.forEach((callback) => callback(event));
2085
2309
  }
@@ -2176,9 +2400,9 @@ function registerExternalHandler(action, handler, handlers, log) {
2176
2400
  };
2177
2401
  }
2178
2402
  async function handleExternalRequest(request, handlers, respond, log) {
2179
- console.log("[SDK Debug] handleExternalRequest called!");
2180
- console.log("[SDK Debug] Request:", JSON.stringify(request, null, 2));
2181
- console.log("[SDK Debug] Available handlers:", Array.from(handlers.keys()));
2403
+ log("handleExternalRequest called");
2404
+ log("Request:", request);
2405
+ log("Available handlers:", Array.from(handlers.keys()));
2182
2406
  log(`[ExternalRequest] Received request: ${request.action} from ${request.publicKey.substring(0, 20)}...`);
2183
2407
  const handler = handlers.get(request.action);
2184
2408
  if (!handler) {
@@ -2204,7 +2428,6 @@ async function handleExternalRequest(request, handlers, respond, log) {
2204
2428
  }
2205
2429
  }
2206
2430
  async function respondToExternalRequest(response, request) {
2207
- console.log("[SDK Debug] respondToExternalRequest called with:", JSON.stringify(response, null, 2));
2208
2431
  await request(EXTERNAL_BRIDGE_COMMANDS.respond, response);
2209
2432
  }
2210
2433
 
@@ -2231,6 +2454,13 @@ var HaexVaultSdk = class {
2231
2454
  this.reactiveSubscribers = /* @__PURE__ */ new Set();
2232
2455
  // Handlers
2233
2456
  this.messageHandler = null;
2457
+ /**
2458
+ * MessagePort obtained from the main window during iframe-mode handshake.
2459
+ * `null` until `initIframe()` completes successfully. Every outbound
2460
+ * request in iframe mode flows through this port; `sendPostMessage` rejects
2461
+ * if called before the handshake finishes.
2462
+ */
2463
+ this.hostPort = null;
2234
2464
  this.setupPromise = null;
2235
2465
  this.setupHook = null;
2236
2466
  // Public APIs
@@ -2255,11 +2485,17 @@ var HaexVaultSdk = class {
2255
2485
  this.localsend = new LocalSendAPI(this);
2256
2486
  this.spaces = new SpacesAPI(this);
2257
2487
  this.shell = new ShellAPI(this);
2488
+ this.passwords = new PasswordsAPI(this);
2489
+ this.mail = new MailAPI(this);
2258
2490
  installConsoleForwarding(this.config.debug);
2259
- this.readyPromise = new Promise((resolve) => {
2491
+ this.readyPromise = new Promise((resolve, reject) => {
2260
2492
  this.resolveReady = resolve;
2493
+ this.rejectReady = reject;
2494
+ });
2495
+ this.init().catch((error) => {
2496
+ this.log("Init failed:", error);
2497
+ this.rejectReady(error);
2261
2498
  });
2262
- this.init();
2263
2499
  }
2264
2500
  // ==========================================================================
2265
2501
  // Lifecycle
@@ -2287,9 +2523,14 @@ var HaexVaultSdk = class {
2287
2523
  return this.setupPromise;
2288
2524
  }
2289
2525
  destroy() {
2290
- if (this.messageHandler) {
2291
- window.removeEventListener("message", this.messageHandler);
2526
+ if (this.messageHandler && this.hostPort) {
2527
+ this.hostPort.removeEventListener("message", this.messageHandler);
2292
2528
  }
2529
+ if (this.hostPort) {
2530
+ this.hostPort.close();
2531
+ this.hostPort = null;
2532
+ }
2533
+ this.messageHandler = null;
2293
2534
  this.pendingRequests.forEach(({ timeout }) => clearTimeout(timeout));
2294
2535
  this.pendingRequests.clear();
2295
2536
  this.eventListeners.clear();
@@ -2404,7 +2645,15 @@ var HaexVaultSdk = class {
2404
2645
  return sendInvoke(method, paramsWithCredentials, this.config, this.log.bind(this));
2405
2646
  }
2406
2647
  const requestId = generateRequestId(++this.requestCounter);
2407
- return sendPostMessage(method, resolvedParams, requestId, this.config, this._extensionInfo, this.pendingRequests);
2648
+ return sendPostMessage(
2649
+ method,
2650
+ resolvedParams,
2651
+ requestId,
2652
+ this.config,
2653
+ this._extensionInfo,
2654
+ this.pendingRequests,
2655
+ this.hostPort
2656
+ );
2408
2657
  }
2409
2658
  // ==========================================================================
2410
2659
  // Private: Initialization
@@ -2471,7 +2720,7 @@ var HaexVaultSdk = class {
2471
2720
  () => this._extensionInfo,
2472
2721
  this.handleEvent.bind(this)
2473
2722
  );
2474
- const { context: context2 } = await initIframeMode(
2723
+ const { context: context2, port } = await initIframeMode(
2475
2724
  {
2476
2725
  config: this.config,
2477
2726
  state: {
@@ -2503,12 +2752,13 @@ var HaexVaultSdk = class {
2503
2752
  this.messageHandler,
2504
2753
  this.request.bind(this)
2505
2754
  );
2755
+ this.hostPort = port;
2506
2756
  if (this.config.manifest) {
2507
2757
  this._extensionInfo = {
2508
2758
  publicKey: this.config.manifest.publicKey,
2509
2759
  name: this.config.manifest.name,
2510
2760
  version: this.config.manifest.version,
2511
- displayName: this.config.manifest.name
2761
+ displayName: this.config.manifest.displayName ?? this.config.manifest.name
2512
2762
  };
2513
2763
  this.notifySubscribersInternal();
2514
2764
  }