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,719 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- /**
5
- * Scenario 12: Capability-Based Federated Data Access
6
- *
7
- * This test verifies that:
8
- * 1. Capability tokens work correctly for read, write, and delete operations
9
- * 2. The federation registry correctly stores and retrieves capabilities
10
- * 3. Capability verification works for different permission levels
11
- * 4. Scope matching works correctly (holon, lens, dataId levels)
12
- *
13
- * Note: In test environment with MemoryStorage, we use different appNames
14
- * to simulate isolation between holospheres. In production with Nostr relays,
15
- * isolation is enforced by author (public key) filtering.
16
- */
17
- describe('Integration: Scenario 12 - Capability-Based Federated Read', () => {
18
- // Three distinct private keys for three separate holospheres
19
- const privateKeyA = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
20
- const privateKeyB = 'fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210';
21
- const privateKeyC = 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789';
22
-
23
- let holosphereA;
24
- let holosphereB;
25
- let holosphereC;
26
- let publicKeyA;
27
- let publicKeyB;
28
- let publicKeyC;
29
- let testHolon;
30
- let testHolon2;
31
-
32
- beforeEach(async () => {
33
- // Create three independent holospheres with different appNames for isolation
34
- // In production with Nostr, they would use same appName but different keys
35
- holosphereA = new HoloSphere({
36
- relays: [],
37
- appName: 'scenario-12-a',
38
- privateKey: privateKeyA,
39
- logLevel: 'ERROR'
40
- });
41
-
42
- holosphereB = new HoloSphere({
43
- relays: [],
44
- appName: 'scenario-12-b',
45
- privateKey: privateKeyB,
46
- logLevel: 'ERROR'
47
- });
48
-
49
- holosphereC = new HoloSphere({
50
- relays: [],
51
- appName: 'scenario-12-c',
52
- privateKey: privateKeyC,
53
- logLevel: 'ERROR'
54
- });
55
-
56
- // Get public keys
57
- publicKeyA = holosphereA.client.publicKey;
58
- publicKeyB = holosphereB.client.publicKey;
59
- publicKeyC = holosphereC.client.publicKey;
60
-
61
- // Create test holons (H3 cells)
62
- testHolon = await holosphereA.toHolon(37.7749, -122.4194, 9);
63
- testHolon2 = await holosphereA.toHolon(40.7128, -74.0060, 9);
64
- });
65
-
66
- afterEach(async () => {
67
- // Clean up
68
- if (holosphereA?.client?.close) await holosphereA.client.close();
69
- if (holosphereB?.client?.close) await holosphereB.client.close();
70
- if (holosphereC?.client?.close) await holosphereC.client.close();
71
- });
72
-
73
- describe('Capability Token Permissions', () => {
74
- it('should issue and verify capability token with READ permission', async () => {
75
- const token = await holosphereA.issueCapability(
76
- ['read'],
77
- { holonId: testHolon, lensName: 'documents' },
78
- publicKeyB,
79
- { expiresIn: 3600000, issuerKey: privateKeyA }
80
- );
81
-
82
- expect(typeof token).toBe('string');
83
-
84
- // Verify read permission is granted
85
- const hasRead = await holosphereB.verifyCapability(token, 'read', {
86
- holonId: testHolon,
87
- lensName: 'documents'
88
- });
89
- expect(hasRead).toBe(true);
90
-
91
- // Verify write permission is NOT granted
92
- const hasWrite = await holosphereB.verifyCapability(token, 'write', {
93
- holonId: testHolon,
94
- lensName: 'documents'
95
- });
96
- expect(hasWrite).toBe(false);
97
-
98
- // Verify delete permission is NOT granted
99
- const hasDelete = await holosphereB.verifyCapability(token, 'delete', {
100
- holonId: testHolon,
101
- lensName: 'documents'
102
- });
103
- expect(hasDelete).toBe(false);
104
- });
105
-
106
- it('should issue and verify capability token with WRITE permission', async () => {
107
- const token = await holosphereA.issueCapability(
108
- ['write'],
109
- { holonId: testHolon, lensName: 'documents' },
110
- publicKeyB,
111
- { expiresIn: 3600000, issuerKey: privateKeyA }
112
- );
113
-
114
- const hasWrite = await holosphereB.verifyCapability(token, 'write', {
115
- holonId: testHolon,
116
- lensName: 'documents'
117
- });
118
- expect(hasWrite).toBe(true);
119
-
120
- const hasRead = await holosphereB.verifyCapability(token, 'read', {
121
- holonId: testHolon,
122
- lensName: 'documents'
123
- });
124
- expect(hasRead).toBe(false);
125
- });
126
-
127
- it('should issue and verify capability token with DELETE permission', async () => {
128
- const token = await holosphereA.issueCapability(
129
- ['delete'],
130
- { holonId: testHolon, lensName: 'documents' },
131
- publicKeyB,
132
- { expiresIn: 3600000, issuerKey: privateKeyA }
133
- );
134
-
135
- const hasDelete = await holosphereB.verifyCapability(token, 'delete', {
136
- holonId: testHolon,
137
- lensName: 'documents'
138
- });
139
- expect(hasDelete).toBe(true);
140
-
141
- const hasWrite = await holosphereB.verifyCapability(token, 'write', {
142
- holonId: testHolon,
143
- lensName: 'documents'
144
- });
145
- expect(hasWrite).toBe(false);
146
- });
147
-
148
- it('should issue capability token with ALL permissions (read, write, delete)', async () => {
149
- const token = await holosphereA.issueCapability(
150
- ['read', 'write', 'delete'],
151
- { holonId: testHolon, lensName: 'documents' },
152
- publicKeyB,
153
- { expiresIn: 3600000, issuerKey: privateKeyA }
154
- );
155
-
156
- const hasRead = await holosphereB.verifyCapability(token, 'read', {
157
- holonId: testHolon,
158
- lensName: 'documents'
159
- });
160
- expect(hasRead).toBe(true);
161
-
162
- const hasWrite = await holosphereB.verifyCapability(token, 'write', {
163
- holonId: testHolon,
164
- lensName: 'documents'
165
- });
166
- expect(hasWrite).toBe(true);
167
-
168
- const hasDelete = await holosphereB.verifyCapability(token, 'delete', {
169
- holonId: testHolon,
170
- lensName: 'documents'
171
- });
172
- expect(hasDelete).toBe(true);
173
- });
174
-
175
- it('should reject expired capability tokens', async () => {
176
- const expiredToken = await holosphereA.issueCapability(
177
- ['read', 'write', 'delete'],
178
- { holonId: testHolon, lensName: 'documents' },
179
- publicKeyB,
180
- { expiresIn: -1000, issuerKey: privateKeyA } // Already expired
181
- );
182
-
183
- const hasRead = await holosphereB.verifyCapability(expiredToken, 'read', {
184
- holonId: testHolon,
185
- lensName: 'documents'
186
- });
187
- expect(hasRead).toBe(false);
188
-
189
- const hasWrite = await holosphereB.verifyCapability(expiredToken, 'write', {
190
- holonId: testHolon,
191
- lensName: 'documents'
192
- });
193
- expect(hasWrite).toBe(false);
194
- });
195
- });
196
-
197
- describe('Write Operations with Capability Tokens', () => {
198
- it('should allow write operation with valid write capability token', async () => {
199
- // A issues write capability to B
200
- const writeToken = await holosphereA.issueCapability(
201
- ['write'],
202
- { holonId: testHolon, lensName: 'shared' },
203
- publicKeyB,
204
- { expiresIn: 3600000, issuerKey: privateKeyA }
205
- );
206
-
207
- // B writes data using the capability token
208
- await holosphereB.write(testHolon, 'shared', {
209
- id: 'item-from-b',
210
- content: 'Written by B with capability',
211
- author: publicKeyB
212
- }, { capability: writeToken });
213
-
214
- // B can read their own data
215
- const data = await holosphereB.read(testHolon, 'shared', 'item-from-b');
216
- expect(data).toBeDefined();
217
- expect(data.content).toBe('Written by B with capability');
218
- });
219
-
220
- it('should reject write with invalid capability token', async () => {
221
- // Create an invalid token (for wrong scope)
222
- const wrongScopeToken = await holosphereA.issueCapability(
223
- ['write'],
224
- { holonId: testHolon, lensName: 'other-lens' },
225
- publicKeyB,
226
- { expiresIn: 3600000, issuerKey: privateKeyA }
227
- );
228
-
229
- // Verify token is invalid for 'shared' lens
230
- const isValid = await holosphereB.verifyCapability(wrongScopeToken, 'write', {
231
- holonId: testHolon,
232
- lensName: 'shared'
233
- });
234
- expect(isValid).toBe(false);
235
- });
236
-
237
- it('should reject write with read-only capability token', async () => {
238
- const readOnlyToken = await holosphereA.issueCapability(
239
- ['read'],
240
- { holonId: testHolon, lensName: 'protected' },
241
- publicKeyB,
242
- { expiresIn: 3600000, issuerKey: privateKeyA }
243
- );
244
-
245
- // Verify token doesn't have write permission
246
- const hasWrite = await holosphereB.verifyCapability(readOnlyToken, 'write', {
247
- holonId: testHolon,
248
- lensName: 'protected'
249
- });
250
- expect(hasWrite).toBe(false);
251
- });
252
- });
253
-
254
- describe('Delete Operations with Capability Tokens', () => {
255
- it('should allow delete operation with valid delete capability token', async () => {
256
- // A writes data
257
- await holosphereA.write(testHolon, 'deletable', {
258
- id: 'to-delete',
259
- content: 'This will be deleted'
260
- });
261
-
262
- // Verify data exists
263
- const exists = await holosphereA.read(testHolon, 'deletable', 'to-delete');
264
- expect(exists).toBeDefined();
265
-
266
- // A issues delete capability to B
267
- const deleteToken = await holosphereA.issueCapability(
268
- ['delete'],
269
- { holonId: testHolon, lensName: 'deletable' },
270
- publicKeyB,
271
- { expiresIn: 3600000, issuerKey: privateKeyA }
272
- );
273
-
274
- // Verify B has delete permission
275
- const hasDelete = await holosphereB.verifyCapability(deleteToken, 'delete', {
276
- holonId: testHolon,
277
- lensName: 'deletable'
278
- });
279
- expect(hasDelete).toBe(true);
280
- });
281
-
282
- it('should reject delete with write-only capability token', async () => {
283
- const writeOnlyToken = await holosphereA.issueCapability(
284
- ['write'],
285
- { holonId: testHolon, lensName: 'no-delete' },
286
- publicKeyB,
287
- { expiresIn: 3600000, issuerKey: privateKeyA }
288
- );
289
-
290
- // Verify token doesn't have delete permission
291
- const hasDelete = await holosphereB.verifyCapability(writeOnlyToken, 'delete', {
292
- holonId: testHolon,
293
- lensName: 'no-delete'
294
- });
295
- expect(hasDelete).toBe(false);
296
- });
297
- });
298
-
299
- describe('Federation Registry Operations', () => {
300
- it('should store and retrieve inbound capability', async () => {
301
- // A issues capability to B
302
- const readToken = await holosphereA.issueCapability(
303
- ['read'],
304
- { holonId: testHolon, lensName: 'federated-docs' },
305
- publicKeyB,
306
- { expiresIn: 3600000, issuerKey: privateKeyA }
307
- );
308
-
309
- // B stores the capability
310
- await holosphereB.storeInboundCapability(publicKeyA, {
311
- token: readToken,
312
- scope: { holonId: testHolon, lensName: 'federated-docs' },
313
- permissions: ['read'],
314
- expires: Date.now() + 3600000
315
- });
316
-
317
- // B can verify the stored capability
318
- const isValid = await holosphereB.verifyCapability(readToken, 'read', {
319
- holonId: testHolon,
320
- lensName: 'federated-docs'
321
- });
322
- expect(isValid).toBe(true);
323
- });
324
-
325
- it('should store capabilities from multiple partners', async () => {
326
- // A issues capability to C
327
- const tokenFromA = await holosphereA.issueCapability(
328
- ['read'],
329
- { holonId: testHolon, lensName: 'multi-partner' },
330
- publicKeyC,
331
- { expiresIn: 3600000, issuerKey: privateKeyA }
332
- );
333
-
334
- // B issues capability to C
335
- const tokenFromB = await holosphereB.issueCapability(
336
- ['read', 'write'],
337
- { holonId: testHolon, lensName: 'multi-partner' },
338
- publicKeyC,
339
- { expiresIn: 3600000, issuerKey: privateKeyB }
340
- );
341
-
342
- // C stores both capabilities
343
- await holosphereC.storeInboundCapability(publicKeyA, {
344
- token: tokenFromA,
345
- scope: { holonId: testHolon, lensName: 'multi-partner' },
346
- permissions: ['read'],
347
- expires: Date.now() + 3600000
348
- });
349
-
350
- await holosphereC.storeInboundCapability(publicKeyB, {
351
- token: tokenFromB,
352
- scope: { holonId: testHolon, lensName: 'multi-partner' },
353
- permissions: ['read', 'write'],
354
- expires: Date.now() + 3600000
355
- });
356
-
357
- // C can verify both capabilities
358
- const validFromA = await holosphereC.verifyCapability(tokenFromA, 'read', {
359
- holonId: testHolon,
360
- lensName: 'multi-partner'
361
- });
362
- expect(validFromA).toBe(true);
363
-
364
- const validFromB = await holosphereC.verifyCapability(tokenFromB, 'write', {
365
- holonId: testHolon,
366
- lensName: 'multi-partner'
367
- });
368
- expect(validFromB).toBe(true);
369
- });
370
- });
371
-
372
- describe('Scope Matching for Capabilities', () => {
373
- it('should validate capability only for correct holon scope', async () => {
374
- // Token for testHolon only
375
- const token = await holosphereA.issueCapability(
376
- ['read'],
377
- { holonId: testHolon, lensName: 'scoped' },
378
- publicKeyB,
379
- { expiresIn: 3600000, issuerKey: privateKeyA }
380
- );
381
-
382
- // Valid for testHolon
383
- const validForHolon1 = await holosphereB.verifyCapability(token, 'read', {
384
- holonId: testHolon,
385
- lensName: 'scoped'
386
- });
387
- expect(validForHolon1).toBe(true);
388
-
389
- // Invalid for testHolon2
390
- const validForHolon2 = await holosphereB.verifyCapability(token, 'read', {
391
- holonId: testHolon2,
392
- lensName: 'scoped'
393
- });
394
- expect(validForHolon2).toBe(false);
395
- });
396
-
397
- it('should validate capability only for correct lens scope', async () => {
398
- // Token for lens-a only
399
- const token = await holosphereA.issueCapability(
400
- ['read'],
401
- { holonId: testHolon, lensName: 'lens-a' },
402
- publicKeyB,
403
- { expiresIn: 3600000, issuerKey: privateKeyA }
404
- );
405
-
406
- // Valid for lens-a
407
- const validForLensA = await holosphereB.verifyCapability(token, 'read', {
408
- holonId: testHolon,
409
- lensName: 'lens-a'
410
- });
411
- expect(validForLensA).toBe(true);
412
-
413
- // Invalid for lens-b
414
- const validForLensB = await holosphereB.verifyCapability(token, 'read', {
415
- holonId: testHolon,
416
- lensName: 'lens-b'
417
- });
418
- expect(validForLensB).toBe(false);
419
- });
420
-
421
- it('should support wildcard holon scope (*)', async () => {
422
- // Token with wildcard holon
423
- const wildcardToken = await holosphereA.issueCapability(
424
- ['read'],
425
- { holonId: '*', lensName: 'global' },
426
- publicKeyB,
427
- { expiresIn: 3600000, issuerKey: privateKeyA }
428
- );
429
-
430
- // Valid for any holon
431
- const validForHolon1 = await holosphereB.verifyCapability(wildcardToken, 'read', {
432
- holonId: testHolon,
433
- lensName: 'global'
434
- });
435
- expect(validForHolon1).toBe(true);
436
-
437
- const validForHolon2 = await holosphereB.verifyCapability(wildcardToken, 'read', {
438
- holonId: testHolon2,
439
- lensName: 'global'
440
- });
441
- expect(validForHolon2).toBe(true);
442
-
443
- // But still restricted to 'global' lens
444
- const invalidForOtherLens = await holosphereB.verifyCapability(wildcardToken, 'read', {
445
- holonId: testHolon,
446
- lensName: 'other-lens'
447
- });
448
- expect(invalidForOtherLens).toBe(false);
449
- });
450
-
451
- it('should support wildcard lens scope (*)', async () => {
452
- // Token with wildcard lens
453
- const wildcardToken = await holosphereA.issueCapability(
454
- ['read'],
455
- { holonId: testHolon, lensName: '*' },
456
- publicKeyB,
457
- { expiresIn: 3600000, issuerKey: privateKeyA }
458
- );
459
-
460
- // Valid for any lens in testHolon
461
- const validForLensA = await holosphereB.verifyCapability(wildcardToken, 'read', {
462
- holonId: testHolon,
463
- lensName: 'lens-a'
464
- });
465
- expect(validForLensA).toBe(true);
466
-
467
- const validForLensB = await holosphereB.verifyCapability(wildcardToken, 'read', {
468
- holonId: testHolon,
469
- lensName: 'lens-b'
470
- });
471
- expect(validForLensB).toBe(true);
472
-
473
- // But still restricted to testHolon
474
- const invalidForOtherHolon = await holosphereB.verifyCapability(wildcardToken, 'read', {
475
- holonId: testHolon2,
476
- lensName: 'lens-a'
477
- });
478
- expect(invalidForOtherHolon).toBe(false);
479
- });
480
-
481
- it('should support full wildcard scope (*, *)', async () => {
482
- // Token with full wildcard - access to all holons and lenses
483
- const fullWildcardToken = await holosphereA.issueCapability(
484
- ['read'],
485
- { holonId: '*', lensName: '*' },
486
- publicKeyB,
487
- { expiresIn: 3600000, issuerKey: privateKeyA }
488
- );
489
-
490
- // Valid for any holon and lens combination
491
- const valid1 = await holosphereB.verifyCapability(fullWildcardToken, 'read', {
492
- holonId: testHolon,
493
- lensName: 'lens-a'
494
- });
495
- expect(valid1).toBe(true);
496
-
497
- const valid2 = await holosphereB.verifyCapability(fullWildcardToken, 'read', {
498
- holonId: testHolon2,
499
- lensName: 'lens-b'
500
- });
501
- expect(valid2).toBe(true);
502
- });
503
-
504
- it('should support dataId-specific scope', async () => {
505
- // Token for specific item only
506
- const itemToken = await holosphereA.issueCapability(
507
- ['read'],
508
- { holonId: testHolon, lensName: 'items', dataId: 'item-2' },
509
- publicKeyB,
510
- { expiresIn: 3600000, issuerKey: privateKeyA }
511
- );
512
-
513
- // Valid for item-2
514
- const validForItem2 = await holosphereB.verifyCapability(itemToken, 'read', {
515
- holonId: testHolon,
516
- lensName: 'items',
517
- dataId: 'item-2'
518
- });
519
- expect(validForItem2).toBe(true);
520
-
521
- // Invalid for item-1
522
- const validForItem1 = await holosphereB.verifyCapability(itemToken, 'read', {
523
- holonId: testHolon,
524
- lensName: 'items',
525
- dataId: 'item-1'
526
- });
527
- expect(validForItem1).toBe(false);
528
- });
529
- });
530
-
531
- describe('Complete Capability Workflow', () => {
532
- it('should complete full capability workflow: issue -> verify -> use', async () => {
533
- // === STEP 1: A issues full capability (read, write, delete) to B ===
534
- const fullCapability = await holosphereA.issueCapability(
535
- ['read', 'write', 'delete'],
536
- { holonId: testHolon, lensName: 'workflow-test' },
537
- publicKeyB,
538
- { expiresIn: 3600000, issuerKey: privateKeyA }
539
- );
540
-
541
- expect(typeof fullCapability).toBe('string');
542
-
543
- // === STEP 2: B stores the capability ===
544
- await holosphereB.storeInboundCapability(publicKeyA, {
545
- token: fullCapability,
546
- scope: { holonId: testHolon, lensName: 'workflow-test' },
547
- permissions: ['read', 'write', 'delete'],
548
- expires: Date.now() + 3600000
549
- });
550
-
551
- // === STEP 3: B verifies all permissions ===
552
- const hasRead = await holosphereB.verifyCapability(fullCapability, 'read', {
553
- holonId: testHolon,
554
- lensName: 'workflow-test'
555
- });
556
- expect(hasRead).toBe(true);
557
-
558
- const hasWrite = await holosphereB.verifyCapability(fullCapability, 'write', {
559
- holonId: testHolon,
560
- lensName: 'workflow-test'
561
- });
562
- expect(hasWrite).toBe(true);
563
-
564
- const hasDelete = await holosphereB.verifyCapability(fullCapability, 'delete', {
565
- holonId: testHolon,
566
- lensName: 'workflow-test'
567
- });
568
- expect(hasDelete).toBe(true);
569
-
570
- // === STEP 4: B can write data with capability ===
571
- await holosphereB.write(testHolon, 'workflow-test', {
572
- id: 'b-contribution',
573
- title: 'B Contribution',
574
- content: 'Added by B with capability',
575
- contributor: publicKeyB
576
- }, { capability: fullCapability });
577
-
578
- // Verify write worked
579
- const bContrib = await holosphereB.read(testHolon, 'workflow-test', 'b-contribution');
580
- expect(bContrib).toBeDefined();
581
- expect(bContrib.title).toBe('B Contribution');
582
-
583
- // === STEP 5: B deletes with capability ===
584
- const deleteResult = await holosphereB.delete(testHolon, 'workflow-test', 'b-contribution', {
585
- capability: fullCapability
586
- });
587
- expect(deleteResult).toBe(true);
588
-
589
- // Verify deletion
590
- const deleted = await holosphereB.read(testHolon, 'workflow-test', 'b-contribution');
591
- expect(deleted).toBeNull();
592
- });
593
-
594
- it('should properly isolate data between holospheres (different appNames)', async () => {
595
- // A writes data
596
- await holosphereA.write(testHolon, 'isolated', {
597
- id: 'a-data',
598
- content: 'From A',
599
- owner: publicKeyA
600
- });
601
-
602
- // B writes data
603
- await holosphereB.write(testHolon, 'isolated', {
604
- id: 'b-data',
605
- content: 'From B',
606
- owner: publicKeyB
607
- });
608
-
609
- // A can only see A's data
610
- const aData = await holosphereA.read(testHolon, 'isolated', 'a-data');
611
- expect(aData).toBeDefined();
612
- expect(aData.content).toBe('From A');
613
-
614
- const aSeesB = await holosphereA.read(testHolon, 'isolated', 'b-data');
615
- expect(aSeesB).toBeNull(); // Different appName
616
-
617
- // B can only see B's data
618
- const bData = await holosphereB.read(testHolon, 'isolated', 'b-data');
619
- expect(bData).toBeDefined();
620
- expect(bData.content).toBe('From B');
621
-
622
- const bSeesA = await holosphereB.read(testHolon, 'isolated', 'a-data');
623
- expect(bSeesA).toBeNull(); // Different appName
624
- });
625
- });
626
-
627
- describe('Capability Token Security', () => {
628
- it('should not allow capability reuse for different scope', async () => {
629
- const token = await holosphereA.issueCapability(
630
- ['read', 'write', 'delete'],
631
- { holonId: testHolon, lensName: 'specific-lens' },
632
- publicKeyB,
633
- { expiresIn: 3600000, issuerKey: privateKeyA }
634
- );
635
-
636
- // Token is valid for specific-lens
637
- const validForSpecific = await holosphereB.verifyCapability(token, 'read', {
638
- holonId: testHolon,
639
- lensName: 'specific-lens'
640
- });
641
- expect(validForSpecific).toBe(true);
642
-
643
- // Token is NOT valid for different-lens
644
- const validForDifferent = await holosphereB.verifyCapability(token, 'read', {
645
- holonId: testHolon,
646
- lensName: 'different-lens'
647
- });
648
- expect(validForDifferent).toBe(false);
649
-
650
- // Token is NOT valid for different holon
651
- const validForDifferentHolon = await holosphereB.verifyCapability(token, 'read', {
652
- holonId: testHolon2,
653
- lensName: 'specific-lens'
654
- });
655
- expect(validForDifferentHolon).toBe(false);
656
- });
657
-
658
- it('should enforce permission restrictions', async () => {
659
- // Issue read-only token
660
- const readOnlyToken = await holosphereA.issueCapability(
661
- ['read'],
662
- { holonId: testHolon, lensName: 'read-only' },
663
- publicKeyB,
664
- { expiresIn: 3600000, issuerKey: privateKeyA }
665
- );
666
-
667
- // Has read
668
- expect(await holosphereB.verifyCapability(readOnlyToken, 'read', {
669
- holonId: testHolon,
670
- lensName: 'read-only'
671
- })).toBe(true);
672
-
673
- // Does NOT have write
674
- expect(await holosphereB.verifyCapability(readOnlyToken, 'write', {
675
- holonId: testHolon,
676
- lensName: 'read-only'
677
- })).toBe(false);
678
-
679
- // Does NOT have delete
680
- expect(await holosphereB.verifyCapability(readOnlyToken, 'delete', {
681
- holonId: testHolon,
682
- lensName: 'read-only'
683
- })).toBe(false);
684
- });
685
-
686
- it('should have unique nonce per token (replay protection)', async () => {
687
- // Issue two tokens with same parameters
688
- const token1 = await holosphereA.issueCapability(
689
- ['read'],
690
- { holonId: testHolon, lensName: 'replay-test' },
691
- publicKeyB,
692
- { expiresIn: 3600000, issuerKey: privateKeyA }
693
- );
694
-
695
- const token2 = await holosphereA.issueCapability(
696
- ['read'],
697
- { holonId: testHolon, lensName: 'replay-test' },
698
- publicKeyB,
699
- { expiresIn: 3600000, issuerKey: privateKeyA }
700
- );
701
-
702
- // Tokens should be different (different nonces)
703
- expect(token1).not.toBe(token2);
704
-
705
- // But both should be valid
706
- const valid1 = await holosphereB.verifyCapability(token1, 'read', {
707
- holonId: testHolon,
708
- lensName: 'replay-test'
709
- });
710
- const valid2 = await holosphereB.verifyCapability(token2, 'read', {
711
- holonId: testHolon,
712
- lensName: 'replay-test'
713
- });
714
-
715
- expect(valid1).toBe(true);
716
- expect(valid2).toBe(true);
717
- });
718
- });
719
- });