@haex-space/vault-sdk 3.2.7 → 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.
@@ -1,4 +1,4 @@
1
- import { b as HaexHubEvent, c as EXTERNAL_EVENTS, D as DatabaseQueryResult, M as Migration, d as MigrationResult, W as WebRequestOptions, e as WebResponse, f as EventCallback, H as HaexHubConfig, a as ExtensionInfo, A as ApplicationContext, g as DatabasePermissionRequest, P as PermissionResponse, S as SearchResult } from './types-CDMBvvjl.mjs';
1
+ import { b as HaexHubEvent, c as EXTERNAL_EVENTS, D as DatabaseQueryResult, M as Migration, d as MigrationResult, W as WebRequestOptions, e as WebResponse, f as EventCallback, H as HaexHubConfig, a as ExtensionInfo, A as ApplicationContext, g as DatabasePermissionRequest, P as PermissionResponse, S as SearchResult } from './types-Cji-mUN0.js';
2
2
  import { SqliteRemoteDatabase } from 'drizzle-orm/sqlite-proxy';
3
3
 
4
4
  /**
@@ -1468,6 +1468,7 @@ declare class HaexVaultSdk {
1468
1468
  private readonly eventListeners;
1469
1469
  private readonly externalRequestHandlers;
1470
1470
  private readonly reactiveSubscribers;
1471
+ private readonly permissionWaiters;
1471
1472
  private messageHandler;
1472
1473
  /**
1473
1474
  * MessagePort obtained from the main window during iframe-mode handshake.
@@ -1,4 +1,4 @@
1
- import { b as HaexHubEvent, c as EXTERNAL_EVENTS, D as DatabaseQueryResult, M as Migration, d as MigrationResult, W as WebRequestOptions, e as WebResponse, f as EventCallback, H as HaexHubConfig, a as ExtensionInfo, A as ApplicationContext, g as DatabasePermissionRequest, P as PermissionResponse, S as SearchResult } from './types-CDMBvvjl.js';
1
+ import { b as HaexHubEvent, c as EXTERNAL_EVENTS, D as DatabaseQueryResult, M as Migration, d as MigrationResult, W as WebRequestOptions, e as WebResponse, f as EventCallback, H as HaexHubConfig, a as ExtensionInfo, A as ApplicationContext, g as DatabasePermissionRequest, P as PermissionResponse, S as SearchResult } from './types-Cji-mUN0.mjs';
2
2
  import { SqliteRemoteDatabase } from 'drizzle-orm/sqlite-proxy';
3
3
 
4
4
  /**
@@ -1468,6 +1468,7 @@ declare class HaexVaultSdk {
1468
1468
  private readonly eventListeners;
1469
1469
  private readonly externalRequestHandlers;
1470
1470
  private readonly reactiveSubscribers;
1471
+ private readonly permissionWaiters;
1471
1472
  private messageHandler;
1472
1473
  /**
1473
1474
  * MessagePort obtained from the main window during iframe-mode handshake.
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { H as HaexVaultSdk } from './client-Bbm83Oy6.mjs';
2
- export { A as AuthorizedClient, B as BlockedClient, C as ConnectionSecurity, D as DatabaseAPI, a as DecryptedSpace, b as Device, c as DeviceInfo, d as DeviceType, e as DirEntry, E as ExternalAuthDecision, f as ExternalConnection, g as ExternalConnectionErrorCode, h as ExternalConnectionState, i as ExternalRequest, j as ExternalRequestEvent, k as ExternalRequestHandler, l as ExternalRequestPayload, m as ExternalResponse, F as FileStat, n as FilesystemAPI, I as ImapConfig, K as KnownPath, o as KnownPaths, L as LOCALSEND_EVENTS, p as LocalSendAPI, q as LocalSendEvent, r as LocalSendFileInfo, s as LocalSendSettings, M as MailAPI, t as MailAccount, u as MailAddress, v as MailAttachment, w as MailFetchRange, x as MailMessage, y as MailboxInfo, z as MessageEnvelope, O as OutgoingAttachment, G as OutgoingMessage, P as PasswordInput, J as PasswordItemFull, N as PasswordItemSummary, Q as PasswordKeyValue, R as PasswordKeyValueInput, T as PasswordsAPI, U as PendingAuthorization, V as PendingTransfer, W as PermissionsAPI, X as RemoteAddBackendRequest, Y as RemoteS3Config, Z as RemoteS3PublicConfig, _ as RemoteStorageAPI, $ as RemoteStorageBackendInfo, a0 as RemoteStorageObjectInfo, a1 as RemoteUpdateBackendRequest, a2 as RequestedExtension, a3 as SelectFileOptions, a4 as SelectFolderOptions, a5 as ServerInfo, a6 as ServerStatus, a7 as SessionAuthorization, a8 as SharedSpace, a9 as ShellAPI, aa as ShellCreateOptions, ab as ShellCreateResponse, ac as ShellExitEvent, ad as ShellOutputEvent, ae as SmtpConfig, af as SpaceAccessTokenInfo, ag as SpaceAssignment, ah as SpaceInvite, ai as SpaceKeyGrantInfo, aj as SpaceMemberInfo, ak as SpacesAPI, al as SyncBackendInfo, am as TransferDirection, an as TransferProgress, ao as TransferState, ap as WebAPI, aq as canExternalClientSendRequests, ar as isExternalClientConnected } from './client-Bbm83Oy6.mjs';
3
- import { E as ExtensionManifest, h as SignedClaimPresentation, H as HaexHubConfig } from './types-CDMBvvjl.mjs';
4
- export { A as ApplicationContext, C as ClaimRequirement, i as ContextChangedEvent, j as DEFAULT_TIMEOUT, k as DatabaseColumnInfo, l as DatabaseExecuteParams, m as DatabasePermission, g as DatabasePermissionRequest, n as DatabaseQueryParams, D as DatabaseQueryResult, o as DatabaseTableInfo, c as EXTERNAL_EVENTS, p as ErrorCode, f as EventCallback, a as ExtensionInfo, q as ExtensionRuntimeMode, r as ExternalEvent, F as FileChangeEvent, s as FileChangePayload, t as FileChangeType, u as FilteredSyncTablesResult, v as HAEXTENSION_EVENTS, b as HaexHubEvent, w as HaexHubRequest, x as HaexHubResponse, y as HaexVaultSdkError, z as HaextensionEvent, I as IdentityClaim, B as ManifestI18nEntry, G as PermissionDeniedError, J as PermissionErrorBase, K as PermissionErrorCode, L as PermissionPromptError, P as PermissionResponse, N as PermissionStatus, O as SHELL_EVENTS, Q as SearchQuery, R as SearchRequestEvent, S as SearchResult, T as ShellEvent, U as SyncTablesUpdatedEvent, V as TABLE_SEPARATOR, W as WebRequestOptions, e as WebResponse, X as getTableName, Y as isPermissionDeniedError, Z as isPermissionError, _ as isPermissionPromptError } from './types-CDMBvvjl.mjs';
1
+ import { H as HaexVaultSdk } from './client-DaS2fAf-.mjs';
2
+ export { A as AuthorizedClient, B as BlockedClient, C as ConnectionSecurity, D as DatabaseAPI, a as DecryptedSpace, b as Device, c as DeviceInfo, d as DeviceType, e as DirEntry, E as ExternalAuthDecision, f as ExternalConnection, g as ExternalConnectionErrorCode, h as ExternalConnectionState, i as ExternalRequest, j as ExternalRequestEvent, k as ExternalRequestHandler, l as ExternalRequestPayload, m as ExternalResponse, F as FileStat, n as FilesystemAPI, I as ImapConfig, K as KnownPath, o as KnownPaths, L as LOCALSEND_EVENTS, p as LocalSendAPI, q as LocalSendEvent, r as LocalSendFileInfo, s as LocalSendSettings, M as MailAPI, t as MailAccount, u as MailAddress, v as MailAttachment, w as MailFetchRange, x as MailMessage, y as MailboxInfo, z as MessageEnvelope, O as OutgoingAttachment, G as OutgoingMessage, P as PasswordInput, J as PasswordItemFull, N as PasswordItemSummary, Q as PasswordKeyValue, R as PasswordKeyValueInput, T as PasswordsAPI, U as PendingAuthorization, V as PendingTransfer, W as PermissionsAPI, X as RemoteAddBackendRequest, Y as RemoteS3Config, Z as RemoteS3PublicConfig, _ as RemoteStorageAPI, $ as RemoteStorageBackendInfo, a0 as RemoteStorageObjectInfo, a1 as RemoteUpdateBackendRequest, a2 as RequestedExtension, a3 as SelectFileOptions, a4 as SelectFolderOptions, a5 as ServerInfo, a6 as ServerStatus, a7 as SessionAuthorization, a8 as SharedSpace, a9 as ShellAPI, aa as ShellCreateOptions, ab as ShellCreateResponse, ac as ShellExitEvent, ad as ShellOutputEvent, ae as SmtpConfig, af as SpaceAccessTokenInfo, ag as SpaceAssignment, ah as SpaceInvite, ai as SpaceKeyGrantInfo, aj as SpaceMemberInfo, ak as SpacesAPI, al as SyncBackendInfo, am as TransferDirection, an as TransferProgress, ao as TransferState, ap as WebAPI, aq as canExternalClientSendRequests, ar as isExternalClientConnected } from './client-DaS2fAf-.mjs';
3
+ import { E as ExtensionManifest, h as SignedClaimPresentation, H as HaexHubConfig } from './types-Cji-mUN0.mjs';
4
+ export { A as ApplicationContext, C as ClaimRequirement, i as ContextChangedEvent, j as DEFAULT_TIMEOUT, k as DatabaseColumnInfo, l as DatabaseExecuteParams, m as DatabasePermission, g as DatabasePermissionRequest, n as DatabaseQueryParams, D as DatabaseQueryResult, o as DatabaseTableInfo, c as EXTERNAL_EVENTS, p as ErrorCode, f as EventCallback, a as ExtensionInfo, q as ExtensionRuntimeMode, r as ExternalEvent, F as FileChangeEvent, s as FileChangePayload, t as FileChangeType, u as FilteredSyncTablesResult, v as HAEXTENSION_EVENTS, b as HaexHubEvent, w as HaexHubRequest, x as HaexHubResponse, y as HaexVaultSdkError, z as HaextensionEvent, I as IdentityClaim, B as ManifestI18nEntry, G as PermissionDeniedError, J as PermissionErrorBase, K as PermissionErrorCode, L as PermissionPromptError, P as PermissionResponse, N as PermissionStatus, O as SHELL_EVENTS, Q as SearchQuery, R as SearchRequestEvent, S as SearchResult, T as ShellEvent, U as SyncTablesUpdatedEvent, V as TABLE_SEPARATOR, W as WebRequestOptions, e as WebResponse, X as getTableName, Y as isPermissionDeniedError, Z as isPermissionError, _ as isPermissionPromptError } from './types-Cji-mUN0.mjs';
5
5
  export { H as HaextensionConfig } from './config-D_HXjsEV.mjs';
6
6
  import 'drizzle-orm/sqlite-proxy';
7
7
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { H as HaexVaultSdk } from './client-exZiz0Ph.js';
2
- export { A as AuthorizedClient, B as BlockedClient, C as ConnectionSecurity, D as DatabaseAPI, a as DecryptedSpace, b as Device, c as DeviceInfo, d as DeviceType, e as DirEntry, E as ExternalAuthDecision, f as ExternalConnection, g as ExternalConnectionErrorCode, h as ExternalConnectionState, i as ExternalRequest, j as ExternalRequestEvent, k as ExternalRequestHandler, l as ExternalRequestPayload, m as ExternalResponse, F as FileStat, n as FilesystemAPI, I as ImapConfig, K as KnownPath, o as KnownPaths, L as LOCALSEND_EVENTS, p as LocalSendAPI, q as LocalSendEvent, r as LocalSendFileInfo, s as LocalSendSettings, M as MailAPI, t as MailAccount, u as MailAddress, v as MailAttachment, w as MailFetchRange, x as MailMessage, y as MailboxInfo, z as MessageEnvelope, O as OutgoingAttachment, G as OutgoingMessage, P as PasswordInput, J as PasswordItemFull, N as PasswordItemSummary, Q as PasswordKeyValue, R as PasswordKeyValueInput, T as PasswordsAPI, U as PendingAuthorization, V as PendingTransfer, W as PermissionsAPI, X as RemoteAddBackendRequest, Y as RemoteS3Config, Z as RemoteS3PublicConfig, _ as RemoteStorageAPI, $ as RemoteStorageBackendInfo, a0 as RemoteStorageObjectInfo, a1 as RemoteUpdateBackendRequest, a2 as RequestedExtension, a3 as SelectFileOptions, a4 as SelectFolderOptions, a5 as ServerInfo, a6 as ServerStatus, a7 as SessionAuthorization, a8 as SharedSpace, a9 as ShellAPI, aa as ShellCreateOptions, ab as ShellCreateResponse, ac as ShellExitEvent, ad as ShellOutputEvent, ae as SmtpConfig, af as SpaceAccessTokenInfo, ag as SpaceAssignment, ah as SpaceInvite, ai as SpaceKeyGrantInfo, aj as SpaceMemberInfo, ak as SpacesAPI, al as SyncBackendInfo, am as TransferDirection, an as TransferProgress, ao as TransferState, ap as WebAPI, aq as canExternalClientSendRequests, ar as isExternalClientConnected } from './client-exZiz0Ph.js';
3
- import { E as ExtensionManifest, h as SignedClaimPresentation, H as HaexHubConfig } from './types-CDMBvvjl.js';
4
- export { A as ApplicationContext, C as ClaimRequirement, i as ContextChangedEvent, j as DEFAULT_TIMEOUT, k as DatabaseColumnInfo, l as DatabaseExecuteParams, m as DatabasePermission, g as DatabasePermissionRequest, n as DatabaseQueryParams, D as DatabaseQueryResult, o as DatabaseTableInfo, c as EXTERNAL_EVENTS, p as ErrorCode, f as EventCallback, a as ExtensionInfo, q as ExtensionRuntimeMode, r as ExternalEvent, F as FileChangeEvent, s as FileChangePayload, t as FileChangeType, u as FilteredSyncTablesResult, v as HAEXTENSION_EVENTS, b as HaexHubEvent, w as HaexHubRequest, x as HaexHubResponse, y as HaexVaultSdkError, z as HaextensionEvent, I as IdentityClaim, B as ManifestI18nEntry, G as PermissionDeniedError, J as PermissionErrorBase, K as PermissionErrorCode, L as PermissionPromptError, P as PermissionResponse, N as PermissionStatus, O as SHELL_EVENTS, Q as SearchQuery, R as SearchRequestEvent, S as SearchResult, T as ShellEvent, U as SyncTablesUpdatedEvent, V as TABLE_SEPARATOR, W as WebRequestOptions, e as WebResponse, X as getTableName, Y as isPermissionDeniedError, Z as isPermissionError, _ as isPermissionPromptError } from './types-CDMBvvjl.js';
1
+ import { H as HaexVaultSdk } from './client-BBD-YsPv.js';
2
+ export { A as AuthorizedClient, B as BlockedClient, C as ConnectionSecurity, D as DatabaseAPI, a as DecryptedSpace, b as Device, c as DeviceInfo, d as DeviceType, e as DirEntry, E as ExternalAuthDecision, f as ExternalConnection, g as ExternalConnectionErrorCode, h as ExternalConnectionState, i as ExternalRequest, j as ExternalRequestEvent, k as ExternalRequestHandler, l as ExternalRequestPayload, m as ExternalResponse, F as FileStat, n as FilesystemAPI, I as ImapConfig, K as KnownPath, o as KnownPaths, L as LOCALSEND_EVENTS, p as LocalSendAPI, q as LocalSendEvent, r as LocalSendFileInfo, s as LocalSendSettings, M as MailAPI, t as MailAccount, u as MailAddress, v as MailAttachment, w as MailFetchRange, x as MailMessage, y as MailboxInfo, z as MessageEnvelope, O as OutgoingAttachment, G as OutgoingMessage, P as PasswordInput, J as PasswordItemFull, N as PasswordItemSummary, Q as PasswordKeyValue, R as PasswordKeyValueInput, T as PasswordsAPI, U as PendingAuthorization, V as PendingTransfer, W as PermissionsAPI, X as RemoteAddBackendRequest, Y as RemoteS3Config, Z as RemoteS3PublicConfig, _ as RemoteStorageAPI, $ as RemoteStorageBackendInfo, a0 as RemoteStorageObjectInfo, a1 as RemoteUpdateBackendRequest, a2 as RequestedExtension, a3 as SelectFileOptions, a4 as SelectFolderOptions, a5 as ServerInfo, a6 as ServerStatus, a7 as SessionAuthorization, a8 as SharedSpace, a9 as ShellAPI, aa as ShellCreateOptions, ab as ShellCreateResponse, ac as ShellExitEvent, ad as ShellOutputEvent, ae as SmtpConfig, af as SpaceAccessTokenInfo, ag as SpaceAssignment, ah as SpaceInvite, ai as SpaceKeyGrantInfo, aj as SpaceMemberInfo, ak as SpacesAPI, al as SyncBackendInfo, am as TransferDirection, an as TransferProgress, ao as TransferState, ap as WebAPI, aq as canExternalClientSendRequests, ar as isExternalClientConnected } from './client-BBD-YsPv.js';
3
+ import { E as ExtensionManifest, h as SignedClaimPresentation, H as HaexHubConfig } from './types-Cji-mUN0.js';
4
+ export { A as ApplicationContext, C as ClaimRequirement, i as ContextChangedEvent, j as DEFAULT_TIMEOUT, k as DatabaseColumnInfo, l as DatabaseExecuteParams, m as DatabasePermission, g as DatabasePermissionRequest, n as DatabaseQueryParams, D as DatabaseQueryResult, o as DatabaseTableInfo, c as EXTERNAL_EVENTS, p as ErrorCode, f as EventCallback, a as ExtensionInfo, q as ExtensionRuntimeMode, r as ExternalEvent, F as FileChangeEvent, s as FileChangePayload, t as FileChangeType, u as FilteredSyncTablesResult, v as HAEXTENSION_EVENTS, b as HaexHubEvent, w as HaexHubRequest, x as HaexHubResponse, y as HaexVaultSdkError, z as HaextensionEvent, I as IdentityClaim, B as ManifestI18nEntry, G as PermissionDeniedError, J as PermissionErrorBase, K as PermissionErrorCode, L as PermissionPromptError, P as PermissionResponse, N as PermissionStatus, O as SHELL_EVENTS, Q as SearchQuery, R as SearchRequestEvent, S as SearchResult, T as ShellEvent, U as SyncTablesUpdatedEvent, V as TABLE_SEPARATOR, W as WebRequestOptions, e as WebResponse, X as getTableName, Y as isPermissionDeniedError, Z as isPermissionError, _ as isPermissionPromptError } from './types-Cji-mUN0.js';
5
5
  export { H as HaextensionConfig } from './config-D_HXjsEV.js';
6
6
  import 'drizzle-orm/sqlite-proxy';
7
7
 
package/dist/index.js CHANGED
@@ -711,7 +711,11 @@ var HAEXTENSION_EVENTS = {
711
711
  /** File system change detected (from native file watcher) */
712
712
  FILE_CHANGED: "filesync:file-changed",
713
713
  /** Tables have been updated via sync (CRDT pull from server) */
714
- SYNC_TABLES_UPDATED: "haextension:sync:tables-updated"
714
+ SYNC_TABLES_UPDATED: "haextension:sync:tables-updated",
715
+ /** A runtime permission prompt was resolved (granted/denied) by the user.
716
+ * The SDK uses this to auto-retry the original request; extensions may also
717
+ * subscribe via `client.on(HAEXTENSION_EVENTS.PERMISSION_RESOLVED, ...)`. */
718
+ PERMISSION_RESOLVED: "extension:permission-resolved"
715
719
  };
716
720
  var EXTERNAL_EVENTS = {
717
721
  /** External request from authorized client */
@@ -2300,6 +2304,21 @@ async function initNativeMode(ctx, log, onEvent, onContextChange) {
2300
2304
  await setupTauriEventListeners(ctx, log, onEvent, onContextChange);
2301
2305
  return { extensionInfo, context };
2302
2306
  }
2307
+ async function forwardEvent(listen, log, onEvent, listenOptions, eventName, shape) {
2308
+ try {
2309
+ await listen(eventName, (event) => {
2310
+ if (event.payload == null) {
2311
+ log(`Event '${eventName}' received with no payload`);
2312
+ return;
2313
+ }
2314
+ const extra = shape ? shape(event.payload) : { data: event.payload };
2315
+ onEvent({ type: eventName, timestamp: Date.now(), ...extra });
2316
+ }, listenOptions);
2317
+ log(`Listener registered: ${eventName}`);
2318
+ } catch (error) {
2319
+ log(`Failed to register listener '${eventName}':`, error);
2320
+ }
2321
+ }
2303
2322
  async function setupTauriEventListeners(ctx, log, onEvent, onContextChange) {
2304
2323
  const { listen } = getTauriEvent();
2305
2324
  const webviewLabel = getCurrentWebviewLabel();
@@ -2331,207 +2350,29 @@ async function setupTauriEventListeners(ctx, log, onEvent, onContextChange) {
2331
2350
  } catch (error) {
2332
2351
  log("Failed to setup context change listener:", error);
2333
2352
  }
2334
- try {
2335
- await listen(EXTERNAL_EVENTS.REQUEST, (event) => {
2336
- log("====== EXTERNAL REQUEST RECEIVED ======");
2337
- log("Event payload:", JSON.stringify(event.payload, null, 2));
2338
- if (event.payload) {
2339
- onEvent({
2340
- type: EXTERNAL_EVENTS.REQUEST,
2341
- data: event.payload,
2342
- timestamp: Date.now()
2343
- });
2344
- } else {
2345
- log("External request event has no payload!");
2346
- }
2347
- }, listenOptions);
2348
- log("External request listener registered successfully");
2349
- } catch (error) {
2350
- log("Failed to setup external request listener:", error);
2351
- }
2352
- try {
2353
- await listen(EXTERNAL_EVENTS.ACTION_REQUEST, (event) => {
2354
- log("====== AI ACTION REQUEST RECEIVED ======");
2355
- log("Payload:", JSON.stringify(event.payload));
2356
- if (event.payload) {
2357
- onEvent({
2358
- type: EXTERNAL_EVENTS.ACTION_REQUEST,
2359
- data: event.payload,
2360
- timestamp: Date.now()
2361
- });
2362
- } else {
2363
- log("AI action request event has no payload!");
2364
- }
2365
- }, listenOptions);
2366
- log("AI action request listener registered successfully");
2367
- } catch (error) {
2368
- log("Failed to setup AI action request listener:", error);
2369
- }
2370
- log("Registering file change listener for:", HAEXTENSION_EVENTS.FILE_CHANGED);
2371
- try {
2372
- await listen(HAEXTENSION_EVENTS.FILE_CHANGED, (event) => {
2373
- log("File change event received:", event.payload);
2374
- if (event.payload) {
2375
- const payload = event.payload;
2376
- onEvent({
2377
- type: HAEXTENSION_EVENTS.FILE_CHANGED,
2378
- ruleId: payload.ruleId,
2379
- changeType: payload.changeType,
2380
- path: payload.path,
2381
- timestamp: Date.now()
2382
- });
2383
- }
2384
- }, listenOptions);
2385
- log("File change listener registered successfully");
2386
- } catch (error) {
2387
- log("Failed to setup file change listener:", error);
2388
- }
2389
- log("Registering sync tables updated listener for:", HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED);
2390
- try {
2391
- await listen(HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED, (event) => {
2392
- log("Sync tables updated event received:", event.payload);
2393
- if (event.payload) {
2394
- const payload = event.payload;
2395
- onEvent({
2396
- type: HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED,
2397
- data: { tables: payload.tables },
2398
- timestamp: Date.now()
2399
- });
2400
- }
2401
- }, listenOptions);
2402
- log("Sync tables updated listener registered successfully");
2403
- } catch (error) {
2404
- log("Failed to setup sync tables updated listener:", error);
2405
- }
2406
- log("Setting up LocalSend event listeners");
2407
- try {
2408
- await setupLocalSendEventListeners(log, onEvent, listenOptions);
2409
- log("LocalSend event listeners setup complete");
2410
- } catch (error) {
2411
- log("Failed to setup LocalSend event listeners:", error);
2412
- }
2413
- log("Setting up Shell event listeners");
2414
- try {
2415
- await listen(SHELL_EVENTS.OUTPUT, (event) => {
2416
- if (event.payload) {
2417
- const payload = event.payload;
2418
- onEvent({
2419
- type: SHELL_EVENTS.OUTPUT,
2420
- timestamp: Date.now(),
2421
- sessionId: payload.sessionId,
2422
- data: payload.data
2423
- });
2424
- }
2425
- }, listenOptions);
2426
- log("Shell output listener registered");
2427
- await listen(SHELL_EVENTS.EXIT, (event) => {
2428
- if (event.payload) {
2429
- const payload = event.payload;
2430
- onEvent({
2431
- type: SHELL_EVENTS.EXIT,
2432
- timestamp: Date.now(),
2433
- sessionId: payload.sessionId,
2434
- exitCode: payload.exitCode
2435
- });
2436
- }
2437
- }, listenOptions);
2438
- log("Shell exit listener registered");
2439
- } catch (error) {
2440
- log("Failed to setup Shell event listeners:", error);
2441
- }
2442
- }
2443
- async function setupLocalSendEventListeners(log, onEvent, listenOptions) {
2444
- const { listen } = getTauriEvent();
2445
- try {
2446
- await listen(LOCALSEND_EVENTS.deviceDiscovered, (event) => {
2447
- log("LocalSend device discovered:", event.payload);
2448
- if (event.payload) {
2449
- onEvent({
2450
- type: LOCALSEND_EVENTS.deviceDiscovered,
2451
- data: event.payload,
2452
- timestamp: Date.now()
2453
- });
2454
- }
2455
- }, listenOptions);
2456
- log("LocalSend device discovered listener registered");
2457
- } catch (error) {
2458
- log("Failed to setup LocalSend device discovered listener:", error);
2459
- }
2460
- try {
2461
- await listen(LOCALSEND_EVENTS.deviceLost, (event) => {
2462
- log("LocalSend device lost:", event.payload);
2463
- if (event.payload) {
2464
- onEvent({
2465
- type: LOCALSEND_EVENTS.deviceLost,
2466
- data: event.payload,
2467
- timestamp: Date.now()
2468
- });
2469
- }
2470
- }, listenOptions);
2471
- log("LocalSend device lost listener registered");
2472
- } catch (error) {
2473
- log("Failed to setup LocalSend device lost listener:", error);
2474
- }
2475
- try {
2476
- await listen(LOCALSEND_EVENTS.transferRequest, (event) => {
2477
- log("LocalSend transfer request:", event.payload);
2478
- if (event.payload) {
2479
- onEvent({
2480
- type: LOCALSEND_EVENTS.transferRequest,
2481
- data: event.payload,
2482
- timestamp: Date.now()
2483
- });
2484
- }
2485
- }, listenOptions);
2486
- log("LocalSend transfer request listener registered");
2487
- } catch (error) {
2488
- log("Failed to setup LocalSend transfer request listener:", error);
2489
- }
2490
- try {
2491
- await listen(LOCALSEND_EVENTS.transferProgress, (event) => {
2492
- log("LocalSend transfer progress event:", event);
2493
- if (event.payload) {
2494
- onEvent({
2495
- type: LOCALSEND_EVENTS.transferProgress,
2496
- data: event.payload,
2497
- timestamp: Date.now()
2498
- });
2499
- }
2500
- }, listenOptions);
2501
- log("LocalSend transfer progress listener registered");
2502
- } catch (error) {
2503
- log("Failed to setup LocalSend transfer progress listener:", error);
2504
- }
2505
- try {
2506
- await listen(LOCALSEND_EVENTS.transferComplete, (event) => {
2507
- log("LocalSend transfer complete:", event.payload);
2508
- if (event.payload) {
2509
- onEvent({
2510
- type: LOCALSEND_EVENTS.transferComplete,
2511
- data: event.payload,
2512
- timestamp: Date.now()
2513
- });
2514
- }
2515
- }, listenOptions);
2516
- log("LocalSend transfer complete listener registered");
2517
- } catch (error) {
2518
- log("Failed to setup LocalSend transfer complete listener:", error);
2519
- }
2520
- try {
2521
- await listen(LOCALSEND_EVENTS.transferFailed, (event) => {
2522
- log("LocalSend transfer failed:", event.payload);
2523
- if (event.payload) {
2524
- onEvent({
2525
- type: LOCALSEND_EVENTS.transferFailed,
2526
- data: event.payload,
2527
- timestamp: Date.now()
2528
- });
2529
- }
2530
- }, listenOptions);
2531
- log("LocalSend transfer failed listener registered");
2532
- } catch (error) {
2533
- log("Failed to setup LocalSend transfer failed listener:", error);
2534
- }
2353
+ for (const eventName of [
2354
+ HAEXTENSION_EVENTS.PERMISSION_RESOLVED,
2355
+ EXTERNAL_EVENTS.REQUEST,
2356
+ EXTERNAL_EVENTS.ACTION_REQUEST,
2357
+ ...Object.values(LOCALSEND_EVENTS)
2358
+ ]) {
2359
+ await forwardEvent(listen, log, onEvent, listenOptions, eventName);
2360
+ }
2361
+ await forwardEvent(listen, log, onEvent, listenOptions, HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED, (payload) => ({
2362
+ data: { tables: payload.tables }
2363
+ }));
2364
+ await forwardEvent(listen, log, onEvent, listenOptions, HAEXTENSION_EVENTS.FILE_CHANGED, (payload) => {
2365
+ const { ruleId, changeType, path } = payload;
2366
+ return { ruleId, changeType, path };
2367
+ });
2368
+ await forwardEvent(listen, log, onEvent, listenOptions, SHELL_EVENTS.OUTPUT, (payload) => {
2369
+ const { sessionId, data } = payload;
2370
+ return { sessionId, data };
2371
+ });
2372
+ await forwardEvent(listen, log, onEvent, listenOptions, SHELL_EVENTS.EXIT, (payload) => {
2373
+ const { sessionId, exitCode } = payload;
2374
+ return { sessionId, exitCode };
2375
+ });
2535
2376
  }
2536
2377
  async function initIframeMode(ctx, log, messageHandler) {
2537
2378
  if (!isInIframe()) {
@@ -2875,6 +2716,68 @@ var AI_COMMANDS = {
2875
2716
  actionRespond: "ai_action_respond"
2876
2717
  };
2877
2718
 
2719
+ // src/client/permissionRetry.ts
2720
+ var PERMISSION_DECISION_TIMEOUT_MS = 5 * 60 * 1e3;
2721
+ var MAX_PERMISSION_RETRIES = 3;
2722
+ function permissionKey(resourceType, action, target) {
2723
+ return `${resourceType}:${action}:${target}`;
2724
+ }
2725
+ var PermissionWaiterRegistry = class {
2726
+ constructor() {
2727
+ this.waiters = /* @__PURE__ */ new Map();
2728
+ }
2729
+ /** Wait for a decision on `key`; resolves "timeout" if none arrives in time. */
2730
+ wait(key, timeoutMs = PERMISSION_DECISION_TIMEOUT_MS) {
2731
+ return new Promise((resolve) => {
2732
+ const set = this.waiters.get(key) ?? /* @__PURE__ */ new Set();
2733
+ this.waiters.set(key, set);
2734
+ const settle = (outcome) => {
2735
+ if (!set.has(callback)) return;
2736
+ set.delete(callback);
2737
+ if (set.size === 0) this.waiters.delete(key);
2738
+ clearTimeout(timer);
2739
+ resolve(outcome);
2740
+ };
2741
+ const callback = (outcome) => settle(outcome);
2742
+ const timer = setTimeout(() => settle("timeout"), timeoutMs);
2743
+ set.add(callback);
2744
+ });
2745
+ }
2746
+ /** Resolve everyone waiting on `key` with the user's decision. */
2747
+ resolve(key, decision) {
2748
+ const set = this.waiters.get(key);
2749
+ if (!set) return;
2750
+ for (const callback of [...set]) callback(decision);
2751
+ }
2752
+ };
2753
+ function toDeniedError(error) {
2754
+ return { ...error, code: 1002 /* DENIED */ };
2755
+ }
2756
+ async function withPermissionRetry(send, registry, log, timeoutMs = PERMISSION_DECISION_TIMEOUT_MS) {
2757
+ for (let attempt = 0; ; attempt++) {
2758
+ try {
2759
+ return await send();
2760
+ } catch (error) {
2761
+ if (!isPermissionPromptError(error) || attempt >= MAX_PERMISSION_RETRIES) {
2762
+ throw error;
2763
+ }
2764
+ const key = permissionKey(error.resourceType, error.action, error.target);
2765
+ log(`Permission prompt required for ${key} \u2014 waiting for user decision`);
2766
+ const outcome = await registry.wait(key, timeoutMs);
2767
+ if (outcome === "granted") {
2768
+ log(`Permission ${key} granted \u2014 retrying request`);
2769
+ continue;
2770
+ }
2771
+ if (outcome === "denied") {
2772
+ log(`Permission ${key} denied`);
2773
+ throw toDeniedError(error);
2774
+ }
2775
+ log(`Permission ${key} prompt timed out`);
2776
+ throw error;
2777
+ }
2778
+ }
2779
+ }
2780
+
2878
2781
  // src/client.ts
2879
2782
  var HaexVaultSdk = class {
2880
2783
  constructor(config = {}) {
@@ -2890,6 +2793,7 @@ var HaexVaultSdk = class {
2890
2793
  this.eventListeners = /* @__PURE__ */ new Map();
2891
2794
  this.externalRequestHandlers = /* @__PURE__ */ new Map();
2892
2795
  this.reactiveSubscribers = /* @__PURE__ */ new Set();
2796
+ this.permissionWaiters = new PermissionWaiterRegistry();
2893
2797
  // Handlers
2894
2798
  this.messageHandler = null;
2895
2799
  /**
@@ -2926,6 +2830,14 @@ var HaexVaultSdk = class {
2926
2830
  this.passwords = new PasswordsAPI(this);
2927
2831
  this.mail = new MailAPI(this);
2928
2832
  installConsoleForwarding(this.config.debug);
2833
+ this.on(HAEXTENSION_EVENTS.PERMISSION_RESOLVED, (event) => {
2834
+ const data = event.data;
2835
+ if (!data) return;
2836
+ this.permissionWaiters.resolve(
2837
+ permissionKey(data.resourceType, data.action, data.target),
2838
+ data.decision === "denied" ? "denied" : "granted"
2839
+ );
2840
+ });
2929
2841
  this.readyPromise = new Promise((resolve, reject) => {
2930
2842
  this.resolveReady = resolve;
2931
2843
  this.rejectReady = reject;
@@ -3074,24 +2986,27 @@ var HaexVaultSdk = class {
3074
2986
  // ==========================================================================
3075
2987
  async request(method, params) {
3076
2988
  const resolvedParams = params ?? {};
3077
- if (this.isNativeWindow && hasTauri()) {
3078
- const paramsWithCredentials = {
3079
- ...resolvedParams,
3080
- publicKey: this._extensionInfo?.publicKey,
3081
- name: this._extensionInfo?.name
3082
- };
3083
- return sendInvoke(method, paramsWithCredentials, this.config, this.log.bind(this));
3084
- }
3085
- const requestId = generateRequestId(++this.requestCounter);
3086
- return sendPostMessage(
3087
- method,
3088
- resolvedParams,
3089
- requestId,
3090
- this.config,
3091
- this._extensionInfo,
3092
- this.pendingRequests,
3093
- this.hostPort
3094
- );
2989
+ const send = () => {
2990
+ if (this.isNativeWindow && hasTauri()) {
2991
+ const paramsWithCredentials = {
2992
+ ...resolvedParams,
2993
+ publicKey: this._extensionInfo?.publicKey,
2994
+ name: this._extensionInfo?.name
2995
+ };
2996
+ return sendInvoke(method, paramsWithCredentials, this.config, this.log.bind(this));
2997
+ }
2998
+ const requestId = generateRequestId(++this.requestCounter);
2999
+ return sendPostMessage(
3000
+ method,
3001
+ resolvedParams,
3002
+ requestId,
3003
+ this.config,
3004
+ this._extensionInfo,
3005
+ this.pendingRequests,
3006
+ this.hostPort
3007
+ );
3008
+ };
3009
+ return withPermissionRetry(send, this.permissionWaiters, this.log.bind(this));
3095
3010
  }
3096
3011
  // ==========================================================================
3097
3012
  // Private: Initialization