@haex-space/vault-sdk 2.3.15 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -378,67 +378,6 @@ var HAEXTENSION_EVENTS = {
378
378
  EXTERNAL_REQUEST: "haextension:external:request"
379
379
  };
380
380
 
381
- // src/methods.ts
382
- var HAEXTENSION_METHODS = {
383
- context: {
384
- get: "haextension:context:get"
385
- },
386
- database: {
387
- query: "haextension:database:query",
388
- execute: "haextension:database:execute",
389
- transaction: "haextension:database:transaction",
390
- registerMigrations: "haextension:database:register-migrations"
391
- },
392
- filesystem: {
393
- saveFile: "haextension:filesystem:save-file",
394
- openFile: "haextension:filesystem:open-file",
395
- showImage: "haextension:filesystem:show-image",
396
- sync: {
397
- // Spaces
398
- listSpaces: "haextension:filesystem:sync:list-spaces",
399
- createSpace: "haextension:filesystem:sync:create-space",
400
- deleteSpace: "haextension:filesystem:sync:delete-space",
401
- // Files
402
- listFiles: "haextension:filesystem:sync:list-files",
403
- getFile: "haextension:filesystem:sync:get-file",
404
- uploadFile: "haextension:filesystem:sync:upload-file",
405
- downloadFile: "haextension:filesystem:sync:download-file",
406
- deleteFile: "haextension:filesystem:sync:delete-file",
407
- // Backends
408
- listBackends: "haextension:filesystem:sync:list-backends",
409
- addBackend: "haextension:filesystem:sync:add-backend",
410
- removeBackend: "haextension:filesystem:sync:remove-backend",
411
- testBackend: "haextension:filesystem:sync:test-backend",
412
- // Sync Rules
413
- listSyncRules: "haextension:filesystem:sync:list-sync-rules",
414
- addSyncRule: "haextension:filesystem:sync:add-sync-rule",
415
- removeSyncRule: "haextension:filesystem:sync:remove-sync-rule",
416
- // Sync Operations
417
- getSyncStatus: "haextension:filesystem:sync:get-sync-status",
418
- triggerSync: "haextension:filesystem:sync:trigger-sync",
419
- pauseSync: "haextension:filesystem:sync:pause-sync",
420
- resumeSync: "haextension:filesystem:sync:resume-sync",
421
- // Conflict Resolution
422
- resolveConflict: "haextension:filesystem:sync:resolve-conflict",
423
- // UI Helpers
424
- selectFolder: "haextension:filesystem:sync:select-folder"
425
- }
426
- },
427
- storage: {
428
- getItem: "haextension:storage:get-item",
429
- setItem: "haextension:storage:set-item",
430
- removeItem: "haextension:storage:remove-item",
431
- clear: "haextension:storage:clear",
432
- keys: "haextension:storage:keys"
433
- },
434
- web: {
435
- fetch: "haextension:web:fetch"
436
- },
437
- application: {
438
- open: "haextension:application:open"
439
- }
440
- };
441
-
442
381
  // src/types.ts
443
382
  var DEFAULT_TIMEOUT = 3e4;
444
383
  var TABLE_SEPARATOR = "__";
@@ -468,13 +407,13 @@ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
468
407
  ErrorCode2["WEB_ERROR"] = "WEB_ERROR";
469
408
  return ErrorCode2;
470
409
  })(ErrorCode || {});
471
- var HaexHubError = class extends Error {
410
+ var HaexVaultSdkError = class extends Error {
472
411
  constructor(code, messageKey, details) {
473
412
  super(messageKey);
474
413
  this.code = code;
475
414
  this.messageKey = messageKey;
476
415
  this.details = details;
477
- this.name = "HaexHubError";
416
+ this.name = "HaexVaultSdkError";
478
417
  }
479
418
  /**
480
419
  * Get localized error message
@@ -502,6 +441,67 @@ var HaexHubError = class extends Error {
502
441
  }
503
442
  };
504
443
 
444
+ // src/methods.ts
445
+ var HAEXTENSION_METHODS = {
446
+ context: {
447
+ get: "haextension:context:get"
448
+ },
449
+ database: {
450
+ query: "haextension:database:query",
451
+ execute: "haextension:database:execute",
452
+ transaction: "haextension:database:transaction",
453
+ registerMigrations: "haextension:database:register-migrations"
454
+ },
455
+ filesystem: {
456
+ saveFile: "haextension:filesystem:save-file",
457
+ openFile: "haextension:filesystem:open-file",
458
+ showImage: "haextension:filesystem:show-image",
459
+ sync: {
460
+ // Spaces
461
+ listSpaces: "haextension:filesystem:sync:list-spaces",
462
+ createSpace: "haextension:filesystem:sync:create-space",
463
+ deleteSpace: "haextension:filesystem:sync:delete-space",
464
+ // Files
465
+ listFiles: "haextension:filesystem:sync:list-files",
466
+ getFile: "haextension:filesystem:sync:get-file",
467
+ uploadFile: "haextension:filesystem:sync:upload-file",
468
+ downloadFile: "haextension:filesystem:sync:download-file",
469
+ deleteFile: "haextension:filesystem:sync:delete-file",
470
+ // Backends
471
+ listBackends: "haextension:filesystem:sync:list-backends",
472
+ addBackend: "haextension:filesystem:sync:add-backend",
473
+ removeBackend: "haextension:filesystem:sync:remove-backend",
474
+ testBackend: "haextension:filesystem:sync:test-backend",
475
+ // Sync Rules
476
+ listSyncRules: "haextension:filesystem:sync:list-sync-rules",
477
+ addSyncRule: "haextension:filesystem:sync:add-sync-rule",
478
+ removeSyncRule: "haextension:filesystem:sync:remove-sync-rule",
479
+ // Sync Operations
480
+ getSyncStatus: "haextension:filesystem:sync:get-sync-status",
481
+ triggerSync: "haextension:filesystem:sync:trigger-sync",
482
+ pauseSync: "haextension:filesystem:sync:pause-sync",
483
+ resumeSync: "haextension:filesystem:sync:resume-sync",
484
+ // Conflict Resolution
485
+ resolveConflict: "haextension:filesystem:sync:resolve-conflict",
486
+ // UI Helpers
487
+ selectFolder: "haextension:filesystem:sync:select-folder"
488
+ }
489
+ },
490
+ storage: {
491
+ getItem: "haextension:storage:get-item",
492
+ setItem: "haextension:storage:set-item",
493
+ removeItem: "haextension:storage:remove-item",
494
+ clear: "haextension:storage:clear",
495
+ keys: "haextension:storage:keys"
496
+ },
497
+ web: {
498
+ fetch: "haextension:web:fetch"
499
+ },
500
+ application: {
501
+ open: "haextension:application:open"
502
+ }
503
+ };
504
+
505
505
  // src/api/storage.ts
506
506
  var StorageAPI = class {
507
507
  constructor(client) {
@@ -1044,548 +1044,547 @@ var PermissionsAPI = class {
1044
1044
  return response.status === "granted";
1045
1045
  }
1046
1046
  };
1047
- var HaexVaultClient = class {
1048
- constructor(config = {}) {
1049
- this.pendingRequests = /* @__PURE__ */ new Map();
1050
- this.eventListeners = /* @__PURE__ */ new Map();
1051
- this.externalRequestHandlers = /* @__PURE__ */ new Map();
1052
- this.messageHandler = null;
1053
- this.initialized = false;
1054
- this.requestCounter = 0;
1055
- this._extensionInfo = null;
1056
- this._context = null;
1057
- this.reactiveSubscribers = /* @__PURE__ */ new Set();
1058
- this.isNativeWindow = false;
1059
- // Wird im Konstruktor initialisiert
1060
- this.setupPromise = null;
1061
- this.setupHook = null;
1062
- this._setupCompleted = false;
1063
- this.orm = null;
1064
- this.config = {
1065
- debug: config.debug ?? false,
1066
- timeout: config.timeout ?? DEFAULT_TIMEOUT,
1067
- manifest: config.manifest
1068
- };
1069
- this.storage = new StorageAPI(this);
1070
- this.database = new DatabaseAPI(this);
1071
- this.filesystem = new FilesystemAPI(this);
1072
- this.web = new WebAPI(this);
1073
- this.permissions = new PermissionsAPI(this);
1074
- installConsoleForwarding(this.config.debug);
1075
- this.readyPromise = new Promise((resolve) => {
1076
- this.resolveReady = resolve;
1077
- });
1078
- this.init();
1079
- }
1080
- /**
1081
- * Gibt ein Promise zurück, das aufgelöst wird, sobald der Client
1082
- * initialisiert ist und Extension-Infos empfangen hat.
1083
- */
1084
- async ready() {
1085
- return this.readyPromise;
1086
- }
1087
- /**
1088
- * Gibt zurück, ob das Setup bereits abgeschlossen wurde.
1089
- */
1090
- get setupCompleted() {
1091
- return this._setupCompleted;
1047
+
1048
+ // src/client/tableName.ts
1049
+ function validatePublicKey(publicKey) {
1050
+ if (!publicKey || typeof publicKey !== "string" || publicKey.trim() === "") {
1051
+ throw new HaexVaultSdkError(
1052
+ "INVALID_PUBLIC_KEY" /* INVALID_PUBLIC_KEY */,
1053
+ "errors.invalid_public_key",
1054
+ { publicKey }
1055
+ );
1092
1056
  }
1093
- /**
1094
- * Registriert eine Setup-Funktion, die nach der Initialisierung ausgeführt wird.
1095
- * Diese Funktion sollte für Aufgaben wie Tabellenerstellung, Migrationen, etc. verwendet werden.
1096
- * @param setupFn Die Setup-Funktion, die ausgeführt werden soll
1097
- */
1098
- onSetup(setupFn) {
1099
- if (this.setupHook) {
1100
- throw new Error("Setup hook already registered");
1101
- }
1102
- this.setupHook = setupFn;
1057
+ }
1058
+ function validateExtensionName(extensionName) {
1059
+ if (!extensionName || !/^[a-z][a-z0-9-]*$/i.test(extensionName)) {
1060
+ throw new HaexVaultSdkError(
1061
+ "INVALID_EXTENSION_NAME" /* INVALID_EXTENSION_NAME */,
1062
+ "errors.invalid_extension_name",
1063
+ { extensionName }
1064
+ );
1103
1065
  }
1104
- /**
1105
- * Gibt ein Promise zurück, das aufgelöst wird, sobald der Client vollständig eingerichtet ist.
1106
- * Dies umfasst die Initialisierung UND das Setup (z.B. Tabellenerstellung).
1107
- * Falls kein Setup-Hook registriert wurde, entspricht dies ready().
1108
- */
1109
- async setupComplete() {
1110
- await this.readyPromise;
1111
- if (!this.setupHook || this.setupCompleted) {
1112
- return;
1113
- }
1114
- if (!this.setupPromise) {
1115
- this.setupPromise = this.runSetupAsync();
1116
- }
1117
- return this.setupPromise;
1066
+ if (extensionName.includes(TABLE_SEPARATOR)) {
1067
+ throw new HaexVaultSdkError(
1068
+ "INVALID_EXTENSION_NAME" /* INVALID_EXTENSION_NAME */,
1069
+ "errors.extension_name_contains_separator",
1070
+ { extensionName, separator: TABLE_SEPARATOR }
1071
+ );
1118
1072
  }
1119
- async runSetupAsync() {
1120
- if (!this.setupHook) return;
1121
- try {
1122
- this.log("[HaexSpace] Running setup hook...");
1123
- await this.setupHook();
1124
- this._setupCompleted = true;
1125
- this.log("[HaexSpace] Setup completed successfully");
1126
- this.notifySubscribers();
1127
- } catch (error) {
1128
- this.log("[HaexSpace] Setup failed:", error);
1129
- throw error;
1130
- }
1073
+ }
1074
+ function validateTableName(tableName) {
1075
+ if (!tableName || typeof tableName !== "string") {
1076
+ throw new HaexVaultSdkError(
1077
+ "INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
1078
+ "errors.table_name_empty"
1079
+ );
1131
1080
  }
1132
- /**
1133
- * Initialisiert die Drizzle-Datenbankinstanz.
1134
- * Muss nach der Definition des Schemas aufgerufen werden.
1135
- * @param schema Das Drizzle-Schemaobjekt (mit bereits geprefixten Tabellennamen).
1136
- * @returns Die typsichere Drizzle-Datenbankinstanz.
1137
- */
1138
- initializeDatabase(schema) {
1139
- if (!this._extensionInfo) {
1140
- throw new HaexHubError(
1141
- "EXTENSION_INFO_UNAVAILABLE" /* EXTENSION_INFO_UNAVAILABLE */,
1142
- "errors.client_not_ready"
1143
- );
1144
- }
1145
- const dbInstance = drizzle(
1146
- async (sql, params, method) => {
1147
- try {
1148
- if (method === "run" || method === "all") {
1149
- const result2 = await this.request(
1150
- HAEXTENSION_METHODS.database.execute,
1151
- {
1152
- query: sql,
1153
- params
1154
- }
1155
- );
1156
- if (method === "all") {
1157
- return { rows: result2.rows || [] };
1158
- }
1159
- if (result2.rows && Array.isArray(result2.rows) && result2.rows.length > 0) {
1160
- return { rows: result2.rows };
1161
- }
1162
- return result2;
1163
- }
1164
- const result = await this.request(HAEXTENSION_METHODS.database.query, {
1165
- query: sql,
1166
- params
1167
- });
1168
- const rows = result.rows;
1169
- if (method === "get") {
1170
- return { rows: rows.length > 0 ? rows.at(0) : void 0 };
1171
- }
1172
- return { rows };
1173
- } catch (error) {
1174
- this.log("Database operation failed:", error);
1175
- throw error;
1176
- }
1177
- },
1178
- {
1179
- schema,
1180
- logger: false
1181
- }
1081
+ if (tableName.includes(TABLE_SEPARATOR)) {
1082
+ throw new HaexVaultSdkError(
1083
+ "INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
1084
+ "errors.table_name_contains_separator",
1085
+ { tableName, separator: TABLE_SEPARATOR }
1182
1086
  );
1183
- this.orm = dbInstance;
1184
- return dbInstance;
1185
1087
  }
1186
- get extensionInfo() {
1187
- return this._extensionInfo;
1088
+ if (!/^[a-z][a-z0-9-_]*$/i.test(tableName)) {
1089
+ throw new HaexVaultSdkError(
1090
+ "INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
1091
+ "errors.table_name_format",
1092
+ { tableName }
1093
+ );
1188
1094
  }
1189
- get context() {
1190
- return this._context;
1095
+ }
1096
+ function getExtensionTableName(extensionInfo, tableName) {
1097
+ if (!extensionInfo) {
1098
+ throw new HaexVaultSdkError(
1099
+ "EXTENSION_INFO_UNAVAILABLE" /* EXTENSION_INFO_UNAVAILABLE */,
1100
+ "errors.extension_info_unavailable"
1101
+ );
1191
1102
  }
1192
- subscribe(callback) {
1193
- this.reactiveSubscribers.add(callback);
1194
- return () => {
1195
- this.reactiveSubscribers.delete(callback);
1196
- };
1103
+ validateTableName(tableName);
1104
+ const { publicKey, name } = extensionInfo;
1105
+ return `"${getTableName(publicKey, name, tableName)}"`;
1106
+ }
1107
+ function getDependencyTableName(publicKey, extensionName, tableName) {
1108
+ validatePublicKey(publicKey);
1109
+ validateExtensionName(extensionName);
1110
+ validateTableName(tableName);
1111
+ return `"${getTableName(publicKey, extensionName, tableName)}"`;
1112
+ }
1113
+ function parseTableName(fullTableName) {
1114
+ let cleanTableName = fullTableName;
1115
+ if (cleanTableName.startsWith('"') && cleanTableName.endsWith('"')) {
1116
+ cleanTableName = cleanTableName.slice(1, -1);
1197
1117
  }
1198
- notifySubscribers() {
1199
- this.reactiveSubscribers.forEach((callback) => callback());
1118
+ const parts = cleanTableName.split(TABLE_SEPARATOR);
1119
+ if (parts.length !== 3) {
1120
+ return null;
1200
1121
  }
1201
- async getDependencies() {
1202
- return this.request("extensions.getDependencies");
1122
+ const [publicKey, extensionName, tableName] = parts;
1123
+ if (!publicKey || !extensionName || !tableName) {
1124
+ return null;
1203
1125
  }
1204
- getTableName(tableName) {
1205
- if (!this._extensionInfo) {
1206
- throw new HaexHubError(
1207
- "EXTENSION_INFO_UNAVAILABLE" /* EXTENSION_INFO_UNAVAILABLE */,
1208
- "errors.extension_info_unavailable"
1209
- );
1210
- }
1211
- this.validateTableName(tableName);
1212
- const { publicKey, name } = this._extensionInfo;
1213
- return `"${getTableName(publicKey, name, tableName)}"`;
1126
+ return {
1127
+ publicKey,
1128
+ extensionName,
1129
+ tableName
1130
+ };
1131
+ }
1132
+
1133
+ // src/client/init.ts
1134
+ function isInIframe() {
1135
+ return window.self !== window.top;
1136
+ }
1137
+ function hasTauri() {
1138
+ return typeof window.__TAURI__ !== "undefined";
1139
+ }
1140
+ function getTauriCore() {
1141
+ return window.__TAURI__.core;
1142
+ }
1143
+ function getTauriEvent() {
1144
+ return window.__TAURI__.event;
1145
+ }
1146
+ async function initNativeMode(ctx, log, onEvent, onContextChange) {
1147
+ const { invoke } = getTauriCore();
1148
+ const extensionInfo = await invoke("webview_extension_get_info");
1149
+ const context = await invoke("webview_extension_context_get");
1150
+ ctx.state.isNativeWindow = true;
1151
+ ctx.state.initialized = true;
1152
+ ctx.state.extensionInfo = extensionInfo;
1153
+ ctx.state.context = context;
1154
+ log("HaexVault SDK initialized in native WebViewWindow mode");
1155
+ log("Extension info:", extensionInfo);
1156
+ log("Application context:", context);
1157
+ await setupTauriEventListeners(ctx, log, onEvent, onContextChange);
1158
+ return { extensionInfo, context };
1159
+ }
1160
+ async function setupTauriEventListeners(ctx, log, onEvent, onContextChange) {
1161
+ const { listen } = getTauriEvent();
1162
+ console.log("[HaexVault SDK] Setting up Tauri event listener for:", HAEXTENSION_EVENTS.CONTEXT_CHANGED);
1163
+ try {
1164
+ await listen(HAEXTENSION_EVENTS.CONTEXT_CHANGED, (event) => {
1165
+ console.log("[HaexVault SDK] Received Tauri event:", HAEXTENSION_EVENTS.CONTEXT_CHANGED, event);
1166
+ log("Received context change event:", event);
1167
+ const payload = event.payload;
1168
+ if (payload?.context) {
1169
+ ctx.state.context = payload.context;
1170
+ console.log("[HaexVault SDK] Updated context to:", ctx.state.context);
1171
+ onContextChange(payload.context);
1172
+ onEvent({
1173
+ type: HAEXTENSION_EVENTS.CONTEXT_CHANGED,
1174
+ data: { context: ctx.state.context },
1175
+ timestamp: Date.now()
1176
+ });
1177
+ } else {
1178
+ console.warn("[HaexVault SDK] Event received but no context in payload:", event);
1179
+ }
1180
+ });
1181
+ console.log("[HaexVault SDK] Context change listener registered successfully");
1182
+ } catch (error) {
1183
+ console.error("[HaexVault SDK] Failed to setup context change listener:", error);
1184
+ log("Failed to setup context change listener:", error);
1214
1185
  }
1215
- getDependencyTableName(publicKey, extensionName, tableName) {
1216
- this.validatePublicKey(publicKey);
1217
- this.validateExtensionName(extensionName);
1218
- this.validateTableName(tableName);
1219
- return `"${getTableName(publicKey, extensionName, tableName)}"`;
1186
+ try {
1187
+ await listen(HAEXTENSION_EVENTS.EXTERNAL_REQUEST, (event) => {
1188
+ log("Received external request event:", event);
1189
+ if (event.payload) {
1190
+ onEvent({
1191
+ type: HAEXTENSION_EVENTS.EXTERNAL_REQUEST,
1192
+ data: event.payload,
1193
+ timestamp: Date.now()
1194
+ });
1195
+ }
1196
+ });
1197
+ console.log("[HaexVault SDK] External request listener registered successfully");
1198
+ } catch (error) {
1199
+ console.error("[HaexVault SDK] Failed to setup external request listener:", error);
1200
+ log("Failed to setup external request listener:", error);
1220
1201
  }
1221
- parseTableName(fullTableName) {
1222
- let cleanTableName = fullTableName;
1223
- if (cleanTableName.startsWith('"') && cleanTableName.endsWith('"')) {
1224
- cleanTableName = cleanTableName.slice(1, -1);
1225
- }
1226
- const parts = cleanTableName.split(TABLE_SEPARATOR);
1227
- if (parts.length !== 3) {
1228
- return null;
1229
- }
1230
- const [publicKey, extensionName, tableName] = parts;
1231
- if (!publicKey || !extensionName || !tableName) {
1232
- return null;
1233
- }
1234
- return {
1235
- publicKey,
1236
- extensionName,
1237
- tableName
1202
+ }
1203
+ async function initIframeMode(ctx, log, messageHandler, request) {
1204
+ if (!isInIframe()) {
1205
+ throw new HaexVaultSdkError("NOT_IN_IFRAME" /* NOT_IN_IFRAME */, "errors.not_in_iframe");
1206
+ }
1207
+ ctx.handlers.messageHandler = messageHandler;
1208
+ window.addEventListener("message", messageHandler);
1209
+ ctx.state.isNativeWindow = false;
1210
+ ctx.state.initialized = true;
1211
+ log("HaexVault SDK initialized in iframe mode");
1212
+ if (ctx.config.manifest) {
1213
+ ctx.state.extensionInfo = {
1214
+ publicKey: ctx.config.manifest.publicKey,
1215
+ name: ctx.config.manifest.name,
1216
+ version: ctx.config.manifest.version,
1217
+ displayName: ctx.config.manifest.name
1238
1218
  };
1219
+ log("Extension info loaded from manifest:", ctx.state.extensionInfo);
1239
1220
  }
1240
- /**
1241
- * Execute a raw SQL query (SELECT)
1242
- * Returns rows as an array of objects
1243
- */
1244
- async query(sql, params = []) {
1245
- const result = await this.request(
1246
- HAEXTENSION_METHODS.database.query,
1247
- { query: sql, params }
1248
- );
1249
- if (this.config.debug) {
1250
- console.log("[SDK query()] Raw result:", JSON.stringify(result, null, 2));
1251
- }
1252
- return result.rows;
1253
- }
1254
- /**
1255
- * Alias for query() - more intuitive for SELECT statements
1256
- */
1257
- async select(sql, params = []) {
1258
- return this.query(sql, params);
1259
- }
1260
- /**
1261
- * Execute a raw SQL statement (INSERT, UPDATE, DELETE, CREATE, etc.)
1262
- * Returns rowsAffected and lastInsertId
1263
- */
1264
- async execute(sql, params = []) {
1265
- const result = await this.request(
1266
- HAEXTENSION_METHODS.database.execute,
1267
- { query: sql, params }
1268
- );
1269
- return {
1270
- rowsAffected: result.rowsAffected,
1271
- lastInsertId: result.lastInsertId
1272
- };
1273
- }
1274
- /**
1275
- * Registers and applies extension migrations with HaexVault
1276
- *
1277
- * HaexVault will:
1278
- * 1. Validate all SQL statements (ensure only extension's own tables are accessed)
1279
- * 2. Store migrations with applied_at = NULL
1280
- * 3. Query pending migrations sorted by name
1281
- * 4. Apply pending migrations and set up CRDT triggers
1282
- * 5. Mark successful migrations with applied_at timestamp
1283
- *
1284
- * @param extensionVersion - The version of the extension
1285
- * @param migrations - Array of migration objects with name and SQL content
1286
- * @returns Promise with migration result (applied count, already applied count, applied migration names)
1287
- */
1288
- async registerMigrationsAsync(extensionVersion, migrations) {
1289
- return this.database.registerMigrationsAsync(extensionVersion, migrations);
1290
- }
1291
- async requestDatabasePermission(request) {
1292
- return this.request("permissions.database.request", {
1293
- resource: request.resource,
1294
- operation: request.operation,
1295
- reason: request.reason
1296
- });
1297
- }
1298
- async checkDatabasePermission(resource, operation) {
1299
- const response = await this.request(
1300
- "permissions.database.check",
1301
- {
1302
- resource,
1303
- operation
1304
- }
1305
- );
1306
- return response.status === "granted";
1307
- }
1308
- async respondToSearch(requestId, results) {
1309
- await this.request("search.respond", {
1310
- requestId,
1311
- results
1312
- });
1221
+ sendDebugInfo(ctx.config);
1222
+ const context = await request(HAEXTENSION_METHODS.context.get);
1223
+ ctx.state.context = context;
1224
+ log("Application context received:", context);
1225
+ return { context };
1226
+ }
1227
+ function sendDebugInfo(config) {
1228
+ if (!config.debug) return;
1229
+ if (typeof window === "undefined" || !window.parent) return;
1230
+ const debugInfo = `SDK Debug:
1231
+ window.parent exists: ${!!window.parent}
1232
+ window.parent === window: ${window.parent === window}
1233
+ window.self === window.top: ${window.self === window.top}`;
1234
+ try {
1235
+ window.parent.postMessage({
1236
+ type: HAEXSPACE_MESSAGE_TYPES.DEBUG,
1237
+ data: debugInfo
1238
+ }, "*");
1239
+ } catch (e) {
1240
+ alert(debugInfo + `
1241
+ postMessage error: ${e}`);
1313
1242
  }
1314
- /**
1315
- * Register a handler for external requests (from browser extensions, CLI, servers, etc.)
1316
- *
1317
- * @param action - The action/method name to handle (e.g., "get-logins", "get-totp")
1318
- * @param handler - Function that processes the request and returns a response
1319
- * @returns Unsubscribe function to remove the handler
1320
- *
1321
- * @example
1322
- * ```typescript
1323
- * client.onExternalRequest("get-logins", async (request) => {
1324
- * const entries = await getMatchingEntries(request.payload.url);
1325
- * return {
1326
- * requestId: request.requestId,
1327
- * success: true,
1328
- * data: { entries }
1329
- * };
1330
- * });
1331
- * ```
1332
- */
1333
- onExternalRequest(action, handler) {
1334
- this.externalRequestHandlers.set(action, handler);
1335
- this.log(`[ExternalRequest] Registered handler for action: ${action}`);
1336
- return () => {
1337
- this.externalRequestHandlers.delete(action);
1338
- this.log(`[ExternalRequest] Unregistered handler for action: ${action}`);
1339
- };
1243
+ }
1244
+
1245
+ // src/commands.ts
1246
+ var TAURI_COMMANDS = {
1247
+ database: {
1248
+ query: "webview_extension_db_query",
1249
+ execute: "webview_extension_db_execute",
1250
+ registerMigrations: "webview_extension_db_register_migrations"
1251
+ },
1252
+ permissions: {
1253
+ checkWeb: "webview_extension_check_web_permission",
1254
+ checkDatabase: "webview_extension_check_database_permission",
1255
+ checkFilesystem: "webview_extension_check_filesystem_permission"
1256
+ },
1257
+ web: {
1258
+ open: "webview_extension_web_open",
1259
+ fetch: "webview_extension_web_request"
1260
+ },
1261
+ filesystem: {
1262
+ saveFile: "webview_extension_fs_save_file",
1263
+ openFile: "webview_extension_fs_open_file",
1264
+ showImage: "webview_extension_fs_show_image"
1265
+ },
1266
+ external: {
1267
+ respond: "webview_extension_external_respond"
1268
+ },
1269
+ extension: {
1270
+ getInfo: "webview_extension_get_info",
1271
+ getContext: "webview_extension_context_get"
1272
+ },
1273
+ filesync: {
1274
+ // Spaces
1275
+ listSpaces: "filesync_list_spaces",
1276
+ createSpace: "filesync_create_space",
1277
+ deleteSpace: "filesync_delete_space",
1278
+ // Files
1279
+ listFiles: "filesync_list_files",
1280
+ getFile: "filesync_get_file",
1281
+ uploadFile: "filesync_upload_file",
1282
+ downloadFile: "filesync_download_file",
1283
+ deleteFile: "filesync_delete_file",
1284
+ // Backends
1285
+ listBackends: "filesync_list_backends",
1286
+ addBackend: "filesync_add_backend",
1287
+ removeBackend: "filesync_remove_backend",
1288
+ testBackend: "filesync_test_backend",
1289
+ // Sync Rules
1290
+ listSyncRules: "filesync_list_sync_rules",
1291
+ addSyncRule: "filesync_add_sync_rule",
1292
+ removeSyncRule: "filesync_remove_sync_rule",
1293
+ // Sync Operations
1294
+ getSyncStatus: "filesync_get_sync_status",
1295
+ triggerSync: "filesync_trigger_sync",
1296
+ pauseSync: "filesync_pause_sync",
1297
+ resumeSync: "filesync_resume_sync",
1298
+ // Conflict Resolution
1299
+ resolveConflict: "filesync_resolve_conflict",
1300
+ // UI Helpers
1301
+ selectFolder: "filesync_select_folder"
1340
1302
  }
1341
- /**
1342
- * Send a response to an external request back to haex-vault
1343
- * This is called internally after a handler processes a request
1344
- */
1345
- async respondToExternalRequest(response) {
1346
- await this.request("external.respond", response);
1303
+ };
1304
+
1305
+ // src/transport/handlers/database.ts
1306
+ var databaseHandlers = {
1307
+ [HAEXTENSION_METHODS.database.query]: {
1308
+ command: TAURI_COMMANDS.database.query,
1309
+ args: (p) => ({
1310
+ query: p.query,
1311
+ params: p.params || []
1312
+ })
1313
+ },
1314
+ [HAEXTENSION_METHODS.database.execute]: {
1315
+ command: TAURI_COMMANDS.database.execute,
1316
+ args: (p) => ({
1317
+ query: p.query,
1318
+ params: p.params || []
1319
+ })
1320
+ },
1321
+ [HAEXTENSION_METHODS.database.registerMigrations]: {
1322
+ command: TAURI_COMMANDS.database.registerMigrations,
1323
+ args: (p) => ({
1324
+ extensionVersion: p.extensionVersion,
1325
+ migrations: p.migrations
1326
+ })
1347
1327
  }
1348
- async request(method, params) {
1349
- const resolvedParams = params ?? {};
1350
- if (this.isNativeWindow && typeof window.__TAURI__ !== "undefined") {
1351
- return this.invoke(method, resolvedParams);
1352
- }
1353
- return this.postMessage(method, resolvedParams);
1354
- }
1355
- async postMessage(method, params) {
1356
- const requestId = this.generateRequestId();
1357
- const request = {
1358
- method,
1359
- params,
1360
- timestamp: Date.now()
1361
- };
1362
- return new Promise((resolve, reject) => {
1363
- const timeout = setTimeout(() => {
1364
- this.pendingRequests.delete(requestId);
1365
- reject(
1366
- new HaexHubError("TIMEOUT" /* TIMEOUT */, "errors.timeout", {
1367
- timeout: this.config.timeout
1368
- })
1369
- );
1370
- }, this.config.timeout);
1371
- this.pendingRequests.set(requestId, { resolve, reject, timeout });
1372
- const targetOrigin = "*";
1373
- if (this.config.debug) {
1374
- console.log("[SDK Debug] ========== Sending Request ==========");
1375
- console.log("[SDK Debug] Request ID:", requestId);
1376
- console.log("[SDK Debug] Method:", request.method);
1377
- console.log("[SDK Debug] Params:", request.params);
1378
- console.log("[SDK Debug] Target origin:", targetOrigin);
1379
- console.log("[SDK Debug] Extension info:", this._extensionInfo);
1380
- console.log("[SDK Debug] ========================================");
1381
- }
1382
- window.parent.postMessage({ id: requestId, ...request }, targetOrigin);
1383
- });
1328
+ };
1329
+
1330
+ // src/transport/handlers/permissions.ts
1331
+ var permissionsHandlers = {
1332
+ "permissions.web.check": {
1333
+ command: TAURI_COMMANDS.permissions.checkWeb,
1334
+ args: (p) => ({
1335
+ url: p.url
1336
+ })
1337
+ },
1338
+ "permissions.database.check": {
1339
+ command: TAURI_COMMANDS.permissions.checkDatabase,
1340
+ args: (p) => ({
1341
+ resource: p.resource,
1342
+ operation: p.operation
1343
+ })
1344
+ },
1345
+ "permissions.filesystem.check": {
1346
+ command: TAURI_COMMANDS.permissions.checkFilesystem,
1347
+ args: (p) => ({
1348
+ path: p.path,
1349
+ actionStr: p.action
1350
+ })
1384
1351
  }
1385
- async invoke(method, params) {
1386
- const { invoke } = window.__TAURI__.core;
1387
- if (this.config.debug) {
1388
- console.log("[SDK Debug] ========== Invoke Request ==========");
1389
- console.log("[SDK Debug] Method:", method);
1390
- console.log("[SDK Debug] Params:", params);
1391
- console.log("[SDK Debug] =======================================");
1392
- }
1393
- switch (method) {
1394
- case HAEXTENSION_METHODS.database.query:
1395
- return invoke("webview_extension_db_query", {
1396
- query: params.query,
1397
- params: params.params || []
1398
- });
1399
- case HAEXTENSION_METHODS.database.execute:
1400
- return invoke("webview_extension_db_execute", {
1401
- query: params.query,
1402
- params: params.params || []
1403
- });
1404
- case "permissions.web.check":
1405
- return invoke("webview_extension_check_web_permission", {
1406
- url: params.url
1407
- });
1408
- case "permissions.database.check":
1409
- return invoke("webview_extension_check_database_permission", {
1410
- resource: params.resource,
1411
- operation: params.operation
1412
- });
1413
- case "permissions.filesystem.check":
1414
- return invoke("webview_extension_check_filesystem_permission", {
1415
- path: params.path,
1416
- actionStr: params.action
1417
- });
1418
- case HAEXTENSION_METHODS.application.open:
1419
- return invoke("webview_extension_web_open", {
1420
- url: params.url
1421
- });
1422
- case HAEXTENSION_METHODS.web.fetch:
1423
- return invoke("webview_extension_web_request", {
1424
- url: params.url,
1425
- method: params.method,
1426
- headers: params.headers,
1427
- body: params.body
1428
- });
1429
- case HAEXTENSION_METHODS.filesystem.saveFile:
1430
- return invoke("webview_extension_fs_save_file", {
1431
- data: params.data,
1432
- defaultPath: params.defaultPath,
1433
- title: params.title,
1434
- filters: params.filters
1435
- });
1436
- case HAEXTENSION_METHODS.filesystem.openFile:
1437
- return invoke("webview_extension_fs_open_file", {
1438
- data: params.data,
1439
- fileName: params.fileName
1440
- });
1441
- case HAEXTENSION_METHODS.database.registerMigrations:
1442
- return invoke("webview_extension_db_register_migrations", {
1443
- extensionVersion: params.extensionVersion,
1444
- migrations: params.migrations
1445
- });
1446
- case "external.respond":
1447
- return invoke("webview_extension_external_respond", {
1448
- requestId: params.requestId,
1449
- success: params.success,
1450
- data: params.data,
1451
- error: params.error
1452
- });
1453
- default:
1454
- throw new HaexHubError(
1455
- "METHOD_NOT_FOUND" /* METHOD_NOT_FOUND */,
1456
- "errors.method_not_found",
1457
- { method }
1458
- );
1459
- }
1352
+ };
1353
+
1354
+ // src/transport/handlers/web.ts
1355
+ var webHandlers = {
1356
+ [HAEXTENSION_METHODS.application.open]: {
1357
+ command: TAURI_COMMANDS.web.open,
1358
+ args: (p) => ({
1359
+ url: p.url
1360
+ })
1361
+ },
1362
+ [HAEXTENSION_METHODS.web.fetch]: {
1363
+ command: TAURI_COMMANDS.web.fetch,
1364
+ args: (p) => ({
1365
+ url: p.url,
1366
+ method: p.method,
1367
+ headers: p.headers,
1368
+ body: p.body
1369
+ })
1460
1370
  }
1461
- on(eventType, callback) {
1462
- if (!this.eventListeners.has(eventType)) {
1463
- this.eventListeners.set(eventType, /* @__PURE__ */ new Set());
1464
- }
1465
- this.eventListeners.get(eventType).add(callback);
1371
+ };
1372
+
1373
+ // src/transport/handlers/filesystem.ts
1374
+ var filesystemHandlers = {
1375
+ [HAEXTENSION_METHODS.filesystem.saveFile]: {
1376
+ command: TAURI_COMMANDS.filesystem.saveFile,
1377
+ args: (p) => ({
1378
+ data: p.data,
1379
+ defaultPath: p.defaultPath,
1380
+ title: p.title,
1381
+ filters: p.filters
1382
+ })
1383
+ },
1384
+ [HAEXTENSION_METHODS.filesystem.openFile]: {
1385
+ command: TAURI_COMMANDS.filesystem.openFile,
1386
+ args: (p) => ({
1387
+ data: p.data,
1388
+ fileName: p.fileName
1389
+ })
1390
+ },
1391
+ [HAEXTENSION_METHODS.filesystem.showImage]: {
1392
+ command: TAURI_COMMANDS.filesystem.showImage,
1393
+ args: (p) => ({
1394
+ dataUrl: p.dataUrl
1395
+ })
1466
1396
  }
1467
- off(eventType, callback) {
1468
- const listeners = this.eventListeners.get(eventType);
1469
- if (listeners) {
1470
- listeners.delete(callback);
1471
- }
1397
+ };
1398
+
1399
+ // src/transport/handlers/external.ts
1400
+ var externalHandlers = {
1401
+ "external.respond": {
1402
+ command: TAURI_COMMANDS.external.respond,
1403
+ args: (p) => ({
1404
+ requestId: p.requestId,
1405
+ success: p.success,
1406
+ data: p.data,
1407
+ error: p.error
1408
+ })
1472
1409
  }
1473
- destroy() {
1474
- if (this.messageHandler) {
1475
- window.removeEventListener("message", this.messageHandler);
1476
- }
1477
- this.pendingRequests.forEach(({ timeout }) => clearTimeout(timeout));
1478
- this.pendingRequests.clear();
1479
- this.eventListeners.clear();
1480
- this.initialized = false;
1481
- this.log("HaexHub SDK destroyed");
1410
+ };
1411
+
1412
+ // src/transport/handlers/filesync.ts
1413
+ var filesyncHandlers = {
1414
+ // ==========================================================================
1415
+ // Spaces
1416
+ // ==========================================================================
1417
+ [HAEXTENSION_METHODS.filesystem.sync.listSpaces]: {
1418
+ command: TAURI_COMMANDS.filesync.listSpaces,
1419
+ args: () => ({})
1420
+ },
1421
+ [HAEXTENSION_METHODS.filesystem.sync.createSpace]: {
1422
+ command: TAURI_COMMANDS.filesync.createSpace,
1423
+ args: (p) => ({ request: p })
1424
+ },
1425
+ [HAEXTENSION_METHODS.filesystem.sync.deleteSpace]: {
1426
+ command: TAURI_COMMANDS.filesync.deleteSpace,
1427
+ args: (p) => ({ spaceId: p.spaceId })
1428
+ },
1429
+ // ==========================================================================
1430
+ // Files
1431
+ // ==========================================================================
1432
+ [HAEXTENSION_METHODS.filesystem.sync.listFiles]: {
1433
+ command: TAURI_COMMANDS.filesync.listFiles,
1434
+ args: (p) => ({ request: p })
1435
+ },
1436
+ [HAEXTENSION_METHODS.filesystem.sync.getFile]: {
1437
+ command: TAURI_COMMANDS.filesync.getFile,
1438
+ args: (p) => ({ fileId: p.fileId })
1439
+ },
1440
+ [HAEXTENSION_METHODS.filesystem.sync.uploadFile]: {
1441
+ command: TAURI_COMMANDS.filesync.uploadFile,
1442
+ args: (p) => ({ request: p })
1443
+ },
1444
+ [HAEXTENSION_METHODS.filesystem.sync.downloadFile]: {
1445
+ command: TAURI_COMMANDS.filesync.downloadFile,
1446
+ args: (p) => ({ request: p })
1447
+ },
1448
+ [HAEXTENSION_METHODS.filesystem.sync.deleteFile]: {
1449
+ command: TAURI_COMMANDS.filesync.deleteFile,
1450
+ args: (p) => ({ fileId: p.fileId })
1451
+ },
1452
+ // ==========================================================================
1453
+ // Backends
1454
+ // ==========================================================================
1455
+ [HAEXTENSION_METHODS.filesystem.sync.listBackends]: {
1456
+ command: TAURI_COMMANDS.filesync.listBackends,
1457
+ args: () => ({})
1458
+ },
1459
+ [HAEXTENSION_METHODS.filesystem.sync.addBackend]: {
1460
+ command: TAURI_COMMANDS.filesync.addBackend,
1461
+ args: (p) => ({ request: p })
1462
+ },
1463
+ [HAEXTENSION_METHODS.filesystem.sync.removeBackend]: {
1464
+ command: TAURI_COMMANDS.filesync.removeBackend,
1465
+ args: (p) => ({ backendId: p.backendId })
1466
+ },
1467
+ [HAEXTENSION_METHODS.filesystem.sync.testBackend]: {
1468
+ command: TAURI_COMMANDS.filesync.testBackend,
1469
+ args: (p) => ({ backendId: p.backendId })
1470
+ },
1471
+ // ==========================================================================
1472
+ // Sync Rules
1473
+ // ==========================================================================
1474
+ [HAEXTENSION_METHODS.filesystem.sync.listSyncRules]: {
1475
+ command: TAURI_COMMANDS.filesync.listSyncRules,
1476
+ args: () => ({})
1477
+ },
1478
+ [HAEXTENSION_METHODS.filesystem.sync.addSyncRule]: {
1479
+ command: TAURI_COMMANDS.filesync.addSyncRule,
1480
+ args: (p) => ({ request: p })
1481
+ },
1482
+ [HAEXTENSION_METHODS.filesystem.sync.removeSyncRule]: {
1483
+ command: TAURI_COMMANDS.filesync.removeSyncRule,
1484
+ args: (p) => ({ ruleId: p.ruleId })
1485
+ },
1486
+ // ==========================================================================
1487
+ // Sync Operations
1488
+ // ==========================================================================
1489
+ [HAEXTENSION_METHODS.filesystem.sync.getSyncStatus]: {
1490
+ command: TAURI_COMMANDS.filesync.getSyncStatus,
1491
+ args: () => ({})
1492
+ },
1493
+ [HAEXTENSION_METHODS.filesystem.sync.triggerSync]: {
1494
+ command: TAURI_COMMANDS.filesync.triggerSync,
1495
+ args: () => ({})
1496
+ },
1497
+ [HAEXTENSION_METHODS.filesystem.sync.pauseSync]: {
1498
+ command: TAURI_COMMANDS.filesync.pauseSync,
1499
+ args: () => ({})
1500
+ },
1501
+ [HAEXTENSION_METHODS.filesystem.sync.resumeSync]: {
1502
+ command: TAURI_COMMANDS.filesync.resumeSync,
1503
+ args: () => ({})
1504
+ },
1505
+ // ==========================================================================
1506
+ // Conflict Resolution
1507
+ // ==========================================================================
1508
+ [HAEXTENSION_METHODS.filesystem.sync.resolveConflict]: {
1509
+ command: TAURI_COMMANDS.filesync.resolveConflict,
1510
+ args: (p) => ({ request: p })
1511
+ },
1512
+ // ==========================================================================
1513
+ // UI Helpers
1514
+ // ==========================================================================
1515
+ [HAEXTENSION_METHODS.filesystem.sync.selectFolder]: {
1516
+ command: TAURI_COMMANDS.filesync.selectFolder,
1517
+ args: () => ({})
1482
1518
  }
1483
- async init() {
1484
- if (this.initialized) return;
1485
- const isInIframe = window.self !== window.top;
1486
- if (!isInIframe) {
1487
- try {
1488
- if (typeof window.__TAURI__ !== "undefined") {
1489
- const { invoke } = window.__TAURI__.core;
1490
- this._extensionInfo = await invoke("webview_extension_get_info");
1491
- this._context = await invoke("webview_extension_context_get");
1492
- this.isNativeWindow = true;
1493
- this.initialized = true;
1494
- this.log("HaexHub SDK initialized in native WebViewWindow mode");
1495
- this.log("Extension info:", this._extensionInfo);
1496
- this.log("Application context:", this._context);
1497
- this.notifySubscribers();
1498
- const { listen } = window.__TAURI__.event;
1499
- console.log("[HaexSpace SDK] Setting up Tauri event listener for:", HAEXTENSION_EVENTS.CONTEXT_CHANGED);
1500
- try {
1501
- await listen(HAEXTENSION_EVENTS.CONTEXT_CHANGED, (event) => {
1502
- console.log("[HaexSpace SDK] Received Tauri event:", HAEXTENSION_EVENTS.CONTEXT_CHANGED, event);
1503
- this.log("Received context change event:", event);
1504
- if (event.payload?.context) {
1505
- this._context = event.payload.context;
1506
- console.log("[HaexSpace SDK] Updated context to:", this._context);
1507
- this.handleEvent({
1508
- type: HAEXTENSION_EVENTS.CONTEXT_CHANGED,
1509
- data: { context: this._context },
1510
- timestamp: Date.now()
1511
- });
1512
- } else {
1513
- console.warn("[HaexSpace SDK] Event received but no context in payload:", event);
1514
- }
1515
- });
1516
- console.log("[HaexSpace SDK] Context change listener registered successfully");
1517
- } catch (error) {
1518
- console.error("[HaexSpace SDK] Failed to setup context change listener:", error);
1519
- this.log("Failed to setup context change listener:", error);
1520
- }
1521
- try {
1522
- await listen(HAEXTENSION_EVENTS.EXTERNAL_REQUEST, (event) => {
1523
- this.log("Received external request event:", event);
1524
- if (event.payload) {
1525
- this.handleEvent({
1526
- type: HAEXTENSION_EVENTS.EXTERNAL_REQUEST,
1527
- data: event.payload,
1528
- timestamp: Date.now()
1529
- });
1530
- }
1531
- });
1532
- console.log("[HaexSpace SDK] External request listener registered successfully");
1533
- } catch (error) {
1534
- console.error("[HaexSpace SDK] Failed to setup external request listener:", error);
1535
- this.log("Failed to setup external request listener:", error);
1536
- }
1537
- this.resolveReady();
1538
- return;
1539
- }
1540
- } catch (error) {
1541
- this.log("Tauri commands failed, falling back to iframe mode", error);
1542
- }
1543
- }
1544
- if (window.self === window.top) {
1545
- throw new HaexHubError("NOT_IN_IFRAME" /* NOT_IN_IFRAME */, "errors.not_in_iframe");
1546
- }
1547
- this.messageHandler = this.handleMessage.bind(this);
1548
- window.addEventListener("message", this.messageHandler);
1549
- this.isNativeWindow = false;
1550
- this.initialized = true;
1551
- this.log("HaexSpace SDK initialized in iframe mode");
1552
- try {
1553
- if (this.config.manifest) {
1554
- this._extensionInfo = {
1555
- publicKey: this.config.manifest.publicKey,
1556
- name: this.config.manifest.name,
1557
- version: this.config.manifest.version,
1558
- displayName: this.config.manifest.name
1559
- };
1560
- this.log("Extension info loaded from manifest:", this._extensionInfo);
1561
- this.notifySubscribers();
1562
- }
1563
- if (typeof window !== "undefined" && window.parent) {
1564
- const debugInfo = `SDK Debug:
1565
- window.parent exists: ${!!window.parent}
1566
- window.parent === window: ${window.parent === window}
1567
- window.self === window.top: ${window.self === window.top}`;
1568
- try {
1569
- window.parent.postMessage({
1570
- type: HAEXSPACE_MESSAGE_TYPES.DEBUG,
1571
- data: debugInfo
1572
- }, "*");
1573
- } catch (e) {
1574
- alert(debugInfo + `
1575
- postMessage error: ${e}`);
1576
- }
1577
- }
1578
- this._context = await this.request(HAEXTENSION_METHODS.context.get);
1579
- this.log("Application context received:", this._context);
1580
- this.notifySubscribers();
1581
- this.resolveReady();
1582
- } catch (error) {
1583
- this.log("Failed to load extension info or context:", error);
1584
- throw error;
1519
+ };
1520
+
1521
+ // src/transport/handlers/index.ts
1522
+ var allHandlers = {
1523
+ ...databaseHandlers,
1524
+ ...permissionsHandlers,
1525
+ ...webHandlers,
1526
+ ...filesystemHandlers,
1527
+ ...externalHandlers,
1528
+ ...filesyncHandlers
1529
+ };
1530
+
1531
+ // src/client/transport.ts
1532
+ function generateRequestId(counter) {
1533
+ return `req_${counter}`;
1534
+ }
1535
+ function sendPostMessage(method, params, requestId, config, extensionInfo, pendingRequests) {
1536
+ const request = {
1537
+ method,
1538
+ params,
1539
+ timestamp: Date.now()
1540
+ };
1541
+ return new Promise((resolve, reject) => {
1542
+ const timeout = setTimeout(() => {
1543
+ pendingRequests.delete(requestId);
1544
+ reject(
1545
+ new HaexVaultSdkError("TIMEOUT" /* TIMEOUT */, "errors.timeout", {
1546
+ timeout: config.timeout
1547
+ })
1548
+ );
1549
+ }, config.timeout);
1550
+ pendingRequests.set(requestId, { resolve, reject, timeout });
1551
+ const targetOrigin = "*";
1552
+ if (config.debug) {
1553
+ console.log("[SDK Debug] ========== Sending Request ==========");
1554
+ console.log("[SDK Debug] Request ID:", requestId);
1555
+ console.log("[SDK Debug] Method:", request.method);
1556
+ console.log("[SDK Debug] Params:", request.params);
1557
+ console.log("[SDK Debug] Target origin:", targetOrigin);
1558
+ console.log("[SDK Debug] Extension info:", extensionInfo);
1559
+ console.log("[SDK Debug] ========================================");
1585
1560
  }
1586
- }
1587
- handleMessage(event) {
1588
- if (this.config.debug) {
1561
+ window.parent.postMessage({ id: requestId, ...request }, targetOrigin);
1562
+ });
1563
+ }
1564
+ async function sendInvoke(method, params, config, log) {
1565
+ const { invoke } = window.__TAURI__.core;
1566
+ if (config.debug) {
1567
+ console.log("[SDK Debug] ========== Invoke Request ==========");
1568
+ console.log("[SDK Debug] Method:", method);
1569
+ console.log("[SDK Debug] Params:", params);
1570
+ console.log("[SDK Debug] =======================================");
1571
+ }
1572
+ const handler = allHandlers[method];
1573
+ if (handler) {
1574
+ const args = handler.args(params);
1575
+ return invoke(handler.command, args);
1576
+ }
1577
+ throw new HaexVaultSdkError(
1578
+ "METHOD_NOT_FOUND" /* METHOD_NOT_FOUND */,
1579
+ "errors.method_not_found",
1580
+ { method }
1581
+ );
1582
+ }
1583
+
1584
+ // src/client/events.ts
1585
+ function createMessageHandler(config, pendingRequests, extensionInfo, onEvent) {
1586
+ return (event) => {
1587
+ if (config.debug) {
1589
1588
  console.log("[SDK Debug] ========== Message Received ==========");
1590
1589
  console.log("[SDK Debug] Event origin:", event.origin);
1591
1590
  console.log(
@@ -1593,160 +1592,534 @@ postMessage error: ${e}`);
1593
1592
  event.source === window.parent ? "parent window" : "unknown"
1594
1593
  );
1595
1594
  console.log("[SDK Debug] Event data:", event.data);
1596
- console.log("[SDK Debug] Extension info loaded:", !!this._extensionInfo);
1595
+ console.log("[SDK Debug] Extension info loaded:", !!extensionInfo());
1597
1596
  console.log(
1598
1597
  "[SDK Debug] Pending requests count:",
1599
- this.pendingRequests.size
1598
+ pendingRequests.size
1600
1599
  );
1601
1600
  }
1602
1601
  if (event.source !== window.parent) {
1603
- if (this.config.debug) {
1602
+ if (config.debug) {
1604
1603
  console.error("[SDK Debug] \u274C REJECTED: Message not from parent window!");
1605
1604
  }
1606
1605
  return;
1607
1606
  }
1608
1607
  const data = event.data;
1609
- if ("id" in data && this.pendingRequests.has(data.id)) {
1610
- if (this.config.debug) {
1608
+ if ("id" in data && pendingRequests.has(data.id)) {
1609
+ if (config.debug) {
1611
1610
  console.log("[SDK Debug] \u2705 Found pending request for ID:", data.id);
1612
1611
  }
1613
- const pending = this.pendingRequests.get(data.id);
1612
+ const pending = pendingRequests.get(data.id);
1614
1613
  clearTimeout(pending.timeout);
1615
- this.pendingRequests.delete(data.id);
1614
+ pendingRequests.delete(data.id);
1616
1615
  if (data.error) {
1617
- if (this.config.debug) {
1616
+ if (config.debug) {
1618
1617
  console.error("[SDK Debug] \u274C Request failed:", data.error);
1619
1618
  }
1620
1619
  pending.reject(data.error);
1621
1620
  } else {
1622
- if (this.config.debug) {
1621
+ if (config.debug) {
1623
1622
  console.log("[SDK Debug] \u2705 Request succeeded:", data.result);
1624
1623
  }
1625
1624
  pending.resolve(data.result);
1626
1625
  }
1627
1626
  return;
1628
1627
  }
1629
- if ("id" in data && !this.pendingRequests.has(data.id)) {
1630
- if (this.config.debug) {
1628
+ if ("id" in data && !pendingRequests.has(data.id)) {
1629
+ if (config.debug) {
1631
1630
  console.warn(
1632
1631
  "[SDK Debug] \u26A0\uFE0F Received response for unknown request ID:",
1633
1632
  data.id
1634
1633
  );
1635
1634
  console.warn(
1636
1635
  "[SDK Debug] Known IDs:",
1637
- Array.from(this.pendingRequests.keys())
1636
+ Array.from(pendingRequests.keys())
1638
1637
  );
1639
1638
  }
1640
1639
  }
1641
1640
  if ("type" in data && data.type) {
1642
- if (this.config.debug) {
1641
+ if (config.debug) {
1643
1642
  console.log("[SDK Debug] Event received:", data.type);
1644
1643
  }
1645
- this.handleEvent(data);
1644
+ onEvent(data);
1646
1645
  }
1647
- if (this.config.debug) {
1646
+ if (config.debug) {
1648
1647
  console.log("[SDK Debug] ========== End Message ==========");
1649
1648
  }
1649
+ };
1650
+ }
1651
+ function processEvent(event, log, eventListeners, onContextChanged, onExternalRequest) {
1652
+ if (event.type === HAEXTENSION_EVENTS.CONTEXT_CHANGED) {
1653
+ const contextEvent = event;
1654
+ onContextChanged(contextEvent.data.context);
1655
+ log("Context updated:", contextEvent.data.context);
1656
+ }
1657
+ if (event.type === HAEXTENSION_EVENTS.EXTERNAL_REQUEST) {
1658
+ const externalEvent = event;
1659
+ onExternalRequest(externalEvent);
1660
+ return;
1650
1661
  }
1651
- handleEvent(event) {
1652
- if (event.type === HAEXTENSION_EVENTS.CONTEXT_CHANGED) {
1653
- const contextEvent = event;
1654
- this._context = contextEvent.data.context;
1655
- this.log("Context updated:", this._context);
1656
- this.notifySubscribers();
1662
+ emitEvent(event, log, eventListeners);
1663
+ }
1664
+ function emitEvent(event, log, eventListeners) {
1665
+ log("Event received:", event);
1666
+ const listeners = eventListeners.get(event.type);
1667
+ if (listeners) {
1668
+ listeners.forEach((callback) => callback(event));
1669
+ }
1670
+ }
1671
+ function addEventListener(eventType, callback, eventListeners) {
1672
+ if (!eventListeners.has(eventType)) {
1673
+ eventListeners.set(eventType, /* @__PURE__ */ new Set());
1674
+ }
1675
+ eventListeners.get(eventType).add(callback);
1676
+ }
1677
+ function removeEventListener(eventType, callback, eventListeners) {
1678
+ const listeners = eventListeners.get(eventType);
1679
+ if (listeners) {
1680
+ listeners.delete(callback);
1681
+ }
1682
+ }
1683
+ function notifySubscribers(subscribers) {
1684
+ subscribers.forEach((callback) => callback());
1685
+ }
1686
+ function createDrizzleInstance(schema, extensionInfo, request, log) {
1687
+ if (!extensionInfo) {
1688
+ throw new HaexVaultSdkError(
1689
+ "EXTENSION_INFO_UNAVAILABLE" /* EXTENSION_INFO_UNAVAILABLE */,
1690
+ "errors.client_not_ready"
1691
+ );
1692
+ }
1693
+ return drizzle(
1694
+ async (sql, params, method) => {
1695
+ try {
1696
+ if (method === "run" || method === "all") {
1697
+ const result2 = await request(
1698
+ HAEXTENSION_METHODS.database.execute,
1699
+ {
1700
+ query: sql,
1701
+ params
1702
+ }
1703
+ );
1704
+ if (method === "all") {
1705
+ return { rows: result2.rows || [] };
1706
+ }
1707
+ if (result2.rows && Array.isArray(result2.rows) && result2.rows.length > 0) {
1708
+ return { rows: result2.rows };
1709
+ }
1710
+ return result2;
1711
+ }
1712
+ const result = await request(HAEXTENSION_METHODS.database.query, {
1713
+ query: sql,
1714
+ params
1715
+ });
1716
+ const rows = result.rows;
1717
+ if (method === "get") {
1718
+ return { rows: rows.length > 0 ? rows.at(0) : void 0 };
1719
+ }
1720
+ return { rows };
1721
+ } catch (error) {
1722
+ log("Database operation failed:", error);
1723
+ throw error;
1724
+ }
1725
+ },
1726
+ {
1727
+ schema,
1728
+ logger: false
1657
1729
  }
1658
- if (event.type === HAEXTENSION_EVENTS.EXTERNAL_REQUEST) {
1659
- const externalEvent = event;
1660
- this.handleExternalRequest(externalEvent.data);
1661
- return;
1730
+ );
1731
+ }
1732
+ async function queryRaw(sql, params, request, debug) {
1733
+ const result = await request(
1734
+ HAEXTENSION_METHODS.database.query,
1735
+ { query: sql, params }
1736
+ );
1737
+ if (debug) {
1738
+ console.log("[SDK query()] Raw result:", JSON.stringify(result, null, 2));
1739
+ }
1740
+ return result.rows;
1741
+ }
1742
+ async function executeRaw(sql, params, request) {
1743
+ const result = await request(
1744
+ HAEXTENSION_METHODS.database.execute,
1745
+ { query: sql, params }
1746
+ );
1747
+ return {
1748
+ rowsAffected: result.rowsAffected,
1749
+ lastInsertId: result.lastInsertId
1750
+ };
1751
+ }
1752
+
1753
+ // src/client/external.ts
1754
+ function registerExternalHandler(action, handler, handlers, log) {
1755
+ handlers.set(action, handler);
1756
+ log(`[ExternalRequest] Registered handler for action: ${action}`);
1757
+ return () => {
1758
+ handlers.delete(action);
1759
+ log(`[ExternalRequest] Unregistered handler for action: ${action}`);
1760
+ };
1761
+ }
1762
+ async function handleExternalRequest(request, handlers, respond, log) {
1763
+ log(`[ExternalRequest] Received request: ${request.action} from ${request.publicKey.substring(0, 20)}...`);
1764
+ const handler = handlers.get(request.action);
1765
+ if (!handler) {
1766
+ log(`[ExternalRequest] No handler for action: ${request.action}`);
1767
+ await respond({
1768
+ requestId: request.requestId,
1769
+ success: false,
1770
+ error: `No handler registered for action: ${request.action}`
1771
+ });
1772
+ return;
1773
+ }
1774
+ try {
1775
+ const response = await handler(request);
1776
+ await respond(response);
1777
+ log(`[ExternalRequest] Response sent for: ${request.action}`);
1778
+ } catch (error) {
1779
+ log(`[ExternalRequest] Handler error:`, error);
1780
+ await respond({
1781
+ requestId: request.requestId,
1782
+ success: false,
1783
+ error: error instanceof Error ? error.message : String(error)
1784
+ });
1785
+ }
1786
+ }
1787
+ async function respondToExternalRequest(response, request) {
1788
+ await request("external.respond", response);
1789
+ }
1790
+
1791
+ // src/client.ts
1792
+ var HaexVaultClient = class {
1793
+ constructor(config = {}) {
1794
+ // State
1795
+ this.initialized = false;
1796
+ this.isNativeWindow = false;
1797
+ this.requestCounter = 0;
1798
+ this._extensionInfo = null;
1799
+ this._context = null;
1800
+ this._setupCompleted = false;
1801
+ // Collections
1802
+ this.pendingRequests = /* @__PURE__ */ new Map();
1803
+ this.eventListeners = /* @__PURE__ */ new Map();
1804
+ this.externalRequestHandlers = /* @__PURE__ */ new Map();
1805
+ this.reactiveSubscribers = /* @__PURE__ */ new Set();
1806
+ // Handlers
1807
+ this.messageHandler = null;
1808
+ this.setupPromise = null;
1809
+ this.setupHook = null;
1810
+ // Public APIs
1811
+ this.orm = null;
1812
+ this.config = {
1813
+ debug: config.debug ?? false,
1814
+ timeout: config.timeout ?? DEFAULT_TIMEOUT,
1815
+ manifest: config.manifest
1816
+ };
1817
+ this.storage = new StorageAPI(this);
1818
+ this.database = new DatabaseAPI(this);
1819
+ this.filesystem = new FilesystemAPI(this);
1820
+ this.web = new WebAPI(this);
1821
+ this.permissions = new PermissionsAPI(this);
1822
+ installConsoleForwarding(this.config.debug);
1823
+ this.readyPromise = new Promise((resolve) => {
1824
+ this.resolveReady = resolve;
1825
+ });
1826
+ this.init();
1827
+ }
1828
+ // ==========================================================================
1829
+ // Lifecycle
1830
+ // ==========================================================================
1831
+ async ready() {
1832
+ return this.readyPromise;
1833
+ }
1834
+ get setupCompleted() {
1835
+ return this._setupCompleted;
1836
+ }
1837
+ onSetup(setupFn) {
1838
+ if (this.setupHook) {
1839
+ throw new Error("Setup hook already registered");
1662
1840
  }
1663
- this.emitEvent(event);
1664
- }
1665
- async handleExternalRequest(request) {
1666
- this.log(`[ExternalRequest] Received request: ${request.action} from ${request.publicKey.substring(0, 20)}...`);
1667
- const handler = this.externalRequestHandlers.get(request.action);
1668
- if (!handler) {
1669
- this.log(`[ExternalRequest] No handler for action: ${request.action}`);
1670
- await this.respondToExternalRequest({
1671
- requestId: request.requestId,
1672
- success: false,
1673
- error: `No handler registered for action: ${request.action}`
1674
- });
1841
+ this.setupHook = setupFn;
1842
+ }
1843
+ async setupComplete() {
1844
+ await this.readyPromise;
1845
+ if (!this.setupHook || this.setupCompleted) {
1675
1846
  return;
1676
1847
  }
1677
- try {
1678
- const response = await handler(request);
1679
- await this.respondToExternalRequest(response);
1680
- this.log(`[ExternalRequest] Response sent for: ${request.action}`);
1681
- } catch (error) {
1682
- this.log(`[ExternalRequest] Handler error:`, error);
1683
- await this.respondToExternalRequest({
1684
- requestId: request.requestId,
1685
- success: false,
1686
- error: error instanceof Error ? error.message : String(error)
1687
- });
1848
+ if (!this.setupPromise) {
1849
+ this.setupPromise = this.runSetupAsync();
1688
1850
  }
1851
+ return this.setupPromise;
1689
1852
  }
1690
- emitEvent(event) {
1691
- this.log("Event received:", event);
1692
- const listeners = this.eventListeners.get(event.type);
1693
- if (listeners) {
1694
- listeners.forEach((callback) => callback(event));
1853
+ destroy() {
1854
+ if (this.messageHandler) {
1855
+ window.removeEventListener("message", this.messageHandler);
1695
1856
  }
1857
+ this.pendingRequests.forEach(({ timeout }) => clearTimeout(timeout));
1858
+ this.pendingRequests.clear();
1859
+ this.eventListeners.clear();
1860
+ this.initialized = false;
1861
+ this.log("HaexVault SDK destroyed");
1696
1862
  }
1697
- generateRequestId() {
1698
- return `req_${++this.requestCounter}`;
1863
+ // ==========================================================================
1864
+ // Properties
1865
+ // ==========================================================================
1866
+ get extensionInfo() {
1867
+ return this._extensionInfo;
1699
1868
  }
1700
- validatePublicKey(publicKey) {
1701
- if (!publicKey || typeof publicKey !== "string" || publicKey.trim() === "") {
1702
- throw new HaexHubError(
1703
- "INVALID_PUBLIC_KEY" /* INVALID_PUBLIC_KEY */,
1704
- "errors.invalid_public_key",
1705
- { publicKey }
1706
- );
1707
- }
1869
+ get context() {
1870
+ return this._context;
1708
1871
  }
1709
- validateExtensionName(extensionName) {
1710
- if (!extensionName || !/^[a-z][a-z0-9-]*$/i.test(extensionName)) {
1711
- throw new HaexHubError(
1712
- "INVALID_EXTENSION_NAME" /* INVALID_EXTENSION_NAME */,
1713
- "errors.invalid_extension_name",
1714
- { extensionName }
1715
- );
1716
- }
1717
- if (extensionName.includes(TABLE_SEPARATOR)) {
1718
- throw new HaexHubError(
1719
- "INVALID_EXTENSION_NAME" /* INVALID_EXTENSION_NAME */,
1720
- "errors.extension_name_contains_separator",
1721
- { extensionName, separator: TABLE_SEPARATOR }
1722
- );
1872
+ // ==========================================================================
1873
+ // Subscriptions
1874
+ // ==========================================================================
1875
+ subscribe(callback) {
1876
+ this.reactiveSubscribers.add(callback);
1877
+ return () => {
1878
+ this.reactiveSubscribers.delete(callback);
1879
+ };
1880
+ }
1881
+ // ==========================================================================
1882
+ // Table Name Utilities
1883
+ // ==========================================================================
1884
+ getTableName(tableName) {
1885
+ return getExtensionTableName(this._extensionInfo, tableName);
1886
+ }
1887
+ getDependencyTableName(publicKey, extensionName, tableName) {
1888
+ return getDependencyTableName(publicKey, extensionName, tableName);
1889
+ }
1890
+ parseTableName(fullTableName) {
1891
+ return parseTableName(fullTableName);
1892
+ }
1893
+ // ==========================================================================
1894
+ // Database
1895
+ // ==========================================================================
1896
+ initializeDatabase(schema) {
1897
+ const db = createDrizzleInstance(schema, this._extensionInfo, this.request.bind(this), this.log.bind(this));
1898
+ this.orm = db;
1899
+ return db;
1900
+ }
1901
+ async query(sql, params = []) {
1902
+ return queryRaw(sql, params, this.request.bind(this), this.config.debug);
1903
+ }
1904
+ async select(sql, params = []) {
1905
+ return this.query(sql, params);
1906
+ }
1907
+ async execute(sql, params = []) {
1908
+ return executeRaw(sql, params, this.request.bind(this));
1909
+ }
1910
+ async registerMigrationsAsync(extensionVersion, migrations) {
1911
+ return this.database.registerMigrationsAsync(extensionVersion, migrations);
1912
+ }
1913
+ // ==========================================================================
1914
+ // Dependencies
1915
+ // ==========================================================================
1916
+ async getDependencies() {
1917
+ return this.request("extensions.getDependencies");
1918
+ }
1919
+ // ==========================================================================
1920
+ // Permissions
1921
+ // ==========================================================================
1922
+ async requestDatabasePermission(request) {
1923
+ return this.request("permissions.database.request", {
1924
+ resource: request.resource,
1925
+ operation: request.operation,
1926
+ reason: request.reason
1927
+ });
1928
+ }
1929
+ async checkDatabasePermission(resource, operation) {
1930
+ const response = await this.request("permissions.database.check", { resource, operation });
1931
+ return response.status === "granted";
1932
+ }
1933
+ // ==========================================================================
1934
+ // Search
1935
+ // ==========================================================================
1936
+ async respondToSearch(requestId, results) {
1937
+ await this.request("search.respond", { requestId, results });
1938
+ }
1939
+ // ==========================================================================
1940
+ // External Requests
1941
+ // ==========================================================================
1942
+ onExternalRequest(action, handler) {
1943
+ return registerExternalHandler(action, handler, this.externalRequestHandlers, this.log.bind(this));
1944
+ }
1945
+ async respondToExternalRequest(response) {
1946
+ await respondToExternalRequest(response, this.request.bind(this));
1947
+ }
1948
+ // ==========================================================================
1949
+ // Events
1950
+ // ==========================================================================
1951
+ on(eventType, callback) {
1952
+ addEventListener(eventType, callback, this.eventListeners);
1953
+ }
1954
+ off(eventType, callback) {
1955
+ removeEventListener(eventType, callback, this.eventListeners);
1956
+ }
1957
+ // ==========================================================================
1958
+ // Communication
1959
+ // ==========================================================================
1960
+ async request(method, params) {
1961
+ const resolvedParams = params ?? {};
1962
+ if (this.isNativeWindow && hasTauri()) {
1963
+ return sendInvoke(method, resolvedParams, this.config, this.log.bind(this));
1723
1964
  }
1965
+ const requestId = generateRequestId(++this.requestCounter);
1966
+ return sendPostMessage(method, resolvedParams, requestId, this.config, this._extensionInfo, this.pendingRequests);
1724
1967
  }
1725
- validateTableName(tableName) {
1726
- if (!tableName || typeof tableName !== "string") {
1727
- throw new HaexHubError(
1728
- "INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
1729
- "errors.table_name_empty"
1730
- );
1968
+ // ==========================================================================
1969
+ // Private: Initialization
1970
+ // ==========================================================================
1971
+ async init() {
1972
+ if (this.initialized) return;
1973
+ if (!isInIframe() && hasTauri()) {
1974
+ try {
1975
+ await this.initNative();
1976
+ return;
1977
+ } catch (error) {
1978
+ this.log("Tauri commands failed, falling back to iframe mode", error);
1979
+ }
1731
1980
  }
1732
- if (tableName.includes(TABLE_SEPARATOR)) {
1733
- throw new HaexHubError(
1734
- "INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
1735
- "errors.table_name_contains_separator",
1736
- { tableName, separator: TABLE_SEPARATOR }
1737
- );
1981
+ await this.initIframe();
1982
+ }
1983
+ async initNative() {
1984
+ const { extensionInfo, context } = await initNativeMode(
1985
+ {
1986
+ config: this.config,
1987
+ state: {
1988
+ initialized: this.initialized,
1989
+ isNativeWindow: this.isNativeWindow,
1990
+ requestCounter: this.requestCounter,
1991
+ setupCompleted: this._setupCompleted,
1992
+ extensionInfo: this._extensionInfo,
1993
+ context: this._context,
1994
+ orm: this.orm
1995
+ },
1996
+ collections: {
1997
+ pendingRequests: this.pendingRequests,
1998
+ eventListeners: this.eventListeners,
1999
+ externalRequestHandlers: this.externalRequestHandlers,
2000
+ reactiveSubscribers: this.reactiveSubscribers
2001
+ },
2002
+ promises: {
2003
+ readyPromise: this.readyPromise,
2004
+ resolveReady: this.resolveReady,
2005
+ setupPromise: this.setupPromise,
2006
+ setupHook: this.setupHook
2007
+ },
2008
+ handlers: {
2009
+ messageHandler: this.messageHandler
2010
+ }
2011
+ },
2012
+ this.log.bind(this),
2013
+ this.handleEvent.bind(this),
2014
+ (ctx) => {
2015
+ this._context = ctx;
2016
+ this.notifySubscribersInternal();
2017
+ }
2018
+ );
2019
+ this._extensionInfo = extensionInfo;
2020
+ this._context = context;
2021
+ this.isNativeWindow = true;
2022
+ this.initialized = true;
2023
+ this.notifySubscribersInternal();
2024
+ this.resolveReady();
2025
+ }
2026
+ async initIframe() {
2027
+ this.messageHandler = createMessageHandler(
2028
+ this.config,
2029
+ this.pendingRequests,
2030
+ () => this._extensionInfo,
2031
+ this.handleEvent.bind(this)
2032
+ );
2033
+ const { context } = await initIframeMode(
2034
+ {
2035
+ config: this.config,
2036
+ state: {
2037
+ initialized: this.initialized,
2038
+ isNativeWindow: this.isNativeWindow,
2039
+ requestCounter: this.requestCounter,
2040
+ setupCompleted: this._setupCompleted,
2041
+ extensionInfo: this._extensionInfo,
2042
+ context: this._context,
2043
+ orm: this.orm
2044
+ },
2045
+ collections: {
2046
+ pendingRequests: this.pendingRequests,
2047
+ eventListeners: this.eventListeners,
2048
+ externalRequestHandlers: this.externalRequestHandlers,
2049
+ reactiveSubscribers: this.reactiveSubscribers
2050
+ },
2051
+ promises: {
2052
+ readyPromise: this.readyPromise,
2053
+ resolveReady: this.resolveReady,
2054
+ setupPromise: this.setupPromise,
2055
+ setupHook: this.setupHook
2056
+ },
2057
+ handlers: {
2058
+ messageHandler: this.messageHandler
2059
+ }
2060
+ },
2061
+ this.log.bind(this),
2062
+ this.messageHandler,
2063
+ this.request.bind(this)
2064
+ );
2065
+ if (this.config.manifest) {
2066
+ this._extensionInfo = {
2067
+ publicKey: this.config.manifest.publicKey,
2068
+ name: this.config.manifest.name,
2069
+ version: this.config.manifest.version,
2070
+ displayName: this.config.manifest.name
2071
+ };
2072
+ this.notifySubscribersInternal();
1738
2073
  }
1739
- if (!/^[a-z][a-z0-9-_]*$/i.test(tableName)) {
1740
- throw new HaexHubError(
1741
- "INVALID_TABLE_NAME" /* INVALID_TABLE_NAME */,
1742
- "errors.table_name_format",
1743
- { tableName }
1744
- );
2074
+ this._context = context;
2075
+ this.isNativeWindow = false;
2076
+ this.initialized = true;
2077
+ this.notifySubscribersInternal();
2078
+ this.resolveReady();
2079
+ }
2080
+ // ==========================================================================
2081
+ // Private: Event Handling
2082
+ // ==========================================================================
2083
+ handleEvent(event) {
2084
+ processEvent(
2085
+ event,
2086
+ this.log.bind(this),
2087
+ this.eventListeners,
2088
+ (ctx) => {
2089
+ this._context = ctx;
2090
+ this.notifySubscribersInternal();
2091
+ },
2092
+ (extEvent) => this.handleExternalRequestInternal(extEvent.data)
2093
+ );
2094
+ }
2095
+ async handleExternalRequestInternal(request) {
2096
+ await handleExternalRequest(request, this.externalRequestHandlers, this.respondToExternalRequest.bind(this), this.log.bind(this));
2097
+ }
2098
+ // ==========================================================================
2099
+ // Private: Setup
2100
+ // ==========================================================================
2101
+ async runSetupAsync() {
2102
+ if (!this.setupHook) return;
2103
+ try {
2104
+ this.log("[HaexVault] Running setup hook...");
2105
+ await this.setupHook();
2106
+ this._setupCompleted = true;
2107
+ this.log("[HaexVault] Setup completed successfully");
2108
+ this.notifySubscribersInternal();
2109
+ } catch (error) {
2110
+ this.log("[HaexVault] Setup failed:", error);
2111
+ throw error;
1745
2112
  }
1746
2113
  }
2114
+ // ==========================================================================
2115
+ // Private: Utilities
2116
+ // ==========================================================================
2117
+ notifySubscribersInternal() {
2118
+ notifySubscribers(this.reactiveSubscribers);
2119
+ }
1747
2120
  log(...args) {
1748
2121
  if (this.config.debug) {
1749
- console.log("[HaexSpace SDK]", ...args);
2122
+ console.log("[HaexVault SDK]", ...args);
1750
2123
  }
1751
2124
  }
1752
2125
  };
@@ -1978,6 +2351,42 @@ async function encryptCrdtData(data, vaultKey) {
1978
2351
  nonce: arrayBufferToBase64(nonce)
1979
2352
  };
1980
2353
  }
2354
+ async function wrapKey(keyToWrap, wrappingKey) {
2355
+ const cryptoKey = await crypto.subtle.importKey(
2356
+ "raw",
2357
+ new Uint8Array(wrappingKey),
2358
+ { name: ALGORITHM },
2359
+ false,
2360
+ ["encrypt"]
2361
+ );
2362
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
2363
+ const ciphertext = await crypto.subtle.encrypt(
2364
+ { name: ALGORITHM, iv: nonce },
2365
+ cryptoKey,
2366
+ new Uint8Array(keyToWrap)
2367
+ );
2368
+ const result = new Uint8Array(12 + ciphertext.byteLength);
2369
+ result.set(nonce, 0);
2370
+ result.set(new Uint8Array(ciphertext), 12);
2371
+ return result;
2372
+ }
2373
+ async function unwrapKey(wrappedKey, wrappingKey) {
2374
+ const cryptoKey = await crypto.subtle.importKey(
2375
+ "raw",
2376
+ new Uint8Array(wrappingKey),
2377
+ { name: ALGORITHM },
2378
+ false,
2379
+ ["decrypt"]
2380
+ );
2381
+ const nonce = wrappedKey.slice(0, 12);
2382
+ const ciphertext = wrappedKey.slice(12);
2383
+ const plaintext = await crypto.subtle.decrypt(
2384
+ { name: ALGORITHM, iv: nonce },
2385
+ cryptoKey,
2386
+ ciphertext
2387
+ );
2388
+ return new Uint8Array(plaintext);
2389
+ }
1981
2390
  async function decryptCrdtData(encryptedData, nonce, vaultKey) {
1982
2391
  const vaultKeyBuffer = new Uint8Array(vaultKey);
1983
2392
  const cryptoKey = await crypto.subtle.importKey(
@@ -2034,6 +2443,6 @@ function createHaexVaultClient(config = {}) {
2034
2443
  return new HaexVaultClient(config);
2035
2444
  }
2036
2445
 
2037
- export { DEFAULT_TIMEOUT, DatabaseAPI, ErrorCode, FileSyncAPI, FilesystemAPI, HAEXSPACE_MESSAGE_TYPES, HAEXTENSION_EVENTS, HAEXTENSION_METHODS, HaexHubError, HaexVaultClient, PermissionStatus, PermissionsAPI, TABLE_SEPARATOR, WebAPI, arrayBufferToBase64, base64ToArrayBuffer, createHaexVaultClient, decryptCrdtData, decryptString, decryptVaultKey, decryptVaultName, deriveKeyFromPassword, encryptCrdtData, encryptString, encryptVaultKey, generateVaultKey, getTableName, hexToBytes, installBaseTag, installCookiePolyfill, installHistoryPolyfill, installLocalStoragePolyfill, installPolyfills, installSessionStoragePolyfill, sortObjectKeysRecursively, verifyExtensionSignature };
2446
+ export { DEFAULT_TIMEOUT, DatabaseAPI, ErrorCode, FileSyncAPI, FilesystemAPI, HAEXSPACE_MESSAGE_TYPES, HAEXTENSION_EVENTS, HAEXTENSION_METHODS, HaexVaultClient, HaexVaultSdkError, PermissionStatus, PermissionsAPI, TABLE_SEPARATOR, TAURI_COMMANDS, WebAPI, arrayBufferToBase64, base64ToArrayBuffer, createHaexVaultClient, decryptCrdtData, decryptString, decryptVaultKey, decryptVaultName, deriveKeyFromPassword, encryptCrdtData, encryptString, encryptVaultKey, generateVaultKey, getTableName, hexToBytes, installBaseTag, installCookiePolyfill, installHistoryPolyfill, installLocalStoragePolyfill, installPolyfills, installSessionStoragePolyfill, sortObjectKeysRecursively, unwrapKey, verifyExtensionSignature, wrapKey };
2038
2447
  //# sourceMappingURL=index.mjs.map
2039
2448
  //# sourceMappingURL=index.mjs.map