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,159 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import HoloSphere from '../../../src/index.js';
3
-
4
- describe('Contract: Utility Operations', () => {
5
- let hs;
6
-
7
- beforeEach(() => {
8
- hs = new HoloSphere({ relays: [], appName: 'test-utils' });
9
- });
10
-
11
- describe('isValidH3()', () => {
12
- it('should return true for valid H3 ID', () => {
13
- expect(hs.isValidH3('8928342e20fffff')).toBe(true);
14
- });
15
-
16
- it('should return false for invalid string', () => {
17
- expect(hs.isValidH3('invalid')).toBe(false);
18
- });
19
-
20
- it('should return false for non-string input', () => {
21
- expect(hs.isValidH3(123)).toBe(false);
22
- expect(hs.isValidH3(null)).toBe(false);
23
- expect(hs.isValidH3(undefined)).toBe(false);
24
- expect(hs.isValidH3({})).toBe(false);
25
- });
26
-
27
- it('should validate H3 format (starts with 8, at least 15 chars)', () => {
28
- expect(hs.isValidH3('8a2a1072b59ffff')).toBe(true);
29
- expect(hs.isValidH3('7a2a1072b59ffff')).toBe(false);
30
- expect(hs.isValidH3('8a2a107')).toBe(false);
31
- });
32
- });
33
-
34
- describe('metrics()', () => {
35
- it('should return metrics object', () => {
36
- const metrics = hs.metrics();
37
- expect(typeof metrics).toBe('object');
38
- });
39
-
40
- it('should include writes count', () => {
41
- const metrics = hs.metrics();
42
- expect(metrics).toHaveProperty('writes');
43
- expect(typeof metrics.writes).toBe('number');
44
- });
45
-
46
- it('should include reads count', () => {
47
- const metrics = hs.metrics();
48
- expect(metrics).toHaveProperty('reads');
49
- expect(typeof metrics.reads).toBe('number');
50
- });
51
-
52
- it('should include subscriptions count', () => {
53
- const metrics = hs.metrics();
54
- expect(metrics).toHaveProperty('subscriptions');
55
- expect(typeof metrics.subscriptions).toBe('number');
56
- });
57
-
58
- it('should include federations count', () => {
59
- const metrics = hs.metrics();
60
- expect(metrics).toHaveProperty('federations');
61
- expect(typeof metrics.federations).toBe('number');
62
- });
63
-
64
- it('should include average write time', () => {
65
- const metrics = hs.metrics();
66
- expect(metrics).toHaveProperty('avgWriteTime');
67
- expect(typeof metrics.avgWriteTime).toBe('number');
68
- });
69
-
70
- it('should include average read time', () => {
71
- const metrics = hs.metrics();
72
- expect(metrics).toHaveProperty('avgReadTime');
73
- expect(typeof metrics.avgReadTime).toBe('number');
74
- });
75
-
76
- it('should update metrics after operations', async () => {
77
- const holonId = await hs.toHolon(37.7749, -122.4194, 9);
78
-
79
- const before = hs.metrics();
80
-
81
- await hs.write(holonId, 'test', { id: 'test-1', value: 'data' });
82
- await hs.read(holonId, 'test', 'test-1');
83
-
84
- const after = hs.metrics();
85
-
86
- expect(after.writes).toBeGreaterThanOrEqual(before.writes);
87
- expect(after.reads).toBeGreaterThanOrEqual(before.reads);
88
- });
89
- });
90
-
91
- describe('Error Types', () => {
92
- it('should export ValidationError class', async () => {
93
- try {
94
- await hs.setSchema('test', 'invalid://schema', true);
95
- } catch (err) {
96
- expect(err.constructor.name).toBe('ValidationError');
97
- expect(err).toHaveProperty('errors');
98
- expect(Array.isArray(err.errors)).toBe(true);
99
- }
100
- });
101
-
102
- it('should export AuthorizationError class', async () => {
103
- const holonId = await hs.toHolon(37.7749, -122.4194, 9);
104
-
105
- // Write data with an owner to trigger authorization check
106
- await hs.write(holonId, 'test', {
107
- id: 'others-data',
108
- _creator: '04' + 'fedcba9876543210'.repeat(8) // Different owner
109
- });
110
-
111
- try {
112
- await hs.delete(holonId, 'test', 'others-data');
113
- } catch (err) {
114
- expect(err.constructor.name).toBe('AuthorizationError');
115
- expect(err).toHaveProperty('requiredPermission');
116
- }
117
- });
118
-
119
- it('should export HolosphereError class', () => {
120
- try {
121
- new HoloSphere({ relays: [], appName: 123 });
122
- } catch (err) {
123
- expect(err.constructor.name).toMatch(/Error$/);
124
- }
125
- });
126
-
127
- it('ValidationError should include validation details', async () => {
128
- await hs.setSchema('test', 'test://schema', true);
129
-
130
- try {
131
- await hs.write(
132
- await hs.toHolon(37.7749, -122.4194, 9),
133
- 'test',
134
- { invalid: 'data' },
135
- { strict: true }
136
- );
137
- } catch (err) {
138
- expect(err.message).toBeTruthy();
139
- expect(err.errors).toBeTruthy();
140
- }
141
- });
142
-
143
- it('AuthorizationError should include required permission', async () => {
144
- const holonId = await hs.toHolon(37.7749, -122.4194, 9);
145
-
146
- // Write data with an owner to trigger authorization check
147
- await hs.write(holonId, 'test', {
148
- id: 'protected-data',
149
- _creator: '04' + 'fedcba9876543210'.repeat(8) // Different owner
150
- });
151
-
152
- try {
153
- await hs.delete(holonId, 'test', 'protected-data');
154
- } catch (err) {
155
- expect(err.requiredPermission).toBe('delete');
156
- }
157
- });
158
- });
159
- });
@@ -1,152 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import HoloSphere from '../../src/index.js';
3
-
4
- describe('Unit: Core Module', () => {
5
- describe('HoloSphere class initialization', () => {
6
- it('should initialize with default config', () => {
7
- const hs = new HoloSphere({ relays: [] });
8
- expect(hs).toBeInstanceOf(HoloSphere);
9
- });
10
-
11
- it('should initialize with custom appName', () => {
12
- const hs = new HoloSphere({ relays: [], appName: 'custom-app' });
13
- expect(hs).toBeInstanceOf(HoloSphere);
14
- });
15
-
16
- it('should initialize with custom peers array', () => {
17
- const hs = new HoloSphere({
18
- appName: 'test',
19
- peers: ['https://relay1.com/gun', 'https://relay2.com/gun']
20
- });
21
- expect(hs).toBeInstanceOf(HoloSphere);
22
- });
23
-
24
- it('should initialize with radisk enabled', () => {
25
- const hs = new HoloSphere({
26
- appName: 'test',
27
- radisk: true
28
- });
29
- expect(hs).toBeInstanceOf(HoloSphere);
30
- });
31
-
32
- it('should initialize with radisk config object', () => {
33
- const hs = new HoloSphere({
34
- appName: 'test',
35
- radisk: { path: './test-data' }
36
- });
37
- expect(hs).toBeInstanceOf(HoloSphere);
38
- });
39
- });
40
-
41
- describe('Config validation', () => {
42
- it('should throw TypeError for invalid appName type', () => {
43
- expect(() => new HoloSphere({ relays: [], appName: 123 })).toThrow(TypeError);
44
- expect(() => new HoloSphere({ relays: [], appName: null })).toThrow(TypeError);
45
- expect(() => new HoloSphere({ relays: [], appName: {} })).toThrow(TypeError);
46
- });
47
-
48
- it('should throw TypeError for invalid relays type', () => {
49
- expect(() => new HoloSphere({ relays: 'not-an-array', appName: 'test' })).toThrow(TypeError);
50
- expect(() => new HoloSphere({ relays: 123, appName: 'test' })).toThrow(TypeError);
51
- });
52
-
53
- it('should throw TypeError for invalid logLevel', () => {
54
- expect(() => new HoloSphere({ logLevel: 'INVALID' })).toThrow(TypeError);
55
- expect(() => new HoloSphere({ logLevel: 123 })).toThrow(TypeError);
56
- });
57
-
58
- it('should validate config defaults are applied', () => {
59
- const hs = new HoloSphere({ relays: [] });
60
- // Should use default appName, radisk: true, logLevel: 'WARN'
61
- expect(hs).toBeInstanceOf(HoloSphere);
62
- });
63
- });
64
-
65
- describe('Nostr client creation', () => {
66
- it('should create Nostr client instance internally', () => {
67
- const hs = new HoloSphere({ relays: [], appName: 'test' });
68
- // Internal client instance should exist
69
- expect(hs).toHaveProperty('client');
70
- });
71
-
72
- it('should configure Nostr client with relays', () => {
73
- const relays = ['wss://relay.example.com'];
74
- const hs = new HoloSphere({ relays, appName: 'test' });
75
- expect(hs).toBeInstanceOf(HoloSphere);
76
- expect(hs.client.relays).toEqual(relays);
77
- });
78
-
79
- it('should accept empty relays array for testing', () => {
80
- const hs = new HoloSphere({ relays: [], appName: 'test' });
81
- expect(hs.client.relays).toEqual([]);
82
- });
83
- });
84
-
85
- describe('Radisk adapter integration', () => {
86
- it('should integrate radisk when enabled', () => {
87
- const hs = new HoloSphere({
88
- appName: 'test',
89
- radisk: true
90
- });
91
- expect(hs).toBeInstanceOf(HoloSphere);
92
- });
93
-
94
- it('should accept radisk path configuration', () => {
95
- const hs = new HoloSphere({
96
- appName: 'test',
97
- radisk: { path: './custom-path' }
98
- });
99
- expect(hs).toBeInstanceOf(HoloSphere);
100
- });
101
-
102
- it('should work without radisk when disabled', () => {
103
- const hs = new HoloSphere({
104
- appName: 'test',
105
- radisk: false
106
- });
107
- expect(hs).toBeInstanceOf(HoloSphere);
108
- });
109
- });
110
-
111
- describe('Log level configuration', () => {
112
- it('should accept ERROR log level', () => {
113
- const hs = new HoloSphere({ logLevel: 'ERROR' });
114
- expect(hs).toBeInstanceOf(HoloSphere);
115
- });
116
-
117
- it('should accept WARN log level', () => {
118
- const hs = new HoloSphere({ logLevel: 'WARN' });
119
- expect(hs).toBeInstanceOf(HoloSphere);
120
- });
121
-
122
- it('should accept INFO log level', () => {
123
- const hs = new HoloSphere({ logLevel: 'INFO' });
124
- expect(hs).toBeInstanceOf(HoloSphere);
125
- });
126
-
127
- it('should accept DEBUG log level', () => {
128
- const hs = new HoloSphere({ logLevel: 'DEBUG' });
129
- expect(hs).toBeInstanceOf(HoloSphere);
130
- });
131
-
132
- it('should use WARN as default log level', () => {
133
- const hs = new HoloSphere({ relays: [] });
134
- // Default should be WARN
135
- expect(hs).toBeInstanceOf(HoloSphere);
136
- });
137
- });
138
-
139
- describe('App configuration storage', () => {
140
- it('should store app configuration internally', () => {
141
- const config = {
142
- appName: 'test-app',
143
- peers: ['https://relay.com/gun'],
144
- logLevel: 'DEBUG'
145
- };
146
-
147
- const hs = new HoloSphere(config);
148
- // Config should be accessible (implementation-specific)
149
- expect(hs).toHaveProperty('config');
150
- });
151
- });
152
- });
@@ -1,328 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import HoloSphere from '../../src/index.js';
3
- import { getPublicKey } from '../../src/crypto/secp256k1.js';
4
-
5
- describe('Unit: Crypto Module', () => {
6
- let hs;
7
- let privateKey;
8
- let publicKey;
9
-
10
- beforeEach(async () => {
11
- hs = new HoloSphere({ relays: [], appName: 'test-crypto-unit', relays: [] });
12
- // Use valid secp256k1 keys - derive public key from private key
13
- privateKey = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
14
- publicKey = await getPublicKey(privateKey);
15
- });
16
-
17
- describe('secp256k1 signing and verification', () => {
18
- it('should sign content with private key', async () => {
19
- const content = { message: 'Test message' };
20
- const signature = await hs.sign(content, privateKey);
21
-
22
- expect(typeof signature).toBe('string');
23
- expect(signature).toMatch(/^[0-9a-f]+$/);
24
- expect(signature.length).toBeGreaterThan(0);
25
- });
26
-
27
- it('should verify valid signature', async () => {
28
- const content = { message: 'Test message' };
29
- const signature = await hs.sign(content, privateKey);
30
-
31
- const isValid = await hs.verify(content, signature, publicKey);
32
- expect(isValid).toBe(true);
33
- });
34
-
35
- it('should reject invalid signature', async () => {
36
- const content = { message: 'Test message' };
37
- const invalidSig = 'invalid-signature';
38
-
39
- const isValid = await hs.verify(content, invalidSig, publicKey);
40
- expect(isValid).toBe(false);
41
- });
42
-
43
- it('should reject tampered content', async () => {
44
- const content = { message: 'Original message' };
45
- const signature = await hs.sign(content, privateKey);
46
-
47
- const tamperedContent = { message: 'Tampered message' };
48
- const isValid = await hs.verify(tamperedContent, signature, publicKey);
49
- expect(isValid).toBe(false);
50
- });
51
-
52
- it('should reject wrong public key', async () => {
53
- const content = { message: 'Test message' };
54
- const signature = await hs.sign(content, privateKey);
55
-
56
- const wrongPublicKey = '04' + 'fedcba9876543210'.repeat(8);
57
- const isValid = await hs.verify(content, signature, wrongPublicKey);
58
- expect(isValid).toBe(false);
59
- });
60
-
61
- it('should handle string content', async () => {
62
- const content = 'Plain string content';
63
- const signature = await hs.sign(content, privateKey);
64
-
65
- expect(typeof signature).toBe('string');
66
-
67
- const isValid = await hs.verify(content, signature, publicKey);
68
- expect(isValid).toBe(true);
69
- });
70
-
71
- it('should handle complex object content', async () => {
72
- const content = {
73
- nested: {
74
- deep: {
75
- object: 'value',
76
- array: [1, 2, 3]
77
- }
78
- },
79
- number: 42,
80
- boolean: true
81
- };
82
-
83
- const signature = await hs.sign(content, privateKey);
84
- const isValid = await hs.verify(content, signature, publicKey);
85
- expect(isValid).toBe(true);
86
- });
87
- });
88
-
89
- describe('Capability token generation', () => {
90
- it('should generate capability token', async () => {
91
- const token = await hs.issueCapability(
92
- ['read', 'write'],
93
- { holonId: '8928342e20fffff', lensName: 'test' },
94
- publicKey
95
- );
96
-
97
- expect(typeof token).toBe('string');
98
- expect(token.length).toBeGreaterThan(0);
99
- });
100
-
101
- it('should include permissions in token', async () => {
102
- const token = await hs.issueCapability(
103
- ['read', 'write', 'delete'],
104
- { holonId: '8928342e20fffff', lensName: 'test' },
105
- publicKey
106
- );
107
-
108
- // Token should encode permissions
109
- expect(typeof token).toBe('string');
110
- });
111
-
112
- it('should include scope in token', async () => {
113
- const token = await hs.issueCapability(
114
- ['read'],
115
- { holonId: '8928342e20fffff', lensName: 'specific-lens' },
116
- publicKey
117
- );
118
-
119
- expect(typeof token).toBe('string');
120
- });
121
-
122
- it('should include recipient public key in token', async () => {
123
- const recipientKey = '04' + 'abcdef0123456789'.repeat(8);
124
- const token = await hs.issueCapability(
125
- ['write'],
126
- { holonId: '8928342e20fffff', lensName: 'test' },
127
- recipientKey
128
- );
129
-
130
- expect(typeof token).toBe('string');
131
- });
132
-
133
- it('should accept custom expiration time', async () => {
134
- const token = await hs.issueCapability(
135
- ['read'],
136
- { holonId: '8928342e20fffff', lensName: 'test' },
137
- publicKey,
138
- { expiresIn: 86400000 } // 24 hours
139
- );
140
-
141
- expect(typeof token).toBe('string');
142
- });
143
-
144
- it('should use issuer key when provided', async () => {
145
- const token = await hs.issueCapability(
146
- ['delete'],
147
- { holonId: '8928342e20fffff', lensName: 'test' },
148
- publicKey,
149
- { issuerKey: privateKey }
150
- );
151
-
152
- expect(typeof token).toBe('string');
153
- });
154
- });
155
-
156
- describe('Token expiration validation', () => {
157
- it('should validate non-expired token', async () => {
158
- const token = await hs.issueCapability(
159
- ['read'],
160
- { holonId: '8928342e20fffff', lensName: 'test' },
161
- publicKey,
162
- { expiresIn: 3600000 } // 1 hour
163
- );
164
-
165
- const isValid = await hs.verifyCapability(
166
- token,
167
- 'read',
168
- { holonId: '8928342e20fffff', lensName: 'test' }
169
- );
170
-
171
- expect(isValid).toBe(true);
172
- });
173
-
174
- it('should reject expired token', async () => {
175
- const token = await hs.issueCapability(
176
- ['read'],
177
- { holonId: '8928342e20fffff', lensName: 'test' },
178
- publicKey,
179
- { expiresIn: -1000 } // Already expired
180
- );
181
-
182
- const isValid = await hs.verifyCapability(
183
- token,
184
- 'read',
185
- { holonId: '8928342e20fffff', lensName: 'test' }
186
- );
187
-
188
- expect(isValid).toBe(false);
189
- });
190
-
191
- it('should validate token with sufficient time remaining', async () => {
192
- const token = await hs.issueCapability(
193
- ['write'],
194
- { holonId: '8928342e20fffff', lensName: 'test' },
195
- publicKey,
196
- { expiresIn: 7200000 } // 2 hours
197
- );
198
-
199
- const isValid = await hs.verifyCapability(
200
- token,
201
- 'write',
202
- { holonId: '8928342e20fffff', lensName: 'test' }
203
- );
204
-
205
- expect(isValid).toBe(true);
206
- });
207
- });
208
-
209
- describe('Nonce uniqueness (replay protection)', () => {
210
- it('should include unique nonce in each token', async () => {
211
- const token1 = await hs.issueCapability(
212
- ['read'],
213
- { holonId: '8928342e20fffff', lensName: 'test' },
214
- publicKey
215
- );
216
-
217
- const token2 = await hs.issueCapability(
218
- ['read'],
219
- { holonId: '8928342e20fffff', lensName: 'test' },
220
- publicKey
221
- );
222
-
223
- // Tokens should be different due to unique nonces
224
- expect(token1).not.toBe(token2);
225
- });
226
-
227
- it('should reject replayed token', async () => {
228
- const token = await hs.issueCapability(
229
- ['write'],
230
- { holonId: '8928342e20fffff', lensName: 'test' },
231
- publicKey
232
- );
233
-
234
- // First use should succeed
235
- const firstUse = await hs.verifyCapability(
236
- token,
237
- 'write',
238
- { holonId: '8928342e20fffff', lensName: 'test' }
239
- );
240
- expect(firstUse).toBe(true);
241
-
242
- // Replay should be rejected (if nonce tracking implemented)
243
- // This depends on implementation of replay protection
244
- });
245
- });
246
-
247
- describe('Lazy initialization (module not loaded until first use)', () => {
248
- it('should not load crypto module on HoloSphere initialization', () => {
249
- const hs = new HoloSphere({ relays: [], appName: 'lazy-test', relays: [] });
250
-
251
- // Crypto module should not be loaded yet
252
- expect(hs).toBeInstanceOf(HoloSphere);
253
- });
254
-
255
- it('should lazy load crypto module on first sign() call', async () => {
256
- const hs = new HoloSphere({ relays: [], appName: 'lazy-test', relays: [] });
257
-
258
- // First crypto operation triggers lazy load
259
- const signature = await hs.sign({ test: 'data' }, privateKey);
260
-
261
- expect(typeof signature).toBe('string');
262
- });
263
-
264
- it('should lazy load crypto module on first issueCapability() call', async () => {
265
- const hs = new HoloSphere({ relays: [], appName: 'lazy-test', relays: [] });
266
-
267
- const token = await hs.issueCapability(
268
- ['read'],
269
- { holonId: '8928342e20fffff', lensName: 'test' },
270
- publicKey
271
- );
272
-
273
- expect(typeof token).toBe('string');
274
- });
275
-
276
- it('should reuse loaded crypto module for subsequent operations', async () => {
277
- const hs = new HoloSphere({ relays: [], appName: 'lazy-test', relays: [] });
278
-
279
- // First operation loads module
280
- await hs.sign({ test: 'data' }, privateKey);
281
-
282
- // Subsequent operations use loaded module
283
- const token = await hs.issueCapability(
284
- ['read'],
285
- { holonId: '8928342e20fffff', lensName: 'test' },
286
- publicKey
287
- );
288
-
289
- expect(typeof token).toBe('string');
290
- });
291
- });
292
-
293
- describe('Error handling', () => {
294
- it('should throw error for invalid private key format', async () => {
295
- await expect(
296
- hs.sign({ test: 'data' }, 'invalid-key')
297
- ).rejects.toThrow(Error);
298
- });
299
-
300
- it('should throw error for invalid public key format', async () => {
301
- const signature = await hs.sign({ test: 'data' }, privateKey);
302
-
303
- await expect(
304
- hs.verify({ test: 'data' }, signature, 'invalid-pubkey')
305
- ).rejects.toThrow(Error);
306
- });
307
-
308
- it('should handle empty permissions array', async () => {
309
- await expect(
310
- hs.issueCapability(
311
- [],
312
- { holonId: '8928342e20fffff', lensName: 'test' },
313
- publicKey
314
- )
315
- ).rejects.toThrow(Error);
316
- });
317
-
318
- it('should handle invalid scope', async () => {
319
- await expect(
320
- hs.issueCapability(
321
- ['read'],
322
- { holonId: '', lensName: '' },
323
- publicKey
324
- )
325
- ).rejects.toThrow(Error);
326
- });
327
- });
328
- });