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.
Files changed (193) hide show
  1. package/README.md +139 -43
  2. package/dist/s3db.cjs +72425 -38970
  3. package/dist/s3db.cjs.map +1 -1
  4. package/dist/s3db.es.js +72177 -38764
  5. package/dist/s3db.es.js.map +1 -1
  6. package/mcp/lib/base-handler.js +157 -0
  7. package/mcp/lib/handlers/connection-handler.js +280 -0
  8. package/mcp/lib/handlers/query-handler.js +533 -0
  9. package/mcp/lib/handlers/resource-handler.js +428 -0
  10. package/mcp/lib/tool-registry.js +336 -0
  11. package/mcp/lib/tools/connection-tools.js +161 -0
  12. package/mcp/lib/tools/query-tools.js +267 -0
  13. package/mcp/lib/tools/resource-tools.js +404 -0
  14. package/package.json +94 -49
  15. package/src/clients/memory-client.class.js +346 -191
  16. package/src/clients/memory-storage.class.js +300 -84
  17. package/src/clients/s3-client.class.js +7 -6
  18. package/src/concerns/geo-encoding.js +19 -2
  19. package/src/concerns/ip.js +59 -9
  20. package/src/concerns/money.js +8 -1
  21. package/src/concerns/password-hashing.js +49 -8
  22. package/src/concerns/plugin-storage.js +186 -18
  23. package/src/concerns/storage-drivers/filesystem-driver.js +284 -0
  24. package/src/database.class.js +139 -29
  25. package/src/errors.js +332 -42
  26. package/src/plugins/api/auth/oidc-auth.js +66 -17
  27. package/src/plugins/api/auth/strategies/base-strategy.class.js +74 -0
  28. package/src/plugins/api/auth/strategies/factory.class.js +63 -0
  29. package/src/plugins/api/auth/strategies/global-strategy.class.js +44 -0
  30. package/src/plugins/api/auth/strategies/path-based-strategy.class.js +83 -0
  31. package/src/plugins/api/auth/strategies/path-rules-strategy.class.js +118 -0
  32. package/src/plugins/api/concerns/failban-manager.js +106 -57
  33. package/src/plugins/api/concerns/opengraph-helper.js +116 -0
  34. package/src/plugins/api/concerns/route-context.js +601 -0
  35. package/src/plugins/api/concerns/state-machine.js +288 -0
  36. package/src/plugins/api/index.js +180 -41
  37. package/src/plugins/api/routes/auth-routes.js +198 -30
  38. package/src/plugins/api/routes/resource-routes.js +19 -4
  39. package/src/plugins/api/server/health-manager.class.js +163 -0
  40. package/src/plugins/api/server/middleware-chain.class.js +310 -0
  41. package/src/plugins/api/server/router.class.js +472 -0
  42. package/src/plugins/api/server.js +280 -1303
  43. package/src/plugins/api/utils/custom-routes.js +17 -5
  44. package/src/plugins/api/utils/guards.js +76 -17
  45. package/src/plugins/api/utils/openapi-generator-cached.class.js +133 -0
  46. package/src/plugins/api/utils/openapi-generator.js +7 -6
  47. package/src/plugins/api/utils/template-engine.js +77 -3
  48. package/src/plugins/audit.plugin.js +30 -8
  49. package/src/plugins/backup.plugin.js +110 -14
  50. package/src/plugins/cache/cache.class.js +22 -5
  51. package/src/plugins/cache/filesystem-cache.class.js +116 -19
  52. package/src/plugins/cache/memory-cache.class.js +211 -57
  53. package/src/plugins/cache/multi-tier-cache.class.js +371 -0
  54. package/src/plugins/cache/partition-aware-filesystem-cache.class.js +168 -47
  55. package/src/plugins/cache/redis-cache.class.js +552 -0
  56. package/src/plugins/cache/s3-cache.class.js +17 -8
  57. package/src/plugins/cache.plugin.js +176 -61
  58. package/src/plugins/cloud-inventory/drivers/alibaba-driver.js +8 -1
  59. package/src/plugins/cloud-inventory/drivers/aws-driver.js +60 -29
  60. package/src/plugins/cloud-inventory/drivers/azure-driver.js +8 -1
  61. package/src/plugins/cloud-inventory/drivers/base-driver.js +16 -2
  62. package/src/plugins/cloud-inventory/drivers/cloudflare-driver.js +8 -1
  63. package/src/plugins/cloud-inventory/drivers/digitalocean-driver.js +8 -1
  64. package/src/plugins/cloud-inventory/drivers/hetzner-driver.js +8 -1
  65. package/src/plugins/cloud-inventory/drivers/linode-driver.js +8 -1
  66. package/src/plugins/cloud-inventory/drivers/mongodb-atlas-driver.js +8 -1
  67. package/src/plugins/cloud-inventory/drivers/vultr-driver.js +8 -1
  68. package/src/plugins/cloud-inventory/index.js +29 -8
  69. package/src/plugins/cloud-inventory/registry.js +64 -42
  70. package/src/plugins/cloud-inventory.plugin.js +240 -138
  71. package/src/plugins/concerns/plugin-dependencies.js +54 -0
  72. package/src/plugins/concerns/resource-names.js +100 -0
  73. package/src/plugins/consumers/index.js +10 -2
  74. package/src/plugins/consumers/sqs-consumer.js +12 -2
  75. package/src/plugins/cookie-farm-suite.plugin.js +278 -0
  76. package/src/plugins/cookie-farm.errors.js +73 -0
  77. package/src/plugins/cookie-farm.plugin.js +869 -0
  78. package/src/plugins/costs.plugin.js +7 -1
  79. package/src/plugins/eventual-consistency/analytics.js +94 -19
  80. package/src/plugins/eventual-consistency/config.js +15 -7
  81. package/src/plugins/eventual-consistency/consolidation.js +29 -11
  82. package/src/plugins/eventual-consistency/garbage-collection.js +3 -1
  83. package/src/plugins/eventual-consistency/helpers.js +39 -14
  84. package/src/plugins/eventual-consistency/install.js +21 -2
  85. package/src/plugins/eventual-consistency/utils.js +32 -10
  86. package/src/plugins/fulltext.plugin.js +38 -11
  87. package/src/plugins/geo.plugin.js +61 -9
  88. package/src/plugins/identity/concerns/config.js +61 -0
  89. package/src/plugins/identity/concerns/mfa-manager.js +15 -2
  90. package/src/plugins/identity/concerns/rate-limit.js +124 -0
  91. package/src/plugins/identity/concerns/resource-schemas.js +9 -1
  92. package/src/plugins/identity/concerns/token-generator.js +29 -4
  93. package/src/plugins/identity/drivers/auth-driver.interface.js +76 -0
  94. package/src/plugins/identity/drivers/client-credentials-driver.js +127 -0
  95. package/src/plugins/identity/drivers/index.js +18 -0
  96. package/src/plugins/identity/drivers/password-driver.js +122 -0
  97. package/src/plugins/identity/email-service.js +17 -2
  98. package/src/plugins/identity/index.js +413 -69
  99. package/src/plugins/identity/oauth2-server.js +413 -30
  100. package/src/plugins/identity/oidc-discovery.js +16 -8
  101. package/src/plugins/identity/rsa-keys.js +115 -35
  102. package/src/plugins/identity/server.js +166 -45
  103. package/src/plugins/identity/session-manager.js +53 -7
  104. package/src/plugins/identity/ui/pages/mfa-verification.js +17 -15
  105. package/src/plugins/identity/ui/routes.js +363 -255
  106. package/src/plugins/importer/index.js +153 -20
  107. package/src/plugins/index.js +9 -2
  108. package/src/plugins/kubernetes-inventory/index.js +6 -0
  109. package/src/plugins/kubernetes-inventory/k8s-driver.js +867 -0
  110. package/src/plugins/kubernetes-inventory/resource-types.js +274 -0
  111. package/src/plugins/kubernetes-inventory.plugin.js +980 -0
  112. package/src/plugins/metrics.plugin.js +64 -16
  113. package/src/plugins/ml/base-model.class.js +25 -15
  114. package/src/plugins/ml/regression-model.class.js +1 -1
  115. package/src/plugins/ml.errors.js +57 -25
  116. package/src/plugins/ml.plugin.js +28 -4
  117. package/src/plugins/namespace.js +210 -0
  118. package/src/plugins/plugin.class.js +180 -8
  119. package/src/plugins/puppeteer/console-monitor.js +729 -0
  120. package/src/plugins/puppeteer/cookie-manager.js +492 -0
  121. package/src/plugins/puppeteer/network-monitor.js +816 -0
  122. package/src/plugins/puppeteer/performance-manager.js +746 -0
  123. package/src/plugins/puppeteer/proxy-manager.js +478 -0
  124. package/src/plugins/puppeteer/stealth-manager.js +556 -0
  125. package/src/plugins/puppeteer.errors.js +81 -0
  126. package/src/plugins/puppeteer.plugin.js +1327 -0
  127. package/src/plugins/queue-consumer.plugin.js +69 -14
  128. package/src/plugins/recon/behaviors/uptime-behavior.js +691 -0
  129. package/src/plugins/recon/concerns/command-runner.js +148 -0
  130. package/src/plugins/recon/concerns/diff-detector.js +372 -0
  131. package/src/plugins/recon/concerns/fingerprint-builder.js +307 -0
  132. package/src/plugins/recon/concerns/process-manager.js +338 -0
  133. package/src/plugins/recon/concerns/report-generator.js +478 -0
  134. package/src/plugins/recon/concerns/security-analyzer.js +571 -0
  135. package/src/plugins/recon/concerns/target-normalizer.js +68 -0
  136. package/src/plugins/recon/config/defaults.js +321 -0
  137. package/src/plugins/recon/config/resources.js +370 -0
  138. package/src/plugins/recon/index.js +778 -0
  139. package/src/plugins/recon/managers/dependency-manager.js +174 -0
  140. package/src/plugins/recon/managers/scheduler-manager.js +179 -0
  141. package/src/plugins/recon/managers/storage-manager.js +745 -0
  142. package/src/plugins/recon/managers/target-manager.js +274 -0
  143. package/src/plugins/recon/stages/asn-stage.js +314 -0
  144. package/src/plugins/recon/stages/certificate-stage.js +84 -0
  145. package/src/plugins/recon/stages/dns-stage.js +107 -0
  146. package/src/plugins/recon/stages/dnsdumpster-stage.js +362 -0
  147. package/src/plugins/recon/stages/fingerprint-stage.js +71 -0
  148. package/src/plugins/recon/stages/google-dorks-stage.js +440 -0
  149. package/src/plugins/recon/stages/http-stage.js +89 -0
  150. package/src/plugins/recon/stages/latency-stage.js +148 -0
  151. package/src/plugins/recon/stages/massdns-stage.js +302 -0
  152. package/src/plugins/recon/stages/osint-stage.js +1373 -0
  153. package/src/plugins/recon/stages/ports-stage.js +169 -0
  154. package/src/plugins/recon/stages/screenshot-stage.js +94 -0
  155. package/src/plugins/recon/stages/secrets-stage.js +514 -0
  156. package/src/plugins/recon/stages/subdomains-stage.js +295 -0
  157. package/src/plugins/recon/stages/tls-audit-stage.js +78 -0
  158. package/src/plugins/recon/stages/vulnerability-stage.js +78 -0
  159. package/src/plugins/recon/stages/web-discovery-stage.js +113 -0
  160. package/src/plugins/recon/stages/whois-stage.js +349 -0
  161. package/src/plugins/recon.plugin.js +75 -0
  162. package/src/plugins/recon.plugin.js.backup +2635 -0
  163. package/src/plugins/relation.errors.js +87 -14
  164. package/src/plugins/replicator.plugin.js +514 -137
  165. package/src/plugins/replicators/base-replicator.class.js +89 -1
  166. package/src/plugins/replicators/bigquery-replicator.class.js +66 -22
  167. package/src/plugins/replicators/dynamodb-replicator.class.js +22 -15
  168. package/src/plugins/replicators/mongodb-replicator.class.js +22 -15
  169. package/src/plugins/replicators/mysql-replicator.class.js +52 -17
  170. package/src/plugins/replicators/planetscale-replicator.class.js +30 -4
  171. package/src/plugins/replicators/postgres-replicator.class.js +62 -27
  172. package/src/plugins/replicators/s3db-replicator.class.js +25 -18
  173. package/src/plugins/replicators/schema-sync.helper.js +3 -3
  174. package/src/plugins/replicators/sqs-replicator.class.js +8 -2
  175. package/src/plugins/replicators/turso-replicator.class.js +23 -3
  176. package/src/plugins/replicators/webhook-replicator.class.js +42 -4
  177. package/src/plugins/s3-queue.plugin.js +464 -65
  178. package/src/plugins/scheduler.plugin.js +20 -6
  179. package/src/plugins/state-machine.plugin.js +40 -9
  180. package/src/plugins/tfstate/README.md +126 -126
  181. package/src/plugins/tfstate/base-driver.js +28 -4
  182. package/src/plugins/tfstate/errors.js +65 -10
  183. package/src/plugins/tfstate/filesystem-driver.js +52 -8
  184. package/src/plugins/tfstate/index.js +163 -90
  185. package/src/plugins/tfstate/s3-driver.js +64 -6
  186. package/src/plugins/ttl.plugin.js +72 -17
  187. package/src/plugins/vector/distances.js +18 -12
  188. package/src/plugins/vector/kmeans.js +26 -4
  189. package/src/resource.class.js +115 -19
  190. package/src/testing/factory.class.js +20 -3
  191. package/src/testing/seeder.class.js +7 -1
  192. package/src/clients/memory-client.md +0 -917
  193. package/src/plugins/cloud-inventory/drivers/mock-drivers.js +0 -449
@@ -1,42 +1,42 @@
1
1
  # TfState Plugin - Internal Development Guide
2
2
 
3
- Este documento é o guia interno de desenvolvimento do TfState Plugin.
3
+ This document is the internal development guide for the TfState Plugin.
4
4
 
5
5
  ---
6
6
 
7
- ## 📋 Arquitetura Geral
7
+ ## 📋 General Architecture
8
8
 
9
- ### Filosofia
9
+ ### Philosophy
10
10
 
11
- O TfState Plugin transforma states do Terraform (arquivos `.tfstate`) em dados consultáveis no s3db.
11
+ The TfState Plugin transforms Terraform states (`.tfstate` files) into queryable data in s3db.
12
12
 
13
- **Princípios:**
14
- - ✅ **Simplicidade**: API clara e direta
15
- - ✅ **Performance**: Partitions para queries rápidas (sync mode)
16
- - ✅ **Flexibilidade**: Suporta local files, S3, glob patterns
17
- - ✅ **Rastreabilidade**: Diff tracking entre versões
18
- - ✅ **Deduplicação**: SHA256 hash para evitar re-imports
13
+ **Principles:**
14
+ - ✅ **Simplicity**: Clear and direct API
15
+ - ✅ **Performance**: Partitions for fast queries (sync mode)
16
+ - ✅ **Flexibility**: Supports local files, S3, glob patterns
17
+ - ✅ **Traceability**: Diff tracking between versions
18
+ - ✅ **Deduplication**: SHA256 hash to avoid re-imports
19
19
 
20
20
  ---
21
21
 
22
- ## 🗄️ Os 3 Resources
22
+ ## 🗄️ The 3 Resources
23
23
 
24
24
  ### 1. State Files Resource (`plg_tfstate_states`)
25
25
 
26
- Armazena metadados sobre cada `.tfstate` importado.
26
+ Stores metadata about each imported `.tfstate`.
27
27
 
28
- **Schema Completo:**
28
+ **Complete Schema:**
29
29
  ```javascript
30
30
  {
31
- id: 'string|required', // nanoid gerado
31
+ id: 'string|required', // generated nanoid
32
32
  sourceFile: 'string|required', // 'prod/terraform.tfstate'
33
- serial: 'number|required', // Serial do state
33
+ serial: 'number|required', // State serial
34
34
  lineage: 'string', // Terraform lineage
35
35
  terraformVersion: 'string', // e.g. '1.5.0'
36
- resourceCount: 'number', // Quantos recursos
37
- sha256Hash: 'string|required', // Para dedup
36
+ resourceCount: 'number', // How many resources
37
+ sha256Hash: 'string|required', // For dedup
38
38
  importedAt: 'number|required', // timestamp
39
- stateVersion: 'number' // 3 ou 4
39
+ stateVersion: 'number' // 3 or 4
40
40
  }
41
41
  ```
42
42
 
@@ -47,18 +47,18 @@ Armazena metadados sobre cada `.tfstate` importado.
47
47
  bySerial: { fields: { serial: 'number' } }
48
48
  }
49
49
 
50
- asyncPartitions: false // Sync para queries imediatas
50
+ asyncPartitions: false // Sync for immediate queries
51
51
  ```
52
52
 
53
- **Queries Comuns:**
53
+ **Common Queries:**
54
54
  ```javascript
55
- // Buscar última versão de um state
55
+ // Fetch latest version of a state
56
56
  const latest = await stateFilesResource.listPartition({
57
57
  partition: 'bySourceFile',
58
58
  partitionValues: { sourceFile: 'prod/terraform.tfstate' }
59
59
  }).then(results => results.sort((a, b) => b.serial - a.serial)[0]);
60
60
 
61
- // Buscar serial específico
61
+ // Fetch specific serial
62
62
  const v100 = await stateFilesResource.listPartition({
63
63
  partition: 'bySerial',
64
64
  partitionValues: { serial: 100 }
@@ -69,34 +69,34 @@ const v100 = await stateFilesResource.listPartition({
69
69
 
70
70
  ### 2. Resources Resource (`plg_tfstate_resources`)
71
71
 
72
- O resource principal contendo todos os recursos de infraestrutura extraídos dos states.
72
+ The main resource containing all infrastructure resources extracted from states.
73
73
 
74
- **Schema Completo:**
74
+ **Complete Schema:**
75
75
  ```javascript
76
76
  {
77
- id: 'string|required', // nanoid gerado
78
- stateFileId: 'string|required', // FK para states resource
77
+ id: 'string|required', // generated nanoid
78
+ stateFileId: 'string|required', // FK to states resource
79
79
 
80
- // Denormalized para queries
81
- stateSerial: 'number|required', // De qual versão veio
82
- sourceFile: 'string|required', // De qual arquivo veio
80
+ // Denormalized for queries
81
+ stateSerial: 'number|required', // Which version it came from
82
+ sourceFile: 'string|required', // Which file it came from
83
83
 
84
- // Identidade do recurso
84
+ // Resource identity
85
85
  resourceType: 'string|required', // 'aws_instance'
86
86
  resourceName: 'string|required', // 'web_server'
87
87
  resourceAddress: 'string|required', // 'aws_instance.web_server'
88
88
  providerName: 'string|required', // 'aws', 'google', 'azure', etc
89
89
 
90
- // Dados do recurso
91
- mode: 'string', // 'managed' ou 'data'
92
- attributes: 'json', // Atributos completos do recurso
93
- dependencies: 'array', // Lista de dependências
90
+ // Resource data
91
+ mode: 'string', // 'managed' or 'data'
92
+ attributes: 'json', // Complete resource attributes
93
+ dependencies: 'array', // Dependency list
94
94
 
95
95
  importedAt: 'number|required' // timestamp
96
96
  }
97
97
  ```
98
98
 
99
- **Partitions (crítico para performance!):**
99
+ **Partitions (critical for performance!):**
100
100
  ```javascript
101
101
  {
102
102
  byType: {
@@ -119,7 +119,7 @@ O resource principal contendo todos os recursos de infraestrutura extraídos dos
119
119
  }
120
120
  }
121
121
 
122
- asyncPartitions: false // IMPORTANTE: Sync para queries imediatas!
122
+ asyncPartitions: false // IMPORTANT: Sync for immediate queries!
123
123
  ```
124
124
 
125
125
  **Provider Detection Logic:**
@@ -146,21 +146,21 @@ function detectProvider(resourceType) {
146
146
  }
147
147
  ```
148
148
 
149
- **Queries Comuns:**
149
+ **Common Queries:**
150
150
  ```javascript
151
- // Query por tipo (usa partition - O(1))
151
+ // Query by type (uses partition - O(1))
152
152
  const ec2 = await resource.listPartition({
153
153
  partition: 'byType',
154
154
  partitionValues: { resourceType: 'aws_instance' }
155
155
  });
156
156
 
157
- // Query por provider (usa partition - O(1))
157
+ // Query by provider (uses partition - O(1))
158
158
  const awsResources = await resource.listPartition({
159
159
  partition: 'byProvider',
160
160
  partitionValues: { providerName: 'aws' }
161
161
  });
162
162
 
163
- // Query por provider + tipo (partition combinada - O(1))
163
+ // Query by provider + type (combined partition - O(1))
164
164
  const awsRds = await resource.listPartition({
165
165
  partition: 'byProviderAndType',
166
166
  partitionValues: {
@@ -174,22 +174,22 @@ const awsRds = await resource.listPartition({
174
174
 
175
175
  ### 3. Diffs Resource (`plg_tfstate_diffs`)
176
176
 
177
- Rastreia mudanças entre versões de states.
177
+ Tracks changes between state versions.
178
178
 
179
- **Schema Completo:**
179
+ **Complete Schema:**
180
180
  ```javascript
181
181
  {
182
- id: 'string|required', // nanoid gerado
183
- sourceFile: 'string|required', // Qual state
184
- oldSerial: 'number|required', // Versão antiga
185
- newSerial: 'number|required', // Versão nova
182
+ id: 'string|required', // generated nanoid
183
+ sourceFile: 'string|required', // Which state
184
+ oldSerial: 'number|required', // Old version
185
+ newSerial: 'number|required', // New version
186
186
 
187
187
  summary: {
188
188
  type: 'object',
189
189
  props: {
190
- addedCount: 'number', // Quantos adicionados
191
- modifiedCount: 'number', // Quantos modificados
192
- deletedCount: 'number' // Quantos deletados
190
+ addedCount: 'number', // How many added
191
+ modifiedCount: 'number', // How many modified
192
+ deletedCount: 'number' // How many deleted
193
193
  }
194
194
  },
195
195
 
@@ -220,7 +220,7 @@ Rastreia mudanças entre versões de states.
220
220
  }
221
221
  }
222
222
 
223
- asyncPartitions: false // Sync para queries imediatas
223
+ asyncPartitions: false // Sync for immediate queries
224
224
  ```
225
225
 
226
226
  **Diff Calculation Logic:**
@@ -234,7 +234,7 @@ async function calculateDiff(oldState, newState) {
234
234
  const deleted = [];
235
235
  const modified = [];
236
236
 
237
- // Detectar adicionados
237
+ // Detect added
238
238
  for (const [address, resource] of Object.entries(newResources)) {
239
239
  if (!oldResources[address]) {
240
240
  added.push({
@@ -246,7 +246,7 @@ async function calculateDiff(oldState, newState) {
246
246
  }
247
247
  }
248
248
 
249
- // Detectar deletados
249
+ // Detect deleted
250
250
  for (const [address, resource] of Object.entries(oldResources)) {
251
251
  if (!newResources[address]) {
252
252
  deleted.push({
@@ -258,7 +258,7 @@ async function calculateDiff(oldState, newState) {
258
258
  }
259
259
  }
260
260
 
261
- // Detectar modificados
261
+ // Detect modified
262
262
  for (const [address, newResource] of Object.entries(newResources)) {
263
263
  const oldResource = oldResources[address];
264
264
  if (oldResource) {
@@ -291,7 +291,7 @@ async function calculateDiff(oldState, newState) {
291
291
  function detectChanges(oldAttrs, newAttrs, path = '') {
292
292
  const changes = [];
293
293
 
294
- // Comparar cada campo
294
+ // Compare each field
295
295
  const allKeys = new Set([...Object.keys(oldAttrs), ...Object.keys(newAttrs)]);
296
296
 
297
297
  for (const key of allKeys) {
@@ -314,43 +314,43 @@ function detectChanges(oldAttrs, newAttrs, path = '') {
314
314
 
315
315
  ---
316
316
 
317
- ## 🔧 Métodos Principais
317
+ ## 🔧 Main Methods
318
318
 
319
319
  ### Import Flow
320
320
 
321
321
  ```
322
322
  importState(filePath)
323
323
 
324
- 1. Ler arquivo do filesystem
325
- 2. Parsear JSON
326
- 3. Calcular SHA256
327
- 4. Verificar se existe (dedup)
328
- 5. Se novo:
329
- - Criar record em stateFilesResource
330
- - Extrair recursos
331
- - Criar records em resource
332
- - Se tem versão anterior:
333
- - Calcular diff
334
- - Criar record em diffsResource
324
+ 1. Read file from filesystem
325
+ 2. Parse JSON
326
+ 3. Calculate SHA256
327
+ 4. Check if already exists (dedup)
328
+ 5. If new:
329
+ - Create record in stateFilesResource
330
+ - Extract resources
331
+ - Create records in resource
332
+ - If previous version exists:
333
+ - Calculate diff
334
+ - Create record in diffsResource
335
335
  ```
336
336
 
337
- **Código:**
337
+ **Code:**
338
338
  ```javascript
339
339
  async importState(filePath, options = {}) {
340
- // 1. Ler e parsear
340
+ // 1. Read and parse
341
341
  const content = await fs.readFile(filePath, 'utf8');
342
342
  const state = JSON.parse(content);
343
343
 
344
344
  // 2. SHA256
345
345
  const sha256Hash = crypto.createHash('sha256').update(content).digest('hex');
346
346
 
347
- // 3. Verificar se existe
347
+ // 3. Check if already exists
348
348
  const existing = await this.stateFilesResource.query({ sha256Hash });
349
349
  if (existing.length > 0) {
350
350
  return { alreadyImported: true, stateFileId: existing[0].id };
351
351
  }
352
352
 
353
- // 4. Criar state file record
353
+ // 4. Create state file record
354
354
  const sourceFile = options.sourceFile || path.basename(filePath);
355
355
  const stateFileRecord = await this.stateFilesResource.insert({
356
356
  sourceFile,
@@ -363,10 +363,10 @@ async importState(filePath, options = {}) {
363
363
  stateVersion: state.version
364
364
  });
365
365
 
366
- // 5. Extrair e inserir recursos
366
+ // 5. Extract and insert resources
367
367
  const extractedResources = await this._extractResources(state, stateFileRecord.id);
368
368
 
369
- // 6. Calcular diff se houver versão anterior
369
+ // 6. Calculate diff if previous version exists
370
370
  if (this.trackDiffs) {
371
371
  await this._maybeCalculateDiff(sourceFile, state.serial);
372
372
  }
@@ -386,12 +386,12 @@ async _extractResources(state, stateFileId) {
386
386
  const extracted = [];
387
387
 
388
388
  for (const resource of resources) {
389
- // Aplicar filtros
389
+ // Apply filters
390
390
  if (!this._shouldIncludeResource(resource)) {
391
391
  continue;
392
392
  }
393
393
 
394
- // Processar cada instance do recurso
394
+ // Process each resource instance
395
395
  for (const instance of resource.instances || []) {
396
396
  const providerName = this._detectProvider(resource.type);
397
397
 
@@ -418,14 +418,14 @@ async _extractResources(state, stateFileId) {
418
418
  }
419
419
 
420
420
  _shouldIncludeResource(resource) {
421
- // Filtro por tipo
421
+ // Filter by type
422
422
  if (this.filters?.types && this.filters.types.length > 0) {
423
423
  if (!this.filters.types.includes(resource.type)) {
424
424
  return false;
425
425
  }
426
426
  }
427
427
 
428
- // Filtro por provider
428
+ // Filter by provider
429
429
  if (this.filters?.providers && this.filters.providers.length > 0) {
430
430
  const provider = this._detectProvider(resource.type);
431
431
  if (!this.filters.providers.includes(provider)) {
@@ -433,7 +433,7 @@ _shouldIncludeResource(resource) {
433
433
  }
434
434
  }
435
435
 
436
- // Filtro de exclusão
436
+ // Exclusion filter
437
437
  if (this.filters?.exclude && this.filters.exclude.length > 0) {
438
438
  for (const pattern of this.filters.exclude) {
439
439
  if (this._matchesPattern(resource.type, pattern)) {
@@ -470,24 +470,24 @@ _detectProvider(resourceType) {
470
470
 
471
471
  ```javascript
472
472
  async _maybeCalculateDiff(sourceFile, newSerial) {
473
- // Buscar versão anterior
473
+ // Fetch previous version
474
474
  const previousStates = await this.stateFilesResource.listPartition({
475
475
  partition: 'bySourceFile',
476
476
  partitionValues: { sourceFile }
477
477
  });
478
478
 
479
479
  if (previousStates.length < 2) {
480
- return; // Primeira versão, sem diff
480
+ return; // First version, no diff
481
481
  }
482
482
 
483
- // Ordenar por serial
483
+ // Sort by serial
484
484
  previousStates.sort((a, b) => b.serial - a.serial);
485
485
 
486
486
  const newState = previousStates[0];
487
487
  const oldState = previousStates[1];
488
488
 
489
489
  if (newState.serial === newSerial) {
490
- // Buscar recursos de ambas as versões
490
+ // Fetch resources from both versions
491
491
  const newResources = await this.resource.listPartition({
492
492
  partition: 'bySerial',
493
493
  partitionValues: { stateSerial: newState.serial }
@@ -498,10 +498,10 @@ async _maybeCalculateDiff(sourceFile, newSerial) {
498
498
  partitionValues: { stateSerial: oldState.serial }
499
499
  });
500
500
 
501
- // Calcular diff
501
+ // Calculate diff
502
502
  const diff = this._calculateDiff(oldResources, newResources);
503
503
 
504
- // Salvar diff
504
+ // Save diff
505
505
  await this.diffsResource.insert({
506
506
  sourceFile,
507
507
  oldSerial: oldState.serial,
@@ -518,7 +518,7 @@ async _maybeCalculateDiff(sourceFile, newSerial) {
518
518
 
519
519
  ## 🎯 Query Helpers
520
520
 
521
- Métodos convenientes que usam partitions para queries rápidas:
521
+ Convenient methods that use partitions for fast queries:
522
522
 
523
523
  ```javascript
524
524
  async getResourcesByType(type) {
@@ -563,7 +563,7 @@ async getLatestDiff(sourceFile) {
563
563
 
564
564
  if (diffs.length === 0) return null;
565
565
 
566
- // Ordenar por calculatedAt desc
566
+ // Sort by calculatedAt desc
567
567
  diffs.sort((a, b) => b.calculatedAt - a.calculatedAt);
568
568
  return diffs[0];
569
569
  }
@@ -640,33 +640,33 @@ async getStatsByType() {
640
640
 
641
641
  ## ⚡ Performance Considerations
642
642
 
643
- ### 1. Partitions em Sync Mode
643
+ ### 1. Partitions in Sync Mode
644
644
 
645
- **CRÍTICO**: Todas as 3 resources usam `asyncPartitions: false`.
645
+ **CRITICAL**: All 3 resources use `asyncPartitions: false`.
646
646
 
647
- **Por quê?**
648
- - Queries precisam ser imediatas após o import
649
- - Partitions async criam race conditions
650
- - Diff tracking requer dados imediatos
647
+ **Why?**
648
+ - Queries need to be immediate after import
649
+ - Async partitions create race conditions
650
+ - Diff tracking requires immediate data
651
651
 
652
652
  **Trade-off:**
653
- - Insert é um pouco mais lento (mas ainda rápido)
654
- - Queries são O(1) usando partitions
653
+ - Insert is slightly slower (but still fast)
654
+ - Queries are O(1) using partitions
655
655
 
656
- ### 2. Denormalização
656
+ ### 2. Denormalization
657
657
 
658
- Os campos `stateSerial` e `sourceFile` são denormalizados no resources resource para permitir queries rápidas sem joins.
658
+ Fields `stateSerial` and `sourceFile` are denormalized in the resources resource to enable fast queries without joins.
659
659
 
660
660
  ### 3. SHA256 Deduplication
661
661
 
662
- Antes de importar, sempre verificamos se o SHA256 existe. Isso evita re-imports desnecessários.
662
+ Before importing, we always check if SHA256 already exists. This avoids unnecessary re-imports.
663
663
 
664
664
  ### 4. Batch Operations
665
665
 
666
- Para glob imports, processamos em paralelo mas com limite:
666
+ For glob imports, we process in parallel but with limit:
667
667
 
668
668
  ```javascript
669
- const concurrency = 5; // Max 5 imports simultâneos
669
+ const concurrency = 5; // Max 5 simultaneous imports
670
670
  await PromisePool
671
671
  .withConcurrency(concurrency)
672
672
  .for(files)
@@ -679,62 +679,62 @@ await PromisePool
679
679
 
680
680
  ### 1. Unit Tests
681
681
 
682
- Testar métodos isolados:
683
- - `_detectProvider()` → Detecção correta de providers
684
- - `_shouldIncludeResource()` → Filtros funcionando
685
- - `_calculateDiff()` → Diff calculation correto
682
+ Test isolated methods:
683
+ - `_detectProvider()` → Correct provider detection
684
+ - `_shouldIncludeResource()` → Filters working
685
+ - `_calculateDiff()` → Correct diff calculation
686
686
 
687
687
  ### 2. Integration Tests
688
688
 
689
- Testar fluxos completos:
690
- - Import → Verificar resources criados
691
- - Import 2x → Verificar dedup funciona
692
- - Import v1 + v2 → Verificar diff criado
689
+ Test complete flows:
690
+ - Import → Verify resources created
691
+ - Import 2x → Verify dedup works
692
+ - Import v1 + v2 → Verify diff created
693
693
 
694
694
  ### 3. Partition Tests
695
695
 
696
- Testar queries usando partitions:
697
- - `getResourcesByType()` → Deve usar partition
698
- - `getResourcesByProvider()` → Deve usar partition
699
- - `getResourcesByProviderAndType()` → Deve usar partition combinada
696
+ Test queries using partitions:
697
+ - `getResourcesByType()` → Should use partition
698
+ - `getResourcesByProvider()` → Should use partition
699
+ - `getResourcesByProviderAndType()` → Should use combined partition
700
700
 
701
701
  ### 4. Performance Tests
702
702
 
703
- Verificar que partitions são rápidas:
703
+ Verify partitions are fast:
704
704
  - Import 1000 resources
705
- - Query por tipoDeve ser < 100ms
705
+ - Query by typeShould be < 100ms
706
706
 
707
707
  ---
708
708
 
709
709
  ## 🐛 Common Issues
710
710
 
711
- ### Issue: Partitions retornam vazio
711
+ ### Issue: Partitions return empty
712
712
 
713
- **Causa**: `asyncPartitions: true` (default)
713
+ **Cause**: `asyncPartitions: true` (default)
714
714
 
715
- **Solução**: Sempre usar `asyncPartitions: false` nos 3 resources
715
+ **Solution**: Always use `asyncPartitions: false` in all 3 resources
716
716
 
717
- ### Issue: Diff não está sendo criado
717
+ ### Issue: Diff not being created
718
718
 
719
- **Causa**: `trackDiffs: false` ou primeira versão do state
719
+ **Cause**: `trackDiffs: false` or first version of state
720
720
 
721
- **Solução**: Verificar que `trackDiffs: true` e que pelo menos 2 versões do state
721
+ **Solution**: Verify that `trackDiffs: true` and there are at least 2 versions of the state
722
722
 
723
- ### Issue: Provider detection errado
723
+ ### Issue: Wrong provider detection
724
724
 
725
- **Causa**: Provider não está no `providerMap`
725
+ **Cause**: Provider not in `providerMap`
726
726
 
727
- **Solução**: Adicionar provider ao map em `_detectProvider()`
727
+ **Solution**: Add provider to map in `_detectProvider()`
728
728
 
729
729
  ---
730
730
 
731
731
  ## 🚀 Future Enhancements
732
732
 
733
- 1. **Partial imports**: Importar apenas recursos modificados
734
- 2. **Compression**: Comprimir `attributes` JSON para economizar espaço
735
- 3. **Resource relationships**: Mapear dependências entre recursos
736
- 4. **Cost estimation**: Integrar com pricing APIs
737
- 5. **Compliance checks**: Validar recursos contra políticas
733
+ 1. **Partial imports**: Import only modified resources
734
+ 2. **Compression**: Compress `attributes` JSON to save space
735
+ 3. **Resource relationships**: Map dependencies between resources
736
+ 4. **Cost estimation**: Integrate with pricing APIs
737
+ 5. **Compliance checks**: Validate resources against policies
738
738
 
739
739
  ---
740
740
 
@@ -1,3 +1,5 @@
1
+ import { TfStateError } from './errors.js';
2
+
1
3
  /**
2
4
  * Base Driver Class for TfState Plugin
3
5
  *
@@ -14,7 +16,12 @@ export class TfStateDriver {
14
16
  * Called during plugin installation
15
17
  */
16
18
  async initialize() {
17
- throw new Error('Driver must implement initialize()');
19
+ throw new TfStateError('Driver must implement initialize()', {
20
+ operation: 'initialize',
21
+ statusCode: 501,
22
+ retriable: false,
23
+ suggestion: 'Extend TfStateDriver and implement initialize() to configure backend connections.'
24
+ });
18
25
  }
19
26
 
20
27
  /**
@@ -22,7 +29,12 @@ export class TfStateDriver {
22
29
  * @returns {Promise<Array>} Array of state file metadata { path, lastModified, size }
23
30
  */
24
31
  async listStateFiles() {
25
- throw new Error('Driver must implement listStateFiles()');
32
+ throw new TfStateError('Driver must implement listStateFiles()', {
33
+ operation: 'listStateFiles',
34
+ statusCode: 501,
35
+ retriable: false,
36
+ suggestion: 'Override listStateFiles() to return available Terraform state metadata.'
37
+ });
26
38
  }
27
39
 
28
40
  /**
@@ -31,7 +43,13 @@ export class TfStateDriver {
31
43
  * @returns {Promise<Object>} Parsed state file content
32
44
  */
33
45
  async readStateFile(path) {
34
- throw new Error('Driver must implement readStateFile()');
46
+ throw new TfStateError('Driver must implement readStateFile()', {
47
+ operation: 'readStateFile',
48
+ statusCode: 501,
49
+ retriable: false,
50
+ suggestion: 'Override readStateFile(path) to load and parse the Terraform state JSON.',
51
+ path
52
+ });
35
53
  }
36
54
 
37
55
  /**
@@ -40,7 +58,13 @@ export class TfStateDriver {
40
58
  * @returns {Promise<Object>} Metadata { path, lastModified, size, etag }
41
59
  */
42
60
  async getStateFileMetadata(path) {
43
- throw new Error('Driver must implement getStateFileMetadata()');
61
+ throw new TfStateError('Driver must implement getStateFileMetadata()', {
62
+ operation: 'getStateFileMetadata',
63
+ statusCode: 501,
64
+ retriable: false,
65
+ suggestion: 'Override getStateFileMetadata(path) to return lastModified, size, and ETag information.',
66
+ path
67
+ });
44
68
  }
45
69
 
46
70
  /**