s3db.js 11.2.6 → 11.3.2

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.
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Bulk Operations Tools
3
+ * Handles bulk updates and upserts for efficient batch processing
4
+ */
5
+
6
+ export const bulkTools = [
7
+ {
8
+ name: 'resourceUpdateMany',
9
+ description: 'Update multiple documents matching a query filter',
10
+ inputSchema: {
11
+ type: 'object',
12
+ properties: {
13
+ resourceName: {
14
+ type: 'string',
15
+ description: 'Name of the resource'
16
+ },
17
+ filters: {
18
+ type: 'object',
19
+ description: 'Query filters to select documents'
20
+ },
21
+ updates: {
22
+ type: 'object',
23
+ description: 'Updates to apply to matching documents'
24
+ },
25
+ limit: {
26
+ type: 'number',
27
+ description: 'Maximum number of documents to update',
28
+ default: 1000
29
+ }
30
+ },
31
+ required: ['resourceName', 'filters', 'updates']
32
+ }
33
+ },
34
+ {
35
+ name: 'resourceBulkUpsert',
36
+ description: 'Upsert multiple documents (insert if not exists, update if exists)',
37
+ inputSchema: {
38
+ type: 'object',
39
+ properties: {
40
+ resourceName: {
41
+ type: 'string',
42
+ description: 'Name of the resource'
43
+ },
44
+ data: {
45
+ type: 'array',
46
+ description: 'Array of documents to upsert (must include id field)'
47
+ }
48
+ },
49
+ required: ['resourceName', 'data']
50
+ }
51
+ }
52
+ ];
53
+
54
+ export function createBulkHandlers(server) {
55
+ return {
56
+ async resourceUpdateMany(args, database) {
57
+ server.ensureConnected(database);
58
+ const { resourceName, filters, updates, limit = 1000 } = args;
59
+ const resource = server.getResource(database, resourceName);
60
+
61
+ try {
62
+ // Query documents matching filters
63
+ const docs = await resource.query(filters, { limit });
64
+
65
+ // Update each document
66
+ const updatePromises = docs.map(doc =>
67
+ resource.update(doc.id, updates)
68
+ );
69
+
70
+ const results = await Promise.all(updatePromises);
71
+
72
+ return {
73
+ success: true,
74
+ updatedCount: results.length,
75
+ filters,
76
+ updates,
77
+ data: results
78
+ };
79
+ } catch (error) {
80
+ return {
81
+ success: false,
82
+ error: error.message,
83
+ filters,
84
+ updates
85
+ };
86
+ }
87
+ },
88
+
89
+ async resourceBulkUpsert(args, database) {
90
+ server.ensureConnected(database);
91
+ const { resourceName, data } = args;
92
+ const resource = server.getResource(database, resourceName);
93
+
94
+ try {
95
+ // Upsert each document
96
+ const upsertPromises = data.map(doc => resource.upsert(doc));
97
+ const results = await Promise.all(upsertPromises);
98
+
99
+ return {
100
+ success: true,
101
+ upsertedCount: results.length,
102
+ data: results
103
+ };
104
+ } catch (error) {
105
+ return {
106
+ success: false,
107
+ error: error.message
108
+ };
109
+ }
110
+ }
111
+ };
112
+ }
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Connection Management Tools
3
+ * Handles database connection, disconnection, and status checks
4
+ */
5
+
6
+ export const connectionTools = [
7
+ {
8
+ name: 'dbConnect',
9
+ description: 'Connect to an S3DB database with automatic costs tracking and configurable cache (memory or filesystem)',
10
+ inputSchema: {
11
+ type: 'object',
12
+ properties: {
13
+ connectionString: {
14
+ type: 'string',
15
+ description: 'S3DB connection string (e.g., s3://key:secret@bucket/path)'
16
+ },
17
+ verbose: {
18
+ type: 'boolean',
19
+ description: 'Enable verbose logging',
20
+ default: false
21
+ },
22
+ parallelism: {
23
+ type: 'number',
24
+ description: 'Number of parallel operations',
25
+ default: 10
26
+ },
27
+ passphrase: {
28
+ type: 'string',
29
+ description: 'Passphrase for encryption',
30
+ default: 'secret'
31
+ },
32
+ versioningEnabled: {
33
+ type: 'boolean',
34
+ description: 'Enable resource versioning',
35
+ default: false
36
+ },
37
+ enableCache: {
38
+ type: 'boolean',
39
+ description: 'Enable cache for improved performance',
40
+ default: true
41
+ },
42
+ enableCosts: {
43
+ type: 'boolean',
44
+ description: 'Enable costs tracking for S3 operations',
45
+ default: true
46
+ },
47
+ cacheDriver: {
48
+ type: 'string',
49
+ description: 'Cache driver type: "memory" or "filesystem"',
50
+ enum: ['memory', 'filesystem'],
51
+ default: 'memory'
52
+ },
53
+ cacheMaxSize: {
54
+ type: 'number',
55
+ description: 'Maximum number of items in memory cache (memory driver only)',
56
+ default: 1000
57
+ },
58
+ cacheTtl: {
59
+ type: 'number',
60
+ description: 'Cache time-to-live in milliseconds',
61
+ default: 300000
62
+ },
63
+ cacheDirectory: {
64
+ type: 'string',
65
+ description: 'Directory path for filesystem cache (filesystem driver only)',
66
+ default: './cache'
67
+ },
68
+ cachePrefix: {
69
+ type: 'string',
70
+ description: 'Prefix for cache files (filesystem driver only)',
71
+ default: 'cache'
72
+ }
73
+ },
74
+ required: ['connectionString']
75
+ }
76
+ },
77
+ {
78
+ name: 'dbDisconnect',
79
+ description: 'Disconnect from the S3DB database',
80
+ inputSchema: {
81
+ type: 'object',
82
+ properties: {},
83
+ required: []
84
+ }
85
+ },
86
+ {
87
+ name: 'dbStatus',
88
+ description: 'Get the current database connection status',
89
+ inputSchema: {
90
+ type: 'object',
91
+ properties: {},
92
+ required: []
93
+ }
94
+ }
95
+ ];
96
+
97
+ export function createConnectionHandlers(server) {
98
+ return {
99
+ async dbConnect(args, database, { S3db, CachePlugin, CostsPlugin, FilesystemCache }) {
100
+ const {
101
+ connectionString,
102
+ verbose = false,
103
+ parallelism = 10,
104
+ passphrase = 'secret',
105
+ versioningEnabled = false,
106
+ enableCache = true,
107
+ enableCosts = true,
108
+ cacheDriver = 'memory',
109
+ cacheMaxSize = 1000,
110
+ cacheTtl = 300000,
111
+ cacheDirectory = './cache',
112
+ cachePrefix = 'cache'
113
+ } = args;
114
+
115
+ if (database && database.isConnected()) {
116
+ return { success: false, message: 'Database is already connected' };
117
+ }
118
+
119
+ const plugins = [];
120
+
121
+ // Costs plugin
122
+ const costsEnabled = enableCosts !== false && process.env.S3DB_COSTS_ENABLED !== 'false';
123
+ if (costsEnabled) {
124
+ plugins.push(CostsPlugin);
125
+ }
126
+
127
+ // Cache plugin
128
+ const cacheEnabled = enableCache !== false && process.env.S3DB_CACHE_ENABLED !== 'false';
129
+
130
+ if (cacheEnabled) {
131
+ const cacheMaxSizeEnv = process.env.S3DB_CACHE_MAX_SIZE ? parseInt(process.env.S3DB_CACHE_MAX_SIZE) : cacheMaxSize;
132
+ const cacheTtlEnv = process.env.S3DB_CACHE_TTL ? parseInt(process.env.S3DB_CACHE_TTL) : cacheTtl;
133
+ const cacheDriverEnv = process.env.S3DB_CACHE_DRIVER || cacheDriver;
134
+ const cacheDirectoryEnv = process.env.S3DB_CACHE_DIRECTORY || cacheDirectory;
135
+ const cachePrefixEnv = process.env.S3DB_CACHE_PREFIX || cachePrefix;
136
+
137
+ let cacheConfig = {
138
+ includePartitions: true
139
+ };
140
+
141
+ if (cacheDriverEnv === 'filesystem') {
142
+ cacheConfig.driver = new FilesystemCache({
143
+ directory: cacheDirectoryEnv,
144
+ prefix: cachePrefixEnv,
145
+ ttl: cacheTtlEnv,
146
+ enableCompression: true,
147
+ enableStats: verbose,
148
+ enableCleanup: true,
149
+ cleanupInterval: 300000,
150
+ createDirectory: true
151
+ });
152
+ } else {
153
+ cacheConfig.driver = 'memory';
154
+ cacheConfig.memoryOptions = {
155
+ maxSize: cacheMaxSizeEnv,
156
+ ttl: cacheTtlEnv,
157
+ enableStats: verbose
158
+ };
159
+ }
160
+
161
+ plugins.push(new CachePlugin(cacheConfig));
162
+ }
163
+
164
+ const newDatabase = new S3db({
165
+ connectionString,
166
+ verbose,
167
+ parallelism,
168
+ passphrase,
169
+ versioningEnabled,
170
+ plugins
171
+ });
172
+
173
+ await newDatabase.connect();
174
+
175
+ return {
176
+ success: true,
177
+ message: 'Connected to S3DB database',
178
+ database: newDatabase,
179
+ status: {
180
+ connected: newDatabase.isConnected(),
181
+ bucket: newDatabase.bucket,
182
+ keyPrefix: newDatabase.keyPrefix,
183
+ version: newDatabase.s3dbVersion,
184
+ plugins: {
185
+ costs: costsEnabled,
186
+ cache: cacheEnabled,
187
+ cacheDriver: cacheEnabled ? cacheDriverEnv : null,
188
+ cacheDirectory: cacheEnabled && cacheDriverEnv === 'filesystem' ? cacheDirectoryEnv : null,
189
+ cacheMaxSize: cacheEnabled && cacheDriverEnv === 'memory' ? cacheMaxSizeEnv : null,
190
+ cacheTtl: cacheEnabled ? cacheTtlEnv : null
191
+ }
192
+ }
193
+ };
194
+ },
195
+
196
+ async dbDisconnect(args, database) {
197
+ if (!database || !database.isConnected()) {
198
+ return { success: false, message: 'No database connection to disconnect' };
199
+ }
200
+
201
+ await database.disconnect();
202
+
203
+ return {
204
+ success: true,
205
+ message: 'Disconnected from S3DB database',
206
+ clearDatabase: true
207
+ };
208
+ },
209
+
210
+ async dbStatus(args, database) {
211
+ if (!database) {
212
+ return {
213
+ connected: false,
214
+ message: 'No database instance created'
215
+ };
216
+ }
217
+
218
+ return {
219
+ connected: database.isConnected(),
220
+ bucket: database.bucket,
221
+ keyPrefix: database.keyPrefix,
222
+ version: database.s3dbVersion,
223
+ resourceCount: Object.keys(database.resources || {}).length,
224
+ resources: Object.keys(database.resources || {})
225
+ };
226
+ }
227
+ };
228
+ }