holosphere 1.0.7 → 1.1.0

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/holosphere.js CHANGED
@@ -7,22 +7,25 @@ class HoloSphere {
7
7
  /**
8
8
  * Initializes a new instance of the HoloSphere class.
9
9
  * @param {string} appname - The name of the application.
10
+ * @param {boolean} strict - Whether to enforce strict schema validation.
10
11
  * @param {string|null} openaikey - The OpenAI API key.
11
12
  */
12
- constructor(appname, openaikey = null) {
13
- this.validator = new Ajv2019({ allErrors: false, strict: false });
13
+ constructor(appname, strict = false, openaikey = null) {
14
+ this.appname = appname
15
+ this.strict = strict;
16
+ this.validator = new Ajv2019({
17
+ allErrors: true,
18
+ strict: false, // Keep this false to avoid Ajv strict mode issues
19
+ validateSchema: true // Always validate schemas
20
+ });
14
21
  this.gun = Gun({
15
- peers: ['https://59.src.eco/gun'],
22
+ peers: ['http://gun.holons.io', 'https://59.src.eco/gun'],
16
23
  axe: false,
17
24
  // uuid: (content) => { // generate a unique id for each node
18
25
  // console.log('uuid', content);
19
26
  // return content;}
20
27
  });
21
28
 
22
- this.gun = this.gun.get(appname)
23
- this.users = {}; // Initialize users
24
- this.hexagonVotes = {}; // Initialize hexagonVotes
25
-
26
29
  if (openaikey != null) {
27
30
  this.openai = new OpenAI({
28
31
  apiKey: openaikey,
@@ -30,6 +33,8 @@ class HoloSphere {
30
33
  }
31
34
  }
32
35
 
36
+ // ================================ SCHEMA FUNCTIONS ================================
37
+
33
38
  /**
34
39
  * Sets the JSON schema for a specific lens.
35
40
  * @param {string} lens - The lens identifier.
@@ -37,16 +42,84 @@ class HoloSphere {
37
42
  * @returns {Promise} - Resolves when the schema is set.
38
43
  */
39
44
  async setSchema(lens, schema) {
40
- return new Promise((resolve, reject) => {
41
- this.gun.get(lens).get('schema').put(JSON.stringify(schema), ack => {
42
- if (ack.err) {
43
- resolve(new Error('Failed to add schema: ' + ack.err));
44
- } else {
45
- console.log('Schema added successfully under lens:', lens);
46
- resolve(ack);
45
+ if (!lens || !schema) {
46
+ console.error('setSchema: Missing required parameters');
47
+ return false;
48
+ }
49
+
50
+ // Basic schema validation - check for required fields
51
+ if (!schema.type || typeof schema.type !== 'string') {
52
+ console.error('setSchema: Schema must have a type field');
53
+ return false;
54
+ }
55
+
56
+ if (this.strict) {
57
+ try {
58
+ // Validate schema against JSON Schema meta-schema
59
+ const metaSchema = {
60
+ type: 'object',
61
+ required: ['type', 'properties'],
62
+ properties: {
63
+ type: { type: 'string' },
64
+ properties: {
65
+ type: 'object',
66
+ additionalProperties: {
67
+ type: 'object',
68
+ required: ['type'],
69
+ properties: {
70
+ type: { type: 'string' }
71
+ }
72
+ }
73
+ },
74
+ required: {
75
+ type: 'array',
76
+ items: { type: 'string' }
77
+ }
78
+ }
79
+ };
80
+
81
+ const valid = this.validator.validate(metaSchema, schema);
82
+ if (!valid) {
83
+ console.error('setSchema: Invalid schema structure:', this.validator.errors);
84
+ return false;
47
85
  }
48
- })
49
- })
86
+
87
+ // Additional strict mode checks
88
+ if (!schema.properties || typeof schema.properties !== 'object') {
89
+ console.error('setSchema: Schema must have properties in strict mode');
90
+ return false;
91
+ }
92
+
93
+ if (!schema.required || !Array.isArray(schema.required) || schema.required.length === 0) {
94
+ console.error('setSchema: Schema must have required fields in strict mode');
95
+ return false;
96
+ }
97
+ } catch (error) {
98
+ console.error('setSchema: Schema validation error:', error);
99
+ return false;
100
+ }
101
+ }
102
+
103
+ return new Promise((resolve) => {
104
+ try {
105
+ const schemaString = JSON.stringify(schema);
106
+ this.gun.get(this.appname)
107
+ .get(lens)
108
+ .get('schema')
109
+ .put(schemaString, ack => {
110
+ if (ack.err) {
111
+ console.error('Failed to add schema:', ack.err);
112
+ resolve(false);
113
+ } else {
114
+ console.log('Schema added successfully for lens:', lens);
115
+ resolve(true);
116
+ }
117
+ });
118
+ } catch (error) {
119
+ console.error('setSchema: Error stringifying schema:', error);
120
+ resolve(false);
121
+ }
122
+ });
50
123
  }
51
124
 
52
125
  /**
@@ -55,232 +128,505 @@ class HoloSphere {
55
128
  * @returns {Promise<object|null>} - The retrieved schema or null if not found.
56
129
  */
57
130
  async getSchema(lens) {
131
+ if (!lens) {
132
+ console.error('getSchema: Missing lens parameter');
133
+ return null;
134
+ }
135
+
58
136
  return new Promise((resolve) => {
59
- this.gun.get(lens).get('schema').once(data => {
60
- if (data) {
61
- let parsed;
62
- try {
63
- parsed = JSON.parse(data);
137
+ this.gun.get(this.appname)
138
+ .get(lens)
139
+ .get('schema')
140
+ .once(data => {
141
+ if (!data) {
142
+ resolve(null);
143
+ return;
64
144
  }
65
- catch (e) {
66
- resolve(null)
145
+
146
+ try {
147
+ // If data is already a string, parse it
148
+ if (typeof data === 'string') {
149
+ resolve(JSON.parse(data));
150
+ }
151
+ // If data is an object with a string value (GunDB format)
152
+ else if (typeof data === 'object' && data !== null) {
153
+ const schemaStr = Object.values(data).find(v =>
154
+ typeof v === 'string' && v.includes('"type":'));
155
+ if (schemaStr) {
156
+ resolve(JSON.parse(schemaStr));
157
+ } else {
158
+ resolve(null);
159
+ }
160
+ } else {
161
+ resolve(null);
162
+ }
163
+ } catch (error) {
164
+ console.error('getSchema: Error parsing schema:', error);
165
+ resolve(null);
67
166
  }
68
- resolve(parsed);
69
- } else {
70
- resolve(null);
71
- }
72
- })
73
- })
74
- }
75
- /**
76
- * Deletes a specific tag from a given ID.
77
- * @param {string} id - The identifier from which to delete the tag.
78
- * @param {string} tag - The tag to delete.
79
- */
80
- async delete(id, tag) {
81
- await this.gun.get(id).get(tag).put(null)
167
+ });
168
+ });
82
169
  }
83
170
 
171
+ // ================================ CONTENT FUNCTIONS ================================
172
+
84
173
  /**
85
- * Stores content in the specified hex and lens.
86
- * @param {string} hex - The hex identifier.
174
+ * Stores content in the specified holon and lens.
175
+ * @param {string} holon - The holon identifier.
87
176
  * @param {string} lens - The lens under which to store the content.
88
- * @param {object} content - The content to store.
177
+ * @param {object} data - The data to store.
178
+ * @returns {Promise<boolean>} - Returns true if successful, false if there was an error
89
179
  */
90
- async put(hex, lens, content) {
91
- if (!hex || !lens || !content) return;
92
- console.error('Error in put:', hex, lens, content);
93
- // Retrieve the schema for the lens
94
- let schema = await this.getSchema(lens)
95
- if (schema) {
96
- // Validate the content against the schema
97
- const valid = this.validator.validate(schema, content);
98
- if (!valid) {
99
- console.error('Not committing invalid content:', this.validator.errors);
100
- return null;
101
- }
180
+ async put(holon, lens, data) {
181
+ if (!holon || !lens || !data) {
182
+ console.error('put: Missing required parameters:', { holon, lens, data });
183
+ return false;
102
184
  }
103
185
 
104
- // Create a node for the content
105
- const payload = JSON.stringify(content);
106
-
107
- let noderef;
108
-
109
- if (content.id) { //use the user-defined id. Important to be able to send updates using put
110
- noderef = this.gun.get(lens).get(content.id).put(payload)
111
- this.gun.get(hex.toString()).get(lens).get(content.id).put(payload)
112
- } else { // create a content-addressable reference like IPFS. Note: no updates possible using put
113
- const hashBuffer = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(payload));
114
- const hashArray = Array.from(new Uint8Array(hashBuffer));
115
- const hashHex = hashArray.map(byte => byte.toString(16).padStart(2, "0")).join("");
116
- noderef = this.gun.get(lens).get(hashHex).put(payload)
117
- this.gun.get(hex.toString()).get(lens).get(hashHex).put(payload)
186
+ if (!data.id) {
187
+ console.error('put: Data must have an id field');
188
+ return false;
118
189
  }
119
190
 
120
- }
121
-
122
- async putNode(hex, lens, node) {
123
- this.gun.get(hex).get(lens).set(node)
124
- }
125
-
126
- async parse(data) {
127
- let parsed = {};
128
-
129
- if (typeof data === 'object' && data !== null) {
130
- if (data._ && data._["#"]) {
131
- // If the data is a reference, fetch the actual content
132
- let query = data._['#'].split('/');
133
- let hex = query[1];
134
- let lens = query[2];
135
- let key = query[3];
136
- parsed = await this.getKey(hex, lens, key);
137
- } else if (data._ && data._['>']) {
138
- // This might be a GunDB node, try to get its value
139
- const nodeValue = Object.values(data).find(v => typeof v !== 'object' && v !== '_');
140
- if (nodeValue) {
141
- try {
142
- parsed = JSON.parse(nodeValue);
143
- } catch (e) {
144
- console.log('Invalid JSON in node value:', nodeValue);
145
- parsed = nodeValue; // return the raw data
146
- }
147
- } else {
148
- console.log('Unable to parse GunDB node:', data);
149
- parsed = data; // return the original data
150
- }
151
- } else {
152
- // Treat it as regular data
153
- parsed = data;
154
- }
155
- } else {
156
- // If it's not an object, try parsing it as JSON
191
+ // Strict validation of schema and data
192
+ const schema = await this.getSchema(lens);
193
+ if (schema) {
157
194
  try {
158
- parsed = JSON.parse(data);
159
- } catch (e) {
160
- console.log('Invalid JSON:', data);
161
- parsed = data; // return the raw data
195
+ const valid = this.validator.validate(schema, data);
196
+ if (!valid) {
197
+ const errors = this.validator.errors;
198
+ console.error('put: Schema validation failed:', errors);
199
+ return false;
200
+ }
201
+ } catch (error) {
202
+ console.error('put: Schema validation error:', error);
203
+ return false;
162
204
  }
205
+ } else if (this.strict) {
206
+ console.error('put: Schema required in strict mode for lens:', lens);
207
+ return false;
163
208
  }
164
209
 
165
- return parsed;
210
+ return new Promise((resolve) => {
211
+ try {
212
+ const payload = JSON.stringify(data);
213
+
214
+ this.gun.get(this.appname)
215
+ .get(holon)
216
+ .get(lens)
217
+ .get(data.id)
218
+ .put(payload, ack => {
219
+ if (ack.err) {
220
+ console.error("Error adding data to GunDB:", ack.err);
221
+ resolve(false);
222
+ } else {
223
+ resolve(true);
224
+ }
225
+ });
226
+ } catch (error) {
227
+ console.error('Error in put operation:', error);
228
+ resolve(false);
229
+ }
230
+ });
166
231
  }
167
232
 
168
233
  /**
169
- * Retrieves content from the specified hex and lens.
170
- * @param {string} hex - The hex identifier.
234
+ * Retrieves content from the specified holon and lens.
235
+ * @param {string} holon - The holon identifier.
171
236
  * @param {string} lens - The lens from which to retrieve content.
172
237
  * @returns {Promise<Array<object>>} - The retrieved content.
173
238
  */
174
- async get(hex, lens) {
175
- if (!hex || !lens) {
176
- console.log('Wrong get:', hex, lens)
177
- return;
239
+ async getAll(holon, lens) {
240
+ if (!holon || !lens) {
241
+ console.error('getAll: Missing required parameters:', { holon, lens });
242
+ return [];
178
243
  }
179
- // Wrap the GunDB operation in a promise
180
- //retrieve lens schema
181
- const schema = await this.getSchema(lens);
182
244
 
183
- if (!schema) {
184
- console.log('The schema for "' + lens + '" is not defined');
185
- // return null; // No schema found, return null if strict about it
245
+ const schema = await this.getSchema(lens);
246
+ if (!schema && this.strict) {
247
+ console.error('getAll: Schema required in strict mode for lens:', lens);
248
+ return [];
186
249
  }
187
250
 
188
- return new Promise(async (resolve, reject) => {
189
- let output = []
190
- let counter = 0
191
- this.gun.get(hex.toString()).get(lens).once((data, key) => {
192
- if (data) {
193
- const maplenght = Object.keys(data).length - 1
194
- console.log('Map length:', maplenght)
195
- this.gun.get(hex.toString()).get(lens).map().once(async (itemdata, key) => {
196
- counter += 1
197
- if (itemdata) {
198
- let parsed = await this.parse (itemdata)
199
-
251
+ return new Promise((resolve) => {
252
+ let output = [];
253
+ let counter = 0;
254
+
255
+ this.gun.get(this.appname).get(holon).get(lens).once((data, key) => {
256
+ if (!data) {
257
+ resolve(output);
258
+ return;
259
+ }
200
260
 
261
+ const mapLength = Object.keys(data).length - 1;
262
+
263
+ this.gun.get(this.appname).get(holon).get(lens).map().once(async (itemdata, key) => {
264
+ counter += 1;
265
+ if (itemdata) {
266
+ try {
267
+ const parsed = JSON.parse(itemdata);
268
+
201
269
  if (schema) {
202
- let valid = this.validator.validate(schema, parsed);
203
- if (!valid || parsed == null || parsed == undefined) {
204
- console.log('Removing Invalid content:', this.validator.errors);
205
- this.gun.get(hex).get(lens).get(key).put(null);
206
-
270
+ const valid = this.validator.validate(schema, parsed);
271
+ if (valid) {
272
+ output.push(parsed);
273
+ } else if (this.strict) {
274
+ console.warn('Invalid data removed:', key, this.validator.errors);
275
+ await this.delete(holon, lens, key);
207
276
  } else {
277
+ console.warn('Invalid data found:', key, this.validator.errors);
208
278
  output.push(parsed);
209
279
  }
210
- }
211
- else {
280
+ } else {
212
281
  output.push(parsed);
213
282
  }
283
+ } catch (error) {
284
+ console.error('Error parsing data:', error);
285
+ if (this.strict) {
286
+ await this.delete(holon, lens, key);
287
+ }
214
288
  }
289
+ }
215
290
 
216
- if (counter == maplenght) {
217
- resolve(output);
218
- }
291
+ if (counter === mapLength) {
292
+ resolve(output);
219
293
  }
220
- );
221
- } else resolve(output)
222
- })
223
- }
224
- );
294
+ });
295
+ });
296
+ });
225
297
  }
226
298
 
227
- /**
228
- * Retrieves a specific key from the specified hex and lens.
229
- * @param {string} hex - The hex identifier.
299
+ /**
300
+ * Retrieves a specific key from the specified holon and lens.
301
+ * @param {string} holon - The holon identifier.
230
302
  * @param {string} lens - The lens from which to retrieve the key.
231
303
  * @param {string} key - The specific key to retrieve.
232
304
  * @returns {Promise<object|null>} - The retrieved content or null if not found.
233
305
  */
234
- async getKey(hex, lens, key) {
306
+ async get(holon, lens, key) {
307
+ if (!holon || !lens || !key) {
308
+ console.error('get: Missing required parameters:', { holon, lens, key });
309
+ return null;
310
+ }
311
+
312
+ // Get schema for validation
313
+ const schema = await this.getSchema(lens);
314
+
235
315
  return new Promise((resolve) => {
236
- // Use Gun to get the data
237
- this.gun.get(hex).get(lens).get(key).once((data, key) => {
238
- if (data) {
239
- console.log('Data getting parsed:', data)
316
+ let timeout = setTimeout(() => {
317
+ console.warn('get: Operation timed out');
318
+ resolve(null);
319
+ }, 5000); // 5 second timeout
320
+
321
+ this.gun.get(this.appname)
322
+ .get(holon)
323
+ .get(lens)
324
+ .get(key)
325
+ .once((data) => {
326
+ clearTimeout(timeout);
327
+
328
+ if (!data) {
329
+ resolve(null);
330
+ return;
331
+ }
332
+
240
333
  try {
241
- let parsed = JSON.parse(data); // Resolve the promise with the data if data is found
334
+ const parsed = JSON.parse(data);
335
+
336
+ // Validate against schema if one exists
337
+ if (schema) {
338
+ const valid = this.validator.validate(schema, parsed);
339
+ if (!valid) {
340
+ console.error('get: Invalid data according to schema:', this.validator.errors);
341
+ if (this.strict) {
342
+ resolve(null);
343
+ return;
344
+ }
345
+ }
346
+ }
347
+
242
348
  resolve(parsed);
349
+ } catch (error) {
350
+ console.error('Error parsing data:', error);
351
+ resolve(null);
243
352
  }
244
- catch (e) {
245
- resolve(data)
353
+ });
354
+ });
355
+ }
356
+
357
+ /**
358
+ * Deletes a specific key from a given holon and lens.
359
+ * @param {string} holon - The holon identifier.
360
+ * @param {string} lens - The lens from which to delete the key.
361
+ * @param {string} key - The specific key to delete.
362
+ */
363
+ async delete (holon, lens, key) {
364
+ return new Promise((resolve, reject) => {
365
+ this.gun.get(this.appname).get(holon).get(lens).get(key).put(null, ack => {
366
+ if (ack.err) {
367
+ resolve(ack.err);
368
+ } else {
369
+ resolve(ack.ok);
246
370
  }
247
-
248
- } else {
249
- resolve(null); // Reject the promise if no data is found
371
+ });
372
+ });
373
+ }
374
+
375
+ /**
376
+ * Deletes all keys from a given holon and lens.
377
+ * @param {string} holon - The holon identifier.
378
+ * @param {string} lens - The lens from which to delete all keys.
379
+ * @returns {Promise<boolean>} - Returns true if successful, false if there was an error
380
+ */
381
+ async deleteAll(holon, lens) {
382
+ if (!holon || !lens) {
383
+ console.error('deleteAll: Missing holon or lens parameter');
384
+ return false;
385
+ }
386
+
387
+ return new Promise((resolve) => {
388
+ let deletionPromises = [];
389
+
390
+ // First get all the data to find keys to delete
391
+ this.gun.get(this.appname).get(holon).get(lens).once((data) => {
392
+ if (!data) {
393
+ resolve(true); // Nothing to delete
394
+ return;
250
395
  }
396
+
397
+ // Get all keys except Gun's metadata key '_'
398
+ const keys = Object.keys(data).filter(key => key !== '_');
399
+
400
+ // Create deletion promises for each key
401
+ keys.forEach(key => {
402
+ deletionPromises.push(
403
+ new Promise((resolveDelete) => {
404
+ this.gun.get(this.appname).get(holon).get(lens).get(key).put(null, ack => {
405
+ resolveDelete(!!ack.ok); // Convert to boolean
406
+ });
407
+ })
408
+ );
409
+ });
410
+
411
+ // Wait for all deletions to complete
412
+ Promise.all(deletionPromises)
413
+ .then(results => {
414
+ const allSuccessful = results.every(result => result === true);
415
+ resolve(allSuccessful);
416
+ })
417
+ .catch(error => {
418
+ console.error('Error in deleteAll:', error);
419
+ resolve(false);
420
+ });
251
421
  });
252
422
  });
253
-
254
423
  }
255
424
 
425
+ // ================================ NODE FUNCTIONS ================================
426
+
427
+
428
+ /**
429
+ * Stores a specific gun node in a given holon and lens.
430
+ * @param {string} holon - The holon identifier.
431
+ * @param {string} lens - The lens under which to store the node.
432
+ * @param {object} node - The node to store.
433
+ */
434
+ async putNode(holon, lens, node) {
435
+ this.gun.get(this.appname).get(holon).get(lens).put(node)
436
+ }
437
+
256
438
  /**
257
- * Retrieves a specific gundb node from the specified hex and lens.
258
- * @param {string} hex - The hex identifier.
259
- * @param {string} lens - The lens from which to retrieve the key.
439
+ * Retrieves a specific gun node from the specified holon and lens.
440
+ * @param {string} holon - The holon identifier.
441
+ * @param {string} lens - The lens identifier.
260
442
  * @param {string} key - The specific key to retrieve.
261
- * @returns {Promise<object|null>} - The retrieved content or null if not found.
443
+ * @returns {Promise<object|null>} - The retrieved node or null if not found.
262
444
  */
263
- getNode(hex, lens, key) {
264
- // Use Gun to get the data
265
- return this.gun.get(hex).get(lens).get(key)
445
+ async getNode(holon, lens, key) {
446
+ if (!holon || !lens || !key) {
447
+ console.error('getNode: Missing required parameters');
448
+ return null;
449
+ }
450
+
451
+ return new Promise((resolve) => {
452
+ let timeout = setTimeout(() => {
453
+ console.warn('getNode: Operation timed out');
454
+ resolve(null);
455
+ }, 5000);
456
+
457
+ this.gun.get(this.appname)
458
+ .get(holon)
459
+ .get(lens)
460
+ .get(key)
461
+ .once((data) => {
462
+ clearTimeout(timeout);
463
+ resolve(data || null);
464
+ });
465
+ });
466
+ }
467
+
468
+ /**
469
+ * Deletes a specific gun node from a given holon and lens.
470
+ * @param {string} holon - The holon identifier.
471
+ * @param {string} lens - The lens identifier.
472
+ * @param {string} key - The key of the node to delete.
473
+ * @returns {Promise<boolean>} - Returns true if successful
474
+ */
475
+ async deleteNode(holon, lens, key) {
476
+ if (!holon || !lens || !key) {
477
+ console.error('deleteNode: Missing required parameters');
478
+ return false;
479
+ }
480
+
481
+ return new Promise((resolve) => {
482
+ this.gun.get(this.appname)
483
+ .get(holon)
484
+ .get(lens)
485
+ .get(key)
486
+ .put(null, ack => {
487
+ if (ack.err) {
488
+ console.error('deleteNode: Error deleting node:', ack.err);
489
+ resolve(false);
490
+ } else {
491
+ resolve(true);
492
+ }
493
+ });
494
+ });
266
495
  }
267
496
 
497
+ // ================================ GLOBAL FUNCTIONS ================================
498
+ /**
499
+ * Stores data in a global (non-holon-specific) table.
500
+ * @param {string} tableName - The table name to store data in.
501
+ * @param {object} data - The data to store. If it has an 'id' field, it will be used as the key.
502
+ * @returns {Promise<void>}
503
+ */
504
+ async putGlobal(tableName, data) {
505
+
506
+ return new Promise((resolve, reject) => {
507
+ if (!tableName || !data) {
508
+ reject(new Error('Table name and data are required'));
509
+ return;
510
+ }
511
+
512
+
513
+ if (data.id) {
514
+ this.gun.get(this.appname).get(tableName).get(data.id).put(JSON.stringify(data), ack => {
515
+ if (ack.err) {
516
+ reject(new Error(ack.err));
517
+ } else {
518
+ resolve();
519
+ }
520
+ });
521
+ } else {
522
+ this.gun.get(this.appname).get(tableName).put(JSON.stringify(data), ack => {
523
+ if (ack.err) {
524
+ reject(new Error(ack.err));
525
+ } else {
526
+ resolve();
527
+ }
528
+ });
529
+ }
530
+ });
531
+ }
532
+
533
+ /**
534
+ * Retrieves a specific key from a global table.
535
+ * @param {string} tableName - The table name to retrieve from.
536
+ * @param {string} key - The key to retrieve.
537
+ * @returns {Promise<object|null>} - The parsed data for the key or null if not found.
538
+ */
539
+ async getGlobal(tableName, key) {
540
+ return new Promise((resolve) => {
541
+ this.gun.get(this.appname).get(tableName).get(key).once((data) => {
542
+ if (!data) {
543
+ resolve(null);
544
+ return;
545
+ }
546
+ try {
547
+ const parsed = this.parse(data);
548
+ resolve(parsed);
549
+ } catch (e) {
550
+ resolve(null);
551
+ }
552
+ });
553
+ });
554
+ }
555
+
556
+
268
557
 
558
+ /**
559
+ * Retrieves all data from a global table.
560
+ * @param {string} tableName - The table name to retrieve data from.
561
+ * @returns {Promise<object|null>} - The parsed data from the table or null if not found.
562
+ */
563
+ async getAllGlobal(tableName) {
564
+ return new Promise(async (resolve, reject) => {
565
+ let output = []
566
+ let counter = 0
567
+ this.gun.get(tableName.toString()).once((data, key) => {
568
+ if (data) {
569
+ const maplenght = Object.keys(data).length - 1
570
+ this.gun.get(tableName.toString()).map().once(async (itemdata, key) => {
571
+ counter += 1
572
+ if (itemdata) {
573
+ let parsed = await this.parse(itemdata)
574
+ output.push(parsed);
575
+ }
576
+
577
+ if (counter == maplenght) {
578
+ resolve(output);
579
+ }
580
+ }
581
+ );
582
+ } else resolve(output)
583
+ })
584
+ }
585
+ )
586
+ }
587
+
588
+ /**
589
+ * Deletes a specific key from a global table.
590
+ * @param {string} tableName - The table name to delete from.
591
+ * @param {string} key - The key to delete.
592
+ * @returns {Promise<void>}
593
+ */
594
+ async deleteGlobal(tableName, key) {
595
+ await this.gun.get(this.appname).get(tableName).get(key).put(null)
596
+ }
597
+
598
+ /**
599
+ * Deletes an entire global table.
600
+ * @param {string} tableName - The table name to delete.
601
+ * @returns {Promise<void>}
602
+ */
603
+ async deleteAllGlobal(tableName) {
604
+
605
+ return new Promise((resolve) => {
606
+ this.gun.get(this.appname).get(tableName).map().put(null).once(
607
+ (data, key) => this.gun.get(this.appname).get(tableName).get(key).put(null)
608
+ )
609
+ this.gun.get(this.appname).get(tableName).put({}, ack => {
610
+ resolve();
611
+ });
612
+ });
613
+ }
269
614
 
615
+ // ================================ COMPUTE FUNCTIONS ================================
270
616
  /**
271
- * Computes summaries based on the content within a hex and lens.
272
- * @param {string} hex - The hex identifier.
617
+ * Computes summaries based on the content within a holon and lens.
618
+ * @param {string} holon - The holon identifier.
273
619
  * @param {string} lens - The lens to compute.
274
620
  * @param {string} operation - The operation to perform.
275
621
  */
276
- async compute(hex, lens, operation) {
622
+ async compute(holon, lens, operation) {
277
623
 
278
- let res = h3.getResolution(hex);
279
- if (res < 1 || res > 15) return;
624
+ let res = h3.getResolution(holon);
625
+ if(res < 1 || res > 15) return;
280
626
  console.log(res)
281
- let parent = h3.cellToParent(hex, res - 1);
627
+ let parent = h3.cellToParent(holon, res - 1);
282
628
  let siblings = h3.cellToChildren(parent, res);
283
- console.log(hex, parent, siblings, res)
629
+ console.log(holon, parent, siblings, res)
284
630
 
285
631
  let content = [];
286
632
  let promises = [];
@@ -292,7 +638,7 @@ class HoloSphere {
292
638
  resolve(); // Resolve the promise to prevent it from hanging
293
639
  }, 1000); // Timeout of 5 seconds
294
640
 
295
- this.gun.get(siblings[i]).get(lens).map().once((data, key) => {
641
+ this.gun.get(this.appname).get(siblings[i]).get(lens).map().once((data, key) => {
296
642
  clearTimeout(timeout); // Clear the timeout if data is received
297
643
  if (data) {
298
644
  content.push(data.content);
@@ -306,25 +652,25 @@ class HoloSphere {
306
652
  console.log('Content:', content);
307
653
  let computed = await this.summarize(content.join('\n'))
308
654
  console.log('Computed:', computed)
309
- let node = await this.gun.get(parent + '_summary').put({ id: parent + '_summary', content: computed })
655
+ let node = await this.gun.get(this.appname).get(parent + '_summary').put({ id: parent + '_summary', content: computed })
310
656
 
311
657
  this.put(parent, lens, node);
312
658
  this.compute(parent, lens, operation)
313
659
  }
314
660
 
315
661
  /**
316
- * Clears all entities under a specific hex and lens.
317
- * @param {string} hex - The hex identifier.
662
+ * Clears all entities under a specific holon and lens.
663
+ * @param {string} holon - The holon identifier.
318
664
  * @param {string} lens - The lens to clear.
319
665
  */
320
- async clearlens(hex, lens) {
666
+ async clearlens(holon, lens) {
321
667
  let entities = {};
322
668
 
323
669
  // Get list out of Gun
324
- this.gun.get(hex).get(lens).map().once((data, key) => {
670
+ this.gun.get(this.appname).get(holon).get(lens).map().once((data, key) => {
325
671
  //entities = data;
326
672
  //const id = Object.keys(entities)[0] // since this would be in object form, you can manipulate it as you would like.
327
- this.gun.get(hex).get(lens).put({ [key]: null })
673
+ this.gun.get(this.appname).get(holon).get(lens).put({ [key]: null })
328
674
  })
329
675
  }
330
676
 
@@ -367,30 +713,30 @@ class HoloSphere {
367
713
  }
368
714
 
369
715
  /**
370
- * Upcasts content to parent hexagons recursively.
371
- * @param {string} hex - The current hex identifier.
716
+ * Upcasts content to parent holonagons recursively.
717
+ * @param {string} holon - The current holon identifier.
372
718
  * @param {string} lens - The lens under which to upcast.
373
719
  * @param {object} content - The content to upcast.
374
720
  * @returns {Promise<object>} - The upcasted content.
375
721
  */
376
- async upcast(hex, lens, content) {
377
- let res = h3.getResolution(hex)
722
+ async upcast(holon, lens, content) {
723
+ let res = h3.getResolution(holon)
378
724
  if (res == 0) {
379
- await this.putNode(hex, lens, content)
725
+ await this.putNode(holon, lens, content)
380
726
  return content
381
727
  }
382
728
  else {
383
- console.log('Upcasting ', hex, lens, content, res)
384
- await this.putNode(hex, lens, content)
385
- let parent = h3.cellToParent(hex, res - 1)
729
+ console.log('Upcasting ', holon, lens, content, res)
730
+ await this.putNode(holon, lens, content)
731
+ let parent = h3.cellToParent(holon, res - 1)
386
732
  return this.upcast(parent, lens, content)
387
733
  }
388
734
  }
389
735
 
390
736
 
391
737
  /**
392
- * Updates the parent hexagon with a new report.
393
- * @param {string} id - The child hex identifier.
738
+ * Updates the parent holonagon with a new report.
739
+ * @param {string} id - The child holon identifier.
394
740
  * @param {string} report - The report to update.
395
741
  * @returns {Promise<object>} - The updated parent information.
396
742
  */
@@ -410,21 +756,21 @@ class HoloSphere {
410
756
 
411
757
 
412
758
  /**
413
- * Converts latitude and longitude to a hex identifier.
759
+ * Converts latitude and longitude to a holon identifier.
414
760
  * @param {number} lat - The latitude.
415
761
  * @param {number} lng - The longitude.
416
762
  * @param {number} resolution - The resolution level.
417
- * @returns {Promise<string>} - The resulting hex identifier.
763
+ * @returns {Promise<string>} - The resulting holon identifier.
418
764
  */
419
- async getHex(lat, lng, resolution) {
765
+ async getHolon(lat, lng, resolution) {
420
766
  return h3.latLngToCell(lat, lng, resolution);
421
767
  }
422
768
 
423
769
  /**
424
- * Retrieves all containing hexagons at all scales for given coordinates.
770
+ * Retrieves all containing holonagons at all scales for given coordinates.
425
771
  * @param {number} lat - The latitude.
426
772
  * @param {number} lng - The longitude.
427
- * @returns {Array<string>} - List of hex identifiers.
773
+ * @returns {Array<string>} - List of holon identifiers.
428
774
  */
429
775
  getScalespace(lat, lng) {
430
776
  let list = []
@@ -437,113 +783,30 @@ class HoloSphere {
437
783
  }
438
784
 
439
785
  /**
440
- * Retrieves all containing hexagons at all scales for a given hex.
441
- * @param {string} hex - The hex identifier.
442
- * @returns {Array<string>} - List of hex identifiers.
786
+ * Retrieves all containing holonagons at all scales for a given holon.
787
+ * @param {string} holon - The holon identifier.
788
+ * @returns {Array<string>} - List of holon identifiers.
443
789
  */
444
- getHexScalespace(hex) {
790
+ getHolonScalespace(holon) {
445
791
  let list = []
446
- let res = h3.getResolution(hex)
792
+ let res = h3.getResolution(holon)
447
793
  for (let i = res; i >= 0; i--) {
448
- list.push(h3.cellToParent(hex, i))
794
+ list.push(h3.cellToParent(holon, i))
449
795
  }
450
796
  return list
451
797
  }
452
798
 
453
799
  /**
454
- * Subscribes to changes in a specific hex and lens.
455
- * @param {string} hex - The hex identifier.
800
+ * Subscribes to changes in a specific holon and lens.
801
+ * @param {string} holon - The holon identifier.
456
802
  * @param {string} lens - The lens to subscribe to.
457
803
  * @param {function} callback - The callback to execute on changes.
458
804
  */
459
- subscribe(hex, lens, callback) {
460
- this.gun.get(hex).get(lens).map().on((data, key) => {
805
+ subscribe(holon, lens, callback) {
806
+ this.gun.get(this.appname).get(holon).get(lens).map().on((data, key) => {
461
807
  callback(data, key)
462
808
  })
463
809
  }
464
-
465
- /**
466
- * Retrieves the final vote for a user, considering delegations.
467
- * @param {string} userId - The user's identifier.
468
- * @param {string} topic - The voting topic.
469
- * @param {object} votes - The current votes.
470
- * @param {Set<string>} [visited=new Set()] - Set of visited users to prevent cycles.
471
- * @returns {string|null} - The final vote or null if not found.
472
- */
473
- getFinalVote(userId, topic, votes, visited = new Set()) {
474
- if (this.users[userId]) { // Added this.users
475
- if (visited.has(userId)) {
476
- return null; // Avoid circular delegations
477
- }
478
- visited.add(userId);
479
-
480
- const delegation = this.users[userId].delegations[topic];
481
- if (delegation && votes[delegation] === undefined) {
482
- return this.getFinalVote(delegation, topic, votes, visited); // Prefixed with this
483
- }
484
-
485
- return votes[userId] !== undefined ? votes[userId] : null;
486
- }
487
- return null;
488
- }
489
-
490
- /**
491
- * Aggregates votes for a specific hex and topic.
492
- * @param {string} hexId - The hex identifier.
493
- * @param {string} topic - The voting topic.
494
- * @returns {object} - Aggregated vote counts.
495
- */
496
- aggregateVotes(hexId, topic) {
497
- if (!this.hexagonVotes[hexId] || !this.hexagonVotes[hexId][topic]) {
498
- return {}; // Handle undefined votes
499
- }
500
- const votes = this.hexagonVotes[hexId][topic];
501
- const aggregatedVotes = {};
502
-
503
- Object.keys(votes).forEach(userId => {
504
- const finalVote = this.getFinalVote(userId, topic, votes); // Prefixed with this
505
- if (finalVote !== null) {
506
- aggregatedVotes[finalVote] = (aggregatedVotes[finalVote] || 0) + 1;
507
- }
508
- });
509
-
510
- return aggregatedVotes;
511
- }
512
-
513
- /**
514
- * Delegates a user's vote to another user.
515
- * @param {string} userId - The user's identifier.
516
- * @param {string} topic - The voting topic.
517
- * @param {string} delegateTo - The user to delegate the vote to.
518
- */
519
- async delegateVote(userId, topic, delegateTo) {
520
- const response = await fetch('/delegate', {
521
- method: 'POST',
522
- headers: { 'Content-Type': 'application/json' },
523
- body: JSON.stringify({ userId, topic, delegateTo })
524
- });
525
- alert(await response.text());
526
- }
527
-
528
- /**
529
- * Casts a vote for a user on a specific topic and hex.
530
- * @param {string} userId - The user's identifier.
531
- * @param {string} hexId - The hex identifier.
532
- * @param {string} topic - The voting topic.
533
- * @param {string} vote - The vote choice.
534
- */
535
- async vote(userId, hexId, topic, vote) {
536
- const response = await fetch('/vote', {
537
- method: 'POST',
538
- headers: { 'Content-Type': 'application/json' },
539
- body: JSON.stringify({ userId, hexId, topic, vote })
540
- });
541
- alert(await response.text());
542
- }
543
-
544
-
545
-
546
-
547
810
  }
548
811
 
549
812
  export default HoloSphere;