holosphere 2.0.0-alpha1 → 2.0.0-alpha4

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 (154) hide show
  1. package/dist/2019-D2OG2idw.js +6680 -0
  2. package/dist/2019-D2OG2idw.js.map +1 -0
  3. package/dist/2019-EION3wKo.cjs +8 -0
  4. package/dist/2019-EION3wKo.cjs.map +1 -0
  5. package/dist/_commonjsHelpers-C37NGDzP.cjs +2 -0
  6. package/dist/_commonjsHelpers-C37NGDzP.cjs.map +1 -0
  7. package/dist/_commonjsHelpers-CUmg6egw.js +7 -0
  8. package/dist/_commonjsHelpers-CUmg6egw.js.map +1 -0
  9. package/dist/browser-BSniCNqO.js +3058 -0
  10. package/dist/browser-BSniCNqO.js.map +1 -0
  11. package/dist/browser-Cq59Ij19.cjs +2 -0
  12. package/dist/browser-Cq59Ij19.cjs.map +1 -0
  13. package/dist/cjs/holosphere.cjs +2 -0
  14. package/dist/cjs/holosphere.cjs.map +1 -0
  15. package/dist/esm/holosphere.js +53 -0
  16. package/dist/esm/holosphere.js.map +1 -0
  17. package/dist/index-BB_vVJgv.cjs +5 -0
  18. package/dist/index-BB_vVJgv.cjs.map +1 -0
  19. package/dist/index-CBitK71M.cjs +12 -0
  20. package/dist/index-CBitK71M.cjs.map +1 -0
  21. package/dist/index-CV0eOogK.js +37423 -0
  22. package/dist/index-CV0eOogK.js.map +1 -0
  23. package/dist/index-Cz-PLCUR.js +15104 -0
  24. package/dist/index-Cz-PLCUR.js.map +1 -0
  25. package/dist/indexeddb-storage-CRsZyB2f.cjs +2 -0
  26. package/dist/indexeddb-storage-CRsZyB2f.cjs.map +1 -0
  27. package/dist/indexeddb-storage-DZaGlY_a.js +132 -0
  28. package/dist/indexeddb-storage-DZaGlY_a.js.map +1 -0
  29. package/dist/memory-storage-BkUi6sZG.js +51 -0
  30. package/dist/memory-storage-BkUi6sZG.js.map +1 -0
  31. package/dist/memory-storage-C0DuUsdY.cjs +2 -0
  32. package/dist/memory-storage-C0DuUsdY.cjs.map +1 -0
  33. package/dist/secp256k1-0kPdAVkK.cjs +12 -0
  34. package/dist/secp256k1-0kPdAVkK.cjs.map +1 -0
  35. package/dist/secp256k1-DN4FVXcv.js +1890 -0
  36. package/dist/secp256k1-DN4FVXcv.js.map +1 -0
  37. package/docs/CONTRACTS.md +797 -0
  38. package/docs/FOSDEM_PROPOSAL.md +388 -0
  39. package/docs/LOCALFIRST.md +266 -0
  40. package/docs/contracts/api-interface.md +793 -0
  41. package/docs/data-model.md +476 -0
  42. package/docs/gun-async-usage.md +338 -0
  43. package/docs/plan.md +349 -0
  44. package/docs/quickstart.md +674 -0
  45. package/docs/research.md +362 -0
  46. package/docs/spec.md +244 -0
  47. package/docs/storage-backends.md +326 -0
  48. package/docs/tasks.md +947 -0
  49. package/examples/demo.html +47 -0
  50. package/package.json +10 -5
  51. package/src/contracts/abis/Appreciative.json +1280 -0
  52. package/src/contracts/abis/AppreciativeFactory.json +101 -0
  53. package/src/contracts/abis/Bundle.json +1435 -0
  54. package/src/contracts/abis/BundleFactory.json +106 -0
  55. package/src/contracts/abis/Holon.json +881 -0
  56. package/src/contracts/abis/Holons.json +330 -0
  57. package/src/contracts/abis/Managed.json +1262 -0
  58. package/src/contracts/abis/ManagedFactory.json +149 -0
  59. package/src/contracts/abis/Membrane.json +261 -0
  60. package/src/contracts/abis/Splitter.json +1624 -0
  61. package/src/contracts/abis/SplitterFactory.json +220 -0
  62. package/src/contracts/abis/TestToken.json +321 -0
  63. package/src/contracts/abis/Zoned.json +1461 -0
  64. package/src/contracts/abis/ZonedFactory.json +154 -0
  65. package/src/contracts/chain-manager.js +375 -0
  66. package/src/contracts/deployer.js +443 -0
  67. package/src/contracts/event-listener.js +507 -0
  68. package/src/contracts/holon-contracts.js +344 -0
  69. package/src/contracts/index.js +83 -0
  70. package/src/contracts/networks.js +224 -0
  71. package/src/contracts/operations.js +670 -0
  72. package/src/contracts/queries.js +589 -0
  73. package/src/core/holosphere.js +453 -1
  74. package/src/crypto/nostr-utils.js +263 -0
  75. package/src/federation/handshake.js +455 -0
  76. package/src/federation/hologram.js +1 -1
  77. package/src/hierarchical/upcast.js +6 -5
  78. package/src/index.js +463 -1939
  79. package/src/lib/ai-methods.js +308 -0
  80. package/src/lib/contract-methods.js +293 -0
  81. package/src/lib/errors.js +23 -0
  82. package/src/lib/federation-methods.js +238 -0
  83. package/src/lib/index.js +26 -0
  84. package/src/spatial/h3-operations.js +2 -2
  85. package/src/storage/backends/gundb-backend.js +377 -46
  86. package/src/storage/global-tables.js +28 -1
  87. package/src/storage/gun-auth.js +303 -0
  88. package/src/storage/gun-federation.js +776 -0
  89. package/src/storage/gun-references.js +198 -0
  90. package/src/storage/gun-schema.js +291 -0
  91. package/src/storage/gun-wrapper.js +347 -31
  92. package/src/storage/indexeddb-storage.js +49 -11
  93. package/src/storage/memory-storage.js +5 -0
  94. package/src/storage/nostr-async.js +45 -23
  95. package/src/storage/nostr-client.js +11 -5
  96. package/src/storage/persistent-storage.js +6 -1
  97. package/src/storage/unified-storage.js +119 -0
  98. package/src/subscriptions/manager.js +1 -1
  99. package/types/index.d.ts +133 -0
  100. package/tests/unit/ai/aggregation.test.js +0 -295
  101. package/tests/unit/ai/breakdown.test.js +0 -446
  102. package/tests/unit/ai/classifier.test.js +0 -294
  103. package/tests/unit/ai/council.test.js +0 -262
  104. package/tests/unit/ai/embeddings.test.js +0 -384
  105. package/tests/unit/ai/federation-ai.test.js +0 -344
  106. package/tests/unit/ai/h3-ai.test.js +0 -458
  107. package/tests/unit/ai/index.test.js +0 -304
  108. package/tests/unit/ai/json-ops.test.js +0 -307
  109. package/tests/unit/ai/llm-service.test.js +0 -390
  110. package/tests/unit/ai/nl-query.test.js +0 -383
  111. package/tests/unit/ai/relationships.test.js +0 -311
  112. package/tests/unit/ai/schema-extractor.test.js +0 -384
  113. package/tests/unit/ai/spatial.test.js +0 -279
  114. package/tests/unit/ai/tts.test.js +0 -279
  115. package/tests/unit/content.test.js +0 -332
  116. package/tests/unit/contract/core.test.js +0 -88
  117. package/tests/unit/contract/crypto.test.js +0 -198
  118. package/tests/unit/contract/data.test.js +0 -223
  119. package/tests/unit/contract/federation.test.js +0 -181
  120. package/tests/unit/contract/hierarchical.test.js +0 -113
  121. package/tests/unit/contract/schema.test.js +0 -114
  122. package/tests/unit/contract/social.test.js +0 -217
  123. package/tests/unit/contract/spatial.test.js +0 -110
  124. package/tests/unit/contract/subscriptions.test.js +0 -128
  125. package/tests/unit/contract/utils.test.js +0 -159
  126. package/tests/unit/core.test.js +0 -152
  127. package/tests/unit/crypto.test.js +0 -328
  128. package/tests/unit/federation.test.js +0 -234
  129. package/tests/unit/gun-async.test.js +0 -252
  130. package/tests/unit/hierarchical.test.js +0 -399
  131. package/tests/unit/integration/scenario-01-geographic-storage.test.js +0 -74
  132. package/tests/unit/integration/scenario-02-federation.test.js +0 -76
  133. package/tests/unit/integration/scenario-03-subscriptions.test.js +0 -102
  134. package/tests/unit/integration/scenario-04-validation.test.js +0 -129
  135. package/tests/unit/integration/scenario-05-hierarchy.test.js +0 -125
  136. package/tests/unit/integration/scenario-06-social.test.js +0 -135
  137. package/tests/unit/integration/scenario-07-persistence.test.js +0 -130
  138. package/tests/unit/integration/scenario-08-authorization.test.js +0 -161
  139. package/tests/unit/integration/scenario-09-cross-dimensional.test.js +0 -139
  140. package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +0 -357
  141. package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +0 -410
  142. package/tests/unit/integration/scenario-12-capability-federated-read.test.js +0 -719
  143. package/tests/unit/performance/benchmark.test.js +0 -85
  144. package/tests/unit/schema.test.js +0 -213
  145. package/tests/unit/spatial.test.js +0 -158
  146. package/tests/unit/storage.test.js +0 -195
  147. package/tests/unit/subscriptions.test.js +0 -328
  148. package/tests/unit/test-data-permanence-debug.js +0 -197
  149. package/tests/unit/test-data-permanence.js +0 -340
  150. package/tests/unit/test-key-persistence-fixed.js +0 -148
  151. package/tests/unit/test-key-persistence.js +0 -172
  152. package/tests/unit/test-relay-permanence.js +0 -376
  153. package/tests/unit/test-second-node.js +0 -95
  154. package/tests/unit/test-simple-write.js +0 -89
@@ -1,113 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- describe('Contract: Hierarchical Operations', () => {
5
- let hs;
6
- let testHolonId;
7
-
8
- beforeEach(async () => {
9
- hs = new HoloSphere({ relays: [], appName: 'test-hierarchical' });
10
- testHolonId = await hs.toHolon(37.7749, -122.4194, 9);
11
- });
12
-
13
- describe('upcast()', () => {
14
- it('should propagate data to parent holons', async () => {
15
- await hs.write(testHolonId, 'events', {
16
- id: 'event-001',
17
- name: 'Test Event'
18
- });
19
-
20
- const success = await hs.upcast(testHolonId, 'events', 'event-001');
21
- expect(success).toBe(true);
22
- });
23
-
24
- it('should accept maxLevel option', async () => {
25
- await hs.write(testHolonId, 'events', { id: 'event-001', name: 'Test' });
26
-
27
- const success = await hs.upcast(
28
- testHolonId,
29
- 'events',
30
- 'event-001',
31
- { maxLevel: 3 }
32
- );
33
- expect(success).toBe(true);
34
- });
35
-
36
- it('should accept operation option: summarize', async () => {
37
- await hs.write(testHolonId, 'events', { id: 'event-001', name: 'Test' });
38
-
39
- const success = await hs.upcast(
40
- testHolonId,
41
- 'events',
42
- 'event-001',
43
- { operation: 'summarize' }
44
- );
45
- expect(success).toBe(true);
46
- });
47
-
48
- it('should accept operation option: aggregate', async () => {
49
- await hs.write(testHolonId, 'events', { id: 'event-001', count: 5 });
50
-
51
- const success = await hs.upcast(
52
- testHolonId,
53
- 'events',
54
- 'event-001',
55
- { operation: 'aggregate' }
56
- );
57
- expect(success).toBe(true);
58
- });
59
-
60
- it('should accept operation option: concatenate (default)', async () => {
61
- await hs.write(testHolonId, 'events', { id: 'event-001', items: [1, 2, 3] });
62
-
63
- const success = await hs.upcast(
64
- testHolonId,
65
- 'events',
66
- 'event-001',
67
- { operation: 'concatenate' }
68
- );
69
- expect(success).toBe(true);
70
- });
71
-
72
- it('should throw Error for noospheric holons (no hierarchy)', async () => {
73
- const noospheric = 'nostr://topic/test';
74
-
75
- await hs.write(noospheric, 'content', { id: 'post-1', text: 'Hello' });
76
-
77
- await expect(
78
- hs.upcast(noospheric, 'content', 'post-1')
79
- ).rejects.toThrow(Error);
80
- });
81
-
82
- it('should respect maxLevel limit', async () => {
83
- await hs.write(testHolonId, 'events', { id: 'event-001', name: 'Test' });
84
-
85
- const success = await hs.upcast(
86
- testHolonId,
87
- 'events',
88
- 'event-001',
89
- { maxLevel: 1 }
90
- );
91
- expect(success).toBe(true);
92
-
93
- // Verify data only propagated to immediate parent
94
- const parents = await hs.getParents(testHolonId);
95
- const immediateParent = parents[0];
96
- const data = await hs.read(immediateParent, 'events');
97
- expect(data.length).toBeGreaterThan(0);
98
- });
99
-
100
- it('should handle upcast to resolution 0 (global level)', async () => {
101
- const highResHolon = await hs.toHolon(37.7749, -122.4194, 12);
102
- await hs.write(highResHolon, 'events', { id: 'event-001', name: 'Test' });
103
-
104
- const success = await hs.upcast(
105
- highResHolon,
106
- 'events',
107
- 'event-001',
108
- { maxLevel: Infinity }
109
- );
110
- expect(success).toBe(true);
111
- });
112
- });
113
- });
@@ -1,114 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- describe('Contract: Schema Operations', () => {
5
- let hs;
6
-
7
- beforeEach(() => {
8
- hs = new HoloSphere({ relays: [], appName: 'test-schema' });
9
- });
10
-
11
- describe('setSchema()', () => {
12
- it('should set schema for a lens', async () => {
13
- await expect(
14
- hs.setSchema('temperature', 'https://example.com/schemas/temperature.json')
15
- ).resolves.toBeUndefined();
16
- });
17
-
18
- it('should set schema with strict mode enabled', async () => {
19
- await expect(
20
- hs.setSchema('temperature', 'https://example.com/schemas/temperature.json', true)
21
- ).resolves.toBeUndefined();
22
- });
23
-
24
- it('should set schema with strict mode disabled (default)', async () => {
25
- await expect(
26
- hs.setSchema('temperature', 'https://example.com/schemas/temperature.json', false)
27
- ).resolves.toBeUndefined();
28
- });
29
-
30
- it('should accept URI schemas without fetching', async () => {
31
- // URI schemas are stored as references without fetching
32
- await expect(
33
- hs.setSchema('temperature', 'https://nonexistent.invalid/schema.json')
34
- ).resolves.toBeUndefined();
35
- });
36
-
37
- it('should store invalid schema objects and validate on use', async () => {
38
- // Invalid schemas are caught during validation, not during setSchema
39
- const invalidSchema = { notAValidSchema: true };
40
- await expect(
41
- hs.setSchema('temperature', invalidSchema)
42
- ).rejects.toThrow('ValidationError');
43
- });
44
-
45
- it('should validate JSON Schema 2019 format', async () => {
46
- const validSchema = {
47
- $schema: 'https://json-schema.org/draft/2019-09/schema',
48
- type: 'object',
49
- properties: {
50
- id: { type: 'string' },
51
- value: { type: 'number' }
52
- }
53
- };
54
-
55
- // Assuming schema can be passed directly or via URI
56
- await expect(
57
- hs.setSchema('temperature', 'test://valid-schema')
58
- ).resolves.toBeUndefined();
59
- });
60
- });
61
-
62
- describe('getSchema()', () => {
63
- it('should return schema object if set', async () => {
64
- await hs.setSchema('temperature', 'https://example.com/schemas/temperature.json');
65
-
66
- const schema = await hs.getSchema('temperature');
67
- expect(schema).not.toBe(null);
68
- expect(typeof schema).toBe('object');
69
- });
70
-
71
- it('should return null if schema not set', async () => {
72
- const schema = await hs.getSchema('nonexistent');
73
- expect(schema).toBe(null);
74
- });
75
-
76
- it('should return URI reference schema object', async () => {
77
- await hs.setSchema('temperature', 'https://example.com/schemas/temperature.json');
78
-
79
- const schema = await hs.getSchema('temperature');
80
- // URI schemas are stored as {$ref: uri}
81
- expect(schema).toHaveProperty('$ref');
82
- expect(schema.$ref).toBe('https://example.com/schemas/temperature.json');
83
- });
84
- });
85
-
86
- describe('clearSchema()', () => {
87
- it('should remove schema from lens', async () => {
88
- await hs.setSchema('temperature', 'https://example.com/schemas/temperature.json');
89
-
90
- await expect(
91
- hs.clearSchema('temperature')
92
- ).resolves.toBeUndefined();
93
-
94
- const schema = await hs.getSchema('temperature');
95
- expect(schema).toBe(null);
96
- });
97
-
98
- it('should be idempotent (no error if schema not set)', async () => {
99
- await expect(
100
- hs.clearSchema('nonexistent')
101
- ).resolves.toBeUndefined();
102
- });
103
-
104
- it('should clear schema without affecting other lenses', async () => {
105
- await hs.setSchema('temperature', 'https://example.com/schemas/temperature.json');
106
- await hs.setSchema('humidity', 'https://example.com/schemas/humidity.json');
107
-
108
- await hs.clearSchema('temperature');
109
-
110
- expect(await hs.getSchema('temperature')).toBe(null);
111
- expect(await hs.getSchema('humidity')).not.toBe(null);
112
- });
113
- });
114
- });
@@ -1,217 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- describe('Contract: Social Protocol Operations', () => {
5
- let hs;
6
- let testHolonId;
7
-
8
- beforeEach(async () => {
9
- hs = new HoloSphere({ relays: [], appName: 'test-social' });
10
- testHolonId = await hs.toHolon(37.7749, -122.4194, 9);
11
- });
12
-
13
- describe('publishNostr()', () => {
14
- it('should publish valid Nostr event', async () => {
15
- const event = {
16
- kind: 1,
17
- content: 'Hello from HoloSphere!',
18
- tags: [['t', 'holosphere']],
19
- created_at: Math.floor(Date.now() / 1000)
20
- };
21
-
22
- const success = await hs.publishNostr(event, testHolonId);
23
- expect(success).toBe(true);
24
- });
25
-
26
- it('should use default lens name "social" when not specified', async () => {
27
- const event = {
28
- kind: 1,
29
- content: 'Test post',
30
- tags: [],
31
- created_at: Math.floor(Date.now() / 1000)
32
- };
33
-
34
- const success = await hs.publishNostr(event, testHolonId);
35
- expect(success).toBe(true);
36
- });
37
-
38
- it('should accept custom lens name', async () => {
39
- const event = {
40
- kind: 1,
41
- content: 'Test post',
42
- tags: [],
43
- created_at: Math.floor(Date.now() / 1000)
44
- };
45
-
46
- const success = await hs.publishNostr(event, testHolonId, 'custom-lens');
47
- expect(success).toBe(true);
48
- });
49
-
50
- it('should throw ValidationError for invalid event format', async () => {
51
- const invalidEvent = {
52
- kind: 'invalid',
53
- content: 123
54
- };
55
-
56
- await expect(
57
- hs.publishNostr(invalidEvent, testHolonId)
58
- ).rejects.toThrow('ValidationError');
59
- });
60
-
61
- it('should validate NIP-01 format', async () => {
62
- const event = {
63
- kind: 1,
64
- content: 'Valid NIP-01 event',
65
- tags: [['e', 'event-id'], ['p', 'pubkey']],
66
- created_at: Math.floor(Date.now() / 1000)
67
- };
68
-
69
- const success = await hs.publishNostr(event, testHolonId);
70
- expect(success).toBe(true);
71
- });
72
-
73
- it('should automatically sign event', async () => {
74
- const event = {
75
- kind: 1,
76
- content: 'Auto-signed event',
77
- tags: [],
78
- created_at: Math.floor(Date.now() / 1000)
79
- };
80
-
81
- const success = await hs.publishNostr(event, testHolonId);
82
- expect(success).toBe(true);
83
-
84
- // Verify event was signed
85
- const published = await hs.querySocial(testHolonId, { protocol: 'nostr' });
86
- expect(published[0]).toHaveProperty('sig');
87
- expect(published[0]).toHaveProperty('pubkey');
88
- });
89
- });
90
-
91
- describe('publishActivityPub()', () => {
92
- it('should publish valid ActivityPub object', async () => {
93
- const object = {
94
- '@context': 'https://www.w3.org/ns/activitystreams',
95
- type: 'Note',
96
- content: 'Hello from HoloSphere!',
97
- published: new Date().toISOString()
98
- };
99
-
100
- const success = await hs.publishActivityPub(object, testHolonId);
101
- expect(success).toBe(true);
102
- });
103
-
104
- it('should use default lens name "social" when not specified', async () => {
105
- const object = {
106
- '@context': 'https://www.w3.org/ns/activitystreams',
107
- type: 'Note',
108
- content: 'Test note'
109
- };
110
-
111
- const success = await hs.publishActivityPub(object, testHolonId);
112
- expect(success).toBe(true);
113
- });
114
-
115
- it('should accept custom lens name', async () => {
116
- const object = {
117
- '@context': 'https://www.w3.org/ns/activitystreams',
118
- type: 'Note',
119
- content: 'Test note'
120
- };
121
-
122
- const success = await hs.publishActivityPub(object, testHolonId, 'custom-lens');
123
- expect(success).toBe(true);
124
- });
125
-
126
- it('should throw ValidationError for invalid object format', async () => {
127
- const invalidObject = {
128
- type: 'Invalid',
129
- content: 123
130
- };
131
-
132
- await expect(
133
- hs.publishActivityPub(invalidObject, testHolonId)
134
- ).rejects.toThrow('ValidationError');
135
- });
136
-
137
- it('should support different ActivityPub types', async () => {
138
- const article = {
139
- '@context': 'https://www.w3.org/ns/activitystreams',
140
- type: 'Article',
141
- name: 'Test Article',
142
- content: 'Article content'
143
- };
144
-
145
- const success = await hs.publishActivityPub(article, testHolonId);
146
- expect(success).toBe(true);
147
- });
148
- });
149
-
150
- describe('querySocial()', () => {
151
- it('should return array of social content', async () => {
152
- const nostrEvent = {
153
- kind: 1,
154
- content: 'Test',
155
- tags: [],
156
- created_at: Math.floor(Date.now() / 1000)
157
- };
158
-
159
- await hs.publishNostr(nostrEvent, testHolonId);
160
-
161
- const results = await hs.querySocial(testHolonId);
162
- expect(Array.isArray(results)).toBe(true);
163
- });
164
-
165
- it('should filter by protocol: nostr', async () => {
166
- const results = await hs.querySocial(testHolonId, { protocol: 'nostr' });
167
- expect(Array.isArray(results)).toBe(true);
168
- });
169
-
170
- it('should filter by protocol: activitypub', async () => {
171
- const results = await hs.querySocial(testHolonId, { protocol: 'activitypub' });
172
- expect(Array.isArray(results)).toBe(true);
173
- });
174
-
175
- it('should filter by protocol: all (default)', async () => {
176
- const results = await hs.querySocial(testHolonId, { protocol: 'all' });
177
- expect(Array.isArray(results)).toBe(true);
178
- });
179
-
180
- it('should filter by accessLevel: public (default)', async () => {
181
- const results = await hs.querySocial(testHolonId, { accessLevel: 'public' });
182
- expect(Array.isArray(results)).toBe(true);
183
- });
184
-
185
- it('should filter by accessLevel: protected', async () => {
186
- const results = await hs.querySocial(testHolonId, { accessLevel: 'protected' });
187
- expect(Array.isArray(results)).toBe(true);
188
- });
189
-
190
- it('should accept custom lensName option', async () => {
191
- const results = await hs.querySocial(testHolonId, { lensName: 'custom-lens' });
192
- expect(Array.isArray(results)).toBe(true);
193
- });
194
-
195
- it('should return empty array if no content exists', async () => {
196
- const emptyHolon = await hs.toHolon(40.7128, -74.0060, 9);
197
- const results = await hs.querySocial(emptyHolon);
198
- expect(results).toEqual([]);
199
- });
200
-
201
- it('should include cryptographic signatures in results', async () => {
202
- const event = {
203
- kind: 1,
204
- content: 'Signed content',
205
- tags: [],
206
- created_at: Math.floor(Date.now() / 1000)
207
- };
208
-
209
- await hs.publishNostr(event, testHolonId);
210
-
211
- const results = await hs.querySocial(testHolonId, { protocol: 'nostr' });
212
- if (results.length > 0) {
213
- expect(results[0]).toHaveProperty('sig');
214
- }
215
- });
216
- });
217
- });
@@ -1,110 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- describe('Contract: Spatial Operations', () => {
5
- const hs = new HoloSphere({ relays: [], appName: 'test-spatial' });
6
-
7
- describe('toHolon()', () => {
8
- it('should convert valid coordinates to H3 string', async () => {
9
- const holonId = await hs.toHolon(37.7749, -122.4194, 9);
10
- expect(typeof holonId).toBe('string');
11
- expect(holonId).toMatch(/^8[0-9a-f]+$/);
12
- expect(holonId.length).toBeGreaterThanOrEqual(15);
13
- });
14
-
15
- it('should throw RangeError for latitude out of bounds', async () => {
16
- await expect(hs.toHolon(91, -122.4194, 9)).rejects.toThrow(RangeError);
17
- await expect(hs.toHolon(-91, -122.4194, 9)).rejects.toThrow(RangeError);
18
- });
19
-
20
- it('should throw RangeError for longitude out of bounds', async () => {
21
- await expect(hs.toHolon(37.7749, 181, 9)).rejects.toThrow(RangeError);
22
- await expect(hs.toHolon(37.7749, -181, 9)).rejects.toThrow(RangeError);
23
- });
24
-
25
- it('should throw RangeError for invalid resolution', async () => {
26
- await expect(hs.toHolon(37.7749, -122.4194, -1)).rejects.toThrow(RangeError);
27
- await expect(hs.toHolon(37.7749, -122.4194, 16)).rejects.toThrow(RangeError);
28
- });
29
-
30
- it('should handle resolution 0 (largest hexagons)', async () => {
31
- const holonId = await hs.toHolon(37.7749, -122.4194, 0);
32
- expect(typeof holonId).toBe('string');
33
- });
34
-
35
- it('should handle resolution 15 (smallest hexagons)', async () => {
36
- const holonId = await hs.toHolon(37.7749, -122.4194, 15);
37
- expect(typeof holonId).toBe('string');
38
- });
39
- });
40
-
41
- describe('getParents()', () => {
42
- it('should return array of parent H3 IDs', async () => {
43
- const holonId = await hs.toHolon(37.7749, -122.4194, 9);
44
- const parents = await hs.getParents(holonId);
45
- expect(Array.isArray(parents)).toBe(true);
46
- expect(parents.length).toBeGreaterThan(0);
47
- parents.forEach(parent => {
48
- expect(typeof parent).toBe('string');
49
- expect(parent).toMatch(/^8[0-9a-f]+$/);
50
- });
51
- });
52
-
53
- it('should return parents up to maxResolution', async () => {
54
- const holonId = await hs.toHolon(37.7749, -122.4194, 9);
55
- const parents = await hs.getParents(holonId, 5);
56
- expect(Array.isArray(parents)).toBe(true);
57
- // Should stop at resolution 5
58
- });
59
-
60
- it('should throw Error for invalid H3 ID', async () => {
61
- await expect(hs.getParents('invalid')).rejects.toThrow(Error);
62
- });
63
-
64
- it('should return empty array for resolution 0 holon', async () => {
65
- const holonId = await hs.toHolon(37.7749, -122.4194, 0);
66
- const parents = await hs.getParents(holonId);
67
- expect(parents).toEqual([]);
68
- });
69
- });
70
-
71
- describe('getChildren()', () => {
72
- it('should return 7 children for valid H3 ID', async () => {
73
- const holonId = await hs.toHolon(37.7749, -122.4194, 9);
74
- const children = await hs.getChildren(holonId);
75
- expect(Array.isArray(children)).toBe(true);
76
- expect(children.length).toBe(7);
77
- children.forEach(child => {
78
- expect(typeof child).toBe('string');
79
- expect(child).toMatch(/^8[0-9a-f]+$/);
80
- });
81
- });
82
-
83
- it('should throw Error for invalid H3 ID', async () => {
84
- await expect(hs.getChildren('invalid')).rejects.toThrow(Error);
85
- });
86
-
87
- it('should throw Error for resolution 15 (no children possible)', async () => {
88
- const holonId = await hs.toHolon(37.7749, -122.4194, 15);
89
- await expect(hs.getChildren(holonId)).rejects.toThrow(Error);
90
- });
91
- });
92
-
93
- describe('isValidH3()', () => {
94
- it('should return true for valid H3 ID', () => {
95
- const result = hs.isValidH3('8928342e20fffff');
96
- expect(result).toBe(true);
97
- });
98
-
99
- it('should return false for invalid string', () => {
100
- const result = hs.isValidH3('invalid');
101
- expect(result).toBe(false);
102
- });
103
-
104
- it('should return false for non-string input', () => {
105
- expect(hs.isValidH3(123)).toBe(false);
106
- expect(hs.isValidH3(null)).toBe(false);
107
- expect(hs.isValidH3(undefined)).toBe(false);
108
- });
109
- });
110
- });
@@ -1,128 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- describe('Contract: Subscription Operations', () => {
5
- let hs;
6
- let testHolonId;
7
-
8
- beforeEach(async () => {
9
- hs = new HoloSphere({ relays: [], appName: 'test-subscriptions' });
10
- testHolonId = await hs.toHolon(37.7749, -122.4194, 9);
11
- });
12
-
13
- describe('subscribe()', () => {
14
- it('should return subscription object with unsubscribe method', () => {
15
- const callback = vi.fn();
16
- const subscription = hs.subscribe(testHolonId, 'temperature', callback);
17
-
18
- expect(subscription).toHaveProperty('unsubscribe');
19
- expect(typeof subscription.unsubscribe).toBe('function');
20
- });
21
-
22
- it('should invoke callback on data write', async () => {
23
- const callback = vi.fn();
24
- const subscription = hs.subscribe(testHolonId, 'temperature', callback);
25
-
26
- await hs.write(testHolonId, 'temperature', {
27
- id: 'sensor-001',
28
- value: 72.5
29
- });
30
-
31
- // Wait for async callback
32
- await new Promise(resolve => setTimeout(resolve, 100));
33
-
34
- expect(callback).toHaveBeenCalled();
35
- subscription.unsubscribe();
36
- });
37
-
38
- it('should invoke callback on data update', async () => {
39
- await hs.write(testHolonId, 'temperature', { id: 'sensor-001', value: 72 });
40
-
41
- const callback = vi.fn();
42
- const subscription = hs.subscribe(testHolonId, 'temperature', callback);
43
-
44
- await hs.update(testHolonId, 'temperature', 'sensor-001', { value: 73 });
45
-
46
- await new Promise(resolve => setTimeout(resolve, 100));
47
-
48
- expect(callback).toHaveBeenCalled();
49
- subscription.unsubscribe();
50
- });
51
-
52
- it('should stop callbacks after unsubscribe', async () => {
53
- const callback = vi.fn();
54
- const subscription = hs.subscribe(testHolonId, 'temperature', callback);
55
-
56
- subscription.unsubscribe();
57
-
58
- await hs.write(testHolonId, 'temperature', { id: 'sensor-001', value: 72 });
59
- await new Promise(resolve => setTimeout(resolve, 100));
60
-
61
- expect(callback).not.toHaveBeenCalled();
62
- });
63
-
64
- it('should accept includeFederated option', () => {
65
- const callback = vi.fn();
66
- const subscription = hs.subscribe(
67
- testHolonId,
68
- 'temperature',
69
- callback,
70
- { includeFederated: true }
71
- );
72
-
73
- expect(subscription).toHaveProperty('unsubscribe');
74
- subscription.unsubscribe();
75
- });
76
-
77
- it('should accept throttle option', () => {
78
- const callback = vi.fn();
79
- const subscription = hs.subscribe(
80
- testHolonId,
81
- 'temperature',
82
- callback,
83
- { throttle: 1000 }
84
- );
85
-
86
- expect(subscription).toHaveProperty('unsubscribe');
87
- subscription.unsubscribe();
88
- });
89
-
90
- it('should accept filter option', () => {
91
- const callback = vi.fn();
92
- const subscription = hs.subscribe(
93
- testHolonId,
94
- 'temperature',
95
- callback,
96
- { filter: (data) => data.value > 75 }
97
- );
98
-
99
- expect(subscription).toHaveProperty('unsubscribe');
100
- subscription.unsubscribe();
101
- });
102
-
103
- it('should throw TypeError if callback is not a function', () => {
104
- expect(() => {
105
- hs.subscribe(testHolonId, 'temperature', 'not-a-function');
106
- }).toThrow(TypeError);
107
- });
108
-
109
- it('should pass data and key to callback', async () => {
110
- const callback = vi.fn();
111
- const subscription = hs.subscribe(testHolonId, 'temperature', callback);
112
-
113
- await hs.write(testHolonId, 'temperature', {
114
- id: 'sensor-001',
115
- value: 72.5
116
- });
117
-
118
- await new Promise(resolve => setTimeout(resolve, 100));
119
-
120
- expect(callback).toHaveBeenCalledWith(
121
- expect.objectContaining({ id: 'sensor-001', value: 72.5 }),
122
- expect.any(String)
123
- );
124
-
125
- subscription.unsubscribe();
126
- });
127
- });
128
- });