holosphere 1.1.19 → 2.0.0-alpha0

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 (146) hide show
  1. package/.env.example +36 -0
  2. package/.eslintrc.json +16 -0
  3. package/.prettierrc.json +7 -0
  4. package/README.md +476 -531
  5. package/bin/holosphere-activitypub.js +158 -0
  6. package/cleanup-test-data.js +204 -0
  7. package/examples/demo.html +1333 -0
  8. package/examples/example-bot.js +197 -0
  9. package/package.json +47 -87
  10. package/scripts/check-bundle-size.js +54 -0
  11. package/scripts/check-quest-ids.js +77 -0
  12. package/scripts/import-holons.js +578 -0
  13. package/scripts/publish-to-relay.js +101 -0
  14. package/scripts/read-example.js +186 -0
  15. package/scripts/relay-diagnostic.js +59 -0
  16. package/scripts/relay-example.js +179 -0
  17. package/scripts/resync-to-relay.js +245 -0
  18. package/scripts/revert-import.js +196 -0
  19. package/scripts/test-hybrid-mode.js +108 -0
  20. package/scripts/test-local-storage.js +63 -0
  21. package/scripts/test-nostr-direct.js +55 -0
  22. package/scripts/test-read-data.js +45 -0
  23. package/scripts/test-write-read.js +63 -0
  24. package/scripts/verify-import.js +95 -0
  25. package/scripts/verify-relay-data.js +139 -0
  26. package/src/ai/aggregation.js +319 -0
  27. package/src/ai/breakdown.js +511 -0
  28. package/src/ai/classifier.js +217 -0
  29. package/src/ai/council.js +228 -0
  30. package/src/ai/embeddings.js +279 -0
  31. package/src/ai/federation-ai.js +324 -0
  32. package/src/ai/h3-ai.js +955 -0
  33. package/src/ai/index.js +112 -0
  34. package/src/ai/json-ops.js +225 -0
  35. package/src/ai/llm-service.js +205 -0
  36. package/src/ai/nl-query.js +223 -0
  37. package/src/ai/relationships.js +353 -0
  38. package/src/ai/schema-extractor.js +218 -0
  39. package/src/ai/spatial.js +293 -0
  40. package/src/ai/tts.js +194 -0
  41. package/src/content/social-protocols.js +168 -0
  42. package/src/core/holosphere.js +273 -0
  43. package/src/crypto/secp256k1.js +259 -0
  44. package/src/federation/discovery.js +334 -0
  45. package/src/federation/hologram.js +1042 -0
  46. package/src/federation/registry.js +386 -0
  47. package/src/hierarchical/upcast.js +110 -0
  48. package/src/index.js +2669 -0
  49. package/src/schema/validator.js +91 -0
  50. package/src/spatial/h3-operations.js +110 -0
  51. package/src/storage/backend-factory.js +125 -0
  52. package/src/storage/backend-interface.js +142 -0
  53. package/src/storage/backends/activitypub/server.js +653 -0
  54. package/src/storage/backends/activitypub-backend.js +272 -0
  55. package/src/storage/backends/gundb-backend.js +233 -0
  56. package/src/storage/backends/nostr-backend.js +136 -0
  57. package/src/storage/filesystem-storage-browser.js +41 -0
  58. package/src/storage/filesystem-storage.js +138 -0
  59. package/src/storage/global-tables.js +81 -0
  60. package/src/storage/gun-async.js +281 -0
  61. package/src/storage/gun-wrapper.js +221 -0
  62. package/src/storage/indexeddb-storage.js +122 -0
  63. package/src/storage/key-storage-simple.js +76 -0
  64. package/src/storage/key-storage.js +136 -0
  65. package/src/storage/memory-storage.js +59 -0
  66. package/src/storage/migration.js +338 -0
  67. package/src/storage/nostr-async.js +811 -0
  68. package/src/storage/nostr-client.js +939 -0
  69. package/src/storage/nostr-wrapper.js +211 -0
  70. package/src/storage/outbox-queue.js +208 -0
  71. package/src/storage/persistent-storage.js +109 -0
  72. package/src/storage/sync-service.js +164 -0
  73. package/src/subscriptions/manager.js +142 -0
  74. package/test-ai-real-api.js +202 -0
  75. package/tests/unit/ai/aggregation.test.js +295 -0
  76. package/tests/unit/ai/breakdown.test.js +446 -0
  77. package/tests/unit/ai/classifier.test.js +294 -0
  78. package/tests/unit/ai/council.test.js +262 -0
  79. package/tests/unit/ai/embeddings.test.js +384 -0
  80. package/tests/unit/ai/federation-ai.test.js +344 -0
  81. package/tests/unit/ai/h3-ai.test.js +458 -0
  82. package/tests/unit/ai/index.test.js +304 -0
  83. package/tests/unit/ai/json-ops.test.js +307 -0
  84. package/tests/unit/ai/llm-service.test.js +390 -0
  85. package/tests/unit/ai/nl-query.test.js +383 -0
  86. package/tests/unit/ai/relationships.test.js +311 -0
  87. package/tests/unit/ai/schema-extractor.test.js +384 -0
  88. package/tests/unit/ai/spatial.test.js +279 -0
  89. package/tests/unit/ai/tts.test.js +279 -0
  90. package/tests/unit/content.test.js +332 -0
  91. package/tests/unit/contract/core.test.js +88 -0
  92. package/tests/unit/contract/crypto.test.js +198 -0
  93. package/tests/unit/contract/data.test.js +223 -0
  94. package/tests/unit/contract/federation.test.js +181 -0
  95. package/tests/unit/contract/hierarchical.test.js +113 -0
  96. package/tests/unit/contract/schema.test.js +114 -0
  97. package/tests/unit/contract/social.test.js +217 -0
  98. package/tests/unit/contract/spatial.test.js +110 -0
  99. package/tests/unit/contract/subscriptions.test.js +128 -0
  100. package/tests/unit/contract/utils.test.js +159 -0
  101. package/tests/unit/core.test.js +152 -0
  102. package/tests/unit/crypto.test.js +328 -0
  103. package/tests/unit/federation.test.js +234 -0
  104. package/tests/unit/gun-async.test.js +252 -0
  105. package/tests/unit/hierarchical.test.js +399 -0
  106. package/tests/unit/integration/scenario-01-geographic-storage.test.js +74 -0
  107. package/tests/unit/integration/scenario-02-federation.test.js +76 -0
  108. package/tests/unit/integration/scenario-03-subscriptions.test.js +102 -0
  109. package/tests/unit/integration/scenario-04-validation.test.js +129 -0
  110. package/tests/unit/integration/scenario-05-hierarchy.test.js +125 -0
  111. package/tests/unit/integration/scenario-06-social.test.js +135 -0
  112. package/tests/unit/integration/scenario-07-persistence.test.js +130 -0
  113. package/tests/unit/integration/scenario-08-authorization.test.js +161 -0
  114. package/tests/unit/integration/scenario-09-cross-dimensional.test.js +139 -0
  115. package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +357 -0
  116. package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +410 -0
  117. package/tests/unit/integration/scenario-12-capability-federated-read.test.js +719 -0
  118. package/tests/unit/performance/benchmark.test.js +85 -0
  119. package/tests/unit/schema.test.js +213 -0
  120. package/tests/unit/spatial.test.js +158 -0
  121. package/tests/unit/storage.test.js +195 -0
  122. package/tests/unit/subscriptions.test.js +328 -0
  123. package/tests/unit/test-data-permanence-debug.js +197 -0
  124. package/tests/unit/test-data-permanence.js +340 -0
  125. package/tests/unit/test-key-persistence-fixed.js +148 -0
  126. package/tests/unit/test-key-persistence.js +172 -0
  127. package/tests/unit/test-relay-permanence.js +376 -0
  128. package/tests/unit/test-second-node.js +95 -0
  129. package/tests/unit/test-simple-write.js +89 -0
  130. package/vite.config.js +49 -0
  131. package/vitest.config.js +20 -0
  132. package/FEDERATION.md +0 -213
  133. package/compute.js +0 -298
  134. package/content.js +0 -1022
  135. package/federation.js +0 -1234
  136. package/global.js +0 -736
  137. package/hexlib.js +0 -335
  138. package/hologram.js +0 -183
  139. package/holosphere-bundle.esm.js +0 -34549
  140. package/holosphere-bundle.js +0 -34580
  141. package/holosphere-bundle.min.js +0 -49
  142. package/holosphere.d.ts +0 -604
  143. package/holosphere.js +0 -739
  144. package/node.js +0 -246
  145. package/schema.js +0 -139
  146. package/utils.js +0 -302
package/README.md CHANGED
@@ -1,642 +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
77
+
78
+ HoloSphere implements true local-first principles: your data lives on your device first, with Nostr relays serving as the sync layer.
79
+
80
+ ### How It Works
75
81
 
82
+ **Reads are instant:**
76
83
  ```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
- }
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');
92
87
  ```
93
88
 
94
- 3. **Hybrid Structures**
95
- - Adaptive governance systems
96
- - Scalable social networks
97
- - Emergency response coordination
98
- - Supply chain management
99
-
89
+ **Writes are guaranteed:**
100
90
  ```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
- }
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
121
95
  ```
122
96
 
123
- ### Key Benefits
97
+ ### Offline Behavior
124
98
 
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
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 |
130
104
 
131
- ## Installation
105
+ ### Configuration
132
106
 
133
- ```bash
134
- npm install holosphere
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)
118
+ });
135
119
  ```
136
120
 
137
- ## Quick Start
121
+ See [LOCALFIRST.md](./LOCALFIRST.md) for detailed architecture documentation.
122
+
123
+ ## Core Concepts
138
124
 
139
- ### Node.js Usage
125
+ ### Holons
126
+ Locations in either **geographic space** (H3 hexagonal cells) or **noospheric space** (URI-identified concepts):
140
127
 
141
128
  ```javascript
142
- import HoloSphere from 'holosphere';
129
+ // Geographic holon (H3 cell at resolution 9)
130
+ const geoHolon = await hs.toHolon(37.7749, -122.4194, 9);
131
+ // => "8928342e20fffff"
143
132
 
144
- // Initialize HoloSphere with radisk persistence
145
- const sphere = new HoloSphere('my-app');
133
+ // Noospheric holon (arbitrary string ID)
134
+ const conceptHolon = "topic/bitcoin";
135
+ ```
146
136
 
147
- // Configure radisk storage (optional - enabled by default)
148
- sphere.configureRadisk({
149
- file: './my-data', // Custom storage directory
150
- radisk: true, // Enable disk persistence
151
- retry: 3, // Retry failed operations
152
- timeout: 5000 // Operation timeout
153
- });
137
+ ### Lenses
138
+ Categorical data collections within a holon:
154
139
 
155
- // Store data at a location (persisted to disk)
156
- const holon = await sphere.getHolon(40.7128, -74.0060, 7); // NYC at resolution 7
157
- await sphere.put(holon, 'observations', {
158
- id: 'obs-001',
159
- temperature: 22.5,
160
- timestamp: Date.now()
140
+ ```javascript
141
+ await hs.write(holonId, 'events', {
142
+ id: 'concert-001',
143
+ name: 'Jazz Night',
144
+ venue: 'Blue Note SF'
161
145
  });
162
146
 
163
- // Retrieve data (from memory or disk)
164
- const data = await sphere.get(holon, 'observations', 'obs-001');
165
- console.log(data);
166
-
167
- // Get radisk statistics
168
- const stats = sphere.getRadiskStats();
169
- console.log('Storage stats:', stats);
147
+ await hs.write(holonId, 'sensors', {
148
+ id: 'temp-001',
149
+ value: 22.5,
150
+ unit: 'celsius'
151
+ });
170
152
  ```
171
153
 
172
- ### Browser Usage
154
+ ### Holograms
155
+ Lightweight references to data that can exist in multiple locations while maintaining a single source of truth:
173
156
 
174
- HoloSphere works seamlessly in browsers with radisk persistence. The bundle automatically includes radisk support:
157
+ ```javascript
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
171
+ });
175
172
 
176
- ```html
177
- <!DOCTYPE html>
178
- <html>
179
- <head>
180
- <title>HoloSphere Browser Example</title>
181
- </head>
182
- <body>
183
- <!-- Load HoloSphere Bundle -->
184
- <script src="https://unpkg.com/holosphere@1.1.18/holosphere-bundle.js"></script>
185
-
186
- <script>
187
- // Radisk is enabled by default in browser
188
- const sphere = new HoloSphere('browser-app');
189
-
190
- // Store data (persisted via IndexedDB)
191
- async function storeData() {
192
- const holon = await sphere.getHolon(40.7128, -74.0060, 7);
193
- await sphere.put(holon, 'observations', {
194
- id: 'browser-obs-001',
195
- temperature: 22.5,
196
- timestamp: Date.now()
197
- });
198
- console.log('Data stored and persisted!');
199
- }
200
-
201
- // Retrieve data (from IndexedDB)
202
- async function retrieveData() {
203
- const holon = await sphere.getHolon(40.7128, -74.0060, 7);
204
- const data = await sphere.get(holon, 'observations', 'browser-obs-001');
205
- console.log('Retrieved data:', data);
206
- }
207
-
208
- // Check radisk status
209
- const stats = sphere.getRadiskStats();
210
- console.log('Radisk stats:', stats);
211
- </script>
212
- </body>
213
- </html>
173
+ // Resolution merges source data with local overrides
174
+ const resolved = await hs.resolveHologram(hologram);
175
+ // => { ...sourceData, x: 100, y: 200, pinned: true }
214
176
  ```
215
177
 
216
- **Key Browser Features:**
217
- - Radisk automatically included in bundle
218
- - ✅ Data persists across page reloads via IndexedDB
219
- - ✅ Works offline with local storage
220
- - ✅ No additional configuration needed
221
- - ✅ Compatible with all modern browsers
222
-
223
- See `examples/radisk-browser-example.html` for a complete working example.
224
-
225
- ### Svelte/SvelteKit Usage
226
-
227
- HoloSphere works seamlessly with Svelte and SvelteKit applications:
228
-
229
- ```svelte
230
- <script>
231
- import { onMount } from 'svelte';
232
- import { browser } from '$app/environment'; // SvelteKit only
233
- import HoloSphere from 'holosphere';
234
-
235
- let hs = null;
236
-
237
- async function initHoloSphere() {
238
- // Client-side only for SvelteKit
239
- if (typeof browser !== 'undefined' && !browser) return;
240
-
241
- hs = new HoloSphere('my-app', false, null, {
242
- radisk: true,
243
- file: './app-radata'
244
- });
245
- }
178
+ ### Federation (Within Holosphere)
179
+ Bidirectional data sharing between holons:
246
180
 
247
- onMount(() => {
248
- initHoloSphere();
249
- });
250
- </script>
181
+ ```javascript
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
+ });
251
191
 
252
- <main>
253
- <button on:click={() => storeData()} disabled={!hs}>
254
- Store Data
255
- </button>
256
- </main>
192
+ // Query regional holon sees local data via holograms
193
+ const events = await hs.getFederatedData(regionalHolon, 'events');
257
194
  ```
258
195
 
259
- **Key Svelte Features:**
260
- - Full Svelte and SvelteKit compatibility
261
- - ✅ SSR-safe initialization
262
- - ✅ Reactive data binding
263
- - ✅ Component lifecycle management
264
- - ✅ Persistent storage across navigation
265
-
266
- See `examples/svelte-holosphere-example.svelte` and `examples/sveltekit-holosphere-example/+page.svelte` for complete examples.
267
-
268
- ## Real-World Examples
269
-
270
- ### Environmental Monitoring System
196
+ ### Cross-Holosphere Federation
197
+ Multi-instance partnerships with capability token exchange:
271
198
 
272
199
  ```javascript
273
- // Define a schema for temperature readings
274
- const tempSchema = {
275
- type: 'object',
276
- properties: {
277
- id: { type: 'string' },
278
- temperature: { type: 'number' },
279
- humidity: { type: 'number' },
280
- timestamp: { type: 'number' }
281
- },
282
- required: ['id', 'temperature', 'timestamp']
283
- };
284
-
285
- // Set up the system
286
- const sphere = new HoloSphere('env-monitor', true); // strict mode enabled
287
- await sphere.setSchema('temperature', tempSchema);
288
-
289
- // Store a reading
290
- async function storeReading(lat, lng, temp, humidity) {
291
- const holon = await sphere.getHolon(lat, lng, 8);
292
- const reading = {
293
- id: `temp-${Date.now()}`,
294
- temperature: temp,
295
- humidity: humidity,
296
- timestamp: Date.now()
297
- };
298
-
299
- return sphere.put(holon, 'temperature', reading);
300
- }
200
+ // Add a federated partner by their public key
201
+ await hs.addFederatedHolosphere(partnerPubKey, {
202
+ name: 'Partner Holosphere',
203
+ permissions: ['read', 'write']
204
+ });
301
205
 
302
- // Get all readings for an area
303
- async function getAreaReadings(lat, lng) {
304
- const holon = await sphere.getHolon(lat, lng, 8);
305
- return sphere.getAll(holon, 'temperature');
306
- }
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
+ });
307
212
 
308
- // Monitor an area for new readings
309
- function monitorArea(lat, lng, callback) {
310
- const holon = sphere.getHolon(lat, lng, 8);
311
- sphere.subscribe(holon, 'temperature', callback);
312
- }
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
+ );
313
229
  ```
314
230
 
315
- ### Location-Based Content System
231
+ ### Discovery Protocol (Nostr-Based)
232
+ Automated federation handshake via Nostr events:
316
233
 
317
234
  ```javascript
318
- // Initialize with AI capabilities for content summarization
319
- const sphere = new HoloSphere('local-content', false, 'your-openai-key');
320
-
321
- // Define content schema
322
- const contentSchema = {
323
- type: 'object',
324
- properties: {
325
- id: { type: 'string' },
326
- title: { type: 'string' },
327
- content: { type: 'string' },
328
- author: { type: 'string' },
329
- timestamp: { type: 'number' }
330
- },
331
- required: ['id', 'title', 'content', 'author']
332
- };
333
-
334
- await sphere.setSchema('articles', contentSchema);
335
-
336
- // Post content for a location
337
- async function postLocalContent(lat, lng, title, content, author) {
338
- const holon = await sphere.getHolon(lat, lng, 7);
339
- const article = {
340
- id: `article-${Date.now()}`,
341
- title,
342
- content,
343
- author,
344
- timestamp: Date.now()
345
- };
346
-
347
- await sphere.put(holon, 'articles', article);
348
-
349
- // Generate summaries for parent areas
350
- await sphere.compute(holon, 'articles', 'summarize');
351
- }
352
-
353
- // Get content for multiple zoom levels
354
- async function getAreaContent(lat, lng) {
355
- const holon = await sphere.getHolon(lat, lng, 7);
356
- const scales = sphere.getHolonScalespace(holon);
357
-
358
- const content = {};
359
- for (const scale of scales) {
360
- content[scale] = await sphere.getAll(scale, 'articles');
361
- }
362
-
363
- return content;
364
- }
365
- ```
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
+ });
366
241
 
367
- ### Data Validation Example
242
+ // Listen for incoming federation requests
243
+ hs.subscribeFederationRequests((request) => {
244
+ console.log('Federation request from:', request.authorPubKey);
368
245
 
369
- ```javascript
370
- // Strict validation with custom schema
371
- const sphere = new HoloSphere('validated-data', true);
372
-
373
- const measurementSchema = {
374
- type: 'object',
375
- properties: {
376
- id: { type: 'string' },
377
- value: { type: 'number' },
378
- unit: { type: 'string' },
379
- accuracy: { type: 'number' },
380
- timestamp: { type: 'number' }
381
- },
382
- required: ['id', 'value', 'unit'],
383
- additionalProperties: false
384
- };
385
-
386
- await sphere.setSchema('measurements', measurementSchema);
387
-
388
- // This will succeed
389
- await sphere.put(holon, 'measurements', {
390
- id: 'measure-1',
391
- value: 42.5,
392
- unit: 'celsius',
393
- accuracy: 0.1,
394
- timestamp: Date.now()
246
+ // Accept the request
247
+ hs.acceptFederationRequest(request, {
248
+ grantedPermissions: ['read'],
249
+ grantedScopes: [{ holonId: '*', lensName: 'events' }]
250
+ });
395
251
  });
396
252
 
397
- // This will fail due to schema validation
398
- await sphere.put(holon, 'measurements', {
399
- id: 'measure-2',
400
- value: "invalid", // wrong type
401
- extra: "field" // not allowed
253
+ // Subscribe to acceptance/decline responses
254
+ hs.subscribeFederationAcceptances((acceptance) => {
255
+ console.log('Federation accepted by:', acceptance.authorPubKey);
402
256
  });
403
257
  ```
404
258
 
405
- ## API Reference
259
+ ### Hierarchical Aggregation
260
+ Automatic propagation to parent holons:
406
261
 
407
- ### Constructor
408
262
  ```javascript
409
- new HoloSphere(
410
- appName, // String: Namespace for your application
411
- strict, // Boolean: Enable strict schema validation (default: false)
412
- openaikey // String: Optional OpenAI API key for AI features
413
- )
263
+ await hs.upcast(localHolon, 'sensors', 'temp-001', {
264
+ maxLevel: 3, // Propagate 3 levels up hierarchy
265
+ operation: 'summarize' // or 'aggregate', 'concatenate'
266
+ });
414
267
  ```
415
268
 
416
- ### Core Methods
417
-
418
- - `async getHolon(lat, lng, resolution)` - Get H3 index for coordinates
419
- - `async put(holon, lens, data)` - Store data
420
- - `async get(holon, lens, key)` - Retrieve specific data
421
- - `async getAll(holon, lens)` - Retrieve all data
422
- - `async delete(holon, lens, key)` - Delete specific data
423
- - `async deleteAll(holon, lens)` - Delete all data
424
- - `async setSchema(lens, schema)` - Set JSON schema for validation
425
- - `async getSchema(lens)` - Get current schema
426
- - `subscribe(holon, lens, callback)` - Listen for changes
427
-
428
- ## Storage Architecture
429
-
430
- Data in HoloSphere is organized by:
431
- - **Holons**: H3 geographic indexes
432
- - **Lenses**: Data categories/types
433
- - **Items**: Individual data entries with unique IDs
434
-
435
- ## Dependencies
436
-
437
- - h3-js: Uber's H3 geospatial indexing
438
- - gun: Decentralized database
439
- - ajv: JSON Schema validation
440
- - openai: AI capabilities (optional)
441
-
442
- ## License
443
-
444
- GPL-3.0-or-later
445
-
446
- # HoloSphere Federation
447
-
448
- 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.
449
-
450
- ## Core Federation Features
451
-
452
- ### Space Federation
453
- - Create relationships between spaces with clear source-target connections
454
- - Use soul references to maintain a single source of truth
455
- - Control data propagation between federated spaces
456
- - Manage notification settings for each space
457
-
458
- ### Message Federation
459
- - Track messages across federated spaces
460
- - Maintain message relationships between original and federated copies
461
- - Update messages consistently across all federated spaces
462
-
463
- ## API Reference
464
-
465
- ### Space Federation
466
-
467
- #### `federate(spaceId1, spaceId2, password1, password2, bidirectional)`
468
- Creates a federation relationship between two spaces.
269
+ ## Authentication & Cryptography
469
270
 
271
+ ### Key Management
470
272
  ```javascript
471
- await holosphere.federate('space1', 'space2', 'pass1', 'pass2');
472
- ```
273
+ // Derive public key from private key
274
+ const pubKey = hs.getPublicKey(privateKey);
473
275
 
474
- This sets up:
475
- - space1.federation includes space2
476
- - space2.notify includes space1
276
+ // Sign content
277
+ const signature = await hs.sign(content, privateKey);
477
278
 
478
- Parameters:
479
- - `spaceId1`: First space ID (source space)
480
- - `spaceId2`: Second space ID (target space)
481
- - `password1`: Optional password for first space
482
- - `password2`: Optional password for second space
483
- - `bidirectional`: Whether to set up bidirectional notifications (default: true, but generally not needed)
484
-
485
- ### Data Propagation
279
+ // Verify signature
280
+ const isValid = await hs.verify(content, signature, pubKey);
281
+ ```
486
282
 
487
- #### `propagate(holon, lens, data, options)`
488
- Propagates data to federated spaces.
283
+ ### Capability Tokens
284
+ Fine-grained permission control with scope-based access:
489
285
 
490
286
  ```javascript
491
- await holosphere.propagate('space1', 'items', data, {
492
- useReferences: true, // Default: uses soul references
493
- targetSpaces: ['space2'] // Optional: specific targets
494
- });
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
+ }
495
305
  ```
496
306
 
497
- Parameters:
498
- - `holon`: The holon identifier
499
- - `lens`: The lens identifier
500
- - `data`: The data to propagate
501
- - `options`: Propagation options
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
502
313
 
503
- Alternatively, you can use auto-propagation:
314
+ ## API Reference
315
+
316
+ ### Configuration Options
504
317
 
505
318
  ```javascript
506
- await holosphere.put('space1', 'items', data, null, {
507
- autoPropagate: true // Enable auto-propagation
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)
508
340
  });
509
341
  ```
510
342
 
511
- ### Message Federation
512
-
513
- #### `federateMessage(originalChatId, messageId, federatedChatId, federatedMessageId, type)`
514
- Tracks a federated message across different chats.
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
515
478
 
516
- ```javascript
517
- await holosphere.federateMessage('chat1', 'msg1', 'chat2', 'msg2', 'quest');
518
479
  ```
519
-
520
- #### `getFederatedMessages(originalChatId, messageId)`
521
- Gets all federated messages for a given original message.
522
-
523
- ```javascript
524
- const messages = await holosphere.getFederatedMessages('chat1', 'msg1');
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
525
493
  ```
526
494
 
527
- #### `updateFederatedMessages(originalChatId, messageId, updateCallback)`
528
- Updates a message across all federated chats.
495
+ ### Hologram Structure
529
496
 
530
497
  ```javascript
531
- await holosphere.updateFederatedMessages('chat1', 'msg1', async (chatId, messageId) => {
532
- // Update message in this chat
533
- });
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
+ }
534
515
  ```
535
516
 
536
- ## Usage Example
517
+ ## Development
537
518
 
538
- ```javascript
539
- // Create federation between spaces
540
- await holosphere.federate('space1', 'space2');
541
-
542
- // Store data in space1
543
- const data = { id: 'item1', value: 42 };
544
- await holosphere.put('space1', 'items', data);
545
-
546
- // Propagate to federated spaces
547
- await holosphere.propagate('space1', 'items', data);
548
-
549
- // Retrieve data from space2 (will resolve the reference)
550
- const item = await holosphere.get('space2', 'items', 'item1');
551
-
552
- // Track a federated message
553
- await holosphere.federateMessage('chat1', 'msg1', 'chat2', 'msg2', 'quest');
554
-
555
- // Update message across all federated chats
556
- await holosphere.updateFederatedMessages('chat1', 'msg1', async (chatId, messageId) => {
557
- await updateMessageInChat(chatId, messageId);
558
- });
559
- ```
519
+ ```bash
520
+ # Install dependencies
521
+ npm install
560
522
 
561
- ## Radisk Storage Configuration
523
+ # Run tests
524
+ npm test
562
525
 
563
- HoloSphere uses GunDB's radisk module for persistent storage. Data is automatically saved to disk and can survive application restarts.
526
+ # Watch mode
527
+ npm run test:watch
564
528
 
565
- ### Basic Configuration
529
+ # Coverage
530
+ npm run test:coverage
566
531
 
567
- ```javascript
568
- // Configure radisk with custom options
569
- sphere.configureRadisk({
570
- file: './my-data', // Storage directory
571
- radisk: true, // Enable disk persistence
572
- retry: 3, // Retry failed operations
573
- timeout: 5000 // Operation timeout in ms
574
- });
575
- ```
532
+ # Build
533
+ npm run build
576
534
 
577
- ### Get Storage Statistics
535
+ # Lint
536
+ npm run lint
578
537
 
579
- ```javascript
580
- const stats = sphere.getRadiskStats();
581
- console.log(stats);
582
- // Output:
583
- // {
584
- // enabled: true,
585
- // filePath: './my-data',
586
- // retry: 3,
587
- // timeout: 5000,
588
- // until: null,
589
- // peers: ['https://gun.holons.io/gun'],
590
- // localStorage: false
591
- // }
538
+ # Format
539
+ npm run format
592
540
  ```
593
541
 
594
- ### Radisk Options
595
-
596
- - `file`: Directory for storing data files (default: `'./radata'`)
597
- - `radisk`: Enable/disable disk persistence (default: `true`)
598
- - `retry`: Number of retries for failed operations (default: `3`)
599
- - `timeout`: Operation timeout in milliseconds (default: `5000`)
600
- - `until`: Timestamp until which to keep data (optional)
542
+ ## Testing
601
543
 
602
- ### Data Persistence
544
+ - **375+ tests**: Contract, integration, and unit tests
545
+ - TDD approach: Tests written before implementation
603
546
 
604
- All data stored via HoloSphere is automatically persisted to disk:
547
+ ## Error Handling
605
548
 
606
549
  ```javascript
607
- // This data will be saved to disk
608
- await sphere.put(holon, 'environment', {
609
- id: 'reading-001',
610
- temperature: 22.5,
611
- timestamp: Date.now()
612
- });
613
-
614
- // Data persists across application restarts
615
- const data = await sphere.get(holon, 'environment', 'reading-001');
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
+ }
616
561
  ```
617
562
 
618
- ## Soul References
563
+ ## License
619
564
 
620
- When using the default `useReferences: true` with propagation:
565
+ MIT
621
566
 
622
- 1. Only a lightweight reference is stored in the federated space
623
- 2. The reference contains the original item's ID and soul path
624
- 3. When accessed, the reference is automatically resolved to the original data
625
- 4. Changes to the original data are immediately visible through references
567
+ ## Links
626
568
 
627
- 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)
628
576
 
629
- ## Federation Structure
577
+ ## Contributing
630
578
 
631
- 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
632
584
 
633
- ```javascript
634
- {
635
- id: string,
636
- name: string,
637
- federation: string[], // Source spaces this holon federates with
638
- notify: string[], // Target spaces to notify of changes
639
- timestamp: number
640
- }
641
- ```
585
+ ---
642
586
 
587
+ Generated with [Claude Code](https://claude.com/claude-code)