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/gun-auth.js
DELETED
|
@@ -1,373 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview GunDB Authentication Handler.
|
|
3
|
-
*
|
|
4
|
-
* Handles user authentication and private data storage using Gun's user system.
|
|
5
|
-
* Private data is stored under: user.get('private').get(lens).get(key)
|
|
6
|
-
* Usernames are namespaced: ${appname}:${holonId}
|
|
7
|
-
*
|
|
8
|
-
* @module storage/gun-auth
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { gunPromise, gunPut } from './gun-async.js';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Authentication handler for GunDB backend.
|
|
15
|
-
*
|
|
16
|
-
* Manages user creation, authentication, and private data access.
|
|
17
|
-
*
|
|
18
|
-
* @class GunAuth
|
|
19
|
-
* @example
|
|
20
|
-
* const auth = new GunAuth(gun, 'myapp');
|
|
21
|
-
* await auth.createUser('holon123', 'password');
|
|
22
|
-
* await auth.authenticate('holon123', 'password');
|
|
23
|
-
*/
|
|
24
|
-
export class GunAuth {
|
|
25
|
-
/**
|
|
26
|
-
* Create a new authentication handler.
|
|
27
|
-
*
|
|
28
|
-
* @param {Object} gun - Gun instance
|
|
29
|
-
* @param {string} appname - Application namespace
|
|
30
|
-
*/
|
|
31
|
-
constructor(gun, appname) {
|
|
32
|
-
this.gun = gun;
|
|
33
|
-
this.appname = appname;
|
|
34
|
-
this.user = null;
|
|
35
|
-
this.authenticated = false;
|
|
36
|
-
this.currentHolonId = null;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Generate a namespaced username for a holon
|
|
41
|
-
* @param {string} holonId - Holon ID
|
|
42
|
-
* @returns {string} Namespaced username
|
|
43
|
-
*/
|
|
44
|
-
userName(holonId) {
|
|
45
|
-
return `${this.appname}:${holonId}`;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Authenticate a user for a specific holon
|
|
50
|
-
* @param {string} holonId - Holon ID
|
|
51
|
-
* @param {string} password - Password
|
|
52
|
-
* @returns {Promise<Object>} Authenticated user object
|
|
53
|
-
*/
|
|
54
|
-
async authenticate(holonId, password) {
|
|
55
|
-
if (!holonId || !password) {
|
|
56
|
-
throw new Error('authenticate: holonId and password are required');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const username = this.userName(holonId);
|
|
60
|
-
this.user = this.gun.user();
|
|
61
|
-
|
|
62
|
-
return new Promise((resolve, reject) => {
|
|
63
|
-
this.user.auth(username, password, (ack) => {
|
|
64
|
-
if (ack.err) {
|
|
65
|
-
this.authenticated = false;
|
|
66
|
-
this.currentHolonId = null;
|
|
67
|
-
reject(new Error(ack.err));
|
|
68
|
-
} else {
|
|
69
|
-
this.authenticated = true;
|
|
70
|
-
this.currentHolonId = holonId;
|
|
71
|
-
resolve(this.user);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Create a new user for a holon
|
|
79
|
-
* @param {string} holonId - Holon ID
|
|
80
|
-
* @param {string} password - Password
|
|
81
|
-
* @returns {Promise<Object>} Created user object
|
|
82
|
-
*/
|
|
83
|
-
async createUser(holonId, password) {
|
|
84
|
-
if (!holonId || !password) {
|
|
85
|
-
throw new Error('createUser: holonId and password are required');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const username = this.userName(holonId);
|
|
89
|
-
this.user = this.gun.user();
|
|
90
|
-
|
|
91
|
-
return new Promise((resolve, reject) => {
|
|
92
|
-
this.user.create(username, password, (ack) => {
|
|
93
|
-
if (ack.err) {
|
|
94
|
-
reject(new Error(ack.err));
|
|
95
|
-
} else {
|
|
96
|
-
// Auto-login after creation
|
|
97
|
-
this.user.auth(username, password, (authAck) => {
|
|
98
|
-
if (authAck.err) {
|
|
99
|
-
reject(new Error(authAck.err));
|
|
100
|
-
} else {
|
|
101
|
-
this.authenticated = true;
|
|
102
|
-
this.currentHolonId = holonId;
|
|
103
|
-
resolve(this.user);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Logout current user
|
|
113
|
-
*/
|
|
114
|
-
logout() {
|
|
115
|
-
if (this.user) {
|
|
116
|
-
this.user.leave();
|
|
117
|
-
}
|
|
118
|
-
this.authenticated = false;
|
|
119
|
-
this.currentHolonId = null;
|
|
120
|
-
this.user = null;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Check if currently authenticated
|
|
125
|
-
* @returns {boolean} True if authenticated
|
|
126
|
-
*/
|
|
127
|
-
isAuthenticated() {
|
|
128
|
-
return this.authenticated && this.user !== null;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Get the private data path for a lens and key
|
|
133
|
-
* @param {string} lens - Lens name
|
|
134
|
-
* @param {string} key - Data key (optional)
|
|
135
|
-
* @returns {Object} Gun chain reference
|
|
136
|
-
*/
|
|
137
|
-
getPrivatePath(lens, key = null) {
|
|
138
|
-
if (!this.isAuthenticated()) {
|
|
139
|
-
throw new Error('Not authenticated');
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const basePath = this.user.get('private').get(lens);
|
|
143
|
-
return key ? basePath.get(key) : basePath;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Write data to private storage
|
|
148
|
-
* @param {string} lens - Lens name
|
|
149
|
-
* @param {string} key - Data key
|
|
150
|
-
* @param {Object} data - Data to write
|
|
151
|
-
* @returns {Promise<boolean>} Success indicator
|
|
152
|
-
*/
|
|
153
|
-
async writePrivate(lens, key, data) {
|
|
154
|
-
if (!this.isAuthenticated()) {
|
|
155
|
-
throw new Error('Not authenticated');
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (!data || !key) {
|
|
159
|
-
throw new Error('writePrivate: key and data are required');
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
try {
|
|
163
|
-
const serialized = JSON.stringify(data);
|
|
164
|
-
await gunPut(this.getPrivatePath(lens, key), serialized, 2000);
|
|
165
|
-
return true;
|
|
166
|
-
} catch (error) {
|
|
167
|
-
throw error;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Read data from private storage
|
|
173
|
-
* @param {string} lens - Lens name
|
|
174
|
-
* @param {string} key - Data key
|
|
175
|
-
* @returns {Promise<Object|null>} Data or null if not found
|
|
176
|
-
*/
|
|
177
|
-
async readPrivate(lens, key) {
|
|
178
|
-
if (!this.isAuthenticated()) {
|
|
179
|
-
throw new Error('Not authenticated');
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
try {
|
|
183
|
-
const rawData = await gunPromise(this.getPrivatePath(lens, key), 2000);
|
|
184
|
-
|
|
185
|
-
if (!rawData) {
|
|
186
|
-
return null;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Deserialize - primary format is JSON string (like old holosphere)
|
|
190
|
-
if (typeof rawData === 'string') {
|
|
191
|
-
try {
|
|
192
|
-
return JSON.parse(rawData);
|
|
193
|
-
} catch (e) {
|
|
194
|
-
return rawData; // Return as-is if not valid JSON
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Legacy _json wrapper format
|
|
199
|
-
if (rawData._json && typeof rawData._json === 'string') {
|
|
200
|
-
try {
|
|
201
|
-
return JSON.parse(rawData._json);
|
|
202
|
-
} catch (e) {
|
|
203
|
-
return null;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Plain object format
|
|
208
|
-
if (typeof rawData === 'object') {
|
|
209
|
-
const cleaned = { ...rawData };
|
|
210
|
-
delete cleaned['_'];
|
|
211
|
-
return cleaned;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return null;
|
|
215
|
-
} catch (error) {
|
|
216
|
-
throw error;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Read all data from a private lens
|
|
222
|
-
* First gets count of items, then collects until count is reached
|
|
223
|
-
* @param {string} lens - Lens name
|
|
224
|
-
* @param {number} timeout - Timeout in ms (fallback)
|
|
225
|
-
* @returns {Promise<Object[]>} Array of data objects
|
|
226
|
-
*/
|
|
227
|
-
async readAllPrivate(lens, timeout = 5000) {
|
|
228
|
-
if (!this.isAuthenticated()) {
|
|
229
|
-
throw new Error('Not authenticated');
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return new Promise((resolve) => {
|
|
233
|
-
const results = [];
|
|
234
|
-
const seen = new Set();
|
|
235
|
-
const ref = this.getPrivatePath(lens);
|
|
236
|
-
let settled = false;
|
|
237
|
-
let expectedCount = 0;
|
|
238
|
-
let receivedCount = 0;
|
|
239
|
-
|
|
240
|
-
const tryResolve = () => {
|
|
241
|
-
if (settled) return;
|
|
242
|
-
if (expectedCount > 0 && receivedCount >= expectedCount) {
|
|
243
|
-
settled = true;
|
|
244
|
-
resolve(results);
|
|
245
|
-
}
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
const parseItem = (data) => {
|
|
249
|
-
if (!data) return null;
|
|
250
|
-
let parsed = null;
|
|
251
|
-
// Primary: JSON string format (like old holosphere)
|
|
252
|
-
if (typeof data === 'string') {
|
|
253
|
-
try {
|
|
254
|
-
parsed = JSON.parse(data);
|
|
255
|
-
} catch (e) {
|
|
256
|
-
parsed = data;
|
|
257
|
-
}
|
|
258
|
-
// Legacy: _json wrapper format
|
|
259
|
-
} else if (data._json && typeof data._json === 'string') {
|
|
260
|
-
try {
|
|
261
|
-
parsed = JSON.parse(data._json);
|
|
262
|
-
} catch (e) {}
|
|
263
|
-
// Plain object
|
|
264
|
-
} else if (typeof data === 'object') {
|
|
265
|
-
parsed = { ...data };
|
|
266
|
-
delete parsed['_'];
|
|
267
|
-
}
|
|
268
|
-
return parsed;
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
// Step 1: Get parent to count expected items
|
|
272
|
-
ref.once((parentData) => {
|
|
273
|
-
if (settled) return;
|
|
274
|
-
|
|
275
|
-
if (!parentData) {
|
|
276
|
-
settled = true;
|
|
277
|
-
resolve([]);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const keys = Object.keys(parentData).filter(k => k !== '_');
|
|
282
|
-
if (keys.length === 0) {
|
|
283
|
-
settled = true;
|
|
284
|
-
resolve([]);
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Pre-parse inline items (not Gun references)
|
|
289
|
-
for (const key of keys) {
|
|
290
|
-
const rawItem = parentData[key];
|
|
291
|
-
if (!rawItem) continue;
|
|
292
|
-
|
|
293
|
-
// Skip Gun references - will be fetched via map().once()
|
|
294
|
-
if (typeof rawItem === 'object' && rawItem['#']) continue;
|
|
295
|
-
|
|
296
|
-
const parsed = parseItem(rawItem);
|
|
297
|
-
if (parsed && !parsed._deleted && !seen.has(key)) {
|
|
298
|
-
seen.add(key);
|
|
299
|
-
results.push(parsed);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// Expected count is ALL keys (map().once() fires for all)
|
|
304
|
-
expectedCount = keys.length;
|
|
305
|
-
|
|
306
|
-
// Step 2: Collect items via map().once(), counting as we go
|
|
307
|
-
ref.map().once((data, key) => {
|
|
308
|
-
if (settled || !data || key.startsWith('_')) return;
|
|
309
|
-
|
|
310
|
-
// Count every item, but only add if not already seen
|
|
311
|
-
if (!seen.has(key)) {
|
|
312
|
-
seen.add(key);
|
|
313
|
-
const parsed = parseItem(data);
|
|
314
|
-
if (parsed && !parsed._deleted) {
|
|
315
|
-
results.push(parsed);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
receivedCount++;
|
|
319
|
-
tryResolve();
|
|
320
|
-
});
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
// Fallback timeout
|
|
324
|
-
setTimeout(() => {
|
|
325
|
-
if (!settled) {
|
|
326
|
-
settled = true;
|
|
327
|
-
resolve(results);
|
|
328
|
-
}
|
|
329
|
-
}, timeout);
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Delete data from private storage
|
|
335
|
-
* @param {string} lens - Lens name
|
|
336
|
-
* @param {string} key - Data key
|
|
337
|
-
* @returns {Promise<boolean>} Success indicator
|
|
338
|
-
*/
|
|
339
|
-
async deletePrivate(lens, key) {
|
|
340
|
-
if (!this.isAuthenticated()) {
|
|
341
|
-
throw new Error('Not authenticated');
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
try {
|
|
345
|
-
// Get existing data to preserve ID
|
|
346
|
-
const existing = await this.readPrivate(lens, key);
|
|
347
|
-
|
|
348
|
-
// Create tombstone
|
|
349
|
-
const tombstone = {
|
|
350
|
-
id: existing?.id || key,
|
|
351
|
-
_deleted: true,
|
|
352
|
-
_deletedAt: Date.now()
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
await gunPut(this.getPrivatePath(lens, key), JSON.stringify(tombstone));
|
|
356
|
-
return true;
|
|
357
|
-
} catch (error) {
|
|
358
|
-
throw error;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Create an authentication handler instance
|
|
365
|
-
* @param {Object} gun - Gun instance
|
|
366
|
-
* @param {string} appname - Application namespace
|
|
367
|
-
* @returns {GunAuth} Auth handler instance
|
|
368
|
-
*/
|
|
369
|
-
export function createAuthHandler(gun, appname) {
|
|
370
|
-
return new GunAuth(gun, appname);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
export default GunAuth;
|