@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/index.mjs CHANGED
@@ -539,7 +539,24 @@ var HAEXSPACE_MESSAGE_TYPES = {
539
539
  /** Debug message for development/troubleshooting */
540
540
  DEBUG: "haexspace:debug",
541
541
  /** Console forwarding from extension iframe */
542
- CONSOLE_FORWARD: "console.forward"
542
+ CONSOLE_FORWARD: "console.forward",
543
+ /**
544
+ * Sent from main window to iframe on the shared window listener, carrying
545
+ * one `MessagePort` in `event.ports[0]`. Once received, the SDK switches
546
+ * to port-based messaging and never reads the window listener again.
547
+ *
548
+ * Payload: `{ type: PORT_INIT }` — no data. The port itself is the payload.
549
+ */
550
+ PORT_INIT: "haexspace:port:init",
551
+ /**
552
+ * Sent from SDK to main window *over the MessagePort* after the port is
553
+ * installed. Main uses this to mark the iframe as ready and flush any
554
+ * events buffered during the handshake window. Only valid on the port —
555
+ * a READY sent over window.postMessage is ignored.
556
+ *
557
+ * Payload: `{ type: PORT_READY }` — no data.
558
+ */
559
+ PORT_READY: "haexspace:port:ready"
543
560
  };
544
561
 
545
562
  // src/polyfills/debug.ts
@@ -1030,6 +1047,40 @@ var SHELL_COMMANDS = {
1030
1047
  close: "extension_shell_close"
1031
1048
  };
1032
1049
 
1050
+ // src/commands/passwords.ts
1051
+ var PASSWORD_COMMANDS = {
1052
+ /** List items (no secrets) within the extension's tag scope */
1053
+ list: "extension_password_list",
1054
+ /** Read full item including secrets, by id */
1055
+ read: "extension_password_read",
1056
+ /** Create item — must include >=1 tag in scope */
1057
+ create: "extension_password_create",
1058
+ /** Update item — keeps >=1 tag in scope */
1059
+ update: "extension_password_update",
1060
+ /** Delete item — must be in scope */
1061
+ delete: "extension_password_delete"
1062
+ };
1063
+
1064
+ // src/commands/mail.ts
1065
+ var MAIL_COMMANDS = {
1066
+ /** LIST mailboxes + optional STATUS counts */
1067
+ listMailboxes: "extension_mail_list_mailboxes",
1068
+ /** Lightweight envelope fetch for list views */
1069
+ fetchEnvelopes: "extension_mail_fetch_envelopes",
1070
+ /** Full message fetch (envelope + body + attachment metadata) */
1071
+ fetchMessage: "extension_mail_fetch_message",
1072
+ /** Set or unset IMAP flags on a UID set */
1073
+ setFlags: "extension_mail_set_flags",
1074
+ /** MOVE messages between mailboxes (COPY+EXPUNGE fallback) */
1075
+ moveMessages: "extension_mail_move_messages",
1076
+ /** APPEND a base64-encoded RFC822 message into a mailbox */
1077
+ appendMessage: "extension_mail_append_message",
1078
+ /** SMTP send. Returns the assigned Message-ID. */
1079
+ sendMessage: "extension_mail_send_message",
1080
+ /** Build RFC822 bytes without sending (for Drafts via APPEND) */
1081
+ buildRfc822: "extension_mail_build_rfc822"
1082
+ };
1083
+
1033
1084
  // src/commands/index.ts
1034
1085
  var TAURI_COMMANDS = {
1035
1086
  database: DATABASE_COMMANDS,
@@ -1042,7 +1093,9 @@ var TAURI_COMMANDS = {
1042
1093
  remoteStorage: REMOTE_STORAGE_COMMANDS,
1043
1094
  localsend: LOCALSEND_COMMANDS,
1044
1095
  spaces: SPACE_COMMANDS,
1045
- shell: SHELL_COMMANDS
1096
+ shell: SHELL_COMMANDS,
1097
+ passwords: PASSWORD_COMMANDS,
1098
+ mail: MAIL_COMMANDS
1046
1099
  };
1047
1100
 
1048
1101
  // src/api/storage.ts
@@ -1068,6 +1121,12 @@ var StorageAPI = class {
1068
1121
  };
1069
1122
 
1070
1123
  // src/api/database.ts
1124
+ function quoteIdent(identifier) {
1125
+ if (identifier.startsWith('"') && identifier.endsWith('"')) {
1126
+ return identifier;
1127
+ }
1128
+ return `"${identifier.replace(/"/g, '""')}"`;
1129
+ }
1071
1130
  var DatabaseAPI = class {
1072
1131
  constructor(client) {
1073
1132
  this.client = client;
@@ -1098,11 +1157,11 @@ var DatabaseAPI = class {
1098
1157
  });
1099
1158
  }
1100
1159
  async createTable(tableName, columns) {
1101
- const query = `CREATE TABLE IF NOT EXISTS ${tableName} (${columns})`;
1160
+ const query = `CREATE TABLE IF NOT EXISTS ${quoteIdent(tableName)} (${columns})`;
1102
1161
  await this.execute(query);
1103
1162
  }
1104
1163
  async dropTable(tableName) {
1105
- const query = `DROP TABLE IF EXISTS ${tableName}`;
1164
+ const query = `DROP TABLE IF EXISTS ${quoteIdent(tableName)}`;
1106
1165
  await this.execute(query);
1107
1166
  }
1108
1167
  /**
@@ -1131,18 +1190,17 @@ var DatabaseAPI = class {
1131
1190
  async insert(tableName, data) {
1132
1191
  const keys = Object.keys(data);
1133
1192
  const values = Object.values(data);
1193
+ const quotedCols = keys.map(quoteIdent).join(", ");
1134
1194
  const placeholders = keys.map(() => "?").join(", ");
1135
- const query = `INSERT INTO ${tableName} (${keys.join(
1136
- ", "
1137
- )}) VALUES (${placeholders})`;
1195
+ const query = `INSERT INTO ${quoteIdent(tableName)} (${quotedCols}) VALUES (${placeholders})`;
1138
1196
  const result = await this.execute(query, values);
1139
1197
  return result.lastInsertId ?? -1;
1140
1198
  }
1141
1199
  async update(tableName, data, where, whereParams) {
1142
1200
  const keys = Object.keys(data);
1143
1201
  const values = Object.values(data);
1144
- const setClause = keys.map((key) => `${key} = ?`).join(", ");
1145
- const query = `UPDATE ${tableName} SET ${setClause} WHERE ${where}`;
1202
+ const setClause = keys.map((key) => `${quoteIdent(key)} = ?`).join(", ");
1203
+ const query = `UPDATE ${quoteIdent(tableName)} SET ${setClause} WHERE ${where}`;
1146
1204
  const result = await this.execute(query, [
1147
1205
  ...values,
1148
1206
  ...whereParams || []
@@ -1150,12 +1208,12 @@ var DatabaseAPI = class {
1150
1208
  return result.rowsAffected;
1151
1209
  }
1152
1210
  async delete(tableName, where, whereParams) {
1153
- const query = `DELETE FROM ${tableName} WHERE ${where}`;
1211
+ const query = `DELETE FROM ${quoteIdent(tableName)} WHERE ${where}`;
1154
1212
  const result = await this.execute(query, whereParams);
1155
1213
  return result.rowsAffected;
1156
1214
  }
1157
1215
  async count(tableName, where, whereParams) {
1158
- const query = where ? `SELECT COUNT(*) as count FROM ${tableName} WHERE ${where}` : `SELECT COUNT(*) as count FROM ${tableName}`;
1216
+ const query = where ? `SELECT COUNT(*) as count FROM ${quoteIdent(tableName)} WHERE ${where}` : `SELECT COUNT(*) as count FROM ${quoteIdent(tableName)}`;
1159
1217
  const result = await this.queryOne(query, whereParams);
1160
1218
  return result?.count ?? 0;
1161
1219
  }
@@ -1986,6 +2044,140 @@ var ShellAPI = class {
1986
2044
  }
1987
2045
  };
1988
2046
 
2047
+ // src/api/passwords.ts
2048
+ var PasswordsAPI = class {
2049
+ constructor(client) {
2050
+ this.client = client;
2051
+ }
2052
+ /** List items in scope — summaries only, no secrets. */
2053
+ async listAsync() {
2054
+ return this.client.request(
2055
+ PASSWORD_COMMANDS.list,
2056
+ {}
2057
+ );
2058
+ }
2059
+ /** Read a single item by id with full secrets. */
2060
+ async readAsync(itemId) {
2061
+ return this.client.request(PASSWORD_COMMANDS.read, {
2062
+ itemId
2063
+ });
2064
+ }
2065
+ /**
2066
+ * Create a new password item. `input.tags` must contain at least one
2067
+ * tag within the extension's permission scope, otherwise the write
2068
+ * is rejected as a security violation.
2069
+ *
2070
+ * Returns the new item id.
2071
+ */
2072
+ async createAsync(input) {
2073
+ return this.client.request(PASSWORD_COMMANDS.create, { input });
2074
+ }
2075
+ /**
2076
+ * Update an existing item. The item must already be in scope, and
2077
+ * the new tag set must keep at least one tag in scope (extensions
2078
+ * cannot orphan an item out of their own reach).
2079
+ */
2080
+ async updateAsync(itemId, input) {
2081
+ return this.client.request(PASSWORD_COMMANDS.update, {
2082
+ itemId,
2083
+ input
2084
+ });
2085
+ }
2086
+ /** Delete an item by id. Item must be in scope. */
2087
+ async deleteAsync(itemId) {
2088
+ return this.client.request(PASSWORD_COMMANDS.delete, { itemId });
2089
+ }
2090
+ };
2091
+
2092
+ // src/api/mail.ts
2093
+ var MailAPI = class {
2094
+ constructor(client) {
2095
+ this.client = client;
2096
+ }
2097
+ /**
2098
+ * LIST mailboxes for an IMAP account. Pass `includeStatus=true` for
2099
+ * EXISTS/UNSEEN/UIDVALIDITY/UIDNEXT per box (one extra round-trip
2100
+ * per mailbox — fine for typical accounts, expensive for large
2101
+ * trees).
2102
+ */
2103
+ async listMailboxesAsync(imap, options = {}) {
2104
+ return this.client.request(MAIL_COMMANDS.listMailboxes, {
2105
+ imap,
2106
+ reference: options.reference,
2107
+ pattern: options.pattern,
2108
+ includeStatus: options.includeStatus
2109
+ });
2110
+ }
2111
+ /** Fetch lightweight envelopes for a mailbox + range (for list views). */
2112
+ async fetchEnvelopesAsync(imap, mailbox, range) {
2113
+ return this.client.request(
2114
+ MAIL_COMMANDS.fetchEnvelopes,
2115
+ { imap, mailbox, range }
2116
+ );
2117
+ }
2118
+ /** Fetch a full message (envelope + body + attachment metadata) by UID. */
2119
+ async fetchMessageAsync(imap, mailbox, uid) {
2120
+ return this.client.request(MAIL_COMMANDS.fetchMessage, {
2121
+ imap,
2122
+ mailbox,
2123
+ uid
2124
+ });
2125
+ }
2126
+ /**
2127
+ * Set or unset IMAP flags. Use `flags=["\\Seen"]` + `add=true` to
2128
+ * mark messages as read; `add=false` removes the flag(s).
2129
+ */
2130
+ async setFlagsAsync(imap, mailbox, uids, flags, add) {
2131
+ return this.client.request(MAIL_COMMANDS.setFlags, {
2132
+ imap,
2133
+ mailbox,
2134
+ uids,
2135
+ flags,
2136
+ add
2137
+ });
2138
+ }
2139
+ /** Move messages between mailboxes. Falls back to COPY+EXPUNGE on servers without MOVE. */
2140
+ async moveMessagesAsync(imap, sourceMailbox, destinationMailbox, uids) {
2141
+ return this.client.request(MAIL_COMMANDS.moveMessages, {
2142
+ imap,
2143
+ sourceMailbox,
2144
+ destinationMailbox,
2145
+ uids
2146
+ });
2147
+ }
2148
+ /**
2149
+ * APPEND a base64-encoded RFC822 message into a mailbox. Combine
2150
+ * with `buildRfc822Async` to save drafts, or with the bytes returned
2151
+ * after `sendMessageAsync` to mirror the sent copy into "Sent".
2152
+ */
2153
+ async appendMessageAsync(imap, mailbox, rfc822Base64, flags) {
2154
+ return this.client.request(MAIL_COMMANDS.appendMessage, {
2155
+ imap,
2156
+ mailbox,
2157
+ rfc822Base64,
2158
+ flags
2159
+ });
2160
+ }
2161
+ /** Send a message via SMTP. Returns the assigned Message-ID (no angle brackets). */
2162
+ async sendMessageAsync(smtp, message) {
2163
+ return this.client.request(MAIL_COMMANDS.sendMessage, {
2164
+ smtp,
2165
+ message
2166
+ });
2167
+ }
2168
+ /**
2169
+ * Build RFC822 bytes for a message without sending — useful for
2170
+ * drafts that get APPENDed to a "Drafts" folder. Permission-wise
2171
+ * this is a fetch operation (no SMTP host involved).
2172
+ */
2173
+ async buildRfc822Async(imapHost, message) {
2174
+ return this.client.request(MAIL_COMMANDS.buildRfc822, {
2175
+ imapHost,
2176
+ message
2177
+ });
2178
+ }
2179
+ };
2180
+
1989
2181
  // src/client/tableName.ts
1990
2182
  function validatePublicKey(publicKey) {
1991
2183
  if (!publicKey || typeof publicKey !== "string" || publicKey.trim() === "") {
@@ -2072,6 +2264,7 @@ function parseTableName(fullTableName) {
2072
2264
  }
2073
2265
 
2074
2266
  // src/client/init.ts
2267
+ var PORT_HANDSHAKE_TIMEOUT_MS = 1e4;
2075
2268
  function isInIframe() {
2076
2269
  return window.self !== window.top;
2077
2270
  }
@@ -2328,17 +2521,20 @@ async function initIframeMode(ctx, log, messageHandler, request) {
2328
2521
  if (!isInIframe()) {
2329
2522
  throw new HaexVaultSdkError("NOT_IN_IFRAME" /* NOT_IN_IFRAME */, "errors.not_in_iframe");
2330
2523
  }
2524
+ const port = await waitForHostPortAsync(log);
2331
2525
  ctx.handlers.messageHandler = messageHandler;
2332
- window.addEventListener("message", messageHandler);
2526
+ port.addEventListener("message", messageHandler);
2527
+ port.start();
2528
+ port.postMessage({ type: HAEXSPACE_MESSAGE_TYPES.PORT_READY });
2333
2529
  ctx.state.isNativeWindow = false;
2334
2530
  ctx.state.initialized = true;
2335
- log("HaexVault SDK initialized in iframe mode");
2531
+ log("HaexVault SDK initialized in iframe mode (MessagePort transport)");
2336
2532
  if (ctx.config.manifest) {
2337
2533
  ctx.state.extensionInfo = {
2338
2534
  publicKey: ctx.config.manifest.publicKey,
2339
2535
  name: ctx.config.manifest.name,
2340
2536
  version: ctx.config.manifest.version,
2341
- displayName: ctx.config.manifest.name
2537
+ displayName: ctx.config.manifest.displayName ?? ctx.config.manifest.name
2342
2538
  };
2343
2539
  log("Extension info loaded from manifest:", ctx.state.extensionInfo);
2344
2540
  }
@@ -2346,7 +2542,42 @@ async function initIframeMode(ctx, log, messageHandler, request) {
2346
2542
  const context = await request(EXTENSION_COMMANDS.getContext);
2347
2543
  ctx.state.context = context;
2348
2544
  log("Application context received:", context);
2349
- return { context };
2545
+ return { context, port };
2546
+ }
2547
+ function waitForHostPortAsync(log) {
2548
+ return new Promise((resolve, reject) => {
2549
+ let settled = false;
2550
+ const cleanup = () => {
2551
+ window.removeEventListener("message", handler);
2552
+ };
2553
+ const timeoutId = setTimeout(() => {
2554
+ if (settled) return;
2555
+ settled = true;
2556
+ cleanup();
2557
+ reject(
2558
+ new HaexVaultSdkError(
2559
+ "TIMEOUT" /* TIMEOUT */,
2560
+ "errors.port_handshake_timeout",
2561
+ { timeout: PORT_HANDSHAKE_TIMEOUT_MS }
2562
+ )
2563
+ );
2564
+ }, PORT_HANDSHAKE_TIMEOUT_MS);
2565
+ const handler = (event) => {
2566
+ const type = event.data?.type;
2567
+ if (type !== HAEXSPACE_MESSAGE_TYPES.PORT_INIT) return;
2568
+ const port = event.ports[0];
2569
+ if (!port) {
2570
+ log("PORT_INIT received but event.ports is empty \u2014 ignoring");
2571
+ return;
2572
+ }
2573
+ if (settled) return;
2574
+ settled = true;
2575
+ clearTimeout(timeoutId);
2576
+ cleanup();
2577
+ resolve(port);
2578
+ };
2579
+ window.addEventListener("message", handler);
2580
+ });
2350
2581
  }
2351
2582
  function sendDebugInfo(config) {
2352
2583
  if (!config.debug) return;
@@ -2370,7 +2601,15 @@ postMessage error: ${e}`);
2370
2601
  function generateRequestId(counter) {
2371
2602
  return `req_${counter}`;
2372
2603
  }
2373
- function sendPostMessage(method, params, requestId, config, extensionInfo, pendingRequests) {
2604
+ function sendPostMessage(method, params, requestId, config, extensionInfo, pendingRequests, port) {
2605
+ if (!port) {
2606
+ return Promise.reject(
2607
+ new HaexVaultSdkError(
2608
+ "EXTENSION_NOT_INITIALIZED" /* EXTENSION_NOT_INITIALIZED */,
2609
+ "errors.port_not_connected"
2610
+ )
2611
+ );
2612
+ }
2374
2613
  const request = {
2375
2614
  method,
2376
2615
  params,
@@ -2386,17 +2625,16 @@ function sendPostMessage(method, params, requestId, config, extensionInfo, pendi
2386
2625
  );
2387
2626
  }, config.timeout);
2388
2627
  pendingRequests.set(requestId, { resolve, reject, timeout });
2389
- const targetOrigin = "*";
2390
2628
  if (config.debug) {
2391
2629
  console.log("[SDK Debug] ========== Sending Request ==========");
2392
2630
  console.log("[SDK Debug] Request ID:", requestId);
2393
2631
  console.log("[SDK Debug] Method:", request.method);
2394
2632
  console.log("[SDK Debug] Params:", request.params);
2395
- console.log("[SDK Debug] Target origin:", targetOrigin);
2633
+ console.log("[SDK Debug] Transport: MessagePort");
2396
2634
  console.log("[SDK Debug] Extension info:", extensionInfo);
2397
2635
  console.log("[SDK Debug] ========================================");
2398
2636
  }
2399
- window.parent.postMessage({ id: requestId, ...request }, targetOrigin);
2637
+ port.postMessage({ id: requestId, ...request });
2400
2638
  });
2401
2639
  }
2402
2640
  async function sendInvoke(method, params, config, _log) {
@@ -2415,11 +2653,6 @@ function createMessageHandler(config, pendingRequests, extensionInfo, onEvent) {
2415
2653
  return (event) => {
2416
2654
  if (config.debug) {
2417
2655
  console.log("[SDK Debug] ========== Message Received ==========");
2418
- console.log("[SDK Debug] Event origin:", event.origin);
2419
- console.log(
2420
- "[SDK Debug] Event source:",
2421
- event.source === window.parent ? "parent window" : "unknown"
2422
- );
2423
2656
  console.log("[SDK Debug] Event data:", event.data);
2424
2657
  console.log("[SDK Debug] Extension info loaded:", !!extensionInfo());
2425
2658
  console.log(
@@ -2427,12 +2660,6 @@ function createMessageHandler(config, pendingRequests, extensionInfo, onEvent) {
2427
2660
  pendingRequests.size
2428
2661
  );
2429
2662
  }
2430
- if (event.source !== window.parent) {
2431
- if (config.debug) {
2432
- console.error("[SDK Debug] \u274C REJECTED: Message not from parent window!");
2433
- }
2434
- return;
2435
- }
2436
2663
  const data = event.data;
2437
2664
  if ("id" in data && pendingRequests.has(data.id)) {
2438
2665
  if (config.debug) {
@@ -2498,11 +2725,10 @@ function processEvent(event, log, eventListeners, onContextChanged, onExternalRe
2498
2725
  emitEvent(event, log, eventListeners);
2499
2726
  }
2500
2727
  function emitEvent(event, log, eventListeners) {
2501
- console.log("[HaexVault SDK] emitEvent called with:", event.type, event);
2502
- console.log("[HaexVault SDK] Registered event types:", Array.from(eventListeners.keys()));
2503
- log("Event received:", event);
2728
+ log("emitEvent called with:", event.type, event);
2729
+ log("Registered event types:", Array.from(eventListeners.keys()));
2504
2730
  const listeners = eventListeners.get(event.type);
2505
- console.log("[HaexVault SDK] Listeners for", event.type, ":", listeners?.size ?? 0);
2731
+ log("Listeners for", event.type, ":", listeners?.size ?? 0);
2506
2732
  if (listeners) {
2507
2733
  listeners.forEach((callback) => callback(event));
2508
2734
  }
@@ -2599,9 +2825,9 @@ function registerExternalHandler(action, handler, handlers, log) {
2599
2825
  };
2600
2826
  }
2601
2827
  async function handleExternalRequest(request, handlers, respond, log) {
2602
- console.log("[SDK Debug] handleExternalRequest called!");
2603
- console.log("[SDK Debug] Request:", JSON.stringify(request, null, 2));
2604
- console.log("[SDK Debug] Available handlers:", Array.from(handlers.keys()));
2828
+ log("handleExternalRequest called");
2829
+ log("Request:", request);
2830
+ log("Available handlers:", Array.from(handlers.keys()));
2605
2831
  log(`[ExternalRequest] Received request: ${request.action} from ${request.publicKey.substring(0, 20)}...`);
2606
2832
  const handler = handlers.get(request.action);
2607
2833
  if (!handler) {
@@ -2627,7 +2853,6 @@ async function handleExternalRequest(request, handlers, respond, log) {
2627
2853
  }
2628
2854
  }
2629
2855
  async function respondToExternalRequest(response, request) {
2630
- console.log("[SDK Debug] respondToExternalRequest called with:", JSON.stringify(response, null, 2));
2631
2856
  await request(EXTERNAL_BRIDGE_COMMANDS.respond, response);
2632
2857
  }
2633
2858
 
@@ -2654,6 +2879,13 @@ var HaexVaultSdk = class {
2654
2879
  this.reactiveSubscribers = /* @__PURE__ */ new Set();
2655
2880
  // Handlers
2656
2881
  this.messageHandler = null;
2882
+ /**
2883
+ * MessagePort obtained from the main window during iframe-mode handshake.
2884
+ * `null` until `initIframe()` completes successfully. Every outbound
2885
+ * request in iframe mode flows through this port; `sendPostMessage` rejects
2886
+ * if called before the handshake finishes.
2887
+ */
2888
+ this.hostPort = null;
2657
2889
  this.setupPromise = null;
2658
2890
  this.setupHook = null;
2659
2891
  // Public APIs
@@ -2678,11 +2910,17 @@ var HaexVaultSdk = class {
2678
2910
  this.localsend = new LocalSendAPI(this);
2679
2911
  this.spaces = new SpacesAPI(this);
2680
2912
  this.shell = new ShellAPI(this);
2913
+ this.passwords = new PasswordsAPI(this);
2914
+ this.mail = new MailAPI(this);
2681
2915
  installConsoleForwarding(this.config.debug);
2682
- this.readyPromise = new Promise((resolve) => {
2916
+ this.readyPromise = new Promise((resolve, reject) => {
2683
2917
  this.resolveReady = resolve;
2918
+ this.rejectReady = reject;
2919
+ });
2920
+ this.init().catch((error) => {
2921
+ this.log("Init failed:", error);
2922
+ this.rejectReady(error);
2684
2923
  });
2685
- this.init();
2686
2924
  }
2687
2925
  // ==========================================================================
2688
2926
  // Lifecycle
@@ -2710,9 +2948,14 @@ var HaexVaultSdk = class {
2710
2948
  return this.setupPromise;
2711
2949
  }
2712
2950
  destroy() {
2713
- if (this.messageHandler) {
2714
- window.removeEventListener("message", this.messageHandler);
2951
+ if (this.messageHandler && this.hostPort) {
2952
+ this.hostPort.removeEventListener("message", this.messageHandler);
2715
2953
  }
2954
+ if (this.hostPort) {
2955
+ this.hostPort.close();
2956
+ this.hostPort = null;
2957
+ }
2958
+ this.messageHandler = null;
2716
2959
  this.pendingRequests.forEach(({ timeout }) => clearTimeout(timeout));
2717
2960
  this.pendingRequests.clear();
2718
2961
  this.eventListeners.clear();
@@ -2827,7 +3070,15 @@ var HaexVaultSdk = class {
2827
3070
  return sendInvoke(method, paramsWithCredentials, this.config, this.log.bind(this));
2828
3071
  }
2829
3072
  const requestId = generateRequestId(++this.requestCounter);
2830
- return sendPostMessage(method, resolvedParams, requestId, this.config, this._extensionInfo, this.pendingRequests);
3073
+ return sendPostMessage(
3074
+ method,
3075
+ resolvedParams,
3076
+ requestId,
3077
+ this.config,
3078
+ this._extensionInfo,
3079
+ this.pendingRequests,
3080
+ this.hostPort
3081
+ );
2831
3082
  }
2832
3083
  // ==========================================================================
2833
3084
  // Private: Initialization
@@ -2894,7 +3145,7 @@ var HaexVaultSdk = class {
2894
3145
  () => this._extensionInfo,
2895
3146
  this.handleEvent.bind(this)
2896
3147
  );
2897
- const { context } = await initIframeMode(
3148
+ const { context, port } = await initIframeMode(
2898
3149
  {
2899
3150
  config: this.config,
2900
3151
  state: {
@@ -2926,12 +3177,13 @@ var HaexVaultSdk = class {
2926
3177
  this.messageHandler,
2927
3178
  this.request.bind(this)
2928
3179
  );
3180
+ this.hostPort = port;
2929
3181
  if (this.config.manifest) {
2930
3182
  this._extensionInfo = {
2931
3183
  publicKey: this.config.manifest.publicKey,
2932
3184
  name: this.config.manifest.name,
2933
3185
  version: this.config.manifest.version,
2934
- displayName: this.config.manifest.name
3186
+ displayName: this.config.manifest.displayName ?? this.config.manifest.name
2935
3187
  };
2936
3188
  this.notifySubscribersInternal();
2937
3189
  }
@@ -3586,6 +3838,6 @@ function createHaexVaultSdk(config = {}) {
3586
3838
  return new HaexVaultSdk(config);
3587
3839
  }
3588
3840
 
3589
- export { COSE_ALGORITHM, DEFAULT_TIMEOUT, DatabaseAPI, EXTERNAL_EVENTS, ErrorCode, ExternalConnectionErrorCode, ExternalConnectionState, FilesystemAPI, HAEXSPACE_MESSAGE_TYPES, HAEXTENSION_EVENTS, HaexVaultSdk, HaexVaultSdkError, KEY_AGREEMENT_ALGO, KnownPath, LOCALSEND_EVENTS, LocalSendAPI, PermissionErrorCode, PermissionStatus, PermissionsAPI, RemoteStorageAPI, SHELL_EVENTS, SIGNING_ALGO, SPACE_COMMANDS, ShellAPI, SpacesAPI, TABLE_SEPARATOR, TAURI_COMMANDS, WebAPI, arrayBufferToBase64, base58btcDecode, base58btcEncode, base64ToArrayBuffer, canExternalClientSendRequests, createHaexVaultSdk, decryptCrdtData, decryptPrivateKeyAsync, decryptSpaceNameAsync, decryptString, decryptVaultKey, decryptVaultName, decryptWithPrivateKeyAsync, deriveKeyFromPassword, didKeyToPublicKeyAsync, encryptCrdtData, encryptPrivateKeyAsync, encryptSpaceNameAsync, encryptString, encryptVaultKey, encryptWithPublicKeyAsync, exportKeyPairAsync, exportPrivateKeyAsync, exportPublicKeyAsync, exportPublicKeyCoseAsync, exportUserKeypairAsync, generateCredentialId, generateIdentityAsync, generatePasskeyPairAsync, generateSpaceKey, generateUserKeypairAsync, generateVaultKey, getTableName, hexToBytes, importPrivateKeyAsync, importPrivateKeyForKeyAgreementAsync, importPublicKeyAsync, importPublicKeyForKeyAgreementAsync, importUserPrivateKeyAsync, importUserPublicKeyAsync, installBaseTag, installCookiePolyfill, installHistoryPolyfill, installLocalStoragePolyfill, installPolyfills, installSessionStoragePolyfill, isExternalClientConnected, isPermissionDeniedError, isPermissionError, isPermissionPromptError, publicKeyToDidKeyAsync, signClaimPresentationAsync, signRecordAsync, signSpaceChallengeAsync, signWithPasskeyAsync, sortObjectKeysRecursively, unwrapKey, verifyClaimPresentationAsync, verifyExtensionSignature, verifyRecordSignatureAsync, verifySpaceChallengeAsync, verifyWithPasskeyAsync, wrapKey };
3841
+ export { COSE_ALGORITHM, DEFAULT_TIMEOUT, DatabaseAPI, EXTERNAL_EVENTS, ErrorCode, ExternalConnectionErrorCode, ExternalConnectionState, FilesystemAPI, HAEXSPACE_MESSAGE_TYPES, HAEXTENSION_EVENTS, HaexVaultSdk, HaexVaultSdkError, KEY_AGREEMENT_ALGO, KnownPath, LOCALSEND_EVENTS, LocalSendAPI, MAIL_COMMANDS, MailAPI, PASSWORD_COMMANDS, PasswordsAPI, PermissionErrorCode, PermissionStatus, PermissionsAPI, RemoteStorageAPI, SHELL_EVENTS, SIGNING_ALGO, SPACE_COMMANDS, ShellAPI, SpacesAPI, TABLE_SEPARATOR, TAURI_COMMANDS, WebAPI, arrayBufferToBase64, base58btcDecode, base58btcEncode, base64ToArrayBuffer, canExternalClientSendRequests, createHaexVaultSdk, decryptCrdtData, decryptPrivateKeyAsync, decryptSpaceNameAsync, decryptString, decryptVaultKey, decryptVaultName, decryptWithPrivateKeyAsync, deriveKeyFromPassword, didKeyToPublicKeyAsync, encryptCrdtData, encryptPrivateKeyAsync, encryptSpaceNameAsync, encryptString, encryptVaultKey, encryptWithPublicKeyAsync, exportKeyPairAsync, exportPrivateKeyAsync, exportPublicKeyAsync, exportPublicKeyCoseAsync, exportUserKeypairAsync, generateCredentialId, generateIdentityAsync, generatePasskeyPairAsync, generateSpaceKey, generateUserKeypairAsync, generateVaultKey, getTableName, hexToBytes, importPrivateKeyAsync, importPrivateKeyForKeyAgreementAsync, importPublicKeyAsync, importPublicKeyForKeyAgreementAsync, importUserPrivateKeyAsync, importUserPublicKeyAsync, installBaseTag, installCookiePolyfill, installHistoryPolyfill, installLocalStoragePolyfill, installPolyfills, installSessionStoragePolyfill, isExternalClientConnected, isPermissionDeniedError, isPermissionError, isPermissionPromptError, publicKeyToDidKeyAsync, signClaimPresentationAsync, signRecordAsync, signSpaceChallengeAsync, signWithPasskeyAsync, sortObjectKeysRecursively, unwrapKey, verifyClaimPresentationAsync, verifyExtensionSignature, verifyRecordSignatureAsync, verifySpaceChallengeAsync, verifyWithPasskeyAsync, wrapKey };
3590
3842
  //# sourceMappingURL=index.mjs.map
3591
3843
  //# sourceMappingURL=index.mjs.map