updates types for orbit and bug fixes, and sanitiza data on document prepare
This commit is contained in:
parent
d39b3c7003
commit
44d19ad628
@ -1,126 +0,0 @@
|
|||||||
// Example of how to integrate the new @debros/node-core package into an application
|
|
||||||
|
|
||||||
import express from 'express';
|
|
||||||
import { initIpfs, initOrbitDB, createServiceLogger, getConnectedPeers } from '@debros/node-core'; // This would be the import path when installed from npm
|
|
||||||
|
|
||||||
// Create service-specific loggers
|
|
||||||
const apiLogger = createServiceLogger('API');
|
|
||||||
const networkLogger = createServiceLogger('NETWORK');
|
|
||||||
|
|
||||||
// Initialize Express app
|
|
||||||
const app = express();
|
|
||||||
app.use(express.json());
|
|
||||||
|
|
||||||
// Network state
|
|
||||||
let ipfsNode: any;
|
|
||||||
let orbitInstance: any;
|
|
||||||
let messageDB: any;
|
|
||||||
|
|
||||||
// Initialize network components
|
|
||||||
async function initializeNetwork() {
|
|
||||||
try {
|
|
||||||
// Initialize IPFS
|
|
||||||
networkLogger.info('Initializing IPFS node...');
|
|
||||||
ipfsNode = await initIpfs();
|
|
||||||
|
|
||||||
// Initialize OrbitDB
|
|
||||||
networkLogger.info('Initializing OrbitDB...');
|
|
||||||
orbitInstance = await initOrbitDB({
|
|
||||||
getHelia: () => ipfsNode,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Open message database
|
|
||||||
messageDB = await orbitInstance.open('messages', {
|
|
||||||
type: 'feed',
|
|
||||||
});
|
|
||||||
|
|
||||||
networkLogger.info('Network components initialized successfully');
|
|
||||||
|
|
||||||
// Log connected peers every minute
|
|
||||||
setInterval(() => {
|
|
||||||
const peers = getConnectedPeers();
|
|
||||||
networkLogger.info(`Connected to ${peers.size} peers`);
|
|
||||||
}, 60000);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
networkLogger.error('Failed to initialize network:', error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// API routes
|
|
||||||
app.get('/api/peers', (req, res) => {
|
|
||||||
const peers = getConnectedPeers();
|
|
||||||
const peerList: any[] = [];
|
|
||||||
|
|
||||||
peers.forEach((data, peerId) => {
|
|
||||||
peerList.push({
|
|
||||||
id: peerId,
|
|
||||||
load: data.load,
|
|
||||||
address: data.publicAddress,
|
|
||||||
lastSeen: data.lastSeen,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
res.json({ peers: peerList });
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/api/messages', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const messages = messageDB.iterator({ limit: 100 }).collect();
|
|
||||||
res.json({ messages });
|
|
||||||
} catch (error) {
|
|
||||||
apiLogger.error('Error fetching messages:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to fetch messages' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/api/messages', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const { content } = req.body;
|
|
||||||
if (!content) {
|
|
||||||
return res.status(400).json({ error: 'Content is required' });
|
|
||||||
}
|
|
||||||
|
|
||||||
const entry = await messageDB.add({
|
|
||||||
content,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
});
|
|
||||||
|
|
||||||
res.status(201).json({ id: entry });
|
|
||||||
} catch (error) {
|
|
||||||
apiLogger.error('Error creating message:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to create message' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Start the application
|
|
||||||
async function startApp() {
|
|
||||||
const networkInitialized = await initializeNetwork();
|
|
||||||
|
|
||||||
if (networkInitialized) {
|
|
||||||
const port = config.env.port;
|
|
||||||
app.listen(port, () => {
|
|
||||||
apiLogger.info(`Server listening on port ${port}`);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
apiLogger.error('Cannot start application: Network initialization failed');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shutdown handler
|
|
||||||
process.on('SIGINT', async () => {
|
|
||||||
networkLogger.info('Application shutting down...');
|
|
||||||
if (orbitInstance) {
|
|
||||||
await orbitInstance.stop();
|
|
||||||
}
|
|
||||||
if (ipfsNode) {
|
|
||||||
await initIpfs.stop();
|
|
||||||
}
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Start the application
|
|
||||||
startApp();
|
|
2
orbitdb.d.ts
vendored
2
orbitdb.d.ts
vendored
@ -1,7 +1,7 @@
|
|||||||
// custom.d.ts
|
// custom.d.ts
|
||||||
declare module '@orbitdb/core' {
|
declare module '@orbitdb/core' {
|
||||||
// Import the types from @constl/orbit-db-types
|
// Import the types from @constl/orbit-db-types
|
||||||
import { OrbitDBTypes } from '@constl/orbit-db-types';
|
import { OrbitDBTypes } from '@orbitdb/core-types';
|
||||||
|
|
||||||
// Assuming @orbitdb/core exports an interface or type you want to override
|
// Assuming @orbitdb/core exports an interface or type you want to override
|
||||||
// Replace 'OrbitDB' with the actual export name from @orbitdb/core you want to type
|
// Replace 'OrbitDB' with the actual export name from @orbitdb/core you want to type
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@debros/network",
|
"name": "@debros/network",
|
||||||
"version": "0.0.16-alpha",
|
"version": "0.0.17-alpha",
|
||||||
"description": "Debros network core functionality for IPFS, libp2p and OrbitDB",
|
"description": "Debros network core functionality for IPFS, libp2p and OrbitDB",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
@ -59,7 +59,6 @@
|
|||||||
"typescript": ">=5.0.0"
|
"typescript": ">=5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@constl/orbit-db-types": "^2.0.6",
|
|
||||||
"@eslint/js": "^9.24.0",
|
"@eslint/js": "^9.24.0",
|
||||||
"@orbitdb/core-types": "^1.0.14",
|
"@orbitdb/core-types": "^1.0.14",
|
||||||
"@types/express": "^5.0.1",
|
"@types/express": "^5.0.1",
|
||||||
@ -70,12 +69,14 @@
|
|||||||
"eslint": "^9.24.0",
|
"eslint": "^9.24.0",
|
||||||
"eslint-config-prettier": "^10.1.1",
|
"eslint-config-prettier": "^10.1.1",
|
||||||
"eslint-plugin-prettier": "^5.2.6",
|
"eslint-plugin-prettier": "^5.2.6",
|
||||||
|
"globals": "^16.0.0",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"lint-staged": "^15.5.0",
|
"lint-staged": "^15.5.0",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"tsc-esm-fix": "^3.1.2",
|
"tsc-esm-fix": "^3.1.2",
|
||||||
"typescript": "^5.8.2"
|
"typescript": "^5.8.2",
|
||||||
|
"typescript-eslint": "^8.29.0"
|
||||||
},
|
},
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
|
37
pnpm-lock.yaml
generated
37
pnpm-lock.yaml
generated
@ -78,9 +78,6 @@ importers:
|
|||||||
specifier: ^3.17.0
|
specifier: ^3.17.0
|
||||||
version: 3.17.0
|
version: 3.17.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@constl/orbit-db-types':
|
|
||||||
specifier: ^2.0.6
|
|
||||||
version: 2.0.6
|
|
||||||
'@eslint/js':
|
'@eslint/js':
|
||||||
specifier: ^9.24.0
|
specifier: ^9.24.0
|
||||||
version: 9.24.0
|
version: 9.24.0
|
||||||
@ -111,6 +108,9 @@ importers:
|
|||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^5.2.6
|
specifier: ^5.2.6
|
||||||
version: 5.2.6(eslint-config-prettier@10.1.1(eslint@9.24.0))(eslint@9.24.0)(prettier@3.5.3)
|
version: 5.2.6(eslint-config-prettier@10.1.1(eslint@9.24.0))(eslint@9.24.0)(prettier@3.5.3)
|
||||||
|
globals:
|
||||||
|
specifier: ^16.0.0
|
||||||
|
version: 16.0.0
|
||||||
husky:
|
husky:
|
||||||
specifier: ^8.0.3
|
specifier: ^8.0.3
|
||||||
version: 8.0.3
|
version: 8.0.3
|
||||||
@ -129,6 +129,9 @@ importers:
|
|||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.8.2
|
specifier: ^5.8.2
|
||||||
version: 5.8.2
|
version: 5.8.2
|
||||||
|
typescript-eslint:
|
||||||
|
specifier: ^8.29.0
|
||||||
|
version: 8.29.0(eslint@9.24.0)(typescript@5.8.2)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@ -827,9 +830,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
|
resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
|
||||||
engines: {node: '>=0.1.90'}
|
engines: {node: '>=0.1.90'}
|
||||||
|
|
||||||
'@constl/orbit-db-types@2.0.6':
|
|
||||||
resolution: {integrity: sha512-p23e3tEr9izE9zskwqdN66VhFWYrbhxTvJNalhWqKkXnSV/58gbtc+yFobLPClKEDNKtYAhYhO6spLiI+VpZEg==}
|
|
||||||
|
|
||||||
'@dabh/diagnostics@2.0.3':
|
'@dabh/diagnostics@2.0.3':
|
||||||
resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
|
resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
|
||||||
|
|
||||||
@ -2251,6 +2251,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
|
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
globals@16.0.0:
|
||||||
|
resolution: {integrity: sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
gopd@1.2.0:
|
gopd@1.2.0:
|
||||||
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -3750,6 +3754,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
|
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
typescript-eslint@8.29.0:
|
||||||
|
resolution: {integrity: sha512-ep9rVd9B4kQsZ7ZnWCVxUE/xDLUUUsRzE0poAeNu+4CkFErLfuvPt/qtm2EpnSyfvsR0S6QzDFSrPCFBwf64fg==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: ^8.57.0 || ^9.0.0
|
||||||
|
typescript: '>=4.8.4 <5.9.0'
|
||||||
|
|
||||||
typescript@5.8.2:
|
typescript@5.8.2:
|
||||||
resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
|
resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
|
||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
@ -4862,8 +4873,6 @@ snapshots:
|
|||||||
|
|
||||||
'@colors/colors@1.6.0': {}
|
'@colors/colors@1.6.0': {}
|
||||||
|
|
||||||
'@constl/orbit-db-types@2.0.6': {}
|
|
||||||
|
|
||||||
'@dabh/diagnostics@2.0.3':
|
'@dabh/diagnostics@2.0.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
colorspace: 1.1.4
|
colorspace: 1.1.4
|
||||||
@ -7077,6 +7086,8 @@ snapshots:
|
|||||||
|
|
||||||
globals@14.0.0: {}
|
globals@14.0.0: {}
|
||||||
|
|
||||||
|
globals@16.0.0: {}
|
||||||
|
|
||||||
gopd@1.2.0: {}
|
gopd@1.2.0: {}
|
||||||
|
|
||||||
graceful-fs@4.2.11: {}
|
graceful-fs@4.2.11: {}
|
||||||
@ -8846,6 +8857,16 @@ snapshots:
|
|||||||
media-typer: 1.1.0
|
media-typer: 1.1.0
|
||||||
mime-types: 3.0.1
|
mime-types: 3.0.1
|
||||||
|
|
||||||
|
typescript-eslint@8.29.0(eslint@9.24.0)(typescript@5.8.2):
|
||||||
|
dependencies:
|
||||||
|
'@typescript-eslint/eslint-plugin': 8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.24.0)(typescript@5.8.2))(eslint@9.24.0)(typescript@5.8.2)
|
||||||
|
'@typescript-eslint/parser': 8.29.0(eslint@9.24.0)(typescript@5.8.2)
|
||||||
|
'@typescript-eslint/utils': 8.29.0(eslint@9.24.0)(typescript@5.8.2)
|
||||||
|
eslint: 9.24.0
|
||||||
|
typescript: 5.8.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
typescript@5.8.2: {}
|
typescript@5.8.2: {}
|
||||||
|
|
||||||
uint8-varint@2.0.4:
|
uint8-varint@2.0.4:
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
import { createServiceLogger } from '../../utils/logger';
|
import { createServiceLogger } from '../../utils/logger';
|
||||||
import { openDB } from '../../orbit/orbitDBService';
|
import { openDB } from '../../orbit/orbitDBService';
|
||||||
import { getConnection } from '../core/connection';
|
import { getConnection } from '../core/connection';
|
||||||
import * as cache from '../cache/cacheService';
|
|
||||||
import * as events from '../events/eventService';
|
|
||||||
import { validateDocument } from '../schema/validator';
|
import { validateDocument } from '../schema/validator';
|
||||||
import { measurePerformance } from '../metrics/metricsService';
|
import {
|
||||||
import { ErrorCode, StoreType, StoreOptions, CreateResult, UpdateResult, PaginatedResult, QueryOptions, ListOptions } from '../types';
|
ErrorCode,
|
||||||
|
StoreType,
|
||||||
|
StoreOptions,
|
||||||
|
CreateResult,
|
||||||
|
UpdateResult,
|
||||||
|
PaginatedResult,
|
||||||
|
QueryOptions,
|
||||||
|
ListOptions,
|
||||||
|
} from '../types';
|
||||||
import { DBError } from '../core/error';
|
import { DBError } from '../core/error';
|
||||||
|
|
||||||
const logger = createServiceLogger('DB_STORE');
|
const logger = createServiceLogger('DB_STORE');
|
||||||
@ -18,65 +24,57 @@ export interface BaseStore {
|
|||||||
* Create a new document
|
* Create a new document
|
||||||
*/
|
*/
|
||||||
create<T extends Record<string, any>>(
|
create<T extends Record<string, any>>(
|
||||||
collection: string,
|
collection: string,
|
||||||
id: string,
|
id: string,
|
||||||
data: Omit<T, 'createdAt' | 'updatedAt'>,
|
data: Omit<T, 'createdAt' | 'updatedAt'>,
|
||||||
options?: StoreOptions
|
options?: StoreOptions,
|
||||||
): Promise<CreateResult>;
|
): Promise<CreateResult>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a document by ID
|
* Get a document by ID
|
||||||
*/
|
*/
|
||||||
get<T extends Record<string, any>>(
|
get<T extends Record<string, any>>(
|
||||||
collection: string,
|
collection: string,
|
||||||
id: string,
|
id: string,
|
||||||
options?: StoreOptions & { skipCache?: boolean }
|
options?: StoreOptions & { skipCache?: boolean },
|
||||||
): Promise<T | null>;
|
): Promise<T | null>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a document
|
* Update a document
|
||||||
*/
|
*/
|
||||||
update<T extends Record<string, any>>(
|
update<T extends Record<string, any>>(
|
||||||
collection: string,
|
collection: string,
|
||||||
id: string,
|
id: string,
|
||||||
data: Partial<Omit<T, 'createdAt' | 'updatedAt'>>,
|
data: Partial<Omit<T, 'createdAt' | 'updatedAt'>>,
|
||||||
options?: StoreOptions & { upsert?: boolean }
|
options?: StoreOptions & { upsert?: boolean },
|
||||||
): Promise<UpdateResult>;
|
): Promise<UpdateResult>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a document
|
* Delete a document
|
||||||
*/
|
*/
|
||||||
remove(
|
remove(collection: string, id: string, options?: StoreOptions): Promise<boolean>;
|
||||||
collection: string,
|
|
||||||
id: string,
|
|
||||||
options?: StoreOptions
|
|
||||||
): Promise<boolean>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List all documents in a collection with pagination
|
* List all documents in a collection with pagination
|
||||||
*/
|
*/
|
||||||
list<T extends Record<string, any>>(
|
list<T extends Record<string, any>>(
|
||||||
collection: string,
|
collection: string,
|
||||||
options?: ListOptions
|
options?: ListOptions,
|
||||||
): Promise<PaginatedResult<T>>;
|
): Promise<PaginatedResult<T>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query documents in a collection with filtering and pagination
|
* Query documents in a collection with filtering and pagination
|
||||||
*/
|
*/
|
||||||
query<T extends Record<string, any>>(
|
query<T extends Record<string, any>>(
|
||||||
collection: string,
|
collection: string,
|
||||||
filter: (doc: T) => boolean,
|
filter: (doc: T) => boolean,
|
||||||
options?: QueryOptions
|
options?: QueryOptions,
|
||||||
): Promise<PaginatedResult<T>>;
|
): Promise<PaginatedResult<T>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an index for a collection to speed up queries
|
* Create an index for a collection to speed up queries
|
||||||
*/
|
*/
|
||||||
createIndex(
|
createIndex(collection: string, field: string, options?: StoreOptions): Promise<boolean>;
|
||||||
collection: string,
|
|
||||||
field: string,
|
|
||||||
options?: StoreOptions
|
|
||||||
): Promise<boolean>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,14 +83,21 @@ export interface BaseStore {
|
|||||||
export async function openStore(
|
export async function openStore(
|
||||||
collection: string,
|
collection: string,
|
||||||
storeType: StoreType,
|
storeType: StoreType,
|
||||||
options?: StoreOptions
|
options?: StoreOptions,
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const connection = getConnection(options?.connectionId);
|
const connection = getConnection(options?.connectionId);
|
||||||
return await openDB(collection, storeType);
|
logger.info(`Connection for ${collection}:`, connection);
|
||||||
|
return await openDB(collection, storeType).catch((err) => {
|
||||||
|
throw new Error(`OrbitDB openDB failed: ${err.message}`);
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Error opening ${storeType} store for collection ${collection}:`, error);
|
logger.error(`Error opening ${storeType} store for collection ${collection}:`, error);
|
||||||
throw new DBError(ErrorCode.OPERATION_FAILED, `Failed to open ${storeType} store for collection ${collection}`, error);
|
throw new DBError(
|
||||||
|
ErrorCode.OPERATION_FAILED,
|
||||||
|
`Failed to open ${storeType} store for collection ${collection}`,
|
||||||
|
error,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,31 +107,36 @@ export async function openStore(
|
|||||||
export function prepareDocument<T extends Record<string, any>>(
|
export function prepareDocument<T extends Record<string, any>>(
|
||||||
collection: string,
|
collection: string,
|
||||||
data: Omit<T, 'createdAt' | 'updatedAt'>,
|
data: Omit<T, 'createdAt' | 'updatedAt'>,
|
||||||
existingDoc?: T | null
|
existingDoc?: T | null,
|
||||||
): T {
|
): T {
|
||||||
const timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
|
|
||||||
|
// Sanitize the input data by replacing undefined with null
|
||||||
|
const sanitizedData = Object.fromEntries(
|
||||||
|
Object.entries(data).map(([key, value]) => [key, value === undefined ? null : value]),
|
||||||
|
) as Omit<T, 'createdAt' | 'updatedAt'>;
|
||||||
|
|
||||||
// If it's an update to an existing document
|
// If it's an update to an existing document
|
||||||
if (existingDoc) {
|
if (existingDoc) {
|
||||||
const doc = {
|
const doc = {
|
||||||
...existingDoc,
|
...existingDoc,
|
||||||
...data,
|
...sanitizedData,
|
||||||
updatedAt: timestamp
|
updatedAt: timestamp,
|
||||||
} as T;
|
} as T;
|
||||||
|
|
||||||
// Validate the document against its schema
|
// Validate the document against its schema
|
||||||
validateDocument(collection, doc);
|
validateDocument(collection, doc);
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise it's a new document
|
// Otherwise it's a new document
|
||||||
const doc = {
|
const doc = {
|
||||||
...data,
|
...sanitizedData,
|
||||||
createdAt: timestamp,
|
createdAt: timestamp,
|
||||||
updatedAt: timestamp
|
updatedAt: timestamp,
|
||||||
} as unknown as T;
|
} as unknown as T;
|
||||||
|
|
||||||
// Validate the document against its schema
|
// Validate the document against its schema
|
||||||
validateDocument(collection, doc);
|
validateDocument(collection, doc);
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ export const openDB = async (name: string, type: string) => {
|
|||||||
const dbOptions = {
|
const dbOptions = {
|
||||||
type,
|
type,
|
||||||
overwrite: false,
|
overwrite: false,
|
||||||
AccessController: IPFSAccessController({ write: ['*'], storage: getHelia() }),
|
AccessController: IPFSAccessController({ write: ['*'] }),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (existingAddress) {
|
if (existingAddress) {
|
||||||
|
Reference in New Issue
Block a user