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,139 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- describe('Integration: Scenario 9 - Cross-Dimensional Federation', () => {
5
- let hs;
6
-
7
- beforeEach(() => {
8
- hs = new HoloSphere({ relays: [], appName: 'scenario-09' });
9
- });
10
-
11
- it('should complete cross-dimensional federation workflow', async () => {
12
- // Step 1: Create data in geographic holon (San Francisco)
13
- const geoHolon = await hs.toHolon(37.7749, -122.4194, 9);
14
- await hs.write(geoHolon, 'discussions', {
15
- id: 'thread-001',
16
- topic: 'Urban Planning',
17
- messages: 12
18
- });
19
-
20
- // Step 2: Create noospheric holon (concept space)
21
- const conceptHolon = 'concept://urbanism/sustainable-cities';
22
- await hs.write(conceptHolon, 'discussions', {
23
- id: 'thread-002',
24
- topic: 'Sustainability Frameworks',
25
- messages: 8
26
- });
27
-
28
- // Step 3: Federate geographic ↔ noospheric (cross-dimensional link)
29
- const fedSuccess = await hs.federate(geoHolon, conceptHolon, 'discussions', {
30
- direction: 'bidirectional'
31
- });
32
- expect(fedSuccess).toBe(true);
33
-
34
- // Step 4: Query geographic holon - includes noospheric federated data
35
- const geoDiscussions = await hs.getFederatedData(geoHolon, 'discussions');
36
- expect(Array.isArray(geoDiscussions)).toBe(true);
37
- expect(geoDiscussions.length).toBeGreaterThanOrEqual(2);
38
-
39
- const hasLocal = geoDiscussions.some(d => d.id === 'thread-001');
40
- const hasFederated = geoDiscussions.some(d => d.id === 'thread-002');
41
- expect(hasLocal).toBe(true);
42
- expect(hasFederated).toBe(true);
43
-
44
- // Step 5: Query noospheric holon - includes geographic federated data
45
- const conceptDiscussions = await hs.getFederatedData(conceptHolon, 'discussions');
46
- expect(Array.isArray(conceptDiscussions)).toBe(true);
47
- expect(conceptDiscussions.length).toBeGreaterThanOrEqual(2);
48
- });
49
-
50
- it('should validate noospheric holons identified by URI/URL', async () => {
51
- const noosphericUris = [
52
- 'nostr://topic/climate',
53
- 'concept://philosophy/ethics',
54
- 'ap://community/developers',
55
- 'https://example.com/topic/blockchain'
56
- ];
57
-
58
- for (const uri of noosphericUris) {
59
- const success = await hs.write(uri, 'content', {
60
- id: 'item-001',
61
- text: 'Noospheric content'
62
- });
63
- expect(success).toBe(true);
64
- }
65
- });
66
-
67
- it('should validate federation works across geographic and conceptual dimensions', async () => {
68
- const geographic = await hs.toHolon(40.7128, -74.0060, 9); // New York
69
- const conceptual = 'concept://technology/ai';
70
-
71
- await hs.write(geographic, 'research', {
72
- id: 'study-001',
73
- title: 'AI in Urban Settings'
74
- });
75
-
76
- await hs.write(conceptual, 'research', {
77
- id: 'study-002',
78
- title: 'Machine Learning Ethics'
79
- });
80
-
81
- // Inbound: geographic subscribes to receive data from conceptual
82
- const fedSuccess = await hs.federate(geographic, conceptual, 'research', { direction: 'inbound' });
83
- expect(fedSuccess).toBe(true);
84
-
85
- // Geographic should see conceptual data (inbound federation)
86
- const geoData = await hs.getFederatedData(geographic, 'research');
87
- expect(geoData.some(d => d.id === 'study-002')).toBe(true);
88
- });
89
-
90
- it('should validate bidirectional cross-dimensional linking', async () => {
91
- const geo = await hs.toHolon(37.7749, -122.4194, 9);
92
- const concept = 'concept://sustainability/green-energy';
93
-
94
- await hs.write(geo, 'projects', { id: 'proj-001', name: 'Solar Panels' });
95
- await hs.write(concept, 'projects', { id: 'proj-002', name: 'Wind Farms' });
96
-
97
- await hs.federate(geo, concept, 'projects', { direction: 'bidirectional' });
98
-
99
- // Both directions should work
100
- const geoProjects = await hs.getFederatedData(geo, 'projects');
101
- const conceptProjects = await hs.getFederatedData(concept, 'projects');
102
-
103
- expect(geoProjects.some(p => p.id === 'proj-002')).toBe(true);
104
- expect(conceptProjects.some(p => p.id === 'proj-001')).toBe(true);
105
- });
106
-
107
- it('should validate unified query interface for both dimensions', async () => {
108
- const geographic = await hs.toHolon(37.7749, -122.4194, 9);
109
- const noospheric = 'nostr://topic/javascript';
110
-
111
- // Same API for both dimensions
112
- await hs.write(geographic, 'posts', { id: 'post-1', text: 'Geo post' });
113
- await hs.write(noospheric, 'posts', { id: 'post-2', text: 'Noo post' });
114
-
115
- const geoData = await hs.read(geographic, 'posts');
116
- const nooData = await hs.read(noospheric, 'posts');
117
-
118
- expect(Array.isArray(geoData)).toBe(true);
119
- expect(Array.isArray(nooData)).toBe(true);
120
- });
121
-
122
- it('should validate cross-dimensional navigation enabled', async () => {
123
- const sanFrancisco = await hs.toHolon(37.7749, -122.4194, 9);
124
- const techConcept = 'concept://technology/web3';
125
- const socialProtocol = 'nostr://topic/decentralization';
126
-
127
- // Create triangle of federations
128
- await hs.write(sanFrancisco, 'ideas', { id: 'idea-1', source: 'geo' });
129
- await hs.write(techConcept, 'ideas', { id: 'idea-2', source: 'concept' });
130
- await hs.write(socialProtocol, 'ideas', { id: 'idea-3', source: 'social' });
131
-
132
- await hs.federate(sanFrancisco, techConcept, 'ideas');
133
- await hs.federate(techConcept, socialProtocol, 'ideas');
134
-
135
- // Navigation across dimensions should work
136
- const sfIdeas = await hs.getFederatedData(sanFrancisco, 'ideas');
137
- expect(sfIdeas.length).toBeGreaterThanOrEqual(2);
138
- });
139
- });
@@ -1,357 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- describe('Integration: Scenario 10 - Cross-Holosphere Capability Tokens', () => {
5
- // Two distinct private keys for two separate holospheres
6
- const privateKeyA = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
7
- const privateKeyB = 'fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210';
8
-
9
- let holosphereA;
10
- let holosphereB;
11
- let publicKeyA;
12
- let publicKeyB;
13
- let testHolon;
14
-
15
- beforeEach(async () => {
16
- // Create two independent holospheres with different private keys
17
- holosphereA = new HoloSphere({
18
- relays: [],
19
- appName: 'scenario-10-a',
20
- privateKey: privateKeyA,
21
- logLevel: 'ERROR'
22
- });
23
-
24
- holosphereB = new HoloSphere({
25
- relays: [],
26
- appName: 'scenario-10-b',
27
- privateKey: privateKeyB,
28
- logLevel: 'ERROR'
29
- });
30
-
31
- // Get public keys
32
- publicKeyA = holosphereA.client.publicKey;
33
- publicKeyB = holosphereB.client.publicKey;
34
-
35
- // Create a test holon (H3 cell)
36
- testHolon = await holosphereA.toHolon(37.7749, -122.4194, 9);
37
- });
38
-
39
- afterEach(async () => {
40
- // Clean up any subscriptions or connections
41
- if (holosphereA && holosphereA.client) {
42
- await holosphereA.client.close?.();
43
- }
44
- if (holosphereB && holosphereB.client) {
45
- await holosphereB.client.close?.();
46
- }
47
- });
48
-
49
- it('should have different public keys for different private keys', () => {
50
- expect(publicKeyA).toBeDefined();
51
- expect(publicKeyB).toBeDefined();
52
- expect(publicKeyA).not.toBe(publicKeyB);
53
- });
54
-
55
- it('should NOT allow holosphere B to see data written by holosphere A without capability', async () => {
56
- // Step 1: Holosphere A writes private data
57
- const secretData = {
58
- id: 'secret-001',
59
- content: 'This is private data from Holosphere A',
60
- _creator: publicKeyA
61
- };
62
-
63
- await holosphereA.write(testHolon, 'private-docs', secretData);
64
-
65
- // Step 2: Verify holosphere A can read its own data
66
- const dataFromA = await holosphereA.read(testHolon, 'private-docs', 'secret-001');
67
- expect(dataFromA).toBeDefined();
68
- expect(dataFromA.content).toBe('This is private data from Holosphere A');
69
-
70
- // Step 3: Holosphere B tries to read the same data
71
- // Since they use different appNames and no federation, B should NOT see A's data
72
- const dataFromB = await holosphereB.read(testHolon, 'private-docs', 'secret-001');
73
-
74
- // B should not be able to see A's data (different namespace/holosphere)
75
- expect(dataFromB).toBeNull();
76
- });
77
-
78
- it('should allow access after capability token is granted', async () => {
79
- // Step 1: Holosphere A writes data
80
- const sharedData = {
81
- id: 'shared-001',
82
- content: 'This data will be shared via capability token',
83
- _creator: publicKeyA
84
- };
85
-
86
- await holosphereA.write(testHolon, 'shared-docs', sharedData);
87
-
88
- // Step 2: Verify initial state - B cannot see data
89
- const initialReadByB = await holosphereB.read(testHolon, 'shared-docs', 'shared-001');
90
- expect(initialReadByB).toBeNull();
91
-
92
- // Step 3: Holosphere A issues a READ capability token to Holosphere B
93
- const readCapabilityToken = await holosphereA.issueCapability(
94
- ['read'],
95
- { holonId: testHolon, lensName: 'shared-docs' },
96
- publicKeyB,
97
- {
98
- expiresIn: 3600000, // 1 hour
99
- issuerKey: privateKeyA
100
- }
101
- );
102
-
103
- expect(typeof readCapabilityToken).toBe('string');
104
-
105
- // Step 4: Verify the capability token is valid
106
- const isValidToken = await holosphereA.verifyCapability(
107
- readCapabilityToken,
108
- 'read',
109
- { holonId: testHolon, lensName: 'shared-docs' }
110
- );
111
- expect(isValidToken).toBe(true);
112
-
113
- // Step 5: Holosphere B can now verify the token
114
- const bCanVerify = await holosphereB.verifyCapability(
115
- readCapabilityToken,
116
- 'read',
117
- { holonId: testHolon, lensName: 'shared-docs' }
118
- );
119
- expect(bCanVerify).toBe(true);
120
- });
121
-
122
- it('should allow write access with write capability token', async () => {
123
- // Step 1: Holosphere A creates initial data
124
- await holosphereA.write(testHolon, 'collaborative', {
125
- id: 'collab-001',
126
- content: 'Initial content by A',
127
- _creator: publicKeyA
128
- });
129
-
130
- // Step 2: Holosphere A issues WRITE capability token to B
131
- const writeCapabilityToken = await holosphereA.issueCapability(
132
- ['write', 'read'],
133
- { holonId: testHolon, lensName: 'collaborative' },
134
- publicKeyB,
135
- {
136
- expiresIn: 3600000,
137
- issuerKey: privateKeyA
138
- }
139
- );
140
-
141
- // Step 3: Verify B has write permission with the token
142
- const hasWritePermission = await holosphereB.verifyCapability(
143
- writeCapabilityToken,
144
- 'write',
145
- { holonId: testHolon, lensName: 'collaborative' }
146
- );
147
- expect(hasWritePermission).toBe(true);
148
-
149
- // Step 4: B writes new data using the capability token
150
- await holosphereB.write(testHolon, 'collaborative', {
151
- id: 'collab-002',
152
- content: 'Content added by B with capability',
153
- _creator: publicKeyB
154
- }, { capability: writeCapabilityToken });
155
-
156
- // Step 5: A can verify B's contribution was written
157
- const bContribution = await holosphereB.read(testHolon, 'collaborative', 'collab-002');
158
- expect(bContribution).toBeDefined();
159
- expect(bContribution.content).toBe('Content added by B with capability');
160
- });
161
-
162
- it('should reject operations when capability token does not include required permission', async () => {
163
- // Step 1: A writes data
164
- await holosphereA.write(testHolon, 'restricted', {
165
- id: 'restricted-001',
166
- content: 'Restricted data',
167
- _creator: publicKeyA
168
- });
169
-
170
- // Step 2: A issues READ-ONLY capability token to B
171
- const readOnlyToken = await holosphereA.issueCapability(
172
- ['read'], // Only read, no write or delete
173
- { holonId: testHolon, lensName: 'restricted' },
174
- publicKeyB,
175
- {
176
- expiresIn: 3600000,
177
- issuerKey: privateKeyA
178
- }
179
- );
180
-
181
- // Step 3: Verify B has read but NOT write permission
182
- const hasRead = await holosphereB.verifyCapability(
183
- readOnlyToken,
184
- 'read',
185
- { holonId: testHolon, lensName: 'restricted' }
186
- );
187
- expect(hasRead).toBe(true);
188
-
189
- const hasWrite = await holosphereB.verifyCapability(
190
- readOnlyToken,
191
- 'write',
192
- { holonId: testHolon, lensName: 'restricted' }
193
- );
194
- expect(hasWrite).toBe(false);
195
-
196
- const hasDelete = await holosphereB.verifyCapability(
197
- readOnlyToken,
198
- 'delete',
199
- { holonId: testHolon, lensName: 'restricted' }
200
- );
201
- expect(hasDelete).toBe(false);
202
- });
203
-
204
- it('should reject capability tokens for wrong scope (different lens)', async () => {
205
- // Issue token for 'documents' lens
206
- const documentsToken = await holosphereA.issueCapability(
207
- ['read', 'write', 'delete'],
208
- { holonId: testHolon, lensName: 'documents' },
209
- publicKeyB,
210
- {
211
- expiresIn: 3600000,
212
- issuerKey: privateKeyA
213
- }
214
- );
215
-
216
- // Token should be valid for 'documents' lens
217
- const validForDocuments = await holosphereB.verifyCapability(
218
- documentsToken,
219
- 'read',
220
- { holonId: testHolon, lensName: 'documents' }
221
- );
222
- expect(validForDocuments).toBe(true);
223
-
224
- // Token should be INVALID for 'photos' lens
225
- const validForPhotos = await holosphereB.verifyCapability(
226
- documentsToken,
227
- 'read',
228
- { holonId: testHolon, lensName: 'photos' }
229
- );
230
- expect(validForPhotos).toBe(false);
231
- });
232
-
233
- it('should reject expired capability tokens', async () => {
234
- // Issue a token that is already expired
235
- const expiredToken = await holosphereA.issueCapability(
236
- ['read', 'write'],
237
- { holonId: testHolon, lensName: 'expired-test' },
238
- publicKeyB,
239
- {
240
- expiresIn: -1000, // Already expired
241
- issuerKey: privateKeyA
242
- }
243
- );
244
-
245
- // Expired token should not be valid
246
- const isValid = await holosphereB.verifyCapability(
247
- expiredToken,
248
- 'read',
249
- { holonId: testHolon, lensName: 'expired-test' }
250
- );
251
- expect(isValid).toBe(false);
252
- });
253
-
254
- it('should allow delete access with delete capability token', async () => {
255
- // Step 1: A creates data
256
- await holosphereA.write(testHolon, 'deletable', {
257
- id: 'to-delete-001',
258
- content: 'This will be deleted by B',
259
- _creator: publicKeyA
260
- });
261
-
262
- // Step 2: Verify data exists
263
- const exists = await holosphereA.read(testHolon, 'deletable', 'to-delete-001');
264
- expect(exists).toBeDefined();
265
-
266
- // Step 3: B tries to delete without token - should fail
267
- try {
268
- await holosphereB.delete(testHolon, 'deletable', 'to-delete-001');
269
- // If we reach here, the test should fail
270
- expect(true).toBe(false);
271
- } catch (err) {
272
- // Expected: authorization error or no access
273
- expect(err).toBeDefined();
274
- }
275
-
276
- // Step 4: A issues DELETE capability token to B
277
- const deleteToken = await holosphereA.issueCapability(
278
- ['delete'],
279
- { holonId: testHolon, lensName: 'deletable' },
280
- publicKeyB,
281
- {
282
- expiresIn: 3600000,
283
- issuerKey: privateKeyA
284
- }
285
- );
286
-
287
- // Step 5: Verify B has delete permission
288
- const hasDeletePermission = await holosphereB.verifyCapability(
289
- deleteToken,
290
- 'delete',
291
- { holonId: testHolon, lensName: 'deletable' }
292
- );
293
- expect(hasDeletePermission).toBe(true);
294
- });
295
-
296
- it('complete workflow: isolation -> capability grant -> access', async () => {
297
- // === PHASE 1: ISOLATION ===
298
- // A writes confidential data
299
- const confidentialData = {
300
- id: 'confidential-001',
301
- title: 'Secret Project',
302
- content: 'Top secret information only for authorized users',
303
- _creator: publicKeyA
304
- };
305
-
306
- await holosphereA.write(testHolon, 'projects', confidentialData);
307
-
308
- // A can see their own data
309
- const aCanSee = await holosphereA.read(testHolon, 'projects', 'confidential-001');
310
- expect(aCanSee).toBeDefined();
311
- expect(aCanSee.title).toBe('Secret Project');
312
-
313
- // B cannot see A's data (isolated)
314
- const bCannotSee = await holosphereB.read(testHolon, 'projects', 'confidential-001');
315
- expect(bCannotSee).toBeNull();
316
-
317
- // === PHASE 2: CAPABILITY GRANT ===
318
- // A decides to grant B read access via public key
319
- const capabilityToken = await holosphereA.issueCapability(
320
- ['read'],
321
- { holonId: testHolon, lensName: 'projects' },
322
- publicKeyB, // Grant to B's public key
323
- {
324
- expiresIn: 7200000, // 2 hours
325
- issuerKey: privateKeyA
326
- }
327
- );
328
-
329
- expect(capabilityToken).toBeDefined();
330
- expect(typeof capabilityToken).toBe('string');
331
-
332
- // === PHASE 3: VERIFIED ACCESS ===
333
- // B can now verify they have read access
334
- const bHasReadAccess = await holosphereB.verifyCapability(
335
- capabilityToken,
336
- 'read',
337
- { holonId: testHolon, lensName: 'projects' }
338
- );
339
- expect(bHasReadAccess).toBe(true);
340
-
341
- // B still cannot write (only read permission was granted)
342
- const bHasWriteAccess = await holosphereB.verifyCapability(
343
- capabilityToken,
344
- 'write',
345
- { holonId: testHolon, lensName: 'projects' }
346
- );
347
- expect(bHasWriteAccess).toBe(false);
348
-
349
- // Token is properly scoped - cannot access other lenses
350
- const bHasAccessToOtherLens = await holosphereB.verifyCapability(
351
- capabilityToken,
352
- 'read',
353
- { holonId: testHolon, lensName: 'other-lens' }
354
- );
355
- expect(bHasAccessToOtherLens).toBe(false);
356
- });
357
- });