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
|
@@ -5,8 +5,10 @@ import crypto from 'crypto';
|
|
|
5
5
|
import { Plugin } from "./plugin.class.js";
|
|
6
6
|
import S3Cache from "./cache/s3-cache.class.js";
|
|
7
7
|
import MemoryCache from "./cache/memory-cache.class.js";
|
|
8
|
+
import RedisCache from "./cache/redis-cache.class.js";
|
|
8
9
|
import { FilesystemCache } from "./cache/filesystem-cache.class.js";
|
|
9
10
|
import { PartitionAwareFilesystemCache } from "./cache/partition-aware-filesystem-cache.class.js";
|
|
11
|
+
import MultiTierCache from "./cache/multi-tier-cache.class.js";
|
|
10
12
|
import tryFn from "../concerns/try-fn.js";
|
|
11
13
|
import { CacheError } from "./cache.errors.js";
|
|
12
14
|
|
|
@@ -96,10 +98,21 @@ export class CachePlugin extends Plugin {
|
|
|
96
98
|
constructor(options = {}) {
|
|
97
99
|
super(options);
|
|
98
100
|
|
|
101
|
+
// Detect multi-tier mode (drivers array)
|
|
102
|
+
const isMultiTier = Array.isArray(options.drivers) && options.drivers.length > 0;
|
|
103
|
+
|
|
99
104
|
// Clean, consolidated configuration
|
|
100
105
|
this.config = {
|
|
101
|
-
// Driver configuration
|
|
106
|
+
// Driver configuration (single-tier or multi-tier)
|
|
102
107
|
driver: options.driver || 's3',
|
|
108
|
+
drivers: options.drivers, // Array of driver configs for multi-tier
|
|
109
|
+
isMultiTier,
|
|
110
|
+
|
|
111
|
+
// Multi-tier specific options
|
|
112
|
+
promoteOnHit: options.promoteOnHit !== false,
|
|
113
|
+
strategy: options.strategy || 'write-through', // 'write-through' | 'lazy-promotion'
|
|
114
|
+
fallbackOnError: options.fallbackOnError !== false,
|
|
115
|
+
|
|
103
116
|
config: {
|
|
104
117
|
ttl: options.ttl,
|
|
105
118
|
maxSize: options.maxSize,
|
|
@@ -139,30 +152,16 @@ export class CachePlugin extends Plugin {
|
|
|
139
152
|
}
|
|
140
153
|
|
|
141
154
|
async onInstall() {
|
|
142
|
-
// Initialize cache driver
|
|
143
|
-
if (this.config.
|
|
155
|
+
// Initialize cache driver (multi-tier or single-tier)
|
|
156
|
+
if (this.config.isMultiTier) {
|
|
157
|
+
// Multi-tier mode: create multiple drivers and wrap with MultiTierCache
|
|
158
|
+
this.driver = await this._createMultiTierDriver();
|
|
159
|
+
} else if (this.config.driver && typeof this.config.driver === 'object') {
|
|
144
160
|
// Use custom driver instance if provided
|
|
145
161
|
this.driver = this.config.driver;
|
|
146
|
-
} else if (this.config.driver === 'memory') {
|
|
147
|
-
this.driver = new MemoryCache(this.config.config);
|
|
148
|
-
} else if (this.config.driver === 'filesystem') {
|
|
149
|
-
// Use partition-aware filesystem cache if enabled
|
|
150
|
-
if (this.config.partitionAware) {
|
|
151
|
-
this.driver = new PartitionAwareFilesystemCache({
|
|
152
|
-
partitionStrategy: this.config.partitionStrategy,
|
|
153
|
-
trackUsage: this.config.trackUsage,
|
|
154
|
-
preloadRelated: this.config.preloadRelated,
|
|
155
|
-
...this.config.config
|
|
156
|
-
});
|
|
157
|
-
} else {
|
|
158
|
-
this.driver = new FilesystemCache(this.config.config);
|
|
159
|
-
}
|
|
160
162
|
} else {
|
|
161
|
-
//
|
|
162
|
-
this.driver =
|
|
163
|
-
client: this.database.client,
|
|
164
|
-
...this.config.config
|
|
165
|
-
});
|
|
163
|
+
// Single-tier mode: create single driver
|
|
164
|
+
this.driver = await this._createSingleDriver(this.config.driver, this.config.config);
|
|
166
165
|
}
|
|
167
166
|
|
|
168
167
|
// Use database hooks instead of method overwriting
|
|
@@ -192,6 +191,66 @@ export class CachePlugin extends Plugin {
|
|
|
192
191
|
// Cleanup if needed
|
|
193
192
|
}
|
|
194
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Create a single cache driver instance
|
|
196
|
+
* @private
|
|
197
|
+
*/
|
|
198
|
+
async _createSingleDriver(driverName, config) {
|
|
199
|
+
if (driverName === 'memory') {
|
|
200
|
+
return new MemoryCache(config);
|
|
201
|
+
} else if (driverName === 'redis') {
|
|
202
|
+
return new RedisCache(config);
|
|
203
|
+
} else if (driverName === 'filesystem') {
|
|
204
|
+
// Use partition-aware filesystem cache if enabled
|
|
205
|
+
if (this.config.partitionAware) {
|
|
206
|
+
return new PartitionAwareFilesystemCache({
|
|
207
|
+
partitionStrategy: this.config.partitionStrategy,
|
|
208
|
+
trackUsage: this.config.trackUsage,
|
|
209
|
+
preloadRelated: this.config.preloadRelated,
|
|
210
|
+
...config
|
|
211
|
+
});
|
|
212
|
+
} else {
|
|
213
|
+
return new FilesystemCache(config);
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
// Default to S3Cache
|
|
217
|
+
return new S3Cache({
|
|
218
|
+
client: this.database.client,
|
|
219
|
+
...config
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Create multi-tier cache driver
|
|
226
|
+
* @private
|
|
227
|
+
*/
|
|
228
|
+
async _createMultiTierDriver() {
|
|
229
|
+
const driverInstances = [];
|
|
230
|
+
|
|
231
|
+
// Create each driver instance
|
|
232
|
+
for (const driverConfig of this.config.drivers) {
|
|
233
|
+
const driverInstance = await this._createSingleDriver(
|
|
234
|
+
driverConfig.driver,
|
|
235
|
+
driverConfig.config || {}
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
driverInstances.push({
|
|
239
|
+
driver: driverInstance,
|
|
240
|
+
name: driverConfig.name || `L${driverInstances.length + 1}-${driverConfig.driver}`
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Wrap with MultiTierCache
|
|
245
|
+
return new MultiTierCache({
|
|
246
|
+
drivers: driverInstances,
|
|
247
|
+
promoteOnHit: this.config.promoteOnHit,
|
|
248
|
+
strategy: this.config.strategy,
|
|
249
|
+
fallbackOnError: this.config.fallbackOnError,
|
|
250
|
+
verbose: this.config.verbose
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
195
254
|
// Remove the old installDatabaseProxy method
|
|
196
255
|
installResourceHooks() {
|
|
197
256
|
for (const resource of Object.values(this.database.resources)) {
|
|
@@ -204,11 +263,11 @@ export class CachePlugin extends Plugin {
|
|
|
204
263
|
}
|
|
205
264
|
|
|
206
265
|
shouldCacheResource(resourceName) {
|
|
207
|
-
//
|
|
208
|
-
const
|
|
266
|
+
// Use $schema for reliable access to createdBy
|
|
267
|
+
const resource = this.database.resources[resourceName];
|
|
209
268
|
|
|
210
269
|
// Skip plugin-created resources by default (unless explicitly included)
|
|
211
|
-
if (
|
|
270
|
+
if (resource?.$schema?.createdBy && resource.$schema.createdBy !== 'user' && !this.config.include) {
|
|
212
271
|
return false;
|
|
213
272
|
}
|
|
214
273
|
|
|
@@ -233,18 +292,58 @@ export class CachePlugin extends Plugin {
|
|
|
233
292
|
installResourceHooksForResource(resource) {
|
|
234
293
|
if (!this.driver) return;
|
|
235
294
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
295
|
+
const driver = this.driver;
|
|
296
|
+
const instanceKey = this.instanceName || this.slug;
|
|
297
|
+
|
|
298
|
+
resource.cacheInstances = resource.cacheInstances || {};
|
|
299
|
+
resource.cacheInstances[instanceKey] = driver;
|
|
300
|
+
|
|
301
|
+
if (!Object.prototype.hasOwnProperty.call(resource, 'cache')) {
|
|
302
|
+
Object.defineProperty(resource, 'cache', {
|
|
303
|
+
value: driver,
|
|
304
|
+
writable: true,
|
|
305
|
+
configurable: true,
|
|
306
|
+
enumerable: false
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (typeof resource.getCacheDriver !== 'function') {
|
|
311
|
+
Object.defineProperty(resource, 'getCacheDriver', {
|
|
312
|
+
value: (name = null) => {
|
|
313
|
+
if (!name) {
|
|
314
|
+
return resource.cache;
|
|
315
|
+
}
|
|
316
|
+
return resource.cacheInstances?.[name] || null;
|
|
317
|
+
},
|
|
318
|
+
writable: true,
|
|
319
|
+
configurable: true,
|
|
320
|
+
enumerable: false
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
const computeCacheKey = async (options = {}) => {
|
|
244
324
|
const { action, params = {}, partition, partitionValues } = options;
|
|
245
325
|
return this.generateCacheKey(resource, action, params, partition, partitionValues);
|
|
246
326
|
};
|
|
247
327
|
|
|
328
|
+
resource.cacheKeyResolvers = resource.cacheKeyResolvers || {};
|
|
329
|
+
resource.cacheKeyResolvers[instanceKey] = computeCacheKey;
|
|
330
|
+
|
|
331
|
+
if (!resource.cacheKeyFor) {
|
|
332
|
+
resource.cacheKeyFor = computeCacheKey;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (typeof resource.getCacheKeyResolver !== 'function') {
|
|
336
|
+
Object.defineProperty(resource, 'getCacheKeyResolver', {
|
|
337
|
+
value: (name = null) => {
|
|
338
|
+
if (!name) return resource.cacheKeyFor;
|
|
339
|
+
return resource.cacheKeyResolvers?.[name] || null;
|
|
340
|
+
},
|
|
341
|
+
writable: true,
|
|
342
|
+
configurable: true,
|
|
343
|
+
enumerable: false
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
248
347
|
// Add partition-aware methods if using PartitionAwareFilesystemCache
|
|
249
348
|
if (this.driver instanceof PartitionAwareFilesystemCache) {
|
|
250
349
|
resource.clearPartitionCache = async (partition, partitionValues = {}) => {
|
|
@@ -272,6 +371,7 @@ export class CachePlugin extends Plugin {
|
|
|
272
371
|
|
|
273
372
|
for (const method of cacheMethods) {
|
|
274
373
|
resource.useMiddleware(method, async (ctx, next) => {
|
|
374
|
+
const resolveCacheKey = resource.cacheKeyResolvers?.[instanceKey] || computeCacheKey;
|
|
275
375
|
// Check for skipCache option in the last argument
|
|
276
376
|
let skipCache = false;
|
|
277
377
|
const lastArg = ctx.args[ctx.args.length - 1];
|
|
@@ -287,17 +387,17 @@ export class CachePlugin extends Plugin {
|
|
|
287
387
|
// Build cache key
|
|
288
388
|
let key;
|
|
289
389
|
if (method === 'getMany') {
|
|
290
|
-
key = await
|
|
390
|
+
key = await resolveCacheKey({ action: method, params: { ids: ctx.args[0] } });
|
|
291
391
|
} else if (method === 'page') {
|
|
292
392
|
const { offset, size, partition, partitionValues } = ctx.args[0] || {};
|
|
293
|
-
key = await
|
|
393
|
+
key = await resolveCacheKey({ action: method, params: { offset, size }, partition, partitionValues });
|
|
294
394
|
} else if (method === 'list' || method === 'listIds' || method === 'count') {
|
|
295
395
|
const { partition, partitionValues } = ctx.args[0] || {};
|
|
296
|
-
key = await
|
|
396
|
+
key = await resolveCacheKey({ action: method, partition, partitionValues });
|
|
297
397
|
} else if (method === 'query') {
|
|
298
398
|
const filter = ctx.args[0] || {};
|
|
299
399
|
const options = ctx.args[1] || {};
|
|
300
|
-
key = await
|
|
400
|
+
key = await resolveCacheKey({
|
|
301
401
|
action: method,
|
|
302
402
|
params: { filter, options: { limit: options.limit, offset: options.offset } },
|
|
303
403
|
partition: options.partition,
|
|
@@ -305,16 +405,16 @@ export class CachePlugin extends Plugin {
|
|
|
305
405
|
});
|
|
306
406
|
} else if (method === 'getFromPartition') {
|
|
307
407
|
const { id, partitionName, partitionValues } = ctx.args[0] || {};
|
|
308
|
-
key = await
|
|
408
|
+
key = await resolveCacheKey({
|
|
309
409
|
action: method,
|
|
310
410
|
params: { id, partitionName },
|
|
311
411
|
partition: partitionName,
|
|
312
412
|
partitionValues
|
|
313
413
|
});
|
|
314
414
|
} else if (method === 'getAll') {
|
|
315
|
-
key = await
|
|
415
|
+
key = await resolveCacheKey({ action: method });
|
|
316
416
|
} else if (['get', 'exists', 'content', 'hasContent'].includes(method)) {
|
|
317
|
-
key = await
|
|
417
|
+
key = await resolveCacheKey({ action: method, params: { id: ctx.args[0] } });
|
|
318
418
|
}
|
|
319
419
|
|
|
320
420
|
// Try cache with partition awareness
|
|
@@ -336,7 +436,7 @@ export class CachePlugin extends Plugin {
|
|
|
336
436
|
partitionValues = pValues;
|
|
337
437
|
}
|
|
338
438
|
|
|
339
|
-
const [ok, err, result] = await tryFn(() =>
|
|
439
|
+
const [ok, err, result] = await tryFn(() => driver._get(key, {
|
|
340
440
|
resource: resource.name,
|
|
341
441
|
action: method,
|
|
342
442
|
partition,
|
|
@@ -358,7 +458,7 @@ export class CachePlugin extends Plugin {
|
|
|
358
458
|
|
|
359
459
|
// Store with partition context
|
|
360
460
|
this.stats.writes++;
|
|
361
|
-
await
|
|
461
|
+
await driver._set(key, freshResult, {
|
|
362
462
|
resource: resource.name,
|
|
363
463
|
action: method,
|
|
364
464
|
partition,
|
|
@@ -368,7 +468,7 @@ export class CachePlugin extends Plugin {
|
|
|
368
468
|
return freshResult;
|
|
369
469
|
} else {
|
|
370
470
|
// Standard cache behavior
|
|
371
|
-
const [ok, err, result] = await tryFn(() =>
|
|
471
|
+
const [ok, err, result] = await tryFn(() => driver.get(key));
|
|
372
472
|
if (ok && result !== null && result !== undefined) {
|
|
373
473
|
this.stats.hits++;
|
|
374
474
|
return result;
|
|
@@ -382,7 +482,7 @@ export class CachePlugin extends Plugin {
|
|
|
382
482
|
this.stats.misses++;
|
|
383
483
|
const freshResult = await next();
|
|
384
484
|
this.stats.writes++;
|
|
385
|
-
await
|
|
485
|
+
await driver.set(key, freshResult);
|
|
386
486
|
return freshResult;
|
|
387
487
|
}
|
|
388
488
|
});
|
|
@@ -421,7 +521,8 @@ export class CachePlugin extends Plugin {
|
|
|
421
521
|
}
|
|
422
522
|
|
|
423
523
|
async clearCacheForResource(resource, data) {
|
|
424
|
-
|
|
524
|
+
const driver = this._getDriverForResource(resource);
|
|
525
|
+
if (!driver) return; // Skip if no cache is available
|
|
425
526
|
|
|
426
527
|
const keyPrefix = `resource=${resource.name}`;
|
|
427
528
|
|
|
@@ -431,7 +532,7 @@ export class CachePlugin extends Plugin {
|
|
|
431
532
|
const itemSpecificMethods = ['get', 'exists', 'content', 'hasContent'];
|
|
432
533
|
for (const method of itemSpecificMethods) {
|
|
433
534
|
const specificKey = await this.generateCacheKey(resource, method, { id: data.id });
|
|
434
|
-
const [ok, err] = await this.clearCacheWithRetry(
|
|
535
|
+
const [ok, err] = await this.clearCacheWithRetry(driver, specificKey);
|
|
435
536
|
|
|
436
537
|
if (!ok) {
|
|
437
538
|
this.emit('plg:cache:clear-error', {
|
|
@@ -448,12 +549,12 @@ export class CachePlugin extends Plugin {
|
|
|
448
549
|
}
|
|
449
550
|
|
|
450
551
|
// Clear partition-specific caches if this resource has partitions
|
|
451
|
-
if (this.config.includePartitions === true && resource.
|
|
552
|
+
if (this.config.includePartitions === true && resource.$schema.partitions && Object.keys(resource.$schema.partitions).length > 0) {
|
|
452
553
|
const partitionValues = this.getPartitionValues(data, resource);
|
|
453
554
|
for (const [partitionName, values] of Object.entries(partitionValues)) {
|
|
454
555
|
if (values && Object.keys(values).length > 0 && Object.values(values).some(v => v !== null && v !== undefined)) {
|
|
455
556
|
const partitionKeyPrefix = join(keyPrefix, `partition=${partitionName}`);
|
|
456
|
-
|
|
557
|
+
const [ok, err] = await this.clearCacheWithRetry(driver, partitionKeyPrefix);
|
|
457
558
|
|
|
458
559
|
if (!ok) {
|
|
459
560
|
this.emit('plg:cache:clear-error', {
|
|
@@ -472,7 +573,7 @@ export class CachePlugin extends Plugin {
|
|
|
472
573
|
}
|
|
473
574
|
|
|
474
575
|
// Clear aggregate caches more broadly to ensure all variants are cleared
|
|
475
|
-
const [ok, err] = await this.clearCacheWithRetry(
|
|
576
|
+
const [ok, err] = await this.clearCacheWithRetry(driver, keyPrefix);
|
|
476
577
|
|
|
477
578
|
if (!ok) {
|
|
478
579
|
this.emit('plg:cache:clear-error', {
|
|
@@ -489,8 +590,8 @@ export class CachePlugin extends Plugin {
|
|
|
489
590
|
const aggregateMethods = ['count', 'list', 'listIds', 'getAll', 'page', 'query'];
|
|
490
591
|
for (const method of aggregateMethods) {
|
|
491
592
|
// Try multiple key patterns to ensure we catch all variations
|
|
492
|
-
await this.clearCacheWithRetry(
|
|
493
|
-
await this.clearCacheWithRetry(
|
|
593
|
+
await this.clearCacheWithRetry(driver, `${keyPrefix}/action=${method}`);
|
|
594
|
+
await this.clearCacheWithRetry(driver, `resource=${resource.name}/action=${method}`);
|
|
494
595
|
}
|
|
495
596
|
}
|
|
496
597
|
}
|
|
@@ -523,6 +624,14 @@ export class CachePlugin extends Plugin {
|
|
|
523
624
|
return [false, lastError];
|
|
524
625
|
}
|
|
525
626
|
|
|
627
|
+
_getDriverForResource(resource) {
|
|
628
|
+
const instanceKey = this.instanceName || this.slug;
|
|
629
|
+
if (resource?.cacheInstances && instanceKey && resource.cacheInstances[instanceKey]) {
|
|
630
|
+
return resource.cacheInstances[instanceKey];
|
|
631
|
+
}
|
|
632
|
+
return this.driver;
|
|
633
|
+
}
|
|
634
|
+
|
|
526
635
|
async generateCacheKey(resource, action, params = {}, partition = null, partitionValues = null) {
|
|
527
636
|
const keyParts = [
|
|
528
637
|
`resource=${resource.name}`,
|
|
@@ -562,10 +671,15 @@ export class CachePlugin extends Plugin {
|
|
|
562
671
|
async getCacheStats() {
|
|
563
672
|
if (!this.driver) return null;
|
|
564
673
|
|
|
674
|
+
const driverStats = typeof this.driver.getStats === 'function'
|
|
675
|
+
? this.driver.getStats()
|
|
676
|
+
: null;
|
|
677
|
+
|
|
565
678
|
return {
|
|
566
679
|
size: await this.driver.size(),
|
|
567
680
|
keys: await this.driver.keys(),
|
|
568
|
-
driver: this.driver.constructor.name
|
|
681
|
+
driver: this.driver.constructor.name,
|
|
682
|
+
stats: driverStats
|
|
569
683
|
};
|
|
570
684
|
}
|
|
571
685
|
|
|
@@ -573,10 +687,11 @@ export class CachePlugin extends Plugin {
|
|
|
573
687
|
if (!this.driver) return;
|
|
574
688
|
|
|
575
689
|
for (const resource of Object.values(this.database.resources)) {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
}
|
|
690
|
+
const driver = this._getDriverForResource(resource);
|
|
691
|
+
if (!driver) continue;
|
|
692
|
+
|
|
693
|
+
const keyPrefix = `resource=${resource.name}`;
|
|
694
|
+
await driver.clear(keyPrefix);
|
|
580
695
|
}
|
|
581
696
|
}
|
|
582
697
|
|
|
@@ -596,7 +711,7 @@ export class CachePlugin extends Plugin {
|
|
|
596
711
|
|
|
597
712
|
// Use partition-aware warming if available
|
|
598
713
|
if (this.driver instanceof PartitionAwareFilesystemCache && resource.warmPartitionCache) {
|
|
599
|
-
const partitionNames = resource.
|
|
714
|
+
const partitionNames = resource.$schema.partitions ? Object.keys(resource.$schema.partitions) : [];
|
|
600
715
|
return await resource.warmPartitionCache(partitionNames, options);
|
|
601
716
|
}
|
|
602
717
|
|
|
@@ -628,8 +743,8 @@ export class CachePlugin extends Plugin {
|
|
|
628
743
|
}
|
|
629
744
|
|
|
630
745
|
// Warm partition caches if enabled
|
|
631
|
-
if (includePartitions && resource.
|
|
632
|
-
for (const [partitionName, partitionDef] of Object.entries(resource.
|
|
746
|
+
if (includePartitions && resource.$schema.partitions && sampledRecords.length > 0) {
|
|
747
|
+
for (const [partitionName, partitionDef] of Object.entries(resource.$schema.partitions)) {
|
|
633
748
|
if (partitionDef.fields) {
|
|
634
749
|
// Get unique partition values from sample
|
|
635
750
|
const partitionValuesSet = new Set();
|
|
@@ -653,8 +768,8 @@ export class CachePlugin extends Plugin {
|
|
|
653
768
|
return {
|
|
654
769
|
resourceName,
|
|
655
770
|
recordsSampled: sampledRecords.length,
|
|
656
|
-
partitionsWarmed: includePartitions && resource.
|
|
657
|
-
? Object.keys(resource.
|
|
771
|
+
partitionsWarmed: includePartitions && resource.$schema.partitions
|
|
772
|
+
? Object.keys(resource.$schema.partitions).length
|
|
658
773
|
: 0
|
|
659
774
|
};
|
|
660
775
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseCloudDriver } from './base-driver.js';
|
|
2
|
+
import { PluginError } from '../../../errors.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Production-ready Alibaba Cloud (Aliyun) inventory driver using @alicloud SDK.
|
|
@@ -57,7 +58,13 @@ export class AlibabaInventoryDriver extends BaseCloudDriver {
|
|
|
57
58
|
this._accessKeySecret = credentials.accessKeySecret || process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET;
|
|
58
59
|
|
|
59
60
|
if (!this._accessKeyId || !this._accessKeySecret) {
|
|
60
|
-
throw new
|
|
61
|
+
throw new PluginError('Alibaba Cloud AccessKeyId and AccessKeySecret are required. Provide via credentials or env vars.', {
|
|
62
|
+
pluginName: 'CloudInventoryPlugin',
|
|
63
|
+
operation: 'alibaba:initCredentials',
|
|
64
|
+
statusCode: 400,
|
|
65
|
+
retriable: false,
|
|
66
|
+
suggestion: 'Pass credentials.accessKeyId/accessKeySecret or set ALIBABA_CLOUD_ACCESS_KEY_ID / ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables.'
|
|
67
|
+
});
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
this.logger('info', 'Alibaba Cloud credentials initialized', {
|
|
@@ -87,7 +87,7 @@ import {
|
|
|
87
87
|
} from '@aws-sdk/client-api-gateway';
|
|
88
88
|
import {
|
|
89
89
|
ApiGatewayV2Client,
|
|
90
|
-
|
|
90
|
+
GetApisCommand,
|
|
91
91
|
GetTagsCommand as GetAPIGatewayV2TagsCommand
|
|
92
92
|
} from '@aws-sdk/client-apigatewayv2';
|
|
93
93
|
import {
|
|
@@ -138,8 +138,8 @@ import {
|
|
|
138
138
|
} from '@aws-sdk/client-sfn';
|
|
139
139
|
import {
|
|
140
140
|
EventBridgeClient,
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
ListEventBusesCommand,
|
|
142
|
+
ListRulesCommand,
|
|
143
143
|
ListTagsForResourceCommand as ListEventBridgeTagsCommand
|
|
144
144
|
} from '@aws-sdk/client-eventbridge';
|
|
145
145
|
import {
|
|
@@ -171,12 +171,12 @@ import {
|
|
|
171
171
|
} from '@aws-sdk/client-acm';
|
|
172
172
|
import {
|
|
173
173
|
WAFClient,
|
|
174
|
-
|
|
174
|
+
ListWebACLsCommand as ListWAFWebACLsCommand,
|
|
175
175
|
ListTagsForResourceCommand as ListWAFTagsCommand
|
|
176
176
|
} from '@aws-sdk/client-waf';
|
|
177
177
|
import {
|
|
178
178
|
WAFV2Client,
|
|
179
|
-
|
|
179
|
+
ListWebACLsCommand as ListWAFV2WebACLsCommand,
|
|
180
180
|
ListTagsForResourceCommand as ListWAFV2TagsCommand
|
|
181
181
|
} from '@aws-sdk/client-wafv2';
|
|
182
182
|
import {
|
|
@@ -287,9 +287,22 @@ function extractEc2Tags(instance) {
|
|
|
287
287
|
return Object.keys(tags).length ? tags : null;
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
+
/**
|
|
291
|
+
* @typedef {Object} AwsClientMap
|
|
292
|
+
* @property {Map<string, any>} ec2
|
|
293
|
+
* @property {any} s3
|
|
294
|
+
* @property {Map<string, any>} rds
|
|
295
|
+
* @property {any} iam
|
|
296
|
+
* @property {Map<string, any>} lambda
|
|
297
|
+
* @property {any} sts
|
|
298
|
+
* @property {Map<string, any>} ecs
|
|
299
|
+
* @property {Map<string, any>} eks
|
|
300
|
+
*/
|
|
301
|
+
|
|
290
302
|
export class AwsInventoryDriver extends BaseCloudDriver {
|
|
291
303
|
constructor(options = {}) {
|
|
292
304
|
super({ ...options, driver: options.driver || 'aws' });
|
|
305
|
+
/** @type {AwsClientMap} */
|
|
293
306
|
this._clients = {
|
|
294
307
|
ec2: new Map(),
|
|
295
308
|
s3: null,
|
|
@@ -952,9 +965,12 @@ export class AwsInventoryDriver extends BaseCloudDriver {
|
|
|
952
965
|
|
|
953
966
|
// HTTP/WebSocket APIs (v2)
|
|
954
967
|
const v2Client = this._getApiGatewayV2Client(region);
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
const
|
|
968
|
+
let nextToken;
|
|
969
|
+
do {
|
|
970
|
+
const response = await v2Client.send(new GetApisCommand({ NextToken: nextToken }));
|
|
971
|
+
const apis = response.Items || [];
|
|
972
|
+
nextToken = response.NextToken;
|
|
973
|
+
|
|
958
974
|
for (const api of apis) {
|
|
959
975
|
const tags = await this._safeGetAPIGatewayV2Tags(v2Client, api.ApiId);
|
|
960
976
|
const type = api.ProtocolType?.toLowerCase() || 'http';
|
|
@@ -970,7 +986,7 @@ export class AwsInventoryDriver extends BaseCloudDriver {
|
|
|
970
986
|
configuration: sanitizeConfiguration(api)
|
|
971
987
|
};
|
|
972
988
|
}
|
|
973
|
-
}
|
|
989
|
+
} while (nextToken);
|
|
974
990
|
}
|
|
975
991
|
}
|
|
976
992
|
|
|
@@ -1197,9 +1213,12 @@ export class AwsInventoryDriver extends BaseCloudDriver {
|
|
|
1197
1213
|
const client = this._getEventBridgeClient(region);
|
|
1198
1214
|
|
|
1199
1215
|
// Event Buses
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
const
|
|
1216
|
+
let nextBusToken;
|
|
1217
|
+
do {
|
|
1218
|
+
const busResponse = await client.send(new ListEventBusesCommand({ NextToken: nextBusToken }));
|
|
1219
|
+
const buses = busResponse.EventBuses || [];
|
|
1220
|
+
nextBusToken = busResponse.NextToken;
|
|
1221
|
+
|
|
1203
1222
|
for (const bus of buses) {
|
|
1204
1223
|
const tags = await this._safeListEventBridgeTags(client, bus.Arn);
|
|
1205
1224
|
yield {
|
|
@@ -1214,12 +1233,15 @@ export class AwsInventoryDriver extends BaseCloudDriver {
|
|
|
1214
1233
|
configuration: sanitizeConfiguration(bus)
|
|
1215
1234
|
};
|
|
1216
1235
|
}
|
|
1217
|
-
}
|
|
1236
|
+
} while (nextBusToken);
|
|
1218
1237
|
|
|
1219
1238
|
// Rules
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
const
|
|
1239
|
+
let nextRuleToken;
|
|
1240
|
+
do {
|
|
1241
|
+
const ruleResponse = await client.send(new ListRulesCommand({ NextToken: nextRuleToken }));
|
|
1242
|
+
const rules = ruleResponse.Rules || [];
|
|
1243
|
+
nextRuleToken = ruleResponse.NextToken;
|
|
1244
|
+
|
|
1223
1245
|
for (const rule of rules) {
|
|
1224
1246
|
const tags = await this._safeListEventBridgeTags(client, rule.Arn);
|
|
1225
1247
|
yield {
|
|
@@ -1234,7 +1256,7 @@ export class AwsInventoryDriver extends BaseCloudDriver {
|
|
|
1234
1256
|
configuration: sanitizeConfiguration(rule)
|
|
1235
1257
|
};
|
|
1236
1258
|
}
|
|
1237
|
-
}
|
|
1259
|
+
} while (nextRuleToken);
|
|
1238
1260
|
}
|
|
1239
1261
|
}
|
|
1240
1262
|
|
|
@@ -1380,9 +1402,12 @@ export class AwsInventoryDriver extends BaseCloudDriver {
|
|
|
1380
1402
|
async *_collectWAFResources() {
|
|
1381
1403
|
// WAF Classic (global)
|
|
1382
1404
|
const wafClient = this._getWafClient();
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
const
|
|
1405
|
+
let nextMarker;
|
|
1406
|
+
do {
|
|
1407
|
+
const response = await wafClient.send(new ListWAFWebACLsCommand({ NextMarker: nextMarker }));
|
|
1408
|
+
const webACLs = response.WebACLs || [];
|
|
1409
|
+
nextMarker = response.NextMarker;
|
|
1410
|
+
|
|
1386
1411
|
for (const acl of webACLs) {
|
|
1387
1412
|
const tags = await this._safeListWAFTags(wafClient, acl.WebACLId);
|
|
1388
1413
|
yield {
|
|
@@ -1397,7 +1422,7 @@ export class AwsInventoryDriver extends BaseCloudDriver {
|
|
|
1397
1422
|
configuration: sanitizeConfiguration(acl)
|
|
1398
1423
|
};
|
|
1399
1424
|
}
|
|
1400
|
-
}
|
|
1425
|
+
} while (nextMarker);
|
|
1401
1426
|
}
|
|
1402
1427
|
|
|
1403
1428
|
async *_collectWAFV2Resources() {
|
|
@@ -1405,9 +1430,12 @@ export class AwsInventoryDriver extends BaseCloudDriver {
|
|
|
1405
1430
|
const client = this._getWafv2Client(region);
|
|
1406
1431
|
|
|
1407
1432
|
// Regional WebACLs
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
const
|
|
1433
|
+
let nextMarker;
|
|
1434
|
+
do {
|
|
1435
|
+
const response = await client.send(new ListWAFV2WebACLsCommand({ Scope: 'REGIONAL', NextMarker: nextMarker }));
|
|
1436
|
+
const webACLs = response.WebACLs || [];
|
|
1437
|
+
nextMarker = response.NextMarker;
|
|
1438
|
+
|
|
1411
1439
|
for (const acl of webACLs) {
|
|
1412
1440
|
const tags = await this._safeListWAFV2Tags(client, acl.ARN);
|
|
1413
1441
|
yield {
|
|
@@ -1422,14 +1450,17 @@ export class AwsInventoryDriver extends BaseCloudDriver {
|
|
|
1422
1450
|
configuration: sanitizeConfiguration(acl)
|
|
1423
1451
|
};
|
|
1424
1452
|
}
|
|
1425
|
-
}
|
|
1453
|
+
} while (nextMarker);
|
|
1426
1454
|
}
|
|
1427
1455
|
|
|
1428
1456
|
// CloudFront WebACLs (us-east-1 only)
|
|
1429
1457
|
const cfClient = this._getWafv2Client(GLOBAL_REGION);
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
const
|
|
1458
|
+
let cfNextMarker;
|
|
1459
|
+
do {
|
|
1460
|
+
const cfResponse = await cfClient.send(new ListWAFV2WebACLsCommand({ Scope: 'CLOUDFRONT', NextMarker: cfNextMarker }));
|
|
1461
|
+
const webACLs = cfResponse.WebACLs || [];
|
|
1462
|
+
cfNextMarker = cfResponse.NextMarker;
|
|
1463
|
+
|
|
1433
1464
|
for (const acl of webACLs) {
|
|
1434
1465
|
const tags = await this._safeListWAFV2Tags(cfClient, acl.ARN);
|
|
1435
1466
|
yield {
|
|
@@ -1444,7 +1475,7 @@ export class AwsInventoryDriver extends BaseCloudDriver {
|
|
|
1444
1475
|
configuration: sanitizeConfiguration(acl)
|
|
1445
1476
|
};
|
|
1446
1477
|
}
|
|
1447
|
-
}
|
|
1478
|
+
} while (cfNextMarker);
|
|
1448
1479
|
}
|
|
1449
1480
|
|
|
1450
1481
|
async *_collectCognitoUserPools() {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseCloudDriver } from './base-driver.js';
|
|
2
|
+
import { PluginError } from '../../../errors.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Production-ready Microsoft Azure inventory driver using official @azure SDK.
|
|
@@ -69,7 +70,13 @@ export class AzureInventoryDriver extends BaseCloudDriver {
|
|
|
69
70
|
this._subscriptionId = credentials.subscriptionId || this.config?.subscriptionId;
|
|
70
71
|
|
|
71
72
|
if (!this._subscriptionId) {
|
|
72
|
-
throw new
|
|
73
|
+
throw new PluginError('Azure subscription ID is required. Provide via credentials.subscriptionId or config.subscriptionId.', {
|
|
74
|
+
pluginName: 'CloudInventoryPlugin',
|
|
75
|
+
operation: 'azure:initCredential',
|
|
76
|
+
statusCode: 400,
|
|
77
|
+
retriable: false,
|
|
78
|
+
suggestion: 'Set credentials.subscriptionId or config.subscriptionId before initializing the Azure inventory driver.'
|
|
79
|
+
});
|
|
73
80
|
}
|
|
74
81
|
|
|
75
82
|
this.logger('info', 'Azure credential initialized', {
|