holosphere 1.1.20 → 2.0.0-alpha1

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 (147) hide show
  1. package/.env.example +36 -0
  2. package/.eslintrc.json +16 -0
  3. package/.prettierrc.json +7 -0
  4. package/LICENSE +162 -38
  5. package/README.md +483 -367
  6. package/bin/holosphere-activitypub.js +158 -0
  7. package/cleanup-test-data.js +204 -0
  8. package/examples/demo.html +1333 -0
  9. package/examples/example-bot.js +197 -0
  10. package/package.json +47 -87
  11. package/scripts/check-bundle-size.js +54 -0
  12. package/scripts/check-quest-ids.js +77 -0
  13. package/scripts/import-holons.js +578 -0
  14. package/scripts/publish-to-relay.js +101 -0
  15. package/scripts/read-example.js +186 -0
  16. package/scripts/relay-diagnostic.js +59 -0
  17. package/scripts/relay-example.js +179 -0
  18. package/scripts/resync-to-relay.js +245 -0
  19. package/scripts/revert-import.js +196 -0
  20. package/scripts/test-hybrid-mode.js +108 -0
  21. package/scripts/test-local-storage.js +63 -0
  22. package/scripts/test-nostr-direct.js +55 -0
  23. package/scripts/test-read-data.js +45 -0
  24. package/scripts/test-write-read.js +63 -0
  25. package/scripts/verify-import.js +95 -0
  26. package/scripts/verify-relay-data.js +139 -0
  27. package/src/ai/aggregation.js +319 -0
  28. package/src/ai/breakdown.js +511 -0
  29. package/src/ai/classifier.js +217 -0
  30. package/src/ai/council.js +228 -0
  31. package/src/ai/embeddings.js +279 -0
  32. package/src/ai/federation-ai.js +324 -0
  33. package/src/ai/h3-ai.js +955 -0
  34. package/src/ai/index.js +112 -0
  35. package/src/ai/json-ops.js +225 -0
  36. package/src/ai/llm-service.js +205 -0
  37. package/src/ai/nl-query.js +223 -0
  38. package/src/ai/relationships.js +353 -0
  39. package/src/ai/schema-extractor.js +218 -0
  40. package/src/ai/spatial.js +293 -0
  41. package/src/ai/tts.js +194 -0
  42. package/src/content/social-protocols.js +168 -0
  43. package/src/core/holosphere.js +273 -0
  44. package/src/crypto/secp256k1.js +259 -0
  45. package/src/federation/discovery.js +334 -0
  46. package/src/federation/hologram.js +1042 -0
  47. package/src/federation/registry.js +386 -0
  48. package/src/hierarchical/upcast.js +110 -0
  49. package/src/index.js +2669 -0
  50. package/src/schema/validator.js +91 -0
  51. package/src/spatial/h3-operations.js +110 -0
  52. package/src/storage/backend-factory.js +125 -0
  53. package/src/storage/backend-interface.js +142 -0
  54. package/src/storage/backends/activitypub/server.js +653 -0
  55. package/src/storage/backends/activitypub-backend.js +272 -0
  56. package/src/storage/backends/gundb-backend.js +233 -0
  57. package/src/storage/backends/nostr-backend.js +136 -0
  58. package/src/storage/filesystem-storage-browser.js +41 -0
  59. package/src/storage/filesystem-storage.js +138 -0
  60. package/src/storage/global-tables.js +81 -0
  61. package/src/storage/gun-async.js +281 -0
  62. package/src/storage/gun-wrapper.js +221 -0
  63. package/src/storage/indexeddb-storage.js +122 -0
  64. package/src/storage/key-storage-simple.js +76 -0
  65. package/src/storage/key-storage.js +136 -0
  66. package/src/storage/memory-storage.js +59 -0
  67. package/src/storage/migration.js +338 -0
  68. package/src/storage/nostr-async.js +811 -0
  69. package/src/storage/nostr-client.js +939 -0
  70. package/src/storage/nostr-wrapper.js +211 -0
  71. package/src/storage/outbox-queue.js +208 -0
  72. package/src/storage/persistent-storage.js +109 -0
  73. package/src/storage/sync-service.js +164 -0
  74. package/src/subscriptions/manager.js +142 -0
  75. package/test-ai-real-api.js +202 -0
  76. package/tests/unit/ai/aggregation.test.js +295 -0
  77. package/tests/unit/ai/breakdown.test.js +446 -0
  78. package/tests/unit/ai/classifier.test.js +294 -0
  79. package/tests/unit/ai/council.test.js +262 -0
  80. package/tests/unit/ai/embeddings.test.js +384 -0
  81. package/tests/unit/ai/federation-ai.test.js +344 -0
  82. package/tests/unit/ai/h3-ai.test.js +458 -0
  83. package/tests/unit/ai/index.test.js +304 -0
  84. package/tests/unit/ai/json-ops.test.js +307 -0
  85. package/tests/unit/ai/llm-service.test.js +390 -0
  86. package/tests/unit/ai/nl-query.test.js +383 -0
  87. package/tests/unit/ai/relationships.test.js +311 -0
  88. package/tests/unit/ai/schema-extractor.test.js +384 -0
  89. package/tests/unit/ai/spatial.test.js +279 -0
  90. package/tests/unit/ai/tts.test.js +279 -0
  91. package/tests/unit/content.test.js +332 -0
  92. package/tests/unit/contract/core.test.js +88 -0
  93. package/tests/unit/contract/crypto.test.js +198 -0
  94. package/tests/unit/contract/data.test.js +223 -0
  95. package/tests/unit/contract/federation.test.js +181 -0
  96. package/tests/unit/contract/hierarchical.test.js +113 -0
  97. package/tests/unit/contract/schema.test.js +114 -0
  98. package/tests/unit/contract/social.test.js +217 -0
  99. package/tests/unit/contract/spatial.test.js +110 -0
  100. package/tests/unit/contract/subscriptions.test.js +128 -0
  101. package/tests/unit/contract/utils.test.js +159 -0
  102. package/tests/unit/core.test.js +152 -0
  103. package/tests/unit/crypto.test.js +328 -0
  104. package/tests/unit/federation.test.js +234 -0
  105. package/tests/unit/gun-async.test.js +252 -0
  106. package/tests/unit/hierarchical.test.js +399 -0
  107. package/tests/unit/integration/scenario-01-geographic-storage.test.js +74 -0
  108. package/tests/unit/integration/scenario-02-federation.test.js +76 -0
  109. package/tests/unit/integration/scenario-03-subscriptions.test.js +102 -0
  110. package/tests/unit/integration/scenario-04-validation.test.js +129 -0
  111. package/tests/unit/integration/scenario-05-hierarchy.test.js +125 -0
  112. package/tests/unit/integration/scenario-06-social.test.js +135 -0
  113. package/tests/unit/integration/scenario-07-persistence.test.js +130 -0
  114. package/tests/unit/integration/scenario-08-authorization.test.js +161 -0
  115. package/tests/unit/integration/scenario-09-cross-dimensional.test.js +139 -0
  116. package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +357 -0
  117. package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +410 -0
  118. package/tests/unit/integration/scenario-12-capability-federated-read.test.js +719 -0
  119. package/tests/unit/performance/benchmark.test.js +85 -0
  120. package/tests/unit/schema.test.js +213 -0
  121. package/tests/unit/spatial.test.js +158 -0
  122. package/tests/unit/storage.test.js +195 -0
  123. package/tests/unit/subscriptions.test.js +328 -0
  124. package/tests/unit/test-data-permanence-debug.js +197 -0
  125. package/tests/unit/test-data-permanence.js +340 -0
  126. package/tests/unit/test-key-persistence-fixed.js +148 -0
  127. package/tests/unit/test-key-persistence.js +172 -0
  128. package/tests/unit/test-relay-permanence.js +376 -0
  129. package/tests/unit/test-second-node.js +95 -0
  130. package/tests/unit/test-simple-write.js +89 -0
  131. package/vite.config.js +49 -0
  132. package/vitest.config.js +20 -0
  133. package/FEDERATION.md +0 -213
  134. package/compute.js +0 -298
  135. package/content.js +0 -980
  136. package/federation.js +0 -1234
  137. package/global.js +0 -736
  138. package/hexlib.js +0 -335
  139. package/hologram.js +0 -183
  140. package/holosphere-bundle.esm.js +0 -33256
  141. package/holosphere-bundle.js +0 -33287
  142. package/holosphere-bundle.min.js +0 -39
  143. package/holosphere.d.ts +0 -601
  144. package/holosphere.js +0 -719
  145. package/node.js +0 -246
  146. package/schema.js +0 -139
  147. package/utils.js +0 -302
package/README.md CHANGED
@@ -1,471 +1,587 @@
1
1
  # HoloSphere
2
2
 
3
- HoloSphere is a JavaScript library that provides a spatial data management system using H3 geospatial indexing and GunDB for distributed storage. It enables you to store, validate, and retrieve data organized by geographic location using holonic principles.
3
+ **Holonic Geospatial Communication Infrastructure**
4
+
5
+ A JavaScript library implementing holonic geospatial communication infrastructure by combining H3 hexagonal geospatial indexing with Nostr relay-based distributed peer-to-peer storage.
6
+
7
+ [![Bundle Size](https://img.shields.io/badge/bundle%20size-127%20KB-success)](https://bundlephobia.com)
8
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
+ [![Node Version](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen)](https://nodejs.org)
10
+
11
+ ## Features
12
+
13
+ - **Local-First Architecture**: Reads return instantly from persistent storage; writes guaranteed to sync via OutboxQueue
14
+ - **Geographic & Noospheric Organization**: H3 hexagonal indexing (16 resolution levels) + URI-based conceptual spaces
15
+ - **Distributed P2P Storage**: Nostr relay-based persistence with local-first reads and background sync
16
+ - **Offline Support**: Full read/write functionality offline; automatic sync when connectivity returns
17
+ - **Holonic Architecture**: Autonomous holons with hierarchical parent-child relationships
18
+ - **Holograms**: Lightweight references to data with local overrides and automatic resolution
19
+ - **Real-time Subscriptions**: Live data updates with throttling, filtering, and hologram resolution
20
+ - **Federation**: Bidirectional data sharing within and across HoloSphere instances
21
+ - **Cross-Holosphere Federation**: Multi-instance partnerships with capability token exchange
22
+ - **Discovery Protocol**: Automated Nostr-based federation handshake
23
+ - **Schema Validation**: JSON Schema 2019 with strict/permissive modes and URI references
24
+ - **Cryptographic Security**: secp256k1 signatures, capability tokens with permissions and scopes
25
+ - **Social Protocols**: Unified interface for Nostr (NIP-01) and ActivityPub
26
+ - **Hierarchical Aggregation**: Automatic upcast to parent holons (summarize, aggregate, concatenate)
4
27
 
5
- ## What is a Holon?
6
-
7
- A holon (from Greek 'holos' meaning whole, with suffix 'on' meaning part) is simultaneously a whole and a part. In HoloSphere, holons are implemented as hierarchical geographic cells that can:
28
+ ## Installation
8
29
 
9
- 1. Act as autonomous units (storing their own data)
10
- 2. Be part of larger holons (through H3's hierarchical structure)
11
- 3. Contain smaller holons (through subdivision)
12
- 4. Interact with peer holons (through the distributed network)
30
+ ### npm
31
+ ```bash
32
+ npm install holosphere
33
+ ```
13
34
 
14
- ### Holonic Architecture
35
+ ### CDN
36
+ ```html
37
+ <script src="https://cdn.jsdelivr.net/npm/holosphere@latest/dist/cdn/holosphere.min.js"></script>
38
+ ```
15
39
 
16
- HoloSphere implements holonic architecture in two ways:
40
+ ## Quick Start
17
41
 
18
- #### 1. Spatial Hierarchy
19
42
  ```javascript
20
- // Get holons at different scales for a location
21
- const holon = await sphere.getHolon(lat, lng, 7); // City level
22
- const parent = h3.cellToParent(holon, 6); // Region level
23
- const children = h3.cellToChildren(holon, 8); // Neighborhood level
24
-
25
- // Get entire hierarchy
26
- const scales = sphere.getHolonScalespace(holon); // All containing holons
27
- ```
43
+ import HoloSphere from 'holosphere';
28
44
 
29
- #### 2. Data Organization
30
- ```javascript
31
- // Store data in different aspects (lenses) of a holon
32
- await sphere.put(holon, 'environment', {
33
- id: 'air-001',
34
- temperature: 22.5,
35
- humidity: 65
45
+ // Initialize with Nostr relays
46
+ const hs = new HoloSphere({
47
+ appName: 'myapp',
48
+ relays: ['wss://relay.damus.io', 'wss://nos.lol'],
49
+ privateKey: 'your-hex-private-key', // Optional: auto-generated if not provided
50
+ logLevel: 'INFO'
36
51
  });
37
52
 
38
- await sphere.put(holon, 'social', {
39
- id: 'event-001',
40
- type: 'gathering',
41
- participants: 50
53
+ // Convert coordinates to H3 holon (San Francisco, resolution 9 ≈ 1km²)
54
+ const holonId = await hs.toHolon(37.7749, -122.4194, 9);
55
+
56
+ // Write data to a lens
57
+ await hs.write(holonId, 'temperature', {
58
+ id: 'sensor-001',
59
+ celsius: 18.5,
60
+ timestamp: Date.now()
42
61
  });
43
- ```
44
62
 
45
- ### Use Cases
63
+ // Read data
64
+ const data = await hs.read(holonId, 'temperature', 'sensor-001');
65
+ console.log(data); // => { id: 'sensor-001', celsius: 18.5, ... }
46
66
 
47
- 1. **Localized Structures**
48
- - Local environmental monitoring
49
- - Community event coordination
50
- - Neighborhood resource sharing
51
- - Municipal service management
67
+ // Subscribe to real-time updates
68
+ const subscription = hs.subscribe(holonId, 'temperature', (data, key) => {
69
+ console.log('Temperature updated:', data);
70
+ });
52
71
 
53
- ```javascript
54
- // Example: Local air quality monitoring
55
- async function monitorLocalAir(lat, lng) {
56
- const neighborhood = await sphere.getHolon(lat, lng, 9);
57
-
58
- // Store reading
59
- await sphere.put(neighborhood, 'air-quality', {
60
- id: `reading-${Date.now()}`,
61
- pm25: 12.5,
62
- timestamp: Date.now()
63
- });
64
-
65
- // Get local trends
66
- const readings = await sphere.getAll(neighborhood, 'air-quality');
67
- }
72
+ // Unsubscribe when done
73
+ subscription.unsubscribe();
68
74
  ```
69
75
 
70
- 2. **Delocalized Structures**
71
- - Regional data aggregation
72
- - Cross-boundary collaboration
73
- - Distributed decision making
74
- - Resource flow tracking
76
+ ## Local-First Architecture
75
77
 
76
- ```javascript
77
- // Example: Regional resource coordination
78
- async function coordinateResources(region) {
79
- // Get all sub-holons
80
- const localities = h3.cellToChildren(region, h3.getResolution(region) + 1);
81
-
82
- // Gather resource data from each locality
83
- const resources = await Promise.all(
84
- localities.map(async locality => {
85
- return sphere.getAll(locality, 'resources');
86
- })
87
- );
88
-
89
- // Compute summaries for parent holon
90
- await sphere.compute(region, 'resources', 'summarize');
91
- }
92
- ```
78
+ HoloSphere implements true local-first principles: your data lives on your device first, with Nostr relays serving as the sync layer.
93
79
 
94
- 3. **Hybrid Structures**
95
- - Adaptive governance systems
96
- - Scalable social networks
97
- - Emergency response coordination
98
- - Supply chain management
80
+ ### How It Works
99
81
 
82
+ **Reads are instant:**
100
83
  ```javascript
101
- // Example: Emergency response system
102
- async function coordinateEmergency(incident) {
103
- const epicenter = await sphere.getHolon(incident.lat, incident.lng, 8);
104
- const region = h3.cellToParent(epicenter, 6);
105
-
106
- // Local response
107
- await sphere.put(epicenter, 'emergencies', {
108
- id: incident.id,
109
- type: incident.type,
110
- severity: incident.severity
111
- });
112
-
113
- // Regional coordination
114
- const nearbyResources = await sphere.getAll(region, 'resources');
115
-
116
- // Subscribe to updates
117
- sphere.subscribe(epicenter, 'emergencies', (data) => {
118
- updateResponsePlan(data);
119
- });
120
- }
84
+ // Data returns immediately from local storage
85
+ // Background refresh updates from relays (non-blocking)
86
+ const data = await hs.read(holonId, 'sensors', 'temp-001');
121
87
  ```
122
88
 
123
- ### Key Benefits
124
-
125
- 1. **Scalability**: Holons can be nested infinitely, allowing systems to scale organically
126
- 2. **Autonomy**: Each holon manages its own data while participating in larger structures
127
- 3. **Flexibility**: Systems can be organized both hierarchically and peer-to-peer
128
- 4. **Resilience**: Distributed storage ensures no single point of failure
129
- 5. **Adaptability**: Structures can evolve based on changing needs
130
-
131
- ## Installation
132
-
133
- ```bash
134
- npm install holosphere
89
+ **Writes are guaranteed:**
90
+ ```javascript
91
+ // Write returns after local persist (~10ms)
92
+ // OutboxQueue ensures delivery to relays with retry
93
+ await hs.write(holonId, 'sensors', { id: 'temp-001', value: 22.5 });
94
+ // Works offline - syncs automatically when online
135
95
  ```
136
96
 
137
- ## Quick Start
97
+ ### Offline Behavior
138
98
 
139
- ```javascript
140
- import HoloSphere from 'holosphere';
99
+ | Operation | Offline | When Online |
100
+ |-----------|---------|-------------|
101
+ | Read | Returns local data | Background refresh |
102
+ | Write | Persists locally | OutboxQueue syncs with retry |
103
+ | Subscribe | Local events only | Receives relay updates |
141
104
 
142
- // Initialize HoloSphere
143
- const sphere = new HoloSphere('my-app');
105
+ ### Configuration
144
106
 
145
- // Store data at a location
146
- const holon = await sphere.getHolon(40.7128, -74.0060, 7); // NYC at resolution 7
147
- await sphere.put(holon, 'observations', {
148
- id: 'obs-001',
149
- temperature: 22.5,
150
- timestamp: Date.now()
107
+ ```javascript
108
+ const hs = new HoloSphere({
109
+ appName: 'myapp',
110
+ relays: ['wss://relay.damus.io'],
111
+
112
+ // Local-first options
113
+ persistence: true, // Persistent storage (default: true)
114
+ backgroundSync: true, // Enable SyncService (default: true)
115
+ syncInterval: 10000, // Retry interval in ms (default: 10s)
116
+ maxRetries: 5, // Max delivery attempts (default: 5)
117
+ failedTTL: 86400000, // Failed event TTL (default: 24h)
151
118
  });
152
119
  ```
153
120
 
154
- ## Real-World Examples
121
+ See [LOCALFIRST.md](./LOCALFIRST.md) for detailed architecture documentation.
155
122
 
156
- ### Environmental Monitoring System
123
+ ## Core Concepts
157
124
 
158
- ```javascript
159
- // Define a schema for temperature readings
160
- const tempSchema = {
161
- type: 'object',
162
- properties: {
163
- id: { type: 'string' },
164
- temperature: { type: 'number' },
165
- humidity: { type: 'number' },
166
- timestamp: { type: 'number' }
167
- },
168
- required: ['id', 'temperature', 'timestamp']
169
- };
170
-
171
- // Set up the system
172
- const sphere = new HoloSphere('env-monitor', true); // strict mode enabled
173
- await sphere.setSchema('temperature', tempSchema);
174
-
175
- // Store a reading
176
- async function storeReading(lat, lng, temp, humidity) {
177
- const holon = await sphere.getHolon(lat, lng, 8);
178
- const reading = {
179
- id: `temp-${Date.now()}`,
180
- temperature: temp,
181
- humidity: humidity,
182
- timestamp: Date.now()
183
- };
184
-
185
- return sphere.put(holon, 'temperature', reading);
186
- }
125
+ ### Holons
126
+ Locations in either **geographic space** (H3 hexagonal cells) or **noospheric space** (URI-identified concepts):
187
127
 
188
- // Get all readings for an area
189
- async function getAreaReadings(lat, lng) {
190
- const holon = await sphere.getHolon(lat, lng, 8);
191
- return sphere.getAll(holon, 'temperature');
192
- }
128
+ ```javascript
129
+ // Geographic holon (H3 cell at resolution 9)
130
+ const geoHolon = await hs.toHolon(37.7749, -122.4194, 9);
131
+ // => "8928342e20fffff"
193
132
 
194
- // Monitor an area for new readings
195
- function monitorArea(lat, lng, callback) {
196
- const holon = sphere.getHolon(lat, lng, 8);
197
- sphere.subscribe(holon, 'temperature', callback);
198
- }
133
+ // Noospheric holon (arbitrary string ID)
134
+ const conceptHolon = "topic/bitcoin";
199
135
  ```
200
136
 
201
- ### Location-Based Content System
137
+ ### Lenses
138
+ Categorical data collections within a holon:
202
139
 
203
140
  ```javascript
204
- // Initialize with AI capabilities for content summarization
205
- const sphere = new HoloSphere('local-content', false, 'your-openai-key');
206
-
207
- // Define content schema
208
- const contentSchema = {
209
- type: 'object',
210
- properties: {
211
- id: { type: 'string' },
212
- title: { type: 'string' },
213
- content: { type: 'string' },
214
- author: { type: 'string' },
215
- timestamp: { type: 'number' }
216
- },
217
- required: ['id', 'title', 'content', 'author']
218
- };
219
-
220
- await sphere.setSchema('articles', contentSchema);
221
-
222
- // Post content for a location
223
- async function postLocalContent(lat, lng, title, content, author) {
224
- const holon = await sphere.getHolon(lat, lng, 7);
225
- const article = {
226
- id: `article-${Date.now()}`,
227
- title,
228
- content,
229
- author,
230
- timestamp: Date.now()
231
- };
232
-
233
- await sphere.put(holon, 'articles', article);
234
-
235
- // Generate summaries for parent areas
236
- await sphere.compute(holon, 'articles', 'summarize');
237
- }
141
+ await hs.write(holonId, 'events', {
142
+ id: 'concert-001',
143
+ name: 'Jazz Night',
144
+ venue: 'Blue Note SF'
145
+ });
238
146
 
239
- // Get content for multiple zoom levels
240
- async function getAreaContent(lat, lng) {
241
- const holon = await sphere.getHolon(lat, lng, 7);
242
- const scales = sphere.getHolonScalespace(holon);
243
-
244
- const content = {};
245
- for (const scale of scales) {
246
- content[scale] = await sphere.getAll(scale, 'articles');
247
- }
248
-
249
- return content;
250
- }
147
+ await hs.write(holonId, 'sensors', {
148
+ id: 'temp-001',
149
+ value: 22.5,
150
+ unit: 'celsius'
151
+ });
251
152
  ```
252
153
 
253
- ### Data Validation Example
154
+ ### Holograms
155
+ Lightweight references to data that can exist in multiple locations while maintaining a single source of truth:
254
156
 
255
157
  ```javascript
256
- // Strict validation with custom schema
257
- const sphere = new HoloSphere('validated-data', true);
258
-
259
- const measurementSchema = {
260
- type: 'object',
261
- properties: {
262
- id: { type: 'string' },
263
- value: { type: 'number' },
264
- unit: { type: 'string' },
265
- accuracy: { type: 'number' },
266
- timestamp: { type: 'number' }
267
- },
268
- required: ['id', 'value', 'unit'],
269
- additionalProperties: false
270
- };
271
-
272
- await sphere.setSchema('measurements', measurementSchema);
273
-
274
- // This will succeed
275
- await sphere.put(holon, 'measurements', {
276
- id: 'measure-1',
277
- value: 42.5,
278
- unit: 'celsius',
279
- accuracy: 0.1,
280
- timestamp: Date.now()
158
+ // Create a hologram (reference) in target holon pointing to source data
159
+ await hs.propagateData(
160
+ sourceData,
161
+ sourceHolonId,
162
+ targetHolonId,
163
+ 'events'
164
+ );
165
+
166
+ // Holograms support local overrides (position, pinned status, etc.)
167
+ await hs.updateHologramOverrides(targetHolonId, 'events', hologramId, {
168
+ x: 100,
169
+ y: 200,
170
+ pinned: true
281
171
  });
282
172
 
283
- // This will fail due to schema validation
284
- await sphere.put(holon, 'measurements', {
285
- id: 'measure-2',
286
- value: "invalid", // wrong type
287
- extra: "field" // not allowed
288
- });
173
+ // Resolution merges source data with local overrides
174
+ const resolved = await hs.resolveHologram(hologram);
175
+ // => { ...sourceData, x: 100, y: 200, pinned: true }
289
176
  ```
290
177
 
291
- ## API Reference
178
+ ### Federation (Within Holosphere)
179
+ Bidirectional data sharing between holons:
292
180
 
293
- ### Constructor
294
181
  ```javascript
295
- new HoloSphere(
296
- appName, // String: Namespace for your application
297
- strict, // Boolean: Enable strict schema validation (default: false)
298
- openaikey // String: Optional OpenAI API key for AI features
299
- )
182
+ // Get parent holon (larger geographic region)
183
+ const parents = await hs.getParents(localHolon);
184
+ const regionalHolon = parents[0];
185
+
186
+ // Establish federation - data in localHolon is visible from regionalHolon
187
+ await hs.federate(localHolon, regionalHolon, 'events', {
188
+ direction: 'outbound',
189
+ mode: 'reference' // Creates holograms instead of copies
190
+ });
191
+
192
+ // Query regional holon sees local data via holograms
193
+ const events = await hs.getFederatedData(regionalHolon, 'events');
300
194
  ```
301
195
 
302
- ### Core Methods
196
+ ### Cross-Holosphere Federation
197
+ Multi-instance partnerships with capability token exchange:
303
198
 
304
- - `async getHolon(lat, lng, resolution)` - Get H3 index for coordinates
305
- - `async put(holon, lens, data)` - Store data
306
- - `async get(holon, lens, key)` - Retrieve specific data
307
- - `async getAll(holon, lens)` - Retrieve all data
308
- - `async delete(holon, lens, key)` - Delete specific data
309
- - `async deleteAll(holon, lens)` - Delete all data
310
- - `async setSchema(lens, schema)` - Set JSON schema for validation
311
- - `async getSchema(lens)` - Get current schema
312
- - `subscribe(holon, lens, callback)` - Listen for changes
199
+ ```javascript
200
+ // Add a federated partner by their public key
201
+ await hs.addFederatedHolosphere(partnerPubKey, {
202
+ name: 'Partner Holosphere',
203
+ permissions: ['read', 'write']
204
+ });
313
205
 
314
- ## Storage Architecture
206
+ // Issue capability token for the partner
207
+ const capability = await hs.issueCapabilityForFederation(partnerPubKey, {
208
+ permissions: ['read', 'write'],
209
+ scope: { holonId: '*', lensName: 'events' },
210
+ expiresIn: 86400000 // 24 hours
211
+ });
315
212
 
316
- Data in HoloSphere is organized by:
317
- - **Holons**: H3 geographic indexes
318
- - **Lenses**: Data categories/types
319
- - **Items**: Individual data entries with unique IDs
213
+ // Read data from a federated partner
214
+ const remoteData = await hs.readFromFederatedSource(
215
+ partnerPubKey,
216
+ holonId,
217
+ 'events',
218
+ dataId
219
+ );
220
+
221
+ // Create a hologram pointing to remote data
222
+ await hs.createCrossHolosphereHologram(
223
+ partnerPubKey,
224
+ remoteHolonId,
225
+ 'events',
226
+ remoteDataId,
227
+ localHolonId
228
+ );
229
+ ```
320
230
 
321
- ## Dependencies
231
+ ### Discovery Protocol (Nostr-Based)
232
+ Automated federation handshake via Nostr events:
322
233
 
323
- - h3-js: Uber's H3 geospatial indexing
324
- - gun: Decentralized database
325
- - ajv: JSON Schema validation
326
- - openai: AI capabilities (optional)
234
+ ```javascript
235
+ // Send federation request to another holosphere
236
+ await hs.sendFederationRequest(targetPubKey, {
237
+ proposedPermissions: ['read', 'write'],
238
+ proposedScopes: [{ holonId: '*', lensName: 'events' }],
239
+ message: 'Requesting federation partnership'
240
+ });
327
241
 
328
- ## License
242
+ // Listen for incoming federation requests
243
+ hs.subscribeFederationRequests((request) => {
244
+ console.log('Federation request from:', request.authorPubKey);
329
245
 
330
- GPL-3.0-or-later
246
+ // Accept the request
247
+ hs.acceptFederationRequest(request, {
248
+ grantedPermissions: ['read'],
249
+ grantedScopes: [{ holonId: '*', lensName: 'events' }]
250
+ });
251
+ });
331
252
 
332
- # HoloSphere Federation
253
+ // Subscribe to acceptance/decline responses
254
+ hs.subscribeFederationAcceptances((acceptance) => {
255
+ console.log('Federation accepted by:', acceptance.authorPubKey);
256
+ });
257
+ ```
333
258
 
334
- HoloSphere provides a federation system that allows spaces to share data and messages across different holons. This document outlines the federation functionality and how to use it.
259
+ ### Hierarchical Aggregation
260
+ Automatic propagation to parent holons:
335
261
 
336
- ## Core Federation Features
262
+ ```javascript
263
+ await hs.upcast(localHolon, 'sensors', 'temp-001', {
264
+ maxLevel: 3, // Propagate 3 levels up hierarchy
265
+ operation: 'summarize' // or 'aggregate', 'concatenate'
266
+ });
267
+ ```
337
268
 
338
- ### Space Federation
339
- - Create relationships between spaces with clear source-target connections
340
- - Use soul references to maintain a single source of truth
341
- - Control data propagation between federated spaces
342
- - Manage notification settings for each space
269
+ ## Authentication & Cryptography
343
270
 
344
- ### Message Federation
345
- - Track messages across federated spaces
346
- - Maintain message relationships between original and federated copies
347
- - Update messages consistently across all federated spaces
271
+ ### Key Management
272
+ ```javascript
273
+ // Derive public key from private key
274
+ const pubKey = hs.getPublicKey(privateKey);
348
275
 
349
- ## API Reference
276
+ // Sign content
277
+ const signature = await hs.sign(content, privateKey);
350
278
 
351
- ### Space Federation
279
+ // Verify signature
280
+ const isValid = await hs.verify(content, signature, pubKey);
281
+ ```
352
282
 
353
- #### `federate(spaceId1, spaceId2, password1, password2, bidirectional)`
354
- Creates a federation relationship between two spaces.
283
+ ### Capability Tokens
284
+ Fine-grained permission control with scope-based access:
355
285
 
356
286
  ```javascript
357
- await holosphere.federate('space1', 'space2', 'pass1', 'pass2');
287
+ // Issue a capability token
288
+ const token = await hs.issueCapability(
289
+ ['read', 'write'], // Permissions
290
+ { holonId: '*', lensName: 'events' }, // Scope (supports wildcards)
291
+ recipientPubKey, // Recipient
292
+ { expiresIn: 3600000 } // Options (1 hour expiry)
293
+ );
294
+
295
+ // Verify a capability token
296
+ const result = await hs.verifyCapability(
297
+ token,
298
+ 'write', // Required permission
299
+ { holonId: holonId, lensName: 'events' } // Requested scope
300
+ );
301
+
302
+ if (result.valid) {
303
+ // Authorized
304
+ }
358
305
  ```
359
306
 
360
- This sets up:
361
- - space1.federation includes space2
362
- - space2.notify includes space1
307
+ **Capability Features:**
308
+ - JWT-like base64 encoding
309
+ - Permissions: `read`, `write`, `delete`
310
+ - Scope wildcards: `{ holonId: "*", lensName: "*" }`
311
+ - Automatic expiration
312
+ - Cryptographic signing with secp256k1
363
313
 
364
- Parameters:
365
- - `spaceId1`: First space ID (source space)
366
- - `spaceId2`: Second space ID (target space)
367
- - `password1`: Optional password for first space
368
- - `password2`: Optional password for second space
369
- - `bidirectional`: Whether to set up bidirectional notifications (default: true, but generally not needed)
370
-
371
- ### Data Propagation
314
+ ## API Reference
372
315
 
373
- #### `propagate(holon, lens, data, options)`
374
- Propagates data to federated spaces.
316
+ ### Configuration Options
375
317
 
376
318
  ```javascript
377
- await holosphere.propagate('space1', 'items', data, {
378
- useReferences: true, // Default: uses soul references
379
- targetSpaces: ['space2'] // Optional: specific targets
319
+ const hs = new HoloSphere({
320
+ appName: 'myapp', // Application namespace (default: 'holosphere')
321
+ relays: [ // Nostr relay servers
322
+ 'wss://relay.damus.io',
323
+ 'wss://nos.lol'
324
+ ],
325
+ privateKey: 'hex...', // secp256k1 private key (auto-generated if omitted)
326
+ logLevel: 'WARN', // 'ERROR' | 'WARN' | 'INFO' | 'DEBUG'
327
+ hybridMode: true, // Query both local cache and relays (default: true)
328
+ enableReconnect: true, // Auto-reconnect to relays (default: true)
329
+ enablePing: true, // Keep-alive pings (default: true)
330
+
331
+ // Local-first options
332
+ persistence: true, // Enable persistent storage (default: true)
333
+ dataDir: './data', // Storage directory for persistence
334
+ backgroundSync: true, // Enable SyncService (default: true)
335
+ syncInterval: 10000, // Background sync interval in ms (default: 10000)
336
+ maxRetries: 5, // Max retry attempts for failed writes (default: 5)
337
+ retryBaseDelay: 1000, // Base delay for exponential backoff (default: 1000ms)
338
+ retryMaxDelay: 60000, // Max delay cap for retries (default: 60000ms)
339
+ failedTTL: 86400000, // TTL for failed events before purge (default: 24h)
380
340
  });
381
341
  ```
382
342
 
383
- Parameters:
384
- - `holon`: The holon identifier
385
- - `lens`: The lens identifier
386
- - `data`: The data to propagate
387
- - `options`: Propagation options
388
-
389
- Alternatively, you can use auto-propagation:
343
+ ### Spatial Operations
344
+ | Method | Description |
345
+ |--------|-------------|
346
+ | `toHolon(lat, lng, resolution)` | Convert coordinates to H3 holon ID |
347
+ | `getParents(holonId, maxResolution?)` | Get parent holons up hierarchy |
348
+ | `getChildren(holonId)` | Get 7 child holons at next resolution |
349
+ | `isValidH3(holonId)` | Validate H3 format |
350
+
351
+ ### Data Operations
352
+ | Method | Description |
353
+ |--------|-------------|
354
+ | `write(holonId, lensName, data, options?)` | Write data to lens |
355
+ | `read(holonId, lensName, dataId?)` | Read data (single or all) |
356
+ | `update(holonId, lensName, dataId, updates, options?)` | Partial update |
357
+ | `delete(holonId, lensName, dataId, options?)` | Delete data |
358
+ | `getAll(holonId, lensName)` | Get all data in lens |
359
+
360
+ ### Global Table Operations
361
+ | Method | Description |
362
+ |--------|-------------|
363
+ | `writeGlobal(table, data)` | Write non-location-specific data |
364
+ | `readGlobal(table, key?)` | Read global data |
365
+ | `updateGlobal(table, key, updates)` | Update global data |
366
+ | `deleteGlobal(table, key)` | Delete global data |
367
+ | `getAllGlobal(table)` | Get all data in table |
368
+ | `deleteAllGlobal(table)` | Clear entire table |
369
+
370
+ ### Hologram Operations
371
+ | Method | Description |
372
+ |--------|-------------|
373
+ | `createHologram(sourceHolon, sourceLens, sourceId, targetHolon)` | Create reference |
374
+ | `resolveHologram(hologram)` | Resolve to actual data with overrides |
375
+ | `updateHologramOverrides(holon, lens, id, overrides)` | Update local fields |
376
+ | `deleteHologram(holon, lens, id)` | Delete with cleanup |
377
+ | `getActiveHolograms(holon, lens, id)` | Get all refs to data |
378
+ | `cleanupCircularHolograms(holon, lens)` | Remove circular refs |
379
+
380
+ ### Federation Operations
381
+ | Method | Description |
382
+ |--------|-------------|
383
+ | `federate(source, target, lens, options?)` | Establish federation |
384
+ | `federateHolon(source, target, options?)` | Holon-level federation |
385
+ | `getFederatedData(holonId, lens, options?)` | Query federated data |
386
+ | `unfederate(source, target, lens)` | Remove federation |
387
+ | `propagateData(data, source, target, lens)` | Propagate to target |
388
+
389
+ ### Cross-Holosphere Operations
390
+ | Method | Description |
391
+ |--------|-------------|
392
+ | `addFederatedHolosphere(pubKey, options)` | Add partner instance |
393
+ | `removeFederatedHolosphere(pubKey)` | Remove partner |
394
+ | `getFederatedHolospheres()` | List all partners |
395
+ | `getFederationRegistry()` | Get full registry |
396
+ | `issueCapabilityForFederation(pubKey, options)` | Grant access |
397
+ | `storeInboundCapability(pubKey, token)` | Store received token |
398
+ | `readFromFederatedSource(pubKey, holon, lens, id)` | Read remote data |
399
+ | `createCrossHolosphereHologram(pubKey, holon, lens, id, target)` | Remote reference |
400
+
401
+ ### Discovery Protocol Operations
402
+ | Method | Description |
403
+ |--------|-------------|
404
+ | `sendFederationRequest(targetPubKey, options)` | Propose federation |
405
+ | `subscribeFederationRequests(callback)` | Listen for requests |
406
+ | `acceptFederationRequest(request, options)` | Accept proposal |
407
+ | `declineFederationRequest(request, reason)` | Decline proposal |
408
+ | `subscribeFederationAcceptances(callback)` | Track acceptances |
409
+ | `subscribeFederationDeclines(callback)` | Track declines |
410
+ | `getPendingFederationRequests(options)` | Query pending |
411
+
412
+ ### Schema Operations
413
+ | Method | Description |
414
+ |--------|-------------|
415
+ | `setSchema(lensName, schema, strict?)` | Define JSON Schema validation |
416
+ | `getSchema(lensName)` | Retrieve schema |
417
+ | `clearSchema(lensName)` | Remove schema |
418
+
419
+ ### Subscription Operations
420
+ | Method | Description |
421
+ |--------|-------------|
422
+ | `subscribe(holonId, lens, callback, options?)` | Real-time updates |
423
+ | `subscribeGlobal(table, key, callback)` | Global table subscriptions |
424
+
425
+ **Subscription Options:**
426
+ - `throttle`: Minimum ms between callbacks
427
+ - `filter`: Function to filter events
428
+ - `resolveHolograms`: Auto-resolve hologram references (default: true)
429
+ - `realtimeOnly`: Skip historical data
430
+
431
+ ### Cryptographic Operations
432
+ | Method | Description |
433
+ |--------|-------------|
434
+ | `getPublicKey(privateKey)` | Derive public key |
435
+ | `sign(content, privateKey)` | Sign content |
436
+ | `verify(content, signature, publicKey)` | Verify signature |
437
+ | `issueCapability(permissions, scope, recipient, options?)` | Issue token |
438
+ | `verifyCapability(token, permission, scope)` | Verify token |
439
+
440
+ ### Social Protocol Operations
441
+ | Method | Description |
442
+ |--------|-------------|
443
+ | `publishNostr(event, holonId, lens?)` | Publish Nostr NIP-01 event |
444
+ | `publishActivityPub(object, holonId, lens?)` | Publish ActivityPub object |
445
+ | `querySocial(holonId, options?)` | Query with protocol/access filtering |
446
+ | `verifyNostrEvent(event)` | Verify event signature |
447
+
448
+ ### Hierarchical Operations
449
+ | Method | Description |
450
+ |--------|-------------|
451
+ | `upcast(holonId, lens, dataId, options?)` | Propagate to parent holons |
452
+
453
+ **Upcast Operations:**
454
+ - `summarize`: Condense data to summary
455
+ - `aggregate`: Combine multiple items
456
+ - `concatenate`: Combine all data
457
+
458
+ ### Utility Operations
459
+ | Method | Description |
460
+ |--------|-------------|
461
+ | `metrics()` | Get operation counts and stats |
462
+
463
+ ## Architecture
464
+
465
+ HoloSphere follows constitutional principles:
466
+
467
+ - **Spatial-First**: H3 as universal spatial reference (resolutions 0-15)
468
+ - **Decentralization**: P2P architecture via Nostr relays, no central authority
469
+ - **Single Source of Truth**: Holograms (references) instead of data duplication
470
+ - **Lens-Based Organization**: Independent schemas and federation per category
471
+ - **Real-time Reactive**: Built-in subscriptions with throttling and filtering
472
+ - **Cryptographic Security**: secp256k1 signatures, capability tokens with scopes
473
+ - **Cross-Instance Federation**: Multi-holosphere partnerships via public keys
474
+ - **Schema Flexibility**: Optional strict JSON Schema validation
475
+ - **Hybrid Queries**: Combined local cache + relay queries for performance
476
+
477
+ ### Data Model
390
478
 
391
- ```javascript
392
- await holosphere.put('space1', 'items', data, null, {
393
- autoPropagate: true // Enable auto-propagation
394
- });
479
+ ```
480
+ appName/
481
+ ├── holonId/ # Geographic (H3) or noospheric ID
482
+ │ └── lensName/ # Data category
483
+ │ └── dataId # Individual data item
484
+ │ ├── ...data fields
485
+ │ └── _meta/ # Metadata
486
+ │ ├── timestamp
487
+ │ ├── creator
488
+ │ ├── source # Original location (for copies)
489
+ │ └── activeHolograms[] # Tracking refs
490
+ └── _global/ # Non-spatial data
491
+ └── tableName/
492
+ └── key
395
493
  ```
396
494
 
397
- ### Message Federation
398
-
399
- #### `federateMessage(originalChatId, messageId, federatedChatId, federatedMessageId, type)`
400
- Tracks a federated message across different chats.
495
+ ### Hologram Structure
401
496
 
402
497
  ```javascript
403
- await holosphere.federateMessage('chat1', 'msg1', 'chat2', 'msg2', 'quest');
498
+ {
499
+ id: 'hologram-uuid',
500
+ _isHologram: true,
501
+ soul: 'appname/sourceHolon/lens/dataId', // Source path
502
+ sourceHolonId: 'source-holon',
503
+ sourceLensName: 'events',
504
+ sourceDataId: 'original-id',
505
+
506
+ // Cross-holosphere (optional)
507
+ authorPubKey: 'source-pubkey',
508
+ embeddedCapability: 'base64-token',
509
+
510
+ // Local overrides
511
+ x: 100,
512
+ y: 200,
513
+ pinned: true
514
+ }
404
515
  ```
405
516
 
406
- #### `getFederatedMessages(originalChatId, messageId)`
407
- Gets all federated messages for a given original message.
517
+ ## Development
408
518
 
409
- ```javascript
410
- const messages = await holosphere.getFederatedMessages('chat1', 'msg1');
411
- ```
519
+ ```bash
520
+ # Install dependencies
521
+ npm install
412
522
 
413
- #### `updateFederatedMessages(originalChatId, messageId, updateCallback)`
414
- Updates a message across all federated chats.
523
+ # Run tests
524
+ npm test
415
525
 
416
- ```javascript
417
- await holosphere.updateFederatedMessages('chat1', 'msg1', async (chatId, messageId) => {
418
- // Update message in this chat
419
- });
420
- ```
526
+ # Watch mode
527
+ npm run test:watch
421
528
 
422
- ## Usage Example
529
+ # Coverage
530
+ npm run test:coverage
423
531
 
424
- ```javascript
425
- // Create federation between spaces
426
- await holosphere.federate('space1', 'space2');
532
+ # Build
533
+ npm run build
427
534
 
428
- // Store data in space1
429
- const data = { id: 'item1', value: 42 };
430
- await holosphere.put('space1', 'items', data);
535
+ # Lint
536
+ npm run lint
431
537
 
432
- // Propagate to federated spaces
433
- await holosphere.propagate('space1', 'items', data);
538
+ # Format
539
+ npm run format
540
+ ```
434
541
 
435
- // Retrieve data from space2 (will resolve the reference)
436
- const item = await holosphere.get('space2', 'items', 'item1');
542
+ ## Testing
437
543
 
438
- // Track a federated message
439
- await holosphere.federateMessage('chat1', 'msg1', 'chat2', 'msg2', 'quest');
544
+ - **375+ tests**: Contract, integration, and unit tests
545
+ - TDD approach: Tests written before implementation
440
546
 
441
- // Update message across all federated chats
442
- await holosphere.updateFederatedMessages('chat1', 'msg1', async (chatId, messageId) => {
443
- await updateMessageInChat(chatId, messageId);
444
- });
547
+ ## Error Handling
548
+
549
+ ```javascript
550
+ import { ValidationError, AuthorizationError, HolosphereError } from 'holosphere';
551
+
552
+ try {
553
+ await hs.write(holonId, 'events', invalidData);
554
+ } catch (error) {
555
+ if (error instanceof ValidationError) {
556
+ console.log('Schema validation failed:', error.message);
557
+ } else if (error instanceof AuthorizationError) {
558
+ console.log('Permission denied:', error.message);
559
+ }
560
+ }
445
561
  ```
446
562
 
447
- ## Soul References
563
+ ## License
448
564
 
449
- When using the default `useReferences: true` with propagation:
565
+ MIT
450
566
 
451
- 1. Only a lightweight reference is stored in the federated space
452
- 2. The reference contains the original item's ID and soul path
453
- 3. When accessed, the reference is automatically resolved to the original data
454
- 4. Changes to the original data are immediately visible through references
567
+ ## Links
455
568
 
456
- This maintains a single source of truth while keeping storage efficient.
569
+ - [Local-First Architecture](./LOCALFIRST.md)
570
+ - [FOSDEM Proposal](./FOSDEM_PROPOSAL.md)
571
+ - [Full API Documentation](./specs/001-holosphere-holonic-geospatial/contracts/api-interface.md)
572
+ - [Quickstart Guide](./specs/001-holosphere-holonic-geospatial/quickstart.md)
573
+ - [Implementation Plan](./specs/001-holosphere-holonic-geospatial/plan.md)
574
+ - [Data Model](./specs/001-holosphere-holonic-geospatial/data-model.md)
575
+ - [Constitution](./specify/memory/constitution.md)
457
576
 
458
- ## Federation Structure
577
+ ## Contributing
459
578
 
460
- The federation system uses two key arrays to manage relationships:
579
+ Contributions welcome! Please ensure:
580
+ 1. All tests pass (`npm test`)
581
+ 2. Code is formatted (`npm run format`)
582
+ 3. Linting passes (`npm run lint`)
583
+ 4. Constitutional principles are followed
461
584
 
462
- ```javascript
463
- {
464
- id: string,
465
- name: string,
466
- federation: string[], // Source spaces this holon federates with
467
- notify: string[], // Target spaces to notify of changes
468
- timestamp: number
469
- }
470
- ```
585
+ ---
471
586
 
587
+ Generated with [Claude Code](https://claude.com/claude-code)