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