holosphere 2.0.0-alpha21 → 2.0.0-alpha23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/dist/cjs/holosphere.cjs +1 -1
- package/dist/esm/holosphere.js +61 -58
- package/dist/{index-B6-8KAQm.js → index-BEkCLOwI.js} +2 -2
- package/dist/{index-B6-8KAQm.js.map → index-BEkCLOwI.js.map} +1 -1
- package/dist/{index-D2WstuZJ.js → index-BEvX6DxG.js} +2 -2
- package/dist/{index-D2WstuZJ.js.map → index-BEvX6DxG.js.map} +1 -1
- package/dist/{index--QsHG_gD.cjs → index-BGTOiJ2Y.cjs} +2 -2
- package/dist/{index--QsHG_gD.cjs.map → index-BGTOiJ2Y.cjs.map} +1 -1
- package/dist/{index-COpLk9gL.cjs → index-BH1woZXL.cjs} +2 -2
- package/dist/{index-COpLk9gL.cjs.map → index-BH1woZXL.cjs.map} +1 -1
- package/dist/{index-BHptWysv.js → index-Cvxov2jv.js} +2970 -7753
- package/dist/index-Cvxov2jv.js.map +1 -0
- package/dist/index-vTKI_BAX.cjs +29 -0
- package/dist/index-vTKI_BAX.cjs.map +1 -0
- package/dist/{indexeddb-storage-wKG4mICM.cjs → indexeddb-storage-BmnCNnSg.cjs} +2 -2
- package/dist/{indexeddb-storage-wKG4mICM.cjs.map → indexeddb-storage-BmnCNnSg.cjs.map} +1 -1
- package/dist/{indexeddb-storage-kQ53UHEE.js → indexeddb-storage-MIFisaPy.js} +2 -2
- package/dist/{indexeddb-storage-kQ53UHEE.js.map → indexeddb-storage-MIFisaPy.js.map} +1 -1
- package/dist/{memory-storage-CGC8xM2G.cjs → memory-storage-BJjK3F4r.cjs} +2 -2
- package/dist/{memory-storage-CGC8xM2G.cjs.map → memory-storage-BJjK3F4r.cjs.map} +1 -1
- package/dist/{memory-storage-DnXCSbBl.js → memory-storage-DhHXdKQ-.js} +2 -2
- package/dist/{memory-storage-DnXCSbBl.js.map → memory-storage-DhHXdKQ-.js.map} +1 -1
- package/examples/demo.html +2 -29
- package/package.json +3 -8
- package/src/content/social-protocols.js +3 -59
- package/src/core/holosphere.js +16 -554
- package/src/crypto/nostr-utils.js +98 -1
- package/src/crypto/secp256k1.js +4 -393
- package/src/federation/discovery.js +7 -75
- package/src/federation/handshake.js +69 -202
- package/src/federation/hologram.js +222 -298
- package/src/federation/index.js +2 -9
- package/src/federation/registry.js +67 -1257
- package/src/federation/request-card.js +21 -35
- package/src/hierarchical/upcast.js +4 -9
- package/src/index.js +145 -296
- package/src/lib/federation-methods.js +370 -909
- package/src/storage/global-tables.js +1 -1
- package/src/storage/nostr-wrapper.js +9 -5
- package/src/subscriptions/manager.js +1 -1
- package/types/index.d.ts +145 -37
- package/bin/holosphere-activitypub.js +0 -158
- package/dist/2019-BzVkRcax.js +0 -6680
- package/dist/2019-BzVkRcax.js.map +0 -1
- package/dist/2019-C1hPR_Os.cjs +0 -8
- package/dist/2019-C1hPR_Os.cjs.map +0 -1
- package/dist/browser-BcmACE3G.js +0 -3058
- package/dist/browser-BcmACE3G.js.map +0 -1
- package/dist/browser-DaqYUTcG.cjs +0 -2
- package/dist/browser-DaqYUTcG.cjs.map +0 -1
- package/dist/index-BHptWysv.js.map +0 -1
- package/dist/index-CDlhzxT2.cjs +0 -29
- package/dist/index-CDlhzxT2.cjs.map +0 -1
- package/src/federation/capabilities.js +0 -46
- package/src/storage/backend-factory.js +0 -130
- package/src/storage/backend-interface.js +0 -161
- package/src/storage/backends/activitypub/server.js +0 -675
- package/src/storage/backends/activitypub-backend.js +0 -295
- package/src/storage/backends/gundb-backend.js +0 -875
- package/src/storage/backends/nostr-backend.js +0 -251
- package/src/storage/gun-async.js +0 -341
- package/src/storage/gun-auth.js +0 -373
- package/src/storage/gun-federation.js +0 -785
- package/src/storage/gun-references.js +0 -209
- package/src/storage/gun-schema.js +0 -306
- package/src/storage/gun-wrapper.js +0 -642
- package/src/storage/migration.js +0 -351
- package/src/storage/unified-storage.js +0 -161
package/src/storage/migration.js
DELETED
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Migration tool for HoloSphere storage backends.
|
|
3
|
-
* Enables data migration between different storage backends (Nostr, GunDB, ActivityPub)
|
|
4
|
-
* with export/import functionality, direct migration, and validation.
|
|
5
|
-
* @module storage/migration
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { BackendFactory } from './backend-factory.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Portable data bundle format
|
|
12
|
-
* @typedef {Object} DataBundle
|
|
13
|
-
* @property {string} version - Bundle format version
|
|
14
|
-
* @property {string} exportedAt - ISO timestamp
|
|
15
|
-
* @property {string} sourceType - Source backend type
|
|
16
|
-
* @property {string} sourceKey - Source public key
|
|
17
|
-
* @property {number} recordCount - Number of records
|
|
18
|
-
* @property {Object[]} records - Array of data records
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Migration record format
|
|
23
|
-
* @typedef {Object} MigrationRecord
|
|
24
|
-
* @property {string} path - Storage path
|
|
25
|
-
* @property {Object} data - Record data
|
|
26
|
-
* @property {number} timestamp - Creation timestamp
|
|
27
|
-
* @property {string} [author] - Author public key
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Migration results
|
|
32
|
-
* @typedef {Object} MigrationResults
|
|
33
|
-
* @property {number} success - Successfully migrated records
|
|
34
|
-
* @property {number} failed - Failed records
|
|
35
|
-
* @property {Object[]} errors - Error details
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Migration tool for transferring data between HoloSphere storage backends.
|
|
40
|
-
* Supports export/import to portable format, direct migration, and validation.
|
|
41
|
-
*
|
|
42
|
-
* @class MigrationTool
|
|
43
|
-
* @example
|
|
44
|
-
* const tool = new MigrationTool();
|
|
45
|
-
* await tool.setSource('nostr', { relays: ['wss://...'] });
|
|
46
|
-
* await tool.setTarget('gundb', { peers: ['wss://...'] });
|
|
47
|
-
* const results = await tool.migrate();
|
|
48
|
-
*/
|
|
49
|
-
export class MigrationTool {
|
|
50
|
-
/**
|
|
51
|
-
* Create a new MigrationTool instance.
|
|
52
|
-
*/
|
|
53
|
-
constructor() {
|
|
54
|
-
/** @type {StorageBackend|null} */
|
|
55
|
-
this.sourceBackend = null;
|
|
56
|
-
/** @type {StorageBackend|null} */
|
|
57
|
-
this.targetBackend = null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Configure source backend
|
|
62
|
-
* @param {string} type - Backend type: 'nostr' | 'gundb' | 'activitypub'
|
|
63
|
-
* @param {Object} config - Backend configuration
|
|
64
|
-
* @returns {Promise<void>}
|
|
65
|
-
*/
|
|
66
|
-
async setSource(type, config) {
|
|
67
|
-
this.sourceBackend = await BackendFactory.create(type, config);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Configure target backend
|
|
72
|
-
* @param {string} type - Backend type: 'nostr' | 'gundb' | 'activitypub'
|
|
73
|
-
* @param {Object} config - Backend configuration
|
|
74
|
-
* @returns {Promise<void>}
|
|
75
|
-
*/
|
|
76
|
-
async setTarget(type, config) {
|
|
77
|
-
this.targetBackend = await BackendFactory.create(type, config);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Use an existing backend instance as source
|
|
82
|
-
* @param {StorageBackend} backend - Backend instance
|
|
83
|
-
*/
|
|
84
|
-
useSourceBackend(backend) {
|
|
85
|
-
this.sourceBackend = backend;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Use an existing backend instance as target
|
|
90
|
-
* @param {StorageBackend} backend - Backend instance
|
|
91
|
-
*/
|
|
92
|
-
useTargetBackend(backend) {
|
|
93
|
-
this.targetBackend = backend;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Export data from source to portable format
|
|
98
|
-
* @param {string} [pathPrefix] - Optional path prefix filter
|
|
99
|
-
* @returns {Promise<DataBundle>} Exportable data bundle
|
|
100
|
-
*/
|
|
101
|
-
async export(pathPrefix = '') {
|
|
102
|
-
if (!this.sourceBackend) {
|
|
103
|
-
throw new Error('Source backend not configured. Call setSource() first.');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
console.log(`Exporting data from ${this.sourceBackend.getStatus().type}...`);
|
|
107
|
-
|
|
108
|
-
const records = await this.sourceBackend.exportData(pathPrefix);
|
|
109
|
-
const status = this.sourceBackend.getStatus();
|
|
110
|
-
|
|
111
|
-
const bundle = {
|
|
112
|
-
version: '1.0',
|
|
113
|
-
exportedAt: new Date().toISOString(),
|
|
114
|
-
sourceType: status.type,
|
|
115
|
-
sourceKey: status.publicKey || 'unknown',
|
|
116
|
-
pathPrefix: pathPrefix || '',
|
|
117
|
-
recordCount: records.length,
|
|
118
|
-
records,
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
console.log(`Exported ${records.length} records.`);
|
|
122
|
-
return bundle;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Import data to target backend
|
|
127
|
-
* @param {DataBundle} bundle - Data bundle from export()
|
|
128
|
-
* @param {Object} [options] - Import options
|
|
129
|
-
* @param {boolean} [options.overwrite] - Overwrite existing data
|
|
130
|
-
* @param {boolean} [options.dryRun] - Simulate without writing
|
|
131
|
-
* @param {Function} [options.onProgress] - Progress callback (current, total)
|
|
132
|
-
* @returns {Promise<MigrationResults>} Import results
|
|
133
|
-
*/
|
|
134
|
-
async import(bundle, options = {}) {
|
|
135
|
-
if (!this.targetBackend) {
|
|
136
|
-
throw new Error('Target backend not configured. Call setTarget() first.');
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (!bundle || !bundle.records) {
|
|
140
|
-
throw new Error('Invalid bundle format. Expected { version, records }');
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
console.log(`Importing ${bundle.recordCount} records to ${this.targetBackend.getStatus().type}...`);
|
|
144
|
-
|
|
145
|
-
if (options.dryRun) {
|
|
146
|
-
console.log('Dry run mode - no data will be written.');
|
|
147
|
-
return {
|
|
148
|
-
dryRun: true,
|
|
149
|
-
wouldImport: bundle.recordCount,
|
|
150
|
-
records: bundle.records.map(r => r.path),
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const results = await this.targetBackend.importData(bundle.records, options);
|
|
155
|
-
|
|
156
|
-
if (options.onProgress) {
|
|
157
|
-
options.onProgress(results.success + results.failed, bundle.recordCount);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
console.log(`Import complete: ${results.success} succeeded, ${results.failed} failed.`);
|
|
161
|
-
return results;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Migrate data directly from source to target
|
|
166
|
-
* @param {string} [pathPrefix] - Optional path prefix filter
|
|
167
|
-
* @param {Object} [options] - Migration options
|
|
168
|
-
* @param {boolean} [options.dryRun] - Simulate without writing
|
|
169
|
-
* @param {Function} [options.onProgress] - Progress callback
|
|
170
|
-
* @returns {Promise<Object>} Migration results
|
|
171
|
-
*/
|
|
172
|
-
async migrate(pathPrefix = '', options = {}) {
|
|
173
|
-
if (!this.sourceBackend || !this.targetBackend) {
|
|
174
|
-
throw new Error('Both source and target backends must be configured.');
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const sourceStatus = this.sourceBackend.getStatus();
|
|
178
|
-
const targetStatus = this.targetBackend.getStatus();
|
|
179
|
-
|
|
180
|
-
console.log(`\nMigrating data:`);
|
|
181
|
-
console.log(` From: ${sourceStatus.type} (${sourceStatus.publicKey || 'unknown'})`);
|
|
182
|
-
console.log(` To: ${targetStatus.type}`);
|
|
183
|
-
console.log(` Filter: ${pathPrefix || '(all data)'}\n`);
|
|
184
|
-
|
|
185
|
-
// Export from source
|
|
186
|
-
const bundle = await this.export(pathPrefix);
|
|
187
|
-
|
|
188
|
-
// Import to target
|
|
189
|
-
const importResults = await this.import(bundle, options);
|
|
190
|
-
|
|
191
|
-
return {
|
|
192
|
-
sourceType: sourceStatus.type,
|
|
193
|
-
targetType: targetStatus.type,
|
|
194
|
-
pathPrefix,
|
|
195
|
-
exportedCount: bundle.recordCount,
|
|
196
|
-
...importResults,
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Validate data integrity after migration
|
|
202
|
-
* @param {string} [pathPrefix] - Optional path prefix filter
|
|
203
|
-
* @returns {Promise<Object>} Validation results
|
|
204
|
-
*/
|
|
205
|
-
async validate(pathPrefix = '') {
|
|
206
|
-
if (!this.sourceBackend || !this.targetBackend) {
|
|
207
|
-
throw new Error('Both source and target backends must be configured.');
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
console.log('Validating migration...');
|
|
211
|
-
|
|
212
|
-
const sourceData = await this.sourceBackend.exportData(pathPrefix);
|
|
213
|
-
const targetData = await this.targetBackend.exportData(pathPrefix);
|
|
214
|
-
|
|
215
|
-
const sourceMap = new Map(sourceData.map(r => [r.path, r]));
|
|
216
|
-
const targetMap = new Map(targetData.map(r => [r.path, r]));
|
|
217
|
-
|
|
218
|
-
const missing = [];
|
|
219
|
-
const different = [];
|
|
220
|
-
const extra = [];
|
|
221
|
-
|
|
222
|
-
// Check for missing or different records
|
|
223
|
-
for (const [path, sourceRecord] of sourceMap) {
|
|
224
|
-
const targetRecord = targetMap.get(path);
|
|
225
|
-
|
|
226
|
-
if (!targetRecord) {
|
|
227
|
-
missing.push(path);
|
|
228
|
-
} else {
|
|
229
|
-
// Compare data (ignoring metadata that may differ)
|
|
230
|
-
const sourceDataStr = JSON.stringify(this._normalizeForComparison(sourceRecord.data));
|
|
231
|
-
const targetDataStr = JSON.stringify(this._normalizeForComparison(targetRecord.data));
|
|
232
|
-
|
|
233
|
-
if (sourceDataStr !== targetDataStr) {
|
|
234
|
-
different.push({
|
|
235
|
-
path,
|
|
236
|
-
source: sourceRecord.data,
|
|
237
|
-
target: targetRecord.data,
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Check for extra records in target
|
|
244
|
-
for (const path of targetMap.keys()) {
|
|
245
|
-
if (!sourceMap.has(path)) {
|
|
246
|
-
extra.push(path);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const valid = missing.length === 0 && different.length === 0;
|
|
251
|
-
|
|
252
|
-
console.log(`Validation ${valid ? 'PASSED' : 'FAILED'}:`);
|
|
253
|
-
console.log(` Source records: ${sourceData.length}`);
|
|
254
|
-
console.log(` Target records: ${targetData.length}`);
|
|
255
|
-
console.log(` Missing: ${missing.length}`);
|
|
256
|
-
console.log(` Different: ${different.length}`);
|
|
257
|
-
console.log(` Extra: ${extra.length}`);
|
|
258
|
-
|
|
259
|
-
return {
|
|
260
|
-
valid,
|
|
261
|
-
sourceCount: sourceData.length,
|
|
262
|
-
targetCount: targetData.length,
|
|
263
|
-
missing,
|
|
264
|
-
different,
|
|
265
|
-
extra,
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Normalize data for comparison (remove volatile metadata)
|
|
271
|
-
* @private
|
|
272
|
-
*/
|
|
273
|
-
_normalizeForComparison(data) {
|
|
274
|
-
if (!data || typeof data !== 'object') return data;
|
|
275
|
-
|
|
276
|
-
const normalized = { ...data };
|
|
277
|
-
|
|
278
|
-
// Remove metadata that may legitimately differ
|
|
279
|
-
delete normalized._meta;
|
|
280
|
-
delete normalized._author;
|
|
281
|
-
delete normalized._timestamp;
|
|
282
|
-
|
|
283
|
-
return normalized;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Export bundle to JSON file (for manual transfer)
|
|
288
|
-
* @param {DataBundle} bundle - Data bundle
|
|
289
|
-
* @param {string} filePath - Output file path
|
|
290
|
-
*/
|
|
291
|
-
async exportToFile(bundle, filePath) {
|
|
292
|
-
const fs = await import('fs/promises');
|
|
293
|
-
await fs.writeFile(filePath, JSON.stringify(bundle, null, 2), 'utf-8');
|
|
294
|
-
console.log(`Bundle exported to ${filePath}`);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Import bundle from JSON file
|
|
299
|
-
* @param {string} filePath - Input file path
|
|
300
|
-
* @returns {Promise<DataBundle>} Loaded bundle
|
|
301
|
-
*/
|
|
302
|
-
async importFromFile(filePath) {
|
|
303
|
-
const fs = await import('fs/promises');
|
|
304
|
-
const content = await fs.readFile(filePath, 'utf-8');
|
|
305
|
-
const bundle = JSON.parse(content);
|
|
306
|
-
console.log(`Bundle loaded from ${filePath}: ${bundle.recordCount} records`);
|
|
307
|
-
return bundle;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Close all backend connections
|
|
312
|
-
*/
|
|
313
|
-
close() {
|
|
314
|
-
if (this.sourceBackend) {
|
|
315
|
-
this.sourceBackend.close();
|
|
316
|
-
}
|
|
317
|
-
if (this.targetBackend) {
|
|
318
|
-
this.targetBackend.close();
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Quick migration function for common use cases
|
|
325
|
-
* @param {Object} sourceConfig - Source backend config with 'type' field
|
|
326
|
-
* @param {Object} targetConfig - Target backend config with 'type' field
|
|
327
|
-
* @param {string} [pathPrefix] - Optional path filter
|
|
328
|
-
* @param {Object} [options] - Migration options
|
|
329
|
-
* @returns {Promise<Object>} Migration results
|
|
330
|
-
*/
|
|
331
|
-
export async function quickMigrate(sourceConfig, targetConfig, pathPrefix = '', options = {}) {
|
|
332
|
-
const tool = new MigrationTool();
|
|
333
|
-
|
|
334
|
-
try {
|
|
335
|
-
await tool.setSource(sourceConfig.type, sourceConfig);
|
|
336
|
-
await tool.setTarget(targetConfig.type, targetConfig);
|
|
337
|
-
|
|
338
|
-
const results = await tool.migrate(pathPrefix, options);
|
|
339
|
-
|
|
340
|
-
if (!options.skipValidation) {
|
|
341
|
-
const validation = await tool.validate(pathPrefix);
|
|
342
|
-
results.validation = validation;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
return results;
|
|
346
|
-
} finally {
|
|
347
|
-
tool.close();
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
export default MigrationTool;
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Unified Storage Adapter.
|
|
3
|
-
*
|
|
4
|
-
* Routes storage operations to the correct backend (Nostr or GunDB).
|
|
5
|
-
* Provides a consistent API for reading, writing, updating, and deleting
|
|
6
|
-
* data across different storage backends.
|
|
7
|
-
*
|
|
8
|
-
* @module storage/unified-storage
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import * as nostrWrapper from './nostr-wrapper.js';
|
|
12
|
-
import * as gunWrapper from './gun-wrapper.js';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Build path from components
|
|
16
|
-
* @param {string} appName - Application namespace
|
|
17
|
-
* @param {string} holonId - Holon identifier
|
|
18
|
-
* @param {string} lensName - Lens name
|
|
19
|
-
* @param {string} [key] - Optional data key
|
|
20
|
-
* @returns {string} Constructed path
|
|
21
|
-
*/
|
|
22
|
-
export function buildPath(appName, holonId, lensName, key = null) {
|
|
23
|
-
// Both backends use the same path format
|
|
24
|
-
return nostrWrapper.buildPath(appName, holonId, lensName, key);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Write data to storage
|
|
29
|
-
* @param {Object} client - Client instance (nostr client or gun-compatible client)
|
|
30
|
-
* @param {string} path - Storage path
|
|
31
|
-
* @param {Object} data - Data to write
|
|
32
|
-
* @param {Object} [options={}] - Write options
|
|
33
|
-
* @returns {Promise<boolean>} Success indicator
|
|
34
|
-
*/
|
|
35
|
-
export async function write(client, path, data, options = {}) {
|
|
36
|
-
// Check if this is a GunDB client with backend methods (preferred - has write cache)
|
|
37
|
-
if (client.write && client.gun) {
|
|
38
|
-
return client.write(path, data, options);
|
|
39
|
-
}
|
|
40
|
-
// Fallback to direct gunWrapper (no write cache)
|
|
41
|
-
if (client.gun) {
|
|
42
|
-
return gunWrapper.write(client.gun, path, data, options);
|
|
43
|
-
}
|
|
44
|
-
// Default to Nostr
|
|
45
|
-
return nostrWrapper.write(client, path, data, options);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Read data from storage
|
|
50
|
-
* @param {Object} client - Client instance
|
|
51
|
-
* @param {string} path - Storage path
|
|
52
|
-
* @param {Object} [options] - Read options
|
|
53
|
-
* @returns {Promise<Object|null>} Data or null
|
|
54
|
-
*/
|
|
55
|
-
export async function read(client, path, options = {}) {
|
|
56
|
-
// Check if this is a GunDB client with backend methods (preferred - has write cache)
|
|
57
|
-
if (client.read && client.gun) {
|
|
58
|
-
return client.read(path, options);
|
|
59
|
-
}
|
|
60
|
-
// Fallback to direct gunWrapper
|
|
61
|
-
if (client.gun) {
|
|
62
|
-
return gunWrapper.read(client.gun, path);
|
|
63
|
-
}
|
|
64
|
-
return nostrWrapper.read(client, path, options);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Read all data under a path prefix
|
|
69
|
-
* @param {Object} client - Client instance
|
|
70
|
-
* @param {string} path - Path prefix
|
|
71
|
-
* @param {Object} [options] - Query options
|
|
72
|
-
* @returns {Promise<Object[]>} Array of data objects
|
|
73
|
-
*/
|
|
74
|
-
export async function readAll(client, path, options = {}) {
|
|
75
|
-
// Check if this is a GunDB client with backend methods (preferred - has write cache)
|
|
76
|
-
if (client.readAll && client.gun) {
|
|
77
|
-
return client.readAll(path, options);
|
|
78
|
-
}
|
|
79
|
-
// Fallback to direct gunWrapper
|
|
80
|
-
if (client.gun) {
|
|
81
|
-
return gunWrapper.readAll(client.gun, path);
|
|
82
|
-
}
|
|
83
|
-
return nostrWrapper.readAll(client, path, options);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Update data (merge fields)
|
|
88
|
-
* @param {Object} client - Client instance
|
|
89
|
-
* @param {string} path - Storage path
|
|
90
|
-
* @param {Object} updates - Fields to update
|
|
91
|
-
* @returns {Promise<boolean>} Success indicator
|
|
92
|
-
*/
|
|
93
|
-
export async function update(client, path, updates) {
|
|
94
|
-
// Check if this is a GunDB client with backend methods (preferred - has write cache)
|
|
95
|
-
if (client.update && client.gun) {
|
|
96
|
-
return client.update(path, updates);
|
|
97
|
-
}
|
|
98
|
-
// Fallback to direct gunWrapper
|
|
99
|
-
if (client.gun) {
|
|
100
|
-
return gunWrapper.update(client.gun, path, updates);
|
|
101
|
-
}
|
|
102
|
-
return nostrWrapper.update(client, path, updates);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Delete data at path
|
|
107
|
-
* @param {Object} client - Client instance
|
|
108
|
-
* @param {string} path - Storage path
|
|
109
|
-
* @param {Object} [options] - Delete options
|
|
110
|
-
* @param {string} [options.signingKey] - Private key for signing tombstones (hex format)
|
|
111
|
-
* @param {string} [options.authorPubkey] - Public key of the data author
|
|
112
|
-
* @returns {Promise<boolean>} Success indicator
|
|
113
|
-
*/
|
|
114
|
-
export async function deleteData(client, path, options = {}) {
|
|
115
|
-
// Check if this is a GunDB client with backend methods (preferred - has write cache)
|
|
116
|
-
if (client.delete && client.gun) {
|
|
117
|
-
return client.delete(path);
|
|
118
|
-
}
|
|
119
|
-
// Fallback to direct gunWrapper
|
|
120
|
-
if (client.gun) {
|
|
121
|
-
return gunWrapper.deleteData(client.gun, path);
|
|
122
|
-
}
|
|
123
|
-
return nostrWrapper.deleteData(client, path, options);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Delete all data under path prefix
|
|
128
|
-
* @param {Object} client - Client instance
|
|
129
|
-
* @param {string} path - Path prefix
|
|
130
|
-
* @param {Object} [options] - Delete options
|
|
131
|
-
* @param {string} [options.signingKey] - Private key for signing tombstones (hex format)
|
|
132
|
-
* @param {string} [options.authorPubkey] - Public key of the data author
|
|
133
|
-
* @returns {Promise<Object>} Deletion results
|
|
134
|
-
*/
|
|
135
|
-
export async function deleteAll(client, path, options = {}) {
|
|
136
|
-
// Fallback to direct gunWrapper (deleteAll not typically in client interface)
|
|
137
|
-
if (client.gun) {
|
|
138
|
-
return gunWrapper.deleteAll(client.gun, path);
|
|
139
|
-
}
|
|
140
|
-
return nostrWrapper.deleteAll(client, path, options);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Subscribe to data changes
|
|
145
|
-
* @param {Object} client - Client instance
|
|
146
|
-
* @param {string} path - Path or path prefix
|
|
147
|
-
* @param {Function} callback - Called on changes
|
|
148
|
-
* @param {Object} [options] - Subscription options
|
|
149
|
-
* @returns {Object} Subscription with unsubscribe method
|
|
150
|
-
*/
|
|
151
|
-
export function subscribe(client, path, callback, options = {}) {
|
|
152
|
-
// Check if this is a GunDB client with backend methods
|
|
153
|
-
if (client.subscribe && client.gun) {
|
|
154
|
-
return client.subscribe(path, callback, options);
|
|
155
|
-
}
|
|
156
|
-
// Fallback to direct gunWrapper
|
|
157
|
-
if (client.gun) {
|
|
158
|
-
return gunWrapper.subscribe(client.gun, path, callback, options);
|
|
159
|
-
}
|
|
160
|
-
return nostrWrapper.subscribe(client, path, callback, options);
|
|
161
|
-
}
|