s3db.js 13.6.0 → 14.0.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.
- package/README.md +139 -43
- package/dist/s3db.cjs +72425 -38970
- package/dist/s3db.cjs.map +1 -1
- package/dist/s3db.es.js +72177 -38764
- package/dist/s3db.es.js.map +1 -1
- package/mcp/lib/base-handler.js +157 -0
- package/mcp/lib/handlers/connection-handler.js +280 -0
- package/mcp/lib/handlers/query-handler.js +533 -0
- package/mcp/lib/handlers/resource-handler.js +428 -0
- package/mcp/lib/tool-registry.js +336 -0
- package/mcp/lib/tools/connection-tools.js +161 -0
- package/mcp/lib/tools/query-tools.js +267 -0
- package/mcp/lib/tools/resource-tools.js +404 -0
- package/package.json +94 -49
- package/src/clients/memory-client.class.js +346 -191
- package/src/clients/memory-storage.class.js +300 -84
- package/src/clients/s3-client.class.js +7 -6
- package/src/concerns/geo-encoding.js +19 -2
- package/src/concerns/ip.js +59 -9
- package/src/concerns/money.js +8 -1
- package/src/concerns/password-hashing.js +49 -8
- package/src/concerns/plugin-storage.js +186 -18
- package/src/concerns/storage-drivers/filesystem-driver.js +284 -0
- package/src/database.class.js +139 -29
- package/src/errors.js +332 -42
- package/src/plugins/api/auth/oidc-auth.js +66 -17
- package/src/plugins/api/auth/strategies/base-strategy.class.js +74 -0
- package/src/plugins/api/auth/strategies/factory.class.js +63 -0
- package/src/plugins/api/auth/strategies/global-strategy.class.js +44 -0
- package/src/plugins/api/auth/strategies/path-based-strategy.class.js +83 -0
- package/src/plugins/api/auth/strategies/path-rules-strategy.class.js +118 -0
- package/src/plugins/api/concerns/failban-manager.js +106 -57
- package/src/plugins/api/concerns/opengraph-helper.js +116 -0
- package/src/plugins/api/concerns/route-context.js +601 -0
- package/src/plugins/api/concerns/state-machine.js +288 -0
- package/src/plugins/api/index.js +180 -41
- package/src/plugins/api/routes/auth-routes.js +198 -30
- package/src/plugins/api/routes/resource-routes.js +19 -4
- package/src/plugins/api/server/health-manager.class.js +163 -0
- package/src/plugins/api/server/middleware-chain.class.js +310 -0
- package/src/plugins/api/server/router.class.js +472 -0
- package/src/plugins/api/server.js +280 -1303
- package/src/plugins/api/utils/custom-routes.js +17 -5
- package/src/plugins/api/utils/guards.js +76 -17
- package/src/plugins/api/utils/openapi-generator-cached.class.js +133 -0
- package/src/plugins/api/utils/openapi-generator.js +7 -6
- package/src/plugins/api/utils/template-engine.js +77 -3
- package/src/plugins/audit.plugin.js +30 -8
- package/src/plugins/backup.plugin.js +110 -14
- package/src/plugins/cache/cache.class.js +22 -5
- package/src/plugins/cache/filesystem-cache.class.js +116 -19
- package/src/plugins/cache/memory-cache.class.js +211 -57
- package/src/plugins/cache/multi-tier-cache.class.js +371 -0
- package/src/plugins/cache/partition-aware-filesystem-cache.class.js +168 -47
- package/src/plugins/cache/redis-cache.class.js +552 -0
- package/src/plugins/cache/s3-cache.class.js +17 -8
- package/src/plugins/cache.plugin.js +176 -61
- package/src/plugins/cloud-inventory/drivers/alibaba-driver.js +8 -1
- package/src/plugins/cloud-inventory/drivers/aws-driver.js +60 -29
- package/src/plugins/cloud-inventory/drivers/azure-driver.js +8 -1
- package/src/plugins/cloud-inventory/drivers/base-driver.js +16 -2
- package/src/plugins/cloud-inventory/drivers/cloudflare-driver.js +8 -1
- package/src/plugins/cloud-inventory/drivers/digitalocean-driver.js +8 -1
- package/src/plugins/cloud-inventory/drivers/hetzner-driver.js +8 -1
- package/src/plugins/cloud-inventory/drivers/linode-driver.js +8 -1
- package/src/plugins/cloud-inventory/drivers/mongodb-atlas-driver.js +8 -1
- package/src/plugins/cloud-inventory/drivers/vultr-driver.js +8 -1
- package/src/plugins/cloud-inventory/index.js +29 -8
- package/src/plugins/cloud-inventory/registry.js +64 -42
- package/src/plugins/cloud-inventory.plugin.js +240 -138
- package/src/plugins/concerns/plugin-dependencies.js +54 -0
- package/src/plugins/concerns/resource-names.js +100 -0
- package/src/plugins/consumers/index.js +10 -2
- package/src/plugins/consumers/sqs-consumer.js +12 -2
- package/src/plugins/cookie-farm-suite.plugin.js +278 -0
- package/src/plugins/cookie-farm.errors.js +73 -0
- package/src/plugins/cookie-farm.plugin.js +869 -0
- package/src/plugins/costs.plugin.js +7 -1
- package/src/plugins/eventual-consistency/analytics.js +94 -19
- package/src/plugins/eventual-consistency/config.js +15 -7
- package/src/plugins/eventual-consistency/consolidation.js +29 -11
- package/src/plugins/eventual-consistency/garbage-collection.js +3 -1
- package/src/plugins/eventual-consistency/helpers.js +39 -14
- package/src/plugins/eventual-consistency/install.js +21 -2
- package/src/plugins/eventual-consistency/utils.js +32 -10
- package/src/plugins/fulltext.plugin.js +38 -11
- package/src/plugins/geo.plugin.js +61 -9
- package/src/plugins/identity/concerns/config.js +61 -0
- package/src/plugins/identity/concerns/mfa-manager.js +15 -2
- package/src/plugins/identity/concerns/rate-limit.js +124 -0
- package/src/plugins/identity/concerns/resource-schemas.js +9 -1
- package/src/plugins/identity/concerns/token-generator.js +29 -4
- package/src/plugins/identity/drivers/auth-driver.interface.js +76 -0
- package/src/plugins/identity/drivers/client-credentials-driver.js +127 -0
- package/src/plugins/identity/drivers/index.js +18 -0
- package/src/plugins/identity/drivers/password-driver.js +122 -0
- package/src/plugins/identity/email-service.js +17 -2
- package/src/plugins/identity/index.js +413 -69
- package/src/plugins/identity/oauth2-server.js +413 -30
- package/src/plugins/identity/oidc-discovery.js +16 -8
- package/src/plugins/identity/rsa-keys.js +115 -35
- package/src/plugins/identity/server.js +166 -45
- package/src/plugins/identity/session-manager.js +53 -7
- package/src/plugins/identity/ui/pages/mfa-verification.js +17 -15
- package/src/plugins/identity/ui/routes.js +363 -255
- package/src/plugins/importer/index.js +153 -20
- package/src/plugins/index.js +9 -2
- package/src/plugins/kubernetes-inventory/index.js +6 -0
- package/src/plugins/kubernetes-inventory/k8s-driver.js +867 -0
- package/src/plugins/kubernetes-inventory/resource-types.js +274 -0
- package/src/plugins/kubernetes-inventory.plugin.js +980 -0
- package/src/plugins/metrics.plugin.js +64 -16
- package/src/plugins/ml/base-model.class.js +25 -15
- package/src/plugins/ml/regression-model.class.js +1 -1
- package/src/plugins/ml.errors.js +57 -25
- package/src/plugins/ml.plugin.js +28 -4
- package/src/plugins/namespace.js +210 -0
- package/src/plugins/plugin.class.js +180 -8
- package/src/plugins/puppeteer/console-monitor.js +729 -0
- package/src/plugins/puppeteer/cookie-manager.js +492 -0
- package/src/plugins/puppeteer/network-monitor.js +816 -0
- package/src/plugins/puppeteer/performance-manager.js +746 -0
- package/src/plugins/puppeteer/proxy-manager.js +478 -0
- package/src/plugins/puppeteer/stealth-manager.js +556 -0
- package/src/plugins/puppeteer.errors.js +81 -0
- package/src/plugins/puppeteer.plugin.js +1327 -0
- package/src/plugins/queue-consumer.plugin.js +69 -14
- package/src/plugins/recon/behaviors/uptime-behavior.js +691 -0
- package/src/plugins/recon/concerns/command-runner.js +148 -0
- package/src/plugins/recon/concerns/diff-detector.js +372 -0
- package/src/plugins/recon/concerns/fingerprint-builder.js +307 -0
- package/src/plugins/recon/concerns/process-manager.js +338 -0
- package/src/plugins/recon/concerns/report-generator.js +478 -0
- package/src/plugins/recon/concerns/security-analyzer.js +571 -0
- package/src/plugins/recon/concerns/target-normalizer.js +68 -0
- package/src/plugins/recon/config/defaults.js +321 -0
- package/src/plugins/recon/config/resources.js +370 -0
- package/src/plugins/recon/index.js +778 -0
- package/src/plugins/recon/managers/dependency-manager.js +174 -0
- package/src/plugins/recon/managers/scheduler-manager.js +179 -0
- package/src/plugins/recon/managers/storage-manager.js +745 -0
- package/src/plugins/recon/managers/target-manager.js +274 -0
- package/src/plugins/recon/stages/asn-stage.js +314 -0
- package/src/plugins/recon/stages/certificate-stage.js +84 -0
- package/src/plugins/recon/stages/dns-stage.js +107 -0
- package/src/plugins/recon/stages/dnsdumpster-stage.js +362 -0
- package/src/plugins/recon/stages/fingerprint-stage.js +71 -0
- package/src/plugins/recon/stages/google-dorks-stage.js +440 -0
- package/src/plugins/recon/stages/http-stage.js +89 -0
- package/src/plugins/recon/stages/latency-stage.js +148 -0
- package/src/plugins/recon/stages/massdns-stage.js +302 -0
- package/src/plugins/recon/stages/osint-stage.js +1373 -0
- package/src/plugins/recon/stages/ports-stage.js +169 -0
- package/src/plugins/recon/stages/screenshot-stage.js +94 -0
- package/src/plugins/recon/stages/secrets-stage.js +514 -0
- package/src/plugins/recon/stages/subdomains-stage.js +295 -0
- package/src/plugins/recon/stages/tls-audit-stage.js +78 -0
- package/src/plugins/recon/stages/vulnerability-stage.js +78 -0
- package/src/plugins/recon/stages/web-discovery-stage.js +113 -0
- package/src/plugins/recon/stages/whois-stage.js +349 -0
- package/src/plugins/recon.plugin.js +75 -0
- package/src/plugins/recon.plugin.js.backup +2635 -0
- package/src/plugins/relation.errors.js +87 -14
- package/src/plugins/replicator.plugin.js +514 -137
- package/src/plugins/replicators/base-replicator.class.js +89 -1
- package/src/plugins/replicators/bigquery-replicator.class.js +66 -22
- package/src/plugins/replicators/dynamodb-replicator.class.js +22 -15
- package/src/plugins/replicators/mongodb-replicator.class.js +22 -15
- package/src/plugins/replicators/mysql-replicator.class.js +52 -17
- package/src/plugins/replicators/planetscale-replicator.class.js +30 -4
- package/src/plugins/replicators/postgres-replicator.class.js +62 -27
- package/src/plugins/replicators/s3db-replicator.class.js +25 -18
- package/src/plugins/replicators/schema-sync.helper.js +3 -3
- package/src/plugins/replicators/sqs-replicator.class.js +8 -2
- package/src/plugins/replicators/turso-replicator.class.js +23 -3
- package/src/plugins/replicators/webhook-replicator.class.js +42 -4
- package/src/plugins/s3-queue.plugin.js +464 -65
- package/src/plugins/scheduler.plugin.js +20 -6
- package/src/plugins/state-machine.plugin.js +40 -9
- package/src/plugins/tfstate/README.md +126 -126
- package/src/plugins/tfstate/base-driver.js +28 -4
- package/src/plugins/tfstate/errors.js +65 -10
- package/src/plugins/tfstate/filesystem-driver.js +52 -8
- package/src/plugins/tfstate/index.js +163 -90
- package/src/plugins/tfstate/s3-driver.js +64 -6
- package/src/plugins/ttl.plugin.js +72 -17
- package/src/plugins/vector/distances.js +18 -12
- package/src/plugins/vector/kmeans.js +26 -4
- package/src/resource.class.js +115 -19
- package/src/testing/factory.class.js +20 -3
- package/src/testing/seeder.class.js +7 -1
- package/src/clients/memory-client.md +0 -917
- package/src/plugins/cloud-inventory/drivers/mock-drivers.js +0 -449
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base handler class for MCP tool handlers
|
|
3
|
+
*/
|
|
4
|
+
export class BaseHandler {
|
|
5
|
+
constructor(database) {
|
|
6
|
+
this.database = database;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Ensure database is connected
|
|
11
|
+
*/
|
|
12
|
+
ensureConnected() {
|
|
13
|
+
if (!this.database || !this.database.isConnected()) {
|
|
14
|
+
throw new Error('Database not connected. Use dbConnect tool first.');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get resource by name with validation
|
|
20
|
+
*/
|
|
21
|
+
getResource(resourceName) {
|
|
22
|
+
this.ensureConnected();
|
|
23
|
+
|
|
24
|
+
if (!this.database.resources[resourceName]) {
|
|
25
|
+
const available = Object.keys(this.database.resources).join(', ');
|
|
26
|
+
throw new Error(`Resource '${resourceName}' not found. Available: ${available}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return this.database.resources[resourceName];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Wrap handler execution with error handling
|
|
34
|
+
*/
|
|
35
|
+
async execute(method, args) {
|
|
36
|
+
try {
|
|
37
|
+
return await method.call(this, args);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
return this.handleError(error, args);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Standard error handling
|
|
45
|
+
*/
|
|
46
|
+
handleError(error, context = {}) {
|
|
47
|
+
const suggestion = this.getErrorSuggestion(error);
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
success: false,
|
|
51
|
+
error: {
|
|
52
|
+
message: error.message,
|
|
53
|
+
type: error.constructor.name,
|
|
54
|
+
context,
|
|
55
|
+
suggestion,
|
|
56
|
+
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get contextual error suggestions
|
|
63
|
+
*/
|
|
64
|
+
getErrorSuggestion(error) {
|
|
65
|
+
const message = error.message.toLowerCase();
|
|
66
|
+
|
|
67
|
+
if (message.includes('not connected')) {
|
|
68
|
+
return 'Use dbConnect tool first to establish database connection';
|
|
69
|
+
}
|
|
70
|
+
if (message.includes('not found')) {
|
|
71
|
+
return 'Check resource name or use dbListResources to see available resources';
|
|
72
|
+
}
|
|
73
|
+
if (message.includes('validation')) {
|
|
74
|
+
return 'Use resourceValidate to check data before insertion';
|
|
75
|
+
}
|
|
76
|
+
if (message.includes('permission') || message.includes('access')) {
|
|
77
|
+
return 'Check your AWS credentials and bucket permissions';
|
|
78
|
+
}
|
|
79
|
+
if (message.includes('timeout')) {
|
|
80
|
+
return 'Operation timed out. Try with smaller batch size or increase timeout';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Generate cache key for operations
|
|
88
|
+
*/
|
|
89
|
+
generateCacheKey(resource, action, params = {}) {
|
|
90
|
+
const parts = [`resource=${resource}`, `action=${action}`];
|
|
91
|
+
|
|
92
|
+
const sortedParams = Object.entries(params)
|
|
93
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
94
|
+
.map(([key, value]) => `${key}=${JSON.stringify(value)}`)
|
|
95
|
+
.join('&');
|
|
96
|
+
|
|
97
|
+
if (sortedParams) {
|
|
98
|
+
parts.push(`params=${sortedParams}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return parts.join('/');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Extract partition information from data
|
|
106
|
+
*/
|
|
107
|
+
extractPartitionInfo(resource, data) {
|
|
108
|
+
if (!resource?.config?.partitions || !data) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const partitionInfo = {};
|
|
113
|
+
|
|
114
|
+
for (const [name, config] of Object.entries(resource.config.partitions)) {
|
|
115
|
+
if (config.fields) {
|
|
116
|
+
const values = {};
|
|
117
|
+
let hasValues = false;
|
|
118
|
+
|
|
119
|
+
for (const field of Object.keys(config.fields)) {
|
|
120
|
+
if (data[field] !== undefined && data[field] !== null) {
|
|
121
|
+
values[field] = data[field];
|
|
122
|
+
hasValues = true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (hasValues) {
|
|
127
|
+
partitionInfo[name] = values;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return Object.keys(partitionInfo).length > 0 ? partitionInfo : null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Validate required parameters
|
|
137
|
+
*/
|
|
138
|
+
validateParams(params, required) {
|
|
139
|
+
const missing = required.filter(param => params[param] === undefined);
|
|
140
|
+
|
|
141
|
+
if (missing.length > 0) {
|
|
142
|
+
throw new Error(`Missing required parameters: ${missing.join(', ')}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Format response with standard structure
|
|
148
|
+
*/
|
|
149
|
+
formatResponse(data, meta = {}) {
|
|
150
|
+
return {
|
|
151
|
+
success: true,
|
|
152
|
+
data,
|
|
153
|
+
timestamp: new Date().toISOString(),
|
|
154
|
+
...meta
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { BaseHandler } from '../base-handler.js';
|
|
2
|
+
import { S3db, CachePlugin, CostsPlugin, MetricsPlugin, FilesystemCache, MemoryCache } from 's3db.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Handler for database connection operations
|
|
6
|
+
*/
|
|
7
|
+
export class ConnectionHandler extends BaseHandler {
|
|
8
|
+
constructor(database) {
|
|
9
|
+
super(database);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Connect to S3DB database
|
|
14
|
+
*/
|
|
15
|
+
async connect(args) {
|
|
16
|
+
const {
|
|
17
|
+
connectionString,
|
|
18
|
+
verbose = false,
|
|
19
|
+
parallelism = 10,
|
|
20
|
+
passphrase = 'secret',
|
|
21
|
+
versioningEnabled = false,
|
|
22
|
+
persistHooks = false,
|
|
23
|
+
enableCache = true,
|
|
24
|
+
enableCosts = true,
|
|
25
|
+
enableMetrics = false,
|
|
26
|
+
cacheDriver = 'memory',
|
|
27
|
+
cacheMaxSize = 1000,
|
|
28
|
+
cacheTtl = 300000,
|
|
29
|
+
cacheDirectory = './cache',
|
|
30
|
+
cachePrefix = 'cache',
|
|
31
|
+
cacheCompress = true
|
|
32
|
+
} = args;
|
|
33
|
+
|
|
34
|
+
this.validateParams(args, ['connectionString']);
|
|
35
|
+
|
|
36
|
+
if (this.database && this.database.isConnected()) {
|
|
37
|
+
return this.formatResponse(null, {
|
|
38
|
+
message: 'Database is already connected',
|
|
39
|
+
status: await this.getStatus()
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Build plugins array
|
|
44
|
+
const plugins = this.buildPlugins({
|
|
45
|
+
enableCache,
|
|
46
|
+
enableCosts,
|
|
47
|
+
enableMetrics,
|
|
48
|
+
cacheDriver,
|
|
49
|
+
cacheMaxSize,
|
|
50
|
+
cacheTtl,
|
|
51
|
+
cacheDirectory,
|
|
52
|
+
cachePrefix,
|
|
53
|
+
cacheCompress,
|
|
54
|
+
verbose
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Create and connect database
|
|
58
|
+
this.database = new S3db({
|
|
59
|
+
connectionString,
|
|
60
|
+
verbose,
|
|
61
|
+
parallelism,
|
|
62
|
+
passphrase,
|
|
63
|
+
versioningEnabled,
|
|
64
|
+
persistHooks,
|
|
65
|
+
plugins
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await this.database.connect();
|
|
69
|
+
|
|
70
|
+
return this.formatResponse({
|
|
71
|
+
connected: true,
|
|
72
|
+
bucket: this.database.bucket,
|
|
73
|
+
keyPrefix: this.database.keyPrefix,
|
|
74
|
+
version: this.database.s3dbVersion
|
|
75
|
+
}, {
|
|
76
|
+
message: 'Connected to S3DB database',
|
|
77
|
+
plugins: this.getPluginInfo(plugins)
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Disconnect from database
|
|
83
|
+
*/
|
|
84
|
+
async disconnect() {
|
|
85
|
+
if (!this.database || !this.database.isConnected()) {
|
|
86
|
+
return this.formatResponse(null, {
|
|
87
|
+
message: 'No database connection to disconnect'
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
await this.database.disconnect();
|
|
92
|
+
const info = {
|
|
93
|
+
bucket: this.database.bucket,
|
|
94
|
+
keyPrefix: this.database.keyPrefix
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
this.database = null;
|
|
98
|
+
|
|
99
|
+
return this.formatResponse(info, {
|
|
100
|
+
message: 'Disconnected from S3DB database'
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get database status
|
|
106
|
+
*/
|
|
107
|
+
async status() {
|
|
108
|
+
if (!this.database) {
|
|
109
|
+
return this.formatResponse({
|
|
110
|
+
connected: false,
|
|
111
|
+
message: 'No database instance created'
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const status = await this.getStatus();
|
|
116
|
+
return this.formatResponse(status);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get detailed database statistics
|
|
121
|
+
*/
|
|
122
|
+
async getStats() {
|
|
123
|
+
this.ensureConnected();
|
|
124
|
+
|
|
125
|
+
const stats = {
|
|
126
|
+
database: await this.getStatus(),
|
|
127
|
+
costs: this.getCostStats(),
|
|
128
|
+
cache: await this.getCacheStats(),
|
|
129
|
+
metrics: this.getMetricsStats()
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
return this.formatResponse(stats);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Clear cache
|
|
137
|
+
*/
|
|
138
|
+
async clearCache(args) {
|
|
139
|
+
this.ensureConnected();
|
|
140
|
+
const { resourceName } = args;
|
|
141
|
+
|
|
142
|
+
const cachePlugin = this.getCachePlugin();
|
|
143
|
+
if (!cachePlugin) {
|
|
144
|
+
return this.formatResponse(null, {
|
|
145
|
+
message: 'Cache is not enabled'
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (resourceName) {
|
|
150
|
+
const resource = this.getResource(resourceName);
|
|
151
|
+
await cachePlugin.clearCacheForResource(resource);
|
|
152
|
+
|
|
153
|
+
return this.formatResponse(null, {
|
|
154
|
+
message: `Cache cleared for resource: ${resourceName}`
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
await cachePlugin.driver.clear();
|
|
159
|
+
return this.formatResponse(null, {
|
|
160
|
+
message: 'All cache cleared'
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Private helper methods
|
|
165
|
+
|
|
166
|
+
private buildPlugins(config) {
|
|
167
|
+
const plugins = [];
|
|
168
|
+
|
|
169
|
+
// Costs plugin
|
|
170
|
+
if (config.enableCosts && process.env.S3DB_COSTS_ENABLED !== 'false') {
|
|
171
|
+
plugins.push(CostsPlugin);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Cache plugin
|
|
175
|
+
if (config.enableCache && process.env.S3DB_CACHE_ENABLED !== 'false') {
|
|
176
|
+
plugins.push(this.buildCachePlugin(config));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Metrics plugin
|
|
180
|
+
if (config.enableMetrics) {
|
|
181
|
+
plugins.push(MetricsPlugin);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return plugins;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private buildCachePlugin(config) {
|
|
188
|
+
const cacheConfig = {
|
|
189
|
+
includePartitions: true
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const driver = process.env.S3DB_CACHE_DRIVER || config.cacheDriver;
|
|
193
|
+
|
|
194
|
+
if (driver === 'filesystem') {
|
|
195
|
+
cacheConfig.driver = new FilesystemCache({
|
|
196
|
+
directory: process.env.S3DB_CACHE_DIRECTORY || config.cacheDirectory,
|
|
197
|
+
prefix: process.env.S3DB_CACHE_PREFIX || config.cachePrefix,
|
|
198
|
+
ttl: parseInt(process.env.S3DB_CACHE_TTL) || config.cacheTtl,
|
|
199
|
+
enableCompression: config.cacheCompress,
|
|
200
|
+
enableStats: config.verbose,
|
|
201
|
+
enableCleanup: true,
|
|
202
|
+
cleanupInterval: 300000,
|
|
203
|
+
createDirectory: true
|
|
204
|
+
});
|
|
205
|
+
} else {
|
|
206
|
+
cacheConfig.driver = 'memory';
|
|
207
|
+
cacheConfig.memoryOptions = {
|
|
208
|
+
maxSize: parseInt(process.env.S3DB_CACHE_MAX_SIZE) || config.cacheMaxSize,
|
|
209
|
+
ttl: parseInt(process.env.S3DB_CACHE_TTL) || config.cacheTtl,
|
|
210
|
+
enableStats: config.verbose
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return new CachePlugin(cacheConfig);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private async getStatus() {
|
|
218
|
+
return {
|
|
219
|
+
connected: this.database.isConnected(),
|
|
220
|
+
bucket: this.database.bucket,
|
|
221
|
+
keyPrefix: this.database.keyPrefix,
|
|
222
|
+
version: this.database.s3dbVersion,
|
|
223
|
+
resourceCount: Object.keys(this.database.resources || {}).length,
|
|
224
|
+
resources: Object.keys(this.database.resources || {})
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private getCostStats() {
|
|
229
|
+
if (!this.database.client?.costs) return null;
|
|
230
|
+
|
|
231
|
+
const costs = this.database.client.costs;
|
|
232
|
+
return {
|
|
233
|
+
total: costs.total,
|
|
234
|
+
totalRequests: costs.requests.total,
|
|
235
|
+
requestsByType: { ...costs.requests },
|
|
236
|
+
eventsByType: { ...costs.events },
|
|
237
|
+
estimatedCostUSD: costs.total
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private async getCacheStats() {
|
|
242
|
+
const plugin = this.getCachePlugin();
|
|
243
|
+
if (!plugin?.driver) return { enabled: false };
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
const size = await plugin.driver.size();
|
|
247
|
+
const keys = await plugin.driver.keys();
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
enabled: true,
|
|
251
|
+
driver: plugin.driver.constructor.name,
|
|
252
|
+
size,
|
|
253
|
+
maxSize: plugin.driver.maxSize || 'unlimited',
|
|
254
|
+
ttl: plugin.driver.ttl || 'no expiration',
|
|
255
|
+
keyCount: keys.length,
|
|
256
|
+
sampleKeys: keys.slice(0, 5)
|
|
257
|
+
};
|
|
258
|
+
} catch (error) {
|
|
259
|
+
return { enabled: false, error: error.message };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private getMetricsStats() {
|
|
264
|
+
const plugin = this.database.pluginList?.find(p => p.constructor.name === 'MetricsPlugin');
|
|
265
|
+
if (!plugin) return null;
|
|
266
|
+
|
|
267
|
+
return plugin.getMetrics();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private getCachePlugin() {
|
|
271
|
+
return this.database.pluginList?.find(p => p.constructor.name === 'CachePlugin');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private getPluginInfo(plugins) {
|
|
275
|
+
return plugins.map(p => ({
|
|
276
|
+
name: typeof p === 'function' ? p.name : p.constructor.name,
|
|
277
|
+
enabled: true
|
|
278
|
+
}));
|
|
279
|
+
}
|
|
280
|
+
}
|