holosphere 2.0.0-alpha18 → 2.0.0-alpha19
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/{2019-C9IgM3mu.cjs → 2019-CAYA1q1p.cjs} +2 -2
- package/dist/{2019-C9IgM3mu.cjs.map → 2019-CAYA1q1p.cjs.map} +1 -1
- package/dist/{2019-CyFQLuqg.js → 2019-Cc18leNN.js} +2 -2
- package/dist/{2019-CyFQLuqg.js.map → 2019-Cc18leNN.js.map} +1 -1
- package/dist/{browser-CZ1l8nhY.cjs → browser-DAFvFs8I.cjs} +2 -2
- package/dist/{browser-CZ1l8nhY.cjs.map → browser-DAFvFs8I.cjs.map} +1 -1
- package/dist/{browser-BIvmkBi9.js → browser-yWnjyL8K.js} +2 -2
- package/dist/{browser-BIvmkBi9.js.map → browser-yWnjyL8K.js.map} +1 -1
- package/dist/cjs/holosphere.cjs +1 -1
- package/dist/esm/holosphere.js +1 -1
- package/dist/{index-HW9kbrzC.js → index-Bgi_csBR.js} +2 -2
- package/dist/{index-HW9kbrzC.js.map → index-Bgi_csBR.js.map} +1 -1
- package/dist/{index-B7ERi4ng.js → index-CHfVBEUH.js} +132 -101
- package/dist/index-CHfVBEUH.js.map +1 -0
- package/dist/{index-Cc-_uNpt.cjs → index-CPvYlZtl.cjs} +2 -2
- package/dist/{index-Cc-_uNpt.cjs.map → index-CPvYlZtl.cjs.map} +1 -1
- package/dist/{index-DusXavIT.js → index-CReYsOty.js} +2 -2
- package/dist/{index-DusXavIT.js.map → index-CReYsOty.js.map} +1 -1
- package/dist/index-Dgx5DQG_.cjs +29 -0
- package/dist/index-Dgx5DQG_.cjs.map +1 -0
- package/dist/{index-VrRkpshF.cjs → index-bnw0PiyT.cjs} +2 -2
- package/dist/{index-VrRkpshF.cjs.map → index-bnw0PiyT.cjs.map} +1 -1
- package/dist/{indexeddb-storage-CVz4Q3lo.cjs → indexeddb-storage-CyOZAiHV.cjs} +2 -2
- package/dist/{indexeddb-storage-CVz4Q3lo.cjs.map → indexeddb-storage-CyOZAiHV.cjs.map} +1 -1
- package/dist/{indexeddb-storage-yEswGGMG.js → indexeddb-storage-Ko4sjZtM.js} +2 -2
- package/dist/{indexeddb-storage-yEswGGMG.js.map → indexeddb-storage-Ko4sjZtM.js.map} +1 -1
- package/dist/{memory-storage-CSB5_IfU.js → memory-storage-BTfQQ9Ig.js} +2 -2
- package/dist/{memory-storage-CSB5_IfU.js.map → memory-storage-BTfQQ9Ig.js.map} +1 -1
- package/dist/{memory-storage-Q8mEQ6Ix.cjs → memory-storage-C6YV3dsT.cjs} +2 -2
- package/dist/{memory-storage-Q8mEQ6Ix.cjs.map → memory-storage-C6YV3dsT.cjs.map} +1 -1
- package/package.json +1 -1
- package/src/federation/registry.js +70 -0
- package/src/index.js +34 -1
- package/dist/index-B7ERi4ng.js.map +0 -1
- package/dist/index-DXFsE8r6.cjs +0 -29
- package/dist/index-DXFsE8r6.cjs.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-
|
|
2
|
-
//# sourceMappingURL=indexeddb-storage-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-Dgx5DQG_.cjs");class t extends e.PersistentStorage{constructor(){super(),this.db=null,this.dbName="",this.storeName="events"}async init(e){this.dbName=`holosphere_${e}`;try{await this._openDatabase()}catch(t){if("VersionError"!==t.name)throw t;console.warn(`[IndexedDBStorage] Version conflict detected for ${this.dbName}, recreating database...`),await this._deleteDatabase(),await this._openDatabase()}}async _openDatabase(){return new Promise((e,t)=>{const r=indexedDB.open(this.dbName,1);r.onerror=()=>t(r.error),r.onsuccess=()=>{this.db=r.result,e(void 0)},r.onupgradeneeded=e=>{const t=e.target.result;if(!t.objectStoreNames.contains(this.storeName)){t.createObjectStore(this.storeName,{keyPath:"key"}).createIndex("key","key",{unique:!1})}}})}async _deleteDatabase(){return new Promise((e,t)=>{const r=indexedDB.deleteDatabase(this.dbName);r.onsuccess=()=>e(void 0),r.onerror=()=>t(r.error),r.onblocked=()=>{console.warn(`[IndexedDBStorage] Database deletion blocked for ${this.dbName}`),e(void 0)}})}async put(e,t){return new Promise((r,s)=>{if(!this.db)return void s(new Error("Database not initialized"));const o=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put({key:e,event:t,timestamp:Date.now()});o.onsuccess=()=>r(void 0),o.onerror=()=>s(o.error)})}async get(e){return new Promise((t,r)=>{if(!this.db)return void r(new Error("Database not initialized"));const s=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(e);s.onsuccess=()=>{const e=s.result;t(e?e.event:null)},s.onerror=()=>r(s.error)})}async getAll(e){return new Promise((t,r)=>{if(!this.db)return void r(new Error("Database not initialized"));const s=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName),o=[];let n;if(e){const t=IDBKeyRange.bound(e,e+"",!1,!1);n=s.openCursor(t)}else n=s.openCursor();n.onsuccess=e=>{const r=e.target.result;r?(o.push(r.value.event),r.continue()):t(o)},n.onerror=()=>r(n.error)})}async delete(e){return new Promise((t,r)=>{if(!this.db)return void r(new Error("Database not initialized"));const s=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(e);s.onsuccess=()=>t(void 0),s.onerror=()=>r(s.error)})}async clear(){return new Promise((e,t)=>{if(!this.db)return void t(new Error("Database not initialized"));const r=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).clear();r.onsuccess=()=>e(void 0),r.onerror=()=>t(r.error)})}async close(){this.db&&(this.db.close(),this.db=null)}}exports.IndexedDBStorage=t;
|
|
2
|
+
//# sourceMappingURL=indexeddb-storage-CyOZAiHV.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexeddb-storage-CVz4Q3lo.cjs","sources":["../src/storage/indexeddb-storage.js"],"sourcesContent":["/**\n * @fileoverview IndexedDB storage adapter for browsers.\n *\n * Provides persistent storage with good performance using browser IndexedDB.\n * Uses B-tree indexes for efficient prefix queries.\n *\n * @module storage/indexeddb-storage\n */\n\nimport { PersistentStorage } from './persistent-storage.js';\n\n/**\n * IndexedDB storage adapter for browsers.\n *\n * Provides high-performance persistent storage using IndexedDB with efficient prefix queries.\n *\n * @class IndexedDBStorage\n * @extends PersistentStorage\n * @example\n * const storage = new IndexedDBStorage();\n * await storage.init('myapp');\n * await storage.put('key1', { id: 'event1', content: 'test' });\n */\nexport class IndexedDBStorage extends PersistentStorage {\n /**\n * Create a new IndexedDBStorage instance.\n */\n constructor() {\n super();\n /** @type {IDBDatabase|null} */\n this.db = null;\n /** @type {string} */\n this.dbName = '';\n /** @type {string} */\n this.storeName = 'events';\n }\n\n /**\n * Initialize storage with namespace.\n *\n * Creates or opens the IndexedDB database and object store.\n * Handles version conflicts by deleting and recreating the database if needed.\n *\n * @param {string} namespace - Storage namespace\n * @returns {Promise<void>}\n */\n async init(namespace) {\n this.dbName = `holosphere_${namespace}`;\n\n try {\n await this._openDatabase();\n } catch (error) {\n // Handle version conflict by deleting and recreating the database\n if (error.name === 'VersionError') {\n console.warn(`[IndexedDBStorage] Version conflict detected for ${this.dbName}, recreating database...`);\n await this._deleteDatabase();\n await this._openDatabase();\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Open the IndexedDB database.\n *\n * @returns {Promise<void>}\n * @private\n */\n async _openDatabase() {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, 1);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.db = request.result;\n resolve(undefined);\n };\n\n request.onupgradeneeded = (event) => {\n const target = /** @type {IDBOpenDBRequest} */ (event.target);\n const db = target.result;\n\n // Create object store if it doesn't exist\n if (!db.objectStoreNames.contains(this.storeName)) {\n const objectStore = db.createObjectStore(this.storeName, { keyPath: 'key' });\n // Create index for prefix queries\n objectStore.createIndex('key', 'key', { unique: false });\n }\n };\n });\n }\n\n /**\n * Delete the IndexedDB database.\n *\n * @returns {Promise<void>}\n * @private\n */\n async _deleteDatabase() {\n return new Promise((resolve, reject) => {\n const request = indexedDB.deleteDatabase(this.dbName);\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n request.onblocked = () => {\n console.warn(`[IndexedDBStorage] Database deletion blocked for ${this.dbName}`);\n // Still resolve - the next open attempt will handle it\n resolve(undefined);\n };\n });\n }\n\n /**\n * Store an event.\n *\n * @param {string} key - Storage key\n * @param {Object} event - Event data\n * @returns {Promise<void>}\n */\n async put(key, event) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.put({ key, event, timestamp: Date.now() });\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Retrieve an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<Object|null>} Event data or null\n */\n async get(key) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readonly');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.get(key);\n\n request.onsuccess = () => {\n const result = request.result;\n resolve(result ? result.event : null);\n };\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Retrieve all events matching a prefix.\n *\n * Uses IDBKeyRange for efficient B-tree index queries.\n *\n * @param {string} prefix - Key prefix to match\n * @returns {Promise<any[]>} Array of matching events\n */\n async getAll(prefix) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readonly');\n const objectStore = transaction.objectStore(this.storeName);\n\n /** @type {any[]} */\n const results = [];\n\n // Use IDBKeyRange for efficient prefix query instead of full table scan\n // This creates a range from \"prefix\" to \"prefix\\uffff\" (highest unicode char)\n // which efficiently uses the B-tree index\n let request;\n if (prefix) {\n const range = IDBKeyRange.bound(prefix, prefix + '\\uffff', false, false);\n request = objectStore.openCursor(range);\n } else {\n // No prefix = get all\n request = objectStore.openCursor();\n }\n\n request.onsuccess = (event) => {\n const target = /** @type {IDBRequest} */ (event.target);\n const cursor = target.result;\n if (cursor) {\n results.push(cursor.value.event);\n cursor.continue();\n } else {\n resolve(results);\n }\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Delete an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<void>}\n */\n async delete(key) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.delete(key);\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Clear all stored events.\n *\n * @returns {Promise<void>}\n */\n async clear() {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.clear();\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Close the database connection.\n *\n * @returns {Promise<void>}\n */\n async close() {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n}\n"],"names":["IndexedDBStorage","PersistentStorage","constructor","super","this","db","dbName","storeName","init","namespace","_openDatabase","error","name","console","warn","_deleteDatabase","Promise","resolve","reject","request","indexedDB","open","onerror","onsuccess","result","onupgradeneeded","event","objectStoreNames","contains","createObjectStore","keyPath","createIndex","unique","deleteDatabase","onblocked","put","key","Error","transaction","objectStore","timestamp","Date","now","get","getAll","prefix","results","range","IDBKeyRange","bound","openCursor","cursor","push","value","continue","delete","clear","close"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"indexeddb-storage-CyOZAiHV.cjs","sources":["../src/storage/indexeddb-storage.js"],"sourcesContent":["/**\n * @fileoverview IndexedDB storage adapter for browsers.\n *\n * Provides persistent storage with good performance using browser IndexedDB.\n * Uses B-tree indexes for efficient prefix queries.\n *\n * @module storage/indexeddb-storage\n */\n\nimport { PersistentStorage } from './persistent-storage.js';\n\n/**\n * IndexedDB storage adapter for browsers.\n *\n * Provides high-performance persistent storage using IndexedDB with efficient prefix queries.\n *\n * @class IndexedDBStorage\n * @extends PersistentStorage\n * @example\n * const storage = new IndexedDBStorage();\n * await storage.init('myapp');\n * await storage.put('key1', { id: 'event1', content: 'test' });\n */\nexport class IndexedDBStorage extends PersistentStorage {\n /**\n * Create a new IndexedDBStorage instance.\n */\n constructor() {\n super();\n /** @type {IDBDatabase|null} */\n this.db = null;\n /** @type {string} */\n this.dbName = '';\n /** @type {string} */\n this.storeName = 'events';\n }\n\n /**\n * Initialize storage with namespace.\n *\n * Creates or opens the IndexedDB database and object store.\n * Handles version conflicts by deleting and recreating the database if needed.\n *\n * @param {string} namespace - Storage namespace\n * @returns {Promise<void>}\n */\n async init(namespace) {\n this.dbName = `holosphere_${namespace}`;\n\n try {\n await this._openDatabase();\n } catch (error) {\n // Handle version conflict by deleting and recreating the database\n if (error.name === 'VersionError') {\n console.warn(`[IndexedDBStorage] Version conflict detected for ${this.dbName}, recreating database...`);\n await this._deleteDatabase();\n await this._openDatabase();\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Open the IndexedDB database.\n *\n * @returns {Promise<void>}\n * @private\n */\n async _openDatabase() {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, 1);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.db = request.result;\n resolve(undefined);\n };\n\n request.onupgradeneeded = (event) => {\n const target = /** @type {IDBOpenDBRequest} */ (event.target);\n const db = target.result;\n\n // Create object store if it doesn't exist\n if (!db.objectStoreNames.contains(this.storeName)) {\n const objectStore = db.createObjectStore(this.storeName, { keyPath: 'key' });\n // Create index for prefix queries\n objectStore.createIndex('key', 'key', { unique: false });\n }\n };\n });\n }\n\n /**\n * Delete the IndexedDB database.\n *\n * @returns {Promise<void>}\n * @private\n */\n async _deleteDatabase() {\n return new Promise((resolve, reject) => {\n const request = indexedDB.deleteDatabase(this.dbName);\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n request.onblocked = () => {\n console.warn(`[IndexedDBStorage] Database deletion blocked for ${this.dbName}`);\n // Still resolve - the next open attempt will handle it\n resolve(undefined);\n };\n });\n }\n\n /**\n * Store an event.\n *\n * @param {string} key - Storage key\n * @param {Object} event - Event data\n * @returns {Promise<void>}\n */\n async put(key, event) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.put({ key, event, timestamp: Date.now() });\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Retrieve an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<Object|null>} Event data or null\n */\n async get(key) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readonly');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.get(key);\n\n request.onsuccess = () => {\n const result = request.result;\n resolve(result ? result.event : null);\n };\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Retrieve all events matching a prefix.\n *\n * Uses IDBKeyRange for efficient B-tree index queries.\n *\n * @param {string} prefix - Key prefix to match\n * @returns {Promise<any[]>} Array of matching events\n */\n async getAll(prefix) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readonly');\n const objectStore = transaction.objectStore(this.storeName);\n\n /** @type {any[]} */\n const results = [];\n\n // Use IDBKeyRange for efficient prefix query instead of full table scan\n // This creates a range from \"prefix\" to \"prefix\\uffff\" (highest unicode char)\n // which efficiently uses the B-tree index\n let request;\n if (prefix) {\n const range = IDBKeyRange.bound(prefix, prefix + '\\uffff', false, false);\n request = objectStore.openCursor(range);\n } else {\n // No prefix = get all\n request = objectStore.openCursor();\n }\n\n request.onsuccess = (event) => {\n const target = /** @type {IDBRequest} */ (event.target);\n const cursor = target.result;\n if (cursor) {\n results.push(cursor.value.event);\n cursor.continue();\n } else {\n resolve(results);\n }\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Delete an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<void>}\n */\n async delete(key) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.delete(key);\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Clear all stored events.\n *\n * @returns {Promise<void>}\n */\n async clear() {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.clear();\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Close the database connection.\n *\n * @returns {Promise<void>}\n */\n async close() {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n}\n"],"names":["IndexedDBStorage","PersistentStorage","constructor","super","this","db","dbName","storeName","init","namespace","_openDatabase","error","name","console","warn","_deleteDatabase","Promise","resolve","reject","request","indexedDB","open","onerror","onsuccess","result","onupgradeneeded","event","objectStoreNames","contains","createObjectStore","keyPath","createIndex","unique","deleteDatabase","onblocked","put","key","Error","transaction","objectStore","timestamp","Date","now","get","getAll","prefix","results","range","IDBKeyRange","bound","openCursor","cursor","push","value","continue","delete","clear","close"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { aV as PersistentStorage } from "./index-
|
|
1
|
+
import { aV as PersistentStorage } from "./index-CHfVBEUH.js";
|
|
2
2
|
class IndexedDBStorage extends PersistentStorage {
|
|
3
3
|
/**
|
|
4
4
|
* Create a new IndexedDBStorage instance.
|
|
@@ -210,4 +210,4 @@ class IndexedDBStorage extends PersistentStorage {
|
|
|
210
210
|
export {
|
|
211
211
|
IndexedDBStorage
|
|
212
212
|
};
|
|
213
|
-
//# sourceMappingURL=indexeddb-storage-
|
|
213
|
+
//# sourceMappingURL=indexeddb-storage-Ko4sjZtM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexeddb-storage-yEswGGMG.js","sources":["../src/storage/indexeddb-storage.js"],"sourcesContent":["/**\n * @fileoverview IndexedDB storage adapter for browsers.\n *\n * Provides persistent storage with good performance using browser IndexedDB.\n * Uses B-tree indexes for efficient prefix queries.\n *\n * @module storage/indexeddb-storage\n */\n\nimport { PersistentStorage } from './persistent-storage.js';\n\n/**\n * IndexedDB storage adapter for browsers.\n *\n * Provides high-performance persistent storage using IndexedDB with efficient prefix queries.\n *\n * @class IndexedDBStorage\n * @extends PersistentStorage\n * @example\n * const storage = new IndexedDBStorage();\n * await storage.init('myapp');\n * await storage.put('key1', { id: 'event1', content: 'test' });\n */\nexport class IndexedDBStorage extends PersistentStorage {\n /**\n * Create a new IndexedDBStorage instance.\n */\n constructor() {\n super();\n /** @type {IDBDatabase|null} */\n this.db = null;\n /** @type {string} */\n this.dbName = '';\n /** @type {string} */\n this.storeName = 'events';\n }\n\n /**\n * Initialize storage with namespace.\n *\n * Creates or opens the IndexedDB database and object store.\n * Handles version conflicts by deleting and recreating the database if needed.\n *\n * @param {string} namespace - Storage namespace\n * @returns {Promise<void>}\n */\n async init(namespace) {\n this.dbName = `holosphere_${namespace}`;\n\n try {\n await this._openDatabase();\n } catch (error) {\n // Handle version conflict by deleting and recreating the database\n if (error.name === 'VersionError') {\n console.warn(`[IndexedDBStorage] Version conflict detected for ${this.dbName}, recreating database...`);\n await this._deleteDatabase();\n await this._openDatabase();\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Open the IndexedDB database.\n *\n * @returns {Promise<void>}\n * @private\n */\n async _openDatabase() {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, 1);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.db = request.result;\n resolve(undefined);\n };\n\n request.onupgradeneeded = (event) => {\n const target = /** @type {IDBOpenDBRequest} */ (event.target);\n const db = target.result;\n\n // Create object store if it doesn't exist\n if (!db.objectStoreNames.contains(this.storeName)) {\n const objectStore = db.createObjectStore(this.storeName, { keyPath: 'key' });\n // Create index for prefix queries\n objectStore.createIndex('key', 'key', { unique: false });\n }\n };\n });\n }\n\n /**\n * Delete the IndexedDB database.\n *\n * @returns {Promise<void>}\n * @private\n */\n async _deleteDatabase() {\n return new Promise((resolve, reject) => {\n const request = indexedDB.deleteDatabase(this.dbName);\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n request.onblocked = () => {\n console.warn(`[IndexedDBStorage] Database deletion blocked for ${this.dbName}`);\n // Still resolve - the next open attempt will handle it\n resolve(undefined);\n };\n });\n }\n\n /**\n * Store an event.\n *\n * @param {string} key - Storage key\n * @param {Object} event - Event data\n * @returns {Promise<void>}\n */\n async put(key, event) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.put({ key, event, timestamp: Date.now() });\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Retrieve an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<Object|null>} Event data or null\n */\n async get(key) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readonly');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.get(key);\n\n request.onsuccess = () => {\n const result = request.result;\n resolve(result ? result.event : null);\n };\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Retrieve all events matching a prefix.\n *\n * Uses IDBKeyRange for efficient B-tree index queries.\n *\n * @param {string} prefix - Key prefix to match\n * @returns {Promise<any[]>} Array of matching events\n */\n async getAll(prefix) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readonly');\n const objectStore = transaction.objectStore(this.storeName);\n\n /** @type {any[]} */\n const results = [];\n\n // Use IDBKeyRange for efficient prefix query instead of full table scan\n // This creates a range from \"prefix\" to \"prefix\\uffff\" (highest unicode char)\n // which efficiently uses the B-tree index\n let request;\n if (prefix) {\n const range = IDBKeyRange.bound(prefix, prefix + '\\uffff', false, false);\n request = objectStore.openCursor(range);\n } else {\n // No prefix = get all\n request = objectStore.openCursor();\n }\n\n request.onsuccess = (event) => {\n const target = /** @type {IDBRequest} */ (event.target);\n const cursor = target.result;\n if (cursor) {\n results.push(cursor.value.event);\n cursor.continue();\n } else {\n resolve(results);\n }\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Delete an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<void>}\n */\n async delete(key) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.delete(key);\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Clear all stored events.\n *\n * @returns {Promise<void>}\n */\n async clear() {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.clear();\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Close the database connection.\n *\n * @returns {Promise<void>}\n */\n async close() {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"indexeddb-storage-Ko4sjZtM.js","sources":["../src/storage/indexeddb-storage.js"],"sourcesContent":["/**\n * @fileoverview IndexedDB storage adapter for browsers.\n *\n * Provides persistent storage with good performance using browser IndexedDB.\n * Uses B-tree indexes for efficient prefix queries.\n *\n * @module storage/indexeddb-storage\n */\n\nimport { PersistentStorage } from './persistent-storage.js';\n\n/**\n * IndexedDB storage adapter for browsers.\n *\n * Provides high-performance persistent storage using IndexedDB with efficient prefix queries.\n *\n * @class IndexedDBStorage\n * @extends PersistentStorage\n * @example\n * const storage = new IndexedDBStorage();\n * await storage.init('myapp');\n * await storage.put('key1', { id: 'event1', content: 'test' });\n */\nexport class IndexedDBStorage extends PersistentStorage {\n /**\n * Create a new IndexedDBStorage instance.\n */\n constructor() {\n super();\n /** @type {IDBDatabase|null} */\n this.db = null;\n /** @type {string} */\n this.dbName = '';\n /** @type {string} */\n this.storeName = 'events';\n }\n\n /**\n * Initialize storage with namespace.\n *\n * Creates or opens the IndexedDB database and object store.\n * Handles version conflicts by deleting and recreating the database if needed.\n *\n * @param {string} namespace - Storage namespace\n * @returns {Promise<void>}\n */\n async init(namespace) {\n this.dbName = `holosphere_${namespace}`;\n\n try {\n await this._openDatabase();\n } catch (error) {\n // Handle version conflict by deleting and recreating the database\n if (error.name === 'VersionError') {\n console.warn(`[IndexedDBStorage] Version conflict detected for ${this.dbName}, recreating database...`);\n await this._deleteDatabase();\n await this._openDatabase();\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Open the IndexedDB database.\n *\n * @returns {Promise<void>}\n * @private\n */\n async _openDatabase() {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, 1);\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.db = request.result;\n resolve(undefined);\n };\n\n request.onupgradeneeded = (event) => {\n const target = /** @type {IDBOpenDBRequest} */ (event.target);\n const db = target.result;\n\n // Create object store if it doesn't exist\n if (!db.objectStoreNames.contains(this.storeName)) {\n const objectStore = db.createObjectStore(this.storeName, { keyPath: 'key' });\n // Create index for prefix queries\n objectStore.createIndex('key', 'key', { unique: false });\n }\n };\n });\n }\n\n /**\n * Delete the IndexedDB database.\n *\n * @returns {Promise<void>}\n * @private\n */\n async _deleteDatabase() {\n return new Promise((resolve, reject) => {\n const request = indexedDB.deleteDatabase(this.dbName);\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n request.onblocked = () => {\n console.warn(`[IndexedDBStorage] Database deletion blocked for ${this.dbName}`);\n // Still resolve - the next open attempt will handle it\n resolve(undefined);\n };\n });\n }\n\n /**\n * Store an event.\n *\n * @param {string} key - Storage key\n * @param {Object} event - Event data\n * @returns {Promise<void>}\n */\n async put(key, event) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.put({ key, event, timestamp: Date.now() });\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Retrieve an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<Object|null>} Event data or null\n */\n async get(key) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readonly');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.get(key);\n\n request.onsuccess = () => {\n const result = request.result;\n resolve(result ? result.event : null);\n };\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Retrieve all events matching a prefix.\n *\n * Uses IDBKeyRange for efficient B-tree index queries.\n *\n * @param {string} prefix - Key prefix to match\n * @returns {Promise<any[]>} Array of matching events\n */\n async getAll(prefix) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readonly');\n const objectStore = transaction.objectStore(this.storeName);\n\n /** @type {any[]} */\n const results = [];\n\n // Use IDBKeyRange for efficient prefix query instead of full table scan\n // This creates a range from \"prefix\" to \"prefix\\uffff\" (highest unicode char)\n // which efficiently uses the B-tree index\n let request;\n if (prefix) {\n const range = IDBKeyRange.bound(prefix, prefix + '\\uffff', false, false);\n request = objectStore.openCursor(range);\n } else {\n // No prefix = get all\n request = objectStore.openCursor();\n }\n\n request.onsuccess = (event) => {\n const target = /** @type {IDBRequest} */ (event.target);\n const cursor = target.result;\n if (cursor) {\n results.push(cursor.value.event);\n cursor.continue();\n } else {\n resolve(results);\n }\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Delete an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<void>}\n */\n async delete(key) {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.delete(key);\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Clear all stored events.\n *\n * @returns {Promise<void>}\n */\n async clear() {\n return new Promise((resolve, reject) => {\n if (!this.db) {\n reject(new Error('Database not initialized'));\n return;\n }\n const transaction = this.db.transaction([this.storeName], 'readwrite');\n const objectStore = transaction.objectStore(this.storeName);\n\n const request = objectStore.clear();\n\n request.onsuccess = () => resolve(undefined);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Close the database connection.\n *\n * @returns {Promise<void>}\n */\n async close() {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { aV as PersistentStorage } from "./index-
|
|
1
|
+
import { aV as PersistentStorage } from "./index-CHfVBEUH.js";
|
|
2
2
|
class MemoryStorage extends PersistentStorage {
|
|
3
3
|
/**
|
|
4
4
|
* Create a new MemoryStorage instance.
|
|
@@ -88,4 +88,4 @@ MemoryStorage._globalStore = null;
|
|
|
88
88
|
export {
|
|
89
89
|
MemoryStorage
|
|
90
90
|
};
|
|
91
|
-
//# sourceMappingURL=memory-storage-
|
|
91
|
+
//# sourceMappingURL=memory-storage-BTfQQ9Ig.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-storage-
|
|
1
|
+
{"version":3,"file":"memory-storage-BTfQQ9Ig.js","sources":["../src/storage/memory-storage.js"],"sourcesContent":["/**\n * @fileoverview Memory-only storage adapter (fallback, no actual persistence).\n *\n * Provides in-memory storage for testing or when persistent storage is unavailable.\n * Data is shared across instances with the same namespace but lost on process restart.\n *\n * @module storage/memory-storage\n */\n\nimport { PersistentStorage } from './persistent-storage.js';\n\n/**\n * Memory-only storage adapter.\n *\n * Stores data in memory with no persistence across restarts.\n * Uses a global store to share data across instances with same namespace.\n *\n * @class MemoryStorage\n * @extends PersistentStorage\n * @example\n * const storage = new MemoryStorage();\n * await storage.init('myapp');\n * await storage.put('key1', { id: 'event1' });\n */\nexport class MemoryStorage extends PersistentStorage {\n /**\n * Create a new MemoryStorage instance.\n */\n constructor() {\n super();\n this.data = new Map();\n this.namespace = null;\n }\n\n /**\n * Initialize storage with namespace.\n *\n * @param {string} namespace - Storage namespace\n * @returns {Promise<void>}\n */\n async init(namespace) {\n this.namespace = namespace;\n // Check if there's existing data for this namespace\n if (!MemoryStorage._globalStore) {\n MemoryStorage._globalStore = new Map();\n }\n if (!MemoryStorage._globalStore.has(namespace)) {\n MemoryStorage._globalStore.set(namespace, new Map());\n }\n this.data = MemoryStorage._globalStore.get(namespace);\n }\n\n /**\n * Store an event.\n *\n * @param {string} key - Storage key\n * @param {Object} event - Event data\n * @returns {Promise<void>}\n */\n async put(key, event) {\n this.data.set(key, JSON.parse(JSON.stringify(event))); // Deep clone\n }\n\n /**\n * Retrieve an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<Object|null>} Event data or null\n */\n async get(key) {\n const data = this.data.get(key);\n return data ? JSON.parse(JSON.stringify(data)) : null; // Deep clone\n }\n\n /**\n * Retrieve all events matching a prefix.\n *\n * @param {string} prefix - Key prefix to match\n * @returns {Promise<any[]>} Array of matching events\n */\n async getAll(prefix) {\n /** @type {any[]} */\n const results = [];\n for (const [key, value] of this.data.entries()) {\n if (key.startsWith(prefix)) {\n results.push(JSON.parse(JSON.stringify(value)));\n }\n }\n return results;\n }\n\n /**\n * Delete an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<void>}\n */\n async delete(key) {\n this.data.delete(key);\n }\n\n /**\n * Clear all stored events.\n *\n * @returns {Promise<void>}\n */\n async clear() {\n this.data.clear();\n }\n\n /**\n * Close storage (no-op for memory storage).\n *\n * @returns {Promise<void>}\n */\n async close() {\n // Nothing to close for memory storage\n }\n}\n\n/**\n * Global store shared across instances with same namespace.\n * @private\n */\nMemoryStorage._globalStore = null;\n"],"names":[],"mappings":";AAwBO,MAAM,sBAAsB,kBAAkB;AAAA;AAAA;AAAA;AAAA,EAInD,cAAc;AACZ,UAAK;AACL,SAAK,OAAO,oBAAI,IAAG;AACnB,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,KAAK,WAAW;AACpB,SAAK,YAAY;AAEjB,QAAI,CAAC,cAAc,cAAc;AAC/B,oBAAc,eAAe,oBAAI,IAAG;AAAA,IACtC;AACA,QAAI,CAAC,cAAc,aAAa,IAAI,SAAS,GAAG;AAC9C,oBAAc,aAAa,IAAI,WAAW,oBAAI,IAAG,CAAE;AAAA,IACrD;AACA,SAAK,OAAO,cAAc,aAAa,IAAI,SAAS;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,IAAI,KAAK,OAAO;AACpB,SAAK,KAAK,IAAI,KAAK,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC,CAAC;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,IAAI,KAAK;AACb,UAAM,OAAO,KAAK,KAAK,IAAI,GAAG;AAC9B,WAAO,OAAO,KAAK,MAAM,KAAK,UAAU,IAAI,CAAC,IAAI;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAO,QAAQ;AAEnB,UAAM,UAAU,CAAA;AAChB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,WAAW;AAC9C,UAAI,IAAI,WAAW,MAAM,GAAG;AAC1B,gBAAQ,KAAK,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC,CAAC;AAAA,MAChD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAO,KAAK;AAChB,SAAK,KAAK,OAAO,GAAG;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAQ;AACZ,SAAK,KAAK,MAAK;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAQ;AAAA,EAEd;AACF;AAMA,cAAc,eAAe;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./index-
|
|
2
|
-
//# sourceMappingURL=memory-storage-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./index-Dgx5DQG_.cjs");class e extends t.PersistentStorage{constructor(){super(),this.data=new Map,this.namespace=null}async init(t){this.namespace=t,e._globalStore||(e._globalStore=new Map),e._globalStore.has(t)||e._globalStore.set(t,new Map),this.data=e._globalStore.get(t)}async put(t,e){this.data.set(t,JSON.parse(JSON.stringify(e)))}async get(t){const e=this.data.get(t);return e?JSON.parse(JSON.stringify(e)):null}async getAll(t){const e=[];for(const[s,a]of this.data.entries())s.startsWith(t)&&e.push(JSON.parse(JSON.stringify(a)));return e}async delete(t){this.data.delete(t)}async clear(){this.data.clear()}async close(){}}e._globalStore=null,exports.MemoryStorage=e;
|
|
2
|
+
//# sourceMappingURL=memory-storage-C6YV3dsT.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-storage-
|
|
1
|
+
{"version":3,"file":"memory-storage-C6YV3dsT.cjs","sources":["../src/storage/memory-storage.js"],"sourcesContent":["/**\n * @fileoverview Memory-only storage adapter (fallback, no actual persistence).\n *\n * Provides in-memory storage for testing or when persistent storage is unavailable.\n * Data is shared across instances with the same namespace but lost on process restart.\n *\n * @module storage/memory-storage\n */\n\nimport { PersistentStorage } from './persistent-storage.js';\n\n/**\n * Memory-only storage adapter.\n *\n * Stores data in memory with no persistence across restarts.\n * Uses a global store to share data across instances with same namespace.\n *\n * @class MemoryStorage\n * @extends PersistentStorage\n * @example\n * const storage = new MemoryStorage();\n * await storage.init('myapp');\n * await storage.put('key1', { id: 'event1' });\n */\nexport class MemoryStorage extends PersistentStorage {\n /**\n * Create a new MemoryStorage instance.\n */\n constructor() {\n super();\n this.data = new Map();\n this.namespace = null;\n }\n\n /**\n * Initialize storage with namespace.\n *\n * @param {string} namespace - Storage namespace\n * @returns {Promise<void>}\n */\n async init(namespace) {\n this.namespace = namespace;\n // Check if there's existing data for this namespace\n if (!MemoryStorage._globalStore) {\n MemoryStorage._globalStore = new Map();\n }\n if (!MemoryStorage._globalStore.has(namespace)) {\n MemoryStorage._globalStore.set(namespace, new Map());\n }\n this.data = MemoryStorage._globalStore.get(namespace);\n }\n\n /**\n * Store an event.\n *\n * @param {string} key - Storage key\n * @param {Object} event - Event data\n * @returns {Promise<void>}\n */\n async put(key, event) {\n this.data.set(key, JSON.parse(JSON.stringify(event))); // Deep clone\n }\n\n /**\n * Retrieve an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<Object|null>} Event data or null\n */\n async get(key) {\n const data = this.data.get(key);\n return data ? JSON.parse(JSON.stringify(data)) : null; // Deep clone\n }\n\n /**\n * Retrieve all events matching a prefix.\n *\n * @param {string} prefix - Key prefix to match\n * @returns {Promise<any[]>} Array of matching events\n */\n async getAll(prefix) {\n /** @type {any[]} */\n const results = [];\n for (const [key, value] of this.data.entries()) {\n if (key.startsWith(prefix)) {\n results.push(JSON.parse(JSON.stringify(value)));\n }\n }\n return results;\n }\n\n /**\n * Delete an event.\n *\n * @param {string} key - Storage key\n * @returns {Promise<void>}\n */\n async delete(key) {\n this.data.delete(key);\n }\n\n /**\n * Clear all stored events.\n *\n * @returns {Promise<void>}\n */\n async clear() {\n this.data.clear();\n }\n\n /**\n * Close storage (no-op for memory storage).\n *\n * @returns {Promise<void>}\n */\n async close() {\n // Nothing to close for memory storage\n }\n}\n\n/**\n * Global store shared across instances with same namespace.\n * @private\n */\nMemoryStorage._globalStore = null;\n"],"names":["MemoryStorage","PersistentStorage","constructor","super","this","data","Map","namespace","init","_globalStore","has","set","get","put","key","event","JSON","parse","stringify","getAll","prefix","results","value","entries","startsWith","push","delete","clear","close"],"mappings":"wHAwBO,MAAMA,UAAsBC,EAAAA,kBAIjC,WAAAC,GACEC,QACAC,KAAKC,SAAWC,IAChBF,KAAKG,UAAY,IACnB,CAQA,UAAMC,CAAKD,GACTH,KAAKG,UAAYA,EAEZP,EAAcS,eACjBT,EAAcS,iBAAmBH,KAE9BN,EAAcS,aAAaC,IAAIH,IAClCP,EAAcS,aAAaE,IAAIJ,EAAW,IAAID,KAEhDF,KAAKC,KAAOL,EAAcS,aAAaG,IAAIL,EAC7C,CASA,SAAMM,CAAIC,EAAKC,GACbX,KAAKC,KAAKM,IAAIG,EAAKE,KAAKC,MAAMD,KAAKE,UAAUH,IAC/C,CAQA,SAAMH,CAAIE,GACR,MAAMT,EAAOD,KAAKC,KAAKO,IAAIE,GAC3B,OAAOT,EAAOW,KAAKC,MAAMD,KAAKE,UAAUb,IAAS,IACnD,CAQA,YAAMc,CAAOC,GAEX,MAAMC,EAAU,GAChB,IAAA,MAAYP,EAAKQ,KAAUlB,KAAKC,KAAKkB,UAC/BT,EAAIU,WAAWJ,IACjBC,EAAQI,KAAKT,KAAKC,MAAMD,KAAKE,UAAUI,KAG3C,OAAOD,CACT,CAQA,YAAM,CAAOP,GACXV,KAAKC,KAAKqB,OAAOZ,EACnB,CAOA,WAAMa,GACJvB,KAAKC,KAAKsB,OACZ,CAOA,WAAMC,GAEN,EAOF5B,EAAcS,aAAe"}
|
package/package.json
CHANGED
|
@@ -91,12 +91,18 @@ export async function getFederationRegistry(client, appname, options = {}) {
|
|
|
91
91
|
const registry = await readGlobal(client, appname, FEDERATION_TABLE, client.publicKey) || {
|
|
92
92
|
id: client.publicKey,
|
|
93
93
|
federatedWith: [],
|
|
94
|
+
capabilityWriters: [],
|
|
94
95
|
discoveryEnabled: false,
|
|
95
96
|
autoAccept: false,
|
|
96
97
|
defaultScope: { holonId: '*', lensName: '*' },
|
|
97
98
|
defaultPermissions: ['read'],
|
|
98
99
|
};
|
|
99
100
|
|
|
101
|
+
// Ensure capabilityWriters array exists (for registries created before this field)
|
|
102
|
+
if (!registry.capabilityWriters) {
|
|
103
|
+
registry.capabilityWriters = [];
|
|
104
|
+
}
|
|
105
|
+
|
|
100
106
|
// Build partner index and cache
|
|
101
107
|
const partnerIndex = buildPartnerIndex(registry.federatedWith || []);
|
|
102
108
|
registryCache.set(cacheKey, {
|
|
@@ -230,6 +236,70 @@ export async function getFederatedAuthors(client, appname) {
|
|
|
230
236
|
return registry.federatedWith.map(p => p.pubKey);
|
|
231
237
|
}
|
|
232
238
|
|
|
239
|
+
// ============================================================================
|
|
240
|
+
// Capability Writers (External writers registered via app-level authorization)
|
|
241
|
+
// ============================================================================
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Add a capability writer — an external pubkey authorized to write to this holon
|
|
245
|
+
* via app-level capability tokens (e.g., QR codes). Their pubkey is recorded so
|
|
246
|
+
* their data is included in future read queries.
|
|
247
|
+
*
|
|
248
|
+
* @param {Object} client - NostrClient instance
|
|
249
|
+
* @param {string} appname - Application namespace
|
|
250
|
+
* @param {string} writerPubKey - Writer's public key to register
|
|
251
|
+
* @returns {Promise<boolean>} Success indicator
|
|
252
|
+
*/
|
|
253
|
+
export async function addCapabilityWriter(client, appname, writerPubKey) {
|
|
254
|
+
const registry = await getFederationRegistry(client, appname);
|
|
255
|
+
|
|
256
|
+
// Deduplicate
|
|
257
|
+
const exists = registry.capabilityWriters.some(w => w.pubKey === writerPubKey);
|
|
258
|
+
if (exists) {
|
|
259
|
+
return true; // Already registered
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
registry.capabilityWriters.push({
|
|
263
|
+
pubKey: writerPubKey,
|
|
264
|
+
addedAt: Date.now(),
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
return saveFederationRegistry(client, appname, registry);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Get all capability writer public keys.
|
|
272
|
+
*
|
|
273
|
+
* @param {Object} client - NostrClient instance
|
|
274
|
+
* @param {string} appname - Application namespace
|
|
275
|
+
* @returns {Promise<string[]>} Array of capability writer pubkeys
|
|
276
|
+
*/
|
|
277
|
+
export async function getCapabilityWriters(client, appname) {
|
|
278
|
+
const registry = await getFederationRegistry(client, appname);
|
|
279
|
+
return (registry.capabilityWriters || []).map(w => w.pubKey);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Remove a capability writer.
|
|
284
|
+
*
|
|
285
|
+
* @param {Object} client - NostrClient instance
|
|
286
|
+
* @param {string} appname - Application namespace
|
|
287
|
+
* @param {string} writerPubKey - Writer's public key to remove
|
|
288
|
+
* @returns {Promise<boolean>} Success indicator
|
|
289
|
+
*/
|
|
290
|
+
export async function removeCapabilityWriter(client, appname, writerPubKey) {
|
|
291
|
+
const registry = await getFederationRegistry(client, appname);
|
|
292
|
+
|
|
293
|
+
const initialLength = registry.capabilityWriters.length;
|
|
294
|
+
registry.capabilityWriters = registry.capabilityWriters.filter(w => w.pubKey !== writerPubKey);
|
|
295
|
+
|
|
296
|
+
if (registry.capabilityWriters.length === initialLength) {
|
|
297
|
+
return false; // Writer not found
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return saveFederationRegistry(client, appname, registry);
|
|
301
|
+
}
|
|
302
|
+
|
|
233
303
|
/**
|
|
234
304
|
* Get a specific federated partner (O(1) lookup via index)
|
|
235
305
|
* @param {Object} client - NostrClient instance
|
package/src/index.js
CHANGED
|
@@ -382,7 +382,24 @@ class HoloSphereBase extends HoloSphereCore {
|
|
|
382
382
|
const capToken = options.capabilityToken || options.capability;
|
|
383
383
|
const actingAsHolon = options.actingAs || options.actingAsHolon;
|
|
384
384
|
|
|
385
|
-
if (
|
|
385
|
+
if (options.externalWriter) {
|
|
386
|
+
// App-level authorization already validated (e.g., QR capability token).
|
|
387
|
+
// Skip holosphere-level auth checks, but register this writer's pubkey
|
|
388
|
+
// so their data is included in future read queries.
|
|
389
|
+
const writerPubKey = effectiveWriterPubKey;
|
|
390
|
+
if (writerPubKey && writerPubKey !== holonId) {
|
|
391
|
+
try {
|
|
392
|
+
await registry.addCapabilityWriter(this.client, this.config.appName, writerPubKey);
|
|
393
|
+
this._log('DEBUG', '✅ Registered capability writer', {
|
|
394
|
+
writerPubKey: writerPubKey.slice(0, 12) + '...',
|
|
395
|
+
holonId: holonId.slice(0, 12) + '...'
|
|
396
|
+
});
|
|
397
|
+
} catch (err) {
|
|
398
|
+
this._log('WARN', '⚠️ Failed to register capability writer', { error: err.message });
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// Fall through to actual write below (skip all auth checks)
|
|
402
|
+
} else if (!isOwnHolon) {
|
|
386
403
|
// Writing to non-own holon - check authorization
|
|
387
404
|
// Priority: 1. Explicit capability token, 2. Membership-based access
|
|
388
405
|
|
|
@@ -1043,6 +1060,22 @@ class HoloSphereBase extends HoloSphereCore {
|
|
|
1043
1060
|
} catch (err) {
|
|
1044
1061
|
this._log('WARN', 'Failed to get federated authors', { error: err.message });
|
|
1045
1062
|
}
|
|
1063
|
+
|
|
1064
|
+
// Also include capability writers — external users who wrote via app-level authorization
|
|
1065
|
+
try {
|
|
1066
|
+
const capWritersPromise = registry.getCapabilityWriters(this.client, this.config.appName);
|
|
1067
|
+
const capWritersTimeout = new Promise((resolve) =>
|
|
1068
|
+
setTimeout(() => resolve([]), 1000)
|
|
1069
|
+
);
|
|
1070
|
+
const capabilityWriters = await Promise.race([capWritersPromise, capWritersTimeout]);
|
|
1071
|
+
if (capabilityWriters.length > 0) {
|
|
1072
|
+
const existing = readOptions.authors || [this.client.publicKey];
|
|
1073
|
+
readOptions.authors = [...new Set([...existing, ...capabilityWriters])];
|
|
1074
|
+
this._log('DEBUG', 'Including capability writers', { count: capabilityWriters.length });
|
|
1075
|
+
}
|
|
1076
|
+
} catch (err) {
|
|
1077
|
+
this._log('WARN', 'Failed to get capability writers', { error: err.message });
|
|
1078
|
+
}
|
|
1046
1079
|
}
|
|
1047
1080
|
|
|
1048
1081
|
const startTime = Date.now();
|