@haex-space/vault-sdk 2.9.3 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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
@@ -1094,7 +1111,7 @@ var DatabaseAPI = class {
1094
1111
  }
1095
1112
  async transaction(statements) {
1096
1113
  await this.client.request(DATABASE_COMMANDS.transaction, {
1097
- statements
1114
+ statements: statements.map((s) => [s.sql, s.params || []])
1098
1115
  });
1099
1116
  }
1100
1117
  async createTable(tableName, columns) {
@@ -2072,6 +2089,7 @@ function parseTableName(fullTableName) {
2072
2089
  }
2073
2090
 
2074
2091
  // src/client/init.ts
2092
+ var PORT_HANDSHAKE_TIMEOUT_MS = 1e4;
2075
2093
  function isInIframe() {
2076
2094
  return window.self !== window.top;
2077
2095
  }
@@ -2328,11 +2346,14 @@ async function initIframeMode(ctx, log, messageHandler, request) {
2328
2346
  if (!isInIframe()) {
2329
2347
  throw new HaexVaultSdkError("NOT_IN_IFRAME" /* NOT_IN_IFRAME */, "errors.not_in_iframe");
2330
2348
  }
2349
+ const port = await waitForHostPortAsync(log);
2331
2350
  ctx.handlers.messageHandler = messageHandler;
2332
- window.addEventListener("message", messageHandler);
2351
+ port.addEventListener("message", messageHandler);
2352
+ port.start();
2353
+ port.postMessage({ type: HAEXSPACE_MESSAGE_TYPES.PORT_READY });
2333
2354
  ctx.state.isNativeWindow = false;
2334
2355
  ctx.state.initialized = true;
2335
- log("HaexVault SDK initialized in iframe mode");
2356
+ log("HaexVault SDK initialized in iframe mode (MessagePort transport)");
2336
2357
  if (ctx.config.manifest) {
2337
2358
  ctx.state.extensionInfo = {
2338
2359
  publicKey: ctx.config.manifest.publicKey,
@@ -2346,7 +2367,42 @@ async function initIframeMode(ctx, log, messageHandler, request) {
2346
2367
  const context = await request(EXTENSION_COMMANDS.getContext);
2347
2368
  ctx.state.context = context;
2348
2369
  log("Application context received:", context);
2349
- return { context };
2370
+ return { context, port };
2371
+ }
2372
+ function waitForHostPortAsync(log) {
2373
+ return new Promise((resolve, reject) => {
2374
+ let settled = false;
2375
+ const cleanup = () => {
2376
+ window.removeEventListener("message", handler);
2377
+ };
2378
+ const timeoutId = setTimeout(() => {
2379
+ if (settled) return;
2380
+ settled = true;
2381
+ cleanup();
2382
+ reject(
2383
+ new HaexVaultSdkError(
2384
+ "TIMEOUT" /* TIMEOUT */,
2385
+ "errors.port_handshake_timeout",
2386
+ { timeout: PORT_HANDSHAKE_TIMEOUT_MS }
2387
+ )
2388
+ );
2389
+ }, PORT_HANDSHAKE_TIMEOUT_MS);
2390
+ const handler = (event) => {
2391
+ const type = event.data?.type;
2392
+ if (type !== HAEXSPACE_MESSAGE_TYPES.PORT_INIT) return;
2393
+ const port = event.ports[0];
2394
+ if (!port) {
2395
+ log("PORT_INIT received but event.ports is empty \u2014 ignoring");
2396
+ return;
2397
+ }
2398
+ if (settled) return;
2399
+ settled = true;
2400
+ clearTimeout(timeoutId);
2401
+ cleanup();
2402
+ resolve(port);
2403
+ };
2404
+ window.addEventListener("message", handler);
2405
+ });
2350
2406
  }
2351
2407
  function sendDebugInfo(config) {
2352
2408
  if (!config.debug) return;
@@ -2370,7 +2426,15 @@ postMessage error: ${e}`);
2370
2426
  function generateRequestId(counter) {
2371
2427
  return `req_${counter}`;
2372
2428
  }
2373
- function sendPostMessage(method, params, requestId, config, extensionInfo, pendingRequests) {
2429
+ function sendPostMessage(method, params, requestId, config, extensionInfo, pendingRequests, port) {
2430
+ if (!port) {
2431
+ return Promise.reject(
2432
+ new HaexVaultSdkError(
2433
+ "EXTENSION_NOT_INITIALIZED" /* EXTENSION_NOT_INITIALIZED */,
2434
+ "errors.port_not_connected"
2435
+ )
2436
+ );
2437
+ }
2374
2438
  const request = {
2375
2439
  method,
2376
2440
  params,
@@ -2386,17 +2450,16 @@ function sendPostMessage(method, params, requestId, config, extensionInfo, pendi
2386
2450
  );
2387
2451
  }, config.timeout);
2388
2452
  pendingRequests.set(requestId, { resolve, reject, timeout });
2389
- const targetOrigin = "*";
2390
2453
  if (config.debug) {
2391
2454
  console.log("[SDK Debug] ========== Sending Request ==========");
2392
2455
  console.log("[SDK Debug] Request ID:", requestId);
2393
2456
  console.log("[SDK Debug] Method:", request.method);
2394
2457
  console.log("[SDK Debug] Params:", request.params);
2395
- console.log("[SDK Debug] Target origin:", targetOrigin);
2458
+ console.log("[SDK Debug] Transport: MessagePort");
2396
2459
  console.log("[SDK Debug] Extension info:", extensionInfo);
2397
2460
  console.log("[SDK Debug] ========================================");
2398
2461
  }
2399
- window.parent.postMessage({ id: requestId, ...request }, targetOrigin);
2462
+ port.postMessage({ id: requestId, ...request });
2400
2463
  });
2401
2464
  }
2402
2465
  async function sendInvoke(method, params, config, _log) {
@@ -2415,11 +2478,6 @@ function createMessageHandler(config, pendingRequests, extensionInfo, onEvent) {
2415
2478
  return (event) => {
2416
2479
  if (config.debug) {
2417
2480
  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
2481
  console.log("[SDK Debug] Event data:", event.data);
2424
2482
  console.log("[SDK Debug] Extension info loaded:", !!extensionInfo());
2425
2483
  console.log(
@@ -2427,12 +2485,6 @@ function createMessageHandler(config, pendingRequests, extensionInfo, onEvent) {
2427
2485
  pendingRequests.size
2428
2486
  );
2429
2487
  }
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
2488
  const data = event.data;
2437
2489
  if ("id" in data && pendingRequests.has(data.id)) {
2438
2490
  if (config.debug) {
@@ -2654,6 +2706,13 @@ var HaexVaultSdk = class {
2654
2706
  this.reactiveSubscribers = /* @__PURE__ */ new Set();
2655
2707
  // Handlers
2656
2708
  this.messageHandler = null;
2709
+ /**
2710
+ * MessagePort obtained from the main window during iframe-mode handshake.
2711
+ * `null` until `initIframe()` completes successfully. Every outbound
2712
+ * request in iframe mode flows through this port; `sendPostMessage` rejects
2713
+ * if called before the handshake finishes.
2714
+ */
2715
+ this.hostPort = null;
2657
2716
  this.setupPromise = null;
2658
2717
  this.setupHook = null;
2659
2718
  // Public APIs
@@ -2827,7 +2886,15 @@ var HaexVaultSdk = class {
2827
2886
  return sendInvoke(method, paramsWithCredentials, this.config, this.log.bind(this));
2828
2887
  }
2829
2888
  const requestId = generateRequestId(++this.requestCounter);
2830
- return sendPostMessage(method, resolvedParams, requestId, this.config, this._extensionInfo, this.pendingRequests);
2889
+ return sendPostMessage(
2890
+ method,
2891
+ resolvedParams,
2892
+ requestId,
2893
+ this.config,
2894
+ this._extensionInfo,
2895
+ this.pendingRequests,
2896
+ this.hostPort
2897
+ );
2831
2898
  }
2832
2899
  // ==========================================================================
2833
2900
  // Private: Initialization
@@ -2894,7 +2961,7 @@ var HaexVaultSdk = class {
2894
2961
  () => this._extensionInfo,
2895
2962
  this.handleEvent.bind(this)
2896
2963
  );
2897
- const { context } = await initIframeMode(
2964
+ const { context, port } = await initIframeMode(
2898
2965
  {
2899
2966
  config: this.config,
2900
2967
  state: {
@@ -2926,6 +2993,7 @@ var HaexVaultSdk = class {
2926
2993
  this.messageHandler,
2927
2994
  this.request.bind(this)
2928
2995
  );
2996
+ this.hostPort = port;
2929
2997
  if (this.config.manifest) {
2930
2998
  this._extensionInfo = {
2931
2999
  publicKey: this.config.manifest.publicKey,