holosphere 2.0.0-alpha1 → 2.0.0-alpha4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/dist/2019-D2OG2idw.js +6680 -0
  2. package/dist/2019-D2OG2idw.js.map +1 -0
  3. package/dist/2019-EION3wKo.cjs +8 -0
  4. package/dist/2019-EION3wKo.cjs.map +1 -0
  5. package/dist/_commonjsHelpers-C37NGDzP.cjs +2 -0
  6. package/dist/_commonjsHelpers-C37NGDzP.cjs.map +1 -0
  7. package/dist/_commonjsHelpers-CUmg6egw.js +7 -0
  8. package/dist/_commonjsHelpers-CUmg6egw.js.map +1 -0
  9. package/dist/browser-BSniCNqO.js +3058 -0
  10. package/dist/browser-BSniCNqO.js.map +1 -0
  11. package/dist/browser-Cq59Ij19.cjs +2 -0
  12. package/dist/browser-Cq59Ij19.cjs.map +1 -0
  13. package/dist/cjs/holosphere.cjs +2 -0
  14. package/dist/cjs/holosphere.cjs.map +1 -0
  15. package/dist/esm/holosphere.js +53 -0
  16. package/dist/esm/holosphere.js.map +1 -0
  17. package/dist/index-BB_vVJgv.cjs +5 -0
  18. package/dist/index-BB_vVJgv.cjs.map +1 -0
  19. package/dist/index-CBitK71M.cjs +12 -0
  20. package/dist/index-CBitK71M.cjs.map +1 -0
  21. package/dist/index-CV0eOogK.js +37423 -0
  22. package/dist/index-CV0eOogK.js.map +1 -0
  23. package/dist/index-Cz-PLCUR.js +15104 -0
  24. package/dist/index-Cz-PLCUR.js.map +1 -0
  25. package/dist/indexeddb-storage-CRsZyB2f.cjs +2 -0
  26. package/dist/indexeddb-storage-CRsZyB2f.cjs.map +1 -0
  27. package/dist/indexeddb-storage-DZaGlY_a.js +132 -0
  28. package/dist/indexeddb-storage-DZaGlY_a.js.map +1 -0
  29. package/dist/memory-storage-BkUi6sZG.js +51 -0
  30. package/dist/memory-storage-BkUi6sZG.js.map +1 -0
  31. package/dist/memory-storage-C0DuUsdY.cjs +2 -0
  32. package/dist/memory-storage-C0DuUsdY.cjs.map +1 -0
  33. package/dist/secp256k1-0kPdAVkK.cjs +12 -0
  34. package/dist/secp256k1-0kPdAVkK.cjs.map +1 -0
  35. package/dist/secp256k1-DN4FVXcv.js +1890 -0
  36. package/dist/secp256k1-DN4FVXcv.js.map +1 -0
  37. package/docs/CONTRACTS.md +797 -0
  38. package/docs/FOSDEM_PROPOSAL.md +388 -0
  39. package/docs/LOCALFIRST.md +266 -0
  40. package/docs/contracts/api-interface.md +793 -0
  41. package/docs/data-model.md +476 -0
  42. package/docs/gun-async-usage.md +338 -0
  43. package/docs/plan.md +349 -0
  44. package/docs/quickstart.md +674 -0
  45. package/docs/research.md +362 -0
  46. package/docs/spec.md +244 -0
  47. package/docs/storage-backends.md +326 -0
  48. package/docs/tasks.md +947 -0
  49. package/examples/demo.html +47 -0
  50. package/package.json +10 -5
  51. package/src/contracts/abis/Appreciative.json +1280 -0
  52. package/src/contracts/abis/AppreciativeFactory.json +101 -0
  53. package/src/contracts/abis/Bundle.json +1435 -0
  54. package/src/contracts/abis/BundleFactory.json +106 -0
  55. package/src/contracts/abis/Holon.json +881 -0
  56. package/src/contracts/abis/Holons.json +330 -0
  57. package/src/contracts/abis/Managed.json +1262 -0
  58. package/src/contracts/abis/ManagedFactory.json +149 -0
  59. package/src/contracts/abis/Membrane.json +261 -0
  60. package/src/contracts/abis/Splitter.json +1624 -0
  61. package/src/contracts/abis/SplitterFactory.json +220 -0
  62. package/src/contracts/abis/TestToken.json +321 -0
  63. package/src/contracts/abis/Zoned.json +1461 -0
  64. package/src/contracts/abis/ZonedFactory.json +154 -0
  65. package/src/contracts/chain-manager.js +375 -0
  66. package/src/contracts/deployer.js +443 -0
  67. package/src/contracts/event-listener.js +507 -0
  68. package/src/contracts/holon-contracts.js +344 -0
  69. package/src/contracts/index.js +83 -0
  70. package/src/contracts/networks.js +224 -0
  71. package/src/contracts/operations.js +670 -0
  72. package/src/contracts/queries.js +589 -0
  73. package/src/core/holosphere.js +453 -1
  74. package/src/crypto/nostr-utils.js +263 -0
  75. package/src/federation/handshake.js +455 -0
  76. package/src/federation/hologram.js +1 -1
  77. package/src/hierarchical/upcast.js +6 -5
  78. package/src/index.js +463 -1939
  79. package/src/lib/ai-methods.js +308 -0
  80. package/src/lib/contract-methods.js +293 -0
  81. package/src/lib/errors.js +23 -0
  82. package/src/lib/federation-methods.js +238 -0
  83. package/src/lib/index.js +26 -0
  84. package/src/spatial/h3-operations.js +2 -2
  85. package/src/storage/backends/gundb-backend.js +377 -46
  86. package/src/storage/global-tables.js +28 -1
  87. package/src/storage/gun-auth.js +303 -0
  88. package/src/storage/gun-federation.js +776 -0
  89. package/src/storage/gun-references.js +198 -0
  90. package/src/storage/gun-schema.js +291 -0
  91. package/src/storage/gun-wrapper.js +347 -31
  92. package/src/storage/indexeddb-storage.js +49 -11
  93. package/src/storage/memory-storage.js +5 -0
  94. package/src/storage/nostr-async.js +45 -23
  95. package/src/storage/nostr-client.js +11 -5
  96. package/src/storage/persistent-storage.js +6 -1
  97. package/src/storage/unified-storage.js +119 -0
  98. package/src/subscriptions/manager.js +1 -1
  99. package/types/index.d.ts +133 -0
  100. package/tests/unit/ai/aggregation.test.js +0 -295
  101. package/tests/unit/ai/breakdown.test.js +0 -446
  102. package/tests/unit/ai/classifier.test.js +0 -294
  103. package/tests/unit/ai/council.test.js +0 -262
  104. package/tests/unit/ai/embeddings.test.js +0 -384
  105. package/tests/unit/ai/federation-ai.test.js +0 -344
  106. package/tests/unit/ai/h3-ai.test.js +0 -458
  107. package/tests/unit/ai/index.test.js +0 -304
  108. package/tests/unit/ai/json-ops.test.js +0 -307
  109. package/tests/unit/ai/llm-service.test.js +0 -390
  110. package/tests/unit/ai/nl-query.test.js +0 -383
  111. package/tests/unit/ai/relationships.test.js +0 -311
  112. package/tests/unit/ai/schema-extractor.test.js +0 -384
  113. package/tests/unit/ai/spatial.test.js +0 -279
  114. package/tests/unit/ai/tts.test.js +0 -279
  115. package/tests/unit/content.test.js +0 -332
  116. package/tests/unit/contract/core.test.js +0 -88
  117. package/tests/unit/contract/crypto.test.js +0 -198
  118. package/tests/unit/contract/data.test.js +0 -223
  119. package/tests/unit/contract/federation.test.js +0 -181
  120. package/tests/unit/contract/hierarchical.test.js +0 -113
  121. package/tests/unit/contract/schema.test.js +0 -114
  122. package/tests/unit/contract/social.test.js +0 -217
  123. package/tests/unit/contract/spatial.test.js +0 -110
  124. package/tests/unit/contract/subscriptions.test.js +0 -128
  125. package/tests/unit/contract/utils.test.js +0 -159
  126. package/tests/unit/core.test.js +0 -152
  127. package/tests/unit/crypto.test.js +0 -328
  128. package/tests/unit/federation.test.js +0 -234
  129. package/tests/unit/gun-async.test.js +0 -252
  130. package/tests/unit/hierarchical.test.js +0 -399
  131. package/tests/unit/integration/scenario-01-geographic-storage.test.js +0 -74
  132. package/tests/unit/integration/scenario-02-federation.test.js +0 -76
  133. package/tests/unit/integration/scenario-03-subscriptions.test.js +0 -102
  134. package/tests/unit/integration/scenario-04-validation.test.js +0 -129
  135. package/tests/unit/integration/scenario-05-hierarchy.test.js +0 -125
  136. package/tests/unit/integration/scenario-06-social.test.js +0 -135
  137. package/tests/unit/integration/scenario-07-persistence.test.js +0 -130
  138. package/tests/unit/integration/scenario-08-authorization.test.js +0 -161
  139. package/tests/unit/integration/scenario-09-cross-dimensional.test.js +0 -139
  140. package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +0 -357
  141. package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +0 -410
  142. package/tests/unit/integration/scenario-12-capability-federated-read.test.js +0 -719
  143. package/tests/unit/performance/benchmark.test.js +0 -85
  144. package/tests/unit/schema.test.js +0 -213
  145. package/tests/unit/spatial.test.js +0 -158
  146. package/tests/unit/storage.test.js +0 -195
  147. package/tests/unit/subscriptions.test.js +0 -328
  148. package/tests/unit/test-data-permanence-debug.js +0 -197
  149. package/tests/unit/test-data-permanence.js +0 -340
  150. package/tests/unit/test-key-persistence-fixed.js +0 -148
  151. package/tests/unit/test-key-persistence.js +0 -172
  152. package/tests/unit/test-relay-permanence.js +0 -376
  153. package/tests/unit/test-second-node.js +0 -95
  154. package/tests/unit/test-simple-write.js +0 -89
@@ -0,0 +1,198 @@
1
+ /**
2
+ * GunDB Reference Handler
3
+ * Handles creation and resolution of data references for federation
4
+ *
5
+ * References use a "soul" pattern: appname/holon/lens/key
6
+ * This allows lightweight propagation without data duplication
7
+ */
8
+
9
+ import { read } from './gun-wrapper.js';
10
+
11
+ /**
12
+ * Reference handler for GunDB backend
13
+ */
14
+ export class GunReferenceHandler {
15
+ /**
16
+ * Create a new reference handler
17
+ * @param {string} appname - Application namespace
18
+ */
19
+ constructor(appname) {
20
+ this.appname = appname;
21
+ }
22
+
23
+ /**
24
+ * Create a reference to data
25
+ * @param {string} holon - Holon ID
26
+ * @param {string} lens - Lens name
27
+ * @param {Object} data - Data object (must have 'id' field)
28
+ * @returns {Object} Reference object with id and soul
29
+ */
30
+ createReference(holon, lens, data) {
31
+ if (!data || !data.id) {
32
+ throw new Error('createReference: data must have an id field');
33
+ }
34
+ return {
35
+ id: data.id,
36
+ soul: `${this.appname}/${holon}/${lens}/${data.id}`
37
+ };
38
+ }
39
+
40
+ /**
41
+ * Check if data is a reference
42
+ * @param {Object} data - Data to check
43
+ * @returns {boolean} True if data is a reference
44
+ */
45
+ isReference(data) {
46
+ if (!data) return false;
47
+
48
+ // Simple reference format: { id, soul }
49
+ if (data.soul && data.id && Object.keys(data).filter(k => !k.startsWith('_')).length <= 2) {
50
+ return true;
51
+ }
52
+
53
+ // Legacy reference format: { _federation: { isReference: true } }
54
+ if (data._federation && data._federation.isReference) {
55
+ return true;
56
+ }
57
+
58
+ // Gun internal reference format: { _: { "#": "path/to/data" } }
59
+ if (data._ && data._['#']) {
60
+ return true;
61
+ }
62
+
63
+ return false;
64
+ }
65
+
66
+ /**
67
+ * Parse a soul path into its components
68
+ * @param {string} soul - Soul path (appname/holon/lens/key)
69
+ * @returns {Object|null} Parsed components or null if invalid
70
+ */
71
+ parseSoulPath(soul) {
72
+ if (!soul || typeof soul !== 'string') {
73
+ return null;
74
+ }
75
+
76
+ const parts = soul.split('/');
77
+ if (parts.length < 4) {
78
+ return null;
79
+ }
80
+
81
+ return {
82
+ appname: parts[0],
83
+ holon: parts[1],
84
+ lens: parts[2],
85
+ key: parts.slice(3).join('/') // Handle keys with slashes
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Resolve a reference to get the actual data
91
+ * @param {Object} gun - Gun instance
92
+ * @param {Object} reference - Reference object
93
+ * @param {Object} options - Resolution options
94
+ * @param {boolean} options.followReferences - Whether to recursively resolve nested references (default: true)
95
+ * @returns {Promise<Object|null>} Resolved data or null if not found
96
+ */
97
+ async resolveReference(gun, reference, options = {}) {
98
+ const { followReferences = true } = options;
99
+
100
+ if (!reference) {
101
+ return null;
102
+ }
103
+
104
+ let soul = null;
105
+ let originInfo = null;
106
+
107
+ // Handle simple reference format { id, soul }
108
+ if (reference.soul) {
109
+ soul = reference.soul;
110
+ }
111
+ // Handle legacy reference format { _federation: { isReference: true, origin, lens } }
112
+ else if (reference._federation && reference._federation.isReference) {
113
+ const fed = reference._federation;
114
+ if (fed.origin && fed.lens && reference.id) {
115
+ soul = `${this.appname}/${fed.origin}/${fed.lens}/${reference.id}`;
116
+ originInfo = fed;
117
+ }
118
+ }
119
+ // Handle Gun internal reference format { _: { "#": "path/to/data" } }
120
+ else if (reference._ && reference._['#']) {
121
+ soul = reference._['#'];
122
+ }
123
+
124
+ if (!soul) {
125
+ return null;
126
+ }
127
+
128
+ // Parse soul to get path components
129
+ const parsed = this.parseSoulPath(soul);
130
+ if (!parsed) {
131
+ return null;
132
+ }
133
+
134
+ try {
135
+ // Build path and read data
136
+ const path = `${parsed.appname}/${parsed.holon}/${parsed.lens}/${parsed.key}`;
137
+ const data = await read(gun, path);
138
+
139
+ if (!data) {
140
+ return null;
141
+ }
142
+
143
+ // Check if resolved data is also a reference and we should follow
144
+ if (followReferences && this.isReference(data)) {
145
+ const nested = await this.resolveReference(gun, data, { followReferences: true });
146
+ if (nested) {
147
+ return {
148
+ ...nested,
149
+ _federation: {
150
+ resolved: true,
151
+ soul: soul,
152
+ origin: parsed.holon,
153
+ lens: parsed.lens,
154
+ timestamp: Date.now()
155
+ }
156
+ };
157
+ }
158
+ }
159
+
160
+ // Add federation metadata to resolved data
161
+ return {
162
+ ...data,
163
+ _federation: {
164
+ resolved: true,
165
+ soul: soul,
166
+ origin: originInfo?.origin || parsed.holon,
167
+ lens: originInfo?.lens || parsed.lens,
168
+ timestamp: Date.now()
169
+ }
170
+ };
171
+ } catch (error) {
172
+ console.warn('Error resolving reference:', error);
173
+ return null;
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Get the soul path for data
179
+ * @param {string} holon - Holon ID
180
+ * @param {string} lens - Lens name
181
+ * @param {string} key - Data key
182
+ * @returns {string} Soul path
183
+ */
184
+ getSoul(holon, lens, key) {
185
+ return `${this.appname}/${holon}/${lens}/${key}`;
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Create a reference handler instance
191
+ * @param {string} appname - Application namespace
192
+ * @returns {GunReferenceHandler} Reference handler instance
193
+ */
194
+ export function createReferenceHandler(appname) {
195
+ return new GunReferenceHandler(appname);
196
+ }
197
+
198
+ export default GunReferenceHandler;
@@ -0,0 +1,291 @@
1
+ /**
2
+ * GunDB Schema Validator
3
+ * Handles JSON Schema validation for data stored in GunDB
4
+ *
5
+ * Schemas are stored in the global 'schemas' table
6
+ * Validation uses AJV (Another JSON Schema Validator) with JSON Schema 2019
7
+ */
8
+
9
+ import { writeGlobal, readGlobal, readAllGlobal, deleteGlobal } from './gun-wrapper.js';
10
+
11
+ // Default meta-schema for validating schema definitions
12
+ const META_SCHEMA = {
13
+ type: 'object',
14
+ required: ['type'],
15
+ properties: {
16
+ $schema: { type: 'string' },
17
+ $id: { type: 'string' },
18
+ type: { type: 'string' },
19
+ properties: { type: 'object' },
20
+ required: { type: 'array', items: { type: 'string' } },
21
+ additionalProperties: { type: 'boolean' }
22
+ }
23
+ };
24
+
25
+ /**
26
+ * Schema validator for GunDB backend
27
+ */
28
+ export class GunSchemaValidator {
29
+ /**
30
+ * Create a new schema validator
31
+ * @param {Object} options - Validator options
32
+ * @param {boolean} options.strict - Whether to enforce strict validation (default: false)
33
+ * @param {number} options.cacheMaxAge - Schema cache TTL in ms (default: 3600000 = 1 hour)
34
+ */
35
+ constructor(options = {}) {
36
+ this.strict = options.strict || false;
37
+ this.cacheMaxAge = options.cacheMaxAge || 3600000; // 1 hour
38
+ this.schemaCache = new Map();
39
+ this.validator = null;
40
+ this.Ajv = null;
41
+ }
42
+
43
+ /**
44
+ * Initialize the validator (lazy load AJV)
45
+ * @returns {Promise<boolean>} True if initialized successfully
46
+ */
47
+ async init() {
48
+ if (this.validator) {
49
+ return true;
50
+ }
51
+
52
+ try {
53
+ // Dynamically import AJV to avoid requiring it if not needed
54
+ const AjvModule = await import('ajv/dist/2019.js');
55
+ this.Ajv = AjvModule.default || AjvModule;
56
+
57
+ this.validator = new this.Ajv({
58
+ allErrors: true,
59
+ strict: false,
60
+ validateSchema: true
61
+ });
62
+
63
+ return true;
64
+ } catch (error) {
65
+ console.warn('AJV not available, schema validation disabled:', error.message);
66
+ return false;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Set a schema for a lens
72
+ * @param {Object} gun - Gun instance
73
+ * @param {string} appname - Application namespace
74
+ * @param {string} lens - Lens name
75
+ * @param {Object} schema - JSON Schema definition
76
+ * @returns {Promise<boolean>} Success indicator
77
+ */
78
+ async setSchema(gun, appname, lens, schema) {
79
+ if (!schema || typeof schema !== 'object') {
80
+ throw new Error('setSchema: schema must be an object');
81
+ }
82
+
83
+ // Validate the schema against meta-schema
84
+ if (this.strict && this.validator) {
85
+ const isValid = this.validateSchema(META_SCHEMA, schema);
86
+ if (!isValid) {
87
+ throw new Error('setSchema: Invalid schema definition');
88
+ }
89
+ }
90
+
91
+ // Store schema in global 'schemas' table
92
+ const schemaRecord = {
93
+ id: lens,
94
+ lens: lens,
95
+ schema: schema,
96
+ timestamp: Date.now()
97
+ };
98
+
99
+ await writeGlobal(gun, appname, 'schemas', schemaRecord);
100
+
101
+ // Update cache
102
+ this.schemaCache.set(lens, {
103
+ schema: schema,
104
+ timestamp: Date.now()
105
+ });
106
+
107
+ return true;
108
+ }
109
+
110
+ /**
111
+ * Get a schema for a lens
112
+ * @param {Object} gun - Gun instance
113
+ * @param {string} appname - Application namespace
114
+ * @param {string} lens - Lens name
115
+ * @param {Object} options - Options
116
+ * @param {boolean} options.useCache - Whether to use cache (default: true)
117
+ * @returns {Promise<Object|null>} Schema or null if not found
118
+ */
119
+ async getSchema(gun, appname, lens, options = {}) {
120
+ const { useCache = true } = options;
121
+
122
+ // Check cache first
123
+ if (useCache) {
124
+ const cached = this.schemaCache.get(lens);
125
+ if (cached && (Date.now() - cached.timestamp) < this.cacheMaxAge) {
126
+ return cached.schema;
127
+ }
128
+ }
129
+
130
+ // Fetch from storage
131
+ const schemaRecord = await readGlobal(gun, appname, 'schemas', lens);
132
+
133
+ if (schemaRecord && schemaRecord.schema) {
134
+ // Update cache
135
+ this.schemaCache.set(lens, {
136
+ schema: schemaRecord.schema,
137
+ timestamp: Date.now()
138
+ });
139
+ return schemaRecord.schema;
140
+ }
141
+
142
+ return null;
143
+ }
144
+
145
+ /**
146
+ * Get all schemas
147
+ * @param {Object} gun - Gun instance
148
+ * @param {string} appname - Application namespace
149
+ * @returns {Promise<Object[]>} Array of schema records
150
+ */
151
+ async getAllSchemas(gun, appname) {
152
+ return readAllGlobal(gun, appname, 'schemas');
153
+ }
154
+
155
+ /**
156
+ * Delete a schema
157
+ * @param {Object} gun - Gun instance
158
+ * @param {string} appname - Application namespace
159
+ * @param {string} lens - Lens name
160
+ * @returns {Promise<boolean>} Success indicator
161
+ */
162
+ async deleteSchema(gun, appname, lens) {
163
+ // Remove from cache
164
+ this.schemaCache.delete(lens);
165
+
166
+ // Delete from storage
167
+ return deleteGlobal(gun, appname, 'schemas', lens);
168
+ }
169
+
170
+ /**
171
+ * Validate data against a schema
172
+ * @param {Object} schema - JSON Schema definition
173
+ * @param {Object} data - Data to validate
174
+ * @returns {Object} Validation result { valid: boolean, errors: Array }
175
+ */
176
+ validate(schema, data) {
177
+ if (!this.validator) {
178
+ // If validator not available, skip validation
179
+ return { valid: true, errors: [] };
180
+ }
181
+
182
+ try {
183
+ const validate = this.validator.compile(schema);
184
+ const valid = validate(data);
185
+
186
+ return {
187
+ valid: valid,
188
+ errors: valid ? [] : this.formatErrors(validate.errors)
189
+ };
190
+ } catch (error) {
191
+ return {
192
+ valid: false,
193
+ errors: [{ message: error.message, path: '' }]
194
+ };
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Validate data against a lens schema (fetch schema from storage)
200
+ * @param {Object} gun - Gun instance
201
+ * @param {string} appname - Application namespace
202
+ * @param {string} lens - Lens name
203
+ * @param {Object} data - Data to validate
204
+ * @returns {Promise<Object>} Validation result { valid: boolean, errors: Array }
205
+ */
206
+ async validateData(gun, appname, lens, data) {
207
+ const schema = await this.getSchema(gun, appname, lens);
208
+
209
+ if (!schema) {
210
+ // No schema defined, validation passes
211
+ return { valid: true, errors: [] };
212
+ }
213
+
214
+ return this.validate(schema, data);
215
+ }
216
+
217
+ /**
218
+ * Validate a schema definition against meta-schema
219
+ * @param {Object} metaSchema - Meta schema to validate against
220
+ * @param {Object} schema - Schema to validate
221
+ * @returns {boolean} True if valid
222
+ */
223
+ validateSchema(metaSchema, schema) {
224
+ if (!this.validator) {
225
+ return true;
226
+ }
227
+
228
+ try {
229
+ const validate = this.validator.compile(metaSchema);
230
+ return validate(schema);
231
+ } catch (error) {
232
+ return false;
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Format validation errors into a consistent structure
238
+ * @private
239
+ * @param {Array} errors - AJV error objects
240
+ * @returns {Array} Formatted errors
241
+ */
242
+ formatErrors(errors) {
243
+ if (!errors) return [];
244
+
245
+ return errors.map(err => ({
246
+ message: err.message || 'Validation error',
247
+ path: err.instancePath || err.dataPath || '',
248
+ keyword: err.keyword,
249
+ params: err.params
250
+ }));
251
+ }
252
+
253
+ /**
254
+ * Clear the schema cache
255
+ * @param {string} lens - Specific lens to clear, or null for all
256
+ */
257
+ clearCache(lens = null) {
258
+ if (lens) {
259
+ this.schemaCache.delete(lens);
260
+ } else {
261
+ this.schemaCache.clear();
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Check if strict mode is enabled
267
+ * @returns {boolean} True if strict mode enabled
268
+ */
269
+ isStrict() {
270
+ return this.strict;
271
+ }
272
+
273
+ /**
274
+ * Enable or disable strict mode
275
+ * @param {boolean} strict - Whether to enable strict mode
276
+ */
277
+ setStrict(strict) {
278
+ this.strict = strict;
279
+ }
280
+ }
281
+
282
+ /**
283
+ * Create a schema validator instance
284
+ * @param {Object} options - Validator options
285
+ * @returns {GunSchemaValidator} Validator instance
286
+ */
287
+ export function createSchemaValidator(options = {}) {
288
+ return new GunSchemaValidator(options);
289
+ }
290
+
291
+ export default GunSchemaValidator;