@brightchain/db 0.20.0

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 (56) hide show
  1. package/README.md +81 -0
  2. package/package.json +18 -0
  3. package/src/__tests__/helpers/mockBlockStore.d.ts +113 -0
  4. package/src/__tests__/helpers/mockBlockStore.js +380 -0
  5. package/src/__tests__/helpers/mockBlockStore.js.map +1 -0
  6. package/src/index.d.ts +31 -0
  7. package/src/index.js +78 -0
  8. package/src/index.js.map +1 -0
  9. package/src/lib/aggregation.d.ts +18 -0
  10. package/src/lib/aggregation.js +407 -0
  11. package/src/lib/aggregation.js.map +1 -0
  12. package/src/lib/cblIndex.d.ts +268 -0
  13. package/src/lib/cblIndex.js +856 -0
  14. package/src/lib/cblIndex.js.map +1 -0
  15. package/src/lib/collection.d.ts +305 -0
  16. package/src/lib/collection.js +991 -0
  17. package/src/lib/collection.js.map +1 -0
  18. package/src/lib/cursor.d.ts +8 -0
  19. package/src/lib/cursor.js +13 -0
  20. package/src/lib/cursor.js.map +1 -0
  21. package/src/lib/database.d.ts +158 -0
  22. package/src/lib/database.js +332 -0
  23. package/src/lib/database.js.map +1 -0
  24. package/src/lib/errors.d.ts +85 -0
  25. package/src/lib/errors.js +103 -0
  26. package/src/lib/errors.js.map +1 -0
  27. package/src/lib/expressMiddleware.d.ts +57 -0
  28. package/src/lib/expressMiddleware.js +488 -0
  29. package/src/lib/expressMiddleware.js.map +1 -0
  30. package/src/lib/headRegistry.d.ts +60 -0
  31. package/src/lib/headRegistry.js +216 -0
  32. package/src/lib/headRegistry.js.map +1 -0
  33. package/src/lib/indexing.d.ts +7 -0
  34. package/src/lib/indexing.js +14 -0
  35. package/src/lib/indexing.js.map +1 -0
  36. package/src/lib/model.d.ts +162 -0
  37. package/src/lib/model.js +260 -0
  38. package/src/lib/model.js.map +1 -0
  39. package/src/lib/pooledStoreAdapter.d.ts +44 -0
  40. package/src/lib/pooledStoreAdapter.js +109 -0
  41. package/src/lib/pooledStoreAdapter.js.map +1 -0
  42. package/src/lib/queryEngine.d.ts +48 -0
  43. package/src/lib/queryEngine.js +461 -0
  44. package/src/lib/queryEngine.js.map +1 -0
  45. package/src/lib/schemaValidation.d.ts +80 -0
  46. package/src/lib/schemaValidation.js +353 -0
  47. package/src/lib/schemaValidation.js.map +1 -0
  48. package/src/lib/transaction.d.ts +7 -0
  49. package/src/lib/transaction.js +12 -0
  50. package/src/lib/transaction.js.map +1 -0
  51. package/src/lib/types.d.ts +360 -0
  52. package/src/lib/types.js +6 -0
  53. package/src/lib/types.js.map +1 -0
  54. package/src/lib/updateEngine.d.ts +7 -0
  55. package/src/lib/updateEngine.js +13 -0
  56. package/src/lib/updateEngine.js.map +1 -0
@@ -0,0 +1,488 @@
1
+ "use strict";
2
+ /**
3
+ * Express middleware/router for BrightChainDb.
4
+ *
5
+ * Provides a REST API for interacting with the document database:
6
+ *
7
+ * GET /:collection - Find documents (query params as filter)
8
+ * GET /:collection/:id - Find document by ID
9
+ * POST /:collection - Insert one document (body = document)
10
+ * POST /:collection/find - Find with rich filter (body = { filter, sort, limit, skip, projection })
11
+ * POST /:collection/aggregate - Aggregation pipeline (body = { pipeline })
12
+ * PUT /:collection/:id - Replace document
13
+ * PATCH /:collection/:id - Update document (body = update operators)
14
+ * DELETE /:collection/:id - Delete document by ID
15
+ * POST /:collection/insertMany - Bulk insert (body = { documents })
16
+ * POST /:collection/updateMany - Bulk update (body = { filter, update })
17
+ * POST /:collection/deleteMany - Bulk delete (body = { filter })
18
+ * POST /:collection/count - Count documents (body = { filter })
19
+ * POST /:collection/distinct - Distinct values (body = { field, filter })
20
+ * POST /:collection/indexes - Create index (body = { spec, options })
21
+ * DELETE /:collection/indexes/:name - Drop index
22
+ * GET /:collection/indexes - List indexes
23
+ * POST /:collection/bulkWrite - Bulk write operations
24
+ * POST /:collection/cursor - Create a server-side cursor
25
+ * GET /cursors/:cursorId - Fetch next batch from cursor
26
+ * DELETE /cursors/:cursorId - Close a cursor
27
+ */
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.createDbRouter = createDbRouter;
30
+ /**
31
+ * Create an Express router that provides REST access to a BrightChainDb instance.
32
+ *
33
+ * @param db - The database instance
34
+ * @param options - Router options
35
+ * @returns Express router
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * import express from 'express';
40
+ * import { BrightChainDb, createDbRouter } from '@brightchain/db';
41
+ *
42
+ * const app = express();
43
+ * app.use(express.json());
44
+ *
45
+ * const db = new BrightChainDb(blockStore);
46
+ * app.use('/api/db', createDbRouter(db));
47
+ * ```
48
+ */
49
+ function createDbRouter(db, options) {
50
+ // Dynamic import to avoid hard dependency on express at module level
51
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
52
+ const express = require('express');
53
+ const router = express.Router();
54
+ const maxResults = options?.maxResults ?? 1000;
55
+ function checkCollection(collectionName, res) {
56
+ if (options?.allowedCollections &&
57
+ !options.allowedCollections.includes(collectionName)) {
58
+ res
59
+ .status(403)
60
+ .json({ error: `Collection "${collectionName}" is not allowed` });
61
+ return false;
62
+ }
63
+ return true;
64
+ }
65
+ /**
66
+ * Extract a route param as a plain string.
67
+ * Express 5 types declare params values as `string | string[]`;
68
+ * for our named `:param` routes the value is always a string.
69
+ */
70
+ function param(req, name) {
71
+ const v = req.params[name];
72
+ return Array.isArray(v) ? v[0] : v;
73
+ }
74
+ // ── Get next batch from cursor ──
75
+ // (Must be before /:collection/:id to avoid matching 'cursors' as a collection)
76
+ router.get('/cursors/:cursorId', async (req, res) => {
77
+ const cursorId = param(req, 'cursorId');
78
+ try {
79
+ const batch = db.getNextBatch(cursorId);
80
+ if (batch === null) {
81
+ res.status(404).json({ error: 'Cursor not found or expired' });
82
+ return;
83
+ }
84
+ const cursor = db.getCursorSession(cursorId);
85
+ const coll = db.collection(cursor.collection);
86
+ const docs = [];
87
+ for (const id of batch) {
88
+ const doc = await coll.findById(id);
89
+ if (doc)
90
+ docs.push(doc);
91
+ }
92
+ res.json({
93
+ cursorId,
94
+ nextBatch: docs,
95
+ hasMore: cursor.position < cursor.documentIds.length,
96
+ });
97
+ }
98
+ catch (err) {
99
+ res.status(500).json({ error: String(err) });
100
+ }
101
+ });
102
+ // ── Close cursor ──
103
+ // (Must be before /:collection/:id to avoid matching 'cursors' as a collection)
104
+ router.delete('/cursors/:cursorId', (req, res) => {
105
+ const cursorId = param(req, 'cursorId');
106
+ const closed = db.closeCursorSession(cursorId);
107
+ if (!closed) {
108
+ res.status(404).json({ error: 'Cursor not found' });
109
+ return;
110
+ }
111
+ res.json({ acknowledged: true });
112
+ });
113
+ // ── List indexes ──
114
+ router.get('/:collection/indexes', (req, res) => {
115
+ const collection = param(req, 'collection');
116
+ if (!checkCollection(collection, res))
117
+ return;
118
+ try {
119
+ const coll = db.collection(collection);
120
+ const indexes = coll.listIndexes();
121
+ res.json({ indexes });
122
+ }
123
+ catch (err) {
124
+ res.status(500).json({ error: String(err) });
125
+ }
126
+ });
127
+ // ── Find by ID ──
128
+ router.get('/:collection/:id', async (req, res) => {
129
+ const collection = param(req, 'collection');
130
+ const id = param(req, 'id');
131
+ if (!checkCollection(collection, res))
132
+ return;
133
+ try {
134
+ const coll = db.collection(collection);
135
+ const doc = await coll.findById(id);
136
+ if (!doc) {
137
+ res.status(404).json({ error: 'Document not found' });
138
+ return;
139
+ }
140
+ res.json(doc);
141
+ }
142
+ catch (err) {
143
+ res.status(500).json({ error: String(err) });
144
+ }
145
+ });
146
+ // ── Find documents (query string filter) ──
147
+ router.get('/:collection', async (req, res) => {
148
+ const collection = param(req, 'collection');
149
+ if (!checkCollection(collection, res))
150
+ return;
151
+ try {
152
+ const coll = db.collection(collection);
153
+ const filter = parseQueryFilter(req.query);
154
+ const docs = await coll.find(filter).limit(maxResults).toArray();
155
+ res.json(docs);
156
+ }
157
+ catch (err) {
158
+ res.status(500).json({ error: String(err) });
159
+ }
160
+ });
161
+ // ── Insert one ──
162
+ router.post('/:collection', async (req, res) => {
163
+ const collection = param(req, 'collection');
164
+ if (!checkCollection(collection, res))
165
+ return;
166
+ try {
167
+ const coll = db.collection(collection);
168
+ const result = await coll.insertOne(req.body);
169
+ res.status(201).json(result);
170
+ }
171
+ catch (err) {
172
+ if (isDuplicateKeyError(err)) {
173
+ res.status(409).json({ error: String(err) });
174
+ return;
175
+ }
176
+ res.status(500).json({ error: String(err) });
177
+ }
178
+ });
179
+ // ── Find with rich filter ──
180
+ router.post('/:collection/find', async (req, res) => {
181
+ const collection = param(req, 'collection');
182
+ if (!checkCollection(collection, res))
183
+ return;
184
+ try {
185
+ const coll = db.collection(collection);
186
+ const { filter, sort, limit, skip, projection } = req.body ?? {};
187
+ let cursor = coll.find(filter ?? {});
188
+ if (sort)
189
+ cursor = cursor.sort(sort);
190
+ if (skip)
191
+ cursor = cursor.skip(skip);
192
+ cursor = cursor.limit(Math.min(limit ?? maxResults, maxResults));
193
+ if (projection)
194
+ cursor = cursor.project(projection);
195
+ const docs = await cursor.toArray();
196
+ res.json(docs);
197
+ }
198
+ catch (err) {
199
+ res.status(500).json({ error: String(err) });
200
+ }
201
+ });
202
+ // ── Aggregation ──
203
+ router.post('/:collection/aggregate', async (req, res) => {
204
+ const collection = param(req, 'collection');
205
+ if (!checkCollection(collection, res))
206
+ return;
207
+ try {
208
+ const coll = db.collection(collection);
209
+ const { pipeline } = req.body ?? {};
210
+ if (!Array.isArray(pipeline)) {
211
+ res.status(400).json({ error: 'pipeline must be an array' });
212
+ return;
213
+ }
214
+ const result = await coll.aggregate(pipeline);
215
+ res.json(result);
216
+ }
217
+ catch (err) {
218
+ res.status(500).json({ error: String(err) });
219
+ }
220
+ });
221
+ // ── Insert many ──
222
+ router.post('/:collection/insertMany', async (req, res) => {
223
+ const collection = param(req, 'collection');
224
+ if (!checkCollection(collection, res))
225
+ return;
226
+ try {
227
+ const coll = db.collection(collection);
228
+ const { documents } = req.body ?? {};
229
+ if (!Array.isArray(documents)) {
230
+ res.status(400).json({ error: 'documents must be an array' });
231
+ return;
232
+ }
233
+ const result = await coll.insertMany(documents);
234
+ res.status(201).json(result);
235
+ }
236
+ catch (err) {
237
+ res.status(500).json({ error: String(err) });
238
+ }
239
+ });
240
+ // ── Update many ──
241
+ router.post('/:collection/updateMany', async (req, res) => {
242
+ const collection = param(req, 'collection');
243
+ if (!checkCollection(collection, res))
244
+ return;
245
+ try {
246
+ const coll = db.collection(collection);
247
+ const { filter, update } = req.body ?? {};
248
+ const result = await coll.updateMany(filter ?? {}, update ?? {});
249
+ res.json(result);
250
+ }
251
+ catch (err) {
252
+ res.status(500).json({ error: String(err) });
253
+ }
254
+ });
255
+ // ── Delete many ──
256
+ router.post('/:collection/deleteMany', async (req, res) => {
257
+ const collection = param(req, 'collection');
258
+ if (!checkCollection(collection, res))
259
+ return;
260
+ try {
261
+ const coll = db.collection(collection);
262
+ const { filter } = req.body ?? {};
263
+ const result = await coll.deleteMany(filter ?? {});
264
+ res.json(result);
265
+ }
266
+ catch (err) {
267
+ res.status(500).json({ error: String(err) });
268
+ }
269
+ });
270
+ // ── Count ──
271
+ router.post('/:collection/count', async (req, res) => {
272
+ const collection = param(req, 'collection');
273
+ if (!checkCollection(collection, res))
274
+ return;
275
+ try {
276
+ const coll = db.collection(collection);
277
+ const { filter } = req.body ?? {};
278
+ const count = await coll.countDocuments(filter ?? {});
279
+ res.json({ count });
280
+ }
281
+ catch (err) {
282
+ res.status(500).json({ error: String(err) });
283
+ }
284
+ });
285
+ // ── Distinct ──
286
+ router.post('/:collection/distinct', async (req, res) => {
287
+ const collection = param(req, 'collection');
288
+ if (!checkCollection(collection, res))
289
+ return;
290
+ try {
291
+ const coll = db.collection(collection);
292
+ const { field, filter } = req.body ?? {};
293
+ if (!field) {
294
+ res.status(400).json({ error: 'field is required' });
295
+ return;
296
+ }
297
+ const values = await coll.distinct(field, filter ?? {});
298
+ res.json({ values });
299
+ }
300
+ catch (err) {
301
+ res.status(500).json({ error: String(err) });
302
+ }
303
+ });
304
+ // ── Create index ──
305
+ router.post('/:collection/indexes', async (req, res) => {
306
+ const collection = param(req, 'collection');
307
+ if (!checkCollection(collection, res))
308
+ return;
309
+ try {
310
+ const coll = db.collection(collection);
311
+ const { spec, options: indexOptions } = req.body ?? {};
312
+ if (!spec || typeof spec !== 'object') {
313
+ res
314
+ .status(400)
315
+ .json({ error: 'spec is required and must be an object' });
316
+ return;
317
+ }
318
+ const name = await coll.createIndex(spec, indexOptions ?? {});
319
+ res.status(201).json({ name });
320
+ }
321
+ catch (err) {
322
+ res.status(500).json({ error: String(err) });
323
+ }
324
+ });
325
+ // ── Drop index ──
326
+ router.delete('/:collection/indexes/:name', async (req, res) => {
327
+ const collection = param(req, 'collection');
328
+ const name = param(req, 'name');
329
+ if (!checkCollection(collection, res))
330
+ return;
331
+ try {
332
+ const coll = db.collection(collection);
333
+ await coll.dropIndex(name);
334
+ res.json({ acknowledged: true });
335
+ }
336
+ catch (err) {
337
+ res.status(500).json({ error: String(err) });
338
+ }
339
+ });
340
+ // ── Replace document ──
341
+ router.put('/:collection/:id', async (req, res) => {
342
+ const collection = param(req, 'collection');
343
+ const id = param(req, 'id');
344
+ if (!checkCollection(collection, res))
345
+ return;
346
+ try {
347
+ const coll = db.collection(collection);
348
+ const result = await coll.replaceOne({ _id: id }, req.body);
349
+ if (result.matchedCount === 0) {
350
+ res.status(404).json({ error: 'Document not found' });
351
+ return;
352
+ }
353
+ res.json(result);
354
+ }
355
+ catch (err) {
356
+ res.status(500).json({ error: String(err) });
357
+ }
358
+ });
359
+ // ── Update document ──
360
+ router.patch('/:collection/:id', async (req, res) => {
361
+ const collection = param(req, 'collection');
362
+ const id = param(req, 'id');
363
+ if (!checkCollection(collection, res))
364
+ return;
365
+ try {
366
+ const coll = db.collection(collection);
367
+ const result = await coll.updateOne({ _id: id }, req.body);
368
+ if (result.matchedCount === 0) {
369
+ res.status(404).json({ error: 'Document not found' });
370
+ return;
371
+ }
372
+ res.json(result);
373
+ }
374
+ catch (err) {
375
+ res.status(500).json({ error: String(err) });
376
+ }
377
+ });
378
+ // ── Delete document ──
379
+ router.delete('/:collection/:id', async (req, res) => {
380
+ const collection = param(req, 'collection');
381
+ const id = param(req, 'id');
382
+ if (!checkCollection(collection, res))
383
+ return;
384
+ try {
385
+ const coll = db.collection(collection);
386
+ const result = await coll.deleteOne({ _id: id });
387
+ if (result.deletedCount === 0) {
388
+ res.status(404).json({ error: 'Document not found' });
389
+ return;
390
+ }
391
+ res.json(result);
392
+ }
393
+ catch (err) {
394
+ res.status(500).json({ error: String(err) });
395
+ }
396
+ });
397
+ // ── Bulk write ──
398
+ router.post('/:collection/bulkWrite', async (req, res) => {
399
+ const collection = param(req, 'collection');
400
+ if (!checkCollection(collection, res))
401
+ return;
402
+ try {
403
+ const coll = db.collection(collection);
404
+ const { operations, ordered } = req.body ?? {};
405
+ if (!Array.isArray(operations)) {
406
+ res.status(400).json({ error: 'operations must be an array' });
407
+ return;
408
+ }
409
+ const result = await coll.bulkWrite(operations, {
410
+ ordered: ordered ?? true,
411
+ });
412
+ res.json(result);
413
+ }
414
+ catch (err) {
415
+ if (err instanceof Error && err.name === 'BulkWriteError') {
416
+ res.status(400).json({
417
+ error: String(err),
418
+ details: err['writeErrors'],
419
+ });
420
+ return;
421
+ }
422
+ res.status(500).json({ error: String(err) });
423
+ }
424
+ });
425
+ // ── Create server-side cursor ──
426
+ router.post('/:collection/cursor', async (req, res) => {
427
+ const collection = param(req, 'collection');
428
+ if (!checkCollection(collection, res))
429
+ return;
430
+ try {
431
+ const coll = db.collection(collection);
432
+ const { filter, sort, projection, batchSize } = req.body ?? {};
433
+ const docs = await coll
434
+ .find(filter ?? {}, { sort, projection })
435
+ .toArray();
436
+ const docIds = docs.map((d) => d['_id']).filter(Boolean);
437
+ const cursor = db.createCursorSession({
438
+ collection,
439
+ documentIds: docIds,
440
+ position: 0,
441
+ batchSize: Math.min(batchSize ?? 100, maxResults),
442
+ filter: filter ?? {},
443
+ sort,
444
+ projection,
445
+ });
446
+ // Return first batch
447
+ const firstBatch = docIds.slice(0, cursor.batchSize);
448
+ const batchDocs = [];
449
+ for (const id of firstBatch) {
450
+ const doc = await coll.findById(id);
451
+ if (doc)
452
+ batchDocs.push(doc);
453
+ }
454
+ cursor.position = firstBatch.length;
455
+ res.status(201).json({
456
+ cursorId: cursor.id,
457
+ firstBatch: batchDocs,
458
+ hasMore: cursor.position < docIds.length,
459
+ });
460
+ }
461
+ catch (err) {
462
+ res.status(500).json({ error: String(err) });
463
+ }
464
+ });
465
+ return router;
466
+ }
467
+ // ── Helpers ──
468
+ function parseQueryFilter(query) {
469
+ const filter = {};
470
+ for (const [key, value] of Object.entries(query)) {
471
+ // Skip reserved query params
472
+ if (['limit', 'skip', 'sort', 'projection'].includes(key))
473
+ continue;
474
+ // Try to parse JSON values
475
+ try {
476
+ filter[key] = JSON.parse(value);
477
+ }
478
+ catch {
479
+ filter[key] = value;
480
+ }
481
+ }
482
+ return filter;
483
+ }
484
+ function isDuplicateKeyError(err) {
485
+ return (err instanceof Error &&
486
+ (err.name === 'DuplicateKeyError' || err.message.includes('E11000')));
487
+ }
488
+ //# sourceMappingURL=expressMiddleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expressMiddleware.js","sourceRoot":"","sources":["../../../../brightchain-db/src/lib/expressMiddleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { DeferredHeadUpdate, IHeadRegistry } from '@brightchain/brightchain-lib';
2
+ export { InMemoryHeadRegistry } from '@brightchain/brightchain-lib/lib/db/inMemoryHeadRegistry';
3
+ /**
4
+ * Options for creating a PersistentHeadRegistry.
5
+ */
6
+ export interface HeadRegistryOptions {
7
+ /** Path to the directory where the registry file is stored */
8
+ dataDir: string;
9
+ /** File name for the registry (default: 'head-registry.json') */
10
+ fileName?: string;
11
+ }
12
+ /**
13
+ * Persistent HeadRegistry that writes through to a JSON file on disk.
14
+ *
15
+ * The in-memory Map is the primary read path; disk is the persistence layer.
16
+ * Every mutation (setHead, removeHead, clear) writes the full JSON to disk
17
+ * before returning, ensuring durability across process restarts.
18
+ *
19
+ * File-level locking via `fs.open` with exclusive create prevents concurrent
20
+ * write corruption when multiple processes share the same data directory.
21
+ *
22
+ * If the persisted file is missing or corrupt on load(), the registry starts
23
+ * empty and logs a warning rather than crashing.
24
+ */
25
+ export declare class PersistentHeadRegistry implements IHeadRegistry {
26
+ private readonly heads;
27
+ private readonly timestamps;
28
+ private readonly deferred;
29
+ private readonly filePath;
30
+ private readonly lockPath;
31
+ constructor(options: HeadRegistryOptions);
32
+ private makeKey;
33
+ getHead(dbName: string, collectionName: string): string | undefined;
34
+ setHead(dbName: string, collectionName: string, blockId: string): Promise<void>;
35
+ removeHead(dbName: string, collectionName: string): Promise<void>;
36
+ clear(): Promise<void>;
37
+ load(): Promise<void>;
38
+ getAllHeads(): Map<string, string>;
39
+ getHeadTimestamp(dbName: string, collectionName: string): Date | undefined;
40
+ mergeHeadUpdate(dbName: string, collectionName: string, blockId: string, timestamp: Date): Promise<boolean>;
41
+ deferHeadUpdate(dbName: string, collectionName: string, blockId: string, timestamp: Date): Promise<void>;
42
+ applyDeferredUpdates(blockId: string): Promise<number>;
43
+ getDeferredUpdates(): DeferredHeadUpdate[];
44
+ /**
45
+ * Write the current in-memory state to disk with file-level locking.
46
+ *
47
+ * Locking strategy: create a `.lock` file with exclusive flag (`wx`).
48
+ * If the lock file already exists, retry with a short delay.
49
+ * The lock file is always removed after writing, even on error.
50
+ */
51
+ private writeToDisk;
52
+ private acquireLock;
53
+ private releaseLock;
54
+ private delay;
55
+ /**
56
+ * Factory method that creates a PersistentHeadRegistry for the given directory.
57
+ * Useful for tests that need an isolated persistent registry.
58
+ */
59
+ static create(options: HeadRegistryOptions): PersistentHeadRegistry;
60
+ }