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.
Files changed (69) hide show
  1. package/README.md +1 -2
  2. package/dist/cjs/holosphere.cjs +1 -1
  3. package/dist/esm/holosphere.js +61 -58
  4. package/dist/{index-B6-8KAQm.js → index-BEkCLOwI.js} +2 -2
  5. package/dist/{index-B6-8KAQm.js.map → index-BEkCLOwI.js.map} +1 -1
  6. package/dist/{index-D2WstuZJ.js → index-BEvX6DxG.js} +2 -2
  7. package/dist/{index-D2WstuZJ.js.map → index-BEvX6DxG.js.map} +1 -1
  8. package/dist/{index--QsHG_gD.cjs → index-BGTOiJ2Y.cjs} +2 -2
  9. package/dist/{index--QsHG_gD.cjs.map → index-BGTOiJ2Y.cjs.map} +1 -1
  10. package/dist/{index-COpLk9gL.cjs → index-BH1woZXL.cjs} +2 -2
  11. package/dist/{index-COpLk9gL.cjs.map → index-BH1woZXL.cjs.map} +1 -1
  12. package/dist/{index-BHptWysv.js → index-Cvxov2jv.js} +2970 -7753
  13. package/dist/index-Cvxov2jv.js.map +1 -0
  14. package/dist/index-vTKI_BAX.cjs +29 -0
  15. package/dist/index-vTKI_BAX.cjs.map +1 -0
  16. package/dist/{indexeddb-storage-wKG4mICM.cjs → indexeddb-storage-BmnCNnSg.cjs} +2 -2
  17. package/dist/{indexeddb-storage-wKG4mICM.cjs.map → indexeddb-storage-BmnCNnSg.cjs.map} +1 -1
  18. package/dist/{indexeddb-storage-kQ53UHEE.js → indexeddb-storage-MIFisaPy.js} +2 -2
  19. package/dist/{indexeddb-storage-kQ53UHEE.js.map → indexeddb-storage-MIFisaPy.js.map} +1 -1
  20. package/dist/{memory-storage-CGC8xM2G.cjs → memory-storage-BJjK3F4r.cjs} +2 -2
  21. package/dist/{memory-storage-CGC8xM2G.cjs.map → memory-storage-BJjK3F4r.cjs.map} +1 -1
  22. package/dist/{memory-storage-DnXCSbBl.js → memory-storage-DhHXdKQ-.js} +2 -2
  23. package/dist/{memory-storage-DnXCSbBl.js.map → memory-storage-DhHXdKQ-.js.map} +1 -1
  24. package/examples/demo.html +2 -29
  25. package/package.json +3 -8
  26. package/src/content/social-protocols.js +3 -59
  27. package/src/core/holosphere.js +16 -554
  28. package/src/crypto/nostr-utils.js +98 -1
  29. package/src/crypto/secp256k1.js +4 -393
  30. package/src/federation/discovery.js +7 -75
  31. package/src/federation/handshake.js +69 -202
  32. package/src/federation/hologram.js +222 -298
  33. package/src/federation/index.js +2 -9
  34. package/src/federation/registry.js +67 -1257
  35. package/src/federation/request-card.js +21 -35
  36. package/src/hierarchical/upcast.js +4 -9
  37. package/src/index.js +145 -296
  38. package/src/lib/federation-methods.js +370 -909
  39. package/src/storage/global-tables.js +1 -1
  40. package/src/storage/nostr-wrapper.js +9 -5
  41. package/src/subscriptions/manager.js +1 -1
  42. package/types/index.d.ts +145 -37
  43. package/bin/holosphere-activitypub.js +0 -158
  44. package/dist/2019-BzVkRcax.js +0 -6680
  45. package/dist/2019-BzVkRcax.js.map +0 -1
  46. package/dist/2019-C1hPR_Os.cjs +0 -8
  47. package/dist/2019-C1hPR_Os.cjs.map +0 -1
  48. package/dist/browser-BcmACE3G.js +0 -3058
  49. package/dist/browser-BcmACE3G.js.map +0 -1
  50. package/dist/browser-DaqYUTcG.cjs +0 -2
  51. package/dist/browser-DaqYUTcG.cjs.map +0 -1
  52. package/dist/index-BHptWysv.js.map +0 -1
  53. package/dist/index-CDlhzxT2.cjs +0 -29
  54. package/dist/index-CDlhzxT2.cjs.map +0 -1
  55. package/src/federation/capabilities.js +0 -46
  56. package/src/storage/backend-factory.js +0 -130
  57. package/src/storage/backend-interface.js +0 -161
  58. package/src/storage/backends/activitypub/server.js +0 -675
  59. package/src/storage/backends/activitypub-backend.js +0 -295
  60. package/src/storage/backends/gundb-backend.js +0 -875
  61. package/src/storage/backends/nostr-backend.js +0 -251
  62. package/src/storage/gun-async.js +0 -341
  63. package/src/storage/gun-auth.js +0 -373
  64. package/src/storage/gun-federation.js +0 -785
  65. package/src/storage/gun-references.js +0 -209
  66. package/src/storage/gun-schema.js +0 -306
  67. package/src/storage/gun-wrapper.js +0 -642
  68. package/src/storage/migration.js +0 -351
  69. package/src/storage/unified-storage.js +0 -161
@@ -1,251 +0,0 @@
1
- /**
2
- * @fileoverview Nostr Storage Backend.
3
- *
4
- * Wraps existing nostr-wrapper.js and nostr-client.js as a StorageBackend
5
- * implementation. Provides Nostr-based distributed storage with relay support.
6
- *
7
- * @module storage/backends/nostr-backend
8
- */
9
-
10
- import { StorageBackend } from '../backend-interface.js';
11
- import { createClient } from '../nostr-client.js';
12
- import * as wrapper from '../nostr-wrapper.js';
13
-
14
- /**
15
- * Nostr storage backend implementation.
16
- *
17
- * Provides distributed storage using Nostr relays with event-based data storage.
18
- *
19
- * @class NostrBackend
20
- * @extends StorageBackend
21
- * @example
22
- * const backend = new NostrBackend({
23
- * relays: ['wss://relay.example.com'],
24
- * appName: 'myapp',
25
- * persistence: true
26
- * });
27
- * await backend.init();
28
- */
29
- export class NostrBackend extends StorageBackend {
30
- /**
31
- * Create a new NostrBackend.
32
- *
33
- * @param {Object} config - Backend configuration
34
- * @param {string[]} [config.relays] - Relay URLs
35
- * @param {string} [config.privateKey] - Private key for signing
36
- * @param {string} [config.appName] - Application name
37
- * @param {boolean} [config.persistence=true] - Enable persistent storage
38
- * @param {boolean} [config.backgroundSync] - Enable background sync
39
- */
40
- constructor(config) {
41
- super(config);
42
- this.client = null;
43
- }
44
-
45
- /**
46
- * Initialize the backend.
47
- *
48
- * @returns {Promise<void>}
49
- */
50
- async init() {
51
- this.client = createClient({
52
- relays: this.config.relays || ['wss://relay.holons.io'],
53
- privateKey: this.config.privateKey,
54
- enableReconnect: this.config.enableReconnect !== false,
55
- enablePing: this.config.enablePing !== false,
56
- appName: this.config.appName,
57
- radisk: this.config.radisk !== false,
58
- persistence: this.config.persistence !== false,
59
- dataDir: this.config.dataDir,
60
- backgroundSync: this.config.backgroundSync,
61
- syncInterval: this.config.syncInterval,
62
- });
63
-
64
- // Wait for client initialization
65
- await this.client._initReady;
66
- this.publicKey = this.client.publicKey;
67
- }
68
-
69
- /**
70
- * Build path from components.
71
- *
72
- * @param {string} appName - Application name
73
- * @param {string} holonId - Holon ID
74
- * @param {string} lensName - Lens name
75
- * @param {string} [key=null] - Optional key
76
- * @returns {string} Built path
77
- */
78
- buildPath(appName, holonId, lensName, key = null) {
79
- return wrapper.buildPath(appName, holonId, lensName, key);
80
- }
81
-
82
- /**
83
- * Write data to path.
84
- *
85
- * @param {string} path - Storage path
86
- * @param {Object} data - Data to write
87
- * @param {Object} [options={}] - Write options
88
- * @returns {Promise<Object>} Write result
89
- */
90
- async write(path, data, options = {}) {
91
- return wrapper.write(this.client, path, data);
92
- }
93
-
94
- /**
95
- * Read data from path.
96
- *
97
- * @param {string} path - Storage path
98
- * @param {Object} [options={}] - Read options
99
- * @returns {Promise<Object|null>} Data or null
100
- */
101
- async read(path, options = {}) {
102
- return wrapper.read(this.client, path, options);
103
- }
104
-
105
- /**
106
- * Read all data under path.
107
- *
108
- * @param {string} path - Storage path prefix
109
- * @param {Object} [options={}] - Read options
110
- * @returns {Promise<Object[]>} Array of data objects
111
- */
112
- async readAll(path, options = {}) {
113
- return wrapper.readAll(this.client, path, options);
114
- }
115
-
116
- /**
117
- * Update data at path.
118
- *
119
- * @param {string} path - Storage path
120
- * @param {Object} updates - Fields to update
121
- * @returns {Promise<Object>} Update result
122
- */
123
- async update(path, updates) {
124
- return wrapper.update(this.client, path, updates);
125
- }
126
-
127
- /**
128
- * Delete data at path.
129
- *
130
- * @param {string} path - Storage path
131
- * @returns {Promise<boolean>} Success indicator
132
- */
133
- async delete(path) {
134
- return wrapper.deleteData(this.client, path);
135
- }
136
-
137
- /**
138
- * Delete all data under path.
139
- *
140
- * @param {string} path - Storage path prefix
141
- * @returns {Promise<Object>} Deletion results
142
- */
143
- async deleteAll(path) {
144
- return wrapper.deleteAll(this.client, path);
145
- }
146
-
147
- /**
148
- * Subscribe to changes at path.
149
- *
150
- * @param {string} path - Storage path
151
- * @param {Function} callback - Callback function
152
- * @param {Object} [options={}] - Subscribe options
153
- * @returns {Promise<Object>} Subscription object with unsubscribe method
154
- */
155
- async subscribe(path, callback, options = {}) {
156
- return wrapper.subscribe(this.client, path, callback, options);
157
- }
158
-
159
- /**
160
- * Export all data for this user.
161
- *
162
- * @param {string} [pathPrefix=''] - Optional path prefix filter
163
- * @returns {Promise<Object[]>} Array of exported records
164
- */
165
- async exportData(pathPrefix = '') {
166
- // Wait for client to be ready
167
- await this.client._initReady;
168
-
169
- // Query all events for this author
170
- const events = await this.client.query({
171
- kinds: [30000],
172
- authors: [this.publicKey],
173
- limit: 10000,
174
- });
175
-
176
- return events
177
- .filter(e => {
178
- const dTag = e.tags.find(t => t[0] === 'd');
179
- if (!dTag) return false;
180
- // Filter by prefix if provided
181
- if (pathPrefix && !dTag[1].startsWith(pathPrefix)) return false;
182
- return true;
183
- })
184
- .map(e => {
185
- const dTag = e.tags.find(t => t[0] === 'd');
186
- let data;
187
- try {
188
- data = JSON.parse(e.content);
189
- } catch {
190
- data = { content: e.content };
191
- }
192
- return {
193
- path: dTag[1],
194
- data,
195
- timestamp: e.created_at * 1000,
196
- author: e.pubkey,
197
- };
198
- })
199
- .filter(record => !record.data._deleted); // Filter out deleted items
200
- }
201
-
202
- /**
203
- * Import data records.
204
- *
205
- * @param {Object[]} records - Array of records to import
206
- * @param {Object} [options={}] - Import options
207
- * @returns {Promise<Object>} Import results with success/failed counts
208
- */
209
- async importData(records, options = {}) {
210
- const results = { success: 0, failed: 0, errors: [] };
211
-
212
- for (const record of records) {
213
- try {
214
- await wrapper.write(this.client, record.path, record.data);
215
- results.success++;
216
- } catch (error) {
217
- results.failed++;
218
- results.errors.push({ path: record.path, error: error.message });
219
- }
220
- }
221
-
222
- return results;
223
- }
224
-
225
- /**
226
- * Close the backend and cleanup resources.
227
- *
228
- * @returns {void}
229
- */
230
- close() {
231
- if (this.client) {
232
- this.client.close();
233
- }
234
- }
235
-
236
- /**
237
- * Get backend status.
238
- *
239
- * @returns {Object} Status object with type, publicKey, relays, connected
240
- */
241
- getStatus() {
242
- return {
243
- type: 'nostr',
244
- publicKey: this.publicKey,
245
- relays: this.config.relays || [],
246
- connected: !!this.client,
247
- };
248
- }
249
- }
250
-
251
- export default NostrBackend;
@@ -1,341 +0,0 @@
1
- /**
2
- * @fileoverview Gun Async Utilities.
3
- *
4
- * Provides Promise-based wrappers and async patterns for Gun operations.
5
- * Includes utilities for promises, batch operations, retries, streams, and async iteration.
6
- *
7
- * @module storage/gun-async
8
- */
9
-
10
- /**
11
- * Get data from Gun using native .then() support.
12
- *
13
- * @param {Object} gunChain - Gun chain reference
14
- * @param {number} [timeout=1000] - Timeout in ms
15
- * @returns {Promise<any>} Promise resolving to data or null on timeout
16
- */
17
- export function gunPromise(gunChain, timeout = 1000) {
18
- return new Promise((resolve, reject) => {
19
- let settled = false;
20
-
21
- const timer = setTimeout(() => {
22
- if (!settled) {
23
- settled = true;
24
- resolve(null);
25
- }
26
- }, timeout);
27
-
28
- gunChain.once((data) => {
29
- if (!settled) {
30
- settled = true;
31
- clearTimeout(timer);
32
- resolve(data || null);
33
- }
34
- });
35
- });
36
- }
37
-
38
- /**
39
- * Wait for Gun write acknowledgement.
40
- *
41
- * @param {Object} gunChain - Gun chain reference
42
- * @param {any} data - Data to write
43
- * @param {number} [timeout=1000] - Timeout in ms
44
- * @returns {Promise<Object>} Promise resolving to ack object { ok, timeout? }
45
- * @throws {Error} If write fails with error
46
- */
47
- export function gunPut(gunChain, data, timeout = 1000) {
48
- return new Promise((resolve, reject) => {
49
- let settled = false;
50
-
51
- const timer = setTimeout(() => {
52
- if (!settled) {
53
- settled = true;
54
- resolve({ ok: true, timeout: true });
55
- }
56
- }, timeout);
57
-
58
- gunChain.put(data, (ack) => {
59
- if (!settled) {
60
- settled = true;
61
- clearTimeout(timer);
62
- if (ack.err) {
63
- reject(new Error(ack.err));
64
- } else {
65
- resolve(ack);
66
- }
67
- }
68
- });
69
- });
70
- }
71
-
72
- /**
73
- * Get all items from a Gun map.
74
- *
75
- * First gets count of items, then collects until count is reached.
76
- *
77
- * @param {Object} gunChain - Gun chain reference
78
- * @param {number} [timeout=5000] - Timeout in ms (fallback)
79
- * @returns {Promise<Object>} Promise resolving to map of items
80
- */
81
- export async function gunMap(gunChain, timeout = 5000) {
82
- return new Promise((resolve) => {
83
- const items = {};
84
- let settled = false;
85
- let expectedCount = 0;
86
- let receivedCount = 0;
87
-
88
- const tryResolve = () => {
89
- if (settled) return;
90
- if (expectedCount > 0 && receivedCount >= expectedCount) {
91
- settled = true;
92
- resolve(items);
93
- }
94
- };
95
-
96
- // Step 1: Get parent to count expected items
97
- gunChain.once((parentData) => {
98
- if (settled) return;
99
-
100
- if (!parentData) {
101
- settled = true;
102
- resolve({});
103
- return;
104
- }
105
-
106
- const keys = Object.keys(parentData).filter(k => k !== '_');
107
- if (keys.length === 0) {
108
- settled = true;
109
- resolve({});
110
- return;
111
- }
112
-
113
- // Pre-collect inline items (not Gun references)
114
- for (const key of keys) {
115
- const rawItem = parentData[key];
116
- if (!rawItem) continue;
117
-
118
- // Skip Gun references - will be fetched via map().once()
119
- if (typeof rawItem === 'object' && rawItem['#']) continue;
120
-
121
- items[key] = rawItem;
122
- }
123
-
124
- // Expected count is ALL keys (map().once() fires for all)
125
- expectedCount = keys.length;
126
-
127
- // Step 2: Collect items via map().once(), counting as we go
128
- gunChain.map().once((data, key) => {
129
- if (settled || !data || key.startsWith('_')) return;
130
- // Add/update the item (inline items may be updated by map().once())
131
- items[key] = data;
132
- receivedCount++;
133
- tryResolve();
134
- });
135
- });
136
-
137
- // Fallback timeout
138
- setTimeout(() => {
139
- if (!settled) {
140
- settled = true;
141
- resolve(items);
142
- }
143
- }, timeout);
144
- });
145
- }
146
-
147
- /**
148
- * Load full chain data (follows all references)
149
- * @param {Object} gunChain - Gun chain reference
150
- * @param {number} depth - Max depth to traverse (default 3)
151
- * @returns {Promise<any>} Promise resolving to loaded data
152
- */
153
- export async function gunLoad(gunChain, depth = 3) {
154
- return new Promise((resolve) => {
155
- let result = null;
156
-
157
- gunChain.load((data) => {
158
- result = data;
159
- }, { wait: 100 });
160
-
161
- setTimeout(() => {
162
- resolve(result);
163
- }, 100 * depth);
164
- });
165
- }
166
-
167
- /**
168
- * Async iterator for Gun map
169
- * @param {Object} gunChain - Gun chain reference
170
- * @returns {AsyncGenerator} Async generator yielding [key, value] pairs
171
- */
172
- export async function* gunMapIterator(gunChain) {
173
- const items = await gunMap(gunChain);
174
- for (const [key, value] of Object.entries(items)) {
175
- yield [key, value];
176
- }
177
- }
178
-
179
- /**
180
- * Collect Gun on() stream into array over time
181
- * @param {Object} gunChain - Gun chain reference
182
- * @param {number} duration - Collection duration in ms
183
- * @returns {Promise<Array>} Promise resolving to array of data
184
- */
185
- export async function gunCollect(gunChain, duration = 500) {
186
- return new Promise((resolve) => {
187
- const results = [];
188
- const seen = new Set();
189
-
190
- const listener = gunChain.on((data, key) => {
191
- if (data && !seen.has(key)) {
192
- seen.add(key);
193
- results.push({ key, data });
194
- }
195
- });
196
-
197
- setTimeout(() => {
198
- listener.off();
199
- resolve(results);
200
- }, duration);
201
- });
202
- }
203
-
204
- /**
205
- * Wait for specific condition on Gun data
206
- * @param {Object} gunChain - Gun chain reference
207
- * @param {Function} predicate - Condition function (data) => boolean
208
- * @param {number} timeout - Timeout in ms (default 5000ms)
209
- * @returns {Promise<any>} Promise resolving when condition is met
210
- */
211
- export async function gunWaitFor(gunChain, predicate, timeout = 5000) {
212
- return new Promise((resolve, reject) => {
213
- let timeoutId;
214
- let listener;
215
-
216
- const cleanup = () => {
217
- if (timeoutId) clearTimeout(timeoutId);
218
- if (listener) listener.off();
219
- };
220
-
221
- listener = gunChain.on((data) => {
222
- if (predicate(data)) {
223
- cleanup();
224
- resolve(data);
225
- }
226
- });
227
-
228
- timeoutId = setTimeout(() => {
229
- cleanup();
230
- reject(new Error('Timeout waiting for condition'));
231
- }, timeout);
232
- });
233
- }
234
-
235
- /**
236
- * Batch read multiple Gun paths
237
- * @param {Object} gun - Gun instance
238
- * @param {string[]} paths - Array of paths to read
239
- * @returns {Promise<Object>} Object mapping paths to data
240
- */
241
- export async function gunBatchGet(gun, paths) {
242
- const promises = paths.map(async (path) => {
243
- const data = await gunPromise(gun.get(path));
244
- return [path, data];
245
- });
246
-
247
- const results = await Promise.all(promises);
248
- return Object.fromEntries(results);
249
- }
250
-
251
- /**
252
- * Batch write multiple Gun paths
253
- * @param {Object} gun - Gun instance
254
- * @param {Object} pathDataMap - Object mapping paths to data
255
- * @returns {Promise<Object>} Object mapping paths to ack results
256
- */
257
- export async function gunBatchPut(gun, pathDataMap) {
258
- const promises = Object.entries(pathDataMap).map(async ([path, data]) => {
259
- const ack = await gunPut(gun.get(path), data);
260
- return [path, ack];
261
- });
262
-
263
- const results = await Promise.all(promises);
264
- return Object.fromEntries(results);
265
- }
266
-
267
- /**
268
- * Retry Gun operation with exponential backoff
269
- * @param {Function} operation - Async function to retry
270
- * @param {number} maxRetries - Max retry attempts (default 3)
271
- * @param {number} baseDelay - Base delay in ms (default 100ms)
272
- * @returns {Promise<any>} Promise resolving to operation result
273
- */
274
- export async function gunRetry(operation, maxRetries = 3, baseDelay = 100) {
275
- let lastError;
276
-
277
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
278
- try {
279
- return await operation();
280
- } catch (error) {
281
- lastError = error;
282
- if (attempt < maxRetries) {
283
- const delay = baseDelay * Math.pow(2, attempt);
284
- await new Promise((resolve) => setTimeout(resolve, delay));
285
- }
286
- }
287
- }
288
-
289
- throw lastError;
290
- }
291
-
292
- /**
293
- * Create async stream from Gun on() callback
294
- * @param {Object} gunChain - Gun chain reference
295
- * @returns {Object} Stream object with async iteration support
296
- */
297
- export function gunStream(gunChain) {
298
- let listeners = [];
299
- let buffer = [];
300
- let ended = false;
301
-
302
- const stream = {
303
- [Symbol.asyncIterator]() {
304
- return {
305
- async next() {
306
- if (buffer.length > 0) {
307
- return { value: buffer.shift(), done: false };
308
- }
309
-
310
- if (ended) {
311
- return { done: true };
312
- }
313
-
314
- // Wait for next value
315
- return new Promise((resolve) => {
316
- listeners.push((data) => {
317
- resolve({ value: data, done: false });
318
- });
319
- });
320
- },
321
- };
322
- },
323
-
324
- stop() {
325
- ended = true;
326
- if (this.listener) this.listener.off();
327
- },
328
- };
329
-
330
- stream.listener = gunChain.on((data, key) => {
331
- const item = { key, data };
332
- if (listeners.length > 0) {
333
- const listener = listeners.shift();
334
- listener(item);
335
- } else {
336
- buffer.push(item);
337
- }
338
- });
339
-
340
- return stream;
341
- }