ts-prorm-orm 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/CHANGELOG.md +1111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +573 -0
  4. package/dist/audit/history-query.js +180 -0
  5. package/dist/audit/index.js +23 -0
  6. package/dist/audit/logger.js +236 -0
  7. package/dist/cache/cache-manager.js +84 -0
  8. package/dist/cache/index.js +16 -0
  9. package/dist/cache/redis-cluster-cache.js +557 -0
  10. package/dist/cli.js +2200 -0
  11. package/dist/compliance/audit-trail.js +68 -0
  12. package/dist/compliance/backup-verification.js +685 -0
  13. package/dist/compliance/breach-detector.js +505 -0
  14. package/dist/compliance/consent-record.js +227 -0
  15. package/dist/compliance/consent-versioning.js +331 -0
  16. package/dist/compliance/cross-border-log.js +530 -0
  17. package/dist/compliance/data-classifier.js +258 -0
  18. package/dist/compliance/data-lineage.js +565 -0
  19. package/dist/compliance/data-masker.js +303 -0
  20. package/dist/compliance/data-portability.js +265 -0
  21. package/dist/compliance/data-retention.js +195 -0
  22. package/dist/compliance/dsar-workflow.js +342 -0
  23. package/dist/compliance/field-encryption.js +223 -0
  24. package/dist/compliance/immutable-record.js +148 -0
  25. package/dist/compliance/index.js +260 -0
  26. package/dist/compliance/privacy-impact-assessment.js +364 -0
  27. package/dist/compliance/pseudonymization.js +269 -0
  28. package/dist/compliance/query-firewall.js +1182 -0
  29. package/dist/compliance/rate-limiter.js +580 -0
  30. package/dist/compliance/right-to-erasure.js +117 -0
  31. package/dist/compliance/row-level-security.js +246 -0
  32. package/dist/compliance/security-decorator.js +574 -0
  33. package/dist/compliance/security-monitor.js +525 -0
  34. package/dist/compliance/sensitive-data-discovery.js +476 -0
  35. package/dist/compliance/session-isolation.js +472 -0
  36. package/dist/compliance/tls-enforcer.js +108 -0
  37. package/dist/compliance/worm-storage.js +712 -0
  38. package/dist/connection-manager.js +198 -0
  39. package/dist/connection-pool.js +519 -0
  40. package/dist/decorators/audit.js +136 -0
  41. package/dist/decorators/belongs-to-many.js +115 -0
  42. package/dist/decorators/belongs-to.js +115 -0
  43. package/dist/decorators/check.js +435 -0
  44. package/dist/decorators/collate.js +329 -0
  45. package/dist/decorators/comment.js +205 -0
  46. package/dist/decorators/database-settings.js +236 -0
  47. package/dist/decorators/default.js +244 -0
  48. package/dist/decorators/encryption.js +235 -0
  49. package/dist/decorators/engine.js +97 -0
  50. package/dist/decorators/fk-constraints.js +594 -0
  51. package/dist/decorators/foreign-table.js +136 -0
  52. package/dist/decorators/generated.js +274 -0
  53. package/dist/decorators/has-many.js +127 -0
  54. package/dist/decorators/has-one.js +116 -0
  55. package/dist/decorators/hstore.js +129 -0
  56. package/dist/decorators/index.js +355 -0
  57. package/dist/decorators/json-column.js +83 -0
  58. package/dist/decorators/jsonb.js +101 -0
  59. package/dist/decorators/orm-decorators.js +425 -0
  60. package/dist/decorators/permissions.js +294 -0
  61. package/dist/decorators/procedure.js +210 -0
  62. package/dist/decorators/query-options.js +556 -0
  63. package/dist/decorators/range.js +167 -0
  64. package/dist/decorators/set-column.js +83 -0
  65. package/dist/decorators/spatial.js +114 -0
  66. package/dist/decorators/storage.js +580 -0
  67. package/dist/decorators/timezone.js +512 -0
  68. package/dist/decorators/trigger.js +90 -0
  69. package/dist/decorators/uuid.js +135 -0
  70. package/dist/decorators/view.js +258 -0
  71. package/dist/diagrams/chen-diagram.js +354 -0
  72. package/dist/diagrams/class-diagram.js +384 -0
  73. package/dist/diagrams/dependency-diagram.js +432 -0
  74. package/dist/diagrams/er-diagram.js +605 -0
  75. package/dist/diagrams/flow-diagram.js +394 -0
  76. package/dist/diagrams/gantt-diagram.js +411 -0
  77. package/dist/diagrams/index-diagram.js +353 -0
  78. package/dist/diagrams/index.js +184 -0
  79. package/dist/diagrams/migration-diagram.js +316 -0
  80. package/dist/diagrams/model-diagram.js +616 -0
  81. package/dist/diagrams/package-diagram.js +376 -0
  82. package/dist/diagrams/palette.js +85 -0
  83. package/dist/diagrams/relational-diagram.js +455 -0
  84. package/dist/diagrams/schemadoc-diagram.js +309 -0
  85. package/dist/diagrams/sequence-diagram.js +307 -0
  86. package/dist/diagrams/state-diagram.js +344 -0
  87. package/dist/diagrams/svg-dom.js +111 -0
  88. package/dist/diagrams/tree-diagram.js +250 -0
  89. package/dist/dialects/clickhouse/index.js +1742 -0
  90. package/dist/dialects/cockroachdb/index.js +4677 -0
  91. package/dist/dialects/cratedb/index.js +441 -0
  92. package/dist/dialects/databricks/index.js +517 -0
  93. package/dist/dialects/db2/index.js +2225 -0
  94. package/dist/dialects/dialect.js +720 -0
  95. package/dist/dialects/duckdb/index.js +2014 -0
  96. package/dist/dialects/exasol/index.js +357 -0
  97. package/dist/dialects/firebird/index.js +495 -0
  98. package/dist/dialects/greenplum/index.js +457 -0
  99. package/dist/dialects/hana/index.js +1741 -0
  100. package/dist/dialects/mariadb/index.js +3590 -0
  101. package/dist/dialects/mssql/index.js +2296 -0
  102. package/dist/dialects/mysql/index.js +4058 -0
  103. package/dist/dialects/oracle/index.js +2999 -0
  104. package/dist/dialects/postgres/index.js +5319 -0
  105. package/dist/dialects/query-stream-helper.js +152 -0
  106. package/dist/dialects/questdb/index.js +433 -0
  107. package/dist/dialects/redshift/index.js +2277 -0
  108. package/dist/dialects/singlestore/index.js +354 -0
  109. package/dist/dialects/snowflake/index.js +2082 -0
  110. package/dist/dialects/spanner/index.js +1768 -0
  111. package/dist/dialects/sqlite/index.js +3382 -0
  112. package/dist/dialects/tidb/index.js +377 -0
  113. package/dist/dialects/timescaledb/index.js +164 -0
  114. package/dist/dialects/trino/index.js +420 -0
  115. package/dist/dialects/turso/index.js +227 -0
  116. package/dist/dialects/vertica/index.js +317 -0
  117. package/dist/dialects/yugabytedb/index.js +424 -0
  118. package/dist/errors/index.js +472 -0
  119. package/dist/errors/utils.js +340 -0
  120. package/dist/errors.js +21 -0
  121. package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
  122. package/dist/extensions/catalog/mssql-features.js +147 -0
  123. package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
  124. package/dist/extensions/catalog/oracle-db2-features.js +196 -0
  125. package/dist/extensions/catalog/postgres-extensions.js +516 -0
  126. package/dist/extensions/index.js +71 -0
  127. package/dist/extensions/types.js +13 -0
  128. package/dist/foreign-data.js +173 -0
  129. package/dist/hooks/hooks-manager.js +350 -0
  130. package/dist/hooks/index.js +37 -0
  131. package/dist/index.js +463 -0
  132. package/dist/logging.js +335 -0
  133. package/dist/migrations/index.js +40 -0
  134. package/dist/migrations/migration.js +196 -0
  135. package/dist/migrations/migrator.js +411 -0
  136. package/dist/migrations/prormmigration.js +275 -0
  137. package/dist/migrations/query-interface.js +435 -0
  138. package/dist/migrations/seeder.js +353 -0
  139. package/dist/models/associations.js +852 -0
  140. package/dist/models/constraints.js +288 -0
  141. package/dist/models/data-types.js +2518 -0
  142. package/dist/models/decorators.js +445 -0
  143. package/dist/models/index.js +33 -0
  144. package/dist/models/indexes.js +531 -0
  145. package/dist/models/methods.js +382 -0
  146. package/dist/models/model-manager.js +103 -0
  147. package/dist/models/model.js +5349 -0
  148. package/dist/models/operators.js +67 -0
  149. package/dist/models/scopes.js +189 -0
  150. package/dist/models/typescript-types.js +26 -0
  151. package/dist/nosql/aerospike/index.js +205 -0
  152. package/dist/nosql/allegrograph/index.js +169 -0
  153. package/dist/nosql/arangodb/index.js +364 -0
  154. package/dist/nosql/azure-blob/index.js +206 -0
  155. package/dist/nosql/beanstalkd/index.js +231 -0
  156. package/dist/nosql/beequeue/index.js +210 -0
  157. package/dist/nosql/bigchaindb/index.js +195 -0
  158. package/dist/nosql/bigtable/index.js +224 -0
  159. package/dist/nosql/blazegraph/index.js +173 -0
  160. package/dist/nosql/bullmq/index.js +191 -0
  161. package/dist/nosql/cassandra/index.js +174 -0
  162. package/dist/nosql/chroma/index.js +190 -0
  163. package/dist/nosql/cloudflare-kv/index.js +220 -0
  164. package/dist/nosql/coherence/index.js +200 -0
  165. package/dist/nosql/cosmosdb/index.js +157 -0
  166. package/dist/nosql/couchbase/index.js +213 -0
  167. package/dist/nosql/dax/index.js +212 -0
  168. package/dist/nosql/deno-kv/index.js +206 -0
  169. package/dist/nosql/dgraph/index.js +171 -0
  170. package/dist/nosql/doris/index.js +169 -0
  171. package/dist/nosql/druid/index.js +162 -0
  172. package/dist/nosql/dynamodb/index.js +937 -0
  173. package/dist/nosql/elasticsearch/index.js +377 -0
  174. package/dist/nosql/etcd/index.js +502 -0
  175. package/dist/nosql/eventhubs/index.js +213 -0
  176. package/dist/nosql/eventstore/index.js +254 -0
  177. package/dist/nosql/faunadb/index.js +188 -0
  178. package/dist/nosql/firestore/index.js +177 -0
  179. package/dist/nosql/fluree/index.js +148 -0
  180. package/dist/nosql/fuseki/index.js +170 -0
  181. package/dist/nosql/gcs/index.js +172 -0
  182. package/dist/nosql/gearman/index.js +160 -0
  183. package/dist/nosql/geode/index.js +196 -0
  184. package/dist/nosql/graphdb/index.js +169 -0
  185. package/dist/nosql/graylog/index.js +188 -0
  186. package/dist/nosql/gridgain/index.js +171 -0
  187. package/dist/nosql/hazelcast/index.js +162 -0
  188. package/dist/nosql/hbase/index.js +230 -0
  189. package/dist/nosql/ignite/index.js +173 -0
  190. package/dist/nosql/immudb/index.js +184 -0
  191. package/dist/nosql/index.js +232 -0
  192. package/dist/nosql/infinispan/index.js +200 -0
  193. package/dist/nosql/influxdb/index.js +0 -0
  194. package/dist/nosql/kafka/index.js +234 -0
  195. package/dist/nosql/keyspaces/index.js +189 -0
  196. package/dist/nosql/kinesis/index.js +253 -0
  197. package/dist/nosql/leveldb/index.js +153 -0
  198. package/dist/nosql/lmdb/index.js +160 -0
  199. package/dist/nosql/loki/index.js +201 -0
  200. package/dist/nosql/marklogic/index.js +204 -0
  201. package/dist/nosql/materialize/index.js +145 -0
  202. package/dist/nosql/meilisearch/index.js +154 -0
  203. package/dist/nosql/memcached/index.js +223 -0
  204. package/dist/nosql/milvus/index.js +410 -0
  205. package/dist/nosql/minio/index.js +265 -0
  206. package/dist/nosql/momento/index.js +179 -0
  207. package/dist/nosql/mongodb/index.js +461 -0
  208. package/dist/nosql/nats/index.js +247 -0
  209. package/dist/nosql/nedb/index.js +164 -0
  210. package/dist/nosql/neo4j/index.js +450 -0
  211. package/dist/nosql/neptune/index.js +470 -0
  212. package/dist/nosql/nsq/index.js +200 -0
  213. package/dist/nosql/opensearch/index.js +186 -0
  214. package/dist/nosql/orientdb/index.js +175 -0
  215. package/dist/nosql/papertrail/index.js +200 -0
  216. package/dist/nosql/pinecone/index.js +0 -0
  217. package/dist/nosql/pinot/index.js +133 -0
  218. package/dist/nosql/pouchdb/index.js +172 -0
  219. package/dist/nosql/prometheus/index.js +174 -0
  220. package/dist/nosql/provendb/index.js +147 -0
  221. package/dist/nosql/pubsub/index.js +187 -0
  222. package/dist/nosql/pulsar/index.js +232 -0
  223. package/dist/nosql/qdrant/index.js +295 -0
  224. package/dist/nosql/qldb/index.js +192 -0
  225. package/dist/nosql/r2/index.js +281 -0
  226. package/dist/nosql/rabbitmq/index.js +237 -0
  227. package/dist/nosql/ravendb/index.js +175 -0
  228. package/dist/nosql/redis/index.js +607 -0
  229. package/dist/nosql/redpanda/index.js +237 -0
  230. package/dist/nosql/resque/index.js +203 -0
  231. package/dist/nosql/rethinkdb/index.js +232 -0
  232. package/dist/nosql/rocksdb/index.js +152 -0
  233. package/dist/nosql/rockset/index.js +126 -0
  234. package/dist/nosql/s3/index.js +298 -0
  235. package/dist/nosql/scylladb/index.js +178 -0
  236. package/dist/nosql/signoz/index.js +227 -0
  237. package/dist/nosql/sns/index.js +201 -0
  238. package/dist/nosql/solr/index.js +231 -0
  239. package/dist/nosql/splunk/index.js +227 -0
  240. package/dist/nosql/sqs/index.js +246 -0
  241. package/dist/nosql/stardog/index.js +169 -0
  242. package/dist/nosql/starrocks/index.js +170 -0
  243. package/dist/nosql/store.js +2 -0
  244. package/dist/nosql/sumologic/index.js +213 -0
  245. package/dist/nosql/surrealdb/index.js +179 -0
  246. package/dist/nosql/terminusdb/index.js +151 -0
  247. package/dist/nosql/tigergraph/index.js +469 -0
  248. package/dist/nosql/typesense/index.js +148 -0
  249. package/dist/nosql/unqlite/index.js +157 -0
  250. package/dist/nosql/upstash/index.js +167 -0
  251. package/dist/nosql/vercel-kv/index.js +166 -0
  252. package/dist/nosql/victoriametrics/index.js +213 -0
  253. package/dist/nosql/virtuoso/index.js +169 -0
  254. package/dist/nosql/weaviate/index.js +276 -0
  255. package/dist/operators/index.js +108 -0
  256. package/dist/operators.js +2690 -0
  257. package/dist/prisma-migrate/index.js +38 -0
  258. package/dist/prisma-migrate/migration-generator.js +125 -0
  259. package/dist/prisma-migrate/model-generator.js +172 -0
  260. package/dist/prisma-migrate/relations.js +100 -0
  261. package/dist/prisma-migrate/schema-parser.js +167 -0
  262. package/dist/prisma-migrate/type-mapper.js +40 -0
  263. package/dist/prorm.js +6832 -0
  264. package/dist/query-builders/cte-builder.js +80 -0
  265. package/dist/query-builders/functions/aggregate.js +390 -0
  266. package/dist/query-builders/functions/conditional.js +503 -0
  267. package/dist/query-builders/functions/datetime.js +695 -0
  268. package/dist/query-builders/functions/fulltext.js +439 -0
  269. package/dist/query-builders/functions/index.js +93 -0
  270. package/dist/query-builders/functions/json.js +427 -0
  271. package/dist/query-builders/functions/math.js +399 -0
  272. package/dist/query-builders/functions/string.js +518 -0
  273. package/dist/query-builders/functions/window.js +328 -0
  274. package/dist/query-builders/include-builder.js +323 -0
  275. package/dist/query-builders/index-expression-builder.js +242 -0
  276. package/dist/query-builders/index.js +161 -0
  277. package/dist/query-builders/insert-builder.js +164 -0
  278. package/dist/query-builders/model-helpers.js +38 -0
  279. package/dist/query-builders/order-limit-builder.js +239 -0
  280. package/dist/query-builders/sql-compiler.js +2040 -0
  281. package/dist/query-builders/subquery-builder.js +152 -0
  282. package/dist/query-builders/update-builder.js +182 -0
  283. package/dist/query-builders/view-builder.js +218 -0
  284. package/dist/query-builders/where-builder.js +1532 -0
  285. package/dist/query-interface.js +622 -0
  286. package/dist/query-optimizers/batch-optimizer.js +426 -0
  287. package/dist/query-optimizers/explain-plans.js +415 -0
  288. package/dist/query-optimizers/index.js +51 -0
  289. package/dist/query-optimizers/prepared-statement-cache.js +423 -0
  290. package/dist/query-optimizers/query-hints.js +438 -0
  291. package/dist/query-optimizers/query-optimizer.js +278 -0
  292. package/dist/query-optimizers/slow-query-logger.js +271 -0
  293. package/dist/replica-manager.js +507 -0
  294. package/dist/schema/index.js +15 -0
  295. package/dist/schema/migration-generator.js +374 -0
  296. package/dist/schema/schema-differ.js +549 -0
  297. package/dist/schema/types.js +6 -0
  298. package/dist/sql-constants.js +300 -0
  299. package/dist/sqlite-advanced.js +1047 -0
  300. package/dist/streams/index.js +12 -0
  301. package/dist/streams/transforms.js +178 -0
  302. package/dist/transaction.js +456 -0
  303. package/dist/types/index.js +180 -0
  304. package/dist/user-management.js +127 -0
  305. package/dist/utils/date.js +300 -0
  306. package/dist/utils/index.js +1079 -0
  307. package/dist/utils/string.js +161 -0
  308. package/dist/validators/index.js +19 -0
  309. package/dist/validators/validator.js +911 -0
  310. package/package.json +190 -0
@@ -0,0 +1,505 @@
1
+ "use strict";
2
+ /**
3
+ * BreachDetector
4
+ *
5
+ * A comprehensive breach detection and monitoring system for identifying
6
+ * unusual access patterns, mass exports, failed authentication attempts,
7
+ * and suspicious query patterns.
8
+ *
9
+ * Required for compliance with:
10
+ * - NIST CSF (PR.AC-1, PR.AC-2, PR.DS-5)
11
+ * - CIS Controls (CIS 3.4, 8.2, 8.5)
12
+ * - MITRE ATT&CK (TA0001, TA0009, TA0010)
13
+ *
14
+ * Usage:
15
+ * // Initialize breach detection
16
+ * const detector = BreachDetector.create(prorm, {
17
+ * alertCallback: (alert) => securityTeam.notify(alert),
18
+ * massExportThreshold: 1000,
19
+ * rateLimitWindow: 60000,
20
+ * rateLimitMax: 100,
21
+ * });
22
+ *
23
+ * // Start monitoring
24
+ * await detector.start();
25
+ *
26
+ * // Query alerts and stats
27
+ * const alerts = detector.getAlerts();
28
+ * const stats = detector.getStats();
29
+ */
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.BreachDetector = void 0;
32
+ exports.getGlobalBreachDetector = getGlobalBreachDetector;
33
+ exports.initBreachDetector = initBreachDetector;
34
+ // ==================== Suspicious Query Patterns ====================
35
+ const SUSPICIOUS_PATTERNS = [
36
+ /(\bunion\b.*\bselect\b)/i,
37
+ /(\bselect\b.*\bfrom\b.*\bwhere\b)/i,
38
+ /(exec\s*\()/i,
39
+ /(execute\s*\()/i,
40
+ /(load_file\s*\()/i,
41
+ /(into\s+outfile)/i,
42
+ /(concat\s*\()/i,
43
+ /(substring\s*\()/i,
44
+ /(sleep\s*\()/i,
45
+ /(waitfor\s+delay)/i,
46
+ /(0x[0-9a-f]+)/i,
47
+ /(\bor\b.*\b1\s*=\s*1)/i,
48
+ /('\s*or\s*'1'\s*=\s*'1)/i,
49
+ /(\/\*.*\*\/)/,
50
+ /(--\s*)/,
51
+ /(char\s*\(\s*\d+)/,
52
+ ];
53
+ // ==================== BreachDetector Class ====================
54
+ class BreachDetector {
55
+ constructor(prorm, options) {
56
+ this.alerts = [];
57
+ this.isRunning = false;
58
+ this.originalQuery = null;
59
+ this.queryTimestamps = new Map();
60
+ this.failedAuthAttempts = new Map();
61
+ this.accessPatterns = new Map();
62
+ this.stats = {
63
+ totalQueries: 0,
64
+ massExportAlerts: 0,
65
+ failedAuthAlerts: 0,
66
+ rateLimitAlerts: 0,
67
+ unusualTimeAlerts: 0,
68
+ suspiciousPatternAlerts: 0,
69
+ bulkDownloadAlerts: 0,
70
+ };
71
+ this.prorm = prorm;
72
+ this.options = {
73
+ alertCallback: options.alertCallback ?? (() => { }),
74
+ massExportThreshold: options.massExportThreshold ?? 1000,
75
+ rateLimitWindow: options.rateLimitWindow ?? 60000,
76
+ rateLimitMax: options.rateLimitMax ?? 100,
77
+ failedAuthThreshold: options.failedAuthThreshold ?? 5,
78
+ failedAuthWindow: options.failedAuthWindow ?? 300000,
79
+ detectUnusualAccessTime: options.detectUnusualAccessTime ?? true,
80
+ allowedHours: options.allowedHours ?? [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
81
+ detectSuspiciousPatterns: options.detectSuspiciousPatterns ?? true,
82
+ maxAlerts: options.maxAlerts ?? 1000,
83
+ minAlertSeverity: options.minAlertSeverity ?? 'medium',
84
+ customPatterns: options.customPatterns ?? [],
85
+ trackByUser: options.trackByUser ?? true,
86
+ trackByIP: options.trackByIP ?? true,
87
+ };
88
+ this.startTime = new Date();
89
+ }
90
+ // ==================== Factory Method ====================
91
+ /**
92
+ * Create a new BreachDetector instance
93
+ */
94
+ static create(prorm, options = {}) {
95
+ return new BreachDetector(prorm, options);
96
+ }
97
+ // ==================== Lifecycle ====================
98
+ /**
99
+ * Start monitoring queries for breaches
100
+ */
101
+ async start() {
102
+ if (this.isRunning)
103
+ return;
104
+ this.isRunning = true;
105
+ // Hook into Prorm query method
106
+ this.originalQuery = this.prorm.query;
107
+ this.prorm.query = async (...args) => {
108
+ const startTime = Date.now();
109
+ const query = typeof args[0] === 'string' ? args[0] : args[0]?.sql ?? '';
110
+ const queryOptions = args[1];
111
+ try {
112
+ const result = await this.originalQuery.apply(this.prorm, args);
113
+ const duration = Date.now() - startTime;
114
+ this.stats.totalQueries++;
115
+ this.analyzeQuery(query, queryOptions, duration, result?.length ?? result?.rows?.length ?? 0);
116
+ return result;
117
+ }
118
+ catch (error) {
119
+ this.analyzeError(query, queryOptions, error);
120
+ throw error;
121
+ }
122
+ };
123
+ // Setup model hooks for bulk operations
124
+ this.setupBulkOperationHooks();
125
+ }
126
+ /**
127
+ * Stop monitoring
128
+ */
129
+ stop() {
130
+ if (!this.isRunning)
131
+ return;
132
+ this.isRunning = false;
133
+ if (this.originalQuery) {
134
+ this.prorm.query = this.originalQuery;
135
+ this.originalQuery = null;
136
+ }
137
+ }
138
+ /**
139
+ * Setup hooks for bulk operation monitoring
140
+ */
141
+ setupBulkOperationHooks() {
142
+ const models = this.prorm.getModels?.() ?? [];
143
+ for (const [, Model] of models) {
144
+ // Monitor bulk create operations
145
+ Model.hook('beforeBulkCreate', 'breachDetector:bulkCreate', (instances) => {
146
+ this.checkBulkOperation(instances.length, Model.name, 'create');
147
+ });
148
+ // Monitor bulk update operations
149
+ Model.hook('beforeBulkUpdate', 'breachDetector:bulkUpdate', (opts) => {
150
+ const count = opts.limit ?? 'all';
151
+ this.checkBulkOperation(typeof count === 'number' ? count : 1000, Model.name, 'update');
152
+ });
153
+ // Monitor bulk destroy operations
154
+ Model.hook('beforeBulkDestroy', 'breachDetector:bulkDestroy', (opts) => {
155
+ this.checkBulkOperation(opts.limit ?? 1000, Model.name, 'delete');
156
+ });
157
+ }
158
+ }
159
+ // ==================== Analysis Methods ====================
160
+ /**
161
+ * Analyze a query for breach patterns
162
+ */
163
+ analyzeQuery(query, queryOptions, duration, recordsAffected) {
164
+ const userId = queryOptions?.__userId;
165
+ const ipAddress = queryOptions?.__ipAddress;
166
+ // Check for mass export
167
+ if (recordsAffected > this.options.massExportThreshold) {
168
+ this.addAlert({
169
+ severity: 'high',
170
+ category: 'mass_export',
171
+ message: `Mass export detected: ${recordsAffected} records exported in single query`,
172
+ details: {
173
+ recordsAffected,
174
+ threshold: this.options.massExportThreshold,
175
+ duration,
176
+ },
177
+ userId,
178
+ ipAddress,
179
+ query,
180
+ });
181
+ this.stats.massExportAlerts++;
182
+ }
183
+ // Check for bulk download
184
+ if (query.toUpperCase().includes('SELECT') && recordsAffected > 100) {
185
+ this.addAlert({
186
+ severity: 'medium',
187
+ category: 'bulk_download',
188
+ message: `Bulk download detected: ${recordsAffected} records requested`,
189
+ details: {
190
+ recordsAffected,
191
+ duration,
192
+ },
193
+ userId,
194
+ ipAddress,
195
+ query,
196
+ });
197
+ this.stats.bulkDownloadAlerts++;
198
+ }
199
+ // Rate limiting per user/IP
200
+ this.checkRateLimit(userId, ipAddress);
201
+ // Unusual access time detection
202
+ if (this.options.detectUnusualAccessTime) {
203
+ this.checkUnusualAccessTime(userId, ipAddress);
204
+ }
205
+ // Suspicious query pattern detection
206
+ if (this.options.detectSuspiciousPatterns) {
207
+ this.checkSuspiciousPatterns(query, userId, ipAddress);
208
+ }
209
+ }
210
+ /**
211
+ * Analyze errors for security events
212
+ */
213
+ analyzeError(query, queryOptions, error) {
214
+ const userId = queryOptions?.__userId;
215
+ const ipAddress = queryOptions?.__ipAddress;
216
+ const message = error?.message ?? '';
217
+ // Detect failed authentication
218
+ if (message.includes('authentication') ||
219
+ message.includes('login') ||
220
+ message.includes('password') ||
221
+ message.includes('credential')) {
222
+ this.trackFailedAuth(userId, ipAddress);
223
+ }
224
+ // Access denied patterns
225
+ if (message.includes('permission denied') || message.includes('access denied')) {
226
+ this.addAlert({
227
+ severity: 'high',
228
+ category: 'failed_auth',
229
+ message: 'Access denied detected',
230
+ details: { error: message.substring(0, 200) },
231
+ userId,
232
+ ipAddress,
233
+ query,
234
+ });
235
+ this.stats.failedAuthAlerts++;
236
+ }
237
+ }
238
+ /**
239
+ * Check for bulk operations
240
+ */
241
+ checkBulkOperation(count, modelName, operation) {
242
+ if (count > this.options.massExportThreshold) {
243
+ this.addAlert({
244
+ severity: 'high',
245
+ category: 'mass_export',
246
+ message: `Bulk ${operation} operation detected on ${modelName}: ${count} records`,
247
+ details: {
248
+ count,
249
+ model: modelName,
250
+ operation,
251
+ threshold: this.options.massExportThreshold,
252
+ },
253
+ });
254
+ this.stats.massExportAlerts++;
255
+ }
256
+ }
257
+ /**
258
+ * Check rate limiting
259
+ */
260
+ checkRateLimit(userId, ipAddress) {
261
+ const key = this.getIdentifierKey(userId, ipAddress);
262
+ const now = Date.now();
263
+ let records = this.queryTimestamps.get(key) ?? [];
264
+ const windowStart = now - this.options.rateLimitWindow;
265
+ // Filter to current window
266
+ records = records.filter(r => r.timestamp > windowStart);
267
+ if (records.length >= this.options.rateLimitMax) {
268
+ this.addAlert({
269
+ severity: 'critical',
270
+ category: 'rate_limit_exceeded',
271
+ message: `Rate limit exceeded for ${key}: ${records.length} queries in ${this.options.rateLimitWindow}ms`,
272
+ details: {
273
+ queryCount: records.length,
274
+ windowMs: this.options.rateLimitWindow,
275
+ maxAllowed: this.options.rateLimitMax,
276
+ },
277
+ userId,
278
+ ipAddress,
279
+ });
280
+ this.stats.rateLimitAlerts++;
281
+ }
282
+ // Add current query
283
+ records.push({ timestamp: now, count: 1, userId, ipAddress });
284
+ this.queryTimestamps.set(key, records);
285
+ }
286
+ /**
287
+ * Check for unusual access time
288
+ */
289
+ checkUnusualAccessTime(userId, ipAddress) {
290
+ const hour = new Date().getHours();
291
+ if (!this.options.allowedHours.includes(hour)) {
292
+ this.addAlert({
293
+ severity: 'medium',
294
+ category: 'unusual_access_time',
295
+ message: `Unusual access time detected: ${hour}:00 hours`,
296
+ details: {
297
+ hour,
298
+ allowedHours: this.options.allowedHours,
299
+ },
300
+ userId,
301
+ ipAddress,
302
+ });
303
+ this.stats.unusualTimeAlerts++;
304
+ }
305
+ }
306
+ /**
307
+ * Check for suspicious query patterns
308
+ */
309
+ checkSuspiciousPatterns(query, userId, ipAddress) {
310
+ const allPatterns = [...SUSPICIOUS_PATTERNS, ...this.options.customPatterns];
311
+ for (const pattern of allPatterns) {
312
+ if (pattern.test(query)) {
313
+ this.addAlert({
314
+ severity: 'high',
315
+ category: 'suspicious_query_pattern',
316
+ message: `Suspicious query pattern detected: ${pattern.source}`,
317
+ details: {
318
+ pattern: pattern.source,
319
+ },
320
+ userId,
321
+ ipAddress,
322
+ query,
323
+ });
324
+ this.stats.suspiciousPatternAlerts++;
325
+ break;
326
+ }
327
+ }
328
+ }
329
+ /**
330
+ * Track failed authentication attempts
331
+ */
332
+ trackFailedAuth(userId, ipAddress) {
333
+ const key = this.getIdentifierKey(userId, ipAddress);
334
+ const now = Date.now();
335
+ const windowStart = now - this.options.failedAuthWindow;
336
+ let attempts = this.failedAuthAttempts.get(key) ?? [];
337
+ attempts = attempts.filter(t => t > windowStart);
338
+ if (attempts.length >= this.options.failedAuthThreshold) {
339
+ this.addAlert({
340
+ severity: 'critical',
341
+ category: 'failed_auth',
342
+ message: `Multiple failed authentication attempts: ${attempts.length} attempts`,
343
+ details: {
344
+ attemptCount: attempts.length,
345
+ windowMs: this.options.failedAuthWindow,
346
+ threshold: this.options.failedAuthThreshold,
347
+ },
348
+ userId,
349
+ ipAddress,
350
+ });
351
+ this.stats.failedAuthAlerts++;
352
+ }
353
+ attempts.push(now);
354
+ this.failedAuthAttempts.set(key, attempts);
355
+ }
356
+ /**
357
+ * Get identifier key for rate limiting
358
+ */
359
+ getIdentifierKey(userId, ipAddress) {
360
+ if (userId && this.options.trackByUser)
361
+ return `user:${userId}`;
362
+ if (ipAddress && this.options.trackByIP)
363
+ return `ip:${ipAddress}`;
364
+ return 'anonymous';
365
+ }
366
+ // ==================== Alert Management ====================
367
+ /**
368
+ * Add an alert
369
+ */
370
+ addAlert(alert) {
371
+ const fullAlert = {
372
+ ...alert,
373
+ id: `breach-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
374
+ timestamp: new Date(),
375
+ };
376
+ this.alerts.push(fullAlert);
377
+ // Trim old alerts
378
+ if (this.alerts.length > this.options.maxAlerts) {
379
+ this.alerts = this.alerts.slice(-this.options.maxAlerts);
380
+ }
381
+ // Trigger callback if severity meets threshold
382
+ if (this.shouldTriggerCallback(fullAlert.severity)) {
383
+ this.options.alertCallback(fullAlert);
384
+ }
385
+ }
386
+ /**
387
+ * Check if alert severity meets callback threshold
388
+ */
389
+ shouldTriggerCallback(severity) {
390
+ const severityOrder = ['low', 'medium', 'high', 'critical'];
391
+ return severityOrder.indexOf(severity) >= severityOrder.indexOf(this.options.minAlertSeverity);
392
+ }
393
+ // ==================== Public API ====================
394
+ /**
395
+ * Get all breach alerts
396
+ */
397
+ getAlerts(options) {
398
+ let filtered = [...this.alerts];
399
+ if (options?.severity) {
400
+ filtered = filtered.filter(a => a.severity === options.severity);
401
+ }
402
+ if (options?.category) {
403
+ filtered = filtered.filter(a => a.category === options.category);
404
+ }
405
+ if (options?.limit) {
406
+ filtered = filtered.slice(-options.limit);
407
+ }
408
+ return filtered;
409
+ }
410
+ /**
411
+ * Get detection statistics
412
+ */
413
+ getStats() {
414
+ const alertsBySeverity = {
415
+ low: 0,
416
+ medium: 0,
417
+ high: 0,
418
+ critical: 0,
419
+ };
420
+ const alertsByCategory = {
421
+ mass_export: 0,
422
+ failed_auth: 0,
423
+ unusual_access_time: 0,
424
+ rate_limit_exceeded: 0,
425
+ suspicious_query_pattern: 0,
426
+ bulk_download: 0,
427
+ };
428
+ for (const alert of this.alerts) {
429
+ alertsBySeverity[alert.severity]++;
430
+ alertsByCategory[alert.category]++;
431
+ }
432
+ return {
433
+ uptime: Date.now() - this.startTime.getTime(),
434
+ totalQueries: this.stats.totalQueries,
435
+ totalAlerts: this.alerts.length,
436
+ massExportAlerts: this.stats.massExportAlerts,
437
+ failedAuthAlerts: this.stats.failedAuthAlerts,
438
+ rateLimitAlerts: this.stats.rateLimitAlerts,
439
+ unusualTimeAlerts: this.stats.unusualTimeAlerts,
440
+ suspiciousPatternAlerts: this.stats.suspiciousPatternAlerts,
441
+ bulkDownloadAlerts: this.stats.bulkDownloadAlerts,
442
+ alertsBySeverity,
443
+ alertsByCategory,
444
+ };
445
+ }
446
+ /**
447
+ * Clear all alerts
448
+ */
449
+ clearAlerts() {
450
+ this.alerts = [];
451
+ }
452
+ /**
453
+ * Check if monitoring is active
454
+ */
455
+ isActive() {
456
+ return this.isRunning;
457
+ }
458
+ /**
459
+ * Manually trigger an alert (for custom checks)
460
+ */
461
+ alert(options) {
462
+ this.addAlert(options);
463
+ }
464
+ /**
465
+ * Record a query execution (for external tracking)
466
+ */
467
+ recordQuery(userId, ipAddress, recordsAffected) {
468
+ this.stats.totalQueries++;
469
+ const key = this.getIdentifierKey(userId, ipAddress);
470
+ this.checkRateLimit(userId, ipAddress);
471
+ if (recordsAffected && recordsAffected > this.options.massExportThreshold) {
472
+ this.addAlert({
473
+ severity: 'high',
474
+ category: 'mass_export',
475
+ message: `Mass export detected: ${recordsAffected} records`,
476
+ details: { recordsAffected, threshold: this.options.massExportThreshold },
477
+ userId,
478
+ ipAddress,
479
+ });
480
+ this.stats.massExportAlerts++;
481
+ }
482
+ }
483
+ /**
484
+ * Record authentication failure
485
+ */
486
+ recordAuthFailure(userId, ipAddress) {
487
+ this.trackFailedAuth(userId, ipAddress);
488
+ }
489
+ }
490
+ exports.BreachDetector = BreachDetector;
491
+ // ==================== Global Instance ====================
492
+ let globalDetector = null;
493
+ /**
494
+ * Get the global BreachDetector instance
495
+ */
496
+ function getGlobalBreachDetector() {
497
+ return globalDetector;
498
+ }
499
+ /**
500
+ * Initialize the global BreachDetector instance
501
+ */
502
+ function initBreachDetector(prorm, options) {
503
+ globalDetector = BreachDetector.create(prorm, options);
504
+ return globalDetector;
505
+ }