@ansvar/eu-regulations-mcp 0.6.5 → 0.7.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 (83) hide show
  1. package/README.md +18 -27
  2. package/data/regulations.db +0 -0
  3. package/dist/database/postgres-adapter.d.ts +3 -0
  4. package/dist/database/postgres-adapter.d.ts.map +1 -0
  5. package/dist/database/postgres-adapter.js +65 -0
  6. package/dist/database/postgres-adapter.js.map +1 -0
  7. package/dist/database/sqlite-adapter.d.ts +8 -0
  8. package/dist/database/sqlite-adapter.d.ts.map +1 -0
  9. package/dist/database/sqlite-adapter.js +40 -0
  10. package/dist/database/sqlite-adapter.js.map +1 -0
  11. package/dist/database/types.d.ts +10 -0
  12. package/dist/database/types.d.ts.map +1 -0
  13. package/dist/database/types.js +2 -0
  14. package/dist/database/types.js.map +1 -0
  15. package/dist/http-server.js +3 -1
  16. package/dist/http-server.js.map +1 -1
  17. package/dist/index.js +12 -7
  18. package/dist/index.js.map +1 -1
  19. package/dist/middleware/rate-limit.d.ts +47 -0
  20. package/dist/middleware/rate-limit.d.ts.map +1 -0
  21. package/dist/middleware/rate-limit.js +85 -0
  22. package/dist/middleware/rate-limit.js.map +1 -0
  23. package/dist/tools/applicability.d.ts +2 -2
  24. package/dist/tools/applicability.d.ts.map +1 -1
  25. package/dist/tools/applicability.js +18 -18
  26. package/dist/tools/applicability.js.map +1 -1
  27. package/dist/tools/article.d.ts +2 -2
  28. package/dist/tools/article.d.ts.map +1 -1
  29. package/dist/tools/article.js +4 -3
  30. package/dist/tools/article.js.map +1 -1
  31. package/dist/tools/compare.d.ts +2 -2
  32. package/dist/tools/compare.d.ts.map +1 -1
  33. package/dist/tools/compare.js +3 -6
  34. package/dist/tools/compare.js.map +1 -1
  35. package/dist/tools/definitions.d.ts +2 -2
  36. package/dist/tools/definitions.d.ts.map +1 -1
  37. package/dist/tools/definitions.js +4 -4
  38. package/dist/tools/definitions.js.map +1 -1
  39. package/dist/tools/evidence.d.ts +2 -2
  40. package/dist/tools/evidence.d.ts.map +1 -1
  41. package/dist/tools/evidence.js +6 -6
  42. package/dist/tools/evidence.js.map +1 -1
  43. package/dist/tools/list.d.ts +2 -2
  44. package/dist/tools/list.d.ts.map +1 -1
  45. package/dist/tools/list.js +16 -19
  46. package/dist/tools/list.js.map +1 -1
  47. package/dist/tools/map.d.ts +2 -2
  48. package/dist/tools/map.d.ts.map +1 -1
  49. package/dist/tools/map.js +5 -4
  50. package/dist/tools/map.js.map +1 -1
  51. package/dist/tools/recital.d.ts +2 -2
  52. package/dist/tools/recital.d.ts.map +1 -1
  53. package/dist/tools/recital.js +4 -3
  54. package/dist/tools/recital.js.map +1 -1
  55. package/dist/tools/registry.d.ts +3 -3
  56. package/dist/tools/registry.d.ts.map +1 -1
  57. package/dist/tools/registry.js.map +1 -1
  58. package/dist/tools/search.d.ts +2 -2
  59. package/dist/tools/search.d.ts.map +1 -1
  60. package/dist/tools/search.js +150 -60
  61. package/dist/tools/search.js.map +1 -1
  62. package/dist/worker.d.ts +50 -0
  63. package/dist/worker.d.ts.map +1 -0
  64. package/dist/worker.js +565 -0
  65. package/dist/worker.js.map +1 -0
  66. package/package.json +9 -5
  67. package/src/database/postgres-adapter.ts +84 -0
  68. package/src/database/sqlite-adapter.ts +44 -0
  69. package/src/database/types.ts +10 -0
  70. package/src/http-server.ts +6 -3
  71. package/src/index.ts +14 -8
  72. package/src/middleware/rate-limit.ts +104 -0
  73. package/src/tools/applicability.ts +25 -20
  74. package/src/tools/article.ts +11 -9
  75. package/src/tools/compare.ts +8 -8
  76. package/src/tools/definitions.ts +6 -11
  77. package/src/tools/evidence.ts +8 -20
  78. package/src/tools/list.ts +33 -25
  79. package/src/tools/map.ts +8 -6
  80. package/src/tools/recital.ts +11 -9
  81. package/src/tools/registry.ts +3 -3
  82. package/src/tools/search.ts +205 -82
  83. package/src/worker.ts +708 -0
package/README.md CHANGED
@@ -6,20 +6,14 @@
6
6
  [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
7
7
  [![GitHub stars](https://img.shields.io/github/stars/Ansvar-Systems/EU_compliance_MCP?style=social)](https://github.com/Ansvar-Systems/EU_compliance_MCP)
8
8
  [![Daily EUR-Lex Check](https://github.com/Ansvar-Systems/EU_compliance_MCP/actions/workflows/check-updates.yml/badge.svg)](https://github.com/Ansvar-Systems/EU_compliance_MCP/actions/workflows/check-updates.yml)
9
- [![Deploy to Azure](https://github.com/Ansvar-Systems/EU_compliance_MCP/actions/workflows/deploy-azure.yml/badge.svg)](https://github.com/Ansvar-Systems/EU_compliance_MCP/actions/workflows/deploy-azure.yml)
10
9
  [![Database](https://img.shields.io/badge/database-pre--built-green)](docs/COVERAGE_GAPS.md)
11
10
  [![Recitals](https://img.shields.io/badge/recitals-3500%2B-blue)](docs/COVERAGE_GAPS.md)
12
- [![Hosted](https://img.shields.io/badge/Azure-hosted-0078D4)](https://eu-regulations-mcp.jollysea-916ea475.westeurope.azurecontainerapps.io/health)
13
-
14
- <a href="https://glama.ai/mcp/servers/@Mortalus/eu-regulations">
15
- <img width="380" height="200" src="https://glama.ai/mcp/servers/@Mortalus/eu-regulations/badge" />
16
- </a>
17
11
 
18
12
  Query **37 EU regulations** — from GDPR and AI Act to DORA, MiFID II, eIDAS, Medical Device Regulation, and more — directly from Claude, Cursor, or any MCP-compatible client.
19
13
 
20
14
  If you're building digital products, financial services, healthcare tech, or connected devices for the European market, this is your compliance reference.
21
15
 
22
- Built by [Ansvar Systems](https://ansvar.ai) — Stockholm, Sweden
16
+ Built by [Ansvar Systems](https://ansvar.eu) — Stockholm, Sweden
23
17
 
24
18
  ---
25
19
 
@@ -78,22 +72,6 @@ Restart Claude Desktop. Done.
78
72
  }
79
73
  ```
80
74
 
81
- ### Hosted Service (Zero Setup)
82
-
83
- Already running on Azure - just add to your config:
84
-
85
- ```json
86
- {
87
- "mcpServers": {
88
- "eu-regulations": {
89
- "url": "https://eu-regulations-mcp.jollysea-916ea475.westeurope.azurecontainerapps.io/mcp"
90
- }
91
- }
92
- }
93
- ```
94
-
95
- See [HANDOVER.md](HANDOVER.md) and [SETUP-CICD.md](SETUP-CICD.md) for deployment details.
96
-
97
75
  ---
98
76
 
99
77
  ## Example Queries
@@ -133,10 +111,23 @@ Once connected, just ask naturally:
133
111
 
134
112
  ### Why This Works
135
113
 
114
+ **Verbatim Source Text (No LLM Processing):**
115
+ - All article text is ingested from EUR-Lex/UNECE official sources
116
+ - Snippets are returned **unchanged** from SQLite FTS5 database rows
117
+ - Zero LLM summarization or paraphrasing — the database contains regulation text, not AI interpretations
118
+ - **Note:** HTML-to-text conversion normalizes whitespace/formatting, but preserves content
119
+
136
120
  **Smart Context Management:**
137
- - Search returns **relevant snippets**, not entire regulations
138
- - Article retrieval includes **token usage warnings** for large content
139
- - Cross-references help navigate without loading everything
121
+ - Search returns **32-token snippets** with highlighted matches (safe for context)
122
+ - Article retrieval warns about token usage (some articles = 70k tokens)
123
+ - Cross-references help navigate without loading everything at once
124
+
125
+ **Technical Architecture:**
126
+ ```
127
+ EUR-Lex HTML → Parse → SQLite → FTS5 snippet() → MCP response
128
+ ↑ ↑
129
+ Formatting only Verbatim database query
130
+ ```
140
131
 
141
132
  ### Example: EUR-Lex vs. This MCP
142
133
 
@@ -192,7 +183,7 @@ We build AI-accelerated threat modeling and compliance tools for automotive, fin
192
183
 
193
184
  So we're open-sourcing it. Navigating 37 regulations shouldn't require a legal team.
194
185
 
195
- **[ansvar.ai](https://ansvar.ai)** — Stockholm, Sweden
186
+ **[ansvar.eu](https://ansvar.eu)** — Stockholm, Sweden
196
187
 
197
188
  ---
198
189
 
Binary file
@@ -0,0 +1,3 @@
1
+ import type { DatabaseAdapter } from './types.js';
2
+ export declare function createPostgresAdapter(connectionString: string): Promise<DatabaseAdapter>;
3
+ //# sourceMappingURL=postgres-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-adapter.d.ts","sourceRoot":"","sources":["../../src/database/postgres-adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,YAAY,CAAC;AAE/D,wBAAsB,qBAAqB,CACzC,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,eAAe,CAAC,CA8E1B"}
@@ -0,0 +1,65 @@
1
+ import pg from 'pg';
2
+ export async function createPostgresAdapter(connectionString) {
3
+ const pool = new pg.Pool({
4
+ connectionString,
5
+ max: 10,
6
+ idleTimeoutMillis: 30000,
7
+ connectionTimeoutMillis: 10000,
8
+ });
9
+ // Test connection
10
+ try {
11
+ await pool.query('SELECT 1');
12
+ }
13
+ catch (error) {
14
+ throw new Error(`Failed to connect to PostgreSQL: ${error}`);
15
+ }
16
+ return {
17
+ type: 'postgres',
18
+ async query(sql, params) {
19
+ const QUERY_TIMEOUT_MS = 10000; // 10 seconds
20
+ try {
21
+ // Create timeout promise
22
+ const timeoutPromise = new Promise((_, reject) => {
23
+ setTimeout(() => {
24
+ reject(new Error('Database query timeout: Query exceeded 10 seconds'));
25
+ }, QUERY_TIMEOUT_MS);
26
+ });
27
+ // Race between query and timeout
28
+ const result = await Promise.race([
29
+ pool.query(sql, params),
30
+ timeoutPromise,
31
+ ]);
32
+ return {
33
+ rows: result.rows,
34
+ rowCount: result.rowCount || 0,
35
+ };
36
+ }
37
+ catch (error) {
38
+ const pgError = error;
39
+ console.error('PostgreSQL query failed:', {
40
+ sql: sql.substring(0, 100), // Truncate for logging
41
+ params,
42
+ code: pgError.code,
43
+ message: pgError.message,
44
+ detail: pgError.detail,
45
+ });
46
+ // Check for timeout error
47
+ if (pgError.message?.includes('timeout')) {
48
+ throw new Error('Database query timeout: Query exceeded 10 seconds');
49
+ }
50
+ // Provide helpful error messages based on error code
51
+ if (pgError.code?.startsWith('08')) {
52
+ throw new Error(`Database connection error: ${pgError.message}`);
53
+ }
54
+ if (pgError.code === '42P01') {
55
+ throw new Error(`Table not found: ${pgError.message}`);
56
+ }
57
+ throw new Error(`Query failed: ${pgError.message}${pgError.code ? ` (${pgError.code})` : ''}`);
58
+ }
59
+ },
60
+ async close() {
61
+ await pool.end();
62
+ },
63
+ };
64
+ }
65
+ //# sourceMappingURL=postgres-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-adapter.js","sourceRoot":"","sources":["../../src/database/postgres-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAGpB,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,gBAAwB;IAExB,MAAM,IAAI,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC;QACvB,gBAAgB;QAChB,GAAG,EAAE,EAAE;QACP,iBAAiB,EAAE,KAAK;QACxB,uBAAuB,EAAE,KAAK;KAC/B,CAAC,CAAC;IAEH,kBAAkB;IAClB,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,oCAAoC,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO;QACL,IAAI,EAAE,UAAmB;QAEzB,KAAK,CAAC,KAAK,CAAU,GAAW,EAAE,MAAc;YAC9C,MAAM,gBAAgB,GAAG,KAAK,CAAC,CAAC,aAAa;YAE7C,IAAI,CAAC;gBACH,yBAAyB;gBACzB,MAAM,cAAc,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;oBACtD,UAAU,CAAC,GAAG,EAAE;wBACd,MAAM,CAAC,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC,CAAC;oBACzE,CAAC,EAAE,gBAAgB,CAAC,CAAC;gBACvB,CAAC,CAAC,CAAC;gBAEH,iCAAiC;gBACjC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;oBAChC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC;oBACvB,cAAc;iBACf,CAAC,CAAC;gBAEH,OAAO;oBACL,IAAI,EAAE,MAAM,CAAC,IAAW;oBACxB,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,CAAC;iBAC/B,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,OAAO,GAAG,KAIf,CAAC;gBACF,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE;oBACxC,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,uBAAuB;oBACnD,MAAM;oBACN,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,MAAM,EAAE,OAAO,CAAC,MAAM;iBACvB,CAAC,CAAC;gBAEH,0BAA0B;gBAC1B,IAAI,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;oBACzC,MAAM,IAAI,KAAK,CACb,mDAAmD,CACpD,CAAC;gBACJ,CAAC;gBAED,qDAAqD;gBACrD,IAAI,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;oBACnC,MAAM,IAAI,KAAK,CAAC,8BAA8B,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;gBACnE,CAAC;gBACD,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC7B,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;gBACzD,CAAC;gBAED,MAAM,IAAI,KAAK,CACb,iBAAiB,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9E,CAAC;YACJ,CAAC;QACH,CAAC;QAED,KAAK,CAAC,KAAK;YACT,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type Database from 'better-sqlite3';
2
+ import type { DatabaseAdapter } from './types.js';
3
+ /**
4
+ * Adapter that wraps better-sqlite3 Database to match DatabaseAdapter interface.
5
+ * Allows existing SQLite-based entry points (stdio) to work with the new adapter interface.
6
+ */
7
+ export declare function createSqliteAdapter(db: Database.Database): DatabaseAdapter;
8
+ //# sourceMappingURL=sqlite-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-adapter.d.ts","sourceRoot":"","sources":["../../src/database/sqlite-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,YAAY,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,eAAe,CAoC1E"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Adapter that wraps better-sqlite3 Database to match DatabaseAdapter interface.
3
+ * Allows existing SQLite-based entry points (stdio) to work with the new adapter interface.
4
+ */
5
+ export function createSqliteAdapter(db) {
6
+ return {
7
+ type: 'sqlite',
8
+ async query(sql, params) {
9
+ try {
10
+ // Convert PostgreSQL syntax to SQLite syntax
11
+ let sqliteSql = sql
12
+ // Convert $1, $2 placeholders to ?
13
+ .replace(/\$\d+/g, '?')
14
+ // Convert ILIKE to LIKE (SQLite is case-insensitive by default with LIKE)
15
+ .replace(/\sILIKE\s/gi, ' LIKE ')
16
+ // Convert ::TEXT type casting to CAST(... AS TEXT)
17
+ .replace(/(\w+)::TEXT/g, 'CAST($1 AS TEXT)')
18
+ .replace(/(\w+)::INTEGER/g, 'CAST($1 AS INTEGER)')
19
+ // Convert DISTINCT ON (col) to GROUP BY col
20
+ // PostgreSQL: SELECT DISTINCT ON (col1) col1, col2 FROM ... ORDER BY col1, col2
21
+ // SQLite: SELECT col1, col2 FROM ... GROUP BY col1 HAVING MIN(col2) = col2
22
+ .replace(/SELECT\s+DISTINCT\s+ON\s*\([^)]+\)/gi, 'SELECT');
23
+ const stmt = db.prepare(sqliteSql);
24
+ const rows = params ? stmt.all(...params) : stmt.all();
25
+ return {
26
+ rows: rows,
27
+ rowCount: rows.length,
28
+ };
29
+ }
30
+ catch (error) {
31
+ console.error('SQLite query failed:', sql, params, error);
32
+ throw error;
33
+ }
34
+ },
35
+ async close() {
36
+ db.close();
37
+ },
38
+ };
39
+ }
40
+ //# sourceMappingURL=sqlite-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-adapter.js","sourceRoot":"","sources":["../../src/database/sqlite-adapter.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAqB;IACvD,OAAO;QACL,IAAI,EAAE,QAAiB;QAEvB,KAAK,CAAC,KAAK,CAAU,GAAW,EAAE,MAAc;YAC9C,IAAI,CAAC;gBACH,6CAA6C;gBAC7C,IAAI,SAAS,GAAG,GAAG;oBACjB,mCAAmC;qBAClC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;oBACvB,0EAA0E;qBACzE,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC;oBACjC,mDAAmD;qBAClD,OAAO,CAAC,cAAc,EAAE,kBAAkB,CAAC;qBAC3C,OAAO,CAAC,iBAAiB,EAAE,qBAAqB,CAAC;oBAClD,4CAA4C;oBAC5C,gFAAgF;oBAChF,2EAA2E;qBAC1E,OAAO,CAAC,sCAAsC,EAAE,QAAQ,CAAC,CAAC;gBAE7D,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACnC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACvD,OAAO;oBACL,IAAI,EAAE,IAAW;oBACjB,QAAQ,EAAE,IAAI,CAAC,MAAM;iBACtB,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;gBAC1D,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QAED,KAAK,CAAC,KAAK;YACT,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ export interface QueryResult<T = any> {
2
+ rows: T[];
3
+ rowCount: number;
4
+ }
5
+ export interface DatabaseAdapter {
6
+ query<T = any>(sql: string, params?: any[]): Promise<QueryResult<T>>;
7
+ close(): Promise<void>;
8
+ type: 'sqlite' | 'postgres';
9
+ }
10
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/database/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,GAAG;IAClC,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;CAC7B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/database/types.ts"],"names":[],"mappings":""}
@@ -13,6 +13,7 @@ import { fileURLToPath } from 'url';
13
13
  import { dirname, join } from 'path';
14
14
  import { randomUUID } from 'crypto';
15
15
  import { registerTools } from './tools/registry.js';
16
+ import { createSqliteAdapter } from './database/sqlite-adapter.js';
16
17
  const __filename = fileURLToPath(import.meta.url);
17
18
  const __dirname = dirname(__filename);
18
19
  // Database path - look for regulations.db in data folder
@@ -23,7 +24,8 @@ let db;
23
24
  function getDatabase() {
24
25
  if (!db) {
25
26
  try {
26
- db = new Database(DB_PATH, { readonly: true });
27
+ const sqliteDb = new Database(DB_PATH, { readonly: true });
28
+ db = createSqliteAdapter(sqliteDb);
27
29
  }
28
30
  catch (error) {
29
31
  throw new Error(`Failed to open database at ${DB_PATH}: ${error}`);
@@ -1 +1 @@
1
- {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -5,19 +5,24 @@ import Database from 'better-sqlite3';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { dirname, join } from 'path';
7
7
  import { registerTools } from './tools/registry.js';
8
+ import { createSqliteAdapter } from './database/sqlite-adapter.js';
8
9
  const __filename = fileURLToPath(import.meta.url);
9
10
  const __dirname = dirname(__filename);
10
11
  // Database path - look for regulations.db in data folder
11
12
  const DB_PATH = process.env.EU_COMPLIANCE_DB_PATH || join(__dirname, '..', 'data', 'regulations.db');
13
+ let db;
12
14
  function getDatabase() {
13
- try {
14
- return new Database(DB_PATH, { readonly: true });
15
- }
16
- catch (error) {
17
- throw new Error(`Failed to open database at ${DB_PATH}: ${error}`);
15
+ if (!db) {
16
+ try {
17
+ const sqliteDb = new Database(DB_PATH, { readonly: true });
18
+ db = createSqliteAdapter(sqliteDb);
19
+ }
20
+ catch (error) {
21
+ throw new Error(`Failed to open database at ${DB_PATH}: ${error}`);
22
+ }
18
23
  }
24
+ return db;
19
25
  }
20
- const db = getDatabase();
21
26
  const server = new Server({
22
27
  name: 'eu-regulations-mcp',
23
28
  version: '0.1.0',
@@ -27,7 +32,7 @@ const server = new Server({
27
32
  },
28
33
  });
29
34
  // Register all tools using shared registry
30
- registerTools(server, db);
35
+ registerTools(server, getDatabase());
31
36
  // Start the server
32
37
  async function main() {
33
38
  const transport = new StdioServerTransport();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAKjF,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,yDAAyD;AACzD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAErG,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,8BAA8B,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC;IACrE,CAAC;AACH,CAAC;AAED,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;AACzB,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;IACE,IAAI,EAAE,oBAAoB;IAC1B,OAAO,EAAE,OAAO;CACjB,EACD;IACE,YAAY,EAAE;QACZ,KAAK,EAAE,EAAE;KACV;CACF,CACF,CAAC;AAEF,2CAA2C;AAC3C,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAE1B,mBAAmB;AACnB,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;AACrD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAKjF,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGnE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,yDAAyD;AACzD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAErG,IAAI,EAAmB,CAAC;AAExB,SAAS,WAAW;IAClB,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3D,EAAE,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,8BAA8B,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AACD,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;IACE,IAAI,EAAE,oBAAoB;IAC1B,OAAO,EAAE,OAAO;CACjB,EACD;IACE,YAAY,EAAE;QACZ,KAAK,EAAE,EAAE;KACV;CACF,CACF,CAAC;AAEF,2CAA2C;AAC3C,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;AAErC,mBAAmB;AACnB,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;AACrD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,47 @@
1
+ export interface RateLimitInfo {
2
+ allowed: boolean;
3
+ remaining: number;
4
+ resetAt: number;
5
+ }
6
+ /**
7
+ * Fixed-window rate limiter for IP-based request throttling.
8
+ *
9
+ * Uses fixed time windows that reset at specific intervals. This is simpler
10
+ * than true sliding windows but allows burst traffic at window boundaries
11
+ * (e.g., 100 requests at 09:59:59 + 100 at 10:00:01 = 200 in 2 seconds).
12
+ *
13
+ * Trade-off accepted: Simplicity and performance over burst protection.
14
+ * Suitable for basic rate limiting where occasional bursts are acceptable.
15
+ *
16
+ * @example
17
+ * const limiter = new RateLimiter(100, 3600000); // 100 requests per hour
18
+ * if (limiter.checkLimit(clientIP)) {
19
+ * // Allow request
20
+ * } else {
21
+ * // Return 429 Too Many Requests
22
+ * }
23
+ */
24
+ export declare class RateLimiter {
25
+ private records;
26
+ private readonly maxRequests;
27
+ private readonly windowMs;
28
+ constructor(maxRequests: number, windowMs: number);
29
+ /**
30
+ * Check if a request from the given IP should be allowed
31
+ * @param ip Client IP address
32
+ * @returns true if allowed, false if rate limited
33
+ */
34
+ checkLimit(ip: string): boolean;
35
+ /**
36
+ * Get detailed rate limit information for an IP
37
+ * @param ip Client IP address
38
+ * @returns Rate limit status with remaining requests and reset time
39
+ */
40
+ getRateLimitInfo(ip: string): RateLimitInfo;
41
+ /**
42
+ * Clean up old records to prevent memory leak
43
+ * Should be called periodically (e.g., every hour)
44
+ */
45
+ cleanup(): void;
46
+ }
47
+ //# sourceMappingURL=rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAsC;IACrD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAKjD;;;;OAIG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI/B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa;IAsC3C;;;OAGG;IACH,OAAO,IAAI,IAAI;CAQhB"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Fixed-window rate limiter for IP-based request throttling.
3
+ *
4
+ * Uses fixed time windows that reset at specific intervals. This is simpler
5
+ * than true sliding windows but allows burst traffic at window boundaries
6
+ * (e.g., 100 requests at 09:59:59 + 100 at 10:00:01 = 200 in 2 seconds).
7
+ *
8
+ * Trade-off accepted: Simplicity and performance over burst protection.
9
+ * Suitable for basic rate limiting where occasional bursts are acceptable.
10
+ *
11
+ * @example
12
+ * const limiter = new RateLimiter(100, 3600000); // 100 requests per hour
13
+ * if (limiter.checkLimit(clientIP)) {
14
+ * // Allow request
15
+ * } else {
16
+ * // Return 429 Too Many Requests
17
+ * }
18
+ */
19
+ export class RateLimiter {
20
+ records = new Map();
21
+ maxRequests;
22
+ windowMs;
23
+ constructor(maxRequests, windowMs) {
24
+ this.maxRequests = maxRequests;
25
+ this.windowMs = windowMs;
26
+ }
27
+ /**
28
+ * Check if a request from the given IP should be allowed
29
+ * @param ip Client IP address
30
+ * @returns true if allowed, false if rate limited
31
+ */
32
+ checkLimit(ip) {
33
+ return this.getRateLimitInfo(ip).allowed;
34
+ }
35
+ /**
36
+ * Get detailed rate limit information for an IP
37
+ * @param ip Client IP address
38
+ * @returns Rate limit status with remaining requests and reset time
39
+ */
40
+ getRateLimitInfo(ip) {
41
+ const now = Date.now();
42
+ let record = this.records.get(ip);
43
+ // Clean up if window expired
44
+ if (record && now > record.resetAt) {
45
+ this.records.delete(ip);
46
+ record = undefined;
47
+ }
48
+ // Initialize new record if needed
49
+ if (!record) {
50
+ record = {
51
+ count: 0,
52
+ resetAt: now + this.windowMs,
53
+ };
54
+ this.records.set(ip, record);
55
+ }
56
+ // Check if over limit
57
+ if (record.count >= this.maxRequests) {
58
+ return {
59
+ allowed: false,
60
+ remaining: 0,
61
+ resetAt: record.resetAt,
62
+ };
63
+ }
64
+ // Increment and allow
65
+ record.count++;
66
+ return {
67
+ allowed: true,
68
+ remaining: this.maxRequests - record.count,
69
+ resetAt: record.resetAt,
70
+ };
71
+ }
72
+ /**
73
+ * Clean up old records to prevent memory leak
74
+ * Should be called periodically (e.g., every hour)
75
+ */
76
+ cleanup() {
77
+ const now = Date.now();
78
+ for (const [ip, record] of this.records.entries()) {
79
+ if (now > record.resetAt) {
80
+ this.records.delete(ip);
81
+ }
82
+ }
83
+ }
84
+ }
85
+ //# sourceMappingURL=rate-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,WAAW;IACd,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAC;IACpC,WAAW,CAAS;IACpB,QAAQ,CAAS;IAElC,YAAY,WAAmB,EAAE,QAAgB;QAC/C,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,UAAU,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;IAC3C,CAAC;IAED;;;;OAIG;IACH,gBAAgB,CAAC,EAAU;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAElC,6BAA6B;QAC7B,IAAI,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACxB,MAAM,GAAG,SAAS,CAAC;QACrB,CAAC;QAED,kCAAkC;QAClC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG;gBACP,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,GAAG,GAAG,IAAI,CAAC,QAAQ;aAC7B,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC/B,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,SAAS,EAAE,CAAC;gBACZ,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC;QACJ,CAAC;QAED,sBAAsB;QACtB,MAAM,CAAC,KAAK,EAAE,CAAC;QAEf,OAAO;YACL,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK;YAC1C,OAAO,EAAE,MAAM,CAAC,OAAO;SACxB,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAClD,IAAI,GAAG,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;gBACzB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
@@ -1,4 +1,4 @@
1
- import type { Database } from 'better-sqlite3';
1
+ import type { DatabaseAdapter } from '../database/types.js';
2
2
  export type Sector = 'financial' | 'healthcare' | 'energy' | 'transport' | 'digital_infrastructure' | 'public_administration' | 'manufacturing' | 'other';
3
3
  export interface ApplicabilityInput {
4
4
  sector: Sector;
@@ -36,5 +36,5 @@ export interface ApplicabilityResult {
36
36
  next_steps?: string;
37
37
  };
38
38
  }
39
- export declare function checkApplicability(db: Database, input: ApplicabilityInput): Promise<ApplicabilityResult>;
39
+ export declare function checkApplicability(db: DatabaseAdapter, input: ApplicabilityInput): Promise<ApplicabilityResult>;
40
40
  //# sourceMappingURL=applicability.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"applicability.d.ts","sourceRoot":"","sources":["../../src/tools/applicability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,MAAM,MAAM,GACd,WAAW,GACX,YAAY,GACZ,QAAQ,GACR,WAAW,GACX,wBAAwB,GACxB,uBAAuB,GACvB,eAAe,GACf,OAAO,CAAC;AAEZ,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,SAAS,GAAG,cAAc,GAAG,MAAM,CAAC;CACpD;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC/C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC/C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,sBAAsB,EAAE,oBAAoB,EAAE,CAAC;IAC/C,OAAO,CAAC,EAAE;QACR,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE;YACb,QAAQ,EAAE,MAAM,CAAC;YACjB,MAAM,EAAE,MAAM,CAAC;YACf,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;QACF,mBAAmB,EAAE,iBAAiB,EAAE,CAAC;QACzC,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CA0G9B"}
1
+ {"version":3,"file":"applicability.d.ts","sourceRoot":"","sources":["../../src/tools/applicability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,MAAM,MAAM,GACd,WAAW,GACX,YAAY,GACZ,QAAQ,GACR,WAAW,GACX,wBAAwB,GACxB,uBAAuB,GACvB,eAAe,GACf,OAAO,CAAC;AAEZ,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,SAAS,GAAG,cAAc,GAAG,MAAM,CAAC;CACpD;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC/C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC/C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,sBAAsB,EAAE,oBAAoB,EAAE,CAAC;IAC/C,OAAO,CAAC,EAAE;QACR,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE;YACb,QAAQ,EAAE,MAAM,CAAC;YACjB,MAAM,EAAE,MAAM,CAAC;YACf,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;QACF,mBAAmB,EAAE,iBAAiB,EAAE,CAAC;QACzC,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,eAAe,EACnB,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CA+G9B"}
@@ -1,27 +1,28 @@
1
1
  export async function checkApplicability(db, input) {
2
2
  const { sector, subsector, detail_level = 'full' } = input;
3
3
  // Query for matching rules - check both sector match and subsector match
4
+ // Note: We handle deduplication in JavaScript, so no need for DISTINCT ON
4
5
  let sql = `
5
- SELECT DISTINCT
6
+ SELECT
6
7
  regulation,
7
8
  confidence,
8
9
  basis_article as basis,
9
- notes
10
- FROM applicability_rules
11
- WHERE applies = 1
12
- AND (
13
- (sector = ? AND (subsector IS NULL OR subsector = ?))
14
- OR (sector = ? AND subsector IS NULL)
15
- )
16
- ORDER BY
10
+ notes,
17
11
  CASE confidence
18
12
  WHEN 'definite' THEN 1
19
13
  WHEN 'likely' THEN 2
20
14
  WHEN 'possible' THEN 3
21
- END,
22
- regulation
15
+ END as conf_order
16
+ FROM applicability_rules
17
+ WHERE applies = true
18
+ AND (
19
+ (sector = $1 AND (subsector IS NULL OR subsector = $2))
20
+ OR (sector = $3 AND subsector IS NULL)
21
+ )
22
+ ORDER BY regulation, conf_order
23
23
  `;
24
- const rows = db.prepare(sql).all(sector, subsector || '', sector);
24
+ const result = await db.query(sql, [sector, subsector || '', sector]);
25
+ const rows = result.rows;
25
26
  // Deduplicate by regulation, keeping highest confidence
26
27
  const regulationMap = new Map();
27
28
  for (const row of rows) {
@@ -40,12 +41,11 @@ export async function checkApplicability(db, input) {
40
41
  if (detail_level === 'summary') {
41
42
  // Get regulation metadata for summary
42
43
  const regIds = applicable_regulations.map(r => r.regulation);
43
- const placeholders = regIds.map(() => '?').join(', ');
44
- const regData = db.prepare(`
45
- SELECT id, full_name, effective_date
46
- FROM regulations
47
- WHERE id IN (${placeholders})
48
- `).all(...regIds);
44
+ const placeholders = regIds.map((_, i) => `$${i + 1}`).join(', ');
45
+ const regDataResult = await db.query(`SELECT id, full_name, effective_date
46
+ FROM regulations
47
+ WHERE id IN (${placeholders})`, regIds);
48
+ const regData = regDataResult.rows;
49
49
  const regMetadata = new Map(regData.map(r => [r.id, r]));
50
50
  // Priority deadlines for key regulations
51
51
  const priorityDeadlines = {
@@ -1 +1 @@
1
- {"version":3,"file":"applicability.js","sourceRoot":"","sources":["../../src/tools/applicability.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"applicability.js","sourceRoot":"","sources":["../../src/tools/applicability.ts"],"names":[],"mappings":"AAoDA,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,EAAmB,EACnB,KAAyB;IAEzB,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,KAAK,CAAC;IAE3D,yEAAyE;IACzE,0EAA0E;IAC1E,IAAI,GAAG,GAAG;;;;;;;;;;;;;;;;;;GAkBT,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IAEtE,MAAM,IAAI,GAAG,MAAM,CAAC,IAKlB,CAAC;IAEH,wDAAwD;IACxD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAgC,CAAC;IAC9D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YACvC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE;gBAChC,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,KAAK,EAAE,GAAG,CAAC,KAAK;aACjB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,sBAAsB,GAAG,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;IAElE,yDAAyD;IACzD,IAAI,OAAO,CAAC;IACZ,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,sCAAsC;QACtC,MAAM,MAAM,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAC7D,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,MAAM,aAAa,GAAG,MAAM,EAAE,CAAC,KAAK,CAClC;;sBAEgB,YAAY,GAAG,EAC/B,MAAM,CACP,CAAC;QAEF,MAAM,OAAO,GAAG,aAAa,CAAC,IAI5B,CAAC;QAEH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAEzD,yCAAyC;QACzC,MAAM,iBAAiB,GAA2B;YAChD,MAAM,EAAE,uBAAuB;YAC/B,MAAM,EAAE,uCAAuC;YAC/C,QAAQ,EAAE,iCAAiC;YAC3C,QAAQ,EAAE,+BAA+B;YACzC,MAAM,EAAE,kBAAkB;YAC1B,OAAO,EAAE,+BAA+B;SACzC,CAAC;QAEF,MAAM,mBAAmB,GAAwB,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YAChF,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACjD,OAAO;gBACL,EAAE,EAAE,GAAG,CAAC,UAAU;gBAClB,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,GAAG,CAAC,UAAU;gBAChD,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,iBAAiB,EAAE,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC;aACrD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,aAAa,GAAG;YACpB,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC,MAAM;YAChF,MAAM,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,MAAM;YAC5E,QAAQ,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC,MAAM;SACjF,CAAC;QAEF,OAAO,GAAG;YACR,WAAW,EAAE,sBAAsB,CAAC,MAAM;YAC1C,aAAa;YACb,mBAAmB;YACnB,UAAU,EAAE,qHAAqH;SAClI,CAAC;IACJ,CAAC;IAED,OAAO;QACL,MAAM,EAAE,KAAK;QACb,sBAAsB;QACtB,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { Database } from 'better-sqlite3';
1
+ import type { DatabaseAdapter } from '../database/types.js';
2
2
  export interface GetArticleInput {
3
3
  regulation: string;
4
4
  article: string;
@@ -16,5 +16,5 @@ export interface Article {
16
16
  original_length?: number;
17
17
  token_estimate?: number;
18
18
  }
19
- export declare function getArticle(db: Database, input: GetArticleInput): Promise<Article | null>;
19
+ export declare function getArticle(db: DatabaseAdapter, input: GetArticleInput): Promise<Article | null>;
20
20
  //# sourceMappingURL=article.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"article.d.ts","sourceRoot":"","sources":["../../src/tools/article.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAsDzB"}
1
+ {"version":3,"file":"article.d.ts","sourceRoot":"","sources":["../../src/tools/article.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,eAAe,EACnB,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAwDzB"}
@@ -10,12 +10,13 @@ export async function getArticle(db, input) {
10
10
  recitals,
11
11
  cross_references
12
12
  FROM articles
13
- WHERE regulation = ? AND article_number = ?
13
+ WHERE regulation = $1 AND article_number = $2
14
14
  `;
15
- const row = db.prepare(sql).get(regulation, article);
16
- if (!row) {
15
+ const result = await db.query(sql, [regulation, article]);
16
+ if (result.rows.length === 0) {
17
17
  return null;
18
18
  }
19
+ const row = result.rows[0];
19
20
  // Token management: Truncate very large articles to prevent context overflow
20
21
  const MAX_CHARS = 50000; // ~12,500 tokens (safe for 200k context window)
21
22
  const originalLength = row.text.length;
@@ -1 +1 @@
1
- {"version":3,"file":"article.js","sourceRoot":"","sources":["../../src/tools/article.ts"],"names":[],"mappings":"AAqBA,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,EAAY,EACZ,KAAsB;IAEtB,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAEtC,MAAM,GAAG,GAAG;;;;;;;;;;;GAWX,CAAC;IAEF,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAQtC,CAAC;IAEd,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IAED,6EAA6E;IAC7E,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,gDAAgD;IACzE,MAAM,cAAc,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;IACvC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,qBAAqB;IAC1E,IAAI,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACpB,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,IAAI,cAAc,GAAG,SAAS,EAAE,CAAC;QAC/B,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,sDAAsD,GAAG,cAAc,GAAG,WAAW,GAAG,aAAa,GAAG,8DAA8D,CAAC;QACjN,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,IAAI;QACJ,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI;QACxD,gBAAgB,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI;QAChF,SAAS;QACT,eAAe,EAAE,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS;QACvD,cAAc,EAAE,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS;KACtD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"article.js","sourceRoot":"","sources":["../../src/tools/article.ts"],"names":[],"mappings":"AAqBA,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,EAAmB,EACnB,KAAsB;IAEtB,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAEtC,MAAM,GAAG,GAAG;;;;;;;;;;;GAWX,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAE1D,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAQxB,CAAC;IAEF,6EAA6E;IAC7E,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,gDAAgD;IACzE,MAAM,cAAc,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;IACvC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,qBAAqB;IAC1E,IAAI,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACpB,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,IAAI,cAAc,GAAG,SAAS,EAAE,CAAC;QAC/B,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,sDAAsD,GAAG,cAAc,GAAG,WAAW,GAAG,aAAa,GAAG,8DAA8D,CAAC;QACjN,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,IAAI;QACJ,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI;QACxD,gBAAgB,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI;QAChF,SAAS;QACT,eAAe,EAAE,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS;QACvD,cAAc,EAAE,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS;KACtD,CAAC;AACJ,CAAC"}