@haex-space/vault-sdk 2.3.16 → 2.5.0

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