@haex-space/vault-sdk 2.3.16 → 2.5.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-ChH7wiuU.d.ts → client-BNq2TcVs.d.ts} +25 -95
- package/dist/{client-8eGxojZ1.d.mts → client-DQ6VwHic.d.mts} +25 -95
- package/dist/index.d.mts +75 -5
- package/dist/index.d.ts +75 -5
- package/dist/index.js +1076 -680
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1074 -680
- 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 +1025 -658
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +1025 -658
- 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 +1034 -667
- package/dist/runtime/nuxt.plugin.client.js.map +1 -1
- package/dist/runtime/nuxt.plugin.client.mjs +1034 -667
- 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 +1027 -660
- package/dist/svelte.js.map +1 -1
- package/dist/svelte.mjs +1027 -660
- package/dist/svelte.mjs.map +1 -1
- package/dist/{types-DBF83o_W.d.mts → types-Bw5uc1vm.d.mts} +70 -11
- package/dist/{types-DBF83o_W.d.ts → types-Bw5uc1vm.d.ts} +70 -11
- package/dist/vue.d.mts +2 -2
- package/dist/vue.d.ts +2 -2
- package/dist/vue.js +1025 -658
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs +1025 -658
- package/dist/vue.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -11,9 +11,47 @@ var HAEXTENSION_EVENTS = {
|
|
|
11
11
|
/** Context (theme, locale, platform) has changed */
|
|
12
12
|
CONTEXT_CHANGED: "haextension:context:changed",
|
|
13
13
|
/** Search request from HaexHub */
|
|
14
|
-
SEARCH_REQUEST: "haextension:search:request"
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
SEARCH_REQUEST: "haextension:search:request"
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/types.ts
|
|
18
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
19
|
+
var TABLE_SEPARATOR = "__";
|
|
20
|
+
function getTableName(publicKey, extensionName, tableName) {
|
|
21
|
+
return `${publicKey}${TABLE_SEPARATOR}${extensionName}${TABLE_SEPARATOR}${tableName}`;
|
|
22
|
+
}
|
|
23
|
+
var HaexVaultSdkError = class extends Error {
|
|
24
|
+
constructor(code, messageKey, details) {
|
|
25
|
+
super(messageKey);
|
|
26
|
+
this.code = code;
|
|
27
|
+
this.messageKey = messageKey;
|
|
28
|
+
this.details = details;
|
|
29
|
+
this.name = "HaexVaultSdkError";
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get localized error message
|
|
33
|
+
* @param locale - Locale code (e.g., 'en', 'de')
|
|
34
|
+
* @param translations - Translation object
|
|
35
|
+
*/
|
|
36
|
+
getLocalizedMessage(locale = "en", translations) {
|
|
37
|
+
if (!translations || !translations[locale]) {
|
|
38
|
+
return this.messageKey;
|
|
39
|
+
}
|
|
40
|
+
let message = translations[locale][this.messageKey] || this.messageKey;
|
|
41
|
+
if (this.details) {
|
|
42
|
+
Object.entries(this.details).forEach(([key, value]) => {
|
|
43
|
+
message = message.replace(`{${key}}`, String(value));
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return message;
|
|
47
|
+
}
|
|
48
|
+
toJSON() {
|
|
49
|
+
return {
|
|
50
|
+
code: this.code,
|
|
51
|
+
message: this.messageKey,
|
|
52
|
+
details: this.details
|
|
53
|
+
};
|
|
54
|
+
}
|
|
17
55
|
};
|
|
18
56
|
|
|
19
57
|
// src/methods.ts
|
|
@@ -77,54 +115,6 @@ var HAEXTENSION_METHODS = {
|
|
|
77
115
|
}
|
|
78
116
|
};
|
|
79
117
|
|
|
80
|
-
// src/messages.ts
|
|
81
|
-
var HAEXSPACE_MESSAGE_TYPES = {
|
|
82
|
-
/** Debug message for development/troubleshooting */
|
|
83
|
-
DEBUG: "haexspace:debug",
|
|
84
|
-
/** Console forwarding from extension iframe */
|
|
85
|
-
CONSOLE_FORWARD: "console.forward"
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// src/types.ts
|
|
89
|
-
var DEFAULT_TIMEOUT = 3e4;
|
|
90
|
-
var TABLE_SEPARATOR = "__";
|
|
91
|
-
function getTableName(publicKey, extensionName, tableName) {
|
|
92
|
-
return `${publicKey}${TABLE_SEPARATOR}${extensionName}${TABLE_SEPARATOR}${tableName}`;
|
|
93
|
-
}
|
|
94
|
-
var HaexHubError = class extends Error {
|
|
95
|
-
constructor(code, messageKey, details) {
|
|
96
|
-
super(messageKey);
|
|
97
|
-
this.code = code;
|
|
98
|
-
this.messageKey = messageKey;
|
|
99
|
-
this.details = details;
|
|
100
|
-
this.name = "HaexHubError";
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Get localized error message
|
|
104
|
-
* @param locale - Locale code (e.g., 'en', 'de')
|
|
105
|
-
* @param translations - Translation object
|
|
106
|
-
*/
|
|
107
|
-
getLocalizedMessage(locale = "en", translations) {
|
|
108
|
-
if (!translations || !translations[locale]) {
|
|
109
|
-
return this.messageKey;
|
|
110
|
-
}
|
|
111
|
-
let message = translations[locale][this.messageKey] || this.messageKey;
|
|
112
|
-
if (this.details) {
|
|
113
|
-
Object.entries(this.details).forEach(([key, value]) => {
|
|
114
|
-
message = message.replace(`{${key}}`, String(value));
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
return message;
|
|
118
|
-
}
|
|
119
|
-
toJSON() {
|
|
120
|
-
return {
|
|
121
|
-
code: this.code,
|
|
122
|
-
message: this.messageKey,
|
|
123
|
-
details: this.details
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
|
|
128
118
|
// src/api/storage.ts
|
|
129
119
|
var StorageAPI = class {
|
|
130
120
|
constructor(client) {
|
|
@@ -668,6 +658,14 @@ var PermissionsAPI = class {
|
|
|
668
658
|
}
|
|
669
659
|
};
|
|
670
660
|
|
|
661
|
+
// src/messages.ts
|
|
662
|
+
var HAEXSPACE_MESSAGE_TYPES = {
|
|
663
|
+
/** Debug message for development/troubleshooting */
|
|
664
|
+
DEBUG: "haexspace:debug",
|
|
665
|
+
/** Console forwarding from extension iframe */
|
|
666
|
+
CONSOLE_FORWARD: "console.forward"
|
|
667
|
+
};
|
|
668
|
+
|
|
671
669
|
// src/polyfills/consoleForwarding.ts
|
|
672
670
|
var originalConsole = {
|
|
673
671
|
log: console.log,
|
|
@@ -733,548 +731,543 @@ function installConsoleForwarding(debug = false) {
|
|
|
733
731
|
interceptConsole("debug");
|
|
734
732
|
console.log("[HaexSpace] Console forwarding installed");
|
|
735
733
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
this._context = null;
|
|
746
|
-
this.reactiveSubscribers = /* @__PURE__ */ new Set();
|
|
747
|
-
this.isNativeWindow = false;
|
|
748
|
-
// Wird im Konstruktor initialisiert
|
|
749
|
-
this.setupPromise = null;
|
|
750
|
-
this.setupHook = null;
|
|
751
|
-
this._setupCompleted = false;
|
|
752
|
-
this.orm = null;
|
|
753
|
-
this.config = {
|
|
754
|
-
debug: config.debug ?? false,
|
|
755
|
-
timeout: config.timeout ?? DEFAULT_TIMEOUT,
|
|
756
|
-
manifest: config.manifest
|
|
757
|
-
};
|
|
758
|
-
this.storage = new StorageAPI(this);
|
|
759
|
-
this.database = new DatabaseAPI(this);
|
|
760
|
-
this.filesystem = new FilesystemAPI(this);
|
|
761
|
-
this.web = new WebAPI(this);
|
|
762
|
-
this.permissions = new PermissionsAPI(this);
|
|
763
|
-
installConsoleForwarding(this.config.debug);
|
|
764
|
-
this.readyPromise = new Promise((resolve) => {
|
|
765
|
-
this.resolveReady = resolve;
|
|
766
|
-
});
|
|
767
|
-
this.init();
|
|
768
|
-
}
|
|
769
|
-
/**
|
|
770
|
-
* Gibt ein Promise zurück, das aufgelöst wird, sobald der Client
|
|
771
|
-
* initialisiert ist und Extension-Infos empfangen hat.
|
|
772
|
-
*/
|
|
773
|
-
async ready() {
|
|
774
|
-
return this.readyPromise;
|
|
734
|
+
|
|
735
|
+
// src/client/tableName.ts
|
|
736
|
+
function validatePublicKey(publicKey) {
|
|
737
|
+
if (!publicKey || typeof publicKey !== "string" || publicKey.trim() === "") {
|
|
738
|
+
throw new HaexVaultSdkError(
|
|
739
|
+
"INVALID_PUBLIC_KEY" /* INVALID_PUBLIC_KEY */,
|
|
740
|
+
"errors.invalid_public_key",
|
|
741
|
+
{ publicKey }
|
|
742
|
+
);
|
|
775
743
|
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
744
|
+
}
|
|
745
|
+
function validateExtensionName(extensionName) {
|
|
746
|
+
if (!extensionName || !/^[a-z][a-z0-9-]*$/i.test(extensionName)) {
|
|
747
|
+
throw new HaexVaultSdkError(
|
|
748
|
+
"INVALID_EXTENSION_NAME" /* INVALID_EXTENSION_NAME */,
|
|
749
|
+
"errors.invalid_extension_name",
|
|
750
|
+
{ extensionName }
|
|
751
|
+
);
|
|
781
752
|
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
if (this.setupHook) {
|
|
789
|
-
throw new Error("Setup hook already registered");
|
|
790
|
-
}
|
|
791
|
-
this.setupHook = setupFn;
|
|
753
|
+
if (extensionName.includes(TABLE_SEPARATOR)) {
|
|
754
|
+
throw new HaexVaultSdkError(
|
|
755
|
+
"INVALID_EXTENSION_NAME" /* INVALID_EXTENSION_NAME */,
|
|
756
|
+
"errors.extension_name_contains_separator",
|
|
757
|
+
{ extensionName, separator: TABLE_SEPARATOR }
|
|
758
|
+
);
|
|
792
759
|
}
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
if (!this.setupHook || this.setupCompleted) {
|
|
801
|
-
return;
|
|
802
|
-
}
|
|
803
|
-
if (!this.setupPromise) {
|
|
804
|
-
this.setupPromise = this.runSetupAsync();
|
|
805
|
-
}
|
|
806
|
-
return this.setupPromise;
|
|
760
|
+
}
|
|
761
|
+
function validateTableName(tableName) {
|
|
762
|
+
if (!tableName || typeof tableName !== "string") {
|
|
763
|
+
throw new HaexVaultSdkError(
|
|
764
|
+
"INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
|
|
765
|
+
"errors.table_name_empty"
|
|
766
|
+
);
|
|
807
767
|
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
this.log("[HaexSpace] Setup completed successfully");
|
|
815
|
-
this.notifySubscribers();
|
|
816
|
-
} catch (error) {
|
|
817
|
-
this.log("[HaexSpace] Setup failed:", error);
|
|
818
|
-
throw error;
|
|
819
|
-
}
|
|
768
|
+
if (tableName.includes(TABLE_SEPARATOR)) {
|
|
769
|
+
throw new HaexVaultSdkError(
|
|
770
|
+
"INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
|
|
771
|
+
"errors.table_name_contains_separator",
|
|
772
|
+
{ tableName, separator: TABLE_SEPARATOR }
|
|
773
|
+
);
|
|
820
774
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
*/
|
|
827
|
-
initializeDatabase(schema) {
|
|
828
|
-
if (!this._extensionInfo) {
|
|
829
|
-
throw new HaexHubError(
|
|
830
|
-
"EXTENSION_INFO_UNAVAILABLE" /* EXTENSION_INFO_UNAVAILABLE */,
|
|
831
|
-
"errors.client_not_ready"
|
|
832
|
-
);
|
|
833
|
-
}
|
|
834
|
-
const dbInstance = sqliteProxy.drizzle(
|
|
835
|
-
async (sql, params, method) => {
|
|
836
|
-
try {
|
|
837
|
-
if (method === "run" || method === "all") {
|
|
838
|
-
const result2 = await this.request(
|
|
839
|
-
HAEXTENSION_METHODS.database.execute,
|
|
840
|
-
{
|
|
841
|
-
query: sql,
|
|
842
|
-
params
|
|
843
|
-
}
|
|
844
|
-
);
|
|
845
|
-
if (method === "all") {
|
|
846
|
-
return { rows: result2.rows || [] };
|
|
847
|
-
}
|
|
848
|
-
if (result2.rows && Array.isArray(result2.rows) && result2.rows.length > 0) {
|
|
849
|
-
return { rows: result2.rows };
|
|
850
|
-
}
|
|
851
|
-
return result2;
|
|
852
|
-
}
|
|
853
|
-
const result = await this.request(HAEXTENSION_METHODS.database.query, {
|
|
854
|
-
query: sql,
|
|
855
|
-
params
|
|
856
|
-
});
|
|
857
|
-
const rows = result.rows;
|
|
858
|
-
if (method === "get") {
|
|
859
|
-
return { rows: rows.length > 0 ? rows.at(0) : void 0 };
|
|
860
|
-
}
|
|
861
|
-
return { rows };
|
|
862
|
-
} catch (error) {
|
|
863
|
-
this.log("Database operation failed:", error);
|
|
864
|
-
throw error;
|
|
865
|
-
}
|
|
866
|
-
},
|
|
867
|
-
{
|
|
868
|
-
schema,
|
|
869
|
-
logger: false
|
|
870
|
-
}
|
|
775
|
+
if (!/^[a-z][a-z0-9-_]*$/i.test(tableName)) {
|
|
776
|
+
throw new HaexVaultSdkError(
|
|
777
|
+
"INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
|
|
778
|
+
"errors.table_name_format",
|
|
779
|
+
{ tableName }
|
|
871
780
|
);
|
|
872
|
-
this.orm = dbInstance;
|
|
873
|
-
return dbInstance;
|
|
874
781
|
}
|
|
875
|
-
|
|
876
|
-
|
|
782
|
+
}
|
|
783
|
+
function getExtensionTableName(extensionInfo, tableName) {
|
|
784
|
+
if (!extensionInfo) {
|
|
785
|
+
throw new HaexVaultSdkError(
|
|
786
|
+
"EXTENSION_INFO_UNAVAILABLE" /* EXTENSION_INFO_UNAVAILABLE */,
|
|
787
|
+
"errors.extension_info_unavailable"
|
|
788
|
+
);
|
|
877
789
|
}
|
|
878
|
-
|
|
879
|
-
|
|
790
|
+
validateTableName(tableName);
|
|
791
|
+
const { publicKey, name } = extensionInfo;
|
|
792
|
+
return `"${getTableName(publicKey, name, tableName)}"`;
|
|
793
|
+
}
|
|
794
|
+
function getDependencyTableName(publicKey, extensionName, tableName) {
|
|
795
|
+
validatePublicKey(publicKey);
|
|
796
|
+
validateExtensionName(extensionName);
|
|
797
|
+
validateTableName(tableName);
|
|
798
|
+
return `"${getTableName(publicKey, extensionName, tableName)}"`;
|
|
799
|
+
}
|
|
800
|
+
function parseTableName(fullTableName) {
|
|
801
|
+
let cleanTableName = fullTableName;
|
|
802
|
+
if (cleanTableName.startsWith('"') && cleanTableName.endsWith('"')) {
|
|
803
|
+
cleanTableName = cleanTableName.slice(1, -1);
|
|
880
804
|
}
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
return
|
|
884
|
-
this.reactiveSubscribers.delete(callback);
|
|
885
|
-
};
|
|
805
|
+
const parts = cleanTableName.split(TABLE_SEPARATOR);
|
|
806
|
+
if (parts.length !== 3) {
|
|
807
|
+
return null;
|
|
886
808
|
}
|
|
887
|
-
|
|
888
|
-
|
|
809
|
+
const [publicKey, extensionName, tableName] = parts;
|
|
810
|
+
if (!publicKey || !extensionName || !tableName) {
|
|
811
|
+
return null;
|
|
889
812
|
}
|
|
890
|
-
|
|
891
|
-
|
|
813
|
+
return {
|
|
814
|
+
publicKey,
|
|
815
|
+
extensionName,
|
|
816
|
+
tableName
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// src/client/init.ts
|
|
821
|
+
function isInIframe() {
|
|
822
|
+
return window.self !== window.top;
|
|
823
|
+
}
|
|
824
|
+
function hasTauri() {
|
|
825
|
+
return typeof window.__TAURI__ !== "undefined";
|
|
826
|
+
}
|
|
827
|
+
function getTauriCore() {
|
|
828
|
+
return window.__TAURI__.core;
|
|
829
|
+
}
|
|
830
|
+
function getTauriEvent() {
|
|
831
|
+
return window.__TAURI__.event;
|
|
832
|
+
}
|
|
833
|
+
async function initNativeMode(ctx, log, onEvent, onContextChange) {
|
|
834
|
+
const { invoke } = getTauriCore();
|
|
835
|
+
const extensionInfo = await invoke("webview_extension_get_info");
|
|
836
|
+
const context = await invoke("webview_extension_context_get");
|
|
837
|
+
ctx.state.isNativeWindow = true;
|
|
838
|
+
ctx.state.initialized = true;
|
|
839
|
+
ctx.state.extensionInfo = extensionInfo;
|
|
840
|
+
ctx.state.context = context;
|
|
841
|
+
log("HaexVault SDK initialized in native WebViewWindow mode");
|
|
842
|
+
log("Extension info:", extensionInfo);
|
|
843
|
+
log("Application context:", context);
|
|
844
|
+
await setupTauriEventListeners(ctx, log, onEvent, onContextChange);
|
|
845
|
+
return { extensionInfo, context };
|
|
846
|
+
}
|
|
847
|
+
async function setupTauriEventListeners(ctx, log, onEvent, onContextChange) {
|
|
848
|
+
const { listen } = getTauriEvent();
|
|
849
|
+
console.log("[HaexVault SDK] Setting up Tauri event listener for:", HAEXTENSION_EVENTS.CONTEXT_CHANGED);
|
|
850
|
+
try {
|
|
851
|
+
await listen(HAEXTENSION_EVENTS.CONTEXT_CHANGED, (event) => {
|
|
852
|
+
console.log("[HaexVault SDK] Received Tauri event:", HAEXTENSION_EVENTS.CONTEXT_CHANGED, event);
|
|
853
|
+
log("Received context change event:", event);
|
|
854
|
+
const payload = event.payload;
|
|
855
|
+
if (payload?.context) {
|
|
856
|
+
ctx.state.context = payload.context;
|
|
857
|
+
console.log("[HaexVault SDK] Updated context to:", ctx.state.context);
|
|
858
|
+
onContextChange(payload.context);
|
|
859
|
+
onEvent({
|
|
860
|
+
type: HAEXTENSION_EVENTS.CONTEXT_CHANGED,
|
|
861
|
+
data: { context: ctx.state.context },
|
|
862
|
+
timestamp: Date.now()
|
|
863
|
+
});
|
|
864
|
+
} else {
|
|
865
|
+
console.warn("[HaexVault SDK] Event received but no context in payload:", event);
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
console.log("[HaexVault SDK] Context change listener registered successfully");
|
|
869
|
+
} catch (error) {
|
|
870
|
+
console.error("[HaexVault SDK] Failed to setup context change listener:", error);
|
|
871
|
+
log("Failed to setup context change listener:", error);
|
|
872
|
+
}
|
|
873
|
+
try {
|
|
874
|
+
await listen(HAEXTENSION_EVENTS.EXTERNAL_REQUEST, (event) => {
|
|
875
|
+
log("Received external request event:", event);
|
|
876
|
+
if (event.payload) {
|
|
877
|
+
onEvent({
|
|
878
|
+
type: HAEXTENSION_EVENTS.EXTERNAL_REQUEST,
|
|
879
|
+
data: event.payload,
|
|
880
|
+
timestamp: Date.now()
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
console.log("[HaexVault SDK] External request listener registered successfully");
|
|
885
|
+
} catch (error) {
|
|
886
|
+
console.error("[HaexVault SDK] Failed to setup external request listener:", error);
|
|
887
|
+
log("Failed to setup external request listener:", error);
|
|
892
888
|
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
889
|
+
}
|
|
890
|
+
async function initIframeMode(ctx, log, messageHandler, request) {
|
|
891
|
+
if (!isInIframe()) {
|
|
892
|
+
throw new HaexVaultSdkError("NOT_IN_IFRAME" /* NOT_IN_IFRAME */, "errors.not_in_iframe");
|
|
893
|
+
}
|
|
894
|
+
ctx.handlers.messageHandler = messageHandler;
|
|
895
|
+
window.addEventListener("message", messageHandler);
|
|
896
|
+
ctx.state.isNativeWindow = false;
|
|
897
|
+
ctx.state.initialized = true;
|
|
898
|
+
log("HaexVault SDK initialized in iframe mode");
|
|
899
|
+
if (ctx.config.manifest) {
|
|
900
|
+
ctx.state.extensionInfo = {
|
|
901
|
+
publicKey: ctx.config.manifest.publicKey,
|
|
902
|
+
name: ctx.config.manifest.name,
|
|
903
|
+
version: ctx.config.manifest.version,
|
|
904
|
+
displayName: ctx.config.manifest.name
|
|
905
|
+
};
|
|
906
|
+
log("Extension info loaded from manifest:", ctx.state.extensionInfo);
|
|
903
907
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
908
|
+
sendDebugInfo(ctx.config);
|
|
909
|
+
const context = await request(HAEXTENSION_METHODS.context.get);
|
|
910
|
+
ctx.state.context = context;
|
|
911
|
+
log("Application context received:", context);
|
|
912
|
+
return { context };
|
|
913
|
+
}
|
|
914
|
+
function sendDebugInfo(config) {
|
|
915
|
+
if (!config.debug) return;
|
|
916
|
+
if (typeof window === "undefined" || !window.parent) return;
|
|
917
|
+
const debugInfo = `SDK Debug:
|
|
918
|
+
window.parent exists: ${!!window.parent}
|
|
919
|
+
window.parent === window: ${window.parent === window}
|
|
920
|
+
window.self === window.top: ${window.self === window.top}`;
|
|
921
|
+
try {
|
|
922
|
+
window.parent.postMessage({
|
|
923
|
+
type: HAEXSPACE_MESSAGE_TYPES.DEBUG,
|
|
924
|
+
data: debugInfo
|
|
925
|
+
}, "*");
|
|
926
|
+
} catch (e) {
|
|
927
|
+
alert(debugInfo + `
|
|
928
|
+
postMessage error: ${e}`);
|
|
909
929
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
// src/commands.ts
|
|
933
|
+
var TAURI_COMMANDS = {
|
|
934
|
+
database: {
|
|
935
|
+
query: "webview_extension_db_query",
|
|
936
|
+
execute: "webview_extension_db_execute",
|
|
937
|
+
registerMigrations: "webview_extension_db_register_migrations"
|
|
938
|
+
},
|
|
939
|
+
permissions: {
|
|
940
|
+
checkWeb: "webview_extension_check_web_permission",
|
|
941
|
+
checkDatabase: "webview_extension_check_database_permission",
|
|
942
|
+
checkFilesystem: "webview_extension_check_filesystem_permission"
|
|
943
|
+
},
|
|
944
|
+
web: {
|
|
945
|
+
open: "webview_extension_web_open",
|
|
946
|
+
fetch: "webview_extension_web_request"
|
|
947
|
+
},
|
|
948
|
+
filesystem: {
|
|
949
|
+
saveFile: "webview_extension_fs_save_file",
|
|
950
|
+
openFile: "webview_extension_fs_open_file",
|
|
951
|
+
showImage: "webview_extension_fs_show_image"
|
|
952
|
+
},
|
|
953
|
+
external: {
|
|
954
|
+
// Response handling (called by extensions)
|
|
955
|
+
respond: "external_respond"},
|
|
956
|
+
filesync: {
|
|
957
|
+
// Spaces
|
|
958
|
+
listSpaces: "filesync_list_spaces",
|
|
959
|
+
createSpace: "filesync_create_space",
|
|
960
|
+
deleteSpace: "filesync_delete_space",
|
|
961
|
+
// Files
|
|
962
|
+
listFiles: "filesync_list_files",
|
|
963
|
+
getFile: "filesync_get_file",
|
|
964
|
+
uploadFile: "filesync_upload_file",
|
|
965
|
+
downloadFile: "filesync_download_file",
|
|
966
|
+
deleteFile: "filesync_delete_file",
|
|
967
|
+
// Backends
|
|
968
|
+
listBackends: "filesync_list_backends",
|
|
969
|
+
addBackend: "filesync_add_backend",
|
|
970
|
+
removeBackend: "filesync_remove_backend",
|
|
971
|
+
testBackend: "filesync_test_backend",
|
|
972
|
+
// Sync Rules
|
|
973
|
+
listSyncRules: "filesync_list_sync_rules",
|
|
974
|
+
addSyncRule: "filesync_add_sync_rule",
|
|
975
|
+
removeSyncRule: "filesync_remove_sync_rule",
|
|
976
|
+
// Sync Operations
|
|
977
|
+
getSyncStatus: "filesync_get_sync_status",
|
|
978
|
+
triggerSync: "filesync_trigger_sync",
|
|
979
|
+
pauseSync: "filesync_pause_sync",
|
|
980
|
+
resumeSync: "filesync_resume_sync",
|
|
981
|
+
// Conflict Resolution
|
|
982
|
+
resolveConflict: "filesync_resolve_conflict",
|
|
983
|
+
// UI Helpers
|
|
984
|
+
selectFolder: "filesync_select_folder"
|
|
928
985
|
}
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
// src/transport/handlers/database.ts
|
|
989
|
+
var databaseHandlers = {
|
|
990
|
+
[HAEXTENSION_METHODS.database.query]: {
|
|
991
|
+
command: TAURI_COMMANDS.database.query,
|
|
992
|
+
args: (p) => ({
|
|
993
|
+
query: p.query,
|
|
994
|
+
params: p.params || []
|
|
995
|
+
})
|
|
996
|
+
},
|
|
997
|
+
[HAEXTENSION_METHODS.database.execute]: {
|
|
998
|
+
command: TAURI_COMMANDS.database.execute,
|
|
999
|
+
args: (p) => ({
|
|
1000
|
+
query: p.query,
|
|
1001
|
+
params: p.params || []
|
|
1002
|
+
})
|
|
1003
|
+
},
|
|
1004
|
+
[HAEXTENSION_METHODS.database.registerMigrations]: {
|
|
1005
|
+
command: TAURI_COMMANDS.database.registerMigrations,
|
|
1006
|
+
args: (p) => ({
|
|
1007
|
+
extensionVersion: p.extensionVersion,
|
|
1008
|
+
migrations: p.migrations
|
|
1009
|
+
})
|
|
942
1010
|
}
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1011
|
+
};
|
|
1012
|
+
|
|
1013
|
+
// src/transport/handlers/permissions.ts
|
|
1014
|
+
var permissionsHandlers = {
|
|
1015
|
+
"permissions.web.check": {
|
|
1016
|
+
command: TAURI_COMMANDS.permissions.checkWeb,
|
|
1017
|
+
args: (p) => ({
|
|
1018
|
+
url: p.url
|
|
1019
|
+
})
|
|
1020
|
+
},
|
|
1021
|
+
"permissions.database.check": {
|
|
1022
|
+
command: TAURI_COMMANDS.permissions.checkDatabase,
|
|
1023
|
+
args: (p) => ({
|
|
1024
|
+
resource: p.resource,
|
|
1025
|
+
operation: p.operation
|
|
1026
|
+
})
|
|
1027
|
+
},
|
|
1028
|
+
"permissions.filesystem.check": {
|
|
1029
|
+
command: TAURI_COMMANDS.permissions.checkFilesystem,
|
|
1030
|
+
args: (p) => ({
|
|
1031
|
+
path: p.path,
|
|
1032
|
+
actionStr: p.action
|
|
1033
|
+
})
|
|
948
1034
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
)
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
* 1. Validate all SQL statements (ensure only extension's own tables are accessed)
|
|
968
|
-
* 2. Store migrations with applied_at = NULL
|
|
969
|
-
* 3. Query pending migrations sorted by name
|
|
970
|
-
* 4. Apply pending migrations and set up CRDT triggers
|
|
971
|
-
* 5. Mark successful migrations with applied_at timestamp
|
|
972
|
-
*
|
|
973
|
-
* @param extensionVersion - The version of the extension
|
|
974
|
-
* @param migrations - Array of migration objects with name and SQL content
|
|
975
|
-
* @returns Promise with migration result (applied count, already applied count, applied migration names)
|
|
976
|
-
*/
|
|
977
|
-
async registerMigrationsAsync(extensionVersion, migrations) {
|
|
978
|
-
return this.database.registerMigrationsAsync(extensionVersion, migrations);
|
|
979
|
-
}
|
|
980
|
-
async requestDatabasePermission(request) {
|
|
981
|
-
return this.request("permissions.database.request", {
|
|
982
|
-
resource: request.resource,
|
|
983
|
-
operation: request.operation,
|
|
984
|
-
reason: request.reason
|
|
985
|
-
});
|
|
986
|
-
}
|
|
987
|
-
async checkDatabasePermission(resource, operation) {
|
|
988
|
-
const response = await this.request(
|
|
989
|
-
"permissions.database.check",
|
|
990
|
-
{
|
|
991
|
-
resource,
|
|
992
|
-
operation
|
|
993
|
-
}
|
|
994
|
-
);
|
|
995
|
-
return response.status === "granted";
|
|
996
|
-
}
|
|
997
|
-
async respondToSearch(requestId, results) {
|
|
998
|
-
await this.request("search.respond", {
|
|
999
|
-
requestId,
|
|
1000
|
-
results
|
|
1001
|
-
});
|
|
1002
|
-
}
|
|
1003
|
-
/**
|
|
1004
|
-
* Register a handler for external requests (from browser extensions, CLI, servers, etc.)
|
|
1005
|
-
*
|
|
1006
|
-
* @param action - The action/method name to handle (e.g., "get-logins", "get-totp")
|
|
1007
|
-
* @param handler - Function that processes the request and returns a response
|
|
1008
|
-
* @returns Unsubscribe function to remove the handler
|
|
1009
|
-
*
|
|
1010
|
-
* @example
|
|
1011
|
-
* ```typescript
|
|
1012
|
-
* client.onExternalRequest("get-logins", async (request) => {
|
|
1013
|
-
* const entries = await getMatchingEntries(request.payload.url);
|
|
1014
|
-
* return {
|
|
1015
|
-
* requestId: request.requestId,
|
|
1016
|
-
* success: true,
|
|
1017
|
-
* data: { entries }
|
|
1018
|
-
* };
|
|
1019
|
-
* });
|
|
1020
|
-
* ```
|
|
1021
|
-
*/
|
|
1022
|
-
onExternalRequest(action, handler) {
|
|
1023
|
-
this.externalRequestHandlers.set(action, handler);
|
|
1024
|
-
this.log(`[ExternalRequest] Registered handler for action: ${action}`);
|
|
1025
|
-
return () => {
|
|
1026
|
-
this.externalRequestHandlers.delete(action);
|
|
1027
|
-
this.log(`[ExternalRequest] Unregistered handler for action: ${action}`);
|
|
1028
|
-
};
|
|
1029
|
-
}
|
|
1030
|
-
/**
|
|
1031
|
-
* Send a response to an external request back to haex-vault
|
|
1032
|
-
* This is called internally after a handler processes a request
|
|
1033
|
-
*/
|
|
1034
|
-
async respondToExternalRequest(response) {
|
|
1035
|
-
await this.request("external.respond", response);
|
|
1036
|
-
}
|
|
1037
|
-
async request(method, params) {
|
|
1038
|
-
const resolvedParams = params ?? {};
|
|
1039
|
-
if (this.isNativeWindow && typeof window.__TAURI__ !== "undefined") {
|
|
1040
|
-
return this.invoke(method, resolvedParams);
|
|
1041
|
-
}
|
|
1042
|
-
return this.postMessage(method, resolvedParams);
|
|
1043
|
-
}
|
|
1044
|
-
async postMessage(method, params) {
|
|
1045
|
-
const requestId = this.generateRequestId();
|
|
1046
|
-
const request = {
|
|
1047
|
-
method,
|
|
1048
|
-
params,
|
|
1049
|
-
timestamp: Date.now()
|
|
1050
|
-
};
|
|
1051
|
-
return new Promise((resolve, reject) => {
|
|
1052
|
-
const timeout = setTimeout(() => {
|
|
1053
|
-
this.pendingRequests.delete(requestId);
|
|
1054
|
-
reject(
|
|
1055
|
-
new HaexHubError("TIMEOUT" /* TIMEOUT */, "errors.timeout", {
|
|
1056
|
-
timeout: this.config.timeout
|
|
1057
|
-
})
|
|
1058
|
-
);
|
|
1059
|
-
}, this.config.timeout);
|
|
1060
|
-
this.pendingRequests.set(requestId, { resolve, reject, timeout });
|
|
1061
|
-
const targetOrigin = "*";
|
|
1062
|
-
if (this.config.debug) {
|
|
1063
|
-
console.log("[SDK Debug] ========== Sending Request ==========");
|
|
1064
|
-
console.log("[SDK Debug] Request ID:", requestId);
|
|
1065
|
-
console.log("[SDK Debug] Method:", request.method);
|
|
1066
|
-
console.log("[SDK Debug] Params:", request.params);
|
|
1067
|
-
console.log("[SDK Debug] Target origin:", targetOrigin);
|
|
1068
|
-
console.log("[SDK Debug] Extension info:", this._extensionInfo);
|
|
1069
|
-
console.log("[SDK Debug] ========================================");
|
|
1070
|
-
}
|
|
1071
|
-
window.parent.postMessage({ id: requestId, ...request }, targetOrigin);
|
|
1072
|
-
});
|
|
1073
|
-
}
|
|
1074
|
-
async invoke(method, params) {
|
|
1075
|
-
const { invoke } = window.__TAURI__.core;
|
|
1076
|
-
if (this.config.debug) {
|
|
1077
|
-
console.log("[SDK Debug] ========== Invoke Request ==========");
|
|
1078
|
-
console.log("[SDK Debug] Method:", method);
|
|
1079
|
-
console.log("[SDK Debug] Params:", params);
|
|
1080
|
-
console.log("[SDK Debug] =======================================");
|
|
1081
|
-
}
|
|
1082
|
-
switch (method) {
|
|
1083
|
-
case HAEXTENSION_METHODS.database.query:
|
|
1084
|
-
return invoke("webview_extension_db_query", {
|
|
1085
|
-
query: params.query,
|
|
1086
|
-
params: params.params || []
|
|
1087
|
-
});
|
|
1088
|
-
case HAEXTENSION_METHODS.database.execute:
|
|
1089
|
-
return invoke("webview_extension_db_execute", {
|
|
1090
|
-
query: params.query,
|
|
1091
|
-
params: params.params || []
|
|
1092
|
-
});
|
|
1093
|
-
case "permissions.web.check":
|
|
1094
|
-
return invoke("webview_extension_check_web_permission", {
|
|
1095
|
-
url: params.url
|
|
1096
|
-
});
|
|
1097
|
-
case "permissions.database.check":
|
|
1098
|
-
return invoke("webview_extension_check_database_permission", {
|
|
1099
|
-
resource: params.resource,
|
|
1100
|
-
operation: params.operation
|
|
1101
|
-
});
|
|
1102
|
-
case "permissions.filesystem.check":
|
|
1103
|
-
return invoke("webview_extension_check_filesystem_permission", {
|
|
1104
|
-
path: params.path,
|
|
1105
|
-
actionStr: params.action
|
|
1106
|
-
});
|
|
1107
|
-
case HAEXTENSION_METHODS.application.open:
|
|
1108
|
-
return invoke("webview_extension_web_open", {
|
|
1109
|
-
url: params.url
|
|
1110
|
-
});
|
|
1111
|
-
case HAEXTENSION_METHODS.web.fetch:
|
|
1112
|
-
return invoke("webview_extension_web_request", {
|
|
1113
|
-
url: params.url,
|
|
1114
|
-
method: params.method,
|
|
1115
|
-
headers: params.headers,
|
|
1116
|
-
body: params.body
|
|
1117
|
-
});
|
|
1118
|
-
case HAEXTENSION_METHODS.filesystem.saveFile:
|
|
1119
|
-
return invoke("webview_extension_fs_save_file", {
|
|
1120
|
-
data: params.data,
|
|
1121
|
-
defaultPath: params.defaultPath,
|
|
1122
|
-
title: params.title,
|
|
1123
|
-
filters: params.filters
|
|
1124
|
-
});
|
|
1125
|
-
case HAEXTENSION_METHODS.filesystem.openFile:
|
|
1126
|
-
return invoke("webview_extension_fs_open_file", {
|
|
1127
|
-
data: params.data,
|
|
1128
|
-
fileName: params.fileName
|
|
1129
|
-
});
|
|
1130
|
-
case HAEXTENSION_METHODS.database.registerMigrations:
|
|
1131
|
-
return invoke("webview_extension_db_register_migrations", {
|
|
1132
|
-
extensionVersion: params.extensionVersion,
|
|
1133
|
-
migrations: params.migrations
|
|
1134
|
-
});
|
|
1135
|
-
case "external.respond":
|
|
1136
|
-
return invoke("webview_extension_external_respond", {
|
|
1137
|
-
requestId: params.requestId,
|
|
1138
|
-
success: params.success,
|
|
1139
|
-
data: params.data,
|
|
1140
|
-
error: params.error
|
|
1141
|
-
});
|
|
1142
|
-
default:
|
|
1143
|
-
throw new HaexHubError(
|
|
1144
|
-
"METHOD_NOT_FOUND" /* METHOD_NOT_FOUND */,
|
|
1145
|
-
"errors.method_not_found",
|
|
1146
|
-
{ method }
|
|
1147
|
-
);
|
|
1148
|
-
}
|
|
1035
|
+
};
|
|
1036
|
+
|
|
1037
|
+
// src/transport/handlers/web.ts
|
|
1038
|
+
var webHandlers = {
|
|
1039
|
+
[HAEXTENSION_METHODS.application.open]: {
|
|
1040
|
+
command: TAURI_COMMANDS.web.open,
|
|
1041
|
+
args: (p) => ({
|
|
1042
|
+
url: p.url
|
|
1043
|
+
})
|
|
1044
|
+
},
|
|
1045
|
+
[HAEXTENSION_METHODS.web.fetch]: {
|
|
1046
|
+
command: TAURI_COMMANDS.web.fetch,
|
|
1047
|
+
args: (p) => ({
|
|
1048
|
+
url: p.url,
|
|
1049
|
+
method: p.method,
|
|
1050
|
+
headers: p.headers,
|
|
1051
|
+
body: p.body
|
|
1052
|
+
})
|
|
1149
1053
|
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
// src/transport/handlers/filesystem.ts
|
|
1057
|
+
var filesystemHandlers = {
|
|
1058
|
+
[HAEXTENSION_METHODS.filesystem.saveFile]: {
|
|
1059
|
+
command: TAURI_COMMANDS.filesystem.saveFile,
|
|
1060
|
+
args: (p) => ({
|
|
1061
|
+
data: p.data,
|
|
1062
|
+
defaultPath: p.defaultPath,
|
|
1063
|
+
title: p.title,
|
|
1064
|
+
filters: p.filters
|
|
1065
|
+
})
|
|
1066
|
+
},
|
|
1067
|
+
[HAEXTENSION_METHODS.filesystem.openFile]: {
|
|
1068
|
+
command: TAURI_COMMANDS.filesystem.openFile,
|
|
1069
|
+
args: (p) => ({
|
|
1070
|
+
data: p.data,
|
|
1071
|
+
fileName: p.fileName
|
|
1072
|
+
})
|
|
1073
|
+
},
|
|
1074
|
+
[HAEXTENSION_METHODS.filesystem.showImage]: {
|
|
1075
|
+
command: TAURI_COMMANDS.filesystem.showImage,
|
|
1076
|
+
args: (p) => ({
|
|
1077
|
+
dataUrl: p.dataUrl
|
|
1078
|
+
})
|
|
1155
1079
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1080
|
+
};
|
|
1081
|
+
|
|
1082
|
+
// src/transport/handlers/external.ts
|
|
1083
|
+
var externalHandlers = {
|
|
1084
|
+
"external.respond": {
|
|
1085
|
+
command: TAURI_COMMANDS.external.respond,
|
|
1086
|
+
args: (p) => ({
|
|
1087
|
+
requestId: p.requestId,
|
|
1088
|
+
success: p.success,
|
|
1089
|
+
data: p.data,
|
|
1090
|
+
error: p.error
|
|
1091
|
+
})
|
|
1161
1092
|
}
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1093
|
+
};
|
|
1094
|
+
|
|
1095
|
+
// src/transport/handlers/filesync.ts
|
|
1096
|
+
var filesyncHandlers = {
|
|
1097
|
+
// ==========================================================================
|
|
1098
|
+
// Spaces
|
|
1099
|
+
// ==========================================================================
|
|
1100
|
+
[HAEXTENSION_METHODS.filesystem.sync.listSpaces]: {
|
|
1101
|
+
command: TAURI_COMMANDS.filesync.listSpaces,
|
|
1102
|
+
args: () => ({})
|
|
1103
|
+
},
|
|
1104
|
+
[HAEXTENSION_METHODS.filesystem.sync.createSpace]: {
|
|
1105
|
+
command: TAURI_COMMANDS.filesync.createSpace,
|
|
1106
|
+
args: (p) => ({ request: p })
|
|
1107
|
+
},
|
|
1108
|
+
[HAEXTENSION_METHODS.filesystem.sync.deleteSpace]: {
|
|
1109
|
+
command: TAURI_COMMANDS.filesync.deleteSpace,
|
|
1110
|
+
args: (p) => ({ spaceId: p.spaceId })
|
|
1111
|
+
},
|
|
1112
|
+
// ==========================================================================
|
|
1113
|
+
// Files
|
|
1114
|
+
// ==========================================================================
|
|
1115
|
+
[HAEXTENSION_METHODS.filesystem.sync.listFiles]: {
|
|
1116
|
+
command: TAURI_COMMANDS.filesync.listFiles,
|
|
1117
|
+
args: (p) => ({ request: p })
|
|
1118
|
+
},
|
|
1119
|
+
[HAEXTENSION_METHODS.filesystem.sync.getFile]: {
|
|
1120
|
+
command: TAURI_COMMANDS.filesync.getFile,
|
|
1121
|
+
args: (p) => ({ fileId: p.fileId })
|
|
1122
|
+
},
|
|
1123
|
+
[HAEXTENSION_METHODS.filesystem.sync.uploadFile]: {
|
|
1124
|
+
command: TAURI_COMMANDS.filesync.uploadFile,
|
|
1125
|
+
args: (p) => ({ request: p })
|
|
1126
|
+
},
|
|
1127
|
+
[HAEXTENSION_METHODS.filesystem.sync.downloadFile]: {
|
|
1128
|
+
command: TAURI_COMMANDS.filesync.downloadFile,
|
|
1129
|
+
args: (p) => ({ request: p })
|
|
1130
|
+
},
|
|
1131
|
+
[HAEXTENSION_METHODS.filesystem.sync.deleteFile]: {
|
|
1132
|
+
command: TAURI_COMMANDS.filesync.deleteFile,
|
|
1133
|
+
args: (p) => ({ fileId: p.fileId })
|
|
1134
|
+
},
|
|
1135
|
+
// ==========================================================================
|
|
1136
|
+
// Backends
|
|
1137
|
+
// ==========================================================================
|
|
1138
|
+
[HAEXTENSION_METHODS.filesystem.sync.listBackends]: {
|
|
1139
|
+
command: TAURI_COMMANDS.filesync.listBackends,
|
|
1140
|
+
args: () => ({})
|
|
1141
|
+
},
|
|
1142
|
+
[HAEXTENSION_METHODS.filesystem.sync.addBackend]: {
|
|
1143
|
+
command: TAURI_COMMANDS.filesync.addBackend,
|
|
1144
|
+
args: (p) => ({ request: p })
|
|
1145
|
+
},
|
|
1146
|
+
[HAEXTENSION_METHODS.filesystem.sync.removeBackend]: {
|
|
1147
|
+
command: TAURI_COMMANDS.filesync.removeBackend,
|
|
1148
|
+
args: (p) => ({ backendId: p.backendId })
|
|
1149
|
+
},
|
|
1150
|
+
[HAEXTENSION_METHODS.filesystem.sync.testBackend]: {
|
|
1151
|
+
command: TAURI_COMMANDS.filesync.testBackend,
|
|
1152
|
+
args: (p) => ({ backendId: p.backendId })
|
|
1153
|
+
},
|
|
1154
|
+
// ==========================================================================
|
|
1155
|
+
// Sync Rules
|
|
1156
|
+
// ==========================================================================
|
|
1157
|
+
[HAEXTENSION_METHODS.filesystem.sync.listSyncRules]: {
|
|
1158
|
+
command: TAURI_COMMANDS.filesync.listSyncRules,
|
|
1159
|
+
args: () => ({})
|
|
1160
|
+
},
|
|
1161
|
+
[HAEXTENSION_METHODS.filesystem.sync.addSyncRule]: {
|
|
1162
|
+
command: TAURI_COMMANDS.filesync.addSyncRule,
|
|
1163
|
+
args: (p) => ({ request: p })
|
|
1164
|
+
},
|
|
1165
|
+
[HAEXTENSION_METHODS.filesystem.sync.removeSyncRule]: {
|
|
1166
|
+
command: TAURI_COMMANDS.filesync.removeSyncRule,
|
|
1167
|
+
args: (p) => ({ ruleId: p.ruleId })
|
|
1168
|
+
},
|
|
1169
|
+
// ==========================================================================
|
|
1170
|
+
// Sync Operations
|
|
1171
|
+
// ==========================================================================
|
|
1172
|
+
[HAEXTENSION_METHODS.filesystem.sync.getSyncStatus]: {
|
|
1173
|
+
command: TAURI_COMMANDS.filesync.getSyncStatus,
|
|
1174
|
+
args: () => ({})
|
|
1175
|
+
},
|
|
1176
|
+
[HAEXTENSION_METHODS.filesystem.sync.triggerSync]: {
|
|
1177
|
+
command: TAURI_COMMANDS.filesync.triggerSync,
|
|
1178
|
+
args: () => ({})
|
|
1179
|
+
},
|
|
1180
|
+
[HAEXTENSION_METHODS.filesystem.sync.pauseSync]: {
|
|
1181
|
+
command: TAURI_COMMANDS.filesync.pauseSync,
|
|
1182
|
+
args: () => ({})
|
|
1183
|
+
},
|
|
1184
|
+
[HAEXTENSION_METHODS.filesystem.sync.resumeSync]: {
|
|
1185
|
+
command: TAURI_COMMANDS.filesync.resumeSync,
|
|
1186
|
+
args: () => ({})
|
|
1187
|
+
},
|
|
1188
|
+
// ==========================================================================
|
|
1189
|
+
// Conflict Resolution
|
|
1190
|
+
// ==========================================================================
|
|
1191
|
+
[HAEXTENSION_METHODS.filesystem.sync.resolveConflict]: {
|
|
1192
|
+
command: TAURI_COMMANDS.filesync.resolveConflict,
|
|
1193
|
+
args: (p) => ({ request: p })
|
|
1194
|
+
},
|
|
1195
|
+
// ==========================================================================
|
|
1196
|
+
// UI Helpers
|
|
1197
|
+
// ==========================================================================
|
|
1198
|
+
[HAEXTENSION_METHODS.filesystem.sync.selectFolder]: {
|
|
1199
|
+
command: TAURI_COMMANDS.filesync.selectFolder,
|
|
1200
|
+
args: () => ({})
|
|
1171
1201
|
}
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
if (event.payload) {
|
|
1214
|
-
this.handleEvent({
|
|
1215
|
-
type: HAEXTENSION_EVENTS.EXTERNAL_REQUEST,
|
|
1216
|
-
data: event.payload,
|
|
1217
|
-
timestamp: Date.now()
|
|
1218
|
-
});
|
|
1219
|
-
}
|
|
1220
|
-
});
|
|
1221
|
-
console.log("[HaexSpace SDK] External request listener registered successfully");
|
|
1222
|
-
} catch (error) {
|
|
1223
|
-
console.error("[HaexSpace SDK] Failed to setup external request listener:", error);
|
|
1224
|
-
this.log("Failed to setup external request listener:", error);
|
|
1225
|
-
}
|
|
1226
|
-
this.resolveReady();
|
|
1227
|
-
return;
|
|
1228
|
-
}
|
|
1229
|
-
} catch (error) {
|
|
1230
|
-
this.log("Tauri commands failed, falling back to iframe mode", error);
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
if (window.self === window.top) {
|
|
1234
|
-
throw new HaexHubError("NOT_IN_IFRAME" /* NOT_IN_IFRAME */, "errors.not_in_iframe");
|
|
1235
|
-
}
|
|
1236
|
-
this.messageHandler = this.handleMessage.bind(this);
|
|
1237
|
-
window.addEventListener("message", this.messageHandler);
|
|
1238
|
-
this.isNativeWindow = false;
|
|
1239
|
-
this.initialized = true;
|
|
1240
|
-
this.log("HaexSpace SDK initialized in iframe mode");
|
|
1241
|
-
try {
|
|
1242
|
-
if (this.config.manifest) {
|
|
1243
|
-
this._extensionInfo = {
|
|
1244
|
-
publicKey: this.config.manifest.publicKey,
|
|
1245
|
-
name: this.config.manifest.name,
|
|
1246
|
-
version: this.config.manifest.version,
|
|
1247
|
-
displayName: this.config.manifest.name
|
|
1248
|
-
};
|
|
1249
|
-
this.log("Extension info loaded from manifest:", this._extensionInfo);
|
|
1250
|
-
this.notifySubscribers();
|
|
1251
|
-
}
|
|
1252
|
-
if (typeof window !== "undefined" && window.parent) {
|
|
1253
|
-
const debugInfo = `SDK Debug:
|
|
1254
|
-
window.parent exists: ${!!window.parent}
|
|
1255
|
-
window.parent === window: ${window.parent === window}
|
|
1256
|
-
window.self === window.top: ${window.self === window.top}`;
|
|
1257
|
-
try {
|
|
1258
|
-
window.parent.postMessage({
|
|
1259
|
-
type: HAEXSPACE_MESSAGE_TYPES.DEBUG,
|
|
1260
|
-
data: debugInfo
|
|
1261
|
-
}, "*");
|
|
1262
|
-
} catch (e) {
|
|
1263
|
-
alert(debugInfo + `
|
|
1264
|
-
postMessage error: ${e}`);
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
this._context = await this.request(HAEXTENSION_METHODS.context.get);
|
|
1268
|
-
this.log("Application context received:", this._context);
|
|
1269
|
-
this.notifySubscribers();
|
|
1270
|
-
this.resolveReady();
|
|
1271
|
-
} catch (error) {
|
|
1272
|
-
this.log("Failed to load extension info or context:", error);
|
|
1273
|
-
throw error;
|
|
1202
|
+
};
|
|
1203
|
+
|
|
1204
|
+
// src/transport/handlers/index.ts
|
|
1205
|
+
var allHandlers = {
|
|
1206
|
+
...databaseHandlers,
|
|
1207
|
+
...permissionsHandlers,
|
|
1208
|
+
...webHandlers,
|
|
1209
|
+
...filesystemHandlers,
|
|
1210
|
+
...externalHandlers,
|
|
1211
|
+
...filesyncHandlers
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1214
|
+
// src/client/transport.ts
|
|
1215
|
+
function generateRequestId(counter) {
|
|
1216
|
+
return `req_${counter}`;
|
|
1217
|
+
}
|
|
1218
|
+
function sendPostMessage(method, params, requestId, config, extensionInfo, pendingRequests) {
|
|
1219
|
+
const request = {
|
|
1220
|
+
method,
|
|
1221
|
+
params,
|
|
1222
|
+
timestamp: Date.now()
|
|
1223
|
+
};
|
|
1224
|
+
return new Promise((resolve, reject) => {
|
|
1225
|
+
const timeout = setTimeout(() => {
|
|
1226
|
+
pendingRequests.delete(requestId);
|
|
1227
|
+
reject(
|
|
1228
|
+
new HaexVaultSdkError("TIMEOUT" /* TIMEOUT */, "errors.timeout", {
|
|
1229
|
+
timeout: config.timeout
|
|
1230
|
+
})
|
|
1231
|
+
);
|
|
1232
|
+
}, config.timeout);
|
|
1233
|
+
pendingRequests.set(requestId, { resolve, reject, timeout });
|
|
1234
|
+
const targetOrigin = "*";
|
|
1235
|
+
if (config.debug) {
|
|
1236
|
+
console.log("[SDK Debug] ========== Sending Request ==========");
|
|
1237
|
+
console.log("[SDK Debug] Request ID:", requestId);
|
|
1238
|
+
console.log("[SDK Debug] Method:", request.method);
|
|
1239
|
+
console.log("[SDK Debug] Params:", request.params);
|
|
1240
|
+
console.log("[SDK Debug] Target origin:", targetOrigin);
|
|
1241
|
+
console.log("[SDK Debug] Extension info:", extensionInfo);
|
|
1242
|
+
console.log("[SDK Debug] ========================================");
|
|
1274
1243
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1244
|
+
window.parent.postMessage({ id: requestId, ...request }, targetOrigin);
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
async function sendInvoke(method, params, config, log) {
|
|
1248
|
+
const { invoke } = window.__TAURI__.core;
|
|
1249
|
+
if (config.debug) {
|
|
1250
|
+
console.log("[SDK Debug] ========== Invoke Request ==========");
|
|
1251
|
+
console.log("[SDK Debug] Method:", method);
|
|
1252
|
+
console.log("[SDK Debug] Params:", params);
|
|
1253
|
+
console.log("[SDK Debug] =======================================");
|
|
1254
|
+
}
|
|
1255
|
+
const handler = allHandlers[method];
|
|
1256
|
+
if (handler) {
|
|
1257
|
+
const args = handler.args(params);
|
|
1258
|
+
return invoke(handler.command, args);
|
|
1259
|
+
}
|
|
1260
|
+
throw new HaexVaultSdkError(
|
|
1261
|
+
"METHOD_NOT_FOUND" /* METHOD_NOT_FOUND */,
|
|
1262
|
+
"errors.method_not_found",
|
|
1263
|
+
{ method }
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
// src/client/events.ts
|
|
1268
|
+
function createMessageHandler(config, pendingRequests, extensionInfo, onEvent) {
|
|
1269
|
+
return (event) => {
|
|
1270
|
+
if (config.debug) {
|
|
1278
1271
|
console.log("[SDK Debug] ========== Message Received ==========");
|
|
1279
1272
|
console.log("[SDK Debug] Event origin:", event.origin);
|
|
1280
1273
|
console.log(
|
|
@@ -1282,160 +1275,534 @@ postMessage error: ${e}`);
|
|
|
1282
1275
|
event.source === window.parent ? "parent window" : "unknown"
|
|
1283
1276
|
);
|
|
1284
1277
|
console.log("[SDK Debug] Event data:", event.data);
|
|
1285
|
-
console.log("[SDK Debug] Extension info loaded:", !!
|
|
1278
|
+
console.log("[SDK Debug] Extension info loaded:", !!extensionInfo());
|
|
1286
1279
|
console.log(
|
|
1287
1280
|
"[SDK Debug] Pending requests count:",
|
|
1288
|
-
|
|
1281
|
+
pendingRequests.size
|
|
1289
1282
|
);
|
|
1290
1283
|
}
|
|
1291
1284
|
if (event.source !== window.parent) {
|
|
1292
|
-
if (
|
|
1285
|
+
if (config.debug) {
|
|
1293
1286
|
console.error("[SDK Debug] \u274C REJECTED: Message not from parent window!");
|
|
1294
1287
|
}
|
|
1295
1288
|
return;
|
|
1296
1289
|
}
|
|
1297
1290
|
const data = event.data;
|
|
1298
|
-
if ("id" in data &&
|
|
1299
|
-
if (
|
|
1291
|
+
if ("id" in data && pendingRequests.has(data.id)) {
|
|
1292
|
+
if (config.debug) {
|
|
1300
1293
|
console.log("[SDK Debug] \u2705 Found pending request for ID:", data.id);
|
|
1301
1294
|
}
|
|
1302
|
-
const pending =
|
|
1295
|
+
const pending = pendingRequests.get(data.id);
|
|
1303
1296
|
clearTimeout(pending.timeout);
|
|
1304
|
-
|
|
1297
|
+
pendingRequests.delete(data.id);
|
|
1305
1298
|
if (data.error) {
|
|
1306
|
-
if (
|
|
1299
|
+
if (config.debug) {
|
|
1307
1300
|
console.error("[SDK Debug] \u274C Request failed:", data.error);
|
|
1308
1301
|
}
|
|
1309
1302
|
pending.reject(data.error);
|
|
1310
1303
|
} else {
|
|
1311
|
-
if (
|
|
1304
|
+
if (config.debug) {
|
|
1312
1305
|
console.log("[SDK Debug] \u2705 Request succeeded:", data.result);
|
|
1313
1306
|
}
|
|
1314
1307
|
pending.resolve(data.result);
|
|
1315
1308
|
}
|
|
1316
1309
|
return;
|
|
1317
1310
|
}
|
|
1318
|
-
if ("id" in data && !
|
|
1319
|
-
if (
|
|
1311
|
+
if ("id" in data && !pendingRequests.has(data.id)) {
|
|
1312
|
+
if (config.debug) {
|
|
1320
1313
|
console.warn(
|
|
1321
1314
|
"[SDK Debug] \u26A0\uFE0F Received response for unknown request ID:",
|
|
1322
1315
|
data.id
|
|
1323
1316
|
);
|
|
1324
1317
|
console.warn(
|
|
1325
1318
|
"[SDK Debug] Known IDs:",
|
|
1326
|
-
Array.from(
|
|
1319
|
+
Array.from(pendingRequests.keys())
|
|
1327
1320
|
);
|
|
1328
1321
|
}
|
|
1329
1322
|
}
|
|
1330
1323
|
if ("type" in data && data.type) {
|
|
1331
|
-
if (
|
|
1324
|
+
if (config.debug) {
|
|
1332
1325
|
console.log("[SDK Debug] Event received:", data.type);
|
|
1333
1326
|
}
|
|
1334
|
-
|
|
1327
|
+
onEvent(data);
|
|
1335
1328
|
}
|
|
1336
|
-
if (
|
|
1329
|
+
if (config.debug) {
|
|
1337
1330
|
console.log("[SDK Debug] ========== End Message ==========");
|
|
1338
1331
|
}
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
function processEvent(event, log, eventListeners, onContextChanged, onExternalRequest) {
|
|
1335
|
+
if (event.type === HAEXTENSION_EVENTS.CONTEXT_CHANGED) {
|
|
1336
|
+
const contextEvent = event;
|
|
1337
|
+
onContextChanged(contextEvent.data.context);
|
|
1338
|
+
log("Context updated:", contextEvent.data.context);
|
|
1339
|
+
}
|
|
1340
|
+
if (event.type === HAEXTENSION_EVENTS.EXTERNAL_REQUEST) {
|
|
1341
|
+
const externalEvent = event;
|
|
1342
|
+
onExternalRequest(externalEvent);
|
|
1343
|
+
return;
|
|
1339
1344
|
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1345
|
+
emitEvent(event, log, eventListeners);
|
|
1346
|
+
}
|
|
1347
|
+
function emitEvent(event, log, eventListeners) {
|
|
1348
|
+
log("Event received:", event);
|
|
1349
|
+
const listeners = eventListeners.get(event.type);
|
|
1350
|
+
if (listeners) {
|
|
1351
|
+
listeners.forEach((callback) => callback(event));
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
function addEventListener(eventType, callback, eventListeners) {
|
|
1355
|
+
if (!eventListeners.has(eventType)) {
|
|
1356
|
+
eventListeners.set(eventType, /* @__PURE__ */ new Set());
|
|
1357
|
+
}
|
|
1358
|
+
eventListeners.get(eventType).add(callback);
|
|
1359
|
+
}
|
|
1360
|
+
function removeEventListener(eventType, callback, eventListeners) {
|
|
1361
|
+
const listeners = eventListeners.get(eventType);
|
|
1362
|
+
if (listeners) {
|
|
1363
|
+
listeners.delete(callback);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
function notifySubscribers(subscribers) {
|
|
1367
|
+
subscribers.forEach((callback) => callback());
|
|
1368
|
+
}
|
|
1369
|
+
function createDrizzleInstance(schema, extensionInfo, request, log) {
|
|
1370
|
+
if (!extensionInfo) {
|
|
1371
|
+
throw new HaexVaultSdkError(
|
|
1372
|
+
"EXTENSION_INFO_UNAVAILABLE" /* EXTENSION_INFO_UNAVAILABLE */,
|
|
1373
|
+
"errors.client_not_ready"
|
|
1374
|
+
);
|
|
1375
|
+
}
|
|
1376
|
+
return sqliteProxy.drizzle(
|
|
1377
|
+
async (sql, params, method) => {
|
|
1378
|
+
try {
|
|
1379
|
+
if (method === "run" || method === "all") {
|
|
1380
|
+
const result2 = await request(
|
|
1381
|
+
HAEXTENSION_METHODS.database.execute,
|
|
1382
|
+
{
|
|
1383
|
+
query: sql,
|
|
1384
|
+
params
|
|
1385
|
+
}
|
|
1386
|
+
);
|
|
1387
|
+
if (method === "all") {
|
|
1388
|
+
return { rows: result2.rows || [] };
|
|
1389
|
+
}
|
|
1390
|
+
if (result2.rows && Array.isArray(result2.rows) && result2.rows.length > 0) {
|
|
1391
|
+
return { rows: result2.rows };
|
|
1392
|
+
}
|
|
1393
|
+
return result2;
|
|
1394
|
+
}
|
|
1395
|
+
const result = await request(HAEXTENSION_METHODS.database.query, {
|
|
1396
|
+
query: sql,
|
|
1397
|
+
params
|
|
1398
|
+
});
|
|
1399
|
+
const rows = result.rows;
|
|
1400
|
+
if (method === "get") {
|
|
1401
|
+
return { rows: rows.length > 0 ? rows.at(0) : void 0 };
|
|
1402
|
+
}
|
|
1403
|
+
return { rows };
|
|
1404
|
+
} catch (error) {
|
|
1405
|
+
log("Database operation failed:", error);
|
|
1406
|
+
throw error;
|
|
1407
|
+
}
|
|
1408
|
+
},
|
|
1409
|
+
{
|
|
1410
|
+
schema,
|
|
1411
|
+
logger: false
|
|
1346
1412
|
}
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1413
|
+
);
|
|
1414
|
+
}
|
|
1415
|
+
async function queryRaw(sql, params, request, debug) {
|
|
1416
|
+
const result = await request(
|
|
1417
|
+
HAEXTENSION_METHODS.database.query,
|
|
1418
|
+
{ query: sql, params }
|
|
1419
|
+
);
|
|
1420
|
+
if (debug) {
|
|
1421
|
+
console.log("[SDK query()] Raw result:", JSON.stringify(result, null, 2));
|
|
1422
|
+
}
|
|
1423
|
+
return result.rows;
|
|
1424
|
+
}
|
|
1425
|
+
async function executeRaw(sql, params, request) {
|
|
1426
|
+
const result = await request(
|
|
1427
|
+
HAEXTENSION_METHODS.database.execute,
|
|
1428
|
+
{ query: sql, params }
|
|
1429
|
+
);
|
|
1430
|
+
return {
|
|
1431
|
+
rowsAffected: result.rowsAffected,
|
|
1432
|
+
lastInsertId: result.lastInsertId
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
// src/client/external.ts
|
|
1437
|
+
function registerExternalHandler(action, handler, handlers, log) {
|
|
1438
|
+
handlers.set(action, handler);
|
|
1439
|
+
log(`[ExternalRequest] Registered handler for action: ${action}`);
|
|
1440
|
+
return () => {
|
|
1441
|
+
handlers.delete(action);
|
|
1442
|
+
log(`[ExternalRequest] Unregistered handler for action: ${action}`);
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
async function handleExternalRequest(request, handlers, respond, log) {
|
|
1446
|
+
log(`[ExternalRequest] Received request: ${request.action} from ${request.publicKey.substring(0, 20)}...`);
|
|
1447
|
+
const handler = handlers.get(request.action);
|
|
1448
|
+
if (!handler) {
|
|
1449
|
+
log(`[ExternalRequest] No handler for action: ${request.action}`);
|
|
1450
|
+
await respond({
|
|
1451
|
+
requestId: request.requestId,
|
|
1452
|
+
success: false,
|
|
1453
|
+
error: `No handler registered for action: ${request.action}`
|
|
1454
|
+
});
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
try {
|
|
1458
|
+
const response = await handler(request);
|
|
1459
|
+
await respond(response);
|
|
1460
|
+
log(`[ExternalRequest] Response sent for: ${request.action}`);
|
|
1461
|
+
} catch (error) {
|
|
1462
|
+
log(`[ExternalRequest] Handler error:`, error);
|
|
1463
|
+
await respond({
|
|
1464
|
+
requestId: request.requestId,
|
|
1465
|
+
success: false,
|
|
1466
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
async function respondToExternalRequest(response, request) {
|
|
1471
|
+
await request("external.respond", response);
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
// src/client.ts
|
|
1475
|
+
var HaexVaultClient = class {
|
|
1476
|
+
constructor(config = {}) {
|
|
1477
|
+
// State
|
|
1478
|
+
this.initialized = false;
|
|
1479
|
+
this.isNativeWindow = false;
|
|
1480
|
+
this.requestCounter = 0;
|
|
1481
|
+
this._extensionInfo = null;
|
|
1482
|
+
this._context = null;
|
|
1483
|
+
this._setupCompleted = false;
|
|
1484
|
+
// Collections
|
|
1485
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
1486
|
+
this.eventListeners = /* @__PURE__ */ new Map();
|
|
1487
|
+
this.externalRequestHandlers = /* @__PURE__ */ new Map();
|
|
1488
|
+
this.reactiveSubscribers = /* @__PURE__ */ new Set();
|
|
1489
|
+
// Handlers
|
|
1490
|
+
this.messageHandler = null;
|
|
1491
|
+
this.setupPromise = null;
|
|
1492
|
+
this.setupHook = null;
|
|
1493
|
+
// Public APIs
|
|
1494
|
+
this.orm = null;
|
|
1495
|
+
this.config = {
|
|
1496
|
+
debug: config.debug ?? false,
|
|
1497
|
+
timeout: config.timeout ?? DEFAULT_TIMEOUT,
|
|
1498
|
+
manifest: config.manifest
|
|
1499
|
+
};
|
|
1500
|
+
this.storage = new StorageAPI(this);
|
|
1501
|
+
this.database = new DatabaseAPI(this);
|
|
1502
|
+
this.filesystem = new FilesystemAPI(this);
|
|
1503
|
+
this.web = new WebAPI(this);
|
|
1504
|
+
this.permissions = new PermissionsAPI(this);
|
|
1505
|
+
installConsoleForwarding(this.config.debug);
|
|
1506
|
+
this.readyPromise = new Promise((resolve) => {
|
|
1507
|
+
this.resolveReady = resolve;
|
|
1508
|
+
});
|
|
1509
|
+
this.init();
|
|
1510
|
+
}
|
|
1511
|
+
// ==========================================================================
|
|
1512
|
+
// Lifecycle
|
|
1513
|
+
// ==========================================================================
|
|
1514
|
+
async ready() {
|
|
1515
|
+
return this.readyPromise;
|
|
1516
|
+
}
|
|
1517
|
+
get setupCompleted() {
|
|
1518
|
+
return this._setupCompleted;
|
|
1519
|
+
}
|
|
1520
|
+
onSetup(setupFn) {
|
|
1521
|
+
if (this.setupHook) {
|
|
1522
|
+
throw new Error("Setup hook already registered");
|
|
1351
1523
|
}
|
|
1352
|
-
this.
|
|
1353
|
-
}
|
|
1354
|
-
async
|
|
1355
|
-
this.
|
|
1356
|
-
|
|
1357
|
-
if (!handler) {
|
|
1358
|
-
this.log(`[ExternalRequest] No handler for action: ${request.action}`);
|
|
1359
|
-
await this.respondToExternalRequest({
|
|
1360
|
-
requestId: request.requestId,
|
|
1361
|
-
success: false,
|
|
1362
|
-
error: `No handler registered for action: ${request.action}`
|
|
1363
|
-
});
|
|
1524
|
+
this.setupHook = setupFn;
|
|
1525
|
+
}
|
|
1526
|
+
async setupComplete() {
|
|
1527
|
+
await this.readyPromise;
|
|
1528
|
+
if (!this.setupHook || this.setupCompleted) {
|
|
1364
1529
|
return;
|
|
1365
1530
|
}
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
await this.respondToExternalRequest(response);
|
|
1369
|
-
this.log(`[ExternalRequest] Response sent for: ${request.action}`);
|
|
1370
|
-
} catch (error) {
|
|
1371
|
-
this.log(`[ExternalRequest] Handler error:`, error);
|
|
1372
|
-
await this.respondToExternalRequest({
|
|
1373
|
-
requestId: request.requestId,
|
|
1374
|
-
success: false,
|
|
1375
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1376
|
-
});
|
|
1531
|
+
if (!this.setupPromise) {
|
|
1532
|
+
this.setupPromise = this.runSetupAsync();
|
|
1377
1533
|
}
|
|
1534
|
+
return this.setupPromise;
|
|
1378
1535
|
}
|
|
1379
|
-
|
|
1380
|
-
this.
|
|
1381
|
-
|
|
1382
|
-
if (listeners) {
|
|
1383
|
-
listeners.forEach((callback) => callback(event));
|
|
1536
|
+
destroy() {
|
|
1537
|
+
if (this.messageHandler) {
|
|
1538
|
+
window.removeEventListener("message", this.messageHandler);
|
|
1384
1539
|
}
|
|
1540
|
+
this.pendingRequests.forEach(({ timeout }) => clearTimeout(timeout));
|
|
1541
|
+
this.pendingRequests.clear();
|
|
1542
|
+
this.eventListeners.clear();
|
|
1543
|
+
this.initialized = false;
|
|
1544
|
+
this.log("HaexVault SDK destroyed");
|
|
1385
1545
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1546
|
+
// ==========================================================================
|
|
1547
|
+
// Properties
|
|
1548
|
+
// ==========================================================================
|
|
1549
|
+
get extensionInfo() {
|
|
1550
|
+
return this._extensionInfo;
|
|
1388
1551
|
}
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
throw new HaexHubError(
|
|
1392
|
-
"INVALID_PUBLIC_KEY" /* INVALID_PUBLIC_KEY */,
|
|
1393
|
-
"errors.invalid_public_key",
|
|
1394
|
-
{ publicKey }
|
|
1395
|
-
);
|
|
1396
|
-
}
|
|
1552
|
+
get context() {
|
|
1553
|
+
return this._context;
|
|
1397
1554
|
}
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
);
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1555
|
+
// ==========================================================================
|
|
1556
|
+
// Subscriptions
|
|
1557
|
+
// ==========================================================================
|
|
1558
|
+
subscribe(callback) {
|
|
1559
|
+
this.reactiveSubscribers.add(callback);
|
|
1560
|
+
return () => {
|
|
1561
|
+
this.reactiveSubscribers.delete(callback);
|
|
1562
|
+
};
|
|
1563
|
+
}
|
|
1564
|
+
// ==========================================================================
|
|
1565
|
+
// Table Name Utilities
|
|
1566
|
+
// ==========================================================================
|
|
1567
|
+
getTableName(tableName) {
|
|
1568
|
+
return getExtensionTableName(this._extensionInfo, tableName);
|
|
1569
|
+
}
|
|
1570
|
+
getDependencyTableName(publicKey, extensionName, tableName) {
|
|
1571
|
+
return getDependencyTableName(publicKey, extensionName, tableName);
|
|
1572
|
+
}
|
|
1573
|
+
parseTableName(fullTableName) {
|
|
1574
|
+
return parseTableName(fullTableName);
|
|
1575
|
+
}
|
|
1576
|
+
// ==========================================================================
|
|
1577
|
+
// Database
|
|
1578
|
+
// ==========================================================================
|
|
1579
|
+
initializeDatabase(schema) {
|
|
1580
|
+
const db = createDrizzleInstance(schema, this._extensionInfo, this.request.bind(this), this.log.bind(this));
|
|
1581
|
+
this.orm = db;
|
|
1582
|
+
return db;
|
|
1583
|
+
}
|
|
1584
|
+
async query(sql, params = []) {
|
|
1585
|
+
return queryRaw(sql, params, this.request.bind(this), this.config.debug);
|
|
1586
|
+
}
|
|
1587
|
+
async select(sql, params = []) {
|
|
1588
|
+
return this.query(sql, params);
|
|
1589
|
+
}
|
|
1590
|
+
async execute(sql, params = []) {
|
|
1591
|
+
return executeRaw(sql, params, this.request.bind(this));
|
|
1592
|
+
}
|
|
1593
|
+
async registerMigrationsAsync(extensionVersion, migrations) {
|
|
1594
|
+
return this.database.registerMigrationsAsync(extensionVersion, migrations);
|
|
1595
|
+
}
|
|
1596
|
+
// ==========================================================================
|
|
1597
|
+
// Dependencies
|
|
1598
|
+
// ==========================================================================
|
|
1599
|
+
async getDependencies() {
|
|
1600
|
+
return this.request("extensions.getDependencies");
|
|
1601
|
+
}
|
|
1602
|
+
// ==========================================================================
|
|
1603
|
+
// Permissions
|
|
1604
|
+
// ==========================================================================
|
|
1605
|
+
async requestDatabasePermission(request) {
|
|
1606
|
+
return this.request("permissions.database.request", {
|
|
1607
|
+
resource: request.resource,
|
|
1608
|
+
operation: request.operation,
|
|
1609
|
+
reason: request.reason
|
|
1610
|
+
});
|
|
1611
|
+
}
|
|
1612
|
+
async checkDatabasePermission(resource, operation) {
|
|
1613
|
+
const response = await this.request("permissions.database.check", { resource, operation });
|
|
1614
|
+
return response.status === "granted";
|
|
1615
|
+
}
|
|
1616
|
+
// ==========================================================================
|
|
1617
|
+
// Search
|
|
1618
|
+
// ==========================================================================
|
|
1619
|
+
async respondToSearch(requestId, results) {
|
|
1620
|
+
await this.request("search.respond", { requestId, results });
|
|
1621
|
+
}
|
|
1622
|
+
// ==========================================================================
|
|
1623
|
+
// External Requests
|
|
1624
|
+
// ==========================================================================
|
|
1625
|
+
onExternalRequest(action, handler) {
|
|
1626
|
+
return registerExternalHandler(action, handler, this.externalRequestHandlers, this.log.bind(this));
|
|
1627
|
+
}
|
|
1628
|
+
async respondToExternalRequest(response) {
|
|
1629
|
+
await respondToExternalRequest(response, this.request.bind(this));
|
|
1630
|
+
}
|
|
1631
|
+
// ==========================================================================
|
|
1632
|
+
// Events
|
|
1633
|
+
// ==========================================================================
|
|
1634
|
+
on(eventType, callback) {
|
|
1635
|
+
addEventListener(eventType, callback, this.eventListeners);
|
|
1636
|
+
}
|
|
1637
|
+
off(eventType, callback) {
|
|
1638
|
+
removeEventListener(eventType, callback, this.eventListeners);
|
|
1639
|
+
}
|
|
1640
|
+
// ==========================================================================
|
|
1641
|
+
// Communication
|
|
1642
|
+
// ==========================================================================
|
|
1643
|
+
async request(method, params) {
|
|
1644
|
+
const resolvedParams = params ?? {};
|
|
1645
|
+
if (this.isNativeWindow && hasTauri()) {
|
|
1646
|
+
return sendInvoke(method, resolvedParams, this.config, this.log.bind(this));
|
|
1412
1647
|
}
|
|
1648
|
+
const requestId = generateRequestId(++this.requestCounter);
|
|
1649
|
+
return sendPostMessage(method, resolvedParams, requestId, this.config, this._extensionInfo, this.pendingRequests);
|
|
1413
1650
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1651
|
+
// ==========================================================================
|
|
1652
|
+
// Private: Initialization
|
|
1653
|
+
// ==========================================================================
|
|
1654
|
+
async init() {
|
|
1655
|
+
if (this.initialized) return;
|
|
1656
|
+
if (!isInIframe() && hasTauri()) {
|
|
1657
|
+
try {
|
|
1658
|
+
await this.initNative();
|
|
1659
|
+
return;
|
|
1660
|
+
} catch (error) {
|
|
1661
|
+
this.log("Tauri commands failed, falling back to iframe mode", error);
|
|
1662
|
+
}
|
|
1420
1663
|
}
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1664
|
+
await this.initIframe();
|
|
1665
|
+
}
|
|
1666
|
+
async initNative() {
|
|
1667
|
+
const { extensionInfo, context } = await initNativeMode(
|
|
1668
|
+
{
|
|
1669
|
+
config: this.config,
|
|
1670
|
+
state: {
|
|
1671
|
+
initialized: this.initialized,
|
|
1672
|
+
isNativeWindow: this.isNativeWindow,
|
|
1673
|
+
requestCounter: this.requestCounter,
|
|
1674
|
+
setupCompleted: this._setupCompleted,
|
|
1675
|
+
extensionInfo: this._extensionInfo,
|
|
1676
|
+
context: this._context,
|
|
1677
|
+
orm: this.orm
|
|
1678
|
+
},
|
|
1679
|
+
collections: {
|
|
1680
|
+
pendingRequests: this.pendingRequests,
|
|
1681
|
+
eventListeners: this.eventListeners,
|
|
1682
|
+
externalRequestHandlers: this.externalRequestHandlers,
|
|
1683
|
+
reactiveSubscribers: this.reactiveSubscribers
|
|
1684
|
+
},
|
|
1685
|
+
promises: {
|
|
1686
|
+
readyPromise: this.readyPromise,
|
|
1687
|
+
resolveReady: this.resolveReady,
|
|
1688
|
+
setupPromise: this.setupPromise,
|
|
1689
|
+
setupHook: this.setupHook
|
|
1690
|
+
},
|
|
1691
|
+
handlers: {
|
|
1692
|
+
messageHandler: this.messageHandler
|
|
1693
|
+
}
|
|
1694
|
+
},
|
|
1695
|
+
this.log.bind(this),
|
|
1696
|
+
this.handleEvent.bind(this),
|
|
1697
|
+
(ctx) => {
|
|
1698
|
+
this._context = ctx;
|
|
1699
|
+
this.notifySubscribersInternal();
|
|
1700
|
+
}
|
|
1701
|
+
);
|
|
1702
|
+
this._extensionInfo = extensionInfo;
|
|
1703
|
+
this._context = context;
|
|
1704
|
+
this.isNativeWindow = true;
|
|
1705
|
+
this.initialized = true;
|
|
1706
|
+
this.notifySubscribersInternal();
|
|
1707
|
+
this.resolveReady();
|
|
1708
|
+
}
|
|
1709
|
+
async initIframe() {
|
|
1710
|
+
this.messageHandler = createMessageHandler(
|
|
1711
|
+
this.config,
|
|
1712
|
+
this.pendingRequests,
|
|
1713
|
+
() => this._extensionInfo,
|
|
1714
|
+
this.handleEvent.bind(this)
|
|
1715
|
+
);
|
|
1716
|
+
const { context } = await initIframeMode(
|
|
1717
|
+
{
|
|
1718
|
+
config: this.config,
|
|
1719
|
+
state: {
|
|
1720
|
+
initialized: this.initialized,
|
|
1721
|
+
isNativeWindow: this.isNativeWindow,
|
|
1722
|
+
requestCounter: this.requestCounter,
|
|
1723
|
+
setupCompleted: this._setupCompleted,
|
|
1724
|
+
extensionInfo: this._extensionInfo,
|
|
1725
|
+
context: this._context,
|
|
1726
|
+
orm: this.orm
|
|
1727
|
+
},
|
|
1728
|
+
collections: {
|
|
1729
|
+
pendingRequests: this.pendingRequests,
|
|
1730
|
+
eventListeners: this.eventListeners,
|
|
1731
|
+
externalRequestHandlers: this.externalRequestHandlers,
|
|
1732
|
+
reactiveSubscribers: this.reactiveSubscribers
|
|
1733
|
+
},
|
|
1734
|
+
promises: {
|
|
1735
|
+
readyPromise: this.readyPromise,
|
|
1736
|
+
resolveReady: this.resolveReady,
|
|
1737
|
+
setupPromise: this.setupPromise,
|
|
1738
|
+
setupHook: this.setupHook
|
|
1739
|
+
},
|
|
1740
|
+
handlers: {
|
|
1741
|
+
messageHandler: this.messageHandler
|
|
1742
|
+
}
|
|
1743
|
+
},
|
|
1744
|
+
this.log.bind(this),
|
|
1745
|
+
this.messageHandler,
|
|
1746
|
+
this.request.bind(this)
|
|
1747
|
+
);
|
|
1748
|
+
if (this.config.manifest) {
|
|
1749
|
+
this._extensionInfo = {
|
|
1750
|
+
publicKey: this.config.manifest.publicKey,
|
|
1751
|
+
name: this.config.manifest.name,
|
|
1752
|
+
version: this.config.manifest.version,
|
|
1753
|
+
displayName: this.config.manifest.name
|
|
1754
|
+
};
|
|
1755
|
+
this.notifySubscribersInternal();
|
|
1427
1756
|
}
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1757
|
+
this._context = context;
|
|
1758
|
+
this.isNativeWindow = false;
|
|
1759
|
+
this.initialized = true;
|
|
1760
|
+
this.notifySubscribersInternal();
|
|
1761
|
+
this.resolveReady();
|
|
1762
|
+
}
|
|
1763
|
+
// ==========================================================================
|
|
1764
|
+
// Private: Event Handling
|
|
1765
|
+
// ==========================================================================
|
|
1766
|
+
handleEvent(event) {
|
|
1767
|
+
processEvent(
|
|
1768
|
+
event,
|
|
1769
|
+
this.log.bind(this),
|
|
1770
|
+
this.eventListeners,
|
|
1771
|
+
(ctx) => {
|
|
1772
|
+
this._context = ctx;
|
|
1773
|
+
this.notifySubscribersInternal();
|
|
1774
|
+
},
|
|
1775
|
+
(extEvent) => this.handleExternalRequestInternal(extEvent.data)
|
|
1776
|
+
);
|
|
1777
|
+
}
|
|
1778
|
+
async handleExternalRequestInternal(request) {
|
|
1779
|
+
await handleExternalRequest(request, this.externalRequestHandlers, this.respondToExternalRequest.bind(this), this.log.bind(this));
|
|
1780
|
+
}
|
|
1781
|
+
// ==========================================================================
|
|
1782
|
+
// Private: Setup
|
|
1783
|
+
// ==========================================================================
|
|
1784
|
+
async runSetupAsync() {
|
|
1785
|
+
if (!this.setupHook) return;
|
|
1786
|
+
try {
|
|
1787
|
+
this.log("[HaexVault] Running setup hook...");
|
|
1788
|
+
await this.setupHook();
|
|
1789
|
+
this._setupCompleted = true;
|
|
1790
|
+
this.log("[HaexVault] Setup completed successfully");
|
|
1791
|
+
this.notifySubscribersInternal();
|
|
1792
|
+
} catch (error) {
|
|
1793
|
+
this.log("[HaexVault] Setup failed:", error);
|
|
1794
|
+
throw error;
|
|
1434
1795
|
}
|
|
1435
1796
|
}
|
|
1797
|
+
// ==========================================================================
|
|
1798
|
+
// Private: Utilities
|
|
1799
|
+
// ==========================================================================
|
|
1800
|
+
notifySubscribersInternal() {
|
|
1801
|
+
notifySubscribers(this.reactiveSubscribers);
|
|
1802
|
+
}
|
|
1436
1803
|
log(...args) {
|
|
1437
1804
|
if (this.config.debug) {
|
|
1438
|
-
console.log("[
|
|
1805
|
+
console.log("[HaexVault SDK]", ...args);
|
|
1439
1806
|
}
|
|
1440
1807
|
}
|
|
1441
1808
|
};
|