@haex-space/vault-sdk 3.2.6 → 3.2.8

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/node.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { H as HaextensionConfig, g as getExtensionDir, r as readHaextensionConfig } from './config-D_HXjsEV.mjs';
2
- import { E as ExtensionManifest } from './types-CDMBvvjl.mjs';
2
+ import { E as ExtensionManifest } from './types-Cji-mUN0.mjs';
3
3
 
4
4
  interface ReadManifestOptions {
5
5
  /** Root directory of the project */
package/dist/node.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { H as HaextensionConfig, g as getExtensionDir, r as readHaextensionConfig } from './config-D_HXjsEV.js';
2
- import { E as ExtensionManifest } from './types-CDMBvvjl.js';
2
+ import { E as ExtensionManifest } from './types-Cji-mUN0.js';
3
3
 
4
4
  interface ReadManifestOptions {
5
5
  /** Root directory of the project */
package/dist/react.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { H as HaexVaultSdk, S as StorageAPI } from './client-Bbm83Oy6.mjs';
1
+ import { H as HaexVaultSdk, S as StorageAPI } from './client-DaS2fAf-.mjs';
2
2
  import * as drizzle_orm_sqlite_proxy from 'drizzle-orm/sqlite-proxy';
3
- import { H as HaexHubConfig, a as ExtensionInfo, A as ApplicationContext } from './types-CDMBvvjl.mjs';
3
+ import { H as HaexHubConfig, a as ExtensionInfo, A as ApplicationContext } from './types-Cji-mUN0.mjs';
4
4
 
5
5
  /**
6
6
  * React hook for HaexVault SDK
package/dist/react.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { H as HaexVaultSdk, S as StorageAPI } from './client-exZiz0Ph.js';
1
+ import { H as HaexVaultSdk, S as StorageAPI } from './client-BBD-YsPv.js';
2
2
  import * as drizzle_orm_sqlite_proxy from 'drizzle-orm/sqlite-proxy';
3
- import { H as HaexHubConfig, a as ExtensionInfo, A as ApplicationContext } from './types-CDMBvvjl.js';
3
+ import { H as HaexHubConfig, a as ExtensionInfo, A as ApplicationContext } from './types-Cji-mUN0.js';
4
4
 
5
5
  /**
6
6
  * React hook for HaexVault SDK
package/dist/react.js CHANGED
@@ -398,16 +398,17 @@ var HAEXTENSION_EVENTS = {
398
398
  /** File system change detected (from native file watcher) */
399
399
  FILE_CHANGED: "filesync:file-changed",
400
400
  /** Tables have been updated via sync (CRDT pull from server) */
401
- SYNC_TABLES_UPDATED: "haextension:sync:tables-updated"
401
+ SYNC_TABLES_UPDATED: "haextension:sync:tables-updated",
402
+ /** A runtime permission prompt was resolved (granted/denied) by the user.
403
+ * The SDK uses this to auto-retry the original request; extensions may also
404
+ * subscribe via `client.on(HAEXTENSION_EVENTS.PERMISSION_RESOLVED, ...)`. */
405
+ PERMISSION_RESOLVED: "extension:permission-resolved"
402
406
  };
403
407
  var EXTERNAL_EVENTS = {
404
408
  /** External request from authorized client */
405
409
  REQUEST: "haextension:external:request",
406
410
  /** AI action request (tool calls from AI assistant) */
407
- ACTION_REQUEST: "haextension:action:request",
408
- /** New external client requesting authorization */
409
- AUTHORIZATION_REQUEST: "external:authorization-request"
410
- };
411
+ ACTION_REQUEST: "haextension:action:request"};
411
412
  var SHELL_EVENTS = {
412
413
  /** PTY output data from a shell session */
413
414
  OUTPUT: "shell:output",
@@ -421,6 +422,9 @@ var TABLE_SEPARATOR = "__";
421
422
  function getTableName(publicKey, extensionName, tableName) {
422
423
  return `${publicKey}${TABLE_SEPARATOR}${extensionName}${TABLE_SEPARATOR}${tableName}`;
423
424
  }
425
+ function isPermissionPromptError(error) {
426
+ return typeof error === "object" && error !== null && "code" in error && error.code === 1004 /* PROMPT_REQUIRED */;
427
+ }
424
428
  var HaexVaultSdkError = class extends Error {
425
429
  constructor(code, messageKey, details) {
426
430
  super(messageKey);
@@ -1059,7 +1063,10 @@ var WebAPI = class {
1059
1063
  } else if (options.body instanceof Blob) {
1060
1064
  bodyParam = await this.blobToBase64(options.body);
1061
1065
  } else {
1062
- bodyParam = options.body;
1066
+ const bytes = new TextEncoder().encode(options.body);
1067
+ bodyParam = this.arrayBufferToBase64(
1068
+ bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)
1069
+ );
1063
1070
  }
1064
1071
  }
1065
1072
  const response = await this.client.request(WEB_COMMANDS.fetch, {
@@ -1872,6 +1879,21 @@ async function initNativeMode(ctx, log, onEvent, onContextChange) {
1872
1879
  await setupTauriEventListeners(ctx, log, onEvent, onContextChange);
1873
1880
  return { extensionInfo, context };
1874
1881
  }
1882
+ async function forwardEvent(listen, log, onEvent, listenOptions, eventName, shape) {
1883
+ try {
1884
+ await listen(eventName, (event) => {
1885
+ if (event.payload == null) {
1886
+ log(`Event '${eventName}' received with no payload`);
1887
+ return;
1888
+ }
1889
+ const extra = shape ? shape(event.payload) : { data: event.payload };
1890
+ onEvent({ type: eventName, timestamp: Date.now(), ...extra });
1891
+ }, listenOptions);
1892
+ log(`Listener registered: ${eventName}`);
1893
+ } catch (error) {
1894
+ log(`Failed to register listener '${eventName}':`, error);
1895
+ }
1896
+ }
1875
1897
  async function setupTauriEventListeners(ctx, log, onEvent, onContextChange) {
1876
1898
  const { listen } = getTauriEvent();
1877
1899
  const webviewLabel = getCurrentWebviewLabel();
@@ -1903,207 +1925,29 @@ async function setupTauriEventListeners(ctx, log, onEvent, onContextChange) {
1903
1925
  } catch (error) {
1904
1926
  log("Failed to setup context change listener:", error);
1905
1927
  }
1906
- try {
1907
- await listen(EXTERNAL_EVENTS.REQUEST, (event) => {
1908
- log("====== EXTERNAL REQUEST RECEIVED ======");
1909
- log("Event payload:", JSON.stringify(event.payload, null, 2));
1910
- if (event.payload) {
1911
- onEvent({
1912
- type: EXTERNAL_EVENTS.REQUEST,
1913
- data: event.payload,
1914
- timestamp: Date.now()
1915
- });
1916
- } else {
1917
- log("External request event has no payload!");
1918
- }
1919
- }, listenOptions);
1920
- log("External request listener registered successfully");
1921
- } catch (error) {
1922
- log("Failed to setup external request listener:", error);
1923
- }
1924
- try {
1925
- await listen(EXTERNAL_EVENTS.ACTION_REQUEST, (event) => {
1926
- log("====== AI ACTION REQUEST RECEIVED ======");
1927
- log("Payload:", JSON.stringify(event.payload));
1928
- if (event.payload) {
1929
- onEvent({
1930
- type: EXTERNAL_EVENTS.ACTION_REQUEST,
1931
- data: event.payload,
1932
- timestamp: Date.now()
1933
- });
1934
- } else {
1935
- log("AI action request event has no payload!");
1936
- }
1937
- }, listenOptions);
1938
- log("AI action request listener registered successfully");
1939
- } catch (error) {
1940
- log("Failed to setup AI action request listener:", error);
1941
- }
1942
- log("Registering file change listener for:", HAEXTENSION_EVENTS.FILE_CHANGED);
1943
- try {
1944
- await listen(HAEXTENSION_EVENTS.FILE_CHANGED, (event) => {
1945
- log("File change event received:", event.payload);
1946
- if (event.payload) {
1947
- const payload = event.payload;
1948
- onEvent({
1949
- type: HAEXTENSION_EVENTS.FILE_CHANGED,
1950
- ruleId: payload.ruleId,
1951
- changeType: payload.changeType,
1952
- path: payload.path,
1953
- timestamp: Date.now()
1954
- });
1955
- }
1956
- }, listenOptions);
1957
- log("File change listener registered successfully");
1958
- } catch (error) {
1959
- log("Failed to setup file change listener:", error);
1960
- }
1961
- log("Registering sync tables updated listener for:", HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED);
1962
- try {
1963
- await listen(HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED, (event) => {
1964
- log("Sync tables updated event received:", event.payload);
1965
- if (event.payload) {
1966
- const payload = event.payload;
1967
- onEvent({
1968
- type: HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED,
1969
- data: { tables: payload.tables },
1970
- timestamp: Date.now()
1971
- });
1972
- }
1973
- }, listenOptions);
1974
- log("Sync tables updated listener registered successfully");
1975
- } catch (error) {
1976
- log("Failed to setup sync tables updated listener:", error);
1977
- }
1978
- log("Setting up LocalSend event listeners");
1979
- try {
1980
- await setupLocalSendEventListeners(log, onEvent, listenOptions);
1981
- log("LocalSend event listeners setup complete");
1982
- } catch (error) {
1983
- log("Failed to setup LocalSend event listeners:", error);
1984
- }
1985
- log("Setting up Shell event listeners");
1986
- try {
1987
- await listen(SHELL_EVENTS.OUTPUT, (event) => {
1988
- if (event.payload) {
1989
- const payload = event.payload;
1990
- onEvent({
1991
- type: SHELL_EVENTS.OUTPUT,
1992
- timestamp: Date.now(),
1993
- sessionId: payload.sessionId,
1994
- data: payload.data
1995
- });
1996
- }
1997
- }, listenOptions);
1998
- log("Shell output listener registered");
1999
- await listen(SHELL_EVENTS.EXIT, (event) => {
2000
- if (event.payload) {
2001
- const payload = event.payload;
2002
- onEvent({
2003
- type: SHELL_EVENTS.EXIT,
2004
- timestamp: Date.now(),
2005
- sessionId: payload.sessionId,
2006
- exitCode: payload.exitCode
2007
- });
2008
- }
2009
- }, listenOptions);
2010
- log("Shell exit listener registered");
2011
- } catch (error) {
2012
- log("Failed to setup Shell event listeners:", error);
2013
- }
2014
- }
2015
- async function setupLocalSendEventListeners(log, onEvent, listenOptions) {
2016
- const { listen } = getTauriEvent();
2017
- try {
2018
- await listen(LOCALSEND_EVENTS.deviceDiscovered, (event) => {
2019
- log("LocalSend device discovered:", event.payload);
2020
- if (event.payload) {
2021
- onEvent({
2022
- type: LOCALSEND_EVENTS.deviceDiscovered,
2023
- data: event.payload,
2024
- timestamp: Date.now()
2025
- });
2026
- }
2027
- }, listenOptions);
2028
- log("LocalSend device discovered listener registered");
2029
- } catch (error) {
2030
- log("Failed to setup LocalSend device discovered listener:", error);
2031
- }
2032
- try {
2033
- await listen(LOCALSEND_EVENTS.deviceLost, (event) => {
2034
- log("LocalSend device lost:", event.payload);
2035
- if (event.payload) {
2036
- onEvent({
2037
- type: LOCALSEND_EVENTS.deviceLost,
2038
- data: event.payload,
2039
- timestamp: Date.now()
2040
- });
2041
- }
2042
- }, listenOptions);
2043
- log("LocalSend device lost listener registered");
2044
- } catch (error) {
2045
- log("Failed to setup LocalSend device lost listener:", error);
2046
- }
2047
- try {
2048
- await listen(LOCALSEND_EVENTS.transferRequest, (event) => {
2049
- log("LocalSend transfer request:", event.payload);
2050
- if (event.payload) {
2051
- onEvent({
2052
- type: LOCALSEND_EVENTS.transferRequest,
2053
- data: event.payload,
2054
- timestamp: Date.now()
2055
- });
2056
- }
2057
- }, listenOptions);
2058
- log("LocalSend transfer request listener registered");
2059
- } catch (error) {
2060
- log("Failed to setup LocalSend transfer request listener:", error);
2061
- }
2062
- try {
2063
- await listen(LOCALSEND_EVENTS.transferProgress, (event) => {
2064
- log("LocalSend transfer progress event:", event);
2065
- if (event.payload) {
2066
- onEvent({
2067
- type: LOCALSEND_EVENTS.transferProgress,
2068
- data: event.payload,
2069
- timestamp: Date.now()
2070
- });
2071
- }
2072
- }, listenOptions);
2073
- log("LocalSend transfer progress listener registered");
2074
- } catch (error) {
2075
- log("Failed to setup LocalSend transfer progress listener:", error);
2076
- }
2077
- try {
2078
- await listen(LOCALSEND_EVENTS.transferComplete, (event) => {
2079
- log("LocalSend transfer complete:", event.payload);
2080
- if (event.payload) {
2081
- onEvent({
2082
- type: LOCALSEND_EVENTS.transferComplete,
2083
- data: event.payload,
2084
- timestamp: Date.now()
2085
- });
2086
- }
2087
- }, listenOptions);
2088
- log("LocalSend transfer complete listener registered");
2089
- } catch (error) {
2090
- log("Failed to setup LocalSend transfer complete listener:", error);
2091
- }
2092
- try {
2093
- await listen(LOCALSEND_EVENTS.transferFailed, (event) => {
2094
- log("LocalSend transfer failed:", event.payload);
2095
- if (event.payload) {
2096
- onEvent({
2097
- type: LOCALSEND_EVENTS.transferFailed,
2098
- data: event.payload,
2099
- timestamp: Date.now()
2100
- });
2101
- }
2102
- }, listenOptions);
2103
- log("LocalSend transfer failed listener registered");
2104
- } catch (error) {
2105
- log("Failed to setup LocalSend transfer failed listener:", error);
2106
- }
1928
+ for (const eventName of [
1929
+ HAEXTENSION_EVENTS.PERMISSION_RESOLVED,
1930
+ EXTERNAL_EVENTS.REQUEST,
1931
+ EXTERNAL_EVENTS.ACTION_REQUEST,
1932
+ ...Object.values(LOCALSEND_EVENTS)
1933
+ ]) {
1934
+ await forwardEvent(listen, log, onEvent, listenOptions, eventName);
1935
+ }
1936
+ await forwardEvent(listen, log, onEvent, listenOptions, HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED, (payload) => ({
1937
+ data: { tables: payload.tables }
1938
+ }));
1939
+ await forwardEvent(listen, log, onEvent, listenOptions, HAEXTENSION_EVENTS.FILE_CHANGED, (payload) => {
1940
+ const { ruleId, changeType, path } = payload;
1941
+ return { ruleId, changeType, path };
1942
+ });
1943
+ await forwardEvent(listen, log, onEvent, listenOptions, SHELL_EVENTS.OUTPUT, (payload) => {
1944
+ const { sessionId, data } = payload;
1945
+ return { sessionId, data };
1946
+ });
1947
+ await forwardEvent(listen, log, onEvent, listenOptions, SHELL_EVENTS.EXIT, (payload) => {
1948
+ const { sessionId, exitCode } = payload;
1949
+ return { sessionId, exitCode };
1950
+ });
2107
1951
  }
2108
1952
  async function initIframeMode(ctx, log, messageHandler) {
2109
1953
  if (!isInIframe()) {
@@ -2447,6 +2291,68 @@ var AI_COMMANDS = {
2447
2291
  actionRespond: "ai_action_respond"
2448
2292
  };
2449
2293
 
2294
+ // src/client/permissionRetry.ts
2295
+ var PERMISSION_DECISION_TIMEOUT_MS = 5 * 60 * 1e3;
2296
+ var MAX_PERMISSION_RETRIES = 3;
2297
+ function permissionKey(resourceType, action, target) {
2298
+ return `${resourceType}:${action}:${target}`;
2299
+ }
2300
+ var PermissionWaiterRegistry = class {
2301
+ constructor() {
2302
+ this.waiters = /* @__PURE__ */ new Map();
2303
+ }
2304
+ /** Wait for a decision on `key`; resolves "timeout" if none arrives in time. */
2305
+ wait(key, timeoutMs = PERMISSION_DECISION_TIMEOUT_MS) {
2306
+ return new Promise((resolve) => {
2307
+ const set = this.waiters.get(key) ?? /* @__PURE__ */ new Set();
2308
+ this.waiters.set(key, set);
2309
+ const settle = (outcome) => {
2310
+ if (!set.has(callback)) return;
2311
+ set.delete(callback);
2312
+ if (set.size === 0) this.waiters.delete(key);
2313
+ clearTimeout(timer);
2314
+ resolve(outcome);
2315
+ };
2316
+ const callback = (outcome) => settle(outcome);
2317
+ const timer = setTimeout(() => settle("timeout"), timeoutMs);
2318
+ set.add(callback);
2319
+ });
2320
+ }
2321
+ /** Resolve everyone waiting on `key` with the user's decision. */
2322
+ resolve(key, decision) {
2323
+ const set = this.waiters.get(key);
2324
+ if (!set) return;
2325
+ for (const callback of [...set]) callback(decision);
2326
+ }
2327
+ };
2328
+ function toDeniedError(error) {
2329
+ return { ...error, code: 1002 /* DENIED */ };
2330
+ }
2331
+ async function withPermissionRetry(send, registry, log, timeoutMs = PERMISSION_DECISION_TIMEOUT_MS) {
2332
+ for (let attempt = 0; ; attempt++) {
2333
+ try {
2334
+ return await send();
2335
+ } catch (error) {
2336
+ if (!isPermissionPromptError(error) || attempt >= MAX_PERMISSION_RETRIES) {
2337
+ throw error;
2338
+ }
2339
+ const key = permissionKey(error.resourceType, error.action, error.target);
2340
+ log(`Permission prompt required for ${key} \u2014 waiting for user decision`);
2341
+ const outcome = await registry.wait(key, timeoutMs);
2342
+ if (outcome === "granted") {
2343
+ log(`Permission ${key} granted \u2014 retrying request`);
2344
+ continue;
2345
+ }
2346
+ if (outcome === "denied") {
2347
+ log(`Permission ${key} denied`);
2348
+ throw toDeniedError(error);
2349
+ }
2350
+ log(`Permission ${key} prompt timed out`);
2351
+ throw error;
2352
+ }
2353
+ }
2354
+ }
2355
+
2450
2356
  // src/client.ts
2451
2357
  var HaexVaultSdk = class {
2452
2358
  constructor(config = {}) {
@@ -2462,6 +2368,7 @@ var HaexVaultSdk = class {
2462
2368
  this.eventListeners = /* @__PURE__ */ new Map();
2463
2369
  this.externalRequestHandlers = /* @__PURE__ */ new Map();
2464
2370
  this.reactiveSubscribers = /* @__PURE__ */ new Set();
2371
+ this.permissionWaiters = new PermissionWaiterRegistry();
2465
2372
  // Handlers
2466
2373
  this.messageHandler = null;
2467
2374
  /**
@@ -2498,6 +2405,14 @@ var HaexVaultSdk = class {
2498
2405
  this.passwords = new PasswordsAPI(this);
2499
2406
  this.mail = new MailAPI(this);
2500
2407
  installConsoleForwarding(this.config.debug);
2408
+ this.on(HAEXTENSION_EVENTS.PERMISSION_RESOLVED, (event) => {
2409
+ const data = event.data;
2410
+ if (!data) return;
2411
+ this.permissionWaiters.resolve(
2412
+ permissionKey(data.resourceType, data.action, data.target),
2413
+ data.decision === "denied" ? "denied" : "granted"
2414
+ );
2415
+ });
2501
2416
  this.readyPromise = new Promise((resolve, reject) => {
2502
2417
  this.resolveReady = resolve;
2503
2418
  this.rejectReady = reject;
@@ -2646,24 +2561,27 @@ var HaexVaultSdk = class {
2646
2561
  // ==========================================================================
2647
2562
  async request(method, params) {
2648
2563
  const resolvedParams = params ?? {};
2649
- if (this.isNativeWindow && hasTauri()) {
2650
- const paramsWithCredentials = {
2651
- ...resolvedParams,
2652
- publicKey: this._extensionInfo?.publicKey,
2653
- name: this._extensionInfo?.name
2654
- };
2655
- return sendInvoke(method, paramsWithCredentials, this.config, this.log.bind(this));
2656
- }
2657
- const requestId = generateRequestId(++this.requestCounter);
2658
- return sendPostMessage(
2659
- method,
2660
- resolvedParams,
2661
- requestId,
2662
- this.config,
2663
- this._extensionInfo,
2664
- this.pendingRequests,
2665
- this.hostPort
2666
- );
2564
+ const send = () => {
2565
+ if (this.isNativeWindow && hasTauri()) {
2566
+ const paramsWithCredentials = {
2567
+ ...resolvedParams,
2568
+ publicKey: this._extensionInfo?.publicKey,
2569
+ name: this._extensionInfo?.name
2570
+ };
2571
+ return sendInvoke(method, paramsWithCredentials, this.config, this.log.bind(this));
2572
+ }
2573
+ const requestId = generateRequestId(++this.requestCounter);
2574
+ return sendPostMessage(
2575
+ method,
2576
+ resolvedParams,
2577
+ requestId,
2578
+ this.config,
2579
+ this._extensionInfo,
2580
+ this.pendingRequests,
2581
+ this.hostPort
2582
+ );
2583
+ };
2584
+ return withPermissionRetry(send, this.permissionWaiters, this.log.bind(this));
2667
2585
  }
2668
2586
  // ==========================================================================
2669
2587
  // Private: Initialization