holosphere 1.1.9 → 1.1.11
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/.cursor/rules/futura.mdc +55 -0
- package/FEDERATION.md +17 -17
- package/compute.js +289 -0
- package/content.js +797 -0
- package/examples/federation.js +98 -90
- package/examples/{references.js → holograms.js} +49 -51
- package/federation.js +307 -197
- package/global.js +560 -0
- package/hologram.js +156 -0
- package/holosphere.d.ts +94 -7
- package/holosphere.js +211 -1464
- package/node.js +155 -0
- package/package.json +2 -5
- package/schema.js +132 -0
- package/test/auth.test.js +85 -51
- package/test/delete.test.js +15 -11
- package/test/federation.test.js +179 -0
- package/test/hologram.test.js +316 -0
- package/test/holosphere.test.js +189 -5
- package/test/subscription.test.js +364 -0
- package/utils.js +290 -0
package/global.js
ADDED
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
// holo_global.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stores data in a global (non-holon-specific) table.
|
|
5
|
+
* @param {HoloSphere} holoInstance - The HoloSphere instance.
|
|
6
|
+
* @param {string} tableName - The table name to store data in.
|
|
7
|
+
* @param {object} data - The data to store. If it has an 'id' field, it will be used as the key.
|
|
8
|
+
* @param {string} [password] - Optional password for private holon.
|
|
9
|
+
* @returns {Promise<void>}
|
|
10
|
+
*/
|
|
11
|
+
export async function putGlobal(holoInstance, tableName, data, password = null) {
|
|
12
|
+
try {
|
|
13
|
+
if (!tableName || !data) {
|
|
14
|
+
throw new Error('Table name and data are required');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let user = null;
|
|
18
|
+
if (password) {
|
|
19
|
+
user = holoInstance.gun.user();
|
|
20
|
+
await new Promise((resolve, reject) => {
|
|
21
|
+
const userNameString = holoInstance.userName(tableName);
|
|
22
|
+
user.auth(userNameString, password, (authAck) => {
|
|
23
|
+
if (authAck.err) {
|
|
24
|
+
// If auth fails, try to create the user
|
|
25
|
+
console.log(`Initial auth failed for ${userNameString}, attempting to create...`);
|
|
26
|
+
user.create(userNameString, password, (createAck) => {
|
|
27
|
+
if (createAck.err) {
|
|
28
|
+
// Check if error is "User already created"
|
|
29
|
+
if (createAck.err.includes("already created")) {
|
|
30
|
+
// This means user exists but password might be wrong, or some other issue
|
|
31
|
+
// Proceed with auth again, it might have been a temporary glitch or race.
|
|
32
|
+
// Or, it could be that the password is indeed wrong.
|
|
33
|
+
console.log(`User ${userNameString} already existed, re-attempting auth with fresh user object.`);
|
|
34
|
+
const freshUser = holoInstance.gun.user(); // Get a new user object
|
|
35
|
+
freshUser.auth(userNameString, password, (secondAuthAck) => {
|
|
36
|
+
if (secondAuthAck.err) {
|
|
37
|
+
reject(new Error(`Failed to auth with fresh user object after create attempt (user existed): ${secondAuthAck.err}`));
|
|
38
|
+
} else {
|
|
39
|
+
resolve();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
reject(new Error(`Failed to create user ${userNameString}: ${createAck.err}`));
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
// After successful creation, authenticate again
|
|
47
|
+
console.log(`User ${userNameString} created successfully, attempting auth...`);
|
|
48
|
+
user.auth(userNameString, password, (secondAuthAck) => {
|
|
49
|
+
if (secondAuthAck.err) {
|
|
50
|
+
reject(new Error(`Failed to auth after create for ${userNameString}: ${secondAuthAck.err}`));
|
|
51
|
+
} else {
|
|
52
|
+
resolve();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
} else {
|
|
58
|
+
resolve(); // Auth successful
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
try {
|
|
66
|
+
// Remove isHologram field before storing - NO LONGER NEEDED
|
|
67
|
+
// if (data && data.isHologram !== undefined) {
|
|
68
|
+
// delete data.isHologram;
|
|
69
|
+
// }
|
|
70
|
+
const payload = JSON.stringify(data);
|
|
71
|
+
|
|
72
|
+
const dataPath = password ?
|
|
73
|
+
user.get('private').get(tableName) :
|
|
74
|
+
holoInstance.gun.get(holoInstance.appname).get(tableName);
|
|
75
|
+
|
|
76
|
+
if (data.id) {
|
|
77
|
+
const itemPath = dataPath.get(data.id);
|
|
78
|
+
itemPath.put(payload, ack => {
|
|
79
|
+
if (ack.err) {
|
|
80
|
+
reject(new Error(ack.err));
|
|
81
|
+
} else {
|
|
82
|
+
resolve();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
} else {
|
|
86
|
+
dataPath.put(payload, ack => {
|
|
87
|
+
if (ack.err) {
|
|
88
|
+
reject(new Error(ack.err));
|
|
89
|
+
} else {
|
|
90
|
+
resolve();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
reject(error);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('Error in putGlobal:', error);
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Retrieves a specific key from a global table.
|
|
106
|
+
* @param {HoloSphere} holoInstance - The HoloSphere instance.
|
|
107
|
+
* @param {string} tableName - The table name to retrieve from.
|
|
108
|
+
* @param {string} key - The key to retrieve.
|
|
109
|
+
* @param {string} [password] - Optional password for private holon.
|
|
110
|
+
* @returns {Promise<object|null>} - The parsed data for the key or null if not found.
|
|
111
|
+
*/
|
|
112
|
+
export async function getGlobal(holoInstance, tableName, key, password = null) {
|
|
113
|
+
try {
|
|
114
|
+
let user = null;
|
|
115
|
+
if (password) {
|
|
116
|
+
user = holoInstance.gun.user();
|
|
117
|
+
await new Promise((resolve, reject) => {
|
|
118
|
+
const userNameString = holoInstance.userName(tableName);
|
|
119
|
+
user.auth(userNameString, password, (authAck) => {
|
|
120
|
+
if (authAck.err) {
|
|
121
|
+
// If auth fails, try to create the user
|
|
122
|
+
console.log(`Initial auth failed for ${userNameString}, attempting to create...`);
|
|
123
|
+
user.create(userNameString, password, (createAck) => {
|
|
124
|
+
if (createAck.err) {
|
|
125
|
+
// Check if error is "User already created"
|
|
126
|
+
if (createAck.err.includes("already created")) {
|
|
127
|
+
console.log(`User ${userNameString} already existed, re-attempting auth with fresh user object.`);
|
|
128
|
+
const freshUser = holoInstance.gun.user(); // Get a new user object
|
|
129
|
+
freshUser.auth(userNameString, password, (secondAuthAck) => {
|
|
130
|
+
if (secondAuthAck.err) {
|
|
131
|
+
reject(new Error(`Failed to auth with fresh user object after create attempt (user existed): ${secondAuthAck.err}`));
|
|
132
|
+
} else {
|
|
133
|
+
resolve();
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
} else {
|
|
137
|
+
reject(new Error(`Failed to create user ${userNameString}: ${createAck.err}`));
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
// After successful creation, authenticate again
|
|
141
|
+
console.log(`User ${userNameString} created successfully, attempting auth...`);
|
|
142
|
+
user.auth(userNameString, password, (secondAuthAck) => {
|
|
143
|
+
if (secondAuthAck.err) {
|
|
144
|
+
reject(new Error(`Failed to auth after create for ${userNameString}: ${secondAuthAck.err}`));
|
|
145
|
+
} else {
|
|
146
|
+
resolve();
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
} else {
|
|
152
|
+
resolve(); // Auth successful
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return new Promise(async (resolve) => {
|
|
159
|
+
const handleData = async (data) => {
|
|
160
|
+
if (!data) {
|
|
161
|
+
resolve(null);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
// The data should be a stringified JSON from putGlobal
|
|
167
|
+
const parsed = await holoInstance.parse(data); // Use instance's parse
|
|
168
|
+
|
|
169
|
+
if (!parsed) {
|
|
170
|
+
resolve(null);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Check if this is a hologram that needs to be resolved
|
|
175
|
+
if (holoInstance.isHologram(parsed)) { // Use instance's isHologram
|
|
176
|
+
const resolved = await holoInstance.resolveHologram(parsed, { // Use instance's resolveHologram
|
|
177
|
+
followHolograms: true // Always follow holograms
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
if (resolved === null) {
|
|
181
|
+
console.log(`Hologram at ${tableName}/${key} points to non-existent data. Deleting hologram.`);
|
|
182
|
+
try {
|
|
183
|
+
await holoInstance.deleteGlobal(tableName, key, password); // Use instance's deleteGlobal
|
|
184
|
+
} catch (deleteError) {
|
|
185
|
+
console.error(`Failed to delete invalid global hologram at ${tableName}/${key}:`, deleteError);
|
|
186
|
+
}
|
|
187
|
+
resolve(null); // Return null as the hologram is invalid
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (resolved !== parsed) {
|
|
192
|
+
// Hologram was resolved successfully
|
|
193
|
+
resolve(resolved);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
resolve(parsed);
|
|
199
|
+
} catch (e) {
|
|
200
|
+
console.error('Error parsing data in getGlobal:', e);
|
|
201
|
+
resolve(null);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const dataPath = password ?
|
|
206
|
+
user.get('private').get(tableName) :
|
|
207
|
+
holoInstance.gun.get(holoInstance.appname).get(tableName);
|
|
208
|
+
|
|
209
|
+
const itemPath = dataPath.get(key);
|
|
210
|
+
itemPath.once(handleData);
|
|
211
|
+
});
|
|
212
|
+
} catch (error) {
|
|
213
|
+
console.error('Error in getGlobal:', error);
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Retrieves all data from a global table.
|
|
220
|
+
* @param {HoloSphere} holoInstance - The HoloSphere instance.
|
|
221
|
+
* @param {string} tableName - The table name to retrieve data from.
|
|
222
|
+
* @param {string} [password] - Optional password for private holon.
|
|
223
|
+
* @returns {Promise<Array<object>>} - The parsed data from the table as an array.
|
|
224
|
+
*/
|
|
225
|
+
export async function getAllGlobal(holoInstance, tableName, password = null) {
|
|
226
|
+
if (!tableName) {
|
|
227
|
+
throw new Error('getAllGlobal: Missing table name parameter');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
let user = null;
|
|
232
|
+
if (password) {
|
|
233
|
+
user = holoInstance.gun.user();
|
|
234
|
+
await new Promise((resolve, reject) => {
|
|
235
|
+
const userNameString = holoInstance.userName(tableName);
|
|
236
|
+
user.auth(userNameString, password, (authAck) => {
|
|
237
|
+
if (authAck.err) {
|
|
238
|
+
// If auth fails, try to create the user
|
|
239
|
+
console.log(`Initial auth failed for ${userNameString}, attempting to create...`);
|
|
240
|
+
user.create(userNameString, password, (createAck) => {
|
|
241
|
+
if (createAck.err) {
|
|
242
|
+
// Check if error is "User already created"
|
|
243
|
+
if (createAck.err.includes("already created")) {
|
|
244
|
+
console.log(`User ${userNameString} already existed, re-attempting auth with fresh user object.`);
|
|
245
|
+
const freshUser = holoInstance.gun.user(); // Get a new user object
|
|
246
|
+
freshUser.auth(userNameString, password, (secondAuthAck) => {
|
|
247
|
+
if (secondAuthAck.err) {
|
|
248
|
+
reject(new Error(`Failed to auth with fresh user object after create attempt (user existed): ${secondAuthAck.err}`));
|
|
249
|
+
} else {
|
|
250
|
+
resolve();
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
} else {
|
|
254
|
+
reject(new Error(`Failed to create user ${userNameString}: ${createAck.err}`));
|
|
255
|
+
}
|
|
256
|
+
} else {
|
|
257
|
+
// After successful creation, authenticate again
|
|
258
|
+
console.log(`User ${userNameString} created successfully, attempting auth...`);
|
|
259
|
+
user.auth(userNameString, password, (secondAuthAck) => {
|
|
260
|
+
if (secondAuthAck.err) {
|
|
261
|
+
reject(new Error(`Failed to auth after create for ${userNameString}: ${secondAuthAck.err}`));
|
|
262
|
+
} else {
|
|
263
|
+
resolve();
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
} else {
|
|
269
|
+
resolve(); // Auth successful
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return new Promise((resolve) => {
|
|
276
|
+
let output = [];
|
|
277
|
+
let isResolved = false;
|
|
278
|
+
let timeout = setTimeout(() => {
|
|
279
|
+
if (!isResolved) {
|
|
280
|
+
isResolved = true;
|
|
281
|
+
resolve(output);
|
|
282
|
+
}
|
|
283
|
+
}, 5000);
|
|
284
|
+
|
|
285
|
+
const handleData = async (data) => {
|
|
286
|
+
if (!data) {
|
|
287
|
+
clearTimeout(timeout);
|
|
288
|
+
isResolved = true;
|
|
289
|
+
resolve([]);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const keys = Object.keys(data).filter(key => key !== '_');
|
|
294
|
+
const promises = keys.map(key =>
|
|
295
|
+
new Promise(async (resolveItem) => {
|
|
296
|
+
const itemPath = password ?
|
|
297
|
+
user.get('private').get(tableName).get(key) :
|
|
298
|
+
holoInstance.gun.get(holoInstance.appname).get(tableName).get(key);
|
|
299
|
+
|
|
300
|
+
const itemData = await new Promise(resolveData => {
|
|
301
|
+
itemPath.once(resolveData);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
if (itemData) {
|
|
305
|
+
try {
|
|
306
|
+
const parsed = await holoInstance.parse(itemData); // Use instance's parse
|
|
307
|
+
if (parsed) {
|
|
308
|
+
// Check if this is a hologram that needs to be resolved
|
|
309
|
+
if (holoInstance.isHologram(parsed)) { // Use instance's isHologram
|
|
310
|
+
const resolved = await holoInstance.resolveHologram(parsed, { // Use instance's resolveHologram
|
|
311
|
+
followHolograms: true // Always follow holograms
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
if (resolved === null) {
|
|
315
|
+
console.log(`Hologram at ${tableName}/${key} points to non-existent data. Deleting hologram.`);
|
|
316
|
+
try {
|
|
317
|
+
await holoInstance.deleteGlobal(tableName, key, password); // Use instance's deleteGlobal
|
|
318
|
+
} catch (deleteError) {
|
|
319
|
+
console.error(`Failed to delete invalid global hologram at ${tableName}/${key}:`, deleteError);
|
|
320
|
+
}
|
|
321
|
+
resolveItem();
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (resolved !== parsed) {
|
|
326
|
+
// Hologram was resolved successfully
|
|
327
|
+
output.push(resolved);
|
|
328
|
+
} else {
|
|
329
|
+
// If resolution didn't change it (e.g., circular ref guard), push original parsed (which is a hologram)
|
|
330
|
+
output.push(parsed);
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
output.push(parsed);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
} catch (error) {
|
|
337
|
+
console.error('Error parsing data:', error);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
resolveItem();
|
|
341
|
+
})
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
await Promise.all(promises);
|
|
345
|
+
clearTimeout(timeout);
|
|
346
|
+
if (!isResolved) {
|
|
347
|
+
isResolved = true;
|
|
348
|
+
resolve(output);
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const dataPath = password ?
|
|
353
|
+
user.get('private').get(tableName) :
|
|
354
|
+
holoInstance.gun.get(holoInstance.appname).get(tableName);
|
|
355
|
+
|
|
356
|
+
dataPath.once(handleData);
|
|
357
|
+
});
|
|
358
|
+
} catch (error) {
|
|
359
|
+
console.error('Error in getAllGlobal:', error);
|
|
360
|
+
return [];
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Deletes a specific key from a global table.
|
|
366
|
+
* @param {HoloSphere} holoInstance - The HoloSphere instance.
|
|
367
|
+
* @param {string} tableName - The table name to delete from.
|
|
368
|
+
* @param {string} key - The key to delete.
|
|
369
|
+
* @param {string} [password] - Optional password for private holon.
|
|
370
|
+
* @returns {Promise<boolean>}
|
|
371
|
+
*/
|
|
372
|
+
export async function deleteGlobal(holoInstance, tableName, key, password = null) {
|
|
373
|
+
if (!tableName || !key) {
|
|
374
|
+
throw new Error('deleteGlobal: Missing required parameters');
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
try {
|
|
378
|
+
// console.log('deleteGlobal - Starting deletion:', { tableName, key, hasPassword: !!password }); // Optional logging
|
|
379
|
+
|
|
380
|
+
let user = null;
|
|
381
|
+
if (password) {
|
|
382
|
+
user = holoInstance.gun.user();
|
|
383
|
+
await new Promise((resolve, reject) => {
|
|
384
|
+
const userNameString = holoInstance.userName(tableName);
|
|
385
|
+
user.auth(userNameString, password, (authAck) => {
|
|
386
|
+
if (authAck.err) {
|
|
387
|
+
// If auth fails, try to create the user
|
|
388
|
+
console.log(`Initial auth failed for ${userNameString}, attempting to create...`);
|
|
389
|
+
user.create(userNameString, password, (createAck) => {
|
|
390
|
+
if (createAck.err) {
|
|
391
|
+
// Check if error is "User already created"
|
|
392
|
+
if (createAck.err.includes("already created")) {
|
|
393
|
+
console.log(`User ${userNameString} already existed, re-attempting auth with fresh user object.`);
|
|
394
|
+
const freshUser = holoInstance.gun.user(); // Get a new user object
|
|
395
|
+
freshUser.auth(userNameString, password, (secondAuthAck) => {
|
|
396
|
+
if (secondAuthAck.err) {
|
|
397
|
+
reject(new Error(`Failed to auth with fresh user object after create attempt (user existed): ${secondAuthAck.err}`));
|
|
398
|
+
} else {
|
|
399
|
+
resolve();
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
} else {
|
|
403
|
+
reject(new Error(`Failed to create user ${userNameString}: ${createAck.err}`));
|
|
404
|
+
}
|
|
405
|
+
} else {
|
|
406
|
+
// After successful creation, authenticate again
|
|
407
|
+
console.log(`User ${userNameString} created successfully, attempting auth...`);
|
|
408
|
+
user.auth(userNameString, password, (secondAuthAck) => {
|
|
409
|
+
if (secondAuthAck.err) {
|
|
410
|
+
reject(new Error(`Failed to auth after create for ${userNameString}: ${secondAuthAck.err}`));
|
|
411
|
+
} else {
|
|
412
|
+
resolve();
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
} else {
|
|
418
|
+
resolve(); // Auth successful
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return new Promise((resolve, reject) => {
|
|
425
|
+
const dataPath = password ?
|
|
426
|
+
user.get('private').get(tableName).get(key) :
|
|
427
|
+
holoInstance.gun.get(holoInstance.appname).get(tableName).get(key);
|
|
428
|
+
|
|
429
|
+
// Request deletion
|
|
430
|
+
dataPath.put(null, ack => {
|
|
431
|
+
// console.log('deleteGlobal - Deletion acknowledgment:', ack); // Optional logging
|
|
432
|
+
if (ack.err) {
|
|
433
|
+
console.error('deleteGlobal - Deletion error:', ack.err);
|
|
434
|
+
reject(new Error(ack.err));
|
|
435
|
+
} else {
|
|
436
|
+
// Resolve directly on success, like deleteFunc
|
|
437
|
+
resolve(true);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
} catch (error) {
|
|
442
|
+
console.error('Error in deleteGlobal:', error);
|
|
443
|
+
throw error;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Deletes an entire global table.
|
|
449
|
+
* @param {HoloSphere} holoInstance - The HoloSphere instance.
|
|
450
|
+
* @param {string} tableName - The table name to delete.
|
|
451
|
+
* @param {string} [password] - Optional password for private holon.
|
|
452
|
+
* @returns {Promise<boolean>}
|
|
453
|
+
*/
|
|
454
|
+
export async function deleteAllGlobal(holoInstance, tableName, password = null) {
|
|
455
|
+
if (!tableName) {
|
|
456
|
+
throw new Error('deleteAllGlobal: Missing table name parameter');
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
try {
|
|
460
|
+
let user = null;
|
|
461
|
+
if (password) {
|
|
462
|
+
user = holoInstance.gun.user();
|
|
463
|
+
await new Promise((resolve, reject) => {
|
|
464
|
+
const userNameString = holoInstance.userName(tableName);
|
|
465
|
+
user.auth(userNameString, password, (authAck) => {
|
|
466
|
+
if (authAck.err) {
|
|
467
|
+
// If auth fails, try to create the user
|
|
468
|
+
console.log(`Initial auth failed for ${userNameString}, attempting to create...`);
|
|
469
|
+
user.create(userNameString, password, (createAck) => {
|
|
470
|
+
if (createAck.err) {
|
|
471
|
+
// Check if error is "User already created"
|
|
472
|
+
if (createAck.err.includes("already created")) {
|
|
473
|
+
console.log(`User ${userNameString} already existed, re-attempting auth with fresh user object.`);
|
|
474
|
+
const freshUser = holoInstance.gun.user(); // Get a new user object
|
|
475
|
+
freshUser.auth(userNameString, password, (secondAuthAck) => {
|
|
476
|
+
if (secondAuthAck.err) {
|
|
477
|
+
reject(new Error(`Failed to auth with fresh user object after create attempt (user existed): ${secondAuthAck.err}`));
|
|
478
|
+
} else {
|
|
479
|
+
resolve();
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
} else {
|
|
483
|
+
reject(new Error(`Failed to create user ${userNameString}: ${createAck.err}`));
|
|
484
|
+
}
|
|
485
|
+
} else {
|
|
486
|
+
// After successful creation, authenticate again
|
|
487
|
+
console.log(`User ${userNameString} created successfully, attempting auth...`);
|
|
488
|
+
user.auth(userNameString, password, (secondAuthAck) => {
|
|
489
|
+
if (secondAuthAck.err) {
|
|
490
|
+
reject(new Error(`Failed to auth after create for ${userNameString}: ${secondAuthAck.err}`));
|
|
491
|
+
} else {
|
|
492
|
+
resolve();
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
} else {
|
|
498
|
+
resolve(); // Auth successful
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
return new Promise((resolve, reject) => {
|
|
505
|
+
try {
|
|
506
|
+
const deletions = new Set();
|
|
507
|
+
let timeout = setTimeout(() => {
|
|
508
|
+
if (deletions.size === 0) {
|
|
509
|
+
resolve(true); // No data to delete
|
|
510
|
+
}
|
|
511
|
+
}, 5000);
|
|
512
|
+
|
|
513
|
+
const dataPath = password ?
|
|
514
|
+
user.get('private').get(tableName) :
|
|
515
|
+
holoInstance.gun.get(holoInstance.appname).get(tableName);
|
|
516
|
+
|
|
517
|
+
dataPath.once(async (data) => {
|
|
518
|
+
if (!data) {
|
|
519
|
+
clearTimeout(timeout);
|
|
520
|
+
resolve(true);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const keys = Object.keys(data).filter(key => key !== '_');
|
|
525
|
+
const promises = keys.map(key =>
|
|
526
|
+
new Promise((resolveDelete, rejectDelete) => {
|
|
527
|
+
const deletePath = password ?
|
|
528
|
+
user.get('private').get(tableName).get(key) :
|
|
529
|
+
holoInstance.gun.get(holoInstance.appname).get(tableName).get(key);
|
|
530
|
+
|
|
531
|
+
deletePath.put(null, ack => {
|
|
532
|
+
if (ack.err) {
|
|
533
|
+
console.error(`Failed to delete ${key}:`, ack.err);
|
|
534
|
+
rejectDelete(new Error(ack.err));
|
|
535
|
+
} else {
|
|
536
|
+
resolveDelete();
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
})
|
|
540
|
+
);
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
await Promise.all(promises);
|
|
544
|
+
// Finally delete the table itself
|
|
545
|
+
dataPath.put(null);
|
|
546
|
+
clearTimeout(timeout);
|
|
547
|
+
resolve(true);
|
|
548
|
+
} catch (error) {
|
|
549
|
+
reject(error);
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
} catch (error) {
|
|
553
|
+
reject(error);
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
} catch (error) {
|
|
557
|
+
console.error('Error in deleteAllGlobal:', error);
|
|
558
|
+
throw error;
|
|
559
|
+
}
|
|
560
|
+
}
|