From ced4d4c1ccf7854bba0a7435d0e596b35030f8f6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 12:48:10 +0000 Subject: [PATCH 01/18] Initial plan From d5c93ed9cfb5a059a5eb69d23c138e6cb16ba4e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 12:59:16 +0000 Subject: [PATCH 02/18] Fix flaky Playwright e2e tests for database connection verification - Add waitForGraphPresent() polling helper to apiCalls.ts to retry getGraphs() until expected graph appears instead of one-shot calls - Add connectDatabaseWithRetry() helper to retry streaming connection on transient errors with diagnostic logging - Enhance parseStreamingResponse() to log error message details - Update all database.spec.ts tests to use scoped test.setTimeout(120000/180000) - Increase waitForDatabaseConnection timeout to 90s in all DB connection tests - Replace bare getGraphs() calls with waitForGraphPresent() polling - Add console.log diagnostics throughout for easier CI debugging Co-authored-by: gkorland <753206+gkorland@users.noreply.github.com> --- e2e/logic/api/apiCalls.ts | 74 +++++++++++++ e2e/tests/database.spec.ts | 205 +++++++++++++++++++++++-------------- package-lock.json | 24 ++++- 3 files changed, 225 insertions(+), 78 deletions(-) diff --git a/e2e/logic/api/apiCalls.ts b/e2e/logic/api/apiCalls.ts index a1d00c92..44f54476 100644 --- a/e2e/logic/api/apiCalls.ts +++ b/e2e/logic/api/apiCalls.ts @@ -258,6 +258,14 @@ export default class ApiCalls { .split("|||FALKORDB_MESSAGE_BOUNDARY|||") .filter((msg) => msg.trim()) .map((msg) => JSON.parse(msg.trim())); + // Log error messages to help diagnose CI failures + const errorMessages = messages.filter((m) => m.type === "error"); + if (errorMessages.length > 0) { + console.log( + `[parseStreamingResponse] HTTP status: ${response.status()}, error messages received:`, + JSON.stringify(errorMessages) + ); + } return messages; } catch (error) { throw new Error( @@ -266,6 +274,72 @@ export default class ApiCalls { } } + /** + * Poll getGraphs() until a graph matching the predicate appears, or until timeout. + * Returns the last observed graph list (for diagnostics even on timeout). + */ + async waitForGraphPresent( + predicate: (graphs: GraphsListResponse) => boolean, + timeoutMs: number = 30000, + pollIntervalMs: number = 2000 + ): Promise { + const deadline = Date.now() + timeoutMs; + let lastGraphs: GraphsListResponse = []; + while (Date.now() < deadline) { + try { + lastGraphs = await this.getGraphs(); + if (predicate(lastGraphs)) { + return lastGraphs; + } + } catch (err) { + console.log( + `[waitForGraphPresent] getGraphs() error: ${(err as Error).message}` + ); + } + const remaining = deadline - Date.now(); + if (remaining <= 0) break; + await new Promise((resolve) => + setTimeout(resolve, Math.min(pollIntervalMs, remaining)) + ); + } + console.log( + `[waitForGraphPresent] timed out after ${timeoutMs}ms. Last graphs: ${JSON.stringify(lastGraphs)}` + ); + return lastGraphs; + } + + /** + * Connect to external database with retry on transient errors. + * Retries up to `maxAttempts` times if the streaming response final message is not 'final_result'. + */ + async connectDatabaseWithRetry( + connectionUrl: string, + maxAttempts: number = 3, + retryDelayMs: number = 3000 + ): Promise { + let lastMessages: StreamMessage[] = []; + for (let attempt = 1; attempt <= maxAttempts; attempt++) { + const response = await this.connectDatabase(connectionUrl); + const messages = await this.parseStreamingResponse(response); + const finalMessage = messages[messages.length - 1]; + if (finalMessage && finalMessage.type === "final_result") { + return messages; + } + console.log( + `[connectDatabaseWithRetry] attempt ${attempt}/${maxAttempts} did not return final_result.`, + `Last message: ${JSON.stringify(finalMessage)}` + ); + lastMessages = messages; + if (attempt < maxAttempts) { + await new Promise((resolve) => setTimeout(resolve, retryDelayMs)); + } + } + console.log( + `[connectDatabaseWithRetry] all ${maxAttempts} attempts exhausted. Last messages: ${JSON.stringify(lastMessages)}` + ); + return lastMessages; + } + /** * Confirm destructive SQL operation * POST /graphs/{graph_id}/confirm diff --git a/e2e/tests/database.spec.ts b/e2e/tests/database.spec.ts index d3b91188..58b38693 100644 --- a/e2e/tests/database.spec.ts +++ b/e2e/tests/database.spec.ts @@ -20,31 +20,38 @@ test.describe('Database Connection Tests', () => { }); test('connect PostgreSQL via API -> verify in UI', async () => { + test.setTimeout(120000); // Allow extra time for schema loading in CI const homePage = await browser.createNewPage(HomePage, getBaseUrl()); await browser.setPageToFullScreen(); const { postgres: postgresUrl } = getTestDatabases(); - // Connect via API - response is streaming - const response = await apiCall.connectDatabase(postgresUrl); - const messages = await apiCall.parseStreamingResponse(response); + // Connect via API - response is streaming (retry on transient errors) + const messages = await apiCall.connectDatabaseWithRetry(postgresUrl); // Verify final message indicates success const finalMessage = messages[messages.length - 1]; + if (finalMessage.type !== 'final_result') { + console.log(`[PostgreSQL API connect] unexpected final message: ${JSON.stringify(finalMessage)}`); + } expect(finalMessage.type).toBe('final_result'); expect(finalMessage.success).toBeTruthy(); // Get the list of databases to find the connected database - const graphsList = await apiCall.getGraphs(); + const graphsList = await apiCall.waitForGraphPresent( + (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), + 30000 + ); expect(graphsList).toBeDefined(); expect(Array.isArray(graphsList)).toBeTruthy(); expect(graphsList.length).toBeGreaterThan(0); + console.log(`[PostgreSQL API connect] graphs after connection: ${JSON.stringify(graphsList)}`); // Find the testdb database (not testdb_delete) - could be 'testdb' or 'userId_testdb' const graphId = graphsList.find(id => id === 'testdb' || id.endsWith('_testdb')); expect(graphId).toBeTruthy(); // Wait for UI to reflect the connection (schema loading completes) - const connectionEstablished = await homePage.waitForDatabaseConnection(); + const connectionEstablished = await homePage.waitForDatabaseConnection(90000); expect(connectionEstablished).toBeTruthy(); // Verify connection appears in UI - check database status badge @@ -64,31 +71,38 @@ test.describe('Database Connection Tests', () => { }); test('connect MySQL via API -> verify in UI', async () => { + test.setTimeout(120000); // Allow extra time for schema loading in CI const homePage = await browser.createNewPage(HomePage, getBaseUrl()); await browser.setPageToFullScreen(); const { mysql: mysqlUrl } = getTestDatabases(); - // Connect via API - response is streaming - const response = await apiCall.connectDatabase(mysqlUrl); - const messages = await apiCall.parseStreamingResponse(response); + // Connect via API - response is streaming (retry on transient errors) + const messages = await apiCall.connectDatabaseWithRetry(mysqlUrl); // Verify final message indicates success const finalMessage = messages[messages.length - 1]; + if (finalMessage.type !== 'final_result') { + console.log(`[MySQL API connect] unexpected final message: ${JSON.stringify(finalMessage)}`); + } expect(finalMessage.type).toBe('final_result'); expect(finalMessage.success).toBeTruthy(); // Get the list of databases to find the connected database - const graphsList = await apiCall.getGraphs(); + const graphsList = await apiCall.waitForGraphPresent( + (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), + 30000 + ); expect(graphsList).toBeDefined(); expect(Array.isArray(graphsList)).toBeTruthy(); expect(graphsList.length).toBeGreaterThan(0); + console.log(`[MySQL API connect] graphs after connection: ${JSON.stringify(graphsList)}`); // Find the testdb database (not testdb_delete) - could be 'testdb' or 'userId_testdb' const graphId = graphsList.find(id => id === 'testdb' || id.endsWith('_testdb')); expect(graphId).toBeTruthy(); // Wait for UI to reflect the connection (schema loading completes) - const connectionEstablished = await homePage.waitForDatabaseConnection(); + const connectionEstablished = await homePage.waitForDatabaseConnection(90000); expect(connectionEstablished).toBeTruthy(); // Verify connection appears in UI - check database status badge @@ -108,6 +122,7 @@ test.describe('Database Connection Tests', () => { }); test('connect PostgreSQL via UI (URL) -> verify via API', async () => { + test.setTimeout(120000); // Allow extra time for schema loading in CI const homePage = await browser.createNewPage(HomePage, getBaseUrl()); await browser.setPageToFullScreen(); const { postgres: postgresUrl } = getTestDatabases(); @@ -120,14 +135,21 @@ test.describe('Database Connection Tests', () => { await homePage.clickOnDatabaseModalConnect(); // Wait for UI to reflect the connection (schema loading completes) - const connectionEstablished = await homePage.waitForDatabaseConnection(); + const connectionEstablished = await homePage.waitForDatabaseConnection(90000); + if (!connectionEstablished) { + console.log('[PostgreSQL URL connect] waitForDatabaseConnection timed out'); + } expect(connectionEstablished).toBeTruthy(); - // Verify via API - get the list of databases - const graphsList = await apiCall.getGraphs(); + // Verify via API - poll until graph appears + const graphsList = await apiCall.waitForGraphPresent( + (graphs) => graphs.length > 0, + 30000 + ); expect(graphsList).toBeDefined(); expect(Array.isArray(graphsList)).toBeTruthy(); expect(graphsList.length).toBeGreaterThan(0); + console.log(`[PostgreSQL URL connect] graphs after connection: ${JSON.stringify(graphsList)}`); // Get the connected database ID const graphId = graphsList[0]; @@ -139,6 +161,7 @@ test.describe('Database Connection Tests', () => { }); test('connect MySQL via UI (URL) -> verify via API', async () => { + test.setTimeout(120000); // Allow extra time for schema loading in CI const homePage = await browser.createNewPage(HomePage, getBaseUrl()); await browser.setPageToFullScreen(); const { mysql: mysqlUrl } = getTestDatabases(); @@ -151,14 +174,21 @@ test.describe('Database Connection Tests', () => { await homePage.clickOnDatabaseModalConnect(); // Wait for UI to reflect the connection (schema loading completes) - const connectionEstablished = await homePage.waitForDatabaseConnection(); + const connectionEstablished = await homePage.waitForDatabaseConnection(90000); + if (!connectionEstablished) { + console.log('[MySQL URL connect] waitForDatabaseConnection timed out'); + } expect(connectionEstablished).toBeTruthy(); - // Verify via API - get the list of databases - const graphsList = await apiCall.getGraphs(); + // Verify via API - poll until graph appears + const graphsList = await apiCall.waitForGraphPresent( + (graphs) => graphs.length > 0, + 30000 + ); expect(graphsList).toBeDefined(); expect(Array.isArray(graphsList)).toBeTruthy(); expect(graphsList.length).toBeGreaterThan(0); + console.log(`[MySQL URL connect] graphs after connection: ${JSON.stringify(graphsList)}`); // Get the connected database ID const graphId = graphsList[0]; @@ -170,6 +200,7 @@ test.describe('Database Connection Tests', () => { }); test('connect PostgreSQL via UI (Manual Entry) -> verify via API', async () => { + test.setTimeout(120000); // Allow extra time for schema loading in CI const homePage = await browser.createNewPage(HomePage, getBaseUrl()); await browser.setPageToFullScreen(); @@ -187,14 +218,21 @@ test.describe('Database Connection Tests', () => { await homePage.clickOnDatabaseModalConnect(); // Wait for UI to reflect the connection (schema loading completes) - const connectionEstablished = await homePage.waitForDatabaseConnection(); + const connectionEstablished = await homePage.waitForDatabaseConnection(90000); + if (!connectionEstablished) { + console.log('[PostgreSQL Manual connect] waitForDatabaseConnection timed out'); + } expect(connectionEstablished).toBeTruthy(); - // Verify via API - get the list of databases - const graphsList = await apiCall.getGraphs(); + // Verify via API - poll until graph appears + const graphsList = await apiCall.waitForGraphPresent( + (graphs) => graphs.length > 0, + 30000 + ); expect(graphsList).toBeDefined(); expect(Array.isArray(graphsList)).toBeTruthy(); expect(graphsList.length).toBeGreaterThan(0); + console.log(`[PostgreSQL Manual connect] graphs after connection: ${JSON.stringify(graphsList)}`); // Get the connected database ID const graphId = graphsList[0]; @@ -206,6 +244,7 @@ test.describe('Database Connection Tests', () => { }); test('connect MySQL via UI (Manual Entry) -> verify via API', async () => { + test.setTimeout(120000); // Allow extra time for schema loading in CI const homePage = await browser.createNewPage(HomePage, getBaseUrl()); await browser.setPageToFullScreen(); @@ -223,14 +262,21 @@ test.describe('Database Connection Tests', () => { await homePage.clickOnDatabaseModalConnect(); // Wait for UI to reflect the connection (schema loading completes) - const connectionEstablished = await homePage.waitForDatabaseConnection(); + const connectionEstablished = await homePage.waitForDatabaseConnection(90000); + if (!connectionEstablished) { + console.log('[MySQL Manual connect] waitForDatabaseConnection timed out'); + } expect(connectionEstablished).toBeTruthy(); - // Verify via API - get the list of databases - const graphsList = await apiCall.getGraphs(); + // Verify via API - poll until graph appears + const graphsList = await apiCall.waitForGraphPresent( + (graphs) => graphs.length > 0, + 30000 + ); expect(graphsList).toBeDefined(); expect(Array.isArray(graphsList)).toBeTruthy(); expect(graphsList.length).toBeGreaterThan(0); + console.log(`[MySQL Manual connect] graphs after connection: ${JSON.stringify(graphsList)}`); // Get the connected database ID const graphId = graphsList[0]; @@ -270,31 +316,33 @@ test.describe('Database Connection Tests', () => { // Delete tests run serially to avoid conflicts test.describe.serial('Database Deletion Tests', () => { - test('delete PostgreSQL database via UI -> verify removed via API', async () => { + test('delete PostgreSQL database via UI -> verify removed via API', async () => { + test.setTimeout(180000); // Allow extra time: schema loading + UI interaction // Use the separate postgres delete container on port 5433 const postgresDeleteUrl = 'postgresql://postgres:postgres@localhost:5433/testdb_delete'; - // Connect database via API - const connectResponse = await apiCall.connectDatabase(postgresDeleteUrl); - const connectMessages = await apiCall.parseStreamingResponse(connectResponse); + // Connect database via API (retry on transient errors) + const connectMessages = await apiCall.connectDatabaseWithRetry(postgresDeleteUrl); const finalMessage = connectMessages[connectMessages.length - 1]; + if (finalMessage.type !== 'final_result') { + console.log(`[PostgreSQL delete connect] unexpected final message: ${JSON.stringify(finalMessage)}`); + } expect(finalMessage.type).toBe('final_result'); expect(finalMessage.success).toBeTruthy(); - // Wait a bit for the connection to be fully registered - await new Promise(resolve => setTimeout(resolve, 2000)); - - // Get the graph ID from the API - let graphsList = await apiCall.getGraphs(); + // Poll until the graph appears in the API + let graphsList = await apiCall.waitForGraphPresent( + (graphs) => graphs.some((id) => id.includes('testdb_delete')), + 30000 + ); expect(graphsList.length).toBeGreaterThan(0); // Find the graph that contains 'testdb_delete' (could be 'testdb_delete' or 'userId_testdb_delete') const graphId = graphsList.find(id => id.includes('testdb_delete')); - // If not found, log all graphs for debugging if (!graphId) { - console.log('Available graphs:', graphsList); - console.log('Looking for graph containing: testdb_delete'); + console.log('[PostgreSQL delete] Available graphs:', graphsList); + console.log('[PostgreSQL delete] Looking for graph containing: testdb_delete'); } expect(graphId).toBeTruthy(); @@ -316,55 +364,60 @@ test.describe('Database Connection Tests', () => { graphsList = await apiCall.getGraphs(); expect(graphsList.length).toBe(initialCount - 1); expect(graphsList).not.toContain(graphId); - }); + }); - test('delete MySQL database via UI -> verify removed via API', async () => { - // Use the separate mysql delete container on port 3307 - const mysqlDeleteUrl = 'mysql://root:password@localhost:3307/testdb_delete'; + test('delete MySQL database via UI -> verify removed via API', async () => { + test.setTimeout(180000); // Allow extra time: schema loading + UI interaction + // Use the separate mysql delete container on port 3307 + const mysqlDeleteUrl = 'mysql://root:password@localhost:3307/testdb_delete'; - // Connect database via API - const connectResponse = await apiCall.connectDatabase(mysqlDeleteUrl); - const connectMessages = await apiCall.parseStreamingResponse(connectResponse); - const finalMessage = connectMessages[connectMessages.length - 1]; - expect(finalMessage.type).toBe('final_result'); - expect(finalMessage.success).toBeTruthy(); + // Connect database via API (retry on transient errors) + const connectMessages = await apiCall.connectDatabaseWithRetry(mysqlDeleteUrl); + const finalMessage = connectMessages[connectMessages.length - 1]; + if (finalMessage.type !== 'final_result') { + console.log(`[MySQL delete connect] unexpected final message: ${JSON.stringify(finalMessage)}`); + } + expect(finalMessage.type).toBe('final_result'); + expect(finalMessage.success).toBeTruthy(); - // Wait a bit for the connection to be fully registered - await new Promise(resolve => setTimeout(resolve, 2000)); + // Poll until the graph appears in the API + let graphsList = await apiCall.waitForGraphPresent( + (graphs) => graphs.some((id) => id.includes('testdb_delete')), + 30000 + ); + expect(graphsList.length).toBeGreaterThan(0); + const graphId = graphsList.find(id => id.includes('testdb_delete')); + + if (!graphId) { + console.log('[MySQL delete] Available graphs:', graphsList); + console.log('[MySQL delete] Looking for graph containing: testdb_delete'); + } + + expect(graphId).toBeTruthy(); + const initialCount = graphsList.length; - // Get the graph ID from the API - find the graph containing testdb_delete - let graphsList = await apiCall.getGraphs(); - expect(graphsList.length).toBeGreaterThan(0); - const graphId = graphsList.find(id => id.includes('testdb_delete')); - - // If not found, log all graphs for debugging - if (!graphId) { - console.log('Available graphs:', graphsList); - console.log('Looking for graph containing: testdb_delete'); - } - - expect(graphId).toBeTruthy(); - const initialCount = graphsList.length; + const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + await browser.setPageToFullScreen(); - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); - await browser.setPageToFullScreen(); + // Wait for UI to reflect the connection (increased timeout for schema loading) + const connectionEstablished = await homePage.waitForDatabaseConnection(90000); + if (!connectionEstablished) { + console.log('[MySQL delete] waitForDatabaseConnection timed out'); + } + expect(connectionEstablished).toBeTruthy(); - // Wait for UI to reflect the connection (increased timeout for schema loading) - const connectionEstablished = await homePage.waitForDatabaseConnection(60000); - expect(connectionEstablished).toBeTruthy(); + // Delete via UI - open dropdown, click delete, confirm + await homePage.clickOnDatabaseSelector(); + await homePage.clickOnDeleteGraph(graphId!); + await homePage.clickOnDeleteModalConfirm(); + + // Wait for deletion to complete + await homePage.wait(1000); - // Delete via UI - open dropdown, click delete, confirm - await homePage.clickOnDatabaseSelector(); - await homePage.clickOnDeleteGraph(graphId!); - await homePage.clickOnDeleteModalConfirm(); - - // Wait for deletion to complete - await homePage.wait(1000); - - // Verify removed from API - graphsList = await apiCall.getGraphs(); - expect(graphsList.length).toBe(initialCount - 1); - expect(graphsList).not.toContain(graphId); + // Verify removed from API + graphsList = await apiCall.getGraphs(); + expect(graphsList.length).toBe(initialCount - 1); + expect(graphsList).not.toContain(graphId); }); }); }); diff --git a/package-lock.json b/package-lock.json index ded65412..425f8275 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ }, "app": { "name": "queryweaver-app", - "version": "0.0.1", + "version": "0.0.14", "dependencies": { "@falkordb/canvas": "^0.0.29", "@hookform/resolvers": "^3.10.0", @@ -2229,6 +2229,7 @@ "version": "22.19.7", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -2242,6 +2243,7 @@ "version": "18.3.27", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -2251,6 +2253,7 @@ "version": "18.3.7", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -2294,6 +2297,7 @@ "version": "8.53.0", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.53.0", "@typescript-eslint/types": "8.53.0", @@ -2501,6 +2505,7 @@ "version": "8.15.0", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2674,6 +2679,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2851,6 +2857,7 @@ "app/node_modules/date-fns": { "version": "3.6.0", "license": "MIT", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/kossnocorp" @@ -2908,7 +2915,8 @@ }, "app/node_modules/embla-carousel": { "version": "8.6.0", - "license": "MIT" + "license": "MIT", + "peer": true }, "app/node_modules/embla-carousel-react": { "version": "8.6.0", @@ -2991,6 +2999,7 @@ "version": "9.39.2", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3427,6 +3436,7 @@ "app/node_modules/jiti": { "version": "1.21.7", "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -3753,6 +3763,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -3940,6 +3951,7 @@ "app/node_modules/react": { "version": "18.3.1", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -3962,6 +3974,7 @@ "app/node_modules/react-dom": { "version": "18.3.1", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -3973,6 +3986,7 @@ "app/node_modules/react-hook-form": { "version": "7.71.1", "license": "MIT", + "peer": true, "engines": { "node": ">=18.0.0" }, @@ -4379,6 +4393,7 @@ "app/node_modules/tailwindcss": { "version": "3.4.18", "license": "MIT", + "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -4482,6 +4497,7 @@ "app/node_modules/tinyglobby/node_modules/picomatch": { "version": "4.0.3", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -4533,6 +4549,7 @@ "version": "5.9.3", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -4690,6 +4707,7 @@ "version": "7.3.1", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -4779,6 +4797,7 @@ "version": "4.0.3", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -5277,6 +5296,7 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } From a42427c03cc7db1c684bae584abff6bebea74f36 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:00:25 +0000 Subject: [PATCH 03/18] Bump playwright from 1.57.0 to 1.58.0 Bumps [playwright](https://github.com/microsoft/playwright-python) from 1.57.0 to 1.58.0. - [Release notes](https://github.com/microsoft/playwright-python/releases) - [Commits](https://github.com/microsoft/playwright-python/compare/v1.57.0...v1.58.0) --- updated-dependencies: - dependency-name: playwright dependency-version: 1.58.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Pipfile | 2 +- Pipfile.lock | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Pipfile b/Pipfile index 020cb5ca..6b5193f4 100644 --- a/Pipfile +++ b/Pipfile @@ -22,7 +22,7 @@ fastmcp = ">=2.13.1" [dev-packages] pytest = "~=8.4.2" pylint = "~=4.0.3" -playwright = "~=1.57.0" +playwright = "~=1.58.0" pytest-playwright = "~=0.7.1" pytest-asyncio = "~=1.2.0" diff --git a/Pipfile.lock b/Pipfile.lock index 36252143..86aa6abd 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "87444999c27f9e20ce232a6e0ed25a50d5e6af1a3b102e97aa29fac060e6685b" + "sha256": "f6dfde4badd17c41c4f2b884470e965162451abd316c88bb8811b2cd1ef9ad39" }, "pipfile-spec": 6, "requires": { @@ -3223,18 +3223,18 @@ }, "playwright": { "hashes": [ - "sha256:1dd93b265688da46e91ecb0606d36f777f8eadcf7fbef12f6426b20bf0c9137c", - "sha256:284ed5a706b7c389a06caa431b2f0ba9ac4130113c3a779767dda758c2497bb1", - "sha256:38a1bae6c0a07839cdeaddbc0756b3b2b85e476c07945f64ece08f1f956a86f1", - "sha256:5f065f5a133dbc15e6e7c71e7bc04f258195755b1c32a432b792e28338c8335e", - "sha256:6caefb08ed2c6f29d33b8088d05d09376946e49a73be19271c8cd5384b82b14c", - "sha256:9351c1ac3dfd9b3820fe7fc4340d96c0d3736bb68097b9b7a69bd45d25e9370c", - "sha256:99104771abc4eafee48f47dac2369e0015516dc1ce8c409807d2dd440828b9a4", - "sha256:a4a9d65027bce48eeba842408bcc1421502dfd7e41e28d207e94260fa93ca67e" + "sha256:185e0132578733d02802dfddfbbc35f42be23a45ff49ccae5081f25952238117", + "sha256:1e03be090e75a0fabbdaeab65ce17c308c425d879fa48bb1d7986f96bfad0b99", + "sha256:32ffe5c303901a13a0ecab91d1c3f74baf73b84f4bedbb6b935f5bc11cc98e1b", + "sha256:70c763694739d28df71ed578b9c8202bb83e8fe8fb9268c04dd13afe36301f71", + "sha256:8f9999948f1ab541d98812de25e3a8c410776aa516d948807140aff797b4bffa", + "sha256:96e3204aac292ee639edbfdef6298b4be2ea0a55a16b7068df91adac077cc606", + "sha256:a2bf639d0ce33b3ba38de777e08697b0d8f3dc07ab6802e4ac53fb65e3907af8", + "sha256:c95568ba1eda83812598c1dc9be60b4406dffd60b149bc1536180ad108723d6b" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==1.57.0" + "version": "==1.58.0" }, "pluggy": { "hashes": [ From 3aae1295abde9dfa74abefd5882b77dde7d67a90 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 21:48:52 +0000 Subject: [PATCH 04/18] Address review feedback: try/catch in retry, finalMessage guards, specific DB predicates, polling for deletion - connectDatabaseWithRetry: wrap per-attempt logic in try/catch so network/parse exceptions don't abort retries; log with attempt# via console.error; backoff delay behaviour unchanged - Add expect(messages.length).toBeGreaterThan(0) guard before accessing finalMessage in all 4 caller blocks (PostgreSQL API, MySQL API, PostgreSQL delete, MySQL delete) - Fix UI-to-API test predicates from generic 'graphs.length > 0' to 'testdb'/'_testdb' match, avoiding false positives on pre-existing graphs - Replace wait(1000)+getGraphs() in both delete tests with waitForGraphPresent polling until the deleted graphId is absent Co-authored-by: gkorland <753206+gkorland@users.noreply.github.com> --- e2e/logic/api/apiCalls.ts | 27 +++++++++++++-------- e2e/tests/database.spec.ts | 48 +++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/e2e/logic/api/apiCalls.ts b/e2e/logic/api/apiCalls.ts index 44f54476..e708a810 100644 --- a/e2e/logic/api/apiCalls.ts +++ b/e2e/logic/api/apiCalls.ts @@ -319,17 +319,24 @@ export default class ApiCalls { ): Promise { let lastMessages: StreamMessage[] = []; for (let attempt = 1; attempt <= maxAttempts; attempt++) { - const response = await this.connectDatabase(connectionUrl); - const messages = await this.parseStreamingResponse(response); - const finalMessage = messages[messages.length - 1]; - if (finalMessage && finalMessage.type === "final_result") { - return messages; + try { + const response = await this.connectDatabase(connectionUrl); + const messages = await this.parseStreamingResponse(response); + const finalMessage = messages[messages.length - 1]; + if (finalMessage && finalMessage.type === "final_result") { + return messages; + } + console.log( + `[connectDatabaseWithRetry] attempt ${attempt}/${maxAttempts} did not return final_result.`, + `Last message: ${JSON.stringify(finalMessage)}` + ); + lastMessages = messages; + } catch (err) { + console.error( + `[connectDatabaseWithRetry] attempt ${attempt}/${maxAttempts} threw an error:`, + (err as Error).message + ); } - console.log( - `[connectDatabaseWithRetry] attempt ${attempt}/${maxAttempts} did not return final_result.`, - `Last message: ${JSON.stringify(finalMessage)}` - ); - lastMessages = messages; if (attempt < maxAttempts) { await new Promise((resolve) => setTimeout(resolve, retryDelayMs)); } diff --git a/e2e/tests/database.spec.ts b/e2e/tests/database.spec.ts index 58b38693..e38afd02 100644 --- a/e2e/tests/database.spec.ts +++ b/e2e/tests/database.spec.ts @@ -29,6 +29,7 @@ test.describe('Database Connection Tests', () => { const messages = await apiCall.connectDatabaseWithRetry(postgresUrl); // Verify final message indicates success + expect(messages.length).toBeGreaterThan(0); const finalMessage = messages[messages.length - 1]; if (finalMessage.type !== 'final_result') { console.log(`[PostgreSQL API connect] unexpected final message: ${JSON.stringify(finalMessage)}`); @@ -80,6 +81,7 @@ test.describe('Database Connection Tests', () => { const messages = await apiCall.connectDatabaseWithRetry(mysqlUrl); // Verify final message indicates success + expect(messages.length).toBeGreaterThan(0); const finalMessage = messages[messages.length - 1]; if (finalMessage.type !== 'final_result') { console.log(`[MySQL API connect] unexpected final message: ${JSON.stringify(finalMessage)}`); @@ -141,9 +143,9 @@ test.describe('Database Connection Tests', () => { } expect(connectionEstablished).toBeTruthy(); - // Verify via API - poll until graph appears + // Verify via API - poll until the expected testdb graph appears const graphsList = await apiCall.waitForGraphPresent( - (graphs) => graphs.length > 0, + (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), 30000 ); expect(graphsList).toBeDefined(); @@ -152,7 +154,7 @@ test.describe('Database Connection Tests', () => { console.log(`[PostgreSQL URL connect] graphs after connection: ${JSON.stringify(graphsList)}`); // Get the connected database ID - const graphId = graphsList[0]; + const graphId = graphsList.find((id) => id === 'testdb' || id.endsWith('_testdb')); expect(graphId).toBeTruthy(); // Verify connection appears in UI @@ -180,9 +182,9 @@ test.describe('Database Connection Tests', () => { } expect(connectionEstablished).toBeTruthy(); - // Verify via API - poll until graph appears + // Verify via API - poll until the expected testdb graph appears const graphsList = await apiCall.waitForGraphPresent( - (graphs) => graphs.length > 0, + (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), 30000 ); expect(graphsList).toBeDefined(); @@ -191,7 +193,7 @@ test.describe('Database Connection Tests', () => { console.log(`[MySQL URL connect] graphs after connection: ${JSON.stringify(graphsList)}`); // Get the connected database ID - const graphId = graphsList[0]; + const graphId = graphsList.find((id) => id === 'testdb' || id.endsWith('_testdb')); expect(graphId).toBeTruthy(); // Verify connection appears in UI @@ -224,9 +226,9 @@ test.describe('Database Connection Tests', () => { } expect(connectionEstablished).toBeTruthy(); - // Verify via API - poll until graph appears + // Verify via API - poll until the expected testdb graph appears const graphsList = await apiCall.waitForGraphPresent( - (graphs) => graphs.length > 0, + (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), 30000 ); expect(graphsList).toBeDefined(); @@ -235,7 +237,7 @@ test.describe('Database Connection Tests', () => { console.log(`[PostgreSQL Manual connect] graphs after connection: ${JSON.stringify(graphsList)}`); // Get the connected database ID - const graphId = graphsList[0]; + const graphId = graphsList.find((id) => id === 'testdb' || id.endsWith('_testdb')); expect(graphId).toBeTruthy(); // Verify connection appears in UI @@ -268,9 +270,9 @@ test.describe('Database Connection Tests', () => { } expect(connectionEstablished).toBeTruthy(); - // Verify via API - poll until graph appears + // Verify via API - poll until the expected testdb graph appears const graphsList = await apiCall.waitForGraphPresent( - (graphs) => graphs.length > 0, + (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), 30000 ); expect(graphsList).toBeDefined(); @@ -279,7 +281,7 @@ test.describe('Database Connection Tests', () => { console.log(`[MySQL Manual connect] graphs after connection: ${JSON.stringify(graphsList)}`); // Get the connected database ID - const graphId = graphsList[0]; + const graphId = graphsList.find((id) => id === 'testdb' || id.endsWith('_testdb')); expect(graphId).toBeTruthy(); // Verify connection appears in UI @@ -323,6 +325,7 @@ test.describe('Database Connection Tests', () => { // Connect database via API (retry on transient errors) const connectMessages = await apiCall.connectDatabaseWithRetry(postgresDeleteUrl); + expect(connectMessages.length).toBeGreaterThan(0); const finalMessage = connectMessages[connectMessages.length - 1]; if (finalMessage.type !== 'final_result') { console.log(`[PostgreSQL delete connect] unexpected final message: ${JSON.stringify(finalMessage)}`); @@ -357,11 +360,11 @@ test.describe('Database Connection Tests', () => { await homePage.clickOnDeleteGraph(graphId!); await homePage.clickOnDeleteModalConfirm(); - // Wait for deletion to complete - await homePage.wait(1000); - - // Verify removed from API - graphsList = await apiCall.getGraphs(); + // Wait for deletion to complete - poll until graphId is absent (up to 30s) + graphsList = await apiCall.waitForGraphPresent( + (graphs) => !graphs.some((id) => id === graphId), + 30000 + ); expect(graphsList.length).toBe(initialCount - 1); expect(graphsList).not.toContain(graphId); }); @@ -373,6 +376,7 @@ test.describe('Database Connection Tests', () => { // Connect database via API (retry on transient errors) const connectMessages = await apiCall.connectDatabaseWithRetry(mysqlDeleteUrl); + expect(connectMessages.length).toBeGreaterThan(0); const finalMessage = connectMessages[connectMessages.length - 1]; if (finalMessage.type !== 'final_result') { console.log(`[MySQL delete connect] unexpected final message: ${JSON.stringify(finalMessage)}`); @@ -411,11 +415,11 @@ test.describe('Database Connection Tests', () => { await homePage.clickOnDeleteGraph(graphId!); await homePage.clickOnDeleteModalConfirm(); - // Wait for deletion to complete - await homePage.wait(1000); - - // Verify removed from API - graphsList = await apiCall.getGraphs(); + // Wait for deletion to complete - poll until graphId is absent (up to 30s) + graphsList = await apiCall.waitForGraphPresent( + (graphs) => !graphs.some((id) => id === graphId), + 30000 + ); expect(graphsList.length).toBe(initialCount - 1); expect(graphsList).not.toContain(graphId); }); From 9a4098b183702f0a979b75de455c18be2244e0d9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 06:28:01 +0000 Subject: [PATCH 05/18] Rename waitForGraphPresent to waitForGraphs; make database tests serial - Rename waitForGraphPresent -> waitForGraphs in apiCalls.ts (more neutral name since it's used for both presence and absence checks) - Update all 10 call sites in database.spec.ts accordingly - Change outer test.describe -> test.describe.serial to prevent cross-test interference on local multi-worker runs (CI is already single-worker via workers: CI ? 1 : undefined in playwright.config.ts) Co-authored-by: gkorland <753206+gkorland@users.noreply.github.com> --- e2e/logic/api/apiCalls.ts | 9 +++++---- e2e/tests/database.spec.ts | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/e2e/logic/api/apiCalls.ts b/e2e/logic/api/apiCalls.ts index e708a810..a932453a 100644 --- a/e2e/logic/api/apiCalls.ts +++ b/e2e/logic/api/apiCalls.ts @@ -275,10 +275,11 @@ export default class ApiCalls { } /** - * Poll getGraphs() until a graph matching the predicate appears, or until timeout. + * Poll getGraphs() until the predicate is satisfied, or until timeout. * Returns the last observed graph list (for diagnostics even on timeout). + * Can be used to wait for a graph to appear or to disappear. */ - async waitForGraphPresent( + async waitForGraphs( predicate: (graphs: GraphsListResponse) => boolean, timeoutMs: number = 30000, pollIntervalMs: number = 2000 @@ -293,7 +294,7 @@ export default class ApiCalls { } } catch (err) { console.log( - `[waitForGraphPresent] getGraphs() error: ${(err as Error).message}` + `[waitForGraphs] getGraphs() error: ${(err as Error).message}` ); } const remaining = deadline - Date.now(); @@ -303,7 +304,7 @@ export default class ApiCalls { ); } console.log( - `[waitForGraphPresent] timed out after ${timeoutMs}ms. Last graphs: ${JSON.stringify(lastGraphs)}` + `[waitForGraphs] timed out after ${timeoutMs}ms. Last graphs: ${JSON.stringify(lastGraphs)}` ); return lastGraphs; } diff --git a/e2e/tests/database.spec.ts b/e2e/tests/database.spec.ts index e38afd02..8ee66b3f 100644 --- a/e2e/tests/database.spec.ts +++ b/e2e/tests/database.spec.ts @@ -5,7 +5,7 @@ import BrowserWrapper from '../infra/ui/browserWrapper'; import ApiCalls from '../logic/api/apiCalls'; // Database connection tests - uses authenticated storageState from auth.setup -test.describe('Database Connection Tests', () => { +test.describe.serial('Database Connection Tests', () => { let browser: BrowserWrapper; let apiCall: ApiCalls; @@ -38,7 +38,7 @@ test.describe('Database Connection Tests', () => { expect(finalMessage.success).toBeTruthy(); // Get the list of databases to find the connected database - const graphsList = await apiCall.waitForGraphPresent( + const graphsList = await apiCall.waitForGraphs( (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), 30000 ); @@ -90,7 +90,7 @@ test.describe('Database Connection Tests', () => { expect(finalMessage.success).toBeTruthy(); // Get the list of databases to find the connected database - const graphsList = await apiCall.waitForGraphPresent( + const graphsList = await apiCall.waitForGraphs( (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), 30000 ); @@ -144,7 +144,7 @@ test.describe('Database Connection Tests', () => { expect(connectionEstablished).toBeTruthy(); // Verify via API - poll until the expected testdb graph appears - const graphsList = await apiCall.waitForGraphPresent( + const graphsList = await apiCall.waitForGraphs( (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), 30000 ); @@ -183,7 +183,7 @@ test.describe('Database Connection Tests', () => { expect(connectionEstablished).toBeTruthy(); // Verify via API - poll until the expected testdb graph appears - const graphsList = await apiCall.waitForGraphPresent( + const graphsList = await apiCall.waitForGraphs( (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), 30000 ); @@ -227,7 +227,7 @@ test.describe('Database Connection Tests', () => { expect(connectionEstablished).toBeTruthy(); // Verify via API - poll until the expected testdb graph appears - const graphsList = await apiCall.waitForGraphPresent( + const graphsList = await apiCall.waitForGraphs( (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), 30000 ); @@ -271,7 +271,7 @@ test.describe('Database Connection Tests', () => { expect(connectionEstablished).toBeTruthy(); // Verify via API - poll until the expected testdb graph appears - const graphsList = await apiCall.waitForGraphPresent( + const graphsList = await apiCall.waitForGraphs( (graphs) => graphs.some((id) => id === 'testdb' || id.endsWith('_testdb')), 30000 ); @@ -334,7 +334,7 @@ test.describe('Database Connection Tests', () => { expect(finalMessage.success).toBeTruthy(); // Poll until the graph appears in the API - let graphsList = await apiCall.waitForGraphPresent( + let graphsList = await apiCall.waitForGraphs( (graphs) => graphs.some((id) => id.includes('testdb_delete')), 30000 ); @@ -361,7 +361,7 @@ test.describe('Database Connection Tests', () => { await homePage.clickOnDeleteModalConfirm(); // Wait for deletion to complete - poll until graphId is absent (up to 30s) - graphsList = await apiCall.waitForGraphPresent( + graphsList = await apiCall.waitForGraphs( (graphs) => !graphs.some((id) => id === graphId), 30000 ); @@ -385,7 +385,7 @@ test.describe('Database Connection Tests', () => { expect(finalMessage.success).toBeTruthy(); // Poll until the graph appears in the API - let graphsList = await apiCall.waitForGraphPresent( + let graphsList = await apiCall.waitForGraphs( (graphs) => graphs.some((id) => id.includes('testdb_delete')), 30000 ); @@ -416,7 +416,7 @@ test.describe('Database Connection Tests', () => { await homePage.clickOnDeleteModalConfirm(); // Wait for deletion to complete - poll until graphId is absent (up to 30s) - graphsList = await apiCall.waitForGraphPresent( + graphsList = await apiCall.waitForGraphs( (graphs) => !graphs.some((id) => id === graphId), 30000 ); From 837f8495789bad6dd2eeaf49ce7153edfbf81590 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 06:30:21 +0000 Subject: [PATCH 06/18] Tighten testdb_delete predicate: use === / endsWith instead of includes Replace id.includes('testdb_delete') with id === 'testdb_delete' || id.endsWith('_testdb_delete') in both delete test predicates and find() calls so only the exact graph forms ('testdb_delete' or '{userId}_testdb_delete') match, preventing accidental matches on unrelated graph names. Co-authored-by: gkorland <753206+gkorland@users.noreply.github.com> --- e2e/tests/database.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/e2e/tests/database.spec.ts b/e2e/tests/database.spec.ts index 8ee66b3f..2fa12f39 100644 --- a/e2e/tests/database.spec.ts +++ b/e2e/tests/database.spec.ts @@ -335,13 +335,13 @@ test.describe.serial('Database Connection Tests', () => { // Poll until the graph appears in the API let graphsList = await apiCall.waitForGraphs( - (graphs) => graphs.some((id) => id.includes('testdb_delete')), + (graphs) => graphs.some((id) => id === 'testdb_delete' || id.endsWith('_testdb_delete')), 30000 ); expect(graphsList.length).toBeGreaterThan(0); - // Find the graph that contains 'testdb_delete' (could be 'testdb_delete' or 'userId_testdb_delete') - const graphId = graphsList.find(id => id.includes('testdb_delete')); + // Find the graph that is 'testdb_delete' or '{userId}_testdb_delete' + const graphId = graphsList.find(id => id === 'testdb_delete' || id.endsWith('_testdb_delete')); if (!graphId) { console.log('[PostgreSQL delete] Available graphs:', graphsList); @@ -386,11 +386,11 @@ test.describe.serial('Database Connection Tests', () => { // Poll until the graph appears in the API let graphsList = await apiCall.waitForGraphs( - (graphs) => graphs.some((id) => id.includes('testdb_delete')), + (graphs) => graphs.some((id) => id === 'testdb_delete' || id.endsWith('_testdb_delete')), 30000 ); expect(graphsList.length).toBeGreaterThan(0); - const graphId = graphsList.find(id => id.includes('testdb_delete')); + const graphId = graphsList.find(id => id === 'testdb_delete' || id.endsWith('_testdb_delete')); if (!graphId) { console.log('[MySQL delete] Available graphs:', graphsList); From 2e1f439cc1ef5febe5512795cb54678887473ab2 Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Wed, 25 Feb 2026 12:55:27 +0200 Subject: [PATCH 07/18] Bump fastapi, uvicorn, litellm, playwright, and globals (#439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update dependency versions: - fastapi: ~=0.131.0 → ~=0.133.0 - uvicorn: ~=0.40.0 → ~=0.41.0 - litellm: ~=1.80.9 → ~=1.81.15 - playwright: ~=1.57.0 → ~=1.58.0 - globals (npm): ^15.15.0 → ^17.3.0 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Pipfile | 6 +- Pipfile.lock | 172 +++++++++++++----------------------------- app/package-lock.json | 6 +- app/package.json | 2 +- package-lock.json | 26 ++++--- 5 files changed, 76 insertions(+), 136 deletions(-) diff --git a/Pipfile b/Pipfile index 6b5193f4..0c72b53e 100644 --- a/Pipfile +++ b/Pipfile @@ -4,9 +4,9 @@ verify_ssl = true name = "pypi" [packages] -fastapi = "~=0.131.0" -uvicorn = "~=0.40.0" -litellm = "~=1.80.9" +fastapi = "~=0.133.0" +uvicorn = "~=0.41.0" +litellm = "~=1.81.15" falkordb = "~=1.6.0" psycopg2-binary = "~=2.9.11" pymysql = "~=1.1.0" diff --git a/Pipfile.lock b/Pipfile.lock index 86aa6abd..a6590a20 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "f6dfde4badd17c41c4f2b884470e965162451abd316c88bb8811b2cd1ef9ad39" + "sha256": "d5a1352a56f59b2f5adf844f91e6ac73b1726ffcac0e4beede069e0e281a06d8" }, "pipfile-spec": 6, "requires": { @@ -251,11 +251,11 @@ }, "certifi": { "hashes": [ - "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", - "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120" + "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", + "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7" ], "markers": "python_version >= '3.7'", - "version": "==2026.1.4" + "version": "==2026.2.25" }, "cffi": { "hashes": [ @@ -531,11 +531,11 @@ }, "cyclopts": { "hashes": [ - "sha256:ad001986ec403ca1dc1ed20375c439d62ac796295ea32b451dfe25d6696bc71a", - "sha256:eed4d6c76d4391aa796d8fcaabd50e5aad7793261792beb19285f62c5c456c8b" + "sha256:0a891cb55bfd79a3cdce024db8987b33316aba11071e5258c21ac12a640ba9f2", + "sha256:483c4704b953ea6da742e8de15972f405d2e748d19a848a4d61595e8e5360ee5" ], "markers": "python_version >= '3.10'", - "version": "==4.5.4" + "version": "==4.6.0" }, "diskcache": { "hashes": [ @@ -604,21 +604,21 @@ }, "fastapi": { "hashes": [ - "sha256:6531155e52bee2899a932c746c9a8250f210e3c3303a5f7b9f8a808bfe0548ff", - "sha256:ed0e53decccf4459de78837ce1b867cd04fa9ce4579497b842579755d20b405a" + "sha256:0a78878483d60702a1dde864c24ab349a1a53ef4db6b6f74f8cd4a2b2bc67d2f", + "sha256:b900a2bf5685cdb0647a41d5900bdeafc3a9e8a28ac08c6246b76699e164d60d" ], "index": "pypi", "markers": "python_version >= '3.10'", - "version": "==0.131.0" + "version": "==0.133.0" }, "fastmcp": { "hashes": [ - "sha256:71de15ffa4e54baebb78d7031c4c9a042a1ab8d1c0b44a9961b75d65809b67e8", - "sha256:ba463ae51e357fba2bafe513cc97f0a06c9f31220e6584990b7d8bcbf69f0516" + "sha256:6bd73b4a3bab773ee6932df5249dcbcd78ed18365ed0aeeb97bb42702a7198d7", + "sha256:f513d80d4b30b54749fe8950116b1aab843f3c293f5cb971fc8665cb48dbb028" ], "index": "pypi", "markers": "python_version >= '3.10'", - "version": "==3.0.1" + "version": "==3.0.2" }, "fastuuid": { "hashes": [ @@ -861,73 +861,6 @@ "markers": "python_version >= '3.10' and python_version < '4'", "ref": "6e3c54ae2891e10a24d698a2f0733d65d148edf4" }, - "grpcio": { - "hashes": [ - "sha256:02b82dcd2fa580f5e82b4cf62ecde1b3c7cc9ba27b946421200706a6e5acaf85", - "sha256:07eb016ea7444a22bef465cce045512756956433f54450aeaa0b443b8563b9ca", - "sha256:09fbd4bcaadb6d8604ed1504b0bdf7ac18e48467e83a9d930a70a7fefa27e862", - "sha256:0fa9943d4c7f4a14a9a876153a4e8ee2bb20a410b65c09f31510b2a42271f41b", - "sha256:13937b28986f45fee342806b07c6344db785ad74a549ebcb00c659142973556f", - "sha256:15f6e636d1152667ddb4022b37534c161c8477274edb26a0b65b215dd0a81e97", - "sha256:1a56bf3ee99af5cf32d469de91bf5de79bdac2e18082b495fc1063ea33f4f2d0", - "sha256:263307118791bc350f4642749a9c8c2d13fec496228ab11070973e568c256bfd", - "sha256:27b5cb669603efb7883a882275db88b6b5d6b6c9f0267d5846ba8699b7ace338", - "sha256:27c625532d33ace45d57e775edf1982e183ff8641c72e4e91ef7ba667a149d72", - "sha256:2b7ad2981550ce999e25ce3f10c8863f718a352a2fd655068d29ea3fd37b4907", - "sha256:2c473b54ef1618f4fb85e82ff4994de18143b74efc088b91b5a935a3a45042ba", - "sha256:34b6cb16f4b67eeb5206250dc5b4d5e8e3db939535e58efc330e4c61341554bd", - "sha256:36aeff5ba8aaf70ceb2cbf6cbba9ad6beef715ad744841f3e0cd977ec02e5966", - "sha256:389b77484959bdaad6a2b7dda44d7d1228381dd669a03f5660392aa0e9385b22", - "sha256:39d21fd30d38a5afb93f0e2e71e2ec2bd894605fb75d41d5a40060c2f98f8d11", - "sha256:39da1680d260c0c619c3b5fa2dc47480ca24d5704c7a548098bca7de7f5dd17f", - "sha256:3a8aa79bc6e004394c0abefd4b034c14affda7b66480085d87f5fbadf43b593b", - "sha256:409bfe22220889b9906739910a0ee4c197a967c21b8dd14b4b06dd477f8819ce", - "sha256:41e4605c923e0e9a84a2718e4948a53a530172bfaf1a6d1ded16ef9c5849fca2", - "sha256:4393bef64cf26dc07cd6f18eaa5170ae4eebaafd4418e7e3a59ca9526a6fa30b", - "sha256:43b930cf4f9c4a2262bb3e5d5bc40df426a72538b4f98e46f158b7eb112d2d70", - "sha256:4b8d7fda614cf2af0f73bbb042f3b7fee2ecd4aea69ec98dbd903590a1083529", - "sha256:4d50329b081c223d444751076bb5b389d4f06c2b32d51b31a1e98172e6cecfb9", - "sha256:5380268ab8513445740f1f77bd966d13043d07e2793487e61fd5b5d0935071eb", - "sha256:5572c5dd1e43dbb452b466be9794f77e3502bdb6aa6a1a7feca72c98c5085ca7", - "sha256:559f58b6823e1abc38f82e157800aff649146f8906f7998c356cd48ae274d512", - "sha256:5ce1855e8cfc217cdf6bcfe0cf046d7cf81ddcc3e6894d6cfd075f87a2d8f460", - "sha256:656a5bd142caeb8b1efe1fe0b4434ecc7781f44c97cfc7927f6608627cf178c0", - "sha256:716a544969660ed609164aff27b2effd3ff84e54ac81aa4ce77b1607ca917d22", - "sha256:75fa92c47d048d696f12b81a775316fca68385ffc6e6cb1ed1d76c8562579f74", - "sha256:7e836778c13ff70edada16567e8da0c431e8818eaae85b80d11c1ba5782eccbb", - "sha256:849cc62eb989bc3be5629d4f3acef79be0d0ff15622201ed251a86d17fef6494", - "sha256:86edb3966778fa05bfdb333688fde5dc9079f9e2a9aa6a5c42e9564b7656ba04", - "sha256:888ceb7821acd925b1c90f0cdceaed1386e69cfe25e496e0771f6c35a156132f", - "sha256:8942bdfc143b467c264b048862090c4ba9a0223c52ae28c9ae97754361372e42", - "sha256:8991c2add0d8505178ff6c3ae54bd9386279e712be82fa3733c54067aae9eda1", - "sha256:8e1fcb419da5811deb47b7749b8049f7c62b993ba17822e3c7231e3e0ba65b79", - "sha256:8f27683ca68359bd3f0eb4925824d71e538f84338b3ae337ead2ae43977d7541", - "sha256:917047c19cd120b40aab9a4b8a22e9ce3562f4a1343c0d62b3cd2d5199da3d67", - "sha256:99550e344482e3c21950c034f74668fccf8a546d50c1ecb4f717543bbdc071ba", - "sha256:9a00992d6fafe19d648b9ccb4952200c50d8e36d0cce8cf026c56ed3fdc28465", - "sha256:9dee66d142f4a8cca36b5b98a38f006419138c3c89e72071747f8fca415a6d8f", - "sha256:a40515b69ac50792f9b8ead260f194ba2bb3285375b6c40c7ff938f14c3df17d", - "sha256:a6afd191551fd72e632367dfb083e33cd185bf9ead565f2476bba8ab864ae496", - "sha256:b071dccac245c32cd6b1dd96b722283b855881ca0bf1c685cf843185f5d5d51e", - "sha256:b2acd83186305c0802dbc4d81ed0ec2f3e8658d7fde97cfba2f78d7372f05b89", - "sha256:b5d5881d72a09b8336a8f874784a8eeffacde44a7bc1a148bce5a0243a265ef0", - "sha256:ca6aebae928383e971d5eace4f1a217fd7aadaf18d5ddd3163d80354105e9068", - "sha256:cd26048d066b51f39fe9206e2bcc2cea869a5e5b2d13c8d523f4179193047ebd", - "sha256:d101fe49b1e0fb4a7aa36ed0c3821a0f67a5956ef572745452d2cd790d723a3f", - "sha256:d6fb962947e4fe321eeef3be1ba5ba49d32dea9233c825fcbade8e858c14aaf4", - "sha256:db681513a1bdd879c0b24a5a6a70398da5eaaba0e077a306410dc6008426847a", - "sha256:e2a6b33d1050dce2c6f563c5caf7f7cbeebf7fba8cde37ffe3803d50526900d1", - "sha256:e49e720cd6b092504ec7bb2f60eb459aaaf4ce0e5fe20521c201b179e93b5d5d", - "sha256:e840405a3f1249509892be2399f668c59b9d492068a2cf326d661a8c79e5e747", - "sha256:ebeec1383aed86530a5f39646984e92d6596c050629982ac54eeb4e2f6ead668", - "sha256:f81816faa426da461e9a597a178832a351d6f1078102590a4b32c77d251b71eb", - "sha256:f8759a1347f3b4f03d9a9d4ce8f9f31ad5e5d0144ba06ccfb1ffaeb0ba4c1e20", - "sha256:ff7de398bb3528d44d17e6913a7cfe639e3b15c65595a71155322df16978c5e1", - "sha256:ffbb760df1cd49e0989f9826b2fd48930700db6846ac171eaff404f3cfbe5c28" - ], - "markers": "python_version >= '3.9'", - "version": "==1.78.1" - }, "h11": { "hashes": [ "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", @@ -938,31 +871,34 @@ }, "hf-xet": { "hashes": [ - "sha256:10bfab528b968c70e062607f663e21e34e2bba349e8038db546646875495179e", - "sha256:210d577732b519ac6ede149d2f2f34049d44e8622bf14eb3d63bbcd2d4b332dc", - "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", - "sha256:293a7a3787e5c95d7be1857358a9130694a9c6021de3f27fa233f37267174382", - "sha256:29c8fc913a529ec0a91867ce3d119ac1aac966e098cf49501800c870328cc090", - "sha256:2a212e842647b02eb6a911187dc878e79c4aa0aa397e88dd3b26761676e8c1f8", - "sha256:30e06daccb3a7d4c065f34fc26c14c74f4653069bb2b194e7f18f17cbe9939c0", - "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", - "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", - "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", - "sha256:66e159cbfcfbb29f920db2c09ed8b660eb894640d284f102ada929b6e3dc410a", - "sha256:6de1fc44f58f6dd937956c8d304d8c2dea264c80680bcfa61ca4a15e7b76780f", - "sha256:7d40b18769bb9a8bc82a9ede575ce1a44c75eb80e7375a01d76259089529b5dc", - "sha256:9c91d5ae931510107f148874e9e2de8a16052b6f1b3ca3c1b12f15ccb491390f", - "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", - "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", - "sha256:b70218dd548e9840224df5638fdc94bd033552963cfa97f9170829381179c813", - "sha256:cd3a6027d59cfb60177c12d6424e31f4b5ff13d8e3a1247b3a584bf8977e6df5", - "sha256:ceeefcd1b7aed4956ae8499e2199607765fbd1c60510752003b6cc0b8413b649", - "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", - "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", - "sha256:f182f264ed2acd566c514e45da9f2119110e48a87a327ca271027904c70c5832" + "sha256:0810b69c64e96dee849036193848007f665dca2311879c9ea8693f4fc37f1795", + "sha256:08b231260c68172c866f7aa7257c165d0c87887491aafc5efeee782731725366", + "sha256:1684c840c60da12d76c2a031ba40e4b154fdbf9593836fcf5ff090d95a033c61", + "sha256:2973c3ff594c3a8da890836308cae1444c8af113c6f10fe6824575ddbc37eca7", + "sha256:329c80c86f2dda776bafd2e4813a46a3ee648dce3ac0c84625902c70d7a6ddba", + "sha256:4a322d506c513f98fdc1aa2aaa825daefd535b686e80ca789e6d33fcb146f524", + "sha256:4bc71afd853508b2ddf123b8fc9de71b0afa4c956ec730b69fb76103781e94cd", + "sha256:4eb432e1aa707a65a7e1f8455e40c5b47431d44fe0fb1b0c5d53848c27469398", + "sha256:513aa75f8dc39a63cc44dbc8d635ccf6b449e07cdbd8b2e2d006320d2e4be9bb", + "sha256:541b4b00ed294ae6cfd9416de9506e58971013714d7316189c9638ed54e362d4", + "sha256:581d1809a016f7881069d86a072168a8199a46c839cf394ff53970a47e4f1ca1", + "sha256:607d5bbc2730274516714e2e442a26e40e3330673ac0d0173004461409147dee", + "sha256:6517a245e41df3eae5adc5f9e8c86fa52abd548de798cbcd989f0082152860aa", + "sha256:65411867d46700765018b1990eb1604c3bf0bf576d9e65fc57fdcc10797a2eb9", + "sha256:713913387cc76e300116030705d843a9f15aee86158337eeffb9eb8d26f47fcd", + "sha256:83a8830160392ef4bea78d443ea2cf1febe65783b3843a8f12c64b368981e7e2", + "sha256:851b1be6597a87036fe7258ce7578d5df3c08176283b989c3b165f94125c5097", + "sha256:8f16ec9d26badec46334a798e01b5d86af536924789c95b1a1ec6a05f26523e0", + "sha256:b3012c0f2ce1f0863338491a2bc0fd3f84aded0e147ab25f230da1f5249547fd", + "sha256:e1f5d72bd5b73e61530fff573bcff34bdb64af2bf4862cdd516e6c1dab4dc75b", + "sha256:e5063789c9d21f51e9ed4edbee8539655d3486e9cad37e96b7af967da20e8b16", + "sha256:e56104c84b2a88b9c7b23ba11a2d7ed0ccbe96886b3f985a50cedd2f0e99853f", + "sha256:ecd38f98e7f0f41108e30fd4a9a5553ec30cf726df7473dd3e75a1b6d56728c2", + "sha256:ed4bfd2e6d10cb86c9b0f3483df1d7dd2d0220f75f27166925253bacbc1c2dbe", + "sha256:f85480b4fe3e8e4cdbc59ef1d235152b732fd57ca439cc983c291892945ae818" ], "markers": "python_version >= '3.8'", - "version": "==1.2.0" + "version": "==1.3.1" }, "httpcore": { "hashes": [ @@ -1189,11 +1125,11 @@ }, "jsonschema-path": { "hashes": [ - "sha256:727d8714158c41327908677e6119f9db9d5e0f486d4cc79ca4b4016eee2f33e8", - "sha256:ffca3bd37f66364ae3afeaa2804d6078a9ab3b9359ade4dd9923aabbbd475e71" + "sha256:5f5ff183150030ea24bb51cf1ddac9bf5dbf030272e2792a7ffe8262f7eea2a5", + "sha256:9c3d88e727cc4f1a88e51dbbed4211dbcd815d27799d2685efd904435c3d39e7" ], "markers": "python_version >= '3.10' and python_full_version < '4.0.0'", - "version": "==0.4.1" + "version": "==0.4.2" }, "jsonschema-specifications": { "hashes": [ @@ -1213,12 +1149,12 @@ }, "litellm": { "hashes": [ - "sha256:514ae407e488bccbe0c33a280ed88495d6f079c1dbfe745eb374d898c94b0ac3", - "sha256:52b23a21910a16820e6ea4b982dc81d27c993c1054ce148c56b251e9b89d89df" + "sha256:2fa253658702509ce09fe0e172e5a47baaadf697fb0f784c7fd4ff665ae76ae1", + "sha256:a8a6277a53280762051c5818ebc76dd5f036368b9426c6f21795ae7f1ac6ebdc" ], "index": "pypi", "markers": "python_version >= '3.9' and python_version < '4.0'", - "version": "==1.80.17" + "version": "==1.81.15" }, "markdown-it-py": { "hashes": [ @@ -1587,11 +1523,11 @@ }, "openai": { "hashes": [ - "sha256:0bc1c775e5b1536c294eded39ee08f8407656537ccc71b1004104fe1602e267c", - "sha256:81b48ce4b8bbb2cc3af02047ceb19561f7b1dc0d4e52d1de7f02abfd15aa59b7" + "sha256:1e5769f540dbd01cb33bc4716a23e67b9d695161a734aff9c5f925e2bf99a673", + "sha256:fed30480d7d6c884303287bde864980a4b137b60553ffbcf9ab4a233b7a73d94" ], "markers": "python_version >= '3.9'", - "version": "==2.21.0" + "version": "==2.24.0" }, "openapi-pydantic": { "hashes": [ @@ -2636,12 +2572,12 @@ }, "uvicorn": { "hashes": [ - "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", - "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee" + "sha256:09d11cf7008da33113824ee5a1c6422d89fbc2ff476540d69a34c87fab8b571a", + "sha256:29e35b1d2c36a04b9e180d4007ede3bcb32a85fbdfd6c6aeb3f26839de088187" ], "index": "pypi", "markers": "python_version >= '3.10'", - "version": "==0.40.0" + "version": "==0.41.0" }, "watchfiles": { "hashes": [ @@ -2981,11 +2917,11 @@ }, "certifi": { "hashes": [ - "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", - "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120" + "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", + "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7" ], "markers": "python_version >= '3.7'", - "version": "==2026.1.4" + "version": "==2026.2.25" }, "charset-normalizer": { "hashes": [ diff --git a/app/package-lock.json b/app/package-lock.json index 9d143266..ff176e36 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -73,7 +73,7 @@ "eslint": "^9.32.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", - "globals": "^15.15.0", + "globals": "^17.3.0", "postcss": "^8.5.6", "tailwindcss": "^3.4.17", "typescript": "^5.8.3", @@ -4753,7 +4753,9 @@ } }, "node_modules/globals": { - "version": "15.15.0", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.3.0.tgz", + "integrity": "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==", "dev": true, "license": "MIT", "engines": { diff --git a/app/package.json b/app/package.json index cd7e42c2..dd41812c 100644 --- a/app/package.json +++ b/app/package.json @@ -76,7 +76,7 @@ "eslint": "^9.32.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", - "globals": "^15.15.0", + "globals": "^17.3.0", "postcss": "^8.5.6", "tailwindcss": "^3.4.17", "typescript": "^5.8.3", diff --git a/package-lock.json b/package-lock.json index 425f8275..18275e17 100644 --- a/package-lock.json +++ b/package-lock.json @@ -83,7 +83,7 @@ "eslint": "^9.32.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", - "globals": "^15.15.0", + "globals": "^17.3.0", "postcss": "^8.5.6", "tailwindcss": "^3.4.17", "typescript": "^5.8.3", @@ -3313,17 +3313,6 @@ "node": ">=10.13.0" } }, - "app/node_modules/globals": { - "version": "15.15.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "app/node_modules/has-flag": { "version": "4.0.0", "dev": true, @@ -5445,6 +5434,19 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/globals": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.3.0.tgz", + "integrity": "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", From 2341d4e3dc1b72c848d7604db0d932a54df6d911 Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Thu, 26 Feb 2026 13:41:02 +0200 Subject: [PATCH 08/18] Fix SPA catch-all route not serving index.html (#433) * Return generic 400 for RequestValidationError instead of Pydantic details Add a global RequestValidationError exception handler that returns {"detail": "Bad request"} with status 400, preventing internal Pydantic validation details from leaking to clients. This primarily affects the SPA catch-all proxy route when accessed without the expected path parameter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Scope validation handler to SPA catch-all, add logging, fix tests Address PR review feedback: - Scope the generic 400 handler to only the SPA catch-all route (query._full_path errors) so API consumers still get useful 422 responses with field-level detail - Add logging.warning of validation details for server-side debugging - Make test assertions unconditional instead of guarding behind status-code checks - Add test verifying API routes preserve 422 with field-level info Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix SPA catch-all route parameter name mismatch The function parameter `_full_path` didn't match the URL template `{full_path:path}`, causing FastAPI to treat it as a required query parameter and return 422 for every non-API route. Co-Authored-By: Claude Opus 4.6 * Remove validation error handler workaround The handler was masking a parameter name mismatch in the catch-all route. Now that the root cause is fixed, the handler, its import, pylint suppression, and test file are no longer needed. Co-Authored-By: Claude Opus 4.6 * Suppress pylint unused-argument for catch-all route parameter The parameter name must match the URL template to avoid validation errors, but the function body doesn't use it. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 --- api/app_factory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/app_factory.py b/api/app_factory.py index e26509a8..d32fc9eb 100644 --- a/api/app_factory.py +++ b/api/app_factory.py @@ -261,7 +261,7 @@ async def handle_oauth_error( # Serve React app for all non-API routes (SPA catch-all) @app.get("/{full_path:path}", include_in_schema=False) - async def serve_react_app(_full_path: str): + async def serve_react_app(full_path: str): # pylint: disable=unused-argument """Serve the React app for all routes not handled by API endpoints.""" # Serve index.html for the React SPA index_path = os.path.join(dist_path, "index.html") From 141b5b585bde116b7c70edf599fdf698b336f7bb Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Thu, 26 Feb 2026 14:03:12 +0200 Subject: [PATCH 09/18] Fix: Add CSRF protection via double-submit cookie pattern (#432) * Add CSRF protection via double-submit cookie pattern Add CSRFMiddleware to protect all state-changing endpoints (POST, PUT, DELETE, PATCH) against cross-site request forgery attacks. Backend: - New CSRFMiddleware in app_factory.py sets a csrf_token cookie (non-HttpOnly, readable by JS) on every response - State-changing requests must echo the token via X-CSRF-Token header - Uses hmac.compare_digest for timing-safe validation - Exempts Bearer token auth (not CSRF-vulnerable), login/signup/OAuth flows, and MCP endpoints Frontend: - New app/src/lib/csrf.ts utility reads the cookie and builds headers - All service files (auth, tokens, database, chat) now include the X-CSRF-Token header on every state-changing fetch call Fixes: - CSRF on POST /tokens/generate (API token hijack) - CSRF on POST /logout (forced session termination) - Missing CSRF protection on all other mutating endpoints Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review feedback on CSRF protection - Set CSRF cookie on 403 rejection responses so clients can retry - Add max_age (14 days) to CSRF cookie matching session cookie lifetime - Guard document access in csrf.ts for SSR/Node compatibility - Add console.warn when CSRF cookie is missing for easier debugging - Add comment clarifying MCP exempt prefix pattern - Add comprehensive unit tests for CSRF middleware (12 test cases) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix E2E tests: seed CSRF token in API request helpers The E2E API helpers (postRequest, deleteRequest, patchRequest) now make a lightweight GET to /auth-status first to obtain the csrf_token cookie, then include it as X-CSRF-Token header on the actual request. This ensures E2E tests pass with the new CSRF middleware. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR #432 review: fix missing CSRF headers and improvements - Add csrfHeaders() to POST /graphs/{id}/refresh in Index.tsx - Add csrfHeaders() to POST /database in DatabaseModal.tsx - Refactor CSRFMiddleware.dispatch() to single return path - Change console.warn to console.debug in csrf.ts - Cache CSRF token per APIRequestContext in E2E helpers - Add DELETE/PATCH and secure-flag tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- api/app_factory.py | 78 +++++++++ app/src/components/modals/DatabaseModal.tsx | 2 + app/src/lib/csrf.ts | 38 +++++ app/src/pages/Index.tsx | 4 + app/src/services/auth.ts | 4 + app/src/services/chat.ts | 3 + app/src/services/database.ts | 10 ++ app/src/services/tokens.ts | 3 + e2e/infra/api/apiRequests.ts | 71 +++++++- tests/test_csrf_middleware.py | 170 ++++++++++++++++++++ 10 files changed, 377 insertions(+), 6 deletions(-) create mode 100644 app/src/lib/csrf.ts create mode 100644 tests/test_csrf_middleware.py diff --git a/api/app_factory.py b/api/app_factory.py index d32fc9eb..7c93cce9 100644 --- a/api/app_factory.py +++ b/api/app_factory.py @@ -1,7 +1,9 @@ """Application factory for the text2sql FastAPI app.""" +import hmac import logging import os +import secrets from dotenv import load_dotenv from fastapi import FastAPI, Request, HTTPException @@ -54,6 +56,79 @@ async def dispatch(self, request: Request, call_next): return response +def _is_secure_request(request: Request) -> bool: + """Determine if the request is over HTTPS.""" + forwarded_proto = request.headers.get("x-forwarded-proto") + if forwarded_proto: + return forwarded_proto == "https" + return request.url.scheme == "https" + + +class CSRFMiddleware(BaseHTTPMiddleware): # pylint: disable=too-few-public-methods + """Double Submit Cookie CSRF protection. + + Sets a csrf_token cookie (readable by JS) on every response. + State-changing requests must echo the cookie value back + via the X-CSRF-Token header. Bearer-token authenticated + requests and auth/login endpoints are exempt. + """ + + SAFE_METHODS = frozenset({"GET", "HEAD", "OPTIONS", "TRACE"}) + CSRF_COOKIE = "csrf_token" + CSRF_HEADER = "x-csrf-token" + + # Paths exempt from CSRF validation (auth flow endpoints). + # "/mcp" has no trailing slash so it also covers sub-paths like /mcp/sse. + EXEMPT_PREFIXES = ( + "/login/", + "/signup/", + "/mcp", + ) + + async def dispatch(self, request: Request, call_next): + # Validate CSRF for unsafe, non-exempt, non-Bearer requests + if ( + request.method not in self.SAFE_METHODS + and not request.url.path.startswith(self.EXEMPT_PREFIXES) + and not request.headers.get("authorization", "").lower().startswith("bearer ") + ): + cookie_token = request.cookies.get(self.CSRF_COOKIE) + header_token = request.headers.get(self.CSRF_HEADER) + + if ( + not cookie_token + or not header_token + or not hmac.compare_digest(cookie_token, header_token) + ): + response = JSONResponse( + status_code=403, + content={"detail": "CSRF token missing or invalid"}, + ) + self._ensure_csrf_cookie(request, response) + return response + + response = await call_next(request) + self._ensure_csrf_cookie(request, response) + return response + + # Match the session cookie lifetime (14 days in seconds) + CSRF_COOKIE_MAX_AGE = 60 * 60 * 24 * 14 + + def _ensure_csrf_cookie(self, request: Request, response): + """Set the CSRF cookie if it is not already present.""" + if not request.cookies.get(self.CSRF_COOKIE): + token = secrets.token_urlsafe(32) + response.set_cookie( + key=self.CSRF_COOKIE, + value=token, + httponly=False, # JS must read this value + samesite="lax", + secure=_is_secure_request(request), + path="/", + max_age=self.CSRF_COOKIE_MAX_AGE, + ) + + def create_app(): """Create and configure the FastAPI application.""" @@ -192,6 +267,9 @@ def custom_openapi(): # Add security middleware app.add_middleware(SecurityMiddleware) + # Add CSRF middleware (double-submit cookie pattern) + app.add_middleware(CSRFMiddleware) + # Mount static files from the React build (app/dist) # This serves the bundled assets (JS, CSS, images, etc.) dist_path = os.path.join(os.path.dirname(__file__), "../app/dist") diff --git a/app/src/components/modals/DatabaseModal.tsx b/app/src/components/modals/DatabaseModal.tsx index 5442cf61..35feae26 100644 --- a/app/src/components/modals/DatabaseModal.tsx +++ b/app/src/components/modals/DatabaseModal.tsx @@ -8,6 +8,7 @@ import { useDatabase } from "@/contexts/DatabaseContext"; import { useToast } from "@/components/ui/use-toast"; import { Loader2, CheckCircle2, XCircle } from "lucide-react"; import { buildApiUrl, API_CONFIG } from "@/config/api"; +import { csrfHeaders } from "@/lib/csrf"; interface DatabaseModalProps { open: boolean; @@ -101,6 +102,7 @@ const DatabaseModal = ({ open, onOpenChange }: DatabaseModalProps) => { method: 'POST', headers: { 'Content-Type': 'application/json', + ...csrfHeaders(), }, body: JSON.stringify({ url: dbUrl }), credentials: 'include', diff --git a/app/src/lib/csrf.ts b/app/src/lib/csrf.ts new file mode 100644 index 00000000..61656c30 --- /dev/null +++ b/app/src/lib/csrf.ts @@ -0,0 +1,38 @@ +/** + * CSRF protection utilities. + * + * The backend sets a `csrf_token` cookie (non-HttpOnly) on every response. + * State-changing requests (POST, PUT, DELETE, PATCH) must echo the cookie + * value back via the `X-CSRF-Token` header. + */ + +const CSRF_COOKIE_NAME = 'csrf_token'; + +/** + * Read the CSRF token from the cookie jar. + */ +export function getCsrfToken(): string { + if (typeof document === 'undefined') { + return ''; + } + const match = document.cookie.match( + new RegExp(`(?:^|;\\s*)${CSRF_COOKIE_NAME}=([^;]*)`) + ); + if (!match) { + console.debug( + `CSRF token cookie "${CSRF_COOKIE_NAME}" not found. ` + + 'State-changing requests may fail with 403 until the cookie is set.' + ); + return ''; + } + return decodeURIComponent(match[1]); +} + +/** + * Return headers object containing the CSRF token. + * Merge this into every state-changing fetch call. + */ +export function csrfHeaders(): Record { + const token = getCsrfToken(); + return token ? { 'X-CSRF-Token': token } : {}; +} diff --git a/app/src/pages/Index.tsx b/app/src/pages/Index.tsx index 7ac8bcd4..0572ee48 100644 --- a/app/src/pages/Index.tsx +++ b/app/src/pages/Index.tsx @@ -15,6 +15,7 @@ import { useAuth } from "@/contexts/AuthContext"; import { useDatabase } from "@/contexts/DatabaseContext"; import { DatabaseService } from "@/services/database"; import { useToast } from "@/components/ui/use-toast"; +import { csrfHeaders } from "@/lib/csrf"; import { DropdownMenu, DropdownMenuContent, @@ -255,6 +256,9 @@ const Index = () => { setIsRefreshingSchema(true); const response = await fetch(`/graphs/${selectedGraph.id}/refresh`, { method: 'POST', + headers: { + ...csrfHeaders(), + }, credentials: 'include', }); diff --git a/app/src/services/auth.ts b/app/src/services/auth.ts index 24a3d787..373c8963 100644 --- a/app/src/services/auth.ts +++ b/app/src/services/auth.ts @@ -1,4 +1,5 @@ import { API_CONFIG, buildApiUrl } from '@/config/api'; +import { csrfHeaders } from '@/lib/csrf'; import type { AuthStatus, User } from '@/types/api'; /** @@ -93,6 +94,9 @@ export class AuthService { await fetch(buildApiUrl(API_CONFIG.ENDPOINTS.LOGOUT), { method: 'POST', credentials: 'include', + headers: { + ...csrfHeaders(), + }, }); } catch (error) { console.error('Failed to logout:', error); diff --git a/app/src/services/chat.ts b/app/src/services/chat.ts index f5a1323b..70c438b2 100644 --- a/app/src/services/chat.ts +++ b/app/src/services/chat.ts @@ -1,4 +1,5 @@ import { API_CONFIG, buildApiUrl } from '@/config/api'; +import { csrfHeaders } from '@/lib/csrf'; import type { ChatRequest, StreamMessage, ConfirmRequest } from '@/types/api'; /** @@ -39,6 +40,7 @@ export class ChatService { method: 'POST', headers: { 'Content-Type': 'application/json', + ...csrfHeaders(), }, body: JSON.stringify({ chat: chatHistory, @@ -169,6 +171,7 @@ export class ChatService { method: 'POST', headers: { 'Content-Type': 'application/json', + ...csrfHeaders(), }, body: JSON.stringify(request), credentials: 'include', diff --git a/app/src/services/database.ts b/app/src/services/database.ts index 1e069df1..a74f4e96 100644 --- a/app/src/services/database.ts +++ b/app/src/services/database.ts @@ -1,4 +1,5 @@ import { API_CONFIG, buildApiUrl } from '@/config/api'; +import { csrfHeaders } from '@/lib/csrf'; import type { Graph, GraphUploadResponse, SchemaUploadRequest } from '@/types/api'; /** @@ -128,6 +129,9 @@ export class DatabaseService { method: 'POST', body: formData, credentials: 'include', + headers: { + ...csrfHeaders(), + }, }); if (!response.ok) { @@ -157,6 +161,9 @@ export class DatabaseService { { method: 'DELETE', credentials: 'include', + headers: { + ...csrfHeaders(), + }, } ); @@ -182,6 +189,7 @@ export class DatabaseService { method: 'POST', headers: { 'Content-Type': 'application/json', + ...csrfHeaders(), }, body: JSON.stringify({ url: config.connectionUrl, @@ -240,6 +248,7 @@ export class DatabaseService { method: 'POST', headers: { 'Content-Type': 'application/json', + ...csrfHeaders(), }, body: JSON.stringify({ url: connectionUrl, @@ -317,6 +326,7 @@ export class DatabaseService { credentials: 'include', headers: { 'Content-Type': 'application/json', + ...csrfHeaders(), }, body: JSON.stringify({ user_rules: userRules }), }); diff --git a/app/src/services/tokens.ts b/app/src/services/tokens.ts index 61b1125e..638a5ec5 100644 --- a/app/src/services/tokens.ts +++ b/app/src/services/tokens.ts @@ -3,6 +3,7 @@ */ import { buildApiUrl } from '@/config/api'; +import { csrfHeaders } from '@/lib/csrf'; export interface Token { token_id: string; @@ -27,6 +28,7 @@ export class TokenService { credentials: 'include', headers: { 'Content-Type': 'application/json', + ...csrfHeaders(), }, signal: controller.signal, }); @@ -93,6 +95,7 @@ export class TokenService { credentials: 'include', headers: { 'Content-Type': 'application/json', + ...csrfHeaders(), }, signal: controller.signal, }); diff --git a/e2e/infra/api/apiRequests.ts b/e2e/infra/api/apiRequests.ts index 512315ab..ef0e8bd0 100644 --- a/e2e/infra/api/apiRequests.ts +++ b/e2e/infra/api/apiRequests.ts @@ -2,6 +2,50 @@ import { APIRequestContext, request } from "@playwright/test" +/** + * Extract the CSRF token from a response's Set-Cookie header. + * The backend sets a `csrf_token` cookie on every response. + */ +function extractCsrfToken(setCookieHeaders: string[]): string | undefined { + for (const header of setCookieHeaders) { + const match = header.match(/csrf_token=([^;]+)/); + if (match) return match[1]; + } + return undefined; +} + +/** + * Per-context CSRF token cache. After the first seed request the token is + * stored and reused for subsequent calls on the same APIRequestContext, + * avoiding an extra GET /auth-status on every state-changing request. + */ +const csrfCache = new WeakMap(); + +/** + * Seed the CSRF cookie on the given request context by making a lightweight + * GET (only on the first call), then return the cached token value. + */ +async function getCsrfToken(baseUrl: string, ctx: APIRequestContext): Promise { + const cached = csrfCache.get(ctx); + if (cached) return cached; + + const seedResp = await ctx.get(`${baseUrl}/auth-status`); + const setCookies = seedResp.headersArray() + .filter(h => h.name.toLowerCase() === 'set-cookie') + .map(h => h.value); + const token = extractCsrfToken(setCookies); + if (token) csrfCache.set(ctx, token); + return token; +} + +/** + * Derive the origin (scheme + host + port) from a full URL so we can call + * `getCsrfToken` without requiring callers to pass the base URL separately. + */ +function originOf(url: string): string { + const u = new URL(url); + return u.origin; +} const getRequest = async (url: string, headers?: Record, body?: any, availableRequest?: APIRequestContext) => { const requestOptions = { @@ -15,34 +59,49 @@ const getRequest = async (url: string, headers?: Record, body?: }; const postRequest = async (url: string, body?: any, availableRequest?: APIRequestContext, headers?: Record) => { + const requestContext = availableRequest || (await request.newContext()); + const csrfToken = await getCsrfToken(originOf(url), requestContext); + const requestOptions = { data: body, - headers: headers || undefined, + headers: { + ...(headers || {}), + ...(csrfToken ? { 'X-CSRF-Token': csrfToken } : {}), + }, }; - const requestContext = availableRequest || (await request.newContext()); const response = await requestContext.post(url, requestOptions); return response; }; const deleteRequest = async (url: string, headers?: Record, body?: any, availableRequest?: APIRequestContext) => { + const requestContext = availableRequest || (await request.newContext()); + const csrfToken = await getCsrfToken(originOf(url), requestContext); + const requestOptions = { data: body, - headers: headers || undefined, + headers: { + ...(headers || {}), + ...(csrfToken ? { 'X-CSRF-Token': csrfToken } : {}), + }, }; - const requestContext = availableRequest || (await request.newContext()); const response = await requestContext.delete(url, requestOptions); return response; }; const patchRequest = async (url: string, body?: any, availableRequest?: APIRequestContext, headers?: Record) => { + const requestContext = availableRequest || (await request.newContext()); + const csrfToken = await getCsrfToken(originOf(url), requestContext); + const requestOptions = { data: body, - headers: headers || undefined, + headers: { + ...(headers || {}), + ...(csrfToken ? { 'X-CSRF-Token': csrfToken } : {}), + }, }; - const requestContext = availableRequest || (await request.newContext()); const response = await requestContext.patch(url, requestOptions); return response; }; diff --git a/tests/test_csrf_middleware.py b/tests/test_csrf_middleware.py new file mode 100644 index 00000000..11887e2e --- /dev/null +++ b/tests/test_csrf_middleware.py @@ -0,0 +1,170 @@ +""" +Tests for CSRF middleware (double-submit cookie pattern). +""" +import pytest +from fastapi.testclient import TestClient +from api.index import app + + +class TestCSRFMiddleware: + """Test CSRF double-submit cookie middleware.""" + + @pytest.fixture + def client(self): + """Create a test client.""" + return TestClient(app) + + # ---- Cookie provisioning ---- + + def test_get_sets_csrf_cookie(self, client): + """GET responses should include a csrf_token cookie.""" + response = client.get("/auth-status") + assert response.status_code == 200 + assert "csrf_token" in response.cookies + + def test_csrf_cookie_is_not_httponly(self, client): + """The CSRF cookie must be readable by JavaScript (not HttpOnly).""" + response = client.get("/auth-status") + # TestClient exposes raw Set-Cookie headers + set_cookie = response.headers.get("set-cookie", "") + assert "csrf_token=" in set_cookie + # httponly flag must NOT be present + assert "httponly" not in set_cookie.lower() + + # ---- Safe methods bypass ---- + + def test_get_does_not_require_csrf(self, client): + """GET requests must not be blocked by CSRF checks.""" + response = client.get("/auth-status") + assert response.status_code != 403 + + def test_head_does_not_require_csrf(self, client): + """HEAD requests must not be blocked by CSRF checks.""" + response = client.head("/auth-status") + assert response.status_code != 403 + + def test_options_does_not_require_csrf(self, client): + """OPTIONS requests must not be blocked by CSRF checks.""" + response = client.options("/auth-status") + assert response.status_code != 403 + + # ---- Blocking without token ---- + + def test_post_without_csrf_is_blocked(self, client): + """POST without CSRF header/cookie must return 403.""" + response = client.post("/logout") + assert response.status_code == 403 + assert response.json()["detail"] == "CSRF token missing or invalid" + + def test_post_with_wrong_csrf_is_blocked(self, client): + """POST with mismatched CSRF tokens must return 403.""" + response = client.post( + "/logout", + headers={"X-CSRF-Token": "wrong-value"}, + cookies={"csrf_token": "correct-value"}, + ) + assert response.status_code == 403 + + def test_csrf_rejection_sets_cookie(self, client): + """A 403 CSRF rejection should still set the csrf_token cookie.""" + response = client.post("/logout") + assert response.status_code == 403 + assert "csrf_token" in response.cookies + + # ---- Allowing with valid token ---- + + def test_post_with_valid_csrf_passes(self, client): + """POST with matching cookie + header must pass CSRF check.""" + # First get a token + get_resp = client.get("/auth-status") + csrf = get_resp.cookies["csrf_token"] + + response = client.post( + "/logout", + headers={"X-CSRF-Token": csrf}, + cookies={"csrf_token": csrf}, + ) + # Should not be 403 (will be 200 for logout) + assert response.status_code != 403 + + # ---- Bearer token bypass ---- + + def test_bearer_auth_bypasses_csrf(self, client): + """Requests with Bearer auth should skip CSRF (get 401, not 403).""" + response = client.post( + "/tokens/generate", + headers={"Authorization": "Bearer fake_token_value"}, + ) + # 401 = auth failed (expected), NOT 403 = CSRF blocked + assert response.status_code == 401 + + # ---- Exempt paths ---- + + def test_login_path_exempt(self, client): + """Login endpoints should be exempt from CSRF checks.""" + response = client.post( + "/login/email", + json={"email": "test@test.com", "password": "password"}, + ) + # Should NOT be 403 CSRF error + assert response.json().get("detail") != "CSRF token missing or invalid" + + def test_signup_path_exempt(self, client): + """Signup endpoints should be exempt from CSRF checks.""" + response = client.post( + "/signup/email", + json={ + "firstName": "Test", + "lastName": "User", + "email": "test@test.com", + "password": "password123", + }, + ) + assert response.json().get("detail") != "CSRF token missing or invalid" + + # ---- DELETE and PATCH methods ---- + + def test_delete_without_csrf_is_blocked(self, client): + """DELETE without CSRF header/cookie must return 403.""" + response = client.delete("/graphs/test-graph") + assert response.status_code == 403 + assert response.json()["detail"] == "CSRF token missing or invalid" + + def test_delete_with_valid_csrf_passes(self, client): + """DELETE with matching cookie + header must pass CSRF check.""" + get_resp = client.get("/auth-status") + csrf = get_resp.cookies["csrf_token"] + + response = client.delete( + "/graphs/test-graph", + headers={"X-CSRF-Token": csrf}, + cookies={"csrf_token": csrf}, + ) + assert response.status_code != 403 + + def test_patch_without_csrf_is_blocked(self, client): + """PATCH without CSRF header/cookie must return 403.""" + response = client.patch("/graphs/test-graph") + assert response.status_code == 403 + assert response.json()["detail"] == "CSRF token missing or invalid" + + def test_patch_with_valid_csrf_passes(self, client): + """PATCH with matching cookie + header must pass CSRF check.""" + get_resp = client.get("/auth-status") + csrf = get_resp.cookies["csrf_token"] + + response = client.patch( + "/graphs/test-graph", + headers={"X-CSRF-Token": csrf}, + cookies={"csrf_token": csrf}, + ) + assert response.status_code != 403 + + # ---- Secure flag based on scheme ---- + + def test_csrf_cookie_not_secure_on_http(self, client): + """Over plain HTTP the csrf_token cookie must NOT have the Secure flag.""" + response = client.get("/auth-status") + set_cookie = response.headers.get("set-cookie", "") + assert "csrf_token=" in set_cookie + assert "; secure" not in set_cookie.lower() From 63f1badff2f909214c83a5b48f9450d5db9b69eb Mon Sep 17 00:00:00 2001 From: Anchel123 <110421452+Anchel123@users.noreply.github.com> Date: Thu, 26 Feb 2026 14:04:08 +0200 Subject: [PATCH 10/18] Update @falkordb/canvas version to v0.0.40 (#440) * fix: update @falkordb/canvas version to 0.0.34 in package.json and package-lock.json * fix: update @falkordb/canvas version to 0.0.35 in package.json and package-lock.json * fix: update @falkordb/canvas version to 0.0.36 in package.json and package-lock.json * fix: update @falkordb/canvas version to 0.0.40 in package.json and package-lock.json * fix: update @falkordb/canvas version to 1.51.1 in package-lock.json --------- Co-authored-by: Guy Korland --- app/package-lock.json | 14 ++-- app/package.json | 2 +- package-lock.json | 167 ++---------------------------------------- 3 files changed, 15 insertions(+), 168 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index ff176e36..8a41e329 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -8,7 +8,7 @@ "name": "queryweaver-app", "version": "0.0.14", "dependencies": { - "@falkordb/canvas": "^0.0.29", + "@falkordb/canvas": "^0.0.40", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-accordion": "^1.2.11", "@radix-ui/react-alert-dialog": "^1.1.14", @@ -674,9 +674,9 @@ } }, "node_modules/@falkordb/canvas": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@falkordb/canvas/-/canvas-0.0.29.tgz", - "integrity": "sha512-dDx1H/lOinzQb9rvI5DKDh7+tpwBArkemzZ9iTefH1/iO7BQ0gMr5MsnLxQo0A0Y57RTzKlJRWlpRAwbM4IPag==", + "version": "0.0.40", + "resolved": "https://registry.npmjs.org/@falkordb/canvas/-/canvas-0.0.40.tgz", + "integrity": "sha512-sEIl10QHUXT5oGXkdLxY8saxStVQSxKfYd2THxJ4bjR77eq9L+OI8KYY5WRunX3UiZhfPiOy9PLaHHq0IuM8jg==", "license": "MIT", "dependencies": { "d3": "^7.9.0", @@ -4677,9 +4677,9 @@ } }, "node_modules/force-graph": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/force-graph/-/force-graph-1.51.0.tgz", - "integrity": "sha512-aTnihCmiMA0ItLJLCbrQYS9mzriopW24goFPgUnKAAmAlPogTSmFWqoBPMXzIfPb7bs04Hur5zEI4WYgLW3Sig==", + "version": "1.51.1", + "resolved": "https://registry.npmjs.org/force-graph/-/force-graph-1.51.1.tgz", + "integrity": "sha512-uEEX8iRzgq1IKRISOw6RrB2RLMhcI25xznQYrCTVvxZHZZ+A2jH6qIolYuwavVxAMi64pFp2yZm4KFVdD993cg==", "license": "MIT", "dependencies": { "@tweenjs/tween.js": "18 - 25", diff --git a/app/package.json b/app/package.json index dd41812c..3cd8783d 100644 --- a/app/package.json +++ b/app/package.json @@ -11,7 +11,7 @@ "preview": "vite preview" }, "dependencies": { - "@falkordb/canvas": "^0.0.29", + "@falkordb/canvas": "^0.0.40", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-accordion": "^1.2.11", "@radix-ui/react-alert-dialog": "^1.1.14", diff --git a/package-lock.json b/package-lock.json index 18275e17..644a1d86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "name": "queryweaver-app", "version": "0.0.14", "dependencies": { - "@falkordb/canvas": "^0.0.29", + "@falkordb/canvas": "^0.0.40", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-accordion": "^1.2.11", "@radix-ui/react-alert-dialog": "^1.1.14", @@ -258,6 +258,10 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "app/node_modules/@falkordb/canvas": { + "resolved": "packages/canvas", + "link": true + }, "app/node_modules/@floating-ui/core": { "version": "1.7.3", "license": "MIT", @@ -4834,17 +4838,6 @@ "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/@falkordb/canvas": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@falkordb/canvas/-/canvas-0.0.29.tgz", - "integrity": "sha512-dDx1H/lOinzQb9rvI5DKDh7+tpwBArkemzZ9iTefH1/iO7BQ0gMr5MsnLxQo0A0Y57RTzKlJRWlpRAwbM4IPag==", - "license": "MIT", - "dependencies": { - "d3": "^7.9.0", - "force-graph": "^1.44.4", - "react": "^19.2.3" - } - }, "node_modules/@playwright/test": { "version": "1.57.0", "dev": true, @@ -4886,12 +4879,6 @@ "node": ">=10" } }, - "node_modules/@tweenjs/tween.js": { - "version": "25.0.0", - "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-25.0.0.tgz", - "integrity": "sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A==", - "license": "MIT" - }, "node_modules/@types/node": { "version": "22.19.3", "dev": true, @@ -4900,37 +4887,6 @@ "undici-types": "~6.21.0" } }, - "node_modules/accessor-fn": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/accessor-fn/-/accessor-fn-1.5.3.tgz", - "integrity": "sha512-rkAofCwe/FvYFUlMB0v0gWmhqtfAtV1IUkdPbfhTUyYniu5LrC0A0UJkTH0Jv3S8SvwkmfuAlY+mQIJATdocMA==", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/bezier-js": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/bezier-js/-/bezier-js-6.1.4.tgz", - "integrity": "sha512-PA0FW9ZpcHbojUCMu28z9Vg/fNkwTj5YhusSAjHHDfHDGLxJ6YUKrAN2vk1fP2MMOxVw4Oko16FMlRGVBGqLKg==", - "license": "MIT", - "funding": { - "type": "individual", - "url": "https://github.com/Pomax/bezierjs/blob/master/FUNDING.md" - } - }, - "node_modules/canvas-color-tracker": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/canvas-color-tracker/-/canvas-color-tracker-1.3.2.tgz", - "integrity": "sha512-ryQkDX26yJ3CXzb3hxUVNlg1NKE4REc5crLBq661Nxzr8TNd236SaEf2ffYLXyI5tSABSeguHLqcVq4vf9L3Zg==", - "license": "MIT", - "dependencies": { - "tinycolor2": "^1.6.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -5002,12 +4958,6 @@ "node": ">=12" } }, - "node_modules/d3-binarytree": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d3-binarytree/-/d3-binarytree-1.0.2.tgz", - "integrity": "sha512-cElUNH+sHu95L04m92pG73t2MEJXKu+GeKUN1TJkFsu93E5W8E9Sc3kHEGJKgenGvj19m6upSn2EunvMgMD2Yw==", - "license": "MIT" - }, "node_modules/d3-brush": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", @@ -5151,22 +5101,6 @@ "node": ">=12" } }, - "node_modules/d3-force-3d": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/d3-force-3d/-/d3-force-3d-3.0.6.tgz", - "integrity": "sha512-4tsKHUPLOVkyfEffZo1v6sFHvGFwAIIjt/W8IThbp08DYAsXZck+2pSHEG5W1+gQgEvFLdZkYvmJAbRM2EzMnA==", - "license": "MIT", - "dependencies": { - "d3-binarytree": "1", - "d3-dispatch": "1 - 3", - "d3-octree": "1", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/d3-format": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", @@ -5209,12 +5143,6 @@ "node": ">=12" } }, - "node_modules/d3-octree": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-octree/-/d3-octree-1.1.0.tgz", - "integrity": "sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==", - "license": "MIT" - }, "node_modules/d3-path": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", @@ -5379,46 +5307,6 @@ "robust-predicates": "^3.0.2" } }, - "node_modules/float-tooltip": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/float-tooltip/-/float-tooltip-1.7.5.tgz", - "integrity": "sha512-/kXzuDnnBqyyWyhDMH7+PfP8J/oXiAavGzcRxASOMRHFuReDtofizLLJsf7nnDLAfEaMW4pVWaXrAjtnglpEkg==", - "license": "MIT", - "dependencies": { - "d3-selection": "2 - 3", - "kapsule": "^1.16", - "preact": "10" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/force-graph": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/force-graph/-/force-graph-1.51.0.tgz", - "integrity": "sha512-aTnihCmiMA0ItLJLCbrQYS9mzriopW24goFPgUnKAAmAlPogTSmFWqoBPMXzIfPb7bs04Hur5zEI4WYgLW3Sig==", - "license": "MIT", - "dependencies": { - "@tweenjs/tween.js": "18 - 25", - "accessor-fn": "1", - "bezier-js": "3 - 6", - "canvas-color-tracker": "^1.3", - "d3-array": "1 - 3", - "d3-drag": "2 - 3", - "d3-force-3d": "2 - 3", - "d3-scale": "1 - 4", - "d3-scale-chromatic": "1 - 3", - "d3-selection": "2 - 3", - "d3-zoom": "2 - 3", - "float-tooltip": "^1.7", - "index-array-by": "1", - "kapsule": "^1.16", - "lodash-es": "4" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -5459,15 +5347,6 @@ "node": ">=0.10.0" } }, - "node_modules/index-array-by": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/index-array-by/-/index-array-by-1.4.2.tgz", - "integrity": "sha512-SP23P27OUKzXWEC/TOyWlwLviofQkCSCKONnc62eItjp69yCZZPqDQtr3Pw5gJDnPeUMqExmKydNZaJO0FU9pw==", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -5477,24 +5356,6 @@ "node": ">=12" } }, - "node_modules/kapsule": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/kapsule/-/kapsule-1.16.3.tgz", - "integrity": "sha512-4+5mNNf4vZDSwPhKprKwz3330iisPrb08JyMgbsdFrimBCKNHecua/WBwvVg3n7vwx0C1ARjfhwIpbrbd9n5wg==", - "license": "MIT", - "dependencies": { - "lodash-es": "4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/lodash-es": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", - "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", - "license": "MIT" - }, "node_modules/playwright": { "version": "1.57.0", "dev": true, @@ -5537,15 +5398,6 @@ "resolved": "app", "link": true }, - "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/robust-predicates": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", @@ -5578,16 +5430,11 @@ "tailwindcss": ">=3.0.0 || insiders" } }, - "node_modules/tinycolor2": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", - "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", - "license": "MIT" - }, "node_modules/undici-types": { "version": "6.21.0", "dev": true, "license": "MIT" - } + }, + "packages/canvas": {} } } From 75d5ce36b2c9fdde1b6d665f42192b52ec57f9c3 Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Thu, 26 Feb 2026 15:08:29 +0200 Subject: [PATCH 11/18] fix(e2e): pass authenticated request context to API calls and browser pages - Add defaultRequestContext field to ApiCalls class, set via constructor - All API methods now use the default context for auth (session cookies + CSRF) - Tests use Playwright's request fixture which inherits storageState from config - Pass storageState path to BrowserWrapper.createNewPage for authenticated browser sessions - Revert outer test.describe.serial() to test.describe() to prevent cascade failures (inner Database Deletion Tests remain serial as needed) Fixes unauthenticated API requests that caused 401 errors in Firefox E2E tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- e2e/logic/api/apiCalls.ts | 40 ++++++++++++++++++++++++-------------- e2e/tests/chat.spec.ts | 20 +++++++++---------- e2e/tests/database.spec.ts | 24 +++++++++++------------ 3 files changed, 47 insertions(+), 37 deletions(-) diff --git a/e2e/logic/api/apiCalls.ts b/e2e/logic/api/apiCalls.ts index a932453a..6ffd2279 100644 --- a/e2e/logic/api/apiCalls.ts +++ b/e2e/logic/api/apiCalls.ts @@ -20,6 +20,12 @@ import type { // ==================== AUTHENTICATION ENDPOINTS ==================== export default class ApiCalls { + private defaultRequestContext?: APIRequestContext; + + constructor(requestContext?: APIRequestContext) { + this.defaultRequestContext = requestContext; + } + /** * Check authentication status * GET /auth-status @@ -33,7 +39,7 @@ export default class ApiCalls { `${baseUrl}/auth-status`, undefined, undefined, - requestContext + requestContext || this.defaultRequestContext ); return await response.json(); } catch (error) { @@ -57,7 +63,7 @@ export default class ApiCalls { const response = await postRequest( `${baseUrl}/login/email`, { email, password }, - requestContext + requestContext || this.defaultRequestContext ); const data = await response.json(); @@ -85,7 +91,7 @@ export default class ApiCalls { const response = await postRequest( `${baseUrl}/signup/email`, { firstName, lastName, email, password }, - requestContext + requestContext || this.defaultRequestContext ); return await response.json(); } catch (error) { @@ -107,7 +113,7 @@ export default class ApiCalls { const response = await postRequest( `${baseUrl}/logout`, undefined, - requestContext + requestContext || this.defaultRequestContext ); return await response.json(); } catch (error) { @@ -147,7 +153,8 @@ export default class ApiCalls { const response = await getRequest( `${baseUrl}/graphs`, undefined, - undefined + undefined, + this.defaultRequestContext ); return await response.json(); } catch (error) { @@ -169,7 +176,8 @@ export default class ApiCalls { const response = await getRequest( `${baseUrl}/graphs/${graphId}/data`, undefined, - undefined + undefined, + this.defaultRequestContext ); return await response.json(); } catch (error) { @@ -200,7 +208,7 @@ export default class ApiCalls { const response = await postRequest( `${baseUrl}/graphs`, formData, - undefined, + this.defaultRequestContext, { "Content-Type": "multipart/form-data" } ); return await response.json(); @@ -233,7 +241,7 @@ export default class ApiCalls { const response = await postRequest( `${baseUrl}/graphs/${graphId}`, body, - undefined, + this.defaultRequestContext, { "Content-Type": "application/json" } ); @@ -369,7 +377,7 @@ export default class ApiCalls { const response = await postRequest( `${baseUrl}/graphs/${graphId}/confirm`, body, - undefined, + this.defaultRequestContext, { "Content-Type": "application/json" } ); @@ -393,7 +401,7 @@ export default class ApiCalls { const response = await postRequest( `${baseUrl}/graphs/${graphId}/refresh`, undefined, - undefined, + this.defaultRequestContext, { "Content-Type": "application/json" } ); @@ -419,7 +427,7 @@ export default class ApiCalls { `${baseUrl}/graphs/${graphId}`, undefined, undefined, - requestContext + requestContext || this.defaultRequestContext ); return await response.json(); } catch (error) { @@ -448,7 +456,7 @@ export default class ApiCalls { const response = await postRequest( `${baseUrl}/database`, body, - undefined, + this.defaultRequestContext, { "Content-Type": "application/json" } ); @@ -471,7 +479,8 @@ export default class ApiCalls { const baseUrl = getBaseUrl(); const response = await postRequest( `${baseUrl}/tokens/generate`, - undefined + undefined, + this.defaultRequestContext ); return await response.json(); } catch (error) { @@ -491,7 +500,8 @@ export default class ApiCalls { const response = await getRequest( `${baseUrl}/tokens/list`, undefined, - undefined + undefined, + this.defaultRequestContext ); return await response.json(); } catch (error) { @@ -515,7 +525,7 @@ export default class ApiCalls { `${baseUrl}/tokens/${tokenId}`, undefined, undefined, - requestContext + requestContext || this.defaultRequestContext ); return await response.json(); } catch (error) { diff --git a/e2e/tests/chat.spec.ts b/e2e/tests/chat.spec.ts index ffbc6ba4..cf10442a 100644 --- a/e2e/tests/chat.spec.ts +++ b/e2e/tests/chat.spec.ts @@ -12,9 +12,9 @@ test.describe('Chat Feature Tests', () => { // Set longer timeout for chat tests (60 seconds) test.setTimeout(60000); - test.beforeEach(async () => { + test.beforeEach(async ({ request }) => { browser = new BrowserWrapper(); - apiCall = new ApiCalls(); + apiCall = new ApiCalls(request); }); test.afterEach(async () => { @@ -42,7 +42,7 @@ test.describe('Chat Feature Tests', () => { }); test('valid query shows SQL, results, and AI response', async () => { - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Ensure database is connected (will skip if already connected) @@ -74,7 +74,7 @@ test.describe('Chat Feature Tests', () => { }); test('off-topic query shows AI message without SQL or results', async () => { - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Ensure database is connected (will skip if already connected) @@ -105,7 +105,7 @@ test.describe('Chat Feature Tests', () => { }); test('multiple sequential queries maintain conversation history', async () => { - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Ensure database is connected (will skip if already connected) @@ -141,7 +141,7 @@ test.describe('Chat Feature Tests', () => { }); test('empty query submission is prevented', async () => { - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Ensure database is connected (will skip if already connected) @@ -153,7 +153,7 @@ test.describe('Chat Feature Tests', () => { }); test('rapid query submission is prevented during processing', async () => { - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Ensure database is connected (will skip if already connected) @@ -190,7 +190,7 @@ test.describe('Chat Feature Tests', () => { expect(finalMessage2.type).toBe('final_result'); expect(finalMessage2.success).toBeTruthy(); - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Wait for page to load databases @@ -224,7 +224,7 @@ test.describe('Chat Feature Tests', () => { }); test('destructive operation shows inline confirmation and executes on confirm', async () => { - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Ensure database is connected @@ -266,7 +266,7 @@ test.describe('Chat Feature Tests', () => { }); test('duplicate record shows user-friendly error message', async () => { - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Ensure database is connected diff --git a/e2e/tests/database.spec.ts b/e2e/tests/database.spec.ts index 2fa12f39..73c9ab4c 100644 --- a/e2e/tests/database.spec.ts +++ b/e2e/tests/database.spec.ts @@ -5,14 +5,14 @@ import BrowserWrapper from '../infra/ui/browserWrapper'; import ApiCalls from '../logic/api/apiCalls'; // Database connection tests - uses authenticated storageState from auth.setup -test.describe.serial('Database Connection Tests', () => { +test.describe('Database Connection Tests', () => { let browser: BrowserWrapper; let apiCall: ApiCalls; - test.beforeEach(async () => { + test.beforeEach(async ({ request }) => { browser = new BrowserWrapper(); - apiCall = new ApiCalls(); + apiCall = new ApiCalls(request); }); test.afterEach(async () => { @@ -21,7 +21,7 @@ test.describe.serial('Database Connection Tests', () => { test('connect PostgreSQL via API -> verify in UI', async () => { test.setTimeout(120000); // Allow extra time for schema loading in CI - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); const { postgres: postgresUrl } = getTestDatabases(); @@ -73,7 +73,7 @@ test.describe.serial('Database Connection Tests', () => { test('connect MySQL via API -> verify in UI', async () => { test.setTimeout(120000); // Allow extra time for schema loading in CI - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); const { mysql: mysqlUrl } = getTestDatabases(); @@ -125,7 +125,7 @@ test.describe.serial('Database Connection Tests', () => { test('connect PostgreSQL via UI (URL) -> verify via API', async () => { test.setTimeout(120000); // Allow extra time for schema loading in CI - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); const { postgres: postgresUrl } = getTestDatabases(); @@ -164,7 +164,7 @@ test.describe.serial('Database Connection Tests', () => { test('connect MySQL via UI (URL) -> verify via API', async () => { test.setTimeout(120000); // Allow extra time for schema loading in CI - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); const { mysql: mysqlUrl } = getTestDatabases(); @@ -203,7 +203,7 @@ test.describe.serial('Database Connection Tests', () => { test('connect PostgreSQL via UI (Manual Entry) -> verify via API', async () => { test.setTimeout(120000); // Allow extra time for schema loading in CI - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Connect via UI using manual entry mode @@ -247,7 +247,7 @@ test.describe.serial('Database Connection Tests', () => { test('connect MySQL via UI (Manual Entry) -> verify via API', async () => { test.setTimeout(120000); // Allow extra time for schema loading in CI - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Connect via UI using manual entry mode @@ -290,7 +290,7 @@ test.describe.serial('Database Connection Tests', () => { }); test('invalid connection string -> shows error', async () => { - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); const invalidUrl = 'invalid://connection:string'; @@ -352,7 +352,7 @@ test.describe.serial('Database Connection Tests', () => { const initialCount = graphsList.length; // Create new page and open it - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Delete via UI - open dropdown, click delete, confirm @@ -400,7 +400,7 @@ test.describe.serial('Database Connection Tests', () => { expect(graphId).toBeTruthy(); const initialCount = graphsList.length; - const homePage = await browser.createNewPage(HomePage, getBaseUrl()); + const homePage = await browser.createNewPage(HomePage, getBaseUrl(), 'e2e/.auth/user.json'); await browser.setPageToFullScreen(); // Wait for UI to reflect the connection (increased timeout for schema loading) From a7b39e6cd03f82ed5cf0297e00d97f5fbd986f56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 11:12:57 +0200 Subject: [PATCH 12/18] Bump fastapi from 0.133.0 to 0.135.0 (#446) * Bump fastapi from 0.133.0 to 0.135.0 Bumps [fastapi](https://github.com/fastapi/fastapi) from 0.133.0 to 0.135.0. - [Release notes](https://github.com/fastapi/fastapi/releases) - [Commits](https://github.com/fastapi/fastapi/compare/0.133.0...0.135.0) --- updated-dependencies: - dependency-name: fastapi dependency-version: 0.135.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * fix(e2e): read CSRF token from storageState when Set-Cookie is absent When the Playwright request fixture is initialised from a storageState that already carries a csrf_token cookie, the server does not emit a new Set-Cookie header. getCsrfToken() would then return undefined, causing every state-changing API call to fail with 403 'CSRF token missing or invalid'. Fall back to reading the token from the context's storageState() when the Set-Cookie header does not contain it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Guy Korland Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Pipfile | 2 +- Pipfile.lock | 8 ++++---- e2e/infra/api/apiRequests.ts | 16 +++++++++++++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Pipfile b/Pipfile index 0c72b53e..68486a4c 100644 --- a/Pipfile +++ b/Pipfile @@ -4,7 +4,7 @@ verify_ssl = true name = "pypi" [packages] -fastapi = "~=0.133.0" +fastapi = "~=0.135.0" uvicorn = "~=0.41.0" litellm = "~=1.81.15" falkordb = "~=1.6.0" diff --git a/Pipfile.lock b/Pipfile.lock index a6590a20..4e07acc4 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "d5a1352a56f59b2f5adf844f91e6ac73b1726ffcac0e4beede069e0e281a06d8" + "sha256": "01cd256299ee7875a03eb7bbb48362e405c0c38e359c227ba49ba1221d4bae1f" }, "pipfile-spec": 6, "requires": { @@ -604,12 +604,12 @@ }, "fastapi": { "hashes": [ - "sha256:0a78878483d60702a1dde864c24ab349a1a53ef4db6b6f74f8cd4a2b2bc67d2f", - "sha256:b900a2bf5685cdb0647a41d5900bdeafc3a9e8a28ac08c6246b76699e164d60d" + "sha256:31e2ddc78d6406c6f7d5d7b9996a057985e2600fbe7e9ba6ace8205d48dff688", + "sha256:bd37903acf014d1284bda027096e460814dca9699f9dacfe11c275749d949f4d" ], "index": "pypi", "markers": "python_version >= '3.10'", - "version": "==0.133.0" + "version": "==0.135.0" }, "fastmcp": { "hashes": [ diff --git a/e2e/infra/api/apiRequests.ts b/e2e/infra/api/apiRequests.ts index ef0e8bd0..babed7a5 100644 --- a/e2e/infra/api/apiRequests.ts +++ b/e2e/infra/api/apiRequests.ts @@ -24,6 +24,11 @@ const csrfCache = new WeakMap(); /** * Seed the CSRF cookie on the given request context by making a lightweight * GET (only on the first call), then return the cached token value. + * + * When the context is initialised from a storageState that already contains + * a csrf_token cookie, the server will NOT set a new one (no Set-Cookie + * header). In that case we fall back to reading the cookie value that is + * already stored in the context. */ async function getCsrfToken(baseUrl: string, ctx: APIRequestContext): Promise { const cached = csrfCache.get(ctx); @@ -33,7 +38,16 @@ async function getCsrfToken(baseUrl: string, ctx: APIRequestContext): Promise h.name.toLowerCase() === 'set-cookie') .map(h => h.value); - const token = extractCsrfToken(setCookies); + let token = extractCsrfToken(setCookies); + + // If the server didn't set a new cookie, the context may already carry one + // from its storageState – read it directly. + if (!token) { + const state = await ctx.storageState(); + const existing = state.cookies.find(c => c.name === 'csrf_token'); + if (existing) token = existing.value; + } + if (token) csrfCache.set(ctx, token); return token; } From fd56f783cd4fff3e0bc2f1405c057a8919de9540 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 11:25:39 +0200 Subject: [PATCH 13/18] Bump actions/upload-artifact from 6 to 7 (#444) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Guy Korland --- .github/workflows/playwright.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 89a5f907..7ce41b69 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -148,7 +148,7 @@ jobs: CI: true # Upload test results on failure - - uses: actions/upload-artifact@v6 + - uses: actions/upload-artifact@v7 if: failure() with: name: playwright-report @@ -156,7 +156,7 @@ jobs: retention-days: 30 # Upload test screenshots on failure - - uses: actions/upload-artifact@v6 + - uses: actions/upload-artifact@v7 if: failure() with: name: test-results From f7ff24bb2bdfcd7d5ce922fdea9a52f1362d4e89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 11:50:31 +0200 Subject: [PATCH 14/18] Bump the npm-minor-patch group in /app with 5 updates (#443) * Bump the npm-minor-patch group in /app with 5 updates Bumps the npm-minor-patch group in /app with 5 updates: | Package | From | To | | --- | --- | --- | | [@falkordb/canvas](https://github.com/FalkorDB/falkordb-canvas) | `0.0.40` | `0.0.41` | | [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) | `5.90.19` | `5.90.21` | | [preact](https://github.com/preactjs/preact) | `10.28.3` | `10.28.4` | | [react-hook-form](https://github.com/react-hook-form/react-hook-form) | `7.71.1` | `7.71.2` | | [autoprefixer](https://github.com/postcss/autoprefixer) | `10.4.23` | `10.4.27` | Updates `@falkordb/canvas` from 0.0.40 to 0.0.41 - [Release notes](https://github.com/FalkorDB/falkordb-canvas/releases) - [Commits](https://github.com/FalkorDB/falkordb-canvas/compare/v0.0.40...v0.0.41) Updates `@tanstack/react-query` from 5.90.19 to 5.90.21 - [Release notes](https://github.com/TanStack/query/releases) - [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md) - [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.90.21/packages/react-query) Updates `preact` from 10.28.3 to 10.28.4 - [Release notes](https://github.com/preactjs/preact/releases) - [Commits](https://github.com/preactjs/preact/compare/10.28.3...10.28.4) Updates `react-hook-form` from 7.71.1 to 7.71.2 - [Release notes](https://github.com/react-hook-form/react-hook-form/releases) - [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md) - [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.71.1...v7.71.2) Updates `autoprefixer` from 10.4.23 to 10.4.27 - [Release notes](https://github.com/postcss/autoprefixer/releases) - [Changelog](https://github.com/postcss/autoprefixer/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/autoprefixer/compare/10.4.23...10.4.27) --- updated-dependencies: - dependency-name: "@falkordb/canvas" dependency-version: 0.0.41 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: "@tanstack/react-query" dependency-version: 5.90.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: preact dependency-version: 10.28.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: react-hook-form dependency-version: 7.71.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: autoprefixer dependency-version: 10.4.27 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch ... Signed-off-by: dependabot[bot] * Update root package-lock.json for app dependency bumps The root package-lock.json must be kept in sync with app/package.json changes since root package.json references app via file: protocol. Without this update, npm ci at the root fails with lockfile mismatch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Guy Korland Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- app/package-lock.json | 46 ++-- app/package.json | 10 +- package-lock.json | 609 ++++++++++++++++++++++-------------------- 3 files changed, 359 insertions(+), 306 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index 8a41e329..e0e7623f 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -8,7 +8,7 @@ "name": "queryweaver-app", "version": "0.0.14", "dependencies": { - "@falkordb/canvas": "^0.0.40", + "@falkordb/canvas": "^0.0.41", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-accordion": "^1.2.11", "@radix-ui/react-alert-dialog": "^1.1.14", @@ -37,7 +37,7 @@ "@radix-ui/react-toggle": "^1.1.9", "@radix-ui/react-toggle-group": "^1.1.10", "@radix-ui/react-tooltip": "^1.2.7", - "@tanstack/react-query": "^5.83.0", + "@tanstack/react-query": "^5.90.21", "@types/d3": "^7.4.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -48,11 +48,11 @@ "input-otp": "^1.4.2", "lucide-react": "^0.462.0", "next-themes": "^0.3.0", - "preact": "^10.28.2", + "preact": "^10.28.4", "react": "^18.3.1", "react-day-picker": "^8.10.1", "react-dom": "^18.3.1", - "react-hook-form": "^7.61.1", + "react-hook-form": "^7.71.2", "react-resizable-panels": "^2.1.9", "react-router-dom": "^6.30.1", "recharts": "^2.15.4", @@ -69,7 +69,7 @@ "@types/react": "^18.3.23", "@types/react-dom": "^18.3.7", "@vitejs/plugin-react-swc": "^3.11.0", - "autoprefixer": "^10.4.21", + "autoprefixer": "^10.4.27", "eslint": "^9.32.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", @@ -674,9 +674,9 @@ } }, "node_modules/@falkordb/canvas": { - "version": "0.0.40", - "resolved": "https://registry.npmjs.org/@falkordb/canvas/-/canvas-0.0.40.tgz", - "integrity": "sha512-sEIl10QHUXT5oGXkdLxY8saxStVQSxKfYd2THxJ4bjR77eq9L+OI8KYY5WRunX3UiZhfPiOy9PLaHHq0IuM8jg==", + "version": "0.0.41", + "resolved": "https://registry.npmjs.org/@falkordb/canvas/-/canvas-0.0.41.tgz", + "integrity": "sha512-r2DC2Mo9naASr3DDmVKCQVY/S50Hn2bGlmKaFxDRFcn5btiuuvPBqJ3krtC+uz5ZPmad8EoXRRlcQ6KwKJhUZw==", "license": "MIT", "dependencies": { "d3": "^7.9.0", @@ -2923,7 +2923,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.90.19", + "version": "5.90.20", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz", + "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==", "license": "MIT", "funding": { "type": "github", @@ -2931,10 +2933,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.90.19", + "version": "5.90.21", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz", + "integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.90.19" + "@tanstack/query-core": "5.90.20" }, "funding": { "type": "github", @@ -3519,7 +3523,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.23", + "version": "10.4.27", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", + "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", "dev": true, "funding": [ { @@ -3538,7 +3544,7 @@ "license": "MIT", "dependencies": { "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001760", + "caniuse-lite": "^1.0.30001774", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -3653,7 +3659,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001764", + "version": "1.0.30001775", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001775.tgz", + "integrity": "sha512-s3Qv7Lht9zbVKE9XoTyRG6wVDCKdtOFIjBGg3+Yhn6JaytuNKPIjBMTMIY1AnOH3seL5mvF+x33oGAyK3hVt3A==", "dev": true, "funding": [ { @@ -5391,9 +5399,9 @@ "license": "MIT" }, "node_modules/preact": { - "version": "10.28.3", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.3.tgz", - "integrity": "sha512-tCmoRkPQLpBeWzpmbhryairGnhW9tKV6c6gr/w+RhoRoKEJwsjzipwp//1oCpGPOchvSLaAPlpcJi9MwMmoPyA==", + "version": "10.28.4", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.4.tgz", + "integrity": "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==", "license": "MIT", "funding": { "type": "opencollective", @@ -5481,7 +5489,9 @@ } }, "node_modules/react-hook-form": { - "version": "7.71.1", + "version": "7.71.2", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.2.tgz", + "integrity": "sha512-1CHvcDYzuRUNOflt4MOq3ZM46AronNJtQ1S7tnX6YN4y72qhgiUItpacZUAQ0TyWYci3yz1X+rXaSxiuEm86PA==", "license": "MIT", "engines": { "node": ">=18.0.0" diff --git a/app/package.json b/app/package.json index 3cd8783d..52ec4b17 100644 --- a/app/package.json +++ b/app/package.json @@ -11,7 +11,7 @@ "preview": "vite preview" }, "dependencies": { - "@falkordb/canvas": "^0.0.40", + "@falkordb/canvas": "^0.0.41", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-accordion": "^1.2.11", "@radix-ui/react-alert-dialog": "^1.1.14", @@ -40,7 +40,7 @@ "@radix-ui/react-toggle": "^1.1.9", "@radix-ui/react-toggle-group": "^1.1.10", "@radix-ui/react-tooltip": "^1.2.7", - "@tanstack/react-query": "^5.83.0", + "@tanstack/react-query": "^5.90.21", "@types/d3": "^7.4.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -51,11 +51,11 @@ "input-otp": "^1.4.2", "lucide-react": "^0.462.0", "next-themes": "^0.3.0", - "preact": "^10.28.2", + "preact": "^10.28.4", "react": "^18.3.1", "react-day-picker": "^8.10.1", "react-dom": "^18.3.1", - "react-hook-form": "^7.61.1", + "react-hook-form": "^7.71.2", "react-resizable-panels": "^2.1.9", "react-router-dom": "^6.30.1", "recharts": "^2.15.4", @@ -72,7 +72,7 @@ "@types/react": "^18.3.23", "@types/react-dom": "^18.3.7", "@vitejs/plugin-react-swc": "^3.11.0", - "autoprefixer": "^10.4.21", + "autoprefixer": "^10.4.27", "eslint": "^9.32.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", diff --git a/package-lock.json b/package-lock.json index 644a1d86..a73d9881 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "QueryWeaver", + "name": "queryweaver", "lockfileVersion": 3, "requires": true, "packages": { @@ -18,7 +18,7 @@ "name": "queryweaver-app", "version": "0.0.14", "dependencies": { - "@falkordb/canvas": "^0.0.40", + "@falkordb/canvas": "^0.0.41", "@hookform/resolvers": "^3.10.0", "@radix-ui/react-accordion": "^1.2.11", "@radix-ui/react-alert-dialog": "^1.1.14", @@ -47,7 +47,7 @@ "@radix-ui/react-toggle": "^1.1.9", "@radix-ui/react-toggle-group": "^1.1.10", "@radix-ui/react-tooltip": "^1.2.7", - "@tanstack/react-query": "^5.83.0", + "@tanstack/react-query": "^5.90.21", "@types/d3": "^7.4.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -58,11 +58,11 @@ "input-otp": "^1.4.2", "lucide-react": "^0.462.0", "next-themes": "^0.3.0", - "preact": "^10.28.2", + "preact": "^10.28.4", "react": "^18.3.1", "react-day-picker": "^8.10.1", "react-dom": "^18.3.1", - "react-hook-form": "^7.61.1", + "react-hook-form": "^7.71.2", "react-resizable-panels": "^2.1.9", "react-router-dom": "^6.30.1", "recharts": "^2.15.4", @@ -79,7 +79,7 @@ "@types/react": "^18.3.23", "@types/react-dom": "^18.3.7", "@vitejs/plugin-react-swc": "^3.11.0", - "autoprefixer": "^10.4.21", + "autoprefixer": "^10.4.27", "eslint": "^9.32.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", @@ -2002,28 +2002,6 @@ "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, - "app/node_modules/@tanstack/query-core": { - "version": "5.90.19", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "app/node_modules/@tanstack/react-query": { - "version": "5.90.19", - "license": "MIT", - "dependencies": { - "@tanstack/query-core": "5.90.19" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^18 || ^19" - } - }, "app/node_modules/@types/d3": { "version": "7.4.3", "license": "MIT", @@ -2588,54 +2566,11 @@ "node": ">=10" } }, - "app/node_modules/autoprefixer": { - "version": "10.4.23", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001760", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "app/node_modules/balanced-match": { "version": "1.0.2", "dev": true, "license": "MIT" }, - "app/node_modules/baseline-browser-mapping": { - "version": "2.9.15", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, "app/node_modules/binary-extensions": { "version": "2.3.0", "license": "MIT", @@ -2665,39 +2600,6 @@ "node": ">=8" } }, - "app/node_modules/browserslist": { - "version": "4.28.1", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, "app/node_modules/callsites": { "version": "3.1.0", "dev": true, @@ -2713,25 +2615,6 @@ "node": ">= 6" } }, - "app/node_modules/caniuse-lite": { - "version": "1.0.30001764", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, "app/node_modules/chalk": { "version": "4.1.2", "dev": true, @@ -2912,11 +2795,6 @@ "csstype": "^3.0.2" } }, - "app/node_modules/electron-to-chromium": { - "version": "1.5.267", - "dev": true, - "license": "ISC" - }, "app/node_modules/embla-carousel": { "version": "8.6.0", "license": "MIT", @@ -2980,14 +2858,6 @@ "@esbuild/win32-x64": "0.27.2" } }, - "app/node_modules/escalade": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "app/node_modules/escape-string-regexp": { "version": "4.0.0", "dev": true, @@ -3267,18 +3137,6 @@ "dev": true, "license": "ISC" }, - "app/node_modules/fraction.js": { - "version": "5.3.4", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, "app/node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3434,10 +3292,6 @@ "jiti": "bin/jiti.js" } }, - "app/node_modules/js-tokens": { - "version": "4.0.0", - "license": "MIT" - }, "app/node_modules/js-yaml": { "version": "4.1.1", "dev": true, @@ -3521,16 +3375,6 @@ "dev": true, "license": "MIT" }, - "app/node_modules/loose-envify": { - "version": "1.4.0", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, "app/node_modules/lucide-react": { "version": "0.462.0", "license": "ISC", @@ -3581,22 +3425,6 @@ "thenify-all": "^1.0.0" } }, - "app/node_modules/nanoid": { - "version": "3.3.11", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "app/node_modules/natural-compare": { "version": "1.4.0", "dev": true, @@ -3610,11 +3438,6 @@ "react-dom": "^16.8 || ^17 || ^18" } }, - "app/node_modules/node-releases": { - "version": "2.0.27", - "dev": true, - "license": "MIT" - }, "app/node_modules/normalize-path": { "version": "3.0.0", "license": "MIT", @@ -3711,10 +3534,6 @@ "version": "1.0.7", "license": "MIT" }, - "app/node_modules/picocolors": { - "version": "1.1.1", - "license": "ISC" - }, "app/node_modules/picomatch": { "version": "2.3.1", "license": "MIT", @@ -3739,33 +3558,6 @@ "node": ">= 6" } }, - "app/node_modules/postcss": { - "version": "8.5.6", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "app/node_modules/postcss-import": { "version": "15.1.0", "license": "MIT", @@ -3890,10 +3682,6 @@ "node": ">=4" } }, - "app/node_modules/postcss-value-parser": { - "version": "4.2.0", - "license": "MIT" - }, "app/node_modules/prelude-ls": { "version": "1.2.1", "dev": true, @@ -3941,17 +3729,6 @@ ], "license": "MIT" }, - "app/node_modules/react": { - "version": "18.3.1", - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "app/node_modules/react-day-picker": { "version": "8.10.1", "license": "MIT", @@ -3976,21 +3753,6 @@ "react": "^18.3.1" } }, - "app/node_modules/react-hook-form": { - "version": "7.71.1", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/react-hook-form" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17 || ^18 || ^19" - } - }, "app/node_modules/react-is": { "version": "18.3.1", "license": "MIT" @@ -4309,13 +4071,6 @@ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, - "app/node_modules/source-map-js": { - "version": "1.2.1", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "app/node_modules/strip-json-comments": { "version": "3.1.1", "dev": true, @@ -4578,35 +4333,6 @@ "dev": true, "license": "MIT" }, - "app/node_modules/update-browserslist-db": { - "version": "1.2.3", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, "app/node_modules/uri-js": { "version": "4.4.1", "dev": true, @@ -4879,6 +4605,32 @@ "node": ">=10" } }, + "node_modules/@tanstack/query-core": { + "version": "5.90.20", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz", + "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.90.21", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz", + "integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.90.20" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, "node_modules/@types/node": { "version": "22.19.3", "dev": true, @@ -4887,6 +4639,112 @@ "undici-types": "~6.21.0" } }, + "node_modules/autoprefixer": { + "version": "10.4.27", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", + "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001774", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001775", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001775.tgz", + "integrity": "sha512-s3Qv7Lht9zbVKE9XoTyRG6wVDCKdtOFIjBGg3+Yhn6JaytuNKPIjBMTMIY1AnOH3seL5mvF+x33oGAyK3hVt3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -5307,6 +5165,37 @@ "robust-predicates": "^3.0.2" } }, + "node_modules/electron-to-chromium": { + "version": "1.5.302", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", + "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -5356,6 +5245,55 @@ "node": ">=12" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, "node_modules/playwright": { "version": "1.57.0", "dev": true, @@ -5384,10 +5322,45 @@ "node": ">=18" } }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, "node_modules/preact": { - "version": "10.28.3", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.3.tgz", - "integrity": "sha512-tCmoRkPQLpBeWzpmbhryairGnhW9tKV6c6gr/w+RhoRoKEJwsjzipwp//1oCpGPOchvSLaAPlpcJi9MwMmoPyA==", + "version": "10.28.4", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.4.tgz", + "integrity": "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==", "license": "MIT", "funding": { "type": "opencollective", @@ -5398,6 +5371,36 @@ "resolved": "app", "link": true }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-hook-form": { + "version": "7.71.2", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.2.tgz", + "integrity": "sha512-1CHvcDYzuRUNOflt4MOq3ZM46AronNJtQ1S7tnX6YN4y72qhgiUItpacZUAQ0TyWYci3yz1X+rXaSxiuEm86PA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, "node_modules/robust-predicates": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", @@ -5416,6 +5419,15 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/tailwindcss": { "version": "4.1.17", "dev": true, @@ -5435,6 +5447,37 @@ "dev": true, "license": "MIT" }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "packages/canvas": {} } } From 1e127554a896137de3d2ecdb15ddded527743be3 Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Mon, 2 Mar 2026 13:22:14 +0200 Subject: [PATCH 15/18] perf(ci): accelerate Playwright CI from ~16min to ~5min (#448) * perf(ci): accelerate Playwright CI from ~16min to ~5min - Increase CI workers from 1 to 4 (matches ubuntu-latest vCPUs) - Skip Firefox in CI, run Chromium only (halves test count) - Reduce retries from 2 to 1 (still catches transient failures) - Add pip, npm, and Playwright browser caching - Replace hardcoded sleep 20 with health-check polling - Install only Chromium browser (not Firefox) in CI Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(ci): fix YAML indentation and use docker compose --wait Replace inline Python health-check with docker compose --wait flag which natively waits for service healthchecks to pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(ci): remove pip cache (incompatible with pipenv setup) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(ci): keep 2 retries for flaky AI-dependent chat tests Chat tests that interact with the AI processing endpoint need 2 retries to handle intermittent timeouts, especially under parallel execution. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(ci): key npm cache on both root and app lockfiles The setup-node npm cache was only keyed on the root package-lock.json. Add cache-dependency-path to include app/package-lock.json so the cache invalidates when frontend dependencies change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(ci): add pip caching with Pipfile.lock dependency path The setup-python cache: 'pip' was removed earlier because it failed without cache-dependency-path (defaults to requirements*.txt). Re-add it with cache-dependency-path: Pipfile.lock so pip downloads are cached between runs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: update comment to reflect hard-coded worker count The comment said 'Use all available vCPUs' but the config hard-codes 4 workers. Update to accurately describe the intentional pinning. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/playwright.yml | 30 ++++++++++++++++++++++-------- playwright.config.ts | 10 +++++----- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 7ce41b69..94891b53 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -30,11 +30,17 @@ jobs: uses: actions/setup-python@v6 with: python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + cache-dependency-path: Pipfile.lock # Setup Node.js - uses: actions/setup-node@v6 with: node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + cache-dependency-path: | + package-lock.json + app/package-lock.json # Install pipenv - name: Install pipenv @@ -48,6 +54,14 @@ jobs: - name: Install root dependencies run: npm ci + # Cache Playwright browsers + - name: Cache Playwright browsers + id: playwright-cache + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-browsers-${{ runner.os }}-${{ hashFiles('package-lock.json') }} + # Install Node dependencies (frontend) - name: Install frontend dependencies run: npm ci @@ -61,13 +75,8 @@ jobs: # Start Docker Compose services (test databases) - name: Start test databases run: | - docker compose -f e2e/docker-compose.test.yml up -d - # Wait for databases to be healthy - echo "Waiting for databases to be ready..." - sleep 20 + docker compose -f e2e/docker-compose.test.yml up -d --wait --wait-timeout 120 docker ps -a - # Verify all containers are running - docker compose -f e2e/docker-compose.test.yml ps # Start FalkorDB (Redis graph database) - name: Start FalkorDB @@ -133,9 +142,14 @@ jobs: AZURE_API_BASE: ${{ secrets.AZURE_API_BASE }} AZURE_API_VERSION: ${{ secrets.AZURE_API_VERSION }} - # Install Playwright browsers + # Install Playwright browsers (Chromium only in CI) - name: Install Playwright Browsers - run: npx playwright install --with-deps chromium firefox + if: steps.playwright-cache.outputs.cache-hit != 'true' + run: npx playwright install --with-deps chromium + + - name: Install Playwright system deps + if: steps.playwright-cache.outputs.cache-hit == 'true' + run: npx playwright install-deps chromium # Create auth directory for storage state - name: Create auth directory diff --git a/playwright.config.ts b/playwright.config.ts index 7f9f78fa..b48465c0 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -19,8 +19,8 @@ export default defineConfig({ forbidOnly: !!process.env.CI, /* Retry on CI only */ retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, + /* Pin to 4 workers on CI (matches ubuntu-latest vCPU count) */ + workers: process.env.CI ? 4 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: 'html', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ @@ -53,15 +53,15 @@ export default defineConfig({ dependencies: ['setup'], }, - { + // Firefox is only run locally; skipped in CI to halve test time + ...(!process.env.CI ? [{ name: 'firefox', use: { ...devices['Desktop Firefox'], - // Use saved authentication state storageState: 'e2e/.auth/user.json', }, dependencies: ['setup'], - }, + }] : []), // { // name: 'webkit', From 83e240edbb5156f80ac2dfc3ff87810bbac726a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 13:23:01 +0200 Subject: [PATCH 16/18] Bump litellm from 1.81.15 to 1.82.0 (#445) Bumps [litellm](https://github.com/BerriAI/litellm) from 1.81.15 to 1.82.0. - [Release notes](https://github.com/BerriAI/litellm/releases) - [Commits](https://github.com/BerriAI/litellm/commits) --- updated-dependencies: - dependency-name: litellm dependency-version: 1.82.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Guy Korland --- Pipfile | 2 +- Pipfile.lock | 572 +++++++++++++++++++++++++-------------------------- 2 files changed, 286 insertions(+), 288 deletions(-) diff --git a/Pipfile b/Pipfile index 68486a4c..c1c7fa77 100644 --- a/Pipfile +++ b/Pipfile @@ -6,7 +6,7 @@ name = "pypi" [packages] fastapi = "~=0.135.0" uvicorn = "~=0.41.0" -litellm = "~=1.81.15" +litellm = "~=1.82.0" falkordb = "~=1.6.0" psycopg2-binary = "~=2.9.11" pymysql = "~=1.1.0" diff --git a/Pipfile.lock b/Pipfile.lock index 4e07acc4..a01f66f2 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "01cd256299ee7875a03eb7bbb48362e405c0c38e359c227ba49ba1221d4bae1f" + "sha256": "1fba6f108fd74d27ba11d829c89ee35b72233b52c5efefd802e877194ff152e8" }, "pipfile-spec": 6, "requires": { @@ -706,11 +706,11 @@ }, "filelock": { "hashes": [ - "sha256:011a5644dc937c22699943ebbfc46e969cdde3e171470a6e40b9533e5a72affa", - "sha256:426e9a4660391f7f8a810d71b0555bce9008b0a1cc342ab1f6947d37639e002d" + "sha256:5ccf8069f7948f494968fc0713c10e5c182a9c9d9eef3a636307a20c2490f047", + "sha256:8f00faf3abf9dc730a1ffe9c354ae5c04e079ab7d3a683b7c32da5dd05f26af3" ], "markers": "python_version >= '3.10'", - "version": "==3.24.3" + "version": "==3.25.0" }, "frozenlist": { "hashes": [ @@ -871,34 +871,34 @@ }, "hf-xet": { "hashes": [ - "sha256:0810b69c64e96dee849036193848007f665dca2311879c9ea8693f4fc37f1795", - "sha256:08b231260c68172c866f7aa7257c165d0c87887491aafc5efeee782731725366", - "sha256:1684c840c60da12d76c2a031ba40e4b154fdbf9593836fcf5ff090d95a033c61", - "sha256:2973c3ff594c3a8da890836308cae1444c8af113c6f10fe6824575ddbc37eca7", - "sha256:329c80c86f2dda776bafd2e4813a46a3ee648dce3ac0c84625902c70d7a6ddba", - "sha256:4a322d506c513f98fdc1aa2aaa825daefd535b686e80ca789e6d33fcb146f524", - "sha256:4bc71afd853508b2ddf123b8fc9de71b0afa4c956ec730b69fb76103781e94cd", - "sha256:4eb432e1aa707a65a7e1f8455e40c5b47431d44fe0fb1b0c5d53848c27469398", - "sha256:513aa75f8dc39a63cc44dbc8d635ccf6b449e07cdbd8b2e2d006320d2e4be9bb", - "sha256:541b4b00ed294ae6cfd9416de9506e58971013714d7316189c9638ed54e362d4", - "sha256:581d1809a016f7881069d86a072168a8199a46c839cf394ff53970a47e4f1ca1", - "sha256:607d5bbc2730274516714e2e442a26e40e3330673ac0d0173004461409147dee", - "sha256:6517a245e41df3eae5adc5f9e8c86fa52abd548de798cbcd989f0082152860aa", - "sha256:65411867d46700765018b1990eb1604c3bf0bf576d9e65fc57fdcc10797a2eb9", - "sha256:713913387cc76e300116030705d843a9f15aee86158337eeffb9eb8d26f47fcd", - "sha256:83a8830160392ef4bea78d443ea2cf1febe65783b3843a8f12c64b368981e7e2", - "sha256:851b1be6597a87036fe7258ce7578d5df3c08176283b989c3b165f94125c5097", - "sha256:8f16ec9d26badec46334a798e01b5d86af536924789c95b1a1ec6a05f26523e0", - "sha256:b3012c0f2ce1f0863338491a2bc0fd3f84aded0e147ab25f230da1f5249547fd", - "sha256:e1f5d72bd5b73e61530fff573bcff34bdb64af2bf4862cdd516e6c1dab4dc75b", - "sha256:e5063789c9d21f51e9ed4edbee8539655d3486e9cad37e96b7af967da20e8b16", - "sha256:e56104c84b2a88b9c7b23ba11a2d7ed0ccbe96886b3f985a50cedd2f0e99853f", - "sha256:ecd38f98e7f0f41108e30fd4a9a5553ec30cf726df7473dd3e75a1b6d56728c2", - "sha256:ed4bfd2e6d10cb86c9b0f3483df1d7dd2d0220f75f27166925253bacbc1c2dbe", - "sha256:f85480b4fe3e8e4cdbc59ef1d235152b732fd57ca439cc983c291892945ae818" + "sha256:06b724a361f670ae557836e57801b82c75b534812e351a87a2c739f77d1e0635", + "sha256:06cdbde243c85f39a63b28e9034321399c507bcd5e7befdd17ed2ccc06dfe14e", + "sha256:1c88fbd90ad0d27c46b77a445f0a436ebaa94e14965c581123b68b1c52f5fd30", + "sha256:211f30098512d95e85ad03ae63bd7dd2c4df476558a5095d09f9e38e78cbf674", + "sha256:305f5489d7241a47e0458ef49334be02411d1d0f480846363c1c8084ed9916f7", + "sha256:3155a02e083aa21fd733a7485c7c36025e49d5975c8d6bda0453d224dd0b0ac4", + "sha256:31612ba0629046e425ba50375685a2586e11fb9144270ebabd75878c3eaf6378", + "sha256:335a8f36c55fd35a92d0062f4e9201b4015057e62747b7e7001ffb203c0ee1d2", + "sha256:35b855024ca37f2dd113ac1c08993e997fbe167b9d61f9ef66d3d4f84015e508", + "sha256:433c77c9f4e132b562f37d66c9b22c05b5479f243a1f06a120c1c06ce8b1502a", + "sha256:4a6817c41de7c48ed9270da0b02849347e089c5ece9a0e72ae4f4b3a57617f82", + "sha256:4bc995d6c41992831f762096020dc14a65fdf3963f86ffed580b596d04de32e3", + "sha256:7c2a054a97c44e136b1f7f5a78f12b3efffdf2eed3abc6746fc5ea4b39511633", + "sha256:83d8ec273136171431833a6957e8f3af496bee227a0fe47c7b8b39c106d1749a", + "sha256:91b1dc03c31cbf733d35dc03df7c5353686233d86af045e716f1e0ea4a2673cf", + "sha256:9298b47cce6037b7045ae41482e703c471ce36b52e73e49f71226d2e8e5685a1", + "sha256:959083c89dee30f7d6f890b36cdadda823386c4de63b1a30384a75bfd2ae995d", + "sha256:a85d3d43743174393afe27835bde0cd146e652b5fcfdbcd624602daef2ef3259", + "sha256:c1980abfb68ecf6c1c7983379ed7b1e2b49a1aaf1a5aca9acc7d48e5e2e0a961", + "sha256:c1ae4d3a716afc774e66922f3cac8206bfa707db13f6a7e62dfff74bfc95c9a8", + "sha256:c34e2c7aefad15792d57067c1c89b2b02c1bbaeabd7f8456ae3d07b4bbaf4094", + "sha256:cfa760888633b08c01b398d212ce7e8c0d7adac6c86e4b20dfb2397d8acd78ee", + "sha256:d6dbdf231efac0b9b39adcf12a07f0c030498f9212a18e8c50224d0e84ab803d", + "sha256:e130ee08984783d12717444e538587fa2119385e5bd8fc2bb9f930419b73a7af", + "sha256:f93b7595f1d8fefddfede775c18b5c9256757824f7f6832930b49858483cd56f" ], "markers": "python_version >= '3.8'", - "version": "==1.3.1" + "version": "==1.3.2" }, "httpcore": { "hashes": [ @@ -926,11 +926,11 @@ }, "huggingface-hub": { "hashes": [ - "sha256:9931d075fb7a79af5abc487106414ec5fba2c0ae86104c0c62fd6cae38873d18", - "sha256:b41131ec35e631e7383ab26d6146b8d8972abc8b6309b963b306fbcca87f5ed5" + "sha256:c9c0b3ab95a777fc91666111f3b3ede71c0cdced3614c553a64e98920585c4ee", + "sha256:f281838db29265880fb543de7a23b0f81d3504675de82044307ea3c6c62f799d" ], "markers": "python_full_version >= '3.9.0'", - "version": "==1.4.1" + "version": "==1.5.0" }, "idna": { "hashes": [ @@ -1149,12 +1149,12 @@ }, "litellm": { "hashes": [ - "sha256:2fa253658702509ce09fe0e172e5a47baaadf697fb0f784c7fd4ff665ae76ae1", - "sha256:a8a6277a53280762051c5818ebc76dd5f036368b9426c6f21795ae7f1ac6ebdc" + "sha256:5496b5d4532cccdc7a095c21cbac4042f7662021c57bc1d17be4e39838929e80", + "sha256:d388f52447daccbcaafa19a3e68d17b75f1374b5bf2cde680d65e1cd86e50d22" ], "index": "pypi", "markers": "python_version >= '3.9' and python_version < '4.0'", - "version": "==1.81.15" + "version": "==1.82.0" }, "markdown-it-py": { "hashes": [ @@ -1991,11 +1991,11 @@ }, "python-dotenv": { "hashes": [ - "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", - "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61" + "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", + "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3" ], - "markers": "python_version >= '3.9'", - "version": "==1.2.1" + "markers": "python_version >= '3.10'", + "version": "==1.2.2" }, "python-multipart": { "hashes": [ @@ -2110,123 +2110,123 @@ }, "regex": { "hashes": [ - "sha256:00ec994d7824bf01cd6c7d14c7a6a04d9aeaf7c42a2bc22d2359d715634d539b", - "sha256:015088b8558502f1f0bccd58754835aa154a7a5b0bd9d4c9b7b96ff4ae9ba876", - "sha256:02b9e1b8a7ebe2807cd7bbdf662510c8e43053a23262b9f46ad4fc2dfc9d204e", - "sha256:03d191a9bcf94d31af56d2575210cb0d0c6a054dbcad2ea9e00aa4c42903b919", - "sha256:03d706fbe7dfec503c8c3cb76f9352b3e3b53b623672aa49f18a251a6c71b8e6", - "sha256:0782bd983f19ac7594039c9277cd6f75c89598c1d72f417e4d30d874105eb0c7", - "sha256:0c10869d18abb759a3317c757746cc913d6324ce128b8bcec99350df10419f18", - "sha256:0d0e72703c60d68b18b27cde7cdb65ed2570ae29fb37231aa3076bfb6b1d1c13", - "sha256:0d9f81806abdca3234c3dd582b8a97492e93de3602c8772013cb4affa12d1668", - "sha256:11c138febb40546ff9e026dbbc41dc9fb8b29e61013fa5848ccfe045f5b23b83", - "sha256:127ea69273485348a126ebbf3d6052604d3c7da284f797bba781f364c0947d47", - "sha256:12e86a01594031abf892686fcb309b041bf3de3d13d99eb7e2b02a8f3c687df1", - "sha256:17648e1a88e72d88641b12635e70e6c71c5136ba14edba29bf8fc6834005a265", - "sha256:196553ba2a2f47904e5dc272d948a746352e2644005627467e055be19d73b39e", - "sha256:1e7a08622f7d51d7a068f7e4052a38739c412a3e74f55817073d2e2418149619", - "sha256:2905ff4a97fad42f2d0834d8b1ea3c2f856ec209837e458d71a061a7d05f9f01", - "sha256:294c0fb2e87c6bcc5f577c8f609210f5700b993151913352ed6c6af42f30f95f", - "sha256:2c1693ca6f444d554aa246b592355b5cec030ace5a2729eae1b04ab6e853e768", - "sha256:2cb00aabd96b345d56a8c2bc328c8d6c4d29935061e05078bf1f02302e12abf5", - "sha256:2f914ae8c804c8a8a562fe216100bc156bfb51338c1f8d55fe32cf407774359a", - "sha256:2fedd459c791da24914ecc474feecd94cf7845efb262ac3134fe27cbd7eda799", - "sha256:311fcccb76af31be4c588d5a17f8f1a059ae8f4b097192896ebffc95612f223a", - "sha256:31a5f561eb111d6aae14202e7043fb0b406d3c8dddbbb9e60851725c9b38ab1d", - "sha256:31aefac2506967b7dd69af2c58eca3cc8b086d4110b66d6ac6e9026f0ee5b697", - "sha256:38d88c6ed4a09ed61403dbdf515d969ccba34669af3961ceb7311ecd0cef504a", - "sha256:3a039474986e7a314ace6efb9ce52f5da2bdb80ac4955358723d350ec85c32ad", - "sha256:3aa0944f1dc6e92f91f3b306ba7f851e1009398c84bfd370633182ee4fc26a64", - "sha256:4071209fd4376ab5ceec72ad3507e9d3517c59e38a889079b98916477a871868", - "sha256:4146dc576ea99634ae9c15587d0c43273b4023a10702998edf0fa68ccb60237a", - "sha256:4192464fe3e6cb0ef6751f7d3b16f886d8270d359ed1590dd555539d364f0ff7", - "sha256:43cdde87006271be6963896ed816733b10967baaf0e271d529c82e93da66675b", - "sha256:4584a3ee5f257b71e4b693cc9be3a5104249399f4116fe518c3f79b0c6fc7083", - "sha256:46e69a4bf552e30e74a8aa73f473c87efcb7f6e8c8ece60d9fd7bf13d5c86f02", - "sha256:49cef7bb2a491f91a8869c7cdd90babf0a417047ab0bf923cd038ed2eab2ccb8", - "sha256:4a02faea614e7fdd6ba8b3bec6c8e79529d356b100381cec76e638f45d12ca04", - "sha256:50f1ee9488dd7a9fda850ec7c68cad7a32fa49fd19733f5403a3f92b451dcf73", - "sha256:516ee067c6c721d0d0bfb80a2004edbd060fffd07e456d4e1669e38fe82f922e", - "sha256:52136f5b71f095cb74b736cc3a1b578030dada2e361ef2f07ca582240b703946", - "sha256:5390b130cce14a7d1db226a3896273b7b35be10af35e69f1cca843b6e5d2bb2d", - "sha256:59a7a5216485a1896c5800e9feb8ff9213e11967b482633b6195d7da11450013", - "sha256:5a8f28dd32a4ce9c41758d43b5b9115c1c497b4b1f50c457602c1d571fa98ce1", - "sha256:5b81ff4f9cad99f90c807a00c5882fbcda86d8b3edd94e709fb531fc52cb3d25", - "sha256:5df947cabab4b643d4791af5e28aecf6bf62e6160e525651a12eba3d03755e6b", - "sha256:5e3a31e94d10e52a896adaa3adf3621bd526ad2b45b8c2d23d1bbe74c7423007", - "sha256:5e56c669535ac59cbf96ca1ece0ef26cb66809990cda4fa45e1e32c3b146599e", - "sha256:5ec1d7c080832fdd4e150c6f5621fe674c70c63b3ae5a4454cebd7796263b175", - "sha256:6380f29ff212ec922b6efb56100c089251940e0526a0d05aa7c2d9b571ddf2fe", - "sha256:64128549b600987e0f335c2365879895f860a9161f283b14207c800a6ed623d3", - "sha256:654dc41a5ba9b8cc8432b3f1aa8906d8b45f3e9502442a07c2f27f6c63f85db5", - "sha256:655f553a1fa3ab8a7fd570eca793408b8d26a80bfd89ed24d116baaf13a38969", - "sha256:66e6a43225ff1064f8926adbafe0922b370d381c3330edaf9891cade52daa790", - "sha256:676c4e6847a83a1d5732b4ed553881ad36f0a8133627bb695a89ecf3571499d3", - "sha256:6bc25d7e15f80c9dc7853cbb490b91c1ec7310808b09d56bd278fe03d776f4f6", - "sha256:6c8fb3b19652e425ff24169dad3ee07f99afa7996caa9dfbb3a9106cd726f49a", - "sha256:6fb8cb09b10e38f3ae17cc6dc04a1df77762bd0351b6ba9041438e7cc85ec310", - "sha256:7187fdee1be0896c1499a991e9bf7c78e4b56b7863e7405d7bb687888ac10c4b", - "sha256:74ff212aa61532246bb3036b3dfea62233414b0154b8bc3676975da78383cac3", - "sha256:75472631eee7898e16a8a20998d15106cb31cfde21cdf96ab40b432a7082af06", - "sha256:77cfd6b5e7c4e8bf7a39d243ea05882acf5e3c7002b0ef4756de6606893b0ecd", - "sha256:78af1e499cab704131f6f4e2f155b7f54ce396ca2acb6ef21a49507e4752e0be", - "sha256:79014115e6fdf18fd9b32e291d58181bf42d4298642beaa13fd73e69810e4cb6", - "sha256:790dbf87b0361606cb0d79b393c3e8f4436a14ee56568a7463014565d97da02a", - "sha256:80caaa1ddcc942ec7be18427354f9d58a79cee82dea2a6b3d4fd83302e1240d7", - "sha256:80d31c3f1fe7e4c6cd1831cd4478a0609903044dfcdc4660abfe6fb307add7f0", - "sha256:82336faeecac33297cd42857c3b36f12b91810e3fdd276befdd128f73a2b43fa", - "sha256:8457c1bc10ee9b29cdfd897ccda41dce6bde0e9abd514bcfef7bcd05e254d411", - "sha256:8497421099b981f67c99eba4154cf0dfd8e47159431427a11cfb6487f7791d9e", - "sha256:8abe671cf0f15c26b1ad389bf4043b068ce7d3b1c5d9313e12895f57d6738555", - "sha256:8dbff048c042beef60aa1848961384572c5afb9e8b290b0f1203a5c42cf5af65", - "sha256:8df08decd339e8b3f6a2eb5c05c687fe9d963ae91f352bc57beb05f5b2ac6879", - "sha256:8e6e77cd92216eb489e21e5652a11b186afe9bdefca8a2db739fd6b205a9e0a4", - "sha256:8edda06079bd770f7f0cf7f3bba1a0b447b96b4a543c91fe0c142d034c166161", - "sha256:93b16a18cadb938f0f2306267161d57eb33081a861cee9ffcd71e60941eb5dfc", - "sha256:93d881cab5afdc41a005dba1524a40947d6f7a525057aa64aaf16065cf62faa9", - "sha256:965d59792f5037d9138da6fed50ba943162160443b43d4895b182551805aff9c", - "sha256:997862c619994c4a356cb7c3592502cbd50c2ab98da5f61c5c871f10f22de7e5", - "sha256:9cbc69eae834afbf634f7c902fc72ff3e993f1c699156dd1af1adab5d06b7fe7", - "sha256:9dadc10d1c2bbb1326e572a226d2ec56474ab8aab26fdb8cf19419b372c349a9", - "sha256:9e6693b8567a59459b5dda19104c4a4dbbd4a1c78833eacc758796f2cfef1854", - "sha256:9fff45852160960f29e184ec8a5be5ab4063cfd0b168d439d1fc4ac3744bf29e", - "sha256:a032bc01a4bc73fc3cadba793fce28eb420da39338f47910c59ffcc11a5ba5ef", - "sha256:a09ae430e94c049dc6957f6baa35ee3418a3a77f3c12b6e02883bd80a2b679b0", - "sha256:a178df8ec03011153fbcd2c70cb961bc98cbbd9694b28f706c318bee8927c3db", - "sha256:ab780092b1424d13200aa5a62996e95f65ee3db8509be366437439cdc0af1a9f", - "sha256:b5100acb20648d9efd3f4e7e91f51187f95f22a741dcd719548a6cf4e1b34b3f", - "sha256:b9ab8dec42afefa6314ea9b31b188259ffdd93f433d77cad454cd0b8d235ce1c", - "sha256:bcf57d30659996ee5c7937999874504c11b5a068edc9515e6a59221cc2744dd1", - "sha256:c0761d7ae8d65773e01515ebb0b304df1bf37a0a79546caad9cbe79a42c12af7", - "sha256:c0924c64b082d4512b923ac016d6e1dcf647a3560b8a4c7e55cbbd13656cb4ed", - "sha256:c13228fbecb03eadbfd8f521732c5fda09ef761af02e920a3148e18ad0e09968", - "sha256:c1665138776e4ac1aa75146669236f7a8a696433ec4e525abf092ca9189247cc", - "sha256:c227f2922153ee42bbeb355fd6d009f8c81d9d7bdd666e2276ce41f53ed9a743", - "sha256:c7e121a918bbee3f12ac300ce0a0d2f2c979cf208fb071ed8df5a6323281915c", - "sha256:ccaaf9b907ea6b4223d5cbf5fa5dff5f33dc66f4907a25b967b8a81339a6e332", - "sha256:cce8027010d1ffa3eb89a0b19621cdc78ae548ea2b49fea1f7bfb3ea77064c2b", - "sha256:cdc0a80f679353bd68450d2a42996090c30b2e15ca90ded6156c31f1a3b63f3b", - "sha256:d00c95a2b6bfeb3ea1cb68d1751b1dfce2b05adc2a72c488d77a780db06ab867", - "sha256:d792b84709021945597e05656aac059526df4e0c9ef60a0eaebb306f8fafcaa8", - "sha256:d793c5b4d2b4c668524cd1651404cfc798d40694c759aec997e196fe9729ec60", - "sha256:d89f85a5ccc0cec125c24be75610d433d65295827ebaf0d884cbe56df82d4774", - "sha256:d96162140bb819814428800934c7b71b7bffe81fb6da2d6abc1dcca31741eca3", - "sha256:db5fd91eec71e7b08de10011a2223d0faa20448d4e1380b9daa179fa7bf58906", - "sha256:db970bcce4d63b37b3f9eb8c893f0db980bbf1d404a1d8d2b17aa8189de92c53", - "sha256:dbb240c81cfed5d4a67cb86d7676d9f7ec9c3f186310bec37d8a1415210e111e", - "sha256:e561dd47a85d2660d3d3af4e6cb2da825cf20f121e577147963f875b83d32786", - "sha256:e581f75d5c0b15669139ca1c2d3e23a65bb90e3c06ba9d9ea194c377c726a904", - "sha256:e689fed279cbe797a6b570bd18ff535b284d057202692c73420cb93cca41aa32", - "sha256:ea8dfc99689240e61fb21b5fc2828f68b90abf7777d057b62d3166b7c1543c4c", - "sha256:eb20c11aa4c3793c9ad04c19a972078cdadb261b8429380364be28e867a843f2", - "sha256:ec661807ffc14c8d14bb0b8c1bb3d5906e476bc96f98b565b709d03962ee4dd4", - "sha256:f374366ed35673ea81b86a8859c457d4fae6ba092b71024857e9e237410c7404", - "sha256:f5a37a17d110f9d5357a43aa7e3507cb077bf3143d1c549a45c4649e90e40a70", - "sha256:f9417fd853fcd00b7d55167e692966dd12d95ba1a88bf08a62002ccd85030790", - "sha256:fdbade8acba71bb45057c2b72f477f0b527c4895f9c83e6cfc30d4a006c21726" + "sha256:00945d007fd74a9084d2ab79b695b595c6b7ba3698972fadd43e23230c6979c1", + "sha256:00f2b8d9615aa165fdff0a13f1a92049bfad555ee91e20d246a51aa0b556c60a", + "sha256:01d65fd24206c8e1e97e2e31b286c59009636c022eb5d003f52760b0f42155d4", + "sha256:02473c954af35dd2defeb07e44182f5705b30ea3f351a7cbffa9177beb14da5d", + "sha256:03a83cc26aa2acda6b8b9dfe748cf9e84cbd390c424a1de34fdcef58961a297a", + "sha256:09500be324f49b470d907b3ef8af9afe857f5cca486f853853f7945ddbf75911", + "sha256:0b1d2b07614d95fa2bf8a63fd1e98bd8fa2b4848dc91b1efbc8ba219fdd73952", + "sha256:0d25a10811de831c2baa6aef3c0be91622f44dd8d31dd12e69f6398efb15e48b", + "sha256:0d5bef2031cbf38757a0b0bc4298bb4824b6332d28edc16b39247228fbdbad97", + "sha256:10d28e19bd4888e4abf43bd3925f3c134c52fdf7259219003588a42e24c2aa25", + "sha256:180e08a435a0319e6a4821c3468da18dc7001987e1c17ae1335488dfe7518dd8", + "sha256:195237dc327858a7721bf8b0bbbef797554bc13563c3591e91cd0767bacbe359", + "sha256:19a9c9e0a8f24f39d575a6a854d516b48ffe4cbdcb9de55cb0570a032556ecff", + "sha256:1c2c95e1a2b0f89d01e821ff4de1be4b5d73d1f4b0bf679fa27c1ad8d2327f1a", + "sha256:1d367257cd86c1cbb97ea94e77b373a0bbc2224976e247f173d19e8f18b4afa7", + "sha256:1e496956106fd59ba6322a8ea17141a27c5040e5ee8f9433ae92d4e5204462a0", + "sha256:1f8b17be5c27a684ea6759983c13506bd77bfc7c0347dff41b18ce5ddd2ee09a", + "sha256:2234059cfe33d9813a3677ef7667999caea9eeaa83fef98eb6ce15c6cf9e0215", + "sha256:25b6eb660c5cf4b8c3407a1ed462abba26a926cc9965e164268a3267bcc06a43", + "sha256:2954379dd20752e82d22accf3ff465311cbb2bac6c1f92c4afd400e1757f7451", + "sha256:2afa673660928d0b63d84353c6c08a8a476ddfc4a47e11742949d182e6863ce8", + "sha256:2b2b23587b26496ff5fd40df4278becdf386813ec00dc3533fa43a4cf0e2ad3c", + "sha256:2fb950ac1d88e6b6a9414381f403797b236f9fa17e1eee07683af72b1634207b", + "sha256:3935174fa4d9f70525a4367aaff3cb8bc0548129d114260c29d9dfa4a5b41692", + "sha256:39bb5727650b9a0275c6a6690f9bb3fe693a7e6cc5c3155b1240aedf8926423e", + "sha256:3b24bd7e9d85dc7c6a8bd2aa14ecd234274a0248335a02adeb25448aecdd420d", + "sha256:4390c365fd2d45278f45afd4673cb90f7285f5701607e3ad4274df08e36140ae", + "sha256:481df4623fa4969c8b11f3433ed7d5e3dc9cec0f008356c3212b3933fb77e3d8", + "sha256:4f5c0b182ad4269e7381b7c27fdb0408399881f7a92a4624fd5487f2971dfc11", + "sha256:50c2fc924749543e0eacc93ada6aeeb3ea5f6715825624baa0dccaec771668ae", + "sha256:511f7419f7afab475fd4d639d4aedfc54205bcb0800066753ef68a59f0f330b5", + "sha256:516604edd17b1c2c3e579cf4e9b25a53bf8fa6e7cedddf1127804d3e0140ca64", + "sha256:52b017b35ac2214d0db5f4f90e303634dc44e4aba4bd6235a27f97ecbe5b0472", + "sha256:5a932ea8ad5d0430351ff9c76c8db34db0d9f53c1d78f06022a21f4e290c5c18", + "sha256:5cdcc17d935c8f9d3f4db5c2ebe2640c332e3822ad5d23c2f8e0228e6947943a", + "sha256:5d10303dd18cedfd4d095543998404df656088240bcfd3cd20a8f95b861f74bd", + "sha256:5e68192bb3a1d6fb2836da24aa494e413ea65853a21505e142e5b1064a595f3d", + "sha256:64e7c6ad614573e0640f271e811a408d79a9e1fe62a46adb602f598df42a818d", + "sha256:6591f281cb44dc13de9585b552cec6fc6cf47fb2fe7a48892295ee9bc4a612f9", + "sha256:69fc560ccbf08a09dc9b52ab69cacfae51e0ed80dc5693078bdc97db2f91ae96", + "sha256:6d63a07e5ec8ce7184452cb00c41c37b49e67dc4f73b2955b5b8e782ea970784", + "sha256:6db7bfae0f8a2793ff1f7021468ea55e2699d0790eb58ee6ab36ae43aa00bc5b", + "sha256:71a911098be38c859ceb3f9a9ce43f4ed9f4c6720ad8684a066ea246b76ad9ff", + "sha256:73cdcdbba8028167ea81490c7f45280113e41db2c7afb65a276f4711fa3bcbff", + "sha256:78454178c7df31372ea737996fb7f36b3c2c92cccc641d251e072478afb4babc", + "sha256:7900157786428a79615a8264dac1f12c9b02957c473c8110c6b1f972dcecaddf", + "sha256:7ab218076eb0944549e7fe74cf0e2b83a82edb27e81cc87411f76240865e04d5", + "sha256:7c1b34dfa72f826f535b20712afa9bb3ba580020e834f3c69866c5bddbf10098", + "sha256:851fa70df44325e1e4cdb79c5e676e91a78147b1b543db2aec8734d2add30ec2", + "sha256:864cdd1a2ef5716b0ab468af40139e62ede1b3a53386b375ec0786bb6783fc05", + "sha256:8710d61737b0c0ce6836b1da7109f20d495e49b3809f30e27e9560be67a257bf", + "sha256:9036b400b20e4858d56d117108d7813ed07bb7803e3eed766675862131135ca6", + "sha256:9185cc63359862a6e80fe97f696e04b0ad9a11c4ac0a4a927f979f611bfe3768", + "sha256:948c12ef30ecedb128903c2c2678b339746eb7c689c5c21957c4a23950c96d15", + "sha256:94d63db12e45a9b9f064bfe4800cefefc7e5f182052e4c1b774d46a40ab1d9bb", + "sha256:96f6269a2882fbb0ee76967116b83679dc628e68eaea44e90884b8d53d833881", + "sha256:97054c55db06ab020342cc0d35d6f62a465fa7662871190175f1ad6c655c028f", + "sha256:98adf340100cbe6fbaf8e6dc75e28f2c191b1be50ffefe292fb0e6f6eefdb0d8", + "sha256:99985a2c277dcb9ccb63f937451af5d65177af1efdeb8173ac55b61095a0a05c", + "sha256:9b65d33a17101569f86d9c5966a8b1d7fbf8afdda5a8aa219301b0a80f58cf7d", + "sha256:9dd450db6458387167e033cfa80887a34c99c81d26da1bf8b0b41bf8c9cac88e", + "sha256:a25c7701e4f7a70021db9aaf4a4a0a67033c6318752146e03d1b94d32006217e", + "sha256:a448af01e3d8031c89c5d902040b124a5e921a25c4e5e07a861ca591ce429341", + "sha256:a5dac14d0872eeb35260a8e30bac07ddf22adc1e3a0635b52b02e180d17c9c7e", + "sha256:a729e47d418ea11d03469f321aaf67cdee8954cde3ff2cf8403ab87951ad10f2", + "sha256:aaffaecffcd2479ce87aa1e74076c221700b7c804e48e98e62500ee748f0f550", + "sha256:b059e71ec363968671693a78c5053bd9cb2fe410f9b8e4657e88377ebd603a2e", + "sha256:b387a0d092dac157fb026d737dde35ff3e49ef27f285343e7c6401851239df27", + "sha256:b389c61aa28a79c2e0527ac36da579869c2e235a5b208a12c5b5318cda2501d8", + "sha256:b42f7466e32bf15a961cf09f35fa6323cc72e64d3d2c990b10de1274a5da0a59", + "sha256:b49eb78048c6354f49e91e4b77da21257fecb92256b6d599ae44403cab30b05b", + "sha256:b5acd4b6a95f37c3c3828e5d053a7d4edaedb85de551db0153754924cb7c83e3", + "sha256:b8b3f1be1738feadc69f62daa250c933e85c6f34fa378f54a7ff43807c1b9117", + "sha256:b8cf76f1a29f0e99dcfd7aef1551a9827588aae5a737fe31442021165f1920dc", + "sha256:ba55c50f408fb5c346a3a02d2ce0ebc839784e24f7c9684fde328ff063c3cdea", + "sha256:bba2b18d70eeb7b79950f12f633beeecd923f7c9ad6f6bae28e59b4cb3ab046b", + "sha256:bbb882061f742eb5d46f2f1bd5304055be0a66b783576de3d7eef1bed4778a6e", + "sha256:bcb399ed84eabf4282587ba151f2732ad8168e66f1d3f85b1d038868fe547703", + "sha256:bd477d5f79920338107f04aa645f094032d9e3030cc55be581df3d1ef61aa318", + "sha256:bec23c11cbbf09a4df32fe50d57cbdd777bc442269b6e39a1775654f1c95dee2", + "sha256:c0b5ccbb8ffb433939d248707d4a8b31993cb76ab1a0187ca886bf50e96df952", + "sha256:c15af43c72a7fb0c97cbc66fa36a43546eddc5c06a662b64a0cbf30d6ac40944", + "sha256:c7815afb0ca45456613fdaf60ea9c993715511c8d53a83bc468305cbc0ee23c7", + "sha256:cb3b1db8ff6c7b8bf838ab05583ea15230cb2f678e569ab0e3a24d1e8320940b", + "sha256:d0b02e8b7e5874b48ae0f077ecca61c1a6a9f9895e9c6dfb191b55b242862033", + "sha256:d6b08a06976ff4fb0d83077022fde3eca06c55432bb997d8c0495b9a4e9872f4", + "sha256:d6cfe798d8da41bb1862ed6e0cba14003d387c3c0c4a5d45591076ae9f0ce2f8", + "sha256:d8511a01d0e4ee1992eb3ba19e09bc1866fe03f05129c3aec3fdc4cbc77aad3f", + "sha256:dc8ed8c3f41c27acb83f7b6a9eb727a73fc6663441890c5cb3426a5f6a91ce7d", + "sha256:dd8847c4978bc3c7e6c826fb745f5570e518b8459ac2892151ce6627c7bc00d5", + "sha256:de0cf053139f96219ccfabb4a8dd2d217c8c82cb206c91d9f109f3f552d6b43d", + "sha256:dee50f1be42222f89767b64b283283ef963189da0dda4a515aa54a5563c62dec", + "sha256:e1e7b24cb3ae9953a560c563045d1ba56ee4749fbd05cf21ba571069bd7be81b", + "sha256:e59bc8f30414d283ae8ee1617b13d8112e7135cb92830f0ec3688cb29152585a", + "sha256:e61eea47230eba62a31f3e8a0e3164d0f37ef9f40529fb2c79361bc6b53d2a92", + "sha256:e621fb7c8dc147419b28e1702f58a0177ff8308a76fa295c71f3e7827849f5d9", + "sha256:e71dcecaa113eebcc96622c17692672c2d104b1d71ddf7adeda90da7ddeb26fc", + "sha256:e7ce83654d1ab701cb619285a18a8e5a889c1216d746ddc710c914ca5fd71022", + "sha256:e8c8cb2deba42f5ec1ede46374e990f8adc5e6456a57ac1a261b19be6f28e4e6", + "sha256:ec0c608b7a7465ffadb344ed7c987ff2f11ee03f6a130b569aa74d8a70e8333c", + "sha256:ec6f5674c5dc836994f50f1186dd1fafde4be0666aae201ae2fcc3d29d8adf27", + "sha256:edb1b1b3a5576c56f08ac46f108c40333f222ebfd5cf63afdfa3aab0791ebe5b", + "sha256:ef77bdde9c9eba3f7fa5b58084b29bbcc74bcf55fdbeaa67c102a35b5bd7e7cc", + "sha256:f2791948f7c70bb9335a9102df45e93d428f4b8128020d85920223925d73b9e1", + "sha256:f467cb602f03fbd1ab1908f68b53c649ce393fde056628dc8c7e634dab6bfc07", + "sha256:f8ed9a5d4612df9d4de15878f0bc6aa7a268afbe5af21a3fdd97fa19516e978c", + "sha256:fa539be029844c0ce1114762d2952ab6cfdd7c7c9bd72e0db26b94c3c36dcc5a", + "sha256:fb1c4ff62277d87a7335f2c1ea4e0387b8f2b3ad88a64efd9943906aafad4f33", + "sha256:fb4db2f17e6484904f986c5a657cec85574c76b5c5e61c7aae9ffa1bc6224f95", + "sha256:fb66e5245db9652abd7196ace599b04d9c0e4aa7c8f0e2803938377835780081", + "sha256:fc48c500838be6882b32748f60a15229d2dea96e59ef341eaa96ec83538f498d", + "sha256:fcf26c3c6d0da98fada8ae4ef0aa1c3405a431c0a77eb17306d38a89b02adcd7", + "sha256:fd0ce43e71d825b7c0661f9c54d4d74bd97c56c3fd102a8985bcfea48236bacb", + "sha256:fd63453f10d29097cc3dc62d070746523973fb5aa1c66d25f8558bebd47fed61" ], "markers": "python_version >= '3.10'", - "version": "==2026.2.19" + "version": "==2026.2.28" }, "requests": { "hashes": [ @@ -2763,139 +2763,137 @@ }, "yarl": { "hashes": [ - "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a", - "sha256:029866bde8d7b0878b9c160e72305bbf0a7342bcd20b9999381704ae03308dc8", - "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b", - "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da", - "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", - "sha256:088e4e08f033db4be2ccd1f34cf29fe994772fb54cfe004bbf54db320af56890", - "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093", - "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", - "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79", - "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683", - "sha256:10619d9fdee46d20edc49d3479e2f8269d0779f1b031e6f7c2aa1c76be04b7ed", - "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2", - "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", - "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02", - "sha256:14291620375b1060613f4aab9ebf21850058b6b1b438f386cc814813d901c60b", - "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03", - "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511", - "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c", - "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", - "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c", - "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da", - "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2", - "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0", - "sha256:2e4e1f6f0b4da23e61188676e3ed027ef0baa833a2e633c29ff8530800edccba", - "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", - "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53", - "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138", - "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4", - "sha256:3aa27acb6de7a23785d81557577491f6c38a5209a254d1191519d07d8fe51748", - "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7", - "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d", - "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503", - "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d", - "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", - "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", - "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", - "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f", - "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1", - "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d", - "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694", - "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3", - "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a", - "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d", - "sha256:4dcc74149ccc8bba31ce1944acee24813e93cfdee2acda3c172df844948ddf7b", - "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", - "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6", - "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b", - "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", - "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5", - "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f", - "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df", - "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", - "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b", - "sha256:5dbeefd6ca588b33576a01b0ad58aa934bc1b41ef89dee505bf2932b22ddffba", - "sha256:62441e55958977b8167b2709c164c91a6363e25da322d87ae6dd9c6019ceecf9", - "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", - "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6", - "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b", - "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967", - "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2", - "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708", - "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", - "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", - "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10", - "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", - "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b", - "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028", - "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e", - "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", - "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33", - "sha256:84fc3ec96fce86ce5aa305eb4aa9358279d1aa644b71fab7b8ed33fe3ba1a7ca", - "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590", - "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", - "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53", - "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", - "sha256:99b6fc1d55782461b78221e95fc357b47ad98b041e8e20f47c1411d0aacddc60", - "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f", - "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", - "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27", - "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", - "sha256:a4fcfc8eb2c34148c118dfa02e6427ca278bfd0f3df7c5f99e33d2c0e81eae3e", - "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", - "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca", - "sha256:af74f05666a5e531289cb1cc9c883d1de2088b8e5b4de48004e5ca8a830ac859", - "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273", - "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e", - "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601", - "sha256:b580e71cac3f8113d3135888770903eaf2f507e9421e5697d6ee6d8cd1c7f054", - "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376", - "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", - "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", - "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", - "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65", - "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784", - "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", - "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b", - "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a", - "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c", - "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face", - "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d", - "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", - "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e", - "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", - "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9", - "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", - "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95", - "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed", - "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf", - "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca", - "sha256:dd7afd3f8b0bfb4e0d9fc3c31bfe8a4ec7debe124cfd90619305def3c8ca8cd2", - "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62", - "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", - "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", - "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67", - "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", - "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529", - "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486", - "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a", - "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e", - "sha256:e81fda2fb4a07eda1a2252b216aa0df23ebcd4d584894e9612e80999a78fd95b", - "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", - "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d", - "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b", - "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", - "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", - "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e", - "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8", - "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", - "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd", - "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249" + "sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc", + "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4", + "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85", + "sha256:0e1fdaa14ef51366d7757b45bde294e95f6c8c049194e793eedb8387c86d5993", + "sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222", + "sha256:115136c4a426f9da976187d238e84139ff6b51a20839aa6e3720cd1026d768de", + "sha256:13a563739ae600a631c36ce096615fe307f131344588b0bc0daec108cdb47b25", + "sha256:16c6994ac35c3e74fb0ae93323bf8b9c2a9088d55946109489667c510a7d010e", + "sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2", + "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e", + "sha256:1932b6b8bba8d0160a9d1078aae5838a66039e8832d41d2992daa9a3a08f7860", + "sha256:1b6b572edd95b4fa8df75de10b04bc81acc87c1c7d16bcdd2035b09d30acc957", + "sha256:1c3a3598a832590c5a3ce56ab5576361b5688c12cb1d39429cf5dba30b510760", + "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52", + "sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788", + "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912", + "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719", + "sha256:2569b67d616eab450d262ca7cb9f9e19d2f718c70a8b88712859359d0ab17035", + "sha256:263cd4f47159c09b8b685890af949195b51d1aa82ba451c5847ca9bc6413c220", + "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412", + "sha256:2a6940a074fb3c48356ed0158a3ca5699c955ee4185b4d7d619be3c327143e05", + "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41", + "sha256:31c9921eb8bd12633b41ad27686bbb0b1a2a9b8452bfdf221e34f311e9942ed4", + "sha256:34b6cf500e61c90f305094911f9acc9c86da1a05a7a3f5be9f68817043f486e4", + "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd", + "sha256:389871e65468400d6283c0308e791a640b5ab5c83bcee02a2f51295f95e09748", + "sha256:39004f0ad156da43e86aa71f44e033de68a44e5a31fc53507b36dd253970054a", + "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4", + "sha256:3ceb13c5c858d01321b5d9bb65e4cf37a92169ea470b70fec6f236b2c9dd7e34", + "sha256:411225bae281f114067578891bc75534cfb3d92a3b4dfef7a6ca78ba354e6069", + "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25", + "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2", + "sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb", + "sha256:4966242ec68afc74c122f8459abd597afd7d8a60dc93d695c1334c5fd25f762f", + "sha256:4a42e651629dafb64fd5b0286a3580613702b5809ad3f24934ea87595804f2c5", + "sha256:4a59ba56f340334766f3a4442e0efd0af895fae9e2b204741ef885c446b3a1a8", + "sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c", + "sha256:5023346c4ee7992febc0068e7593de5fa2bf611848c08404b35ebbb76b1b0512", + "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6", + "sha256:51430653db848d258336cfa0244427b17d12db63d42603a55f0d4546f50f25b5", + "sha256:531ef597132086b6cf96faa7c6c1dcd0361dd5f1694e5cc30375907b9b7d3ea9", + "sha256:53ad387048f6f09a8969631e4de3f1bf70c50e93545d64af4f751b2498755072", + "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", + "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277", + "sha256:578110dd426f0d209d1509244e6d4a3f1a3e9077655d98c5f22583d63252a08a", + "sha256:5ec2f42d41ccbd5df0270d7df31618a8ee267bfa50997f5d720ddba86c4a83a6", + "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae", + "sha256:5f10fd85e4b75967468af655228fbfd212bdf66db1c0d135065ce288982eda26", + "sha256:609d3614d78d74ebe35f54953c5bbd2ac647a7ddb9c30a5d877580f5e86b22f2", + "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4", + "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70", + "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723", + "sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c", + "sha256:6e87a6e8735b44816e7db0b2fbc9686932df473c826b0d9743148432e10bb9b9", + "sha256:6f0fd84de0c957b2d280143522c4f91a73aada1923caee763e24a2b3fda9f8a5", + "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e", + "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c", + "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4", + "sha256:75e3026ab649bf48f9a10c0134512638725b521340293f202a69b567518d94e0", + "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2", + "sha256:7c6b9461a2a8b47c65eef63bb1c76a4f1c119618ffa99ea79bc5bb1e46c5821b", + "sha256:803a3c3ce4acc62eaf01eaca1208dcf0783025ef27572c3336502b9c232005e7", + "sha256:80e6d33a3d42a7549b409f199857b4fb54e2103fc44fb87605b6663b7a7ff750", + "sha256:8419ebd326430d1cbb7efb5292330a2cf39114e82df5cc3d83c9a0d5ebeaf2f2", + "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474", + "sha256:85e9beda1f591bc73e77ea1c51965c68e98dafd0fec72cdd745f77d727466716", + "sha256:877b0738624280e34c55680d6054a307aa94f7d52fa0e3034a9cc6e790871da7", + "sha256:88f9fb0116fbfcefcab70f85cf4b74a2b6ce5d199c41345296f49d974ddb4123", + "sha256:8c4fe09e0780c6c3bf2b7d4af02ee2394439d11a523bbcf095cf4747c2932007", + "sha256:93a784271881035ab4406a172edb0faecb6e7d00f4b53dc2f55919d6c9688595", + "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe", + "sha256:95451e6ce06c3e104556d73b559f5da6c34a069b6b62946d3ad66afcd51642ea", + "sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598", + "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679", + "sha256:9cbf44c5cb4a7633d078788e1b56387e3d3cf2b8139a3be38040b22d6c3221c8", + "sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83", + "sha256:a0e317df055958a0c1e79e5d2aa5a5eaa4a6d05a20d4b0c9c3f48918139c9fc6", + "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", + "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94", + "sha256:a3d2bff8f37f8d0f96c7ec554d16945050d54462d6e95414babaa18bfafc7f51", + "sha256:a41bcf68efd19073376eb8cf948b8d9be0af26256403e512bb18f3966f1f9120", + "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039", + "sha256:a8d00f29b42f534cc8aa3931cfe773b13b23e561e10d2b26f27a8d309b0e82a1", + "sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05", + "sha256:ab5f043cb8a2d71c981c09c510da013bc79fd661f5c60139f00dd3c3cc4f2ffb", + "sha256:ac09d42f48f80c9ee1635b2fcaa819496a44502737660d3c0f2ade7526d29144", + "sha256:aecfed0b41aa72b7881712c65cf764e39ce2ec352324f5e0837c7048d9e6daaa", + "sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a", + "sha256:b35d13d549077713e4414f927cdc388d62e543987c572baee613bf82f11a4b99", + "sha256:b39cb32a6582750b6cc77bfb3c49c0f8760dc18dc96ec9fb55fbb0f04e08b928", + "sha256:b5405bb8f0e783a988172993cfc627e4d9d00432d6bbac65a923041edacf997d", + "sha256:baaf55442359053c7d62f6f8413a62adba3205119bcb6f49594894d8be47e5e3", + "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434", + "sha256:be61f6fff406ca40e3b1d84716fde398fc08bc63dd96d15f3a14230a0973ed86", + "sha256:bf49a3ae946a87083ef3a34c8f677ae4243f5b824bfc4c69672e72b3d6719d46", + "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319", + "sha256:c75eb09e8d55bceb4367e83496ff8ef2bc7ea6960efb38e978e8073ea59ecb67", + "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c", + "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169", + "sha256:cbb0fef01f0c6b38cb0f39b1f78fc90b807e0e3c86a7ff3ce74ad77ce5c7880c", + "sha256:cde9a2ecd91668bcb7f077c4966d8ceddb60af01b52e6e3e2680e4cf00ad1a59", + "sha256:cff6d44cb13d39db2663a22b22305d10855efa0fa8015ddeacc40bc59b9d8107", + "sha256:d1009abedb49ae95b136a8904a3f71b342f849ffeced2d3747bf29caeda218c4", + "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a", + "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb", + "sha256:d7504f2b476d21653e4d143f44a175f7f751cd41233525312696c76aa3dbb23f", + "sha256:dbf507e9ef5688bada447a24d68b4b58dd389ba93b7afc065a2ba892bea54769", + "sha256:dc52310451fc7c629e13c4e061cbe2dd01684d91f2f8ee2821b083c58bd72432", + "sha256:dd00607bffbf30250fe108065f07453ec124dbf223420f57f5e749b04295e090", + "sha256:dda608c88cf709b1d406bdfcd84d8d63cff7c9e577a403c6108ce8ce9dcc8764", + "sha256:debe9c4f41c32990771be5c22b56f810659f9ddf3d63f67abfdcaa2c6c9c5c1d", + "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4", + "sha256:e0fd068364a6759bc794459f0a735ab151d11304346332489c7972bacbe9e72b", + "sha256:e4c53f8347cd4200f0d70a48ad059cabaf24f5adc6ba08622a23423bc7efa10d", + "sha256:e5723c01a56c5028c807c701aa66722916d2747ad737a046853f6c46f4875543", + "sha256:e7b0460976dc75cb87ad9cc1f9899a4b97751e7d4e77ab840fc9b6d377b8fd24", + "sha256:e9d9a4d06d3481eab79803beb4d9bd6f6a8e781ec078ac70d7ef2dcc29d1bea5", + "sha256:ead11956716a940c1abc816b7df3fa2b84d06eaed8832ca32f5c5e058c65506b", + "sha256:ed5f69ce7be7902e5c70ea19eb72d20abf7d725ab5d49777d696e32d4fc1811d", + "sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b", + "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6", + "sha256:f514f6474e04179d3d33175ed3f3e31434d3130d42ec153540d5b157deefd735", + "sha256:f69f57305656a4852f2a7203efc661d8c042e6cc67f7acd97d8667fb448a426e", + "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28", + "sha256:fb4948814a2a98e3912505f09c9e7493b1506226afb1f881825368d6fb776ee3", + "sha256:fda207c815b253e34f7e1909840fd14299567b1c0eb4908f8c2ce01a41265401", + "sha256:fe8f8f5e70e6dbdfca9882cd9deaac058729bcf323cf7a58660901e55c9c94f6", + "sha256:fffc45637bcd6538de8b85f51e3df3223e4ad89bccbfca0481c08c7fc8b7ed7d" ], - "markers": "python_version >= '3.9'", - "version": "==1.22.0" + "markers": "python_version >= '3.10'", + "version": "==1.23.0" }, "zipp": { "hashes": [ From d56aa9450e8dd5cbd0fa4e655697c634300e75db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 13:29:25 +0200 Subject: [PATCH 17/18] Bump the npm_and_yarn group across 1 directory with 2 updates (#447) * Bump the npm_and_yarn group across 1 directory with 2 updates Bumps the npm_and_yarn group with 2 updates in the /app directory: [minimatch](https://github.com/isaacs/minimatch) and [rollup](https://github.com/rollup/rollup). Updates `minimatch` from 3.1.2 to 3.1.5 - [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md) - [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5) Updates `rollup` from 4.55.1 to 4.59.0 - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.55.1...v4.59.0) --- updated-dependencies: - dependency-name: minimatch dependency-version: 3.1.5 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: rollup dependency-version: 4.59.0 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] * ci: retrigger CI after transient test failure The previous Playwright test run had database connectivity issues in CI (Docker container readiness timing). All infrastructure steps passed but database connection tests returned success:false. Retriggering to verify. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Guy Korland Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- app/package-lock.json | 212 ++++++++++++++++++++++-------------------- 1 file changed, 110 insertions(+), 102 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index e0e7623f..bcc6b6a0 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -2346,9 +2346,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", - "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", "cpu": [ "arm" ], @@ -2360,9 +2360,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", - "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", "cpu": [ "arm64" ], @@ -2374,9 +2374,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", - "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], @@ -2388,9 +2388,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", - "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", "cpu": [ "x64" ], @@ -2402,9 +2402,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", - "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", "cpu": [ "arm64" ], @@ -2416,9 +2416,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", - "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", "cpu": [ "x64" ], @@ -2430,9 +2430,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", - "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", "cpu": [ "arm" ], @@ -2444,9 +2444,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", - "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", "cpu": [ "arm" ], @@ -2458,9 +2458,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", - "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], @@ -2472,9 +2472,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", - "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", "cpu": [ "arm64" ], @@ -2486,9 +2486,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", - "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", "cpu": [ "loong64" ], @@ -2500,9 +2500,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", - "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", "cpu": [ "loong64" ], @@ -2514,9 +2514,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", - "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", "cpu": [ "ppc64" ], @@ -2528,9 +2528,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", - "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", "cpu": [ "ppc64" ], @@ -2542,9 +2542,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", - "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", "cpu": [ "riscv64" ], @@ -2556,9 +2556,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", - "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", "cpu": [ "riscv64" ], @@ -2570,9 +2570,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", - "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", "cpu": [ "s390x" ], @@ -2584,7 +2584,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.1", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", "cpu": [ "x64" ], @@ -2596,9 +2598,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", - "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", "cpu": [ "x64" ], @@ -2610,9 +2612,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", - "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", "cpu": [ "x64" ], @@ -2624,9 +2626,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", - "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", "cpu": [ "arm64" ], @@ -2638,9 +2640,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", - "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", "cpu": [ "arm64" ], @@ -2652,9 +2654,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", - "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", "cpu": [ "ia32" ], @@ -2666,9 +2668,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", - "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", "cpu": [ "x64" ], @@ -2680,9 +2682,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", - "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", "cpu": [ "x64" ], @@ -3368,11 +3370,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -5062,7 +5066,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -5720,7 +5726,9 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.55.1", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { @@ -5734,31 +5742,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.1", - "@rollup/rollup-android-arm64": "4.55.1", - "@rollup/rollup-darwin-arm64": "4.55.1", - "@rollup/rollup-darwin-x64": "4.55.1", - "@rollup/rollup-freebsd-arm64": "4.55.1", - "@rollup/rollup-freebsd-x64": "4.55.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", - "@rollup/rollup-linux-arm-musleabihf": "4.55.1", - "@rollup/rollup-linux-arm64-gnu": "4.55.1", - "@rollup/rollup-linux-arm64-musl": "4.55.1", - "@rollup/rollup-linux-loong64-gnu": "4.55.1", - "@rollup/rollup-linux-loong64-musl": "4.55.1", - "@rollup/rollup-linux-ppc64-gnu": "4.55.1", - "@rollup/rollup-linux-ppc64-musl": "4.55.1", - "@rollup/rollup-linux-riscv64-gnu": "4.55.1", - "@rollup/rollup-linux-riscv64-musl": "4.55.1", - "@rollup/rollup-linux-s390x-gnu": "4.55.1", - "@rollup/rollup-linux-x64-gnu": "4.55.1", - "@rollup/rollup-linux-x64-musl": "4.55.1", - "@rollup/rollup-openbsd-x64": "4.55.1", - "@rollup/rollup-openharmony-arm64": "4.55.1", - "@rollup/rollup-win32-arm64-msvc": "4.55.1", - "@rollup/rollup-win32-ia32-msvc": "4.55.1", - "@rollup/rollup-win32-x64-gnu": "4.55.1", - "@rollup/rollup-win32-x64-msvc": "4.55.1", + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" } }, From 3f53691197d142419eae49ec14b34170c96ad75e Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 14:04:42 +0200 Subject: [PATCH 18/18] Bump version from 0.0.14 to 0.1.0 (#450) * Initial plan * chore: bump version from 0.0.14 to 0.1.0 Co-authored-by: gkorland <753206+gkorland@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: gkorland <753206+gkorland@users.noreply.github.com> Co-authored-by: Guy Korland --- app/package-lock.json | 4 ++-- app/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/package-lock.json b/app/package-lock.json index bcc6b6a0..33c4e227 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -1,12 +1,12 @@ { "name": "queryweaver-app", - "version": "0.0.14", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "queryweaver-app", - "version": "0.0.14", + "version": "0.1.0", "dependencies": { "@falkordb/canvas": "^0.0.41", "@hookform/resolvers": "^3.10.0", diff --git a/app/package.json b/app/package.json index 52ec4b17..6322ceab 100644 --- a/app/package.json +++ b/app/package.json @@ -1,7 +1,7 @@ { "name": "queryweaver-app", "private": true, - "version": "0.0.14", + "version": "0.1.0", "type": "module", "scripts": { "dev": "vite",