holosphere 1.1.20 → 1.1.21

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/content.js CHANGED
@@ -508,94 +508,110 @@ export async function getAll(holoInstance, holon, lens, password = null) {
508
508
 
509
509
  return new Promise((resolve) => {
510
510
  const output = new Map();
511
+ const pendingProcessing = [];
511
512
 
512
- const processData = async (data, key) => {
513
- if (!data || key === '_') return;
513
+ const dataPath = password ?
514
+ user.get('private').get(lens) :
515
+ holoInstance.gun.get(holoInstance.appname).get(holon).get(lens);
514
516
 
515
- try {
516
- const parsed = await holoInstance.parse(data); // Use instance's parse
517
- if (!parsed || !parsed.id) return;
517
+ // PASS 1: Get shallow node to determine expected item count
518
+ dataPath.once((data) => {
519
+ if (!data) {
520
+ resolve([]);
521
+ return;
522
+ }
518
523
 
519
- // Check if this is a hologram that needs to be resolved
520
- if (holoInstance.isHologram(parsed)) {
524
+ // Filter out Gun metadata, null/deleted entries, and Gun soul references
525
+ const keys = Object.keys(data).filter(key => {
526
+ if (key === '_') return false;
527
+ const val = data[key];
528
+ if (val === null) return false;
529
+ // Filter out Gun graph references (sub-nodes)
530
+ if (typeof val === 'object' && val['#']) return false;
531
+ return true;
532
+ });
533
+ const expectedCount = keys.length;
534
+
535
+ if (expectedCount === 0) {
536
+ resolve([]);
537
+ return;
538
+ }
539
+
540
+ // PASS 2: Use map().once() to iterate and get full item data
541
+ let receivedCount = 0;
542
+
543
+ dataPath.map().once(async (itemData, key) => {
544
+ if (!itemData || key === '_') {
545
+ receivedCount++;
546
+ if (receivedCount >= expectedCount) {
547
+ await Promise.all(pendingProcessing);
548
+ resolve(Array.from(output.values()));
549
+ }
550
+ return;
551
+ }
552
+
553
+ const processingPromise = (async () => {
521
554
  try {
522
- const resolved = await holoInstance.resolveHologram(parsed, {
523
- followHolograms: true,
524
- maxDepth: 10,
525
- currentDepth: 0
526
- });
555
+ const parsed = await holoInstance.parse(itemData);
556
+ if (!parsed || !parsed.id) return;
527
557
 
528
- if (resolved === null) {
529
- console.warn(`Broken hologram detected in getAll for key ${key}. Removing it...`);
530
-
558
+ if (holoInstance.isHologram(parsed)) {
531
559
  try {
532
- // Delete the broken hologram
533
- await holoInstance.delete(holon, lens, key, password);
534
- console.log(`Successfully removed broken hologram from ${holon}/${lens}/${key}`);
535
- } catch (cleanupError) {
536
- console.error(`Failed to remove broken hologram at ${holon}/${lens}/${key}:`, cleanupError);
537
- }
538
- return; // Skip adding this item to output
539
- }
560
+ const resolved = await holoInstance.resolveHologram(parsed, {
561
+ followHolograms: true,
562
+ maxDepth: 10,
563
+ currentDepth: 0
564
+ });
540
565
 
541
- if (resolved && resolved !== parsed) {
542
- // Hologram was resolved successfully
543
- if (schema) {
544
- const valid = holoInstance.validator.validate(schema, resolved);
545
- if (valid || !holoInstance.strict) {
546
- output.set(resolved.id, resolved);
566
+ if (resolved === null) {
567
+ console.warn(`Broken hologram detected in getAll for key ${key}. Removing it...`);
568
+ try {
569
+ await holoInstance.delete(holon, lens, key, password);
570
+ } catch (cleanupError) {
571
+ console.error(`Failed to remove broken hologram at ${holon}/${lens}/${key}:`, cleanupError);
572
+ }
573
+ return;
547
574
  }
548
- } else {
549
- output.set(resolved.id, resolved);
575
+
576
+ if (resolved && resolved !== parsed) {
577
+ if (schema) {
578
+ const valid = holoInstance.validator.validate(schema, resolved);
579
+ if (valid || !holoInstance.strict) {
580
+ output.set(resolved.id, resolved);
581
+ }
582
+ } else {
583
+ output.set(resolved.id, resolved);
584
+ }
585
+ return;
586
+ }
587
+ } catch (hologramError) {
588
+ console.error(`Error resolving hologram for key ${key}:`, hologramError);
589
+ return;
550
590
  }
551
- return;
552
591
  }
553
- } catch (hologramError) {
554
- console.error(`Error resolving hologram for key ${key}:`, hologramError);
555
- return; // Skip this item
556
- }
557
- }
558
592
 
559
- if (schema) {
560
- const valid = holoInstance.validator.validate(schema, parsed);
561
- if (valid || !holoInstance.strict) {
562
- output.set(parsed.id, parsed);
593
+ if (schema) {
594
+ const valid = holoInstance.validator.validate(schema, parsed);
595
+ if (valid || !holoInstance.strict) {
596
+ output.set(parsed.id, parsed);
597
+ }
598
+ } else {
599
+ output.set(parsed.id, parsed);
600
+ }
601
+ } catch (error) {
602
+ console.error('Error processing data:', error);
563
603
  }
564
- } else {
565
- output.set(parsed.id, parsed);
566
- }
567
- } catch (error) {
568
- console.error('Error processing data:', error);
569
- }
570
- };
604
+ })();
571
605
 
572
- const handleData = async (data) => {
573
- if (!data) {
574
- resolve([]);
575
- return;
576
- }
606
+ pendingProcessing.push(processingPromise);
607
+ receivedCount++;
577
608
 
578
- const initialPromises = [];
579
- Object.keys(data)
580
- .filter(key => key !== '_')
581
- .forEach(key => {
582
- initialPromises.push(processData(data[key], key));
583
- });
584
-
585
- try {
586
- await Promise.all(initialPromises);
587
- resolve(Array.from(output.values()));
588
- } catch (error) {
589
- console.error('Error in getAll:', error);
590
- resolve([]);
591
- }
592
- };
593
-
594
- const dataPath = password ?
595
- user.get('private').get(lens) :
596
- holoInstance.gun.get(holoInstance.appname).get(holon).get(lens);
597
-
598
- dataPath.once(handleData);
609
+ if (receivedCount >= expectedCount) {
610
+ await Promise.all(pendingProcessing);
611
+ resolve(Array.from(output.values()));
612
+ }
613
+ });
614
+ });
599
615
  });
600
616
  } catch (error) {
601
617
  console.error('Error in getAll:', error);
package/global.js CHANGED
@@ -320,86 +320,90 @@ export async function getAllGlobal(holoInstance, tableName, password = null) {
320
320
  }
321
321
 
322
322
  return new Promise((resolve) => {
323
- let output = [];
324
- let isResolved = false;
325
- let timeout = setTimeout(() => {
326
- if (!isResolved) {
327
- isResolved = true;
328
- resolve(output);
329
- }
330
- }, 5000);
323
+ const output = [];
324
+ const pendingProcessing = [];
331
325
 
332
- const handleData = async (data) => {
326
+ const dataPath = password ?
327
+ user.get('private').get(tableName) :
328
+ holoInstance.gun.get(holoInstance.appname).get(tableName);
329
+
330
+ // PASS 1: Get shallow node to determine expected item count
331
+ dataPath.once((data) => {
333
332
  if (!data) {
334
- clearTimeout(timeout);
335
- isResolved = true;
336
333
  resolve([]);
337
334
  return;
338
335
  }
339
336
 
340
- const keys = Object.keys(data).filter(key => key !== '_');
341
- const promises = keys.map(key =>
342
- new Promise(async (resolveItem) => {
343
- const itemPath = password ?
344
- user.get('private').get(tableName).get(key) :
345
- holoInstance.gun.get(holoInstance.appname).get(tableName).get(key);
337
+ // Filter out Gun metadata, null/deleted entries, and Gun soul references
338
+ const keys = Object.keys(data).filter(key => {
339
+ if (key === '_') return false;
340
+ const val = data[key];
341
+ if (val === null) return false;
342
+ // Filter out Gun graph references (sub-nodes)
343
+ if (typeof val === 'object' && val['#']) return false;
344
+ return true;
345
+ });
346
+ const expectedCount = keys.length;
346
347
 
347
- const itemData = await new Promise(resolveData => {
348
- itemPath.once(resolveData);
349
- });
348
+ if (expectedCount === 0) {
349
+ resolve([]);
350
+ return;
351
+ }
350
352
 
351
- if (itemData) {
352
- try {
353
- const parsed = await holoInstance.parse(itemData); // Use instance's parse
354
- if (parsed) {
355
- // Check if this is a hologram that needs to be resolved
356
- if (holoInstance.isHologram(parsed)) { // Use instance's isHologram
357
- const resolved = await holoInstance.resolveHologram(parsed, { // Use instance's resolveHologram
358
- followHolograms: true // Always follow holograms
359
- });
353
+ // PASS 2: Use map().once() to iterate and get full item data
354
+ let receivedCount = 0;
360
355
 
361
- if (resolved === null) {
362
- try {
363
- await holoInstance.deleteGlobal(tableName, key, password); // Use instance's deleteGlobal
364
- } catch (deleteError) {
365
- console.error(`Failed to delete invalid global hologram at ${tableName}/${key}:`, deleteError);
366
- }
367
- resolveItem();
368
- return;
369
- }
356
+ dataPath.map().once(async (itemData, key) => {
357
+ if (!itemData || key === '_') {
358
+ receivedCount++;
359
+ if (receivedCount >= expectedCount) {
360
+ await Promise.all(pendingProcessing);
361
+ resolve(output);
362
+ }
363
+ return;
364
+ }
370
365
 
371
- if (resolved !== parsed) {
372
- // Hologram was resolved successfully
373
- output.push(resolved);
374
- } else {
375
- // If resolution didn't change it (e.g., circular ref guard), push original parsed (which is a hologram)
376
- output.push(parsed);
377
- }
378
- } else {
379
- output.push(parsed);
366
+ const processingPromise = (async () => {
367
+ try {
368
+ const parsed = await holoInstance.parse(itemData);
369
+ if (!parsed) return;
370
+
371
+ if (holoInstance.isHologram(parsed)) {
372
+ const resolved = await holoInstance.resolveHologram(parsed, {
373
+ followHolograms: true
374
+ });
375
+
376
+ if (resolved === null) {
377
+ try {
378
+ await holoInstance.deleteGlobal(tableName, key, password);
379
+ } catch (deleteError) {
380
+ console.error(`Failed to delete invalid global hologram at ${tableName}/${key}:`, deleteError);
380
381
  }
382
+ return;
381
383
  }
382
- } catch (error) {
383
- console.error('Error parsing data:', error);
384
+
385
+ if (resolved !== parsed) {
386
+ output.push(resolved);
387
+ } else {
388
+ output.push(parsed);
389
+ }
390
+ } else {
391
+ output.push(parsed);
384
392
  }
393
+ } catch (error) {
394
+ console.error('Error parsing data:', error);
385
395
  }
386
- resolveItem();
387
- })
388
- );
389
-
390
- await Promise.all(promises);
391
- clearTimeout(timeout);
392
- if (!isResolved) {
393
- isResolved = true;
394
- resolve(output);
395
- }
396
- };
396
+ })();
397
397
 
398
- const dataPath = password ?
399
- user.get('private').get(tableName) :
400
- holoInstance.gun.get(holoInstance.appname).get(tableName);
398
+ pendingProcessing.push(processingPromise);
399
+ receivedCount++;
401
400
 
402
- dataPath.once(handleData);
401
+ if (receivedCount >= expectedCount) {
402
+ await Promise.all(pendingProcessing);
403
+ resolve(output);
404
+ }
405
+ });
406
+ });
403
407
  });
404
408
  } catch (error) {
405
409
  console.error('Error in getAllGlobal:', error);