@haex-space/vault-sdk 1.0.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/README.md +1551 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +455 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/index.mjs +430 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/client-O_JEOzfx.d.mts +491 -0
- package/dist/client-O_JEOzfx.d.ts +491 -0
- package/dist/index.d.mts +124 -0
- package/dist/index.d.ts +124 -0
- package/dist/index.js +1429 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1409 -0
- package/dist/index.mjs.map +1 -0
- package/dist/node.d.mts +25 -0
- package/dist/node.d.ts +25 -0
- package/dist/node.js +28 -0
- package/dist/node.js.map +1 -0
- package/dist/node.mjs +25 -0
- package/dist/node.mjs.map +1 -0
- package/dist/nuxt.d.mts +19 -0
- package/dist/nuxt.d.ts +19 -0
- package/dist/nuxt.js +473 -0
- package/dist/nuxt.js.map +1 -0
- package/dist/nuxt.mjs +470 -0
- package/dist/nuxt.mjs.map +1 -0
- package/dist/react.d.mts +28 -0
- package/dist/react.d.ts +28 -0
- package/dist/react.js +1389 -0
- package/dist/react.js.map +1 -0
- package/dist/react.mjs +1386 -0
- package/dist/react.mjs.map +1 -0
- package/dist/runtime/nuxt.plugin.client.d.mts +43 -0
- package/dist/runtime/nuxt.plugin.client.d.ts +43 -0
- package/dist/runtime/nuxt.plugin.client.js +1137 -0
- package/dist/runtime/nuxt.plugin.client.js.map +1 -0
- package/dist/runtime/nuxt.plugin.client.mjs +1135 -0
- package/dist/runtime/nuxt.plugin.client.mjs.map +1 -0
- package/dist/runtime/nuxt.types.d.ts +15 -0
- package/dist/svelte.d.mts +48 -0
- package/dist/svelte.d.ts +48 -0
- package/dist/svelte.js +1398 -0
- package/dist/svelte.js.map +1 -0
- package/dist/svelte.mjs +1391 -0
- package/dist/svelte.mjs.map +1 -0
- package/dist/vite.d.mts +37 -0
- package/dist/vite.d.ts +37 -0
- package/dist/vite.js +346 -0
- package/dist/vite.js.map +1 -0
- package/dist/vite.mjs +341 -0
- package/dist/vite.mjs.map +1 -0
- package/dist/vue.d.mts +49 -0
- package/dist/vue.d.ts +49 -0
- package/dist/vue.js +1388 -0
- package/dist/vue.js.map +1 -0
- package/dist/vue.mjs +1385 -0
- package/dist/vue.mjs.map +1 -0
- package/package.json +121 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1409 @@
|
|
|
1
|
+
import { drizzle } from 'drizzle-orm/sqlite-proxy';
|
|
2
|
+
|
|
3
|
+
// src/polyfills/localStorage.ts
|
|
4
|
+
function installLocalStoragePolyfill() {
|
|
5
|
+
if (typeof window === "undefined") {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
console.log("[HaexHub] Storage Polyfill loading immediately");
|
|
9
|
+
let localStorageWorks = false;
|
|
10
|
+
try {
|
|
11
|
+
const testKey = "__ls_test__";
|
|
12
|
+
localStorage.setItem(testKey, testKey);
|
|
13
|
+
localStorage.removeItem(testKey);
|
|
14
|
+
localStorageWorks = true;
|
|
15
|
+
} catch (e) {
|
|
16
|
+
console.warn("[HaexHub] localStorage blocked \u2013 using in-memory fallback");
|
|
17
|
+
}
|
|
18
|
+
if (!localStorageWorks) {
|
|
19
|
+
const lsStorage = /* @__PURE__ */ new Map();
|
|
20
|
+
const localStoragePoly = {
|
|
21
|
+
getItem(key) {
|
|
22
|
+
return lsStorage.get(key) || null;
|
|
23
|
+
},
|
|
24
|
+
setItem(key, value) {
|
|
25
|
+
lsStorage.set(key, String(value));
|
|
26
|
+
},
|
|
27
|
+
removeItem(key) {
|
|
28
|
+
lsStorage.delete(key);
|
|
29
|
+
},
|
|
30
|
+
clear() {
|
|
31
|
+
lsStorage.clear();
|
|
32
|
+
},
|
|
33
|
+
get length() {
|
|
34
|
+
return lsStorage.size;
|
|
35
|
+
},
|
|
36
|
+
key(index) {
|
|
37
|
+
return Array.from(lsStorage.keys())[index] || null;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
try {
|
|
41
|
+
Object.defineProperty(window, "localStorage", {
|
|
42
|
+
value: localStoragePoly,
|
|
43
|
+
writable: true,
|
|
44
|
+
configurable: true
|
|
45
|
+
});
|
|
46
|
+
} catch (e) {
|
|
47
|
+
window.localStorage = localStoragePoly;
|
|
48
|
+
}
|
|
49
|
+
console.log("[HaexHub] localStorage replaced with in-memory polyfill");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function installSessionStoragePolyfill() {
|
|
53
|
+
if (typeof window === "undefined") {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const sessionStoragePoly = {
|
|
58
|
+
getItem() {
|
|
59
|
+
return null;
|
|
60
|
+
},
|
|
61
|
+
setItem() {
|
|
62
|
+
},
|
|
63
|
+
removeItem() {
|
|
64
|
+
},
|
|
65
|
+
clear() {
|
|
66
|
+
},
|
|
67
|
+
get length() {
|
|
68
|
+
return 0;
|
|
69
|
+
},
|
|
70
|
+
key() {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
Object.defineProperty(window, "sessionStorage", {
|
|
75
|
+
value: sessionStoragePoly,
|
|
76
|
+
writable: true,
|
|
77
|
+
configurable: true
|
|
78
|
+
});
|
|
79
|
+
} catch (e) {
|
|
80
|
+
window.sessionStorage = {
|
|
81
|
+
getItem: () => null,
|
|
82
|
+
setItem: () => {
|
|
83
|
+
},
|
|
84
|
+
removeItem: () => {
|
|
85
|
+
},
|
|
86
|
+
clear: () => {
|
|
87
|
+
},
|
|
88
|
+
get length() {
|
|
89
|
+
return 0;
|
|
90
|
+
},
|
|
91
|
+
key: () => null
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
console.log("[HaexHub] sessionStorage polyfill installed");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/polyfills/cookies.ts
|
|
98
|
+
function installCookiePolyfill() {
|
|
99
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
let cookiesWork = false;
|
|
103
|
+
try {
|
|
104
|
+
document.cookie = "__cookie_test__=1";
|
|
105
|
+
cookiesWork = document.cookie.indexOf("__cookie_test__") !== -1;
|
|
106
|
+
} catch (e) {
|
|
107
|
+
console.warn("[HaexHub] Cookies blocked \u2013 using in-memory fallback");
|
|
108
|
+
}
|
|
109
|
+
if (!cookiesWork) {
|
|
110
|
+
const cookieStore = /* @__PURE__ */ new Map();
|
|
111
|
+
Object.defineProperty(document, "cookie", {
|
|
112
|
+
get() {
|
|
113
|
+
const cookies = [];
|
|
114
|
+
cookieStore.forEach((value, key) => {
|
|
115
|
+
cookies.push(`${key}=${value}`);
|
|
116
|
+
});
|
|
117
|
+
return cookies.join("; ");
|
|
118
|
+
},
|
|
119
|
+
set(cookieString) {
|
|
120
|
+
const parts = cookieString.split(";").map((p) => p.trim());
|
|
121
|
+
const [keyValue] = parts;
|
|
122
|
+
if (!keyValue) return;
|
|
123
|
+
const [key, value] = keyValue.split("=");
|
|
124
|
+
if (!key) return;
|
|
125
|
+
const options = {};
|
|
126
|
+
for (let i = 1; i < parts.length; i++) {
|
|
127
|
+
const part = parts[i];
|
|
128
|
+
if (!part) continue;
|
|
129
|
+
const parts_split = part.split("=");
|
|
130
|
+
const optKey = parts_split[0];
|
|
131
|
+
const optValue = parts_split[1];
|
|
132
|
+
if (optKey) {
|
|
133
|
+
options[optKey.toLowerCase()] = optValue || true;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const expiresValue = options.expires;
|
|
137
|
+
if (expiresValue && typeof expiresValue === "string") {
|
|
138
|
+
const expiresDate = new Date(expiresValue);
|
|
139
|
+
if (expiresDate < /* @__PURE__ */ new Date()) {
|
|
140
|
+
cookieStore.delete(key);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const maxAgeValue = options["max-age"];
|
|
145
|
+
if (typeof maxAgeValue === "string" && maxAgeValue === "0") {
|
|
146
|
+
cookieStore.delete(key);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
cookieStore.set(key, value || "");
|
|
150
|
+
},
|
|
151
|
+
configurable: true
|
|
152
|
+
});
|
|
153
|
+
console.log("[HaexHub] Cookie polyfill installed");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/polyfills/history.ts
|
|
158
|
+
function installHistoryPolyfill() {
|
|
159
|
+
if (typeof window === "undefined" || typeof history === "undefined") {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const install = () => {
|
|
163
|
+
console.log("[HaexHub] History Patch loading");
|
|
164
|
+
const originalPushState = history.pushState;
|
|
165
|
+
const originalReplaceState = history.replaceState;
|
|
166
|
+
let skipNextPush = false;
|
|
167
|
+
let skipNextReplace = false;
|
|
168
|
+
history.pushState = function(state, title, url) {
|
|
169
|
+
console.log("[HaexHub] pushState called:", url, "skip:", skipNextPush);
|
|
170
|
+
if (skipNextPush) {
|
|
171
|
+
skipNextPush = false;
|
|
172
|
+
console.log("[HaexHub] pushState skipped");
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
return originalPushState.call(this, state, title, url);
|
|
177
|
+
} catch (e) {
|
|
178
|
+
if (e.name === "SecurityError" && url) {
|
|
179
|
+
const urlString = url.toString();
|
|
180
|
+
let hashUrl = urlString.replace(/^\/#/, "");
|
|
181
|
+
hashUrl = hashUrl.startsWith("#") ? hashUrl : "#" + hashUrl;
|
|
182
|
+
console.log("[HaexHub] SecurityError - setting hash to:", hashUrl);
|
|
183
|
+
skipNextPush = true;
|
|
184
|
+
window.location.hash = hashUrl.replace(/^#/, "");
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
throw e;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
history.replaceState = function(state, title, url) {
|
|
191
|
+
console.log("[HaexHub] replaceState called:", url, "skip:", skipNextReplace);
|
|
192
|
+
if (skipNextReplace) {
|
|
193
|
+
skipNextReplace = false;
|
|
194
|
+
console.log("[HaexHub] replaceState skipped");
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
return originalReplaceState.call(this, state, title, url);
|
|
199
|
+
} catch (e) {
|
|
200
|
+
if (e.name === "SecurityError" && url) {
|
|
201
|
+
const urlString = url.toString();
|
|
202
|
+
let hashUrl = urlString.replace(/^\/#/, "");
|
|
203
|
+
hashUrl = hashUrl.startsWith("#") ? hashUrl : "#" + hashUrl;
|
|
204
|
+
console.log("[HaexHub] SecurityError - setting hash to:", hashUrl);
|
|
205
|
+
skipNextReplace = true;
|
|
206
|
+
window.location.hash = hashUrl.replace(/^#/, "");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
throw e;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
console.log("[HaexHub] History API patched");
|
|
213
|
+
};
|
|
214
|
+
if (document.readyState === "loading") {
|
|
215
|
+
document.addEventListener("DOMContentLoaded", install, { once: true });
|
|
216
|
+
} else {
|
|
217
|
+
install();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/polyfills/debug.ts
|
|
222
|
+
function installDebugDiagnostics() {
|
|
223
|
+
if (typeof window === "undefined") {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const hasParent = window.parent && window.parent !== window;
|
|
227
|
+
console.log("[HaexHub] hasParent:", hasParent);
|
|
228
|
+
if (hasParent) {
|
|
229
|
+
console.log("[HaexHub] Attempting to send debug message to parent...");
|
|
230
|
+
window.parent.postMessage({
|
|
231
|
+
type: "haexhub:debug",
|
|
232
|
+
data: `[Polyfills] window.parent test: exists=${!!window.parent}, different=${hasParent}, selfIsTop=${window.self === window.top}`
|
|
233
|
+
}, "*");
|
|
234
|
+
console.log("[HaexHub] Debug message sent!");
|
|
235
|
+
} else {
|
|
236
|
+
console.log("[HaexHub] No parent window or parent === window");
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/polyfills/baseTag.ts
|
|
241
|
+
function installBaseTag() {
|
|
242
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (window.__HAEXHUB_BASE_TAG_INSTALLING__) {
|
|
246
|
+
console.log("[HaexHub] Base tag installation already in progress, skipping");
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
console.log("[HaexHub] Base tag installation starting");
|
|
250
|
+
if (window.self === window.top) {
|
|
251
|
+
console.log("[HaexHub] Not in iframe, skipping base tag");
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const existingBaseTag = document.querySelector("base#haexhub-base");
|
|
255
|
+
if (existingBaseTag && existingBaseTag.href && existingBaseTag.href !== window.location.origin + "/") {
|
|
256
|
+
console.log("[HaexHub] Base tag already configured, skipping");
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
window.__HAEXHUB_BASE_TAG_INSTALLING__ = true;
|
|
260
|
+
const pathname = window.location.pathname;
|
|
261
|
+
const lastSlashIndex = pathname.lastIndexOf("/");
|
|
262
|
+
const basePath = lastSlashIndex !== -1 ? pathname.substring(0, lastSlashIndex + 1) : "/";
|
|
263
|
+
console.log("[HaexHub] Extracted base path from location:", basePath);
|
|
264
|
+
if (existingBaseTag) {
|
|
265
|
+
existingBaseTag.href = basePath;
|
|
266
|
+
console.log(`[HaexHub] Base tag updated: ${existingBaseTag.href}`);
|
|
267
|
+
} else {
|
|
268
|
+
const baseTag = document.createElement("base");
|
|
269
|
+
baseTag.id = "haexhub-base";
|
|
270
|
+
baseTag.href = basePath;
|
|
271
|
+
const head = document.head || document.querySelector("head");
|
|
272
|
+
if (head) {
|
|
273
|
+
head.insertBefore(baseTag, head.firstChild);
|
|
274
|
+
console.log(`[HaexHub] Base tag created: ${baseTag.href}`);
|
|
275
|
+
} else {
|
|
276
|
+
console.warn("[HaexHub] No <head> found, cannot inject base tag");
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// src/polyfills/consoleForwarding.ts
|
|
282
|
+
var originalConsole = {
|
|
283
|
+
log: console.log,
|
|
284
|
+
info: console.info,
|
|
285
|
+
warn: console.warn,
|
|
286
|
+
error: console.error,
|
|
287
|
+
debug: console.debug
|
|
288
|
+
};
|
|
289
|
+
function serializeArgs(args) {
|
|
290
|
+
return args.map((arg) => {
|
|
291
|
+
if (arg === null) return "null";
|
|
292
|
+
if (arg === void 0) return "undefined";
|
|
293
|
+
if (typeof arg === "object") {
|
|
294
|
+
try {
|
|
295
|
+
return JSON.stringify(arg, null, 2);
|
|
296
|
+
} catch {
|
|
297
|
+
return String(arg);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return String(arg);
|
|
301
|
+
}).join(" ");
|
|
302
|
+
}
|
|
303
|
+
function interceptConsole(level) {
|
|
304
|
+
console[level] = function(...args) {
|
|
305
|
+
originalConsole[level].apply(console, args);
|
|
306
|
+
if (window.self !== window.top && window.parent) {
|
|
307
|
+
try {
|
|
308
|
+
const message = serializeArgs(args);
|
|
309
|
+
const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
310
|
+
window.parent.postMessage(
|
|
311
|
+
{
|
|
312
|
+
type: "console.forward",
|
|
313
|
+
data: {
|
|
314
|
+
timestamp,
|
|
315
|
+
level,
|
|
316
|
+
message
|
|
317
|
+
},
|
|
318
|
+
timestamp: Date.now()
|
|
319
|
+
},
|
|
320
|
+
"*"
|
|
321
|
+
);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
originalConsole.error("[HaexHub] Failed to forward console message:", error);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function installConsoleForwarding(debug = false) {
|
|
329
|
+
if (typeof window === "undefined") {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (window.self === window.top) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
if (!debug) {
|
|
336
|
+
console.log("[HaexHub] Console forwarding disabled (not in debug mode)");
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
interceptConsole("log");
|
|
340
|
+
interceptConsole("info");
|
|
341
|
+
interceptConsole("warn");
|
|
342
|
+
interceptConsole("error");
|
|
343
|
+
interceptConsole("debug");
|
|
344
|
+
console.log("[HaexHub] Console forwarding installed");
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// src/polyfills/index.ts
|
|
348
|
+
function installPolyfills() {
|
|
349
|
+
if (typeof window === "undefined") {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
installLocalStoragePolyfill();
|
|
353
|
+
installSessionStoragePolyfill();
|
|
354
|
+
installCookiePolyfill();
|
|
355
|
+
installHistoryPolyfill();
|
|
356
|
+
console.log("[HaexHub] All polyfills loaded successfully");
|
|
357
|
+
installDebugDiagnostics();
|
|
358
|
+
}
|
|
359
|
+
if (typeof window !== "undefined") {
|
|
360
|
+
installPolyfills();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// src/events.ts
|
|
364
|
+
var HAEXTENSION_EVENTS = {
|
|
365
|
+
/** Context (theme, locale, platform) has changed */
|
|
366
|
+
CONTEXT_CHANGED: "haextension:context:changed",
|
|
367
|
+
/** Search request from HaexHub */
|
|
368
|
+
SEARCH_REQUEST: "haextension:search:request"
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
// src/methods.ts
|
|
372
|
+
var HAEXTENSION_METHODS = {
|
|
373
|
+
context: {
|
|
374
|
+
get: "haextension:context:get"
|
|
375
|
+
},
|
|
376
|
+
database: {
|
|
377
|
+
query: "haextension:database:query",
|
|
378
|
+
execute: "haextension:database:execute",
|
|
379
|
+
transaction: "haextension:database:transaction",
|
|
380
|
+
registerMigrations: "haextension:database:register-migrations"
|
|
381
|
+
},
|
|
382
|
+
filesystem: {
|
|
383
|
+
saveFile: "haextension:filesystem:save-file",
|
|
384
|
+
openFile: "haextension:filesystem:open-file",
|
|
385
|
+
showImage: "haextension:filesystem:show-image"
|
|
386
|
+
},
|
|
387
|
+
storage: {
|
|
388
|
+
getItem: "haextension:storage:get-item",
|
|
389
|
+
setItem: "haextension:storage:set-item",
|
|
390
|
+
removeItem: "haextension:storage:remove-item",
|
|
391
|
+
clear: "haextension:storage:clear",
|
|
392
|
+
keys: "haextension:storage:keys"
|
|
393
|
+
},
|
|
394
|
+
web: {
|
|
395
|
+
fetch: "haextension:web:fetch"
|
|
396
|
+
},
|
|
397
|
+
application: {
|
|
398
|
+
open: "haextension:application:open"
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
// src/types.ts
|
|
403
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
404
|
+
var TABLE_SEPARATOR = "__";
|
|
405
|
+
var PermissionStatus = /* @__PURE__ */ ((PermissionStatus2) => {
|
|
406
|
+
PermissionStatus2["GRANTED"] = "granted";
|
|
407
|
+
PermissionStatus2["DENIED"] = "denied";
|
|
408
|
+
PermissionStatus2["ASK"] = "ask";
|
|
409
|
+
return PermissionStatus2;
|
|
410
|
+
})(PermissionStatus || {});
|
|
411
|
+
var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
|
|
412
|
+
ErrorCode2["TIMEOUT"] = "TIMEOUT";
|
|
413
|
+
ErrorCode2["NOT_IN_IFRAME"] = "NOT_IN_IFRAME";
|
|
414
|
+
ErrorCode2["UNAUTHORIZED_ORIGIN"] = "UNAUTHORIZED_ORIGIN";
|
|
415
|
+
ErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED";
|
|
416
|
+
ErrorCode2["INVALID_PUBLIC_KEY"] = "INVALID_PUBLIC_KEY";
|
|
417
|
+
ErrorCode2["INVALID_EXTENSION_NAME"] = "INVALID_EXTENSION_NAME";
|
|
418
|
+
ErrorCode2["INVALID_TABLE_NAME"] = "INVALID_TABLE_NAME";
|
|
419
|
+
ErrorCode2["INVALID_PARAMS"] = "INVALID_PARAMS";
|
|
420
|
+
ErrorCode2["EXTENSION_NOT_INITIALIZED"] = "EXTENSION_NOT_INITIALIZED";
|
|
421
|
+
ErrorCode2["EXTENSION_INFO_UNAVAILABLE"] = "EXTENSION_INFO_UNAVAILABLE";
|
|
422
|
+
ErrorCode2["METHOD_NOT_FOUND"] = "METHOD_NOT_FOUND";
|
|
423
|
+
ErrorCode2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
|
|
424
|
+
ErrorCode2["DATABASE_ERROR"] = "DATABASE_ERROR";
|
|
425
|
+
ErrorCode2["WEB_ERROR"] = "WEB_ERROR";
|
|
426
|
+
return ErrorCode2;
|
|
427
|
+
})(ErrorCode || {});
|
|
428
|
+
var HaexHubError = class extends Error {
|
|
429
|
+
constructor(code, messageKey, details) {
|
|
430
|
+
super(messageKey);
|
|
431
|
+
this.code = code;
|
|
432
|
+
this.messageKey = messageKey;
|
|
433
|
+
this.details = details;
|
|
434
|
+
this.name = "HaexHubError";
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Get localized error message
|
|
438
|
+
* @param locale - Locale code (e.g., 'en', 'de')
|
|
439
|
+
* @param translations - Translation object
|
|
440
|
+
*/
|
|
441
|
+
getLocalizedMessage(locale = "en", translations) {
|
|
442
|
+
if (!translations || !translations[locale]) {
|
|
443
|
+
return this.messageKey;
|
|
444
|
+
}
|
|
445
|
+
let message = translations[locale][this.messageKey] || this.messageKey;
|
|
446
|
+
if (this.details) {
|
|
447
|
+
Object.entries(this.details).forEach(([key, value]) => {
|
|
448
|
+
message = message.replace(`{${key}}`, String(value));
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
return message;
|
|
452
|
+
}
|
|
453
|
+
toJSON() {
|
|
454
|
+
return {
|
|
455
|
+
code: this.code,
|
|
456
|
+
message: this.messageKey,
|
|
457
|
+
details: this.details
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
// src/api/storage.ts
|
|
463
|
+
var StorageAPI = class {
|
|
464
|
+
constructor(client) {
|
|
465
|
+
this.client = client;
|
|
466
|
+
}
|
|
467
|
+
async getItem(key) {
|
|
468
|
+
return this.client.request(HAEXTENSION_METHODS.storage.getItem, { key });
|
|
469
|
+
}
|
|
470
|
+
async setItem(key, value) {
|
|
471
|
+
await this.client.request(HAEXTENSION_METHODS.storage.setItem, { key, value });
|
|
472
|
+
}
|
|
473
|
+
async removeItem(key) {
|
|
474
|
+
await this.client.request(HAEXTENSION_METHODS.storage.removeItem, { key });
|
|
475
|
+
}
|
|
476
|
+
async clear() {
|
|
477
|
+
await this.client.request(HAEXTENSION_METHODS.storage.clear);
|
|
478
|
+
}
|
|
479
|
+
async keys() {
|
|
480
|
+
return this.client.request(HAEXTENSION_METHODS.storage.keys);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
// src/api/database.ts
|
|
485
|
+
var DatabaseAPI = class {
|
|
486
|
+
constructor(client) {
|
|
487
|
+
this.client = client;
|
|
488
|
+
}
|
|
489
|
+
async query(query, params) {
|
|
490
|
+
const result = await this.client.request(
|
|
491
|
+
HAEXTENSION_METHODS.database.query,
|
|
492
|
+
{
|
|
493
|
+
query,
|
|
494
|
+
params: params || []
|
|
495
|
+
}
|
|
496
|
+
);
|
|
497
|
+
return result.rows;
|
|
498
|
+
}
|
|
499
|
+
async queryOne(query, params) {
|
|
500
|
+
const rows = await this.query(query, params);
|
|
501
|
+
return rows.length > 0 ? rows[0] ?? null : null;
|
|
502
|
+
}
|
|
503
|
+
async execute(query, params) {
|
|
504
|
+
return this.client.request(HAEXTENSION_METHODS.database.execute, {
|
|
505
|
+
query,
|
|
506
|
+
params: params || []
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
async transaction(statements) {
|
|
510
|
+
await this.client.request(HAEXTENSION_METHODS.database.transaction, {
|
|
511
|
+
statements
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
async createTable(tableName, columns) {
|
|
515
|
+
const query = `CREATE TABLE IF NOT EXISTS ${tableName} (${columns})`;
|
|
516
|
+
await this.execute(query);
|
|
517
|
+
}
|
|
518
|
+
async dropTable(tableName) {
|
|
519
|
+
const query = `DROP TABLE IF EXISTS ${tableName}`;
|
|
520
|
+
await this.execute(query);
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Registers extension migrations with HaexVault for CRDT synchronization
|
|
524
|
+
* HaexVault will validate and execute these migrations, ensuring only
|
|
525
|
+
* tables with the correct prefix are manipulated
|
|
526
|
+
* @param extensionVersion - The version of the extension
|
|
527
|
+
* @param migrations - Array of migration objects with name and SQL content
|
|
528
|
+
* @returns Promise that resolves when migrations are registered
|
|
529
|
+
*/
|
|
530
|
+
async registerMigrationsAsync(extensionVersion, migrations) {
|
|
531
|
+
await this.client.request(HAEXTENSION_METHODS.database.registerMigrations, {
|
|
532
|
+
extensionVersion,
|
|
533
|
+
migrations
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
async insert(tableName, data) {
|
|
537
|
+
const keys = Object.keys(data);
|
|
538
|
+
const values = Object.values(data);
|
|
539
|
+
const placeholders = keys.map(() => "?").join(", ");
|
|
540
|
+
const query = `INSERT INTO ${tableName} (${keys.join(
|
|
541
|
+
", "
|
|
542
|
+
)}) VALUES (${placeholders})`;
|
|
543
|
+
const result = await this.execute(query, values);
|
|
544
|
+
return result.lastInsertId ?? -1;
|
|
545
|
+
}
|
|
546
|
+
async update(tableName, data, where, whereParams) {
|
|
547
|
+
const keys = Object.keys(data);
|
|
548
|
+
const values = Object.values(data);
|
|
549
|
+
const setClause = keys.map((key) => `${key} = ?`).join(", ");
|
|
550
|
+
const query = `UPDATE ${tableName} SET ${setClause} WHERE ${where}`;
|
|
551
|
+
const result = await this.execute(query, [
|
|
552
|
+
...values,
|
|
553
|
+
...whereParams || []
|
|
554
|
+
]);
|
|
555
|
+
return result.rowsAffected;
|
|
556
|
+
}
|
|
557
|
+
async delete(tableName, where, whereParams) {
|
|
558
|
+
const query = `DELETE FROM ${tableName} WHERE ${where}`;
|
|
559
|
+
const result = await this.execute(query, whereParams);
|
|
560
|
+
return result.rowsAffected;
|
|
561
|
+
}
|
|
562
|
+
async count(tableName, where, whereParams) {
|
|
563
|
+
const query = where ? `SELECT COUNT(*) as count FROM ${tableName} WHERE ${where}` : `SELECT COUNT(*) as count FROM ${tableName}`;
|
|
564
|
+
const result = await this.queryOne(query, whereParams);
|
|
565
|
+
return result?.count ?? 0;
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
// src/api/filesystem.ts
|
|
570
|
+
var FilesystemAPI = class {
|
|
571
|
+
constructor(client) {
|
|
572
|
+
this.client = client;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Opens a save file dialog and saves the provided data to the selected location
|
|
576
|
+
* @param data The file data as Uint8Array
|
|
577
|
+
* @param options Options for the save dialog
|
|
578
|
+
* @returns The path where the file was saved, or null if cancelled
|
|
579
|
+
*/
|
|
580
|
+
async saveFileAsync(data, options = {}) {
|
|
581
|
+
const result = await this.client.request(
|
|
582
|
+
HAEXTENSION_METHODS.filesystem.saveFile,
|
|
583
|
+
{
|
|
584
|
+
data: Array.from(data),
|
|
585
|
+
// Convert Uint8Array to regular array for postMessage
|
|
586
|
+
defaultPath: options.defaultPath,
|
|
587
|
+
title: options.title,
|
|
588
|
+
filters: options.filters
|
|
589
|
+
}
|
|
590
|
+
);
|
|
591
|
+
return result;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Opens a file with the system's default viewer
|
|
595
|
+
* @param data The file data as Uint8Array
|
|
596
|
+
* @param options Options for opening the file
|
|
597
|
+
* @returns The result of the operation
|
|
598
|
+
*/
|
|
599
|
+
async openFileAsync(data, options) {
|
|
600
|
+
const result = await this.client.request(
|
|
601
|
+
HAEXTENSION_METHODS.filesystem.openFile,
|
|
602
|
+
{
|
|
603
|
+
data: Array.from(data),
|
|
604
|
+
// Convert Uint8Array to regular array for postMessage
|
|
605
|
+
fileName: options.fileName,
|
|
606
|
+
mimeType: options.mimeType
|
|
607
|
+
}
|
|
608
|
+
);
|
|
609
|
+
return result;
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Shows an image using a data URL (safe, read-only viewing)
|
|
613
|
+
* This is safe to use without special permissions as it only displays images
|
|
614
|
+
* and doesn't execute any code or open files with external applications
|
|
615
|
+
* @param options Options containing the data URL
|
|
616
|
+
* @returns The result of the operation
|
|
617
|
+
*/
|
|
618
|
+
async showImageAsync(options) {
|
|
619
|
+
const result = await this.client.request(
|
|
620
|
+
HAEXTENSION_METHODS.filesystem.showImage,
|
|
621
|
+
{
|
|
622
|
+
dataUrl: options.dataUrl
|
|
623
|
+
}
|
|
624
|
+
);
|
|
625
|
+
return result;
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
// src/api/web.ts
|
|
630
|
+
var WebAPI = class {
|
|
631
|
+
constructor(client) {
|
|
632
|
+
this.client = client;
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Performs a web request through the HaexHub host application
|
|
636
|
+
* @param url The URL to fetch
|
|
637
|
+
* @param options Request options (method, headers, body, timeout)
|
|
638
|
+
* @returns Promise resolving to the web response
|
|
639
|
+
*/
|
|
640
|
+
async fetchAsync(url, options = {}) {
|
|
641
|
+
let bodyParam;
|
|
642
|
+
if (options.body) {
|
|
643
|
+
if (options.body instanceof ArrayBuffer) {
|
|
644
|
+
bodyParam = this.arrayBufferToBase64(options.body);
|
|
645
|
+
} else if (options.body instanceof Blob) {
|
|
646
|
+
bodyParam = await this.blobToBase64(options.body);
|
|
647
|
+
} else {
|
|
648
|
+
bodyParam = options.body;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
const response = await this.client.request(HAEXTENSION_METHODS.web.fetch, {
|
|
652
|
+
url,
|
|
653
|
+
method: options.method || "GET",
|
|
654
|
+
headers: options.headers,
|
|
655
|
+
body: bodyParam,
|
|
656
|
+
timeout: options.timeout
|
|
657
|
+
});
|
|
658
|
+
const bodyBuffer = this.base64ToArrayBuffer(response.body);
|
|
659
|
+
return {
|
|
660
|
+
status: response.status,
|
|
661
|
+
statusText: response.statusText,
|
|
662
|
+
headers: response.headers,
|
|
663
|
+
body: bodyBuffer,
|
|
664
|
+
url: response.url
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Convenience method for JSON requests
|
|
669
|
+
*/
|
|
670
|
+
async fetchJsonAsync(url, options = {}) {
|
|
671
|
+
const response = await this.fetchAsync(url, options);
|
|
672
|
+
const text = new TextDecoder().decode(response.body);
|
|
673
|
+
return JSON.parse(text);
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Convenience method for text requests
|
|
677
|
+
*/
|
|
678
|
+
async fetchTextAsync(url, options = {}) {
|
|
679
|
+
const response = await this.fetchAsync(url, options);
|
|
680
|
+
return new TextDecoder().decode(response.body);
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Convenience method for blob requests
|
|
684
|
+
*/
|
|
685
|
+
async fetchBlobAsync(url, options = {}) {
|
|
686
|
+
const response = await this.fetchAsync(url, options);
|
|
687
|
+
return new Blob([response.body]);
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Opens a URL in the user's default browser
|
|
691
|
+
* @param url The URL to open
|
|
692
|
+
*/
|
|
693
|
+
async openAsync(url) {
|
|
694
|
+
await this.client.request(HAEXTENSION_METHODS.application.open, {
|
|
695
|
+
application: "browser",
|
|
696
|
+
url
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
arrayBufferToBase64(buffer) {
|
|
700
|
+
const bytes = new Uint8Array(buffer);
|
|
701
|
+
let binary = "";
|
|
702
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
703
|
+
const byte = bytes[i];
|
|
704
|
+
if (byte === void 0) {
|
|
705
|
+
throw new Error("Invalid byte at index " + i);
|
|
706
|
+
}
|
|
707
|
+
binary += String.fromCharCode(byte);
|
|
708
|
+
}
|
|
709
|
+
return btoa(binary);
|
|
710
|
+
}
|
|
711
|
+
async blobToBase64(blob) {
|
|
712
|
+
return new Promise((resolve, reject) => {
|
|
713
|
+
const reader = new FileReader();
|
|
714
|
+
reader.onloadend = () => {
|
|
715
|
+
const result = reader.result;
|
|
716
|
+
if (typeof result !== "string") {
|
|
717
|
+
reject(new Error("Failed to read blob as data URL"));
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
const parts = result.split(",");
|
|
721
|
+
const base64 = parts[1];
|
|
722
|
+
if (!base64) {
|
|
723
|
+
reject(new Error("Failed to extract base64 from data URL"));
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
resolve(base64);
|
|
727
|
+
};
|
|
728
|
+
reader.onerror = reject;
|
|
729
|
+
reader.readAsDataURL(blob);
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
base64ToArrayBuffer(base64) {
|
|
733
|
+
const binaryString = atob(base64);
|
|
734
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
735
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
736
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
737
|
+
}
|
|
738
|
+
return bytes.buffer;
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
// src/api/permissions.ts
|
|
743
|
+
var PermissionsAPI = class {
|
|
744
|
+
constructor(client) {
|
|
745
|
+
this.client = client;
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Checks if the extension has permission for a database operation
|
|
749
|
+
* @param resource The database resource (table name or "*" for all tables)
|
|
750
|
+
* @param operation The operation type ("read" or "write")
|
|
751
|
+
* @returns Promise<boolean> indicating if permission is granted
|
|
752
|
+
*/
|
|
753
|
+
async checkDatabaseAsync(resource, operation) {
|
|
754
|
+
const response = await this.client.request(
|
|
755
|
+
"permissions.database.check",
|
|
756
|
+
{
|
|
757
|
+
resource,
|
|
758
|
+
operation
|
|
759
|
+
}
|
|
760
|
+
);
|
|
761
|
+
return response.status === "granted";
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Checks if the extension has permission for a web request
|
|
765
|
+
* @param url The URL to check (e.g., "https://example.com/path")
|
|
766
|
+
* @returns Promise<boolean> indicating if permission is granted
|
|
767
|
+
* @note Method/operation is not checked - permissions apply to all HTTP methods
|
|
768
|
+
*/
|
|
769
|
+
async checkWebAsync(url) {
|
|
770
|
+
const response = await this.client.request(
|
|
771
|
+
"permissions.web.check",
|
|
772
|
+
{
|
|
773
|
+
url
|
|
774
|
+
}
|
|
775
|
+
);
|
|
776
|
+
return response.status === "granted";
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Checks if the extension has permission for a filesystem operation
|
|
780
|
+
* @param path The file or directory path
|
|
781
|
+
* @param operation The operation type ("read" or "write")
|
|
782
|
+
* @returns Promise<boolean> indicating if permission is granted
|
|
783
|
+
*/
|
|
784
|
+
async checkFilesystemAsync(path, operation) {
|
|
785
|
+
const response = await this.client.request(
|
|
786
|
+
"permissions.filesystem.check",
|
|
787
|
+
{
|
|
788
|
+
path,
|
|
789
|
+
operation
|
|
790
|
+
}
|
|
791
|
+
);
|
|
792
|
+
return response.status === "granted";
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
var HaexVaultClient = class {
|
|
796
|
+
constructor(config = {}) {
|
|
797
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
798
|
+
this.eventListeners = /* @__PURE__ */ new Map();
|
|
799
|
+
this.messageHandler = null;
|
|
800
|
+
this.initialized = false;
|
|
801
|
+
this.requestCounter = 0;
|
|
802
|
+
this._extensionInfo = null;
|
|
803
|
+
this._context = null;
|
|
804
|
+
this.reactiveSubscribers = /* @__PURE__ */ new Set();
|
|
805
|
+
this.isNativeWindow = false;
|
|
806
|
+
// Wird im Konstruktor initialisiert
|
|
807
|
+
this.setupPromise = null;
|
|
808
|
+
this.setupHook = null;
|
|
809
|
+
this._setupCompleted = false;
|
|
810
|
+
this.orm = null;
|
|
811
|
+
this.config = {
|
|
812
|
+
debug: config.debug ?? false,
|
|
813
|
+
timeout: config.timeout ?? DEFAULT_TIMEOUT,
|
|
814
|
+
manifest: config.manifest
|
|
815
|
+
};
|
|
816
|
+
this.storage = new StorageAPI(this);
|
|
817
|
+
this.database = new DatabaseAPI(this);
|
|
818
|
+
this.filesystem = new FilesystemAPI(this);
|
|
819
|
+
this.web = new WebAPI(this);
|
|
820
|
+
this.permissions = new PermissionsAPI(this);
|
|
821
|
+
installConsoleForwarding(this.config.debug);
|
|
822
|
+
this.readyPromise = new Promise((resolve) => {
|
|
823
|
+
this.resolveReady = resolve;
|
|
824
|
+
});
|
|
825
|
+
this.init();
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Gibt ein Promise zurück, das aufgelöst wird, sobald der Client
|
|
829
|
+
* initialisiert ist und Extension-Infos empfangen hat.
|
|
830
|
+
*/
|
|
831
|
+
async ready() {
|
|
832
|
+
return this.readyPromise;
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Gibt zurück, ob das Setup bereits abgeschlossen wurde.
|
|
836
|
+
*/
|
|
837
|
+
get setupCompleted() {
|
|
838
|
+
return this._setupCompleted;
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Registriert eine Setup-Funktion, die nach der Initialisierung ausgeführt wird.
|
|
842
|
+
* Diese Funktion sollte für Aufgaben wie Tabellenerstellung, Migrationen, etc. verwendet werden.
|
|
843
|
+
* @param setupFn Die Setup-Funktion, die ausgeführt werden soll
|
|
844
|
+
*/
|
|
845
|
+
onSetup(setupFn) {
|
|
846
|
+
if (this.setupHook) {
|
|
847
|
+
throw new Error("Setup hook already registered");
|
|
848
|
+
}
|
|
849
|
+
this.setupHook = setupFn;
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Gibt ein Promise zurück, das aufgelöst wird, sobald der Client vollständig eingerichtet ist.
|
|
853
|
+
* Dies umfasst die Initialisierung UND das Setup (z.B. Tabellenerstellung).
|
|
854
|
+
* Falls kein Setup-Hook registriert wurde, entspricht dies ready().
|
|
855
|
+
*/
|
|
856
|
+
async setupComplete() {
|
|
857
|
+
await this.readyPromise;
|
|
858
|
+
if (!this.setupHook || this.setupCompleted) {
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
if (!this.setupPromise) {
|
|
862
|
+
this.setupPromise = this.runSetupAsync();
|
|
863
|
+
}
|
|
864
|
+
return this.setupPromise;
|
|
865
|
+
}
|
|
866
|
+
async runSetupAsync() {
|
|
867
|
+
if (!this.setupHook) return;
|
|
868
|
+
try {
|
|
869
|
+
this.log("[HaexHub] Running setup hook...");
|
|
870
|
+
await this.setupHook();
|
|
871
|
+
this._setupCompleted = true;
|
|
872
|
+
this.log("[HaexHub] Setup completed successfully");
|
|
873
|
+
this.notifySubscribers();
|
|
874
|
+
} catch (error) {
|
|
875
|
+
this.log("[HaexHub] Setup failed:", error);
|
|
876
|
+
throw error;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* Initialisiert die Drizzle-Datenbankinstanz.
|
|
881
|
+
* Muss nach der Definition des Schemas aufgerufen werden.
|
|
882
|
+
* @param schema Das Drizzle-Schemaobjekt (mit bereits geprefixten Tabellennamen).
|
|
883
|
+
* @returns Die typsichere Drizzle-Datenbankinstanz.
|
|
884
|
+
*/
|
|
885
|
+
initializeDatabase(schema) {
|
|
886
|
+
if (!this._extensionInfo) {
|
|
887
|
+
throw new HaexHubError(
|
|
888
|
+
"EXTENSION_INFO_UNAVAILABLE" /* EXTENSION_INFO_UNAVAILABLE */,
|
|
889
|
+
"errors.client_not_ready"
|
|
890
|
+
);
|
|
891
|
+
}
|
|
892
|
+
const dbInstance = drizzle(
|
|
893
|
+
async (sql, params, method) => {
|
|
894
|
+
try {
|
|
895
|
+
if (method === "run" || method === "all") {
|
|
896
|
+
const result2 = await this.request(
|
|
897
|
+
HAEXTENSION_METHODS.database.execute,
|
|
898
|
+
{
|
|
899
|
+
query: sql,
|
|
900
|
+
params
|
|
901
|
+
}
|
|
902
|
+
);
|
|
903
|
+
if (method === "all") {
|
|
904
|
+
return { rows: result2.rows || [] };
|
|
905
|
+
}
|
|
906
|
+
if (result2.rows && Array.isArray(result2.rows) && result2.rows.length > 0) {
|
|
907
|
+
return { rows: result2.rows };
|
|
908
|
+
}
|
|
909
|
+
return result2;
|
|
910
|
+
}
|
|
911
|
+
const result = await this.request(HAEXTENSION_METHODS.database.query, {
|
|
912
|
+
query: sql,
|
|
913
|
+
params
|
|
914
|
+
});
|
|
915
|
+
const rows = result.rows;
|
|
916
|
+
if (method === "get") {
|
|
917
|
+
return { rows: rows.length > 0 ? rows.at(0) : void 0 };
|
|
918
|
+
}
|
|
919
|
+
return { rows };
|
|
920
|
+
} catch (error) {
|
|
921
|
+
this.log("Database operation failed:", error);
|
|
922
|
+
throw error;
|
|
923
|
+
}
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
schema,
|
|
927
|
+
logger: false
|
|
928
|
+
}
|
|
929
|
+
);
|
|
930
|
+
this.orm = dbInstance;
|
|
931
|
+
return dbInstance;
|
|
932
|
+
}
|
|
933
|
+
get extensionInfo() {
|
|
934
|
+
return this._extensionInfo;
|
|
935
|
+
}
|
|
936
|
+
get context() {
|
|
937
|
+
return this._context;
|
|
938
|
+
}
|
|
939
|
+
subscribe(callback) {
|
|
940
|
+
this.reactiveSubscribers.add(callback);
|
|
941
|
+
return () => {
|
|
942
|
+
this.reactiveSubscribers.delete(callback);
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
notifySubscribers() {
|
|
946
|
+
this.reactiveSubscribers.forEach((callback) => callback());
|
|
947
|
+
}
|
|
948
|
+
async getDependencies() {
|
|
949
|
+
return this.request("extensions.getDependencies");
|
|
950
|
+
}
|
|
951
|
+
getTableName(tableName) {
|
|
952
|
+
if (!this._extensionInfo) {
|
|
953
|
+
throw new HaexHubError(
|
|
954
|
+
"EXTENSION_INFO_UNAVAILABLE" /* EXTENSION_INFO_UNAVAILABLE */,
|
|
955
|
+
"errors.extension_info_unavailable"
|
|
956
|
+
);
|
|
957
|
+
}
|
|
958
|
+
this.validateTableName(tableName);
|
|
959
|
+
const { publicKey, name } = this._extensionInfo;
|
|
960
|
+
const extensionName = name;
|
|
961
|
+
return `"${publicKey}${TABLE_SEPARATOR}${extensionName}${TABLE_SEPARATOR}${tableName}"`;
|
|
962
|
+
}
|
|
963
|
+
getDependencyTableName(publicKey, extensionName, tableName) {
|
|
964
|
+
this.validatePublicKey(publicKey);
|
|
965
|
+
this.validateExtensionName(extensionName);
|
|
966
|
+
this.validateTableName(tableName);
|
|
967
|
+
return `"${publicKey}${TABLE_SEPARATOR}${extensionName}${TABLE_SEPARATOR}${tableName}"`;
|
|
968
|
+
}
|
|
969
|
+
parseTableName(fullTableName) {
|
|
970
|
+
let cleanTableName = fullTableName;
|
|
971
|
+
if (cleanTableName.startsWith('"') && cleanTableName.endsWith('"')) {
|
|
972
|
+
cleanTableName = cleanTableName.slice(1, -1);
|
|
973
|
+
}
|
|
974
|
+
const parts = cleanTableName.split(TABLE_SEPARATOR);
|
|
975
|
+
if (parts.length !== 3) {
|
|
976
|
+
return null;
|
|
977
|
+
}
|
|
978
|
+
const [publicKey, extensionName, tableName] = parts;
|
|
979
|
+
if (!publicKey || !extensionName || !tableName) {
|
|
980
|
+
return null;
|
|
981
|
+
}
|
|
982
|
+
return {
|
|
983
|
+
publicKey,
|
|
984
|
+
extensionName,
|
|
985
|
+
tableName
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Execute a raw SQL query (SELECT)
|
|
990
|
+
* Returns rows as an array of objects
|
|
991
|
+
*/
|
|
992
|
+
async query(sql, params = []) {
|
|
993
|
+
const result = await this.request(
|
|
994
|
+
HAEXTENSION_METHODS.database.query,
|
|
995
|
+
{ query: sql, params }
|
|
996
|
+
);
|
|
997
|
+
if (this.config.debug) {
|
|
998
|
+
console.log("[SDK query()] Raw result:", JSON.stringify(result, null, 2));
|
|
999
|
+
}
|
|
1000
|
+
return result.rows;
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Alias for query() - more intuitive for SELECT statements
|
|
1004
|
+
*/
|
|
1005
|
+
async select(sql, params = []) {
|
|
1006
|
+
return this.query(sql, params);
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Execute a raw SQL statement (INSERT, UPDATE, DELETE, CREATE, etc.)
|
|
1010
|
+
* Returns rowsAffected and lastInsertId
|
|
1011
|
+
*/
|
|
1012
|
+
async execute(sql, params = []) {
|
|
1013
|
+
const result = await this.request(
|
|
1014
|
+
HAEXTENSION_METHODS.database.execute,
|
|
1015
|
+
{ query: sql, params }
|
|
1016
|
+
);
|
|
1017
|
+
return {
|
|
1018
|
+
rowsAffected: result.rowsAffected,
|
|
1019
|
+
lastInsertId: result.lastInsertId
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Registers extension migrations with HaexVault for CRDT synchronization
|
|
1024
|
+
* HaexVault will validate and execute these migrations
|
|
1025
|
+
* @param extensionVersion - The version of the extension
|
|
1026
|
+
* @param migrations - Array of migration objects with name and SQL content
|
|
1027
|
+
* @returns Promise that resolves when migrations are registered
|
|
1028
|
+
*/
|
|
1029
|
+
async registerMigrationsAsync(extensionVersion, migrations) {
|
|
1030
|
+
return this.database.registerMigrationsAsync(extensionVersion, migrations);
|
|
1031
|
+
}
|
|
1032
|
+
async requestDatabasePermission(request) {
|
|
1033
|
+
return this.request("permissions.database.request", {
|
|
1034
|
+
resource: request.resource,
|
|
1035
|
+
operation: request.operation,
|
|
1036
|
+
reason: request.reason
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
async checkDatabasePermission(resource, operation) {
|
|
1040
|
+
const response = await this.request(
|
|
1041
|
+
"permissions.database.check",
|
|
1042
|
+
{
|
|
1043
|
+
resource,
|
|
1044
|
+
operation
|
|
1045
|
+
}
|
|
1046
|
+
);
|
|
1047
|
+
return response.status === "granted";
|
|
1048
|
+
}
|
|
1049
|
+
async respondToSearch(requestId, results) {
|
|
1050
|
+
await this.request("search.respond", {
|
|
1051
|
+
requestId,
|
|
1052
|
+
results
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
async request(method, params = {}) {
|
|
1056
|
+
if (this.isNativeWindow && typeof window.__TAURI__ !== "undefined") {
|
|
1057
|
+
return this.invoke(method, params);
|
|
1058
|
+
}
|
|
1059
|
+
return this.postMessage(method, params);
|
|
1060
|
+
}
|
|
1061
|
+
async postMessage(method, params) {
|
|
1062
|
+
const requestId = this.generateRequestId();
|
|
1063
|
+
const request = {
|
|
1064
|
+
method,
|
|
1065
|
+
params,
|
|
1066
|
+
timestamp: Date.now()
|
|
1067
|
+
};
|
|
1068
|
+
return new Promise((resolve, reject) => {
|
|
1069
|
+
const timeout = setTimeout(() => {
|
|
1070
|
+
this.pendingRequests.delete(requestId);
|
|
1071
|
+
reject(
|
|
1072
|
+
new HaexHubError("TIMEOUT" /* TIMEOUT */, "errors.timeout", {
|
|
1073
|
+
timeout: this.config.timeout
|
|
1074
|
+
})
|
|
1075
|
+
);
|
|
1076
|
+
}, this.config.timeout);
|
|
1077
|
+
this.pendingRequests.set(requestId, { resolve, reject, timeout });
|
|
1078
|
+
const targetOrigin = "*";
|
|
1079
|
+
if (this.config.debug) {
|
|
1080
|
+
console.log("[SDK Debug] ========== Sending Request ==========");
|
|
1081
|
+
console.log("[SDK Debug] Request ID:", requestId);
|
|
1082
|
+
console.log("[SDK Debug] Method:", request.method);
|
|
1083
|
+
console.log("[SDK Debug] Params:", request.params);
|
|
1084
|
+
console.log("[SDK Debug] Target origin:", targetOrigin);
|
|
1085
|
+
console.log("[SDK Debug] Extension info:", this._extensionInfo);
|
|
1086
|
+
console.log("[SDK Debug] ========================================");
|
|
1087
|
+
}
|
|
1088
|
+
window.parent.postMessage({ id: requestId, ...request }, targetOrigin);
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
async invoke(method, params) {
|
|
1092
|
+
const { invoke } = window.__TAURI__.core;
|
|
1093
|
+
if (this.config.debug) {
|
|
1094
|
+
console.log("[SDK Debug] ========== Invoke Request ==========");
|
|
1095
|
+
console.log("[SDK Debug] Method:", method);
|
|
1096
|
+
console.log("[SDK Debug] Params:", params);
|
|
1097
|
+
console.log("[SDK Debug] =======================================");
|
|
1098
|
+
}
|
|
1099
|
+
switch (method) {
|
|
1100
|
+
case HAEXTENSION_METHODS.database.query:
|
|
1101
|
+
return invoke("webview_extension_db_query", {
|
|
1102
|
+
query: params.query,
|
|
1103
|
+
params: params.params || []
|
|
1104
|
+
});
|
|
1105
|
+
case HAEXTENSION_METHODS.database.execute:
|
|
1106
|
+
return invoke("webview_extension_db_execute", {
|
|
1107
|
+
query: params.query,
|
|
1108
|
+
params: params.params || []
|
|
1109
|
+
});
|
|
1110
|
+
case "permissions.web.check":
|
|
1111
|
+
return invoke("webview_extension_check_web_permission", {
|
|
1112
|
+
url: params.url
|
|
1113
|
+
});
|
|
1114
|
+
case "permissions.database.check":
|
|
1115
|
+
return invoke("webview_extension_check_database_permission", {
|
|
1116
|
+
resource: params.resource,
|
|
1117
|
+
operation: params.operation
|
|
1118
|
+
});
|
|
1119
|
+
case "permissions.filesystem.check":
|
|
1120
|
+
return invoke("webview_extension_check_filesystem_permission", {
|
|
1121
|
+
path: params.path,
|
|
1122
|
+
actionStr: params.action
|
|
1123
|
+
});
|
|
1124
|
+
case HAEXTENSION_METHODS.application.open:
|
|
1125
|
+
return invoke("webview_extension_web_open", {
|
|
1126
|
+
url: params.url
|
|
1127
|
+
});
|
|
1128
|
+
case HAEXTENSION_METHODS.web.fetch:
|
|
1129
|
+
return invoke("webview_extension_web_request", {
|
|
1130
|
+
url: params.url,
|
|
1131
|
+
method: params.method,
|
|
1132
|
+
headers: params.headers,
|
|
1133
|
+
body: params.body
|
|
1134
|
+
});
|
|
1135
|
+
case HAEXTENSION_METHODS.filesystem.saveFile:
|
|
1136
|
+
return invoke("webview_extension_fs_save_file", {
|
|
1137
|
+
data: params.data,
|
|
1138
|
+
defaultPath: params.defaultPath,
|
|
1139
|
+
title: params.title,
|
|
1140
|
+
filters: params.filters
|
|
1141
|
+
});
|
|
1142
|
+
case HAEXTENSION_METHODS.filesystem.openFile:
|
|
1143
|
+
return invoke("webview_extension_fs_open_file", {
|
|
1144
|
+
data: params.data,
|
|
1145
|
+
fileName: params.fileName
|
|
1146
|
+
});
|
|
1147
|
+
default:
|
|
1148
|
+
throw new HaexHubError(
|
|
1149
|
+
"METHOD_NOT_FOUND" /* METHOD_NOT_FOUND */,
|
|
1150
|
+
"errors.method_not_found",
|
|
1151
|
+
{ method }
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
on(eventType, callback) {
|
|
1156
|
+
if (!this.eventListeners.has(eventType)) {
|
|
1157
|
+
this.eventListeners.set(eventType, /* @__PURE__ */ new Set());
|
|
1158
|
+
}
|
|
1159
|
+
this.eventListeners.get(eventType).add(callback);
|
|
1160
|
+
}
|
|
1161
|
+
off(eventType, callback) {
|
|
1162
|
+
const listeners = this.eventListeners.get(eventType);
|
|
1163
|
+
if (listeners) {
|
|
1164
|
+
listeners.delete(callback);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
destroy() {
|
|
1168
|
+
if (this.messageHandler) {
|
|
1169
|
+
window.removeEventListener("message", this.messageHandler);
|
|
1170
|
+
}
|
|
1171
|
+
this.pendingRequests.forEach(({ timeout }) => clearTimeout(timeout));
|
|
1172
|
+
this.pendingRequests.clear();
|
|
1173
|
+
this.eventListeners.clear();
|
|
1174
|
+
this.initialized = false;
|
|
1175
|
+
this.log("HaexHub SDK destroyed");
|
|
1176
|
+
}
|
|
1177
|
+
async init() {
|
|
1178
|
+
if (this.initialized) return;
|
|
1179
|
+
const isInIframe = window.self !== window.top;
|
|
1180
|
+
if (!isInIframe) {
|
|
1181
|
+
try {
|
|
1182
|
+
if (typeof window.__TAURI__ !== "undefined") {
|
|
1183
|
+
const { invoke } = window.__TAURI__.core;
|
|
1184
|
+
this._extensionInfo = await invoke("webview_extension_get_info");
|
|
1185
|
+
this._context = await invoke("webview_extension_context_get");
|
|
1186
|
+
this.isNativeWindow = true;
|
|
1187
|
+
this.initialized = true;
|
|
1188
|
+
this.log("HaexHub SDK initialized in native WebViewWindow mode");
|
|
1189
|
+
this.log("Extension info:", this._extensionInfo);
|
|
1190
|
+
this.log("Application context:", this._context);
|
|
1191
|
+
this.notifySubscribers();
|
|
1192
|
+
const { listen } = window.__TAURI__.event;
|
|
1193
|
+
console.log("[HaexHub SDK] Setting up Tauri event listener for:", HAEXTENSION_EVENTS.CONTEXT_CHANGED);
|
|
1194
|
+
try {
|
|
1195
|
+
await listen(HAEXTENSION_EVENTS.CONTEXT_CHANGED, (event) => {
|
|
1196
|
+
console.log("[HaexHub SDK] Received Tauri event:", HAEXTENSION_EVENTS.CONTEXT_CHANGED, event);
|
|
1197
|
+
this.log("Received context change event:", event);
|
|
1198
|
+
if (event.payload?.context) {
|
|
1199
|
+
this._context = event.payload.context;
|
|
1200
|
+
console.log("[HaexHub SDK] Updated context to:", this._context);
|
|
1201
|
+
this.handleEvent({
|
|
1202
|
+
type: HAEXTENSION_EVENTS.CONTEXT_CHANGED,
|
|
1203
|
+
data: { context: this._context },
|
|
1204
|
+
timestamp: Date.now()
|
|
1205
|
+
});
|
|
1206
|
+
} else {
|
|
1207
|
+
console.warn("[HaexHub SDK] Event received but no context in payload:", event);
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1210
|
+
console.log("[HaexHub SDK] Context change listener registered successfully");
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
console.error("[HaexHub SDK] Failed to setup context change listener:", error);
|
|
1213
|
+
this.log("Failed to setup context change listener:", error);
|
|
1214
|
+
}
|
|
1215
|
+
this.resolveReady();
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
} catch (error) {
|
|
1219
|
+
this.log("Tauri commands failed, falling back to iframe mode", error);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
if (window.self === window.top) {
|
|
1223
|
+
throw new HaexHubError("NOT_IN_IFRAME" /* NOT_IN_IFRAME */, "errors.not_in_iframe");
|
|
1224
|
+
}
|
|
1225
|
+
this.messageHandler = this.handleMessage.bind(this);
|
|
1226
|
+
window.addEventListener("message", this.messageHandler);
|
|
1227
|
+
this.isNativeWindow = false;
|
|
1228
|
+
this.initialized = true;
|
|
1229
|
+
this.log("HaexHub SDK initialized in iframe mode");
|
|
1230
|
+
try {
|
|
1231
|
+
if (this.config.manifest) {
|
|
1232
|
+
this._extensionInfo = {
|
|
1233
|
+
publicKey: this.config.manifest.publicKey,
|
|
1234
|
+
name: this.config.manifest.name,
|
|
1235
|
+
version: this.config.manifest.version,
|
|
1236
|
+
displayName: this.config.manifest.name
|
|
1237
|
+
};
|
|
1238
|
+
this.log("Extension info loaded from manifest:", this._extensionInfo);
|
|
1239
|
+
this.notifySubscribers();
|
|
1240
|
+
}
|
|
1241
|
+
if (typeof window !== "undefined" && window.parent) {
|
|
1242
|
+
const debugInfo = `SDK Debug:
|
|
1243
|
+
window.parent exists: ${!!window.parent}
|
|
1244
|
+
window.parent === window: ${window.parent === window}
|
|
1245
|
+
window.self === window.top: ${window.self === window.top}`;
|
|
1246
|
+
try {
|
|
1247
|
+
window.parent.postMessage({
|
|
1248
|
+
type: "haexhub:debug",
|
|
1249
|
+
data: debugInfo
|
|
1250
|
+
}, "*");
|
|
1251
|
+
} catch (e) {
|
|
1252
|
+
alert(debugInfo + `
|
|
1253
|
+
postMessage error: ${e}`);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
this._context = await this.request(HAEXTENSION_METHODS.context.get);
|
|
1257
|
+
this.log("Application context received:", this._context);
|
|
1258
|
+
this.notifySubscribers();
|
|
1259
|
+
this.resolveReady();
|
|
1260
|
+
} catch (error) {
|
|
1261
|
+
this.log("Failed to load extension info or context:", error);
|
|
1262
|
+
throw error;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
handleMessage(event) {
|
|
1266
|
+
if (this.config.debug) {
|
|
1267
|
+
console.log("[SDK Debug] ========== Message Received ==========");
|
|
1268
|
+
console.log("[SDK Debug] Event origin:", event.origin);
|
|
1269
|
+
console.log(
|
|
1270
|
+
"[SDK Debug] Event source:",
|
|
1271
|
+
event.source === window.parent ? "parent window" : "unknown"
|
|
1272
|
+
);
|
|
1273
|
+
console.log("[SDK Debug] Event data:", event.data);
|
|
1274
|
+
console.log("[SDK Debug] Extension info loaded:", !!this._extensionInfo);
|
|
1275
|
+
console.log(
|
|
1276
|
+
"[SDK Debug] Pending requests count:",
|
|
1277
|
+
this.pendingRequests.size
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1280
|
+
if (event.source !== window.parent) {
|
|
1281
|
+
if (this.config.debug) {
|
|
1282
|
+
console.error("[SDK Debug] \u274C REJECTED: Message not from parent window!");
|
|
1283
|
+
}
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
1286
|
+
const data = event.data;
|
|
1287
|
+
if ("id" in data && this.pendingRequests.has(data.id)) {
|
|
1288
|
+
if (this.config.debug) {
|
|
1289
|
+
console.log("[SDK Debug] \u2705 Found pending request for ID:", data.id);
|
|
1290
|
+
}
|
|
1291
|
+
const pending = this.pendingRequests.get(data.id);
|
|
1292
|
+
clearTimeout(pending.timeout);
|
|
1293
|
+
this.pendingRequests.delete(data.id);
|
|
1294
|
+
if (data.error) {
|
|
1295
|
+
if (this.config.debug) {
|
|
1296
|
+
console.error("[SDK Debug] \u274C Request failed:", data.error);
|
|
1297
|
+
}
|
|
1298
|
+
pending.reject(data.error);
|
|
1299
|
+
} else {
|
|
1300
|
+
if (this.config.debug) {
|
|
1301
|
+
console.log("[SDK Debug] \u2705 Request succeeded:", data.result);
|
|
1302
|
+
}
|
|
1303
|
+
pending.resolve(data.result);
|
|
1304
|
+
}
|
|
1305
|
+
return;
|
|
1306
|
+
}
|
|
1307
|
+
if ("id" in data && !this.pendingRequests.has(data.id)) {
|
|
1308
|
+
if (this.config.debug) {
|
|
1309
|
+
console.warn(
|
|
1310
|
+
"[SDK Debug] \u26A0\uFE0F Received response for unknown request ID:",
|
|
1311
|
+
data.id
|
|
1312
|
+
);
|
|
1313
|
+
console.warn(
|
|
1314
|
+
"[SDK Debug] Known IDs:",
|
|
1315
|
+
Array.from(this.pendingRequests.keys())
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
if ("type" in data && data.type) {
|
|
1320
|
+
if (this.config.debug) {
|
|
1321
|
+
console.log("[SDK Debug] Event received:", data.type);
|
|
1322
|
+
}
|
|
1323
|
+
this.handleEvent(data);
|
|
1324
|
+
}
|
|
1325
|
+
if (this.config.debug) {
|
|
1326
|
+
console.log("[SDK Debug] ========== End Message ==========");
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
handleEvent(event) {
|
|
1330
|
+
if (event.type === HAEXTENSION_EVENTS.CONTEXT_CHANGED) {
|
|
1331
|
+
const contextEvent = event;
|
|
1332
|
+
this._context = contextEvent.data.context;
|
|
1333
|
+
this.log("Context updated:", this._context);
|
|
1334
|
+
this.notifySubscribers();
|
|
1335
|
+
}
|
|
1336
|
+
this.emitEvent(event);
|
|
1337
|
+
}
|
|
1338
|
+
emitEvent(event) {
|
|
1339
|
+
this.log("Event received:", event);
|
|
1340
|
+
const listeners = this.eventListeners.get(event.type);
|
|
1341
|
+
if (listeners) {
|
|
1342
|
+
listeners.forEach((callback) => callback(event));
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
generateRequestId() {
|
|
1346
|
+
return `req_${++this.requestCounter}`;
|
|
1347
|
+
}
|
|
1348
|
+
validatePublicKey(publicKey) {
|
|
1349
|
+
if (!publicKey || typeof publicKey !== "string" || publicKey.trim() === "") {
|
|
1350
|
+
throw new HaexHubError(
|
|
1351
|
+
"INVALID_PUBLIC_KEY" /* INVALID_PUBLIC_KEY */,
|
|
1352
|
+
"errors.invalid_public_key",
|
|
1353
|
+
{ publicKey }
|
|
1354
|
+
);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
validateExtensionName(extensionName) {
|
|
1358
|
+
if (!extensionName || !/^[a-z][a-z0-9-]*$/i.test(extensionName)) {
|
|
1359
|
+
throw new HaexHubError(
|
|
1360
|
+
"INVALID_EXTENSION_NAME" /* INVALID_EXTENSION_NAME */,
|
|
1361
|
+
"errors.invalid_extension_name",
|
|
1362
|
+
{ extensionName }
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1365
|
+
if (extensionName.includes(TABLE_SEPARATOR)) {
|
|
1366
|
+
throw new HaexHubError(
|
|
1367
|
+
"INVALID_EXTENSION_NAME" /* INVALID_EXTENSION_NAME */,
|
|
1368
|
+
"errors.extension_name_contains_separator",
|
|
1369
|
+
{ extensionName, separator: TABLE_SEPARATOR }
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
validateTableName(tableName) {
|
|
1374
|
+
if (!tableName || typeof tableName !== "string") {
|
|
1375
|
+
throw new HaexHubError(
|
|
1376
|
+
"INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
|
|
1377
|
+
"errors.table_name_empty"
|
|
1378
|
+
);
|
|
1379
|
+
}
|
|
1380
|
+
if (tableName.includes(TABLE_SEPARATOR)) {
|
|
1381
|
+
throw new HaexHubError(
|
|
1382
|
+
"INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
|
|
1383
|
+
"errors.table_name_contains_separator",
|
|
1384
|
+
{ tableName, separator: TABLE_SEPARATOR }
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
if (!/^[a-z][a-z0-9-_]*$/i.test(tableName)) {
|
|
1388
|
+
throw new HaexHubError(
|
|
1389
|
+
"INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
|
|
1390
|
+
"errors.table_name_format",
|
|
1391
|
+
{ tableName }
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
log(...args) {
|
|
1396
|
+
if (this.config.debug) {
|
|
1397
|
+
console.log("[HaexHub SDK]", ...args);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
};
|
|
1401
|
+
|
|
1402
|
+
// src/index.ts
|
|
1403
|
+
function createHaexVaultClient(config = {}) {
|
|
1404
|
+
return new HaexVaultClient(config);
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
export { DEFAULT_TIMEOUT, DatabaseAPI, ErrorCode, FilesystemAPI, HAEXTENSION_EVENTS, HAEXTENSION_METHODS, HaexHubError, HaexVaultClient, PermissionStatus, PermissionsAPI, TABLE_SEPARATOR, WebAPI, createHaexVaultClient, installBaseTag, installCookiePolyfill, installHistoryPolyfill, installLocalStoragePolyfill, installPolyfills, installSessionStoragePolyfill };
|
|
1408
|
+
//# sourceMappingURL=index.mjs.map
|
|
1409
|
+
//# sourceMappingURL=index.mjs.map
|