@haex-space/vault-sdk 3.2.7 → 3.3.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/{client-exZiz0Ph.d.ts → client-BW3ayV19.d.mts} +83 -2
- package/dist/{client-Bbm83Oy6.d.mts → client-Cm23j1wm.d.ts} +83 -2
- package/dist/index.d.mts +30 -6
- package/dist/index.d.ts +30 -6
- package/dist/index.js +186 -221
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +184 -222
- package/dist/index.mjs.map +1 -1
- package/dist/node.d.mts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/react.d.mts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +185 -224
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +185 -224
- package/dist/react.mjs.map +1 -1
- package/dist/runtime/nuxt.plugin.client.d.mts +2 -2
- package/dist/runtime/nuxt.plugin.client.d.ts +2 -2
- package/dist/runtime/nuxt.plugin.client.js +185 -224
- package/dist/runtime/nuxt.plugin.client.js.map +1 -1
- package/dist/runtime/nuxt.plugin.client.mjs +185 -224
- package/dist/runtime/nuxt.plugin.client.mjs.map +1 -1
- package/dist/svelte.d.mts +2 -2
- package/dist/svelte.d.ts +2 -2
- package/dist/svelte.js +185 -224
- package/dist/svelte.js.map +1 -1
- package/dist/svelte.mjs +185 -224
- package/dist/svelte.mjs.map +1 -1
- package/dist/{types-CDMBvvjl.d.mts → types-fHuxbqa4.d.mts} +13 -1
- package/dist/{types-CDMBvvjl.d.ts → types-fHuxbqa4.d.ts} +13 -1
- package/dist/vue.d.mts +2 -2
- package/dist/vue.d.ts +2 -2
- package/dist/vue.js +185 -224
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs +185 -224
- package/dist/vue.mjs.map +1 -1
- package/package.json +1 -1
package/dist/svelte.mjs
CHANGED
|
@@ -396,16 +396,21 @@ var HAEXTENSION_EVENTS = {
|
|
|
396
396
|
/** File system change detected (from native file watcher) */
|
|
397
397
|
FILE_CHANGED: "filesync:file-changed",
|
|
398
398
|
/** Tables have been updated via sync (CRDT pull from server) */
|
|
399
|
-
SYNC_TABLES_UPDATED: "haextension:sync:tables-updated"
|
|
399
|
+
SYNC_TABLES_UPDATED: "haextension:sync:tables-updated",
|
|
400
|
+
/** A runtime permission prompt was resolved (granted/denied) by the user.
|
|
401
|
+
* The SDK uses this to auto-retry the original request; extensions may also
|
|
402
|
+
* subscribe via `client.on(HAEXTENSION_EVENTS.PERMISSION_RESOLVED, ...)`. */
|
|
403
|
+
PERMISSION_RESOLVED: "extension:permission-resolved"
|
|
404
|
+
};
|
|
405
|
+
var NOTIFICATION_EVENTS = {
|
|
406
|
+
/** A click on one of this extension's notifications (body or action button). */
|
|
407
|
+
CLICK: "haextension:notification:click"
|
|
400
408
|
};
|
|
401
409
|
var EXTERNAL_EVENTS = {
|
|
402
410
|
/** External request from authorized client */
|
|
403
411
|
REQUEST: "haextension:external:request",
|
|
404
412
|
/** AI action request (tool calls from AI assistant) */
|
|
405
|
-
ACTION_REQUEST: "haextension:action:request"
|
|
406
|
-
/** New external client requesting authorization */
|
|
407
|
-
AUTHORIZATION_REQUEST: "external:authorization-request"
|
|
408
|
-
};
|
|
413
|
+
ACTION_REQUEST: "haextension:action:request"};
|
|
409
414
|
var SHELL_EVENTS = {
|
|
410
415
|
/** PTY output data from a shell session */
|
|
411
416
|
OUTPUT: "shell:output",
|
|
@@ -419,6 +424,9 @@ var TABLE_SEPARATOR = "__";
|
|
|
419
424
|
function getTableName(publicKey, extensionName, tableName) {
|
|
420
425
|
return `${publicKey}${TABLE_SEPARATOR}${extensionName}${TABLE_SEPARATOR}${tableName}`;
|
|
421
426
|
}
|
|
427
|
+
function isPermissionPromptError(error) {
|
|
428
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === 1004 /* PROMPT_REQUIRED */;
|
|
429
|
+
}
|
|
422
430
|
var HaexVaultSdkError = class extends Error {
|
|
423
431
|
constructor(code, messageKey, details) {
|
|
424
432
|
super(messageKey);
|
|
@@ -682,6 +690,14 @@ var MAIL_COMMANDS = {
|
|
|
682
690
|
buildRfc822: "extension_mail_build_rfc822"
|
|
683
691
|
};
|
|
684
692
|
|
|
693
|
+
// src/commands/notifications.ts
|
|
694
|
+
var NOTIFICATION_COMMANDS = {
|
|
695
|
+
/** Show an OS notification. Returns the assigned notification id. */
|
|
696
|
+
show: "extension_notifications_show",
|
|
697
|
+
/** Dismiss a previously shown notification (only own notifications). */
|
|
698
|
+
dismiss: "extension_notifications_dismiss"
|
|
699
|
+
};
|
|
700
|
+
|
|
685
701
|
// src/api/storage.ts
|
|
686
702
|
var StorageAPI = class {
|
|
687
703
|
constructor(client) {
|
|
@@ -1756,6 +1772,38 @@ var MailAPI = class {
|
|
|
1756
1772
|
}
|
|
1757
1773
|
};
|
|
1758
1774
|
|
|
1775
|
+
// src/api/notifications.ts
|
|
1776
|
+
var NotificationsAPI = class {
|
|
1777
|
+
constructor(client) {
|
|
1778
|
+
this.client = client;
|
|
1779
|
+
}
|
|
1780
|
+
/** Show a notification. Returns its id so it can be dismissed later. */
|
|
1781
|
+
async show(opts) {
|
|
1782
|
+
return this.client.request(NOTIFICATION_COMMANDS.show, {
|
|
1783
|
+
options: opts
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
/** Dismiss a previously shown notification (only own notifications). */
|
|
1787
|
+
async dismiss(id) {
|
|
1788
|
+
return this.client.request(NOTIFICATION_COMMANDS.dismiss, { id });
|
|
1789
|
+
}
|
|
1790
|
+
/**
|
|
1791
|
+
* Listen for clicks on this extension's notifications. Useful when the
|
|
1792
|
+
* extension is already open and wants to react in-app (e.g. router.push the
|
|
1793
|
+
* `path`) instead of relying on the host to focus the webview.
|
|
1794
|
+
*
|
|
1795
|
+
* Returns an unsubscribe function.
|
|
1796
|
+
*/
|
|
1797
|
+
onClick(handler) {
|
|
1798
|
+
const wrapped = (event) => {
|
|
1799
|
+
const data = event.data;
|
|
1800
|
+
if (data) handler(data);
|
|
1801
|
+
};
|
|
1802
|
+
this.client.on(NOTIFICATION_EVENTS.CLICK, wrapped);
|
|
1803
|
+
return () => this.client.off(NOTIFICATION_EVENTS.CLICK, wrapped);
|
|
1804
|
+
}
|
|
1805
|
+
};
|
|
1806
|
+
|
|
1759
1807
|
// src/client/tableName.ts
|
|
1760
1808
|
function validatePublicKey(publicKey) {
|
|
1761
1809
|
if (!publicKey || typeof publicKey !== "string" || publicKey.trim() === "") {
|
|
@@ -1873,6 +1921,21 @@ async function initNativeMode(ctx, log, onEvent, onContextChange) {
|
|
|
1873
1921
|
await setupTauriEventListeners(ctx, log, onEvent, onContextChange);
|
|
1874
1922
|
return { extensionInfo: extensionInfo2, context: context2 };
|
|
1875
1923
|
}
|
|
1924
|
+
async function forwardEvent(listen, log, onEvent, listenOptions, eventName, shape) {
|
|
1925
|
+
try {
|
|
1926
|
+
await listen(eventName, (event) => {
|
|
1927
|
+
if (event.payload == null) {
|
|
1928
|
+
log(`Event '${eventName}' received with no payload`);
|
|
1929
|
+
return;
|
|
1930
|
+
}
|
|
1931
|
+
const extra = shape ? shape(event.payload) : { data: event.payload };
|
|
1932
|
+
onEvent({ type: eventName, timestamp: Date.now(), ...extra });
|
|
1933
|
+
}, listenOptions);
|
|
1934
|
+
log(`Listener registered: ${eventName}`);
|
|
1935
|
+
} catch (error) {
|
|
1936
|
+
log(`Failed to register listener '${eventName}':`, error);
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1876
1939
|
async function setupTauriEventListeners(ctx, log, onEvent, onContextChange) {
|
|
1877
1940
|
const { listen } = getTauriEvent();
|
|
1878
1941
|
const webviewLabel = getCurrentWebviewLabel();
|
|
@@ -1904,207 +1967,30 @@ async function setupTauriEventListeners(ctx, log, onEvent, onContextChange) {
|
|
|
1904
1967
|
} catch (error) {
|
|
1905
1968
|
log("Failed to setup context change listener:", error);
|
|
1906
1969
|
}
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
type: EXTERNAL_EVENTS.ACTION_REQUEST,
|
|
1932
|
-
data: event.payload,
|
|
1933
|
-
timestamp: Date.now()
|
|
1934
|
-
});
|
|
1935
|
-
} else {
|
|
1936
|
-
log("AI action request event has no payload!");
|
|
1937
|
-
}
|
|
1938
|
-
}, listenOptions);
|
|
1939
|
-
log("AI action request listener registered successfully");
|
|
1940
|
-
} catch (error) {
|
|
1941
|
-
log("Failed to setup AI action request listener:", error);
|
|
1942
|
-
}
|
|
1943
|
-
log("Registering file change listener for:", HAEXTENSION_EVENTS.FILE_CHANGED);
|
|
1944
|
-
try {
|
|
1945
|
-
await listen(HAEXTENSION_EVENTS.FILE_CHANGED, (event) => {
|
|
1946
|
-
log("File change event received:", event.payload);
|
|
1947
|
-
if (event.payload) {
|
|
1948
|
-
const payload = event.payload;
|
|
1949
|
-
onEvent({
|
|
1950
|
-
type: HAEXTENSION_EVENTS.FILE_CHANGED,
|
|
1951
|
-
ruleId: payload.ruleId,
|
|
1952
|
-
changeType: payload.changeType,
|
|
1953
|
-
path: payload.path,
|
|
1954
|
-
timestamp: Date.now()
|
|
1955
|
-
});
|
|
1956
|
-
}
|
|
1957
|
-
}, listenOptions);
|
|
1958
|
-
log("File change listener registered successfully");
|
|
1959
|
-
} catch (error) {
|
|
1960
|
-
log("Failed to setup file change listener:", error);
|
|
1961
|
-
}
|
|
1962
|
-
log("Registering sync tables updated listener for:", HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED);
|
|
1963
|
-
try {
|
|
1964
|
-
await listen(HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED, (event) => {
|
|
1965
|
-
log("Sync tables updated event received:", event.payload);
|
|
1966
|
-
if (event.payload) {
|
|
1967
|
-
const payload = event.payload;
|
|
1968
|
-
onEvent({
|
|
1969
|
-
type: HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED,
|
|
1970
|
-
data: { tables: payload.tables },
|
|
1971
|
-
timestamp: Date.now()
|
|
1972
|
-
});
|
|
1973
|
-
}
|
|
1974
|
-
}, listenOptions);
|
|
1975
|
-
log("Sync tables updated listener registered successfully");
|
|
1976
|
-
} catch (error) {
|
|
1977
|
-
log("Failed to setup sync tables updated listener:", error);
|
|
1978
|
-
}
|
|
1979
|
-
log("Setting up LocalSend event listeners");
|
|
1980
|
-
try {
|
|
1981
|
-
await setupLocalSendEventListeners(log, onEvent, listenOptions);
|
|
1982
|
-
log("LocalSend event listeners setup complete");
|
|
1983
|
-
} catch (error) {
|
|
1984
|
-
log("Failed to setup LocalSend event listeners:", error);
|
|
1985
|
-
}
|
|
1986
|
-
log("Setting up Shell event listeners");
|
|
1987
|
-
try {
|
|
1988
|
-
await listen(SHELL_EVENTS.OUTPUT, (event) => {
|
|
1989
|
-
if (event.payload) {
|
|
1990
|
-
const payload = event.payload;
|
|
1991
|
-
onEvent({
|
|
1992
|
-
type: SHELL_EVENTS.OUTPUT,
|
|
1993
|
-
timestamp: Date.now(),
|
|
1994
|
-
sessionId: payload.sessionId,
|
|
1995
|
-
data: payload.data
|
|
1996
|
-
});
|
|
1997
|
-
}
|
|
1998
|
-
}, listenOptions);
|
|
1999
|
-
log("Shell output listener registered");
|
|
2000
|
-
await listen(SHELL_EVENTS.EXIT, (event) => {
|
|
2001
|
-
if (event.payload) {
|
|
2002
|
-
const payload = event.payload;
|
|
2003
|
-
onEvent({
|
|
2004
|
-
type: SHELL_EVENTS.EXIT,
|
|
2005
|
-
timestamp: Date.now(),
|
|
2006
|
-
sessionId: payload.sessionId,
|
|
2007
|
-
exitCode: payload.exitCode
|
|
2008
|
-
});
|
|
2009
|
-
}
|
|
2010
|
-
}, listenOptions);
|
|
2011
|
-
log("Shell exit listener registered");
|
|
2012
|
-
} catch (error) {
|
|
2013
|
-
log("Failed to setup Shell event listeners:", error);
|
|
2014
|
-
}
|
|
2015
|
-
}
|
|
2016
|
-
async function setupLocalSendEventListeners(log, onEvent, listenOptions) {
|
|
2017
|
-
const { listen } = getTauriEvent();
|
|
2018
|
-
try {
|
|
2019
|
-
await listen(LOCALSEND_EVENTS.deviceDiscovered, (event) => {
|
|
2020
|
-
log("LocalSend device discovered:", event.payload);
|
|
2021
|
-
if (event.payload) {
|
|
2022
|
-
onEvent({
|
|
2023
|
-
type: LOCALSEND_EVENTS.deviceDiscovered,
|
|
2024
|
-
data: event.payload,
|
|
2025
|
-
timestamp: Date.now()
|
|
2026
|
-
});
|
|
2027
|
-
}
|
|
2028
|
-
}, listenOptions);
|
|
2029
|
-
log("LocalSend device discovered listener registered");
|
|
2030
|
-
} catch (error) {
|
|
2031
|
-
log("Failed to setup LocalSend device discovered listener:", error);
|
|
2032
|
-
}
|
|
2033
|
-
try {
|
|
2034
|
-
await listen(LOCALSEND_EVENTS.deviceLost, (event) => {
|
|
2035
|
-
log("LocalSend device lost:", event.payload);
|
|
2036
|
-
if (event.payload) {
|
|
2037
|
-
onEvent({
|
|
2038
|
-
type: LOCALSEND_EVENTS.deviceLost,
|
|
2039
|
-
data: event.payload,
|
|
2040
|
-
timestamp: Date.now()
|
|
2041
|
-
});
|
|
2042
|
-
}
|
|
2043
|
-
}, listenOptions);
|
|
2044
|
-
log("LocalSend device lost listener registered");
|
|
2045
|
-
} catch (error) {
|
|
2046
|
-
log("Failed to setup LocalSend device lost listener:", error);
|
|
2047
|
-
}
|
|
2048
|
-
try {
|
|
2049
|
-
await listen(LOCALSEND_EVENTS.transferRequest, (event) => {
|
|
2050
|
-
log("LocalSend transfer request:", event.payload);
|
|
2051
|
-
if (event.payload) {
|
|
2052
|
-
onEvent({
|
|
2053
|
-
type: LOCALSEND_EVENTS.transferRequest,
|
|
2054
|
-
data: event.payload,
|
|
2055
|
-
timestamp: Date.now()
|
|
2056
|
-
});
|
|
2057
|
-
}
|
|
2058
|
-
}, listenOptions);
|
|
2059
|
-
log("LocalSend transfer request listener registered");
|
|
2060
|
-
} catch (error) {
|
|
2061
|
-
log("Failed to setup LocalSend transfer request listener:", error);
|
|
2062
|
-
}
|
|
2063
|
-
try {
|
|
2064
|
-
await listen(LOCALSEND_EVENTS.transferProgress, (event) => {
|
|
2065
|
-
log("LocalSend transfer progress event:", event);
|
|
2066
|
-
if (event.payload) {
|
|
2067
|
-
onEvent({
|
|
2068
|
-
type: LOCALSEND_EVENTS.transferProgress,
|
|
2069
|
-
data: event.payload,
|
|
2070
|
-
timestamp: Date.now()
|
|
2071
|
-
});
|
|
2072
|
-
}
|
|
2073
|
-
}, listenOptions);
|
|
2074
|
-
log("LocalSend transfer progress listener registered");
|
|
2075
|
-
} catch (error) {
|
|
2076
|
-
log("Failed to setup LocalSend transfer progress listener:", error);
|
|
2077
|
-
}
|
|
2078
|
-
try {
|
|
2079
|
-
await listen(LOCALSEND_EVENTS.transferComplete, (event) => {
|
|
2080
|
-
log("LocalSend transfer complete:", event.payload);
|
|
2081
|
-
if (event.payload) {
|
|
2082
|
-
onEvent({
|
|
2083
|
-
type: LOCALSEND_EVENTS.transferComplete,
|
|
2084
|
-
data: event.payload,
|
|
2085
|
-
timestamp: Date.now()
|
|
2086
|
-
});
|
|
2087
|
-
}
|
|
2088
|
-
}, listenOptions);
|
|
2089
|
-
log("LocalSend transfer complete listener registered");
|
|
2090
|
-
} catch (error) {
|
|
2091
|
-
log("Failed to setup LocalSend transfer complete listener:", error);
|
|
2092
|
-
}
|
|
2093
|
-
try {
|
|
2094
|
-
await listen(LOCALSEND_EVENTS.transferFailed, (event) => {
|
|
2095
|
-
log("LocalSend transfer failed:", event.payload);
|
|
2096
|
-
if (event.payload) {
|
|
2097
|
-
onEvent({
|
|
2098
|
-
type: LOCALSEND_EVENTS.transferFailed,
|
|
2099
|
-
data: event.payload,
|
|
2100
|
-
timestamp: Date.now()
|
|
2101
|
-
});
|
|
2102
|
-
}
|
|
2103
|
-
}, listenOptions);
|
|
2104
|
-
log("LocalSend transfer failed listener registered");
|
|
2105
|
-
} catch (error) {
|
|
2106
|
-
log("Failed to setup LocalSend transfer failed listener:", error);
|
|
2107
|
-
}
|
|
1970
|
+
for (const eventName of [
|
|
1971
|
+
HAEXTENSION_EVENTS.PERMISSION_RESOLVED,
|
|
1972
|
+
EXTERNAL_EVENTS.REQUEST,
|
|
1973
|
+
EXTERNAL_EVENTS.ACTION_REQUEST,
|
|
1974
|
+
NOTIFICATION_EVENTS.CLICK,
|
|
1975
|
+
...Object.values(LOCALSEND_EVENTS)
|
|
1976
|
+
]) {
|
|
1977
|
+
await forwardEvent(listen, log, onEvent, listenOptions, eventName);
|
|
1978
|
+
}
|
|
1979
|
+
await forwardEvent(listen, log, onEvent, listenOptions, HAEXTENSION_EVENTS.SYNC_TABLES_UPDATED, (payload) => ({
|
|
1980
|
+
data: { tables: payload.tables }
|
|
1981
|
+
}));
|
|
1982
|
+
await forwardEvent(listen, log, onEvent, listenOptions, HAEXTENSION_EVENTS.FILE_CHANGED, (payload) => {
|
|
1983
|
+
const { ruleId, changeType, path } = payload;
|
|
1984
|
+
return { ruleId, changeType, path };
|
|
1985
|
+
});
|
|
1986
|
+
await forwardEvent(listen, log, onEvent, listenOptions, SHELL_EVENTS.OUTPUT, (payload) => {
|
|
1987
|
+
const { sessionId, data } = payload;
|
|
1988
|
+
return { sessionId, data };
|
|
1989
|
+
});
|
|
1990
|
+
await forwardEvent(listen, log, onEvent, listenOptions, SHELL_EVENTS.EXIT, (payload) => {
|
|
1991
|
+
const { sessionId, exitCode } = payload;
|
|
1992
|
+
return { sessionId, exitCode };
|
|
1993
|
+
});
|
|
2108
1994
|
}
|
|
2109
1995
|
async function initIframeMode(ctx, log, messageHandler) {
|
|
2110
1996
|
if (!isInIframe()) {
|
|
@@ -2448,6 +2334,68 @@ var AI_COMMANDS = {
|
|
|
2448
2334
|
actionRespond: "ai_action_respond"
|
|
2449
2335
|
};
|
|
2450
2336
|
|
|
2337
|
+
// src/client/permissionRetry.ts
|
|
2338
|
+
var PERMISSION_DECISION_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
2339
|
+
var MAX_PERMISSION_RETRIES = 3;
|
|
2340
|
+
function permissionKey(resourceType, action, target) {
|
|
2341
|
+
return `${resourceType}:${action}:${target}`;
|
|
2342
|
+
}
|
|
2343
|
+
var PermissionWaiterRegistry = class {
|
|
2344
|
+
constructor() {
|
|
2345
|
+
this.waiters = /* @__PURE__ */ new Map();
|
|
2346
|
+
}
|
|
2347
|
+
/** Wait for a decision on `key`; resolves "timeout" if none arrives in time. */
|
|
2348
|
+
wait(key, timeoutMs = PERMISSION_DECISION_TIMEOUT_MS) {
|
|
2349
|
+
return new Promise((resolve) => {
|
|
2350
|
+
const set = this.waiters.get(key) ?? /* @__PURE__ */ new Set();
|
|
2351
|
+
this.waiters.set(key, set);
|
|
2352
|
+
const settle = (outcome) => {
|
|
2353
|
+
if (!set.has(callback)) return;
|
|
2354
|
+
set.delete(callback);
|
|
2355
|
+
if (set.size === 0) this.waiters.delete(key);
|
|
2356
|
+
clearTimeout(timer);
|
|
2357
|
+
resolve(outcome);
|
|
2358
|
+
};
|
|
2359
|
+
const callback = (outcome) => settle(outcome);
|
|
2360
|
+
const timer = setTimeout(() => settle("timeout"), timeoutMs);
|
|
2361
|
+
set.add(callback);
|
|
2362
|
+
});
|
|
2363
|
+
}
|
|
2364
|
+
/** Resolve everyone waiting on `key` with the user's decision. */
|
|
2365
|
+
resolve(key, decision) {
|
|
2366
|
+
const set = this.waiters.get(key);
|
|
2367
|
+
if (!set) return;
|
|
2368
|
+
for (const callback of [...set]) callback(decision);
|
|
2369
|
+
}
|
|
2370
|
+
};
|
|
2371
|
+
function toDeniedError(error) {
|
|
2372
|
+
return { ...error, code: 1002 /* DENIED */ };
|
|
2373
|
+
}
|
|
2374
|
+
async function withPermissionRetry(send, registry, log, timeoutMs = PERMISSION_DECISION_TIMEOUT_MS) {
|
|
2375
|
+
for (let attempt = 0; ; attempt++) {
|
|
2376
|
+
try {
|
|
2377
|
+
return await send();
|
|
2378
|
+
} catch (error) {
|
|
2379
|
+
if (!isPermissionPromptError(error) || attempt >= MAX_PERMISSION_RETRIES) {
|
|
2380
|
+
throw error;
|
|
2381
|
+
}
|
|
2382
|
+
const key = permissionKey(error.resourceType, error.action, error.target);
|
|
2383
|
+
log(`Permission prompt required for ${key} \u2014 waiting for user decision`);
|
|
2384
|
+
const outcome = await registry.wait(key, timeoutMs);
|
|
2385
|
+
if (outcome === "granted") {
|
|
2386
|
+
log(`Permission ${key} granted \u2014 retrying request`);
|
|
2387
|
+
continue;
|
|
2388
|
+
}
|
|
2389
|
+
if (outcome === "denied") {
|
|
2390
|
+
log(`Permission ${key} denied`);
|
|
2391
|
+
throw toDeniedError(error);
|
|
2392
|
+
}
|
|
2393
|
+
log(`Permission ${key} prompt timed out`);
|
|
2394
|
+
throw error;
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2451
2399
|
// src/client.ts
|
|
2452
2400
|
var HaexVaultSdk = class {
|
|
2453
2401
|
constructor(config = {}) {
|
|
@@ -2463,6 +2411,7 @@ var HaexVaultSdk = class {
|
|
|
2463
2411
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
2464
2412
|
this.externalRequestHandlers = /* @__PURE__ */ new Map();
|
|
2465
2413
|
this.reactiveSubscribers = /* @__PURE__ */ new Set();
|
|
2414
|
+
this.permissionWaiters = new PermissionWaiterRegistry();
|
|
2466
2415
|
// Handlers
|
|
2467
2416
|
this.messageHandler = null;
|
|
2468
2417
|
/**
|
|
@@ -2498,7 +2447,16 @@ var HaexVaultSdk = class {
|
|
|
2498
2447
|
this.shell = new ShellAPI(this);
|
|
2499
2448
|
this.passwords = new PasswordsAPI(this);
|
|
2500
2449
|
this.mail = new MailAPI(this);
|
|
2450
|
+
this.notifications = new NotificationsAPI(this);
|
|
2501
2451
|
installConsoleForwarding(this.config.debug);
|
|
2452
|
+
this.on(HAEXTENSION_EVENTS.PERMISSION_RESOLVED, (event) => {
|
|
2453
|
+
const data = event.data;
|
|
2454
|
+
if (!data) return;
|
|
2455
|
+
this.permissionWaiters.resolve(
|
|
2456
|
+
permissionKey(data.resourceType, data.action, data.target),
|
|
2457
|
+
data.decision === "denied" ? "denied" : "granted"
|
|
2458
|
+
);
|
|
2459
|
+
});
|
|
2502
2460
|
this.readyPromise = new Promise((resolve, reject) => {
|
|
2503
2461
|
this.resolveReady = resolve;
|
|
2504
2462
|
this.rejectReady = reject;
|
|
@@ -2647,24 +2605,27 @@ var HaexVaultSdk = class {
|
|
|
2647
2605
|
// ==========================================================================
|
|
2648
2606
|
async request(method, params) {
|
|
2649
2607
|
const resolvedParams = params ?? {};
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2608
|
+
const send = () => {
|
|
2609
|
+
if (this.isNativeWindow && hasTauri()) {
|
|
2610
|
+
const paramsWithCredentials = {
|
|
2611
|
+
...resolvedParams,
|
|
2612
|
+
publicKey: this._extensionInfo?.publicKey,
|
|
2613
|
+
name: this._extensionInfo?.name
|
|
2614
|
+
};
|
|
2615
|
+
return sendInvoke(method, paramsWithCredentials, this.config, this.log.bind(this));
|
|
2616
|
+
}
|
|
2617
|
+
const requestId = generateRequestId(++this.requestCounter);
|
|
2618
|
+
return sendPostMessage(
|
|
2619
|
+
method,
|
|
2620
|
+
resolvedParams,
|
|
2621
|
+
requestId,
|
|
2622
|
+
this.config,
|
|
2623
|
+
this._extensionInfo,
|
|
2624
|
+
this.pendingRequests,
|
|
2625
|
+
this.hostPort
|
|
2626
|
+
);
|
|
2627
|
+
};
|
|
2628
|
+
return withPermissionRetry(send, this.permissionWaiters, this.log.bind(this));
|
|
2668
2629
|
}
|
|
2669
2630
|
// ==========================================================================
|
|
2670
2631
|
// Private: Initialization
|