@kb-labs/adapters 0.5.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.
- package/.cursorrules +32 -0
- package/.github/workflows/ci.yml +13 -0
- package/.github/workflows/deploy.yml +28 -0
- package/.github/workflows/docker-build.yml +25 -0
- package/.github/workflows/drift-check.yml +10 -0
- package/.github/workflows/profiles-validate.yml +16 -0
- package/.github/workflows/release.yml +8 -0
- package/.kb/devkit/agents/devkit-maintainer/context.globs +15 -0
- package/.kb/devkit/agents/devkit-maintainer/permissions.yml +17 -0
- package/.kb/devkit/agents/devkit-maintainer/prompt.md +28 -0
- package/.kb/devkit/agents/devkit-maintainer/runbook.md +31 -0
- package/.kb/devkit/agents/docs-crafter/prompt.md +24 -0
- package/.kb/devkit/agents/docs-crafter/runbook.md +18 -0
- package/.kb/devkit/agents/release-manager/context.globs +7 -0
- package/.kb/devkit/agents/release-manager/prompt.md +27 -0
- package/.kb/devkit/agents/release-manager/runbook.md +17 -0
- package/.kb/devkit/agents/test-generator/context.globs +7 -0
- package/.kb/devkit/agents/test-generator/prompt.md +27 -0
- package/.kb/devkit/agents/test-generator/runbook.md +18 -0
- package/CONTRIBUTING.md +90 -0
- package/IMPLEMENTATION_COMPLETE.md +416 -0
- package/LICENSE +186 -0
- package/README-TEMPLATE.md +179 -0
- package/README.md +306 -0
- package/docs/DOCUMENTATION.md +74 -0
- package/docs/adr/0000-template.md +49 -0
- package/docs/adr/0001-architecture-and-repository-layout.md +33 -0
- package/docs/adr/0002-plugins-and-extensibility.md +46 -0
- package/docs/adr/0003-package-and-module-boundaries.md +37 -0
- package/docs/adr/0004-versioning-and-release-policy.md +38 -0
- package/docs/adr/0005-use-devkit-for-shared-tooling.md +48 -0
- package/docs/adr/0006-adopt-devkit-sync.md +47 -0
- package/docs/adr/0007-drift-kit-check.md +72 -0
- package/docs/adr/0008-devkit-sync-wrapper-strategy.md +67 -0
- package/docs/naming-convention.md +272 -0
- package/eslint.config.js +27 -0
- package/kb-labs.config.json +5 -0
- package/package.json +84 -0
- package/package.json.bin +25 -0
- package/package.json.lib +30 -0
- package/packages/adapters-analytics-duckdb/package.json +54 -0
- package/packages/adapters-analytics-duckdb/scripts/migrate-from-jsonl.mjs +253 -0
- package/packages/adapters-analytics-duckdb/src/index.ts +380 -0
- package/packages/adapters-analytics-duckdb/src/manifest.ts +36 -0
- package/packages/adapters-analytics-duckdb/src/schema.ts +161 -0
- package/packages/adapters-analytics-duckdb/tsconfig.build.json +15 -0
- package/packages/adapters-analytics-duckdb/tsconfig.json +9 -0
- package/packages/adapters-analytics-duckdb/tsup.config.ts +9 -0
- package/packages/adapters-analytics-file/README.md +32 -0
- package/packages/adapters-analytics-file/eslint.config.js +27 -0
- package/packages/adapters-analytics-file/package.json +50 -0
- package/packages/adapters-analytics-file/src/__tests__/daily-stats.spec.ts +287 -0
- package/packages/adapters-analytics-file/src/__tests__/scoped-analytics.test.ts +233 -0
- package/packages/adapters-analytics-file/src/index.test.ts +214 -0
- package/packages/adapters-analytics-file/src/index.ts +830 -0
- package/packages/adapters-analytics-file/src/manifest.ts +45 -0
- package/packages/adapters-analytics-file/tsconfig.build.json +15 -0
- package/packages/adapters-analytics-file/tsconfig.json +9 -0
- package/packages/adapters-analytics-file/tsup.config.ts +9 -0
- package/packages/adapters-analytics-sqlite/package.json +55 -0
- package/packages/adapters-analytics-sqlite/scripts/migrate-from-jsonl.mjs +194 -0
- package/packages/adapters-analytics-sqlite/src/index.ts +460 -0
- package/packages/adapters-analytics-sqlite/src/manifest.ts +41 -0
- package/packages/adapters-analytics-sqlite/tsconfig.build.json +15 -0
- package/packages/adapters-analytics-sqlite/tsconfig.json +9 -0
- package/packages/adapters-analytics-sqlite/tsup.config.ts +9 -0
- package/packages/adapters-environment-docker/README.md +28 -0
- package/packages/adapters-environment-docker/eslint.config.js +5 -0
- package/packages/adapters-environment-docker/package.json +49 -0
- package/packages/adapters-environment-docker/src/index.test.ts +138 -0
- package/packages/adapters-environment-docker/src/index.ts +439 -0
- package/packages/adapters-environment-docker/src/manifest.ts +65 -0
- package/packages/adapters-environment-docker/tsconfig.build.json +15 -0
- package/packages/adapters-environment-docker/tsconfig.json +16 -0
- package/packages/adapters-environment-docker/tsup.config.ts +9 -0
- package/packages/adapters-eventbus-cache/README.md +242 -0
- package/packages/adapters-eventbus-cache/eslint.config.js +27 -0
- package/packages/adapters-eventbus-cache/package.json +46 -0
- package/packages/adapters-eventbus-cache/src/index.test.ts +235 -0
- package/packages/adapters-eventbus-cache/src/index.ts +215 -0
- package/packages/adapters-eventbus-cache/src/manifest.ts +50 -0
- package/packages/adapters-eventbus-cache/src/types.ts +58 -0
- package/packages/adapters-eventbus-cache/tsconfig.build.json +15 -0
- package/packages/adapters-eventbus-cache/tsconfig.json +9 -0
- package/packages/adapters-eventbus-cache/tsup.config.ts +9 -0
- package/packages/adapters-fs/README.md +171 -0
- package/packages/adapters-fs/allowed.txt +1 -0
- package/packages/adapters-fs/conflict.txt +1 -0
- package/packages/adapters-fs/dest.txt +1 -0
- package/packages/adapters-fs/eslint.config.js +27 -0
- package/packages/adapters-fs/exists.txt +1 -0
- package/packages/adapters-fs/not-allowed.txt +1 -0
- package/packages/adapters-fs/other.txt +1 -0
- package/packages/adapters-fs/package.json +55 -0
- package/packages/adapters-fs/public/file1.txt +1 -0
- package/packages/adapters-fs/public/file2.txt +1 -0
- package/packages/adapters-fs/secret.txt +1 -0
- package/packages/adapters-fs/secrets/key.txt +1 -0
- package/packages/adapters-fs/src/index.test.ts +243 -0
- package/packages/adapters-fs/src/index.ts +258 -0
- package/packages/adapters-fs/src/manifest.ts +35 -0
- package/packages/adapters-fs/src/secure-storage.test.ts +380 -0
- package/packages/adapters-fs/src/secure-storage.ts +268 -0
- package/packages/adapters-fs/test.json +1 -0
- package/packages/adapters-fs/test.txt +1 -0
- package/packages/adapters-fs/test.xyz +1 -0
- package/packages/adapters-fs/test1.txt +1 -0
- package/packages/adapters-fs/test2.txt +1 -0
- package/packages/adapters-fs/tsconfig.build.json +15 -0
- package/packages/adapters-fs/tsconfig.json +9 -0
- package/packages/adapters-fs/tsup.config.ts +8 -0
- package/packages/adapters-fs/vitest.config.ts +19 -0
- package/packages/adapters-log-ringbuffer/README.md +228 -0
- package/packages/adapters-log-ringbuffer/eslint.config.js +27 -0
- package/packages/adapters-log-ringbuffer/package.json +47 -0
- package/packages/adapters-log-ringbuffer/src/__tests__/ring-buffer.test.ts +450 -0
- package/packages/adapters-log-ringbuffer/src/index.ts +212 -0
- package/packages/adapters-log-ringbuffer/src/manifest.ts +30 -0
- package/packages/adapters-log-ringbuffer/tsconfig.build.json +15 -0
- package/packages/adapters-log-ringbuffer/tsconfig.json +9 -0
- package/packages/adapters-log-ringbuffer/tsup.config.ts +9 -0
- package/packages/adapters-log-ringbuffer/vitest.config.ts +14 -0
- package/packages/adapters-log-sqlite/README.md +396 -0
- package/packages/adapters-log-sqlite/eslint.config.js +27 -0
- package/packages/adapters-log-sqlite/package.json +49 -0
- package/packages/adapters-log-sqlite/src/__tests__/log-persistence.test.ts +718 -0
- package/packages/adapters-log-sqlite/src/index.ts +1068 -0
- package/packages/adapters-log-sqlite/src/manifest.ts +36 -0
- package/packages/adapters-log-sqlite/src/schema.sql +46 -0
- package/packages/adapters-log-sqlite/tsconfig.build.json +15 -0
- package/packages/adapters-log-sqlite/tsconfig.json +9 -0
- package/packages/adapters-log-sqlite/tsup.config.ts +9 -0
- package/packages/adapters-log-sqlite/vitest.config.ts +15 -0
- package/packages/adapters-mongodb/README.md +147 -0
- package/packages/adapters-mongodb/eslint.config.js +27 -0
- package/packages/adapters-mongodb/package.json +53 -0
- package/packages/adapters-mongodb/src/index.ts +428 -0
- package/packages/adapters-mongodb/src/manifest.ts +45 -0
- package/packages/adapters-mongodb/src/secure-document.ts +231 -0
- package/packages/adapters-mongodb/tsconfig.build.json +15 -0
- package/packages/adapters-mongodb/tsconfig.json +9 -0
- package/packages/adapters-mongodb/tsup.config.ts +8 -0
- package/packages/adapters-openai/README.md +151 -0
- package/packages/adapters-openai/embeddings.ts +37 -0
- package/packages/adapters-openai/eslint.config.js +26 -0
- package/packages/adapters-openai/index.ts +22 -0
- package/packages/adapters-openai/package.json +57 -0
- package/packages/adapters-openai/src/embeddings-manifest.ts +45 -0
- package/packages/adapters-openai/src/embeddings.ts +104 -0
- package/packages/adapters-openai/src/index.ts +13 -0
- package/packages/adapters-openai/src/llm.ts +304 -0
- package/packages/adapters-openai/src/manifest.ts +47 -0
- package/packages/adapters-openai/tsconfig.build.json +15 -0
- package/packages/adapters-openai/tsconfig.json +9 -0
- package/packages/adapters-openai/tsup.config.ts +8 -0
- package/packages/adapters-pino/README.md +152 -0
- package/packages/adapters-pino/eslint.config.js +27 -0
- package/packages/adapters-pino/package.json +49 -0
- package/packages/adapters-pino/src/index.test.ts +44 -0
- package/packages/adapters-pino/src/index.ts +322 -0
- package/packages/adapters-pino/src/log-ring-buffer.ts +142 -0
- package/packages/adapters-pino/src/manifest.ts +49 -0
- package/packages/adapters-pino/tsconfig.build.json +15 -0
- package/packages/adapters-pino/tsconfig.json +9 -0
- package/packages/adapters-pino/tsup.config.ts +9 -0
- package/packages/adapters-pino-http/README.md +141 -0
- package/packages/adapters-pino-http/eslint.config.js +27 -0
- package/packages/adapters-pino-http/package.json +46 -0
- package/packages/adapters-pino-http/src/index.ts +229 -0
- package/packages/adapters-pino-http/tsconfig.build.json +15 -0
- package/packages/adapters-pino-http/tsconfig.json +9 -0
- package/packages/adapters-pino-http/tsup.config.ts +9 -0
- package/packages/adapters-qdrant/README.md +166 -0
- package/packages/adapters-qdrant/eslint.config.js +27 -0
- package/packages/adapters-qdrant/package.json +49 -0
- package/packages/adapters-qdrant/src/index.ts +490 -0
- package/packages/adapters-qdrant/src/manifest.ts +54 -0
- package/packages/adapters-qdrant/src/retry.ts +204 -0
- package/packages/adapters-qdrant/tsconfig.build.json +15 -0
- package/packages/adapters-qdrant/tsconfig.json +9 -0
- package/packages/adapters-qdrant/tsup.config.ts +9 -0
- package/packages/adapters-redis/README.md +159 -0
- package/packages/adapters-redis/eslint.config.js +27 -0
- package/packages/adapters-redis/package.json +49 -0
- package/packages/adapters-redis/src/index.ts +164 -0
- package/packages/adapters-redis/src/manifest.ts +49 -0
- package/packages/adapters-redis/tsconfig.build.json +15 -0
- package/packages/adapters-redis/tsconfig.json +9 -0
- package/packages/adapters-redis/tsup.config.ts +9 -0
- package/packages/adapters-snapshot-localfs/README.md +10 -0
- package/packages/adapters-snapshot-localfs/eslint.config.js +2 -0
- package/packages/adapters-snapshot-localfs/package.json +46 -0
- package/packages/adapters-snapshot-localfs/src/index.test.ts +40 -0
- package/packages/adapters-snapshot-localfs/src/index.ts +292 -0
- package/packages/adapters-snapshot-localfs/src/manifest.ts +32 -0
- package/packages/adapters-snapshot-localfs/tsconfig.build.json +15 -0
- package/packages/adapters-snapshot-localfs/tsconfig.json +16 -0
- package/packages/adapters-snapshot-localfs/tsup.config.ts +11 -0
- package/packages/adapters-sqlite/README.md +163 -0
- package/packages/adapters-sqlite/eslint.config.js +27 -0
- package/packages/adapters-sqlite/package.json +54 -0
- package/packages/adapters-sqlite/src/index.test.ts +245 -0
- package/packages/adapters-sqlite/src/index.ts +382 -0
- package/packages/adapters-sqlite/src/manifest.ts +47 -0
- package/packages/adapters-sqlite/src/secure-sql.test.ts +290 -0
- package/packages/adapters-sqlite/src/secure-sql.ts +281 -0
- package/packages/adapters-sqlite/tsconfig.build.json +15 -0
- package/packages/adapters-sqlite/tsconfig.json +9 -0
- package/packages/adapters-sqlite/tsup.config.ts +8 -0
- package/packages/adapters-sqlite/vitest.config.ts +19 -0
- package/packages/adapters-transport/README.md +170 -0
- package/packages/adapters-transport/eslint.config.js +27 -0
- package/packages/adapters-transport/package.json +49 -0
- package/packages/adapters-transport/src/__tests__/unix-socket-server.test.ts +550 -0
- package/packages/adapters-transport/src/index.ts +101 -0
- package/packages/adapters-transport/src/ipc-transport.ts +228 -0
- package/packages/adapters-transport/src/transport.ts +224 -0
- package/packages/adapters-transport/src/types.ts +92 -0
- package/packages/adapters-transport/src/unix-socket-server.ts +193 -0
- package/packages/adapters-transport/src/unix-socket-transport.ts +280 -0
- package/packages/adapters-transport/tsconfig.build.json +15 -0
- package/packages/adapters-transport/tsconfig.json +9 -0
- package/packages/adapters-transport/tsup.config.ts +9 -0
- package/packages/adapters-vibeproxy/README.md +159 -0
- package/packages/adapters-vibeproxy/eslint.config.js +27 -0
- package/packages/adapters-vibeproxy/package.json +51 -0
- package/packages/adapters-vibeproxy/src/index.ts +13 -0
- package/packages/adapters-vibeproxy/src/llm.ts +437 -0
- package/packages/adapters-vibeproxy/src/manifest.ts +51 -0
- package/packages/adapters-vibeproxy/tsconfig.build.json +15 -0
- package/packages/adapters-vibeproxy/tsconfig.json +9 -0
- package/packages/adapters-vibeproxy/tsup.config.ts +8 -0
- package/packages/adapters-workspace-agent/package.json +46 -0
- package/packages/adapters-workspace-agent/src/__tests__/adapter.test.ts +212 -0
- package/packages/adapters-workspace-agent/src/index.ts +220 -0
- package/packages/adapters-workspace-agent/src/manifest.ts +36 -0
- package/packages/adapters-workspace-agent/tsconfig.build.json +15 -0
- package/packages/adapters-workspace-agent/tsconfig.json +16 -0
- package/packages/adapters-workspace-agent/tsup.config.ts +11 -0
- package/packages/adapters-workspace-localfs/README.md +9 -0
- package/packages/adapters-workspace-localfs/eslint.config.js +2 -0
- package/packages/adapters-workspace-localfs/package.json +46 -0
- package/packages/adapters-workspace-localfs/src/index.test.ts +27 -0
- package/packages/adapters-workspace-localfs/src/index.ts +172 -0
- package/packages/adapters-workspace-localfs/src/manifest.ts +32 -0
- package/packages/adapters-workspace-localfs/tsconfig.build.json +15 -0
- package/packages/adapters-workspace-localfs/tsconfig.json +16 -0
- package/packages/adapters-workspace-localfs/tsup.config.ts +11 -0
- package/packages/adapters-workspace-worktree/README.md +9 -0
- package/packages/adapters-workspace-worktree/eslint.config.js +2 -0
- package/packages/adapters-workspace-worktree/package.json +46 -0
- package/packages/adapters-workspace-worktree/src/index.test.ts +38 -0
- package/packages/adapters-workspace-worktree/src/index.ts +245 -0
- package/packages/adapters-workspace-worktree/src/manifest.ts +38 -0
- package/packages/adapters-workspace-worktree/tsconfig.build.json +15 -0
- package/packages/adapters-workspace-worktree/tsconfig.json +16 -0
- package/packages/adapters-workspace-worktree/tsup.config.ts +11 -0
- package/pnpm-workspace.yaml +2800 -0
- package/prettierrc.json +1 -0
- package/scripts/devkit-sync.mjs +37 -0
- package/scripts/hooks/post-push +9 -0
- package/scripts/hooks/pre-commit +9 -0
- package/scripts/hooks/pre-push +9 -0
- package/test-integration.ts +242 -0
- package/test.txt +1 -0
- package/tsconfig.base.json +6 -0
- package/tsconfig.build.json +15 -0
- package/tsconfig.json +9 -0
- package/tsconfig.paths.json +26 -0
- package/tsconfig.tools.json +17 -0
- package/tsup.config.bin.ts +34 -0
- package/tsup.config.cli.ts +41 -0
- package/tsup.config.dual.ts +46 -0
- package/tsup.config.ts +36 -0
- package/tsup.external.json +103 -0
- package/vitest.config.ts +2 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @kb-labs/adapters-mongodb
|
|
3
|
+
* MongoDB adapter implementing IDocumentDatabase interface.
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Based on official MongoDB Node.js driver
|
|
7
|
+
* - Connection pooling (automatic)
|
|
8
|
+
* - Type-safe document operations
|
|
9
|
+
* - Query operators ($eq, $ne, $gt, etc.)
|
|
10
|
+
* - Projection and sorting support
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { createAdapter } from '@kb-labs/adapters-mongodb';
|
|
15
|
+
*
|
|
16
|
+
* const db = createAdapter({
|
|
17
|
+
* uri: 'mongodb://localhost:27017',
|
|
18
|
+
* database: 'myapp',
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // Find documents
|
|
22
|
+
* const users = await db.find('users', { age: { $gt: 18 } }, { limit: 10 });
|
|
23
|
+
*
|
|
24
|
+
* // Insert document
|
|
25
|
+
* await db.insertOne('users', { name: 'Alice', age: 25 });
|
|
26
|
+
*
|
|
27
|
+
* // Update documents
|
|
28
|
+
* await db.updateMany('users', { age: { $lt: 18 } }, { $set: { minor: true } });
|
|
29
|
+
*
|
|
30
|
+
* // Close connection
|
|
31
|
+
* await db.close();
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { randomUUID } from "node:crypto";
|
|
36
|
+
import { MongoClient, type Db, type Collection } from "mongodb";
|
|
37
|
+
import type {
|
|
38
|
+
IDocumentDatabase,
|
|
39
|
+
BaseDocument,
|
|
40
|
+
DocumentFilter,
|
|
41
|
+
DocumentUpdate,
|
|
42
|
+
FindOptions,
|
|
43
|
+
} from "@kb-labs/core-platform/adapters";
|
|
44
|
+
|
|
45
|
+
// Re-export manifest
|
|
46
|
+
export { manifest } from "./manifest.js";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Configuration for MongoDB adapter.
|
|
50
|
+
*/
|
|
51
|
+
export interface MongoDBConfig {
|
|
52
|
+
/**
|
|
53
|
+
* MongoDB connection URI.
|
|
54
|
+
* @example 'mongodb://localhost:27017'
|
|
55
|
+
* @example 'mongodb+srv://user:pass@cluster.mongodb.net'
|
|
56
|
+
*/
|
|
57
|
+
uri: string;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Database name.
|
|
61
|
+
*/
|
|
62
|
+
database: string;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Connection options (optional).
|
|
66
|
+
*/
|
|
67
|
+
options?: {
|
|
68
|
+
/** Max pool size (default: 10) */
|
|
69
|
+
maxPoolSize?: number;
|
|
70
|
+
/** Server selection timeout in ms (default: 30000) */
|
|
71
|
+
serverSelectionTimeoutMS?: number;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* MongoDB implementation of IDocumentDatabase interface.
|
|
77
|
+
*
|
|
78
|
+
* Design:
|
|
79
|
+
* - Uses official MongoDB Node.js driver
|
|
80
|
+
* - Connection pooling handled automatically
|
|
81
|
+
* - Type-safe operations with generics
|
|
82
|
+
* - Maps MongoDB operators to DocumentFilter format
|
|
83
|
+
*/
|
|
84
|
+
export class MongoDBAdapter implements IDocumentDatabase {
|
|
85
|
+
private client: MongoClient;
|
|
86
|
+
private db: Db;
|
|
87
|
+
private closed = false;
|
|
88
|
+
|
|
89
|
+
constructor(private config: MongoDBConfig) {
|
|
90
|
+
this.client = new MongoClient(config.uri, {
|
|
91
|
+
maxPoolSize: config.options?.maxPoolSize ?? 10,
|
|
92
|
+
serverSelectionTimeoutMS:
|
|
93
|
+
config.options?.serverSelectionTimeoutMS ?? 30000,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Will connect lazily on first operation
|
|
97
|
+
this.db = this.client.db(config.database);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Ensure connection is established.
|
|
102
|
+
*/
|
|
103
|
+
private async ensureConnected(): Promise<void> {
|
|
104
|
+
if (this.closed) {
|
|
105
|
+
throw new Error("Database connection is closed");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// MongoDB driver connects lazily, but we can trigger it explicitly
|
|
109
|
+
await this.client.connect();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get collection reference.
|
|
114
|
+
*/
|
|
115
|
+
private getCollection<T extends BaseDocument>(
|
|
116
|
+
collection: string,
|
|
117
|
+
): Collection<T> {
|
|
118
|
+
return this.db.collection<T>(collection);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Find documents matching a filter.
|
|
123
|
+
*
|
|
124
|
+
* @param collection - Collection name
|
|
125
|
+
* @param filter - Query filter
|
|
126
|
+
* @param options - Find options (limit, skip, sort, projection)
|
|
127
|
+
* @returns Array of matching documents
|
|
128
|
+
*/
|
|
129
|
+
async find<T extends BaseDocument>(
|
|
130
|
+
collection: string,
|
|
131
|
+
filter: DocumentFilter<T>,
|
|
132
|
+
options?: FindOptions,
|
|
133
|
+
): Promise<T[]> {
|
|
134
|
+
await this.ensureConnected();
|
|
135
|
+
|
|
136
|
+
const col = this.getCollection<T>(collection);
|
|
137
|
+
let cursor = col.find(filter as any);
|
|
138
|
+
|
|
139
|
+
// Apply options
|
|
140
|
+
if (options?.limit) {
|
|
141
|
+
cursor = cursor.limit(options.limit);
|
|
142
|
+
}
|
|
143
|
+
if (options?.skip) {
|
|
144
|
+
cursor = cursor.skip(options.skip);
|
|
145
|
+
}
|
|
146
|
+
if (options?.sort) {
|
|
147
|
+
cursor = cursor.sort(options.sort as any);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return cursor.toArray() as Promise<T[]>;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Find a single document by ID.
|
|
155
|
+
*
|
|
156
|
+
* @param collection - Collection name
|
|
157
|
+
* @param id - Document ID
|
|
158
|
+
* @returns Document or null if not found
|
|
159
|
+
*/
|
|
160
|
+
async findById<T extends BaseDocument>(
|
|
161
|
+
collection: string,
|
|
162
|
+
id: string,
|
|
163
|
+
): Promise<T | null> {
|
|
164
|
+
await this.ensureConnected();
|
|
165
|
+
|
|
166
|
+
const col = this.getCollection<T>(collection);
|
|
167
|
+
const doc = await col.findOne({ _id: id } as any);
|
|
168
|
+
|
|
169
|
+
return doc as T | null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Insert a single document.
|
|
174
|
+
*
|
|
175
|
+
* @param collection - Collection name
|
|
176
|
+
* @param document - Document to insert
|
|
177
|
+
* @returns Inserted document with generated fields
|
|
178
|
+
*/
|
|
179
|
+
async insertOne<T extends BaseDocument>(
|
|
180
|
+
collection: string,
|
|
181
|
+
document: Omit<T, "id" | "createdAt" | "updatedAt">,
|
|
182
|
+
): Promise<T> {
|
|
183
|
+
await this.ensureConnected();
|
|
184
|
+
|
|
185
|
+
const col = this.getCollection<T>(collection);
|
|
186
|
+
|
|
187
|
+
// Add generated fields (timestamps are Unix timestamps in milliseconds)
|
|
188
|
+
const now = Date.now();
|
|
189
|
+
const docWithMeta = {
|
|
190
|
+
...document,
|
|
191
|
+
id: randomUUID(),
|
|
192
|
+
createdAt: now,
|
|
193
|
+
updatedAt: now,
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
await col.insertOne(docWithMeta as any);
|
|
197
|
+
|
|
198
|
+
return docWithMeta as T;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Insert multiple documents.
|
|
203
|
+
*
|
|
204
|
+
* @param collection - Collection name
|
|
205
|
+
* @param documents - Documents to insert
|
|
206
|
+
* @returns Array of inserted document IDs
|
|
207
|
+
*/
|
|
208
|
+
async insertMany<T extends BaseDocument>(
|
|
209
|
+
collection: string,
|
|
210
|
+
documents: Array<Omit<T, "_id">>,
|
|
211
|
+
): Promise<string[]> {
|
|
212
|
+
await this.ensureConnected();
|
|
213
|
+
|
|
214
|
+
if (documents.length === 0) {
|
|
215
|
+
return [];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const col = this.getCollection<T>(collection);
|
|
219
|
+
const result = await col.insertMany(documents as any);
|
|
220
|
+
|
|
221
|
+
return Object.values(result.insertedIds).map(String);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Update a single document.
|
|
226
|
+
*
|
|
227
|
+
* @param collection - Collection name
|
|
228
|
+
* @param filter - Query filter
|
|
229
|
+
* @param update - Update operations
|
|
230
|
+
* @returns Number of documents modified
|
|
231
|
+
*/
|
|
232
|
+
async updateOne<T extends BaseDocument>(
|
|
233
|
+
collection: string,
|
|
234
|
+
filter: DocumentFilter<T>,
|
|
235
|
+
update: DocumentUpdate<T>,
|
|
236
|
+
): Promise<number> {
|
|
237
|
+
await this.ensureConnected();
|
|
238
|
+
|
|
239
|
+
const col = this.getCollection<T>(collection);
|
|
240
|
+
const result = await col.updateOne(filter as any, update as any);
|
|
241
|
+
|
|
242
|
+
return result.modifiedCount;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Update multiple documents.
|
|
247
|
+
*
|
|
248
|
+
* @param collection - Collection name
|
|
249
|
+
* @param filter - Query filter
|
|
250
|
+
* @param update - Update operations
|
|
251
|
+
* @returns Number of documents modified
|
|
252
|
+
*/
|
|
253
|
+
async updateMany<T extends BaseDocument>(
|
|
254
|
+
collection: string,
|
|
255
|
+
filter: DocumentFilter<T>,
|
|
256
|
+
update: DocumentUpdate<T>,
|
|
257
|
+
): Promise<number> {
|
|
258
|
+
await this.ensureConnected();
|
|
259
|
+
|
|
260
|
+
const col = this.getCollection<T>(collection);
|
|
261
|
+
const result = await col.updateMany(filter as any, update as any);
|
|
262
|
+
|
|
263
|
+
return result.modifiedCount;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Update a single document by ID.
|
|
268
|
+
*
|
|
269
|
+
* @param collection - Collection name
|
|
270
|
+
* @param id - Document ID
|
|
271
|
+
* @param update - Update operations
|
|
272
|
+
* @returns Updated document or null if not found
|
|
273
|
+
*/
|
|
274
|
+
async updateById<T extends BaseDocument>(
|
|
275
|
+
collection: string,
|
|
276
|
+
id: string,
|
|
277
|
+
update: DocumentUpdate<T>,
|
|
278
|
+
): Promise<T | null> {
|
|
279
|
+
await this.ensureConnected();
|
|
280
|
+
|
|
281
|
+
const col = this.getCollection<T>(collection);
|
|
282
|
+
|
|
283
|
+
// findOneAndUpdate returns the updated document
|
|
284
|
+
const result = await col.findOneAndUpdate(
|
|
285
|
+
{ id } as any,
|
|
286
|
+
{
|
|
287
|
+
...update,
|
|
288
|
+
$set: { ...((update as any).$set || {}), updatedAt: Date.now() },
|
|
289
|
+
} as any,
|
|
290
|
+
{ returnDocument: "after" },
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
return result as T | null;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Delete a single document.
|
|
298
|
+
*
|
|
299
|
+
* @param collection - Collection name
|
|
300
|
+
* @param filter - Query filter
|
|
301
|
+
* @returns Number of documents deleted
|
|
302
|
+
*/
|
|
303
|
+
async deleteOne<T extends BaseDocument>(
|
|
304
|
+
collection: string,
|
|
305
|
+
filter: DocumentFilter<T>,
|
|
306
|
+
): Promise<number> {
|
|
307
|
+
await this.ensureConnected();
|
|
308
|
+
|
|
309
|
+
const col = this.getCollection<T>(collection);
|
|
310
|
+
const result = await col.deleteOne(filter as any);
|
|
311
|
+
|
|
312
|
+
return result.deletedCount ?? 0;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Delete multiple documents.
|
|
317
|
+
*
|
|
318
|
+
* @param collection - Collection name
|
|
319
|
+
* @param filter - Query filter
|
|
320
|
+
* @returns Number of documents deleted
|
|
321
|
+
*/
|
|
322
|
+
async deleteMany<T extends BaseDocument>(
|
|
323
|
+
collection: string,
|
|
324
|
+
filter: DocumentFilter<T>,
|
|
325
|
+
): Promise<number> {
|
|
326
|
+
await this.ensureConnected();
|
|
327
|
+
|
|
328
|
+
const col = this.getCollection<T>(collection);
|
|
329
|
+
const result = await col.deleteMany(filter as any);
|
|
330
|
+
|
|
331
|
+
return result.deletedCount ?? 0;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Delete a single document by ID.
|
|
336
|
+
*
|
|
337
|
+
* @param collection - Collection name
|
|
338
|
+
* @param id - Document ID
|
|
339
|
+
* @returns True if deleted, false if not found
|
|
340
|
+
*/
|
|
341
|
+
async deleteById(collection: string, id: string): Promise<boolean> {
|
|
342
|
+
await this.ensureConnected();
|
|
343
|
+
|
|
344
|
+
const col = this.getCollection(collection);
|
|
345
|
+
const result = await col.deleteOne({ id } as any);
|
|
346
|
+
|
|
347
|
+
return (result.deletedCount ?? 0) > 0;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Count documents matching a filter.
|
|
352
|
+
*
|
|
353
|
+
* @param collection - Collection name
|
|
354
|
+
* @param filter - Query filter
|
|
355
|
+
* @returns Number of matching documents
|
|
356
|
+
*/
|
|
357
|
+
async count<T extends BaseDocument>(
|
|
358
|
+
collection: string,
|
|
359
|
+
filter: DocumentFilter<T>,
|
|
360
|
+
): Promise<number> {
|
|
361
|
+
await this.ensureConnected();
|
|
362
|
+
|
|
363
|
+
const col = this.getCollection<T>(collection);
|
|
364
|
+
return col.countDocuments(filter as any);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Close the database connection.
|
|
369
|
+
*/
|
|
370
|
+
async close(): Promise<void> {
|
|
371
|
+
if (!this.closed) {
|
|
372
|
+
await this.client.close();
|
|
373
|
+
this.closed = true;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
378
|
+
// Utility methods (not part of IDocumentDatabase interface)
|
|
379
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Check if database is open.
|
|
383
|
+
*/
|
|
384
|
+
isOpen(): boolean {
|
|
385
|
+
return !this.closed;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Get underlying MongoDB client (for advanced usage).
|
|
390
|
+
* Use with caution - bypasses adapter interface.
|
|
391
|
+
*/
|
|
392
|
+
getRawClient(): MongoClient {
|
|
393
|
+
return this.client;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Get underlying MongoDB Db instance (for advanced usage).
|
|
398
|
+
* Use with caution - bypasses adapter interface.
|
|
399
|
+
*/
|
|
400
|
+
getRawDatabase(): Db {
|
|
401
|
+
return this.db;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Create MongoDB database adapter.
|
|
407
|
+
* This is the factory function called by initPlatform() when loading adapters.
|
|
408
|
+
*
|
|
409
|
+
* @param config - MongoDB configuration
|
|
410
|
+
* @returns MongoDB adapter instance
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* ```typescript
|
|
414
|
+
* const db = createAdapter({
|
|
415
|
+
* uri: 'mongodb://localhost:27017',
|
|
416
|
+
* database: 'myapp',
|
|
417
|
+
* options: {
|
|
418
|
+
* maxPoolSize: 20,
|
|
419
|
+
* },
|
|
420
|
+
* });
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
423
|
+
export function createAdapter(config: MongoDBConfig): MongoDBAdapter {
|
|
424
|
+
return new MongoDBAdapter(config);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Default export for direct import
|
|
428
|
+
export default createAdapter;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @kb-labs/adapters-mongodb/manifest
|
|
3
|
+
* Adapter manifest for MongoDB document database.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { AdapterManifest } from "@kb-labs/core-platform";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Adapter manifest for MongoDB document database.
|
|
10
|
+
*/
|
|
11
|
+
export const manifest: AdapterManifest = {
|
|
12
|
+
manifestVersion: "1.0.0",
|
|
13
|
+
id: "mongodb-documentdb",
|
|
14
|
+
name: "MongoDB Document Database",
|
|
15
|
+
version: "1.0.0",
|
|
16
|
+
description: "NoSQL document database using MongoDB",
|
|
17
|
+
author: "KB Labs Team",
|
|
18
|
+
license: "KBPL-1.1",
|
|
19
|
+
type: "core",
|
|
20
|
+
implements: "IDocumentDatabase",
|
|
21
|
+
capabilities: {
|
|
22
|
+
transactions: true,
|
|
23
|
+
search: true,
|
|
24
|
+
custom: {
|
|
25
|
+
aggregation: true,
|
|
26
|
+
indexes: true,
|
|
27
|
+
fullText: true,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
configSchema: {
|
|
31
|
+
uri: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "MongoDB connection URI (e.g., mongodb://localhost:27017)",
|
|
34
|
+
},
|
|
35
|
+
database: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description: "Database name",
|
|
38
|
+
},
|
|
39
|
+
poolSize: {
|
|
40
|
+
type: "number",
|
|
41
|
+
default: 10,
|
|
42
|
+
description: "Connection pool size",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @kb-labs/adapters-mongodb/secure-document
|
|
3
|
+
* SecureDocumentAdapter - IDocumentDatabase wrapper with permission validation.
|
|
4
|
+
*
|
|
5
|
+
* Design Philosophy: Validation-only security (like fs-shim)
|
|
6
|
+
* - Validates collection access against allowlists/denylists
|
|
7
|
+
* - Does NOT rewrite queries or filters
|
|
8
|
+
* - Fails fast with clear errors
|
|
9
|
+
* - Transparent pass-through when permitted
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { createAdapter } from '@kb-labs/adapters-mongodb';
|
|
14
|
+
* import { SecureDocumentAdapter } from '@kb-labs/adapters-mongodb/secure-document';
|
|
15
|
+
*
|
|
16
|
+
* const base = createAdapter({ uri: 'mongodb://localhost:27017', database: 'myapp' });
|
|
17
|
+
* const secure = new SecureDocumentAdapter(base, {
|
|
18
|
+
* allowlist: ['users', 'posts', 'comments'],
|
|
19
|
+
* denylist: ['admin_users', 'secrets'],
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* await secure.find('users', { age: { $gt: 18 } }); // ✅ Allowed
|
|
23
|
+
* await secure.find('admin_users', {}); // ❌ Denied
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import type {
|
|
28
|
+
IDocumentDatabase,
|
|
29
|
+
BaseDocument,
|
|
30
|
+
DocumentFilter,
|
|
31
|
+
DocumentUpdate,
|
|
32
|
+
FindOptions,
|
|
33
|
+
} from "@kb-labs/core-platform/adapters";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Permission configuration for document database access.
|
|
37
|
+
*/
|
|
38
|
+
export interface DocumentPermissions {
|
|
39
|
+
/**
|
|
40
|
+
* Allowed collection names (e.g., ['users', 'posts']).
|
|
41
|
+
* If empty or undefined, all collections are allowed (unless denied).
|
|
42
|
+
*/
|
|
43
|
+
allowlist?: string[];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Denied collection names (e.g., ['admin_users', 'secrets']).
|
|
47
|
+
* Takes precedence over allowlist.
|
|
48
|
+
*/
|
|
49
|
+
denylist?: string[];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Allow read operations (find, findById, count) (default: true)
|
|
53
|
+
*/
|
|
54
|
+
read?: boolean;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Allow write operations (insert, update) (default: true)
|
|
58
|
+
*/
|
|
59
|
+
write?: boolean;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Allow delete operations (deleteOne, deleteMany) (default: false - safer default)
|
|
63
|
+
*/
|
|
64
|
+
delete?: boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Error thrown when document database access is denied.
|
|
69
|
+
*/
|
|
70
|
+
export class DocumentPermissionError extends Error {
|
|
71
|
+
constructor(
|
|
72
|
+
public readonly operation: string,
|
|
73
|
+
public readonly collection: string,
|
|
74
|
+
public readonly reason: string,
|
|
75
|
+
) {
|
|
76
|
+
super(
|
|
77
|
+
`Document database access denied: ${operation} on '${collection}' - ${reason}`,
|
|
78
|
+
);
|
|
79
|
+
this.name = "DocumentPermissionError";
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* SecureDocumentAdapter - validates permissions before delegating to base database.
|
|
85
|
+
*
|
|
86
|
+
* Design:
|
|
87
|
+
* - Validation-only (no query rewriting)
|
|
88
|
+
* - Fails fast with clear errors
|
|
89
|
+
* - Transparent pass-through when permitted
|
|
90
|
+
* - Supports both coarse (read/write/delete) and fine (collection-based) permissions
|
|
91
|
+
*/
|
|
92
|
+
export class SecureDocumentAdapter implements IDocumentDatabase {
|
|
93
|
+
constructor(
|
|
94
|
+
private readonly baseDb: IDocumentDatabase,
|
|
95
|
+
private readonly permissions: DocumentPermissions,
|
|
96
|
+
) {}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Check if a collection is allowed by permissions.
|
|
100
|
+
*/
|
|
101
|
+
private checkCollection(
|
|
102
|
+
collection: string,
|
|
103
|
+
operation: "read" | "write" | "delete",
|
|
104
|
+
): void {
|
|
105
|
+
// Check operation-level permissions
|
|
106
|
+
const operationAllowed = this.permissions[operation] !== false;
|
|
107
|
+
if (!operationAllowed) {
|
|
108
|
+
throw new DocumentPermissionError(
|
|
109
|
+
operation,
|
|
110
|
+
collection,
|
|
111
|
+
`${operation} operations are disabled`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Check denylist first (takes precedence)
|
|
116
|
+
if (this.permissions.denylist?.includes(collection)) {
|
|
117
|
+
throw new DocumentPermissionError(
|
|
118
|
+
operation,
|
|
119
|
+
collection,
|
|
120
|
+
`collection is in denylist`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Check allowlist (if defined)
|
|
125
|
+
if (this.permissions.allowlist && this.permissions.allowlist.length > 0 && !this.permissions.allowlist.includes(collection)) {
|
|
126
|
+
throw new DocumentPermissionError(
|
|
127
|
+
operation,
|
|
128
|
+
collection,
|
|
129
|
+
`collection not in allowlist: [${this.permissions.allowlist.join(", ")}]`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
135
|
+
// IDocumentDatabase methods with permission checks
|
|
136
|
+
// ═══════════════════════════════════════════════════════════════════════
|
|
137
|
+
|
|
138
|
+
async find<T extends BaseDocument>(
|
|
139
|
+
collection: string,
|
|
140
|
+
filter: DocumentFilter<T>,
|
|
141
|
+
options?: FindOptions,
|
|
142
|
+
): Promise<T[]> {
|
|
143
|
+
this.checkCollection(collection, "read");
|
|
144
|
+
return this.baseDb.find<T>(collection, filter, options);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async findById<T extends BaseDocument>(
|
|
148
|
+
collection: string,
|
|
149
|
+
id: string,
|
|
150
|
+
): Promise<T | null> {
|
|
151
|
+
this.checkCollection(collection, "read");
|
|
152
|
+
return this.baseDb.findById<T>(collection, id);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async insertOne<T extends BaseDocument>(
|
|
156
|
+
collection: string,
|
|
157
|
+
document: Omit<T, "id" | "createdAt" | "updatedAt">,
|
|
158
|
+
): Promise<T> {
|
|
159
|
+
this.checkCollection(collection, "write");
|
|
160
|
+
return this.baseDb.insertOne<T>(collection, document);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async updateMany<T extends BaseDocument>(
|
|
164
|
+
collection: string,
|
|
165
|
+
filter: DocumentFilter<T>,
|
|
166
|
+
update: DocumentUpdate<T>,
|
|
167
|
+
): Promise<number> {
|
|
168
|
+
this.checkCollection(collection, "write");
|
|
169
|
+
return this.baseDb.updateMany<T>(collection, filter, update);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async updateById<T extends BaseDocument>(
|
|
173
|
+
collection: string,
|
|
174
|
+
id: string,
|
|
175
|
+
update: DocumentUpdate<T>,
|
|
176
|
+
): Promise<T | null> {
|
|
177
|
+
this.checkCollection(collection, "write");
|
|
178
|
+
return this.baseDb.updateById<T>(collection, id, update);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async deleteMany<T extends BaseDocument>(
|
|
182
|
+
collection: string,
|
|
183
|
+
filter: DocumentFilter<T>,
|
|
184
|
+
): Promise<number> {
|
|
185
|
+
this.checkCollection(collection, "delete");
|
|
186
|
+
return this.baseDb.deleteMany<T>(collection, filter);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async deleteById(collection: string, id: string): Promise<boolean> {
|
|
190
|
+
this.checkCollection(collection, "delete");
|
|
191
|
+
return this.baseDb.deleteById(collection, id);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async count<T extends BaseDocument>(
|
|
195
|
+
collection: string,
|
|
196
|
+
filter: DocumentFilter<T>,
|
|
197
|
+
): Promise<number> {
|
|
198
|
+
this.checkCollection(collection, "read");
|
|
199
|
+
return this.baseDb.count<T>(collection, filter);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async close(): Promise<void> {
|
|
203
|
+
await this.baseDb.close();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Create secure document adapter with permission validation.
|
|
209
|
+
*
|
|
210
|
+
* @param baseDb - Base document adapter (MongoDB, etc.)
|
|
211
|
+
* @param permissions - Permission configuration
|
|
212
|
+
* @returns Wrapped document adapter with permission checks
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* const secure = createSecureDocument(base, {
|
|
217
|
+
* allowlist: ['users', 'posts'],
|
|
218
|
+
* denylist: ['admin_users'],
|
|
219
|
+
* delete: false, // Prevent deletions
|
|
220
|
+
* });
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
export function createSecureDocument(
|
|
224
|
+
baseDb: IDocumentDatabase,
|
|
225
|
+
permissions: DocumentPermissions,
|
|
226
|
+
): SecureDocumentAdapter {
|
|
227
|
+
return new SecureDocumentAdapter(baseDb, permissions);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Default export for direct import
|
|
231
|
+
export default createSecureDocument;
|