holosphere 1.1.20 → 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 +483 -367
  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 -980
  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 -33256
  140. package/holosphere-bundle.js +0 -33287
  141. package/holosphere-bundle.min.js +0 -39
  142. package/holosphere.d.ts +0 -601
  143. package/holosphere.js +0 -719
  144. package/node.js +0 -246
  145. package/schema.js +0 -139
  146. package/utils.js +0 -302
@@ -0,0 +1,91 @@
1
+ /**
2
+ * JSON Schema Validation with Ajv and caching
3
+ */
4
+
5
+ import Ajv from 'ajv';
6
+
7
+ const ajv = new Ajv({ allErrors: true, strict: false });
8
+ const schemaCache = new Map();
9
+ const CACHE_TTL = 3600000; // 1 hour in milliseconds
10
+
11
+ /**
12
+ * Validation Error class
13
+ */
14
+ export class ValidationError extends Error {
15
+ constructor(message, errors = []) {
16
+ super(message);
17
+ this.name = 'ValidationError';
18
+ this.errors = errors;
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Compile and cache JSON Schema
24
+ * @param {Object} schema - JSON Schema object
25
+ * @param {string} lensName - Lens identifier for caching
26
+ * @returns {Function} Ajv validator function
27
+ */
28
+ export function compileSchema(schema, lensName) {
29
+ const cacheKey = lensName;
30
+ const cached = schemaCache.get(cacheKey);
31
+
32
+ // Check if cached and not expired
33
+ if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
34
+ return cached.validator;
35
+ }
36
+
37
+ // Compile new validator
38
+ try {
39
+ const validator = ajv.compile(schema);
40
+ schemaCache.set(cacheKey, {
41
+ validator,
42
+ timestamp: Date.now(),
43
+ });
44
+ return validator;
45
+ } catch (error) {
46
+ throw new Error(`Schema compilation failed: ${error.message}`);
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Validate data against schema
52
+ * @param {Object} data - Data to validate
53
+ * @param {Object} schema - JSON Schema object
54
+ * @param {string} lensName - Lens name for caching
55
+ * @param {boolean} strict - Throw error if invalid (default: false)
56
+ * @returns {boolean} True if valid
57
+ * @throws {ValidationError} If strict=true and validation fails
58
+ */
59
+ export function validate(data, schema, lensName, strict = false) {
60
+ const validator = compileSchema(schema, lensName);
61
+ const valid = validator(data);
62
+
63
+ if (!valid) {
64
+ const errors = validator.errors || [];
65
+ const errorMessage = errors.map((e) => `${e.instancePath} ${e.message}`).join('; ');
66
+
67
+ if (strict) {
68
+ throw new ValidationError(`ValidationError: Validation failed: ${errorMessage}`, errors);
69
+ } else {
70
+ console.warn(`[Schema Validation Warning] ${lensName}: ${errorMessage}`);
71
+ return false;
72
+ }
73
+ }
74
+
75
+ return true;
76
+ }
77
+
78
+ /**
79
+ * Clear schema cache for a lens
80
+ * @param {string} lensName - Lens name
81
+ */
82
+ export function clearSchemaCache(lensName) {
83
+ schemaCache.delete(lensName);
84
+ }
85
+
86
+ /**
87
+ * Clear all cached schemas
88
+ */
89
+ export function clearAllCaches() {
90
+ schemaCache.clear();
91
+ }
@@ -0,0 +1,110 @@
1
+ import {
2
+ latLngToCell,
3
+ cellToParent,
4
+ cellToChildren,
5
+ isValidCell,
6
+ getResolution,
7
+ } from 'h3-js';
8
+
9
+ /**
10
+ * Convert geographic coordinates to H3 holon ID
11
+ * @param {number} lat - Latitude (-90 to 90)
12
+ * @param {number} lng - Longitude (-180 to 180)
13
+ * @param {number} resolution - H3 resolution (0-15)
14
+ * @returns {string} H3 cell ID
15
+ */
16
+ export function toHolon(lat, lng, resolution) {
17
+ // Validate inputs
18
+ if (typeof lat !== 'number' || lat < -90 || lat > 90) {
19
+ throw new RangeError(`Invalid latitude: ${lat}. Must be between -90 and 90.`);
20
+ }
21
+ if (typeof lng !== 'number' || lng < -180 || lng > 180) {
22
+ throw new RangeError(`Invalid longitude: ${lng}. Must be between -180 and 180.`);
23
+ }
24
+ if (!Number.isInteger(resolution) || resolution < 0 || resolution > 15) {
25
+ throw new RangeError(`Invalid resolution: ${resolution}. Must be integer between 0 and 15.`);
26
+ }
27
+
28
+ try {
29
+ const h3Index = latLngToCell(lat, lng, resolution);
30
+ return h3Index;
31
+ } catch (error) {
32
+ throw new Error(`H3 conversion failed: ${error.message}`);
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Get all parent holons up the hierarchy
38
+ * @param {string} holonId - H3 cell ID
39
+ * @param {number} maxResolution - Stop at this resolution (default: 0)
40
+ * @returns {string[]} Array of parent H3 IDs (ascending hierarchy)
41
+ */
42
+ export function getParents(holonId, maxResolution = 0) {
43
+ if (!isValidH3(holonId)) {
44
+ throw new Error(`Invalid H3 holon ID: ${holonId}`);
45
+ }
46
+
47
+ const currentResolution = getResolution(holonId);
48
+ const parents = [];
49
+
50
+ let currentCell = holonId;
51
+ for (let res = currentResolution - 1; res >= maxResolution; res--) {
52
+ try {
53
+ currentCell = cellToParent(currentCell, res);
54
+ parents.push(currentCell);
55
+ } catch (error) {
56
+ break; // Reached root
57
+ }
58
+ }
59
+
60
+ return parents;
61
+ }
62
+
63
+ /**
64
+ * Get all child holons at next resolution level
65
+ * @param {string} holonId - H3 cell ID
66
+ * @returns {string[]} Array of child H3 IDs (7 children per hexagon)
67
+ */
68
+ export function getChildren(holonId) {
69
+ if (!isValidH3(holonId)) {
70
+ throw new Error(`Invalid H3 holon ID: ${holonId}`);
71
+ }
72
+
73
+ try {
74
+ const resolution = getResolution(holonId);
75
+ // H3 max resolution is 15, can't get children of resolution 15
76
+ if (resolution >= 15) {
77
+ throw new Error('Cannot get children of resolution 15 cell (maximum resolution)');
78
+ }
79
+
80
+ // cellToChildren requires the child resolution (one level down)
81
+ const children = cellToChildren(holonId, resolution + 1);
82
+ return children;
83
+ } catch (error) {
84
+ throw new Error(`Failed to get children: ${error.message}`);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Validate H3 cell ID format
90
+ * @param {string} holonId - H3 cell ID
91
+ * @returns {boolean} True if valid H3 format
92
+ */
93
+ export function isValidH3(holonId) {
94
+ if (typeof holonId !== 'string') return false;
95
+ if (holonId.length < 15) return false;
96
+ if (!holonId.startsWith('8')) return false;
97
+ return isValidCell(holonId);
98
+ }
99
+
100
+ /**
101
+ * Get H3 resolution level from cell ID
102
+ * @param {string} holonId - H3 cell ID
103
+ * @returns {number} Resolution (0-15)
104
+ */
105
+ export function getH3Resolution(holonId) {
106
+ if (!isValidH3(holonId)) {
107
+ throw new Error(`Invalid H3 holon ID: ${holonId}`);
108
+ }
109
+ return getResolution(holonId);
110
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Factory for creating storage backends
3
+ * Supports lazy loading of backend implementations
4
+ */
5
+
6
+ const BACKEND_MODULES = {
7
+ nostr: './backends/nostr-backend.js',
8
+ gundb: './backends/gundb-backend.js',
9
+ activitypub: './backends/activitypub-backend.js',
10
+ };
11
+
12
+ // Cache for loaded backend classes
13
+ const loadedBackends = new Map();
14
+
15
+ /**
16
+ * Factory for creating storage backends
17
+ */
18
+ export class BackendFactory {
19
+ /**
20
+ * Get list of available backend types
21
+ * @returns {string[]} Available backend type names
22
+ */
23
+ static getAvailableBackends() {
24
+ return Object.keys(BACKEND_MODULES);
25
+ }
26
+
27
+ /**
28
+ * Check if a backend type is available
29
+ * @param {string} type - Backend type
30
+ * @returns {boolean} Whether the backend is available
31
+ */
32
+ static isAvailable(type) {
33
+ return type in BACKEND_MODULES;
34
+ }
35
+
36
+ /**
37
+ * Load a backend class dynamically
38
+ * @param {string} type - Backend type
39
+ * @returns {Promise<Class>} Backend class
40
+ */
41
+ static async loadBackend(type) {
42
+ if (loadedBackends.has(type)) {
43
+ return loadedBackends.get(type);
44
+ }
45
+
46
+ const modulePath = BACKEND_MODULES[type];
47
+ if (!modulePath) {
48
+ throw new Error(
49
+ `Unknown backend type: '${type}'. Available backends: ${Object.keys(BACKEND_MODULES).join(', ')}`
50
+ );
51
+ }
52
+
53
+ try {
54
+ const module = await import(modulePath);
55
+ const BackendClass = module.default || module[`${capitalize(type)}Backend`];
56
+
57
+ if (!BackendClass) {
58
+ throw new Error(`Backend module '${type}' does not export a valid backend class`);
59
+ }
60
+
61
+ loadedBackends.set(type, BackendClass);
62
+ return BackendClass;
63
+ } catch (error) {
64
+ if (error.code === 'ERR_MODULE_NOT_FOUND') {
65
+ throw new Error(
66
+ `Backend '${type}' requires additional dependencies. ` +
67
+ `Please install them: ${getDependencyHint(type)}`
68
+ );
69
+ }
70
+ throw error;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Create a storage backend instance
76
+ * @param {string} type - Backend type: 'nostr' | 'gundb' | 'activitypub'
77
+ * @param {Object} config - Backend-specific configuration
78
+ * @returns {Promise<StorageBackend>} Initialized backend
79
+ */
80
+ static async create(type, config) {
81
+ const BackendClass = await this.loadBackend(type);
82
+ const backend = new BackendClass(config);
83
+ await backend.init();
84
+ return backend;
85
+ }
86
+
87
+ /**
88
+ * Register a custom backend
89
+ * @param {string} name - Backend name
90
+ * @param {Class|string} BackendClassOrPath - Backend class or module path
91
+ */
92
+ static register(name, BackendClassOrPath) {
93
+ if (typeof BackendClassOrPath === 'string') {
94
+ BACKEND_MODULES[name] = BackendClassOrPath;
95
+ } else {
96
+ loadedBackends.set(name, BackendClassOrPath);
97
+ BACKEND_MODULES[name] = null; // Mark as registered but not file-based
98
+ }
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Capitalize first letter
104
+ * @param {string} str - String to capitalize
105
+ * @returns {string} Capitalized string
106
+ */
107
+ function capitalize(str) {
108
+ return str.charAt(0).toUpperCase() + str.slice(1);
109
+ }
110
+
111
+ /**
112
+ * Get dependency installation hint for a backend
113
+ * @param {string} type - Backend type
114
+ * @returns {string} Installation hint
115
+ */
116
+ function getDependencyHint(type) {
117
+ const hints = {
118
+ nostr: 'npm install nostr-tools',
119
+ gundb: 'npm install gun',
120
+ activitypub: 'npm install express',
121
+ };
122
+ return hints[type] || 'Check the documentation for required dependencies';
123
+ }
124
+
125
+ export default BackendFactory;
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Abstract Storage Backend Interface
3
+ * All storage backends must implement this interface
4
+ */
5
+ export class StorageBackend {
6
+ constructor(config) {
7
+ if (new.target === StorageBackend) {
8
+ throw new Error('StorageBackend is abstract and cannot be instantiated directly');
9
+ }
10
+ this.config = config;
11
+ this.publicKey = null;
12
+ }
13
+
14
+ /**
15
+ * Initialize the backend
16
+ * @returns {Promise<void>}
17
+ */
18
+ async init() {
19
+ throw new Error('init() must be implemented by subclass');
20
+ }
21
+
22
+ /**
23
+ * Build path from components
24
+ * @param {string} appName - Application namespace
25
+ * @param {string} holonId - Holon identifier (H3 hex or URI)
26
+ * @param {string} lensName - Lens name
27
+ * @param {string} [key] - Optional data key
28
+ * @returns {string} Constructed path
29
+ */
30
+ buildPath(appName, holonId, lensName, key = null) {
31
+ throw new Error('buildPath() must be implemented by subclass');
32
+ }
33
+
34
+ /**
35
+ * Write data to storage
36
+ * @param {string} path - Storage path
37
+ * @param {Object} data - Data to write
38
+ * @param {Object} [options] - Write options
39
+ * @returns {Promise<boolean>} Success indicator
40
+ */
41
+ async write(path, data, options = {}) {
42
+ throw new Error('write() must be implemented by subclass');
43
+ }
44
+
45
+ /**
46
+ * Read data from storage
47
+ * @param {string} path - Storage path
48
+ * @param {Object} [options] - Read options
49
+ * @param {string[]} [options.authors] - Public keys to query
50
+ * @param {boolean} [options.includeAuthor] - Include author in response
51
+ * @returns {Promise<Object|null>} Data or null
52
+ */
53
+ async read(path, options = {}) {
54
+ throw new Error('read() must be implemented by subclass');
55
+ }
56
+
57
+ /**
58
+ * Read all data under a path prefix
59
+ * @param {string} path - Path prefix
60
+ * @param {Object} [options] - Query options
61
+ * @param {boolean} [options.hybrid] - Use hybrid mode (local + remote)
62
+ * @param {string[]} [options.authors] - Public keys to query
63
+ * @returns {Promise<Object[]>} Array of data objects
64
+ */
65
+ async readAll(path, options = {}) {
66
+ throw new Error('readAll() must be implemented by subclass');
67
+ }
68
+
69
+ /**
70
+ * Update data (merge fields)
71
+ * @param {string} path - Storage path
72
+ * @param {Object} updates - Fields to update
73
+ * @returns {Promise<boolean>} Success indicator
74
+ */
75
+ async update(path, updates) {
76
+ throw new Error('update() must be implemented by subclass');
77
+ }
78
+
79
+ /**
80
+ * Delete data at path
81
+ * @param {string} path - Storage path
82
+ * @returns {Promise<boolean>} Success indicator
83
+ */
84
+ async delete(path) {
85
+ throw new Error('delete() must be implemented by subclass');
86
+ }
87
+
88
+ /**
89
+ * Delete all data under path prefix
90
+ * @param {string} path - Path prefix
91
+ * @returns {Promise<Object>} Deletion results { success: boolean, count: number }
92
+ */
93
+ async deleteAll(path) {
94
+ throw new Error('deleteAll() must be implemented by subclass');
95
+ }
96
+
97
+ /**
98
+ * Subscribe to data changes
99
+ * @param {string} path - Path or path prefix
100
+ * @param {Function} callback - Called on changes: (data, key) => void
101
+ * @param {Object} [options] - Subscription options
102
+ * @returns {Promise<Object>} Subscription with unsubscribe() method
103
+ */
104
+ async subscribe(path, callback, options = {}) {
105
+ throw new Error('subscribe() must be implemented by subclass');
106
+ }
107
+
108
+ /**
109
+ * Export all data for migration
110
+ * @param {string} [pathPrefix] - Optional prefix to filter
111
+ * @returns {Promise<Object[]>} Array of exportable records
112
+ */
113
+ async exportData(pathPrefix = '') {
114
+ throw new Error('exportData() must be implemented by subclass');
115
+ }
116
+
117
+ /**
118
+ * Import data from migration
119
+ * @param {Object[]} records - Records to import
120
+ * @param {Object} [options] - Import options
121
+ * @param {boolean} [options.overwrite] - Overwrite existing data
122
+ * @returns {Promise<Object>} Import results { success: number, failed: number, errors: [] }
123
+ */
124
+ async importData(records, options = {}) {
125
+ throw new Error('importData() must be implemented by subclass');
126
+ }
127
+
128
+ /**
129
+ * Close connections and cleanup
130
+ */
131
+ close() {
132
+ throw new Error('close() must be implemented by subclass');
133
+ }
134
+
135
+ /**
136
+ * Get backend status/health
137
+ * @returns {Object} Status information { type, publicKey, connected, ... }
138
+ */
139
+ getStatus() {
140
+ throw new Error('getStatus() must be implemented by subclass');
141
+ }
142
+ }