From a2a5dbf197a7de437788fdf409e8a18cb7c6d2dd Mon Sep 17 00:00:00 2001 From: d-klotz Date: Tue, 10 Feb 2026 14:37:06 -0300 Subject: [PATCH 1/5] fix(oauth2): add defensive logging for refresh_token preservation Add trace/warning logs to setTokens() and Module.onTokenUpdate() to aid debugging when a token refresh response omits the refresh_token. This makes it easier to detect misconfigured modules or unexpected OAuth provider behavior in production. Co-Authored-By: Claude Opus 4.6 --- packages/core/modules/module.js | 12 ++++++++---- packages/core/modules/requester/oauth-2.js | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/core/modules/module.js b/packages/core/modules/module.js index ec76dbc43..5ce49ce2b 100644 --- a/packages/core/modules/module.js +++ b/packages/core/modules/module.js @@ -100,10 +100,14 @@ class Module extends Delegate { this.api, this.userId ); - Object.assign( - credentialDetails.details, - this.apiParamsFromCredential(this.api) - ); + const apiParams = this.apiParamsFromCredential(this.api); + + if (!apiParams.refresh_token && this.api.isRefreshable) { + console.warn(`[Module.onTokenUpdate] refresh_token missing from apiParams for module ${this.name}. ` + + `Existing DB value will be preserved via merge.`); + } + + Object.assign(credentialDetails.details, apiParams); credentialDetails.details.authIsValid = true; const persisted = await this.credentialRepository.upsertCredential( diff --git a/packages/core/modules/requester/oauth-2.js b/packages/core/modules/requester/oauth-2.js index c9d881825..78f43838a 100644 --- a/packages/core/modules/requester/oauth-2.js +++ b/packages/core/modules/requester/oauth-2.js @@ -118,6 +118,8 @@ class OAuth2Requester extends Requester { const newRefreshToken = get(params, 'refresh_token', null); if (newRefreshToken !== null) { this.refresh_token = newRefreshToken; + } else { + console.log('[OAuth2Requester.setTokens] No refresh_token in response, preserving existing'); } const accessExpiresIn = get(params, 'expires_in', null); const refreshExpiresIn = get( From 2897c90b23940d59538d7595193f59e38a910e91 Mon Sep 17 00:00:00 2001 From: d-klotz Date: Wed, 11 Feb 2026 17:48:46 -0300 Subject: [PATCH 2/5] fix(oauth2): improve logging for non-500 errors --- packages/core/handlers/app-handler-helpers.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/handlers/app-handler-helpers.js b/packages/core/handlers/app-handler-helpers.js index 841324ea6..cde6bc7d1 100644 --- a/packages/core/handlers/app-handler-helpers.js +++ b/packages/core/handlers/app-handler-helpers.js @@ -32,6 +32,7 @@ const createApp = (applyMiddleware) => { flushDebugLog(boomError); res.status(statusCode).json({ error: 'Internal Server Error' }); } else { + console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message}`); res.status(statusCode).json({ error: err.message }); } }); From a16631cd343ef9ee4bdab5a23a91bc4674c51746 Mon Sep 17 00:00:00 2001 From: d-klotz Date: Thu, 12 Feb 2026 11:27:53 -0300 Subject: [PATCH 3/5] fix(oauth2): enhance logging for refresh_token handling --- packages/core/modules/module.js | 9 ++++++--- packages/core/modules/requester/oauth-2.js | 22 ++++++++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/core/modules/module.js b/packages/core/modules/module.js index 5ce49ce2b..8bf95a03c 100644 --- a/packages/core/modules/module.js +++ b/packages/core/modules/module.js @@ -42,7 +42,9 @@ class Module extends Delegate { const apiParams = { ...this.definition.env, delegate: this, - ...(this.credential?.data ? this.apiParamsFromCredential(this.credential.data) : {}), // Handle case when credential is undefined + ...(this.credential?.data + ? this.apiParamsFromCredential(this.credential.data) + : {}), // Handle case when credential is undefined ...this.apiParamsFromEntity(this.entity), }; this.api = new this.apiClass(apiParams); @@ -103,8 +105,9 @@ class Module extends Delegate { const apiParams = this.apiParamsFromCredential(this.api); if (!apiParams.refresh_token && this.api.isRefreshable) { - console.warn(`[Module.onTokenUpdate] refresh_token missing from apiParams for module ${this.name}. ` + - `Existing DB value will be preserved via merge.`); + console.warn( + `[Frigg] No refresh_token in apiParams for module ${this.name}.` + ); } Object.assign(credentialDetails.details, apiParams); diff --git a/packages/core/modules/requester/oauth-2.js b/packages/core/modules/requester/oauth-2.js index 78f43838a..7843534da 100644 --- a/packages/core/modules/requester/oauth-2.js +++ b/packages/core/modules/requester/oauth-2.js @@ -30,7 +30,6 @@ const { ModuleConstants } = require('../ModuleConstants'); * await api.getTokenFromClientCredentials(); */ class OAuth2Requester extends Requester { - static requesterType = ModuleConstants.authType.oauth2; /** @@ -119,7 +118,15 @@ class OAuth2Requester extends Requester { if (newRefreshToken !== null) { this.refresh_token = newRefreshToken; } else { - console.log('[OAuth2Requester.setTokens] No refresh_token in response, preserving existing'); + if (this.refresh_token) { + console.log( + '[Frigg] No refresh_token in response, preserving existing' + ); + } else { + console.log( + '[Frigg] Current refresh_token is null and no new refresh_token in response' + ); + } } const accessExpiresIn = get(params, 'expires_in', null); const refreshExpiresIn = get( @@ -130,7 +137,9 @@ class OAuth2Requester extends Requester { this.accessTokenExpire = new Date(Date.now() + accessExpiresIn * 1000); if (refreshExpiresIn !== null) { - this.refreshTokenExpire = new Date(Date.now() + refreshExpiresIn * 1000); + this.refreshTokenExpire = new Date( + Date.now() + refreshExpiresIn * 1000 + ); } await this.notify(this.DLGT_TOKEN_UPDATE); @@ -239,6 +248,7 @@ class OAuth2Requester extends Requester { 'Content-Type': 'application/x-www-form-urlencoded', }, }; + console.log('[Frigg] Refreshing access token with options'); const response = await this._post(options, false); await this.setTokens(response); return response; @@ -286,7 +296,7 @@ class OAuth2Requester extends Requester { */ async refreshAuth() { try { - console.log('[OAuth2Requester.refreshAuth] Starting token refresh', { + console.log('[Frigg] Starting token refresh', { grant_type: this.grant_type, has_refresh_token: !!this.refresh_token, has_client_id: !!this.client_id, @@ -302,10 +312,10 @@ class OAuth2Requester extends Requester { } else { await this.getTokenFromClientCredentials(); } - console.log('[OAuth2Requester.refreshAuth] Token refresh succeeded'); + console.log('[Frigg] Token refresh succeeded'); return true; } catch (error) { - console.error('[OAuth2Requester.refreshAuth] Token refresh failed', { + console.error('[Frigg] Token refresh failed', { error_message: error?.message, error_name: error?.name, response_status: error?.response?.status, From 103c6ab56ce9f28244b0647e0114b8aa31a12bec Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Feb 2026 04:00:44 +0000 Subject: [PATCH 4/5] chore: merge cleanup - remove debug files, add Prisma migration, merge next - Remove simple-test.js and test-form-auth.js debug files - Add PostgreSQL migration for AdminProcess and ScriptSchedule models - Merge latest next (PR #537: OAuth2 refresh_token logging fixes) - Update package-lock.json from npm install https://claude.ai/code/session_01UTMSBwVwDXaGTmtnNJ8VX6 --- package-lock.json | 1194 ++++++++++++++++- packages/core/handlers/app-handler-helpers.js | 1 - packages/core/modules/module.js | 13 +- packages/core/modules/requester/oauth-2.js | 17 +- .../migration.sql | 55 + simple-test.js | 304 ----- test-form-auth.js | 337 ----- 7 files changed, 1254 insertions(+), 667 deletions(-) create mode 100644 packages/core/prisma-postgresql/migrations/20260222000000_add_admin_process_and_script_schedule/migration.sql delete mode 100644 simple-test.js delete mode 100644 test-form-auth.js diff --git a/package-lock.json b/package-lock.json index 0b691a6c4..f86b2b97e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/@atomist/slack-messages": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@atomist/slack-messages/-/slack-messages-1.2.2.tgz", @@ -10398,6 +10419,121 @@ "node": ">=12" } }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@date-io/core": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@date-io/core/-/core-3.2.0.tgz", @@ -11332,6 +11468,10 @@ "resolved": "packages/admin-scripts", "link": true }, + "node_modules/@friggframework/ai-agents": { + "resolved": "packages/ai-agents", + "link": true + }, "node_modules/@friggframework/core": { "resolved": "packages/core", "link": true @@ -11340,6 +11480,10 @@ "resolved": "packages/devtools", "link": true }, + "node_modules/@friggframework/e2e": { + "resolved": "packages/e2e", + "link": true + }, "node_modules/@friggframework/eslint-config": { "resolved": "packages/eslint-config", "link": true @@ -19380,6 +19524,56 @@ "node": ">= 14.16" } }, + "node_modules/@vitest/mocker": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", + "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/@vitest/spy": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", + "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker/node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@vitest/pretty-format": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", @@ -19392,6 +19586,110 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/runner": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", + "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/runner/node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", + "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/snapshot/node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@vitest/spy": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", @@ -21092,6 +21390,16 @@ "url": "https://dotenvx.com" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/cacache": { "version": "18.0.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", @@ -22534,6 +22842,27 @@ "node": ">=4" } }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -22561,6 +22890,57 @@ "node": ">=8" } }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -22681,6 +23061,13 @@ "node": ">=0.10.0" } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, "node_modules/decode-uri-component": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.4.1.tgz", @@ -23705,6 +24092,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -24600,6 +24994,16 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -24705,6 +25109,16 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/exponential-backoff": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz", @@ -26261,6 +26675,19 @@ "node": ">=10" } }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -27084,6 +27511,13 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", @@ -29500,6 +29934,130 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.1.0", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/jsdom/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/jsep": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", @@ -31096,6 +31654,16 @@ "node": ">=12" } }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -32489,6 +33057,13 @@ "node": ">=8" } }, + "node_modules/nwsapi": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "dev": true, + "license": "MIT" + }, "node_modules/nx": { "version": "20.3.2", "resolved": "https://registry.npmjs.org/nx/-/nx-20.3.2.tgz", @@ -33575,6 +34150,32 @@ "parse-path": "^7.0.0" } }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -35199,6 +35800,13 @@ "fsevents": "~2.3.2" } }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true, + "license": "MIT" + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -35366,6 +35974,19 @@ "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==", "dev": true }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -36331,6 +36952,13 @@ "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -36734,6 +37362,13 @@ "node": ">=8" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -36742,6 +37377,13 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -37280,6 +37922,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, "node_modules/synckit": { "version": "0.11.11", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", @@ -37706,6 +38355,13 @@ "node": ">=0.12" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, "node_modules/tinycolor2": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", @@ -37718,6 +38374,16 @@ "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", "dev": true }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, "node_modules/tinyrainbow": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", @@ -37736,6 +38402,26 @@ "node": ">=14.0.0" } }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -37802,6 +38488,19 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -39068,6 +39767,250 @@ } } }, + "node_modules/vite-node": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", + "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-node/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vitest": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", + "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/@vitest/expect": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", + "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest/node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest/node_modules/@vitest/spy": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", + "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest/node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest/node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/vitest/node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/vitest/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vitest/node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/vitest/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vitest/node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vitest/node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/vscode-json-languageservice": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-4.2.1.tgz", @@ -39100,6 +40043,19 @@ "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==" }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/walk-up-path": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", @@ -39128,6 +40084,43 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -39242,6 +40235,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -39517,6 +40527,16 @@ } } }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, "node_modules/xml2js": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", @@ -39539,6 +40559,13 @@ "node": ">=4.0" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -39772,6 +40799,37 @@ "node": ">=12.0" } }, + "packages/ai-agents": { + "name": "@friggframework/ai-agents", + "version": "2.0.0-next.0", + "license": "MIT", + "dependencies": { + "@friggframework/schemas": "^2.0.0-next.0" + }, + "devDependencies": { + "@friggframework/eslint-config": "^2.0.0-next.0", + "@friggframework/prettier-config": "^2.0.0-next.0", + "eslint": "^8.22.0", + "jest": "^29.7.0", + "prettier": "^2.7.1" + }, + "peerDependencies": { + "@ai-sdk/openai": ">=1.0.0", + "@anthropic-ai/claude-agent-sdk": ">=0.1.0", + "ai": ">=4.0.0" + }, + "peerDependenciesMeta": { + "@ai-sdk/openai": { + "optional": true + }, + "@anthropic-ai/claude-agent-sdk": { + "optional": true + }, + "ai": { + "optional": true + } + } + }, "packages/core": { "name": "@friggframework/core", "version": "2.0.0-next.0", @@ -39792,6 +40850,7 @@ "express-async-handler": "^1.2.0", "form-data": "^4.0.0", "fs-extra": "^11.2.0", + "js-yaml": "^4.1.0", "lodash": "4.17.21", "lodash.get": "^4.4.2", "mongoose": "6.11.6", @@ -39815,6 +40874,7 @@ "prettier": "^2.7.1", "prisma": "^6.17.0", "sinon": "^16.1.1", + "supertest": "^7.1.4", "typescript": "^5.0.2" }, "peerDependencies": { @@ -39903,6 +40963,7 @@ "@friggframework/prettier-config": "^2.0.0-next.0", "aws-sdk-client-mock": "^4.1.0", "aws-sdk-client-mock-jest": "^4.1.0", + "exit-x": "^0.2.2", "jest": "^30.1.3", "osls": "^3.40.1", "prettier": "^2.7.1", @@ -41069,6 +42130,71 @@ "node": ">=12" } }, + "packages/e2e": { + "name": "@friggframework/e2e", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@friggframework/core": "*" + }, + "devDependencies": { + "@friggframework/test": "*", + "jest": "^29.7.0", + "mongodb-memory-server": "^8.9.0", + "supertest": "^6.3.3" + } + }, + "packages/e2e/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "packages/e2e/node_modules/superagent": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", + "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", + "deprecated": "Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "packages/e2e/node_modules/supertest": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.4.tgz", + "integrity": "sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==", + "deprecated": "Please upgrade to supertest v7.1.3+, see release notes at https://github.com/forwardemail/supertest/releases/tag/v7.1.3 - maintenance is supported by Forward Email @ https://forwardemail.net", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^8.1.2" + }, + "engines": { + "node": ">=6.4.0" + } + }, "packages/eslint-config": { "name": "@friggframework/eslint-config", "version": "2.0.0-next.0", @@ -41151,12 +42277,14 @@ "license": "MIT", "dependencies": { "@babel/eslint-parser": "^7.18.9", + "@hapi/boom": "^10.0.1", "eslint": "^8.22.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-json": "^3.1.0", "eslint-plugin-markdown": "^3.0.0", "eslint-plugin-no-only-tests": "^3.0.0", "eslint-plugin-yaml": "^0.5.0", + "express": "^4.21.2", "jest-runner-groups": "^2.2.0", "mongodb-memory-server": "^8.9.0", "open": "^8.4.2" @@ -41165,7 +42293,67 @@ "@friggframework/eslint-config": "^2.0.0-next.0", "@friggframework/prettier-config": "^2.0.0-next.0", "jest": "^29.7.0", - "prettier": "^2.7.1" + "prettier": "^2.7.1", + "supertest": "^6.3.3" + }, + "peerDependencies": { + "supertest": ">=6.0.0" + }, + "peerDependenciesMeta": { + "supertest": { + "optional": true + } + } + }, + "packages/test/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "packages/test/node_modules/superagent": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", + "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", + "deprecated": "Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "packages/test/node_modules/supertest": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.4.tgz", + "integrity": "sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==", + "deprecated": "Please upgrade to supertest v7.1.3+, see release notes at https://github.com/forwardemail/supertest/releases/tag/v7.1.3 - maintenance is supported by Forward Email @ https://forwardemail.net", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^8.1.2" + }, + "engines": { + "node": ">=6.4.0" } }, "packages/ui": { @@ -41198,9 +42386,11 @@ "eslint-plugin-react": "^7.34.3", "eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-refresh": "^0.4.7", + "jsdom": "^25.0.0", "postcss": "^8.4.41", "tailwindcss": "^3.4.10", - "vite": "^5.3.4" + "vite": "^5.3.4", + "vitest": "^2.1.0" } }, "packages/ui/node_modules/node-fetch": { diff --git a/packages/core/handlers/app-handler-helpers.js b/packages/core/handlers/app-handler-helpers.js index b38e9316c..adfde40fb 100644 --- a/packages/core/handlers/app-handler-helpers.js +++ b/packages/core/handlers/app-handler-helpers.js @@ -35,7 +35,6 @@ const createApp = (applyMiddleware) => { flushDebugLog(boomError); res.status(statusCode).json({ error: 'Internal Server Error' }); } else { - console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message}`); res.status(statusCode).json({ error: err.message }); } }); diff --git a/packages/core/modules/module.js b/packages/core/modules/module.js index 8bf95a03c..4020278fe 100644 --- a/packages/core/modules/module.js +++ b/packages/core/modules/module.js @@ -102,15 +102,10 @@ class Module extends Delegate { this.api, this.userId ); - const apiParams = this.apiParamsFromCredential(this.api); - - if (!apiParams.refresh_token && this.api.isRefreshable) { - console.warn( - `[Frigg] No refresh_token in apiParams for module ${this.name}.` - ); - } - - Object.assign(credentialDetails.details, apiParams); + Object.assign( + credentialDetails.details, + this.apiParamsFromCredential(this.api) + ); credentialDetails.details.authIsValid = true; const persisted = await this.credentialRepository.upsertCredential( diff --git a/packages/core/modules/requester/oauth-2.js b/packages/core/modules/requester/oauth-2.js index 7843534da..0b8d189d0 100644 --- a/packages/core/modules/requester/oauth-2.js +++ b/packages/core/modules/requester/oauth-2.js @@ -117,16 +117,6 @@ class OAuth2Requester extends Requester { const newRefreshToken = get(params, 'refresh_token', null); if (newRefreshToken !== null) { this.refresh_token = newRefreshToken; - } else { - if (this.refresh_token) { - console.log( - '[Frigg] No refresh_token in response, preserving existing' - ); - } else { - console.log( - '[Frigg] Current refresh_token is null and no new refresh_token in response' - ); - } } const accessExpiresIn = get(params, 'expires_in', null); const refreshExpiresIn = get( @@ -248,7 +238,6 @@ class OAuth2Requester extends Requester { 'Content-Type': 'application/x-www-form-urlencoded', }, }; - console.log('[Frigg] Refreshing access token with options'); const response = await this._post(options, false); await this.setTokens(response); return response; @@ -296,7 +285,7 @@ class OAuth2Requester extends Requester { */ async refreshAuth() { try { - console.log('[Frigg] Starting token refresh', { + console.log('[OAuth2Requester.refreshAuth] Starting token refresh', { grant_type: this.grant_type, has_refresh_token: !!this.refresh_token, has_client_id: !!this.client_id, @@ -312,10 +301,10 @@ class OAuth2Requester extends Requester { } else { await this.getTokenFromClientCredentials(); } - console.log('[Frigg] Token refresh succeeded'); + console.log('[OAuth2Requester.refreshAuth] Token refresh succeeded'); return true; } catch (error) { - console.error('[Frigg] Token refresh failed', { + console.error('[OAuth2Requester.refreshAuth] Token refresh failed', { error_message: error?.message, error_name: error?.name, response_status: error?.response?.status, diff --git a/packages/core/prisma-postgresql/migrations/20260222000000_add_admin_process_and_script_schedule/migration.sql b/packages/core/prisma-postgresql/migrations/20260222000000_add_admin_process_and_script_schedule/migration.sql new file mode 100644 index 000000000..9a018d00b --- /dev/null +++ b/packages/core/prisma-postgresql/migrations/20260222000000_add_admin_process_and_script_schedule/migration.sql @@ -0,0 +1,55 @@ +-- CreateEnum +CREATE TYPE "AdminProcessState" AS ENUM ('PENDING', 'RUNNING', 'COMPLETED', 'FAILED'); + +-- CreateEnum +CREATE TYPE "AdminTrigger" AS ENUM ('MANUAL', 'SCHEDULED', 'QUEUE', 'WEBHOOK'); + +-- CreateTable +CREATE TABLE "AdminProcess" ( + "id" SERIAL NOT NULL, + "name" TEXT NOT NULL, + "type" TEXT NOT NULL, + "state" "AdminProcessState" NOT NULL DEFAULT 'PENDING', + "context" JSONB NOT NULL DEFAULT '{}', + "results" JSONB NOT NULL DEFAULT '{}', + "parentProcessId" INTEGER, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "AdminProcess_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ScriptSchedule" ( + "id" SERIAL NOT NULL, + "scriptName" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT false, + "cronExpression" TEXT, + "timezone" TEXT NOT NULL DEFAULT 'UTC', + "lastTriggeredAt" TIMESTAMP(3), + "nextTriggerAt" TIMESTAMP(3), + "externalScheduleId" TEXT, + "externalScheduleName" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "ScriptSchedule_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "AdminProcess_name_createdAt_idx" ON "AdminProcess"("name", "createdAt" DESC); + +-- CreateIndex +CREATE INDEX "AdminProcess_state_idx" ON "AdminProcess"("state"); + +-- CreateIndex +CREATE INDEX "AdminProcess_type_idx" ON "AdminProcess"("type"); + +-- CreateIndex +CREATE UNIQUE INDEX "ScriptSchedule_scriptName_key" ON "ScriptSchedule"("scriptName"); + +-- CreateIndex +CREATE INDEX "ScriptSchedule_enabled_idx" ON "ScriptSchedule"("enabled"); + +-- AddForeignKey +ALTER TABLE "AdminProcess" ADD CONSTRAINT "AdminProcess_parentProcessId_fkey" FOREIGN KEY ("parentProcessId") REFERENCES "AdminProcess"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/simple-test.js b/simple-test.js deleted file mode 100644 index afa5466a0..000000000 --- a/simple-test.js +++ /dev/null @@ -1,304 +0,0 @@ -/** - * @file Simple Form Authentication Test - * @description Basic verification of form-based authentication implementation - */ - -// Mock module definition for testing -class TestFormAuthModule { - static getName() { - return 'test-form-auth'; - } - - static getDisplayName() { - return 'Test Form Auth Service'; - } - - static getDescription() { - return 'A test service with form-based authentication'; - } - - static getAuthType() { - return 'form'; - } - - static getCapabilities() { - return ['read', 'write']; - } - - static getRequiredScopes() { - return ['scope1']; - } - - static getAuthStepCount() { - return 2; // Email โ†’ OTP - } - - static async getAuthRequirementsForStep(step) { - if (step === 1) { - return { - type: 'form', - data: { - jsonSchema: { - title: 'Connect Test Service', - description: 'Enter your email to receive a verification code', - type: 'object', - required: ['email'], - properties: { - email: { - type: 'string', - format: 'email', - title: 'Email Address', - description: 'Your account email' - } - } - }, - uiSchema: { - email: { - 'ui:placeholder': 'your.email@company.com', - 'ui:help': 'Enter the email address associated with your account', - 'ui:autofocus': true - } - } - } - }; - } - - if (step === 2) { - return { - type: 'form', - data: { - jsonSchema: { - title: 'Verify One-Time Password', - description: 'Enter the 6-digit code sent to your email', - type: 'object', - required: ['email', 'otp'], - properties: { - email: { - type: 'string', - format: 'email', - title: 'Email Address', - readOnly: true - }, - otp: { - type: 'string', - title: 'Verification Code', - description: 'Check your email for the code', - minLength: 6, - maxLength: 6, - pattern: '^[0-9]{6}$' - } - } - }, - uiSchema: { - email: { - 'ui:readonly': true, - 'ui:disabled': true - }, - otp: { - 'ui:placeholder': '000000', - 'ui:help': 'Enter the 6-digit verification code from your email', - 'ui:autofocus': true, - 'ui:inputType': 'tel' - } - } - } - }; - } - - throw new Error(`Step ${step} is not defined for Test Form Auth`); - } - - static async processAuthorizationStep(api, step, stepData, sessionData = {}) { - if (step === 1) { - const { email } = stepData; - - // Validate email format - if (!email || !email.includes('@')) { - throw new Error('Valid email address is required'); - } - - console.log(`โœ“ Step 1: Sending OTP to ${email}`); - - return { - nextStep: 2, - stepData: { email }, - message: `Verification code sent to ${email}. Please check your email.` - }; - } - - if (step === 2) { - const { email, otp } = stepData; - - // Validate OTP format - if (!otp || !/^\d{6}$/.test(otp)) { - throw new Error('Verification code must be exactly 6 digits'); - } - - // Simulate OTP verification - if (otp === '123456') { - console.log(`โœ“ Step 2: OTP verification successful for ${email}`); - return { - completed: true, - authData: { - access_token: 'mock_access_token', - refresh_token: 'mock_refresh_token', - user: { - id: 'user_123', - email: email, - name: 'Test User' - }, - token_type: 'Bearer', - expires_in: 3600 - } - }; - } else { - throw new Error('Invalid verification code. Please try again.'); - } - } - - throw new Error(`Step ${step} is not implemented for Test Form Auth`); - } - - static async testAuth(authData) { - return authData.access_token === 'mock_access_token'; - } - - static async getEntityDetails(authData) { - return { - name: authData.user.email, - externalId: authData.user.id, - details: { - email: authData.user.email, - name: authData.user.name - } - }; - } -} - -// Test the module definition directly -async function testModuleDefinition() { - console.log('๐Ÿงช Testing Module Definition...\n'); - - try { - // Test step 1 requirements - console.log('1. Testing Step 1 Requirements:'); - const step1Reqs = await TestFormAuthModule.getAuthRequirementsForStep(1); - console.log(` โœ“ Step 1 type: ${step1Reqs.type}`); - console.log(` โœ“ Step 1 title: ${step1Reqs.data.jsonSchema.title}`); - console.log(` โœ“ Step 1 has email field: ${!!step1Reqs.data.jsonSchema.properties.email}`); - console.log(` โœ“ Step 1 has UI schema: ${!!step1Reqs.data.uiSchema.email}`); - - // Test step 2 requirements - console.log('\n2. Testing Step 2 Requirements:'); - const step2Reqs = await TestFormAuthModule.getAuthRequirementsForStep(2); - console.log(` โœ“ Step 2 type: ${step2Reqs.type}`); - console.log(` โœ“ Step 2 title: ${step2Reqs.data.jsonSchema.title}`); - console.log(` โœ“ Step 2 has OTP field: ${!!step2Reqs.data.jsonSchema.properties.otp}`); - console.log(` โœ“ Step 2 has UI schema: ${!!step2Reqs.data.uiSchema.otp}`); - - // Test step 1 processing - console.log('\n3. Testing Step 1 Processing:'); - const step1Result = await TestFormAuthModule.processAuthorizationStep( - {}, // mock API - 1, - { email: 'test@example.com' } - ); - console.log(` โœ“ Next step: ${step1Result.nextStep}`); - console.log(` โœ“ Message: ${step1Result.message}`); - console.log(` โœ“ Step data preserved: ${step1Result.stepData.email}`); - - // Test step 2 processing (success) - console.log('\n4. Testing Step 2 Processing (Success):'); - const step2Result = await TestFormAuthModule.processAuthorizationStep( - {}, // mock API - 2, - { email: 'test@example.com', otp: '123456' } - ); - console.log(` โœ“ Completed: ${step2Result.completed}`); - console.log(` โœ“ Has auth data: ${!!step2Result.authData}`); - console.log(` โœ“ User email: ${step2Result.authData.user.email}`); - - // Test step 2 processing (failure) - console.log('\n5. Testing Step 2 Processing (Failure):'); - try { - await TestFormAuthModule.processAuthorizationStep( - {}, // mock API - 2, - { email: 'test@example.com', otp: '999999' } - ); - console.log(' โŒ Should have thrown error for invalid OTP'); - } catch (error) { - console.log(` โœ“ Correctly rejected invalid OTP: ${error.message}`); - } - - // Test entity details - console.log('\n6. Testing Entity Details:'); - const entityDetails = await TestFormAuthModule.getEntityDetails(step2Result.authData); - console.log(` โœ“ Entity name: ${entityDetails.name}`); - console.log(` โœ“ External ID: ${entityDetails.externalId}`); - console.log(` โœ“ Has details: ${!!entityDetails.details}`); - - console.log('\nโœ… All Module Definition Tests Passed!\n'); - - } catch (error) { - console.error('โŒ Module Definition Test Failed:', error.message); - process.exit(1); - } -} - -// Test file existence -function testFileExistence() { - console.log('๐Ÿงช Testing File Existence...\n'); - - const fs = require('fs'); - const path = require('path'); - - const filesToCheck = [ - 'packages/ui/lib/integration/presentation/components/AuthorizationWizard.jsx', - 'packages/ui/lib/integration/presentation/components/EntityConnectionModal.jsx', - 'packages/ui/lib/integration/infrastructure/adapters/FriggApiAdapter.js', - 'packages/ui/lib/api/api.js', - 'packages/core/integrations/integration-router.js', - 'packages/core/modules/use-cases/get-authorization-requirements.js', - 'packages/core/modules/use-cases/process-authorization-step.js' - ]; - - filesToCheck.forEach(file => { - const fullPath = path.join(__dirname, file); - const exists = fs.existsSync(fullPath); - console.log(` ${exists ? 'โœ“' : 'โŒ'} ${file}`); - }); - - console.log('\nโœ… File Existence Tests Completed!\n'); -} - -// Main test runner -async function runTests() { - console.log('๐Ÿš€ Starting Form Authentication Verification Tests\n'); - console.log('=' .repeat(60)); - - try { - await testModuleDefinition(); - testFileExistence(); - - console.log('=' .repeat(60)); - console.log('๐ŸŽ‰ All Tests Passed! Form Authentication Implementation is Working!'); - console.log('\n๐Ÿ“‹ Summary:'); - console.log(' โœ… Module Definition: Multi-step form auth with email โ†’ OTP flow'); - console.log(' โœ… File Structure: All required files exist'); - console.log(' โœ… DDD Patterns: Proper separation of concerns'); - console.log(' โœ… Hexagonal Architecture: Clean interfaces between layers'); - console.log('\n๐Ÿ”— Integration Points Verified:'); - console.log(' โ€ข UI Library โ†” Core API endpoints'); - console.log(' โ€ข AuthorizationWizard โ†” Module definitions'); - console.log(' โ€ข Form validation โ†” Business logic'); - console.log(' โ€ข Session management โ†” Multi-step flows'); - - } catch (error) { - console.error('โŒ Test Suite Failed:', error.message); - process.exit(1); - } -} - -// Run the tests -runTests(); diff --git a/test-form-auth.js b/test-form-auth.js deleted file mode 100644 index b1c49ae68..000000000 --- a/test-form-auth.js +++ /dev/null @@ -1,337 +0,0 @@ -/** - * @file Form Authentication Verification Script - * @description Manual verification of form-based authentication implementation - */ - -const express = require('express'); -const request = require('supertest'); - -// Mock module definition for testing -class TestFormAuthModule { - static getName() { - return 'test-form-auth'; - } - - static getDisplayName() { - return 'Test Form Auth Service'; - } - - static getDescription() { - return 'A test service with form-based authentication'; - } - - static getAuthType() { - return 'form'; - } - - static getCapabilities() { - return ['read', 'write']; - } - - static getRequiredScopes() { - return ['scope1']; - } - - static getAuthStepCount() { - return 2; // Email โ†’ OTP - } - - static async getAuthRequirementsForStep(step) { - if (step === 1) { - return { - type: 'form', - data: { - jsonSchema: { - title: 'Connect Test Service', - description: 'Enter your email to receive a verification code', - type: 'object', - required: ['email'], - properties: { - email: { - type: 'string', - format: 'email', - title: 'Email Address', - description: 'Your account email' - } - } - }, - uiSchema: { - email: { - 'ui:placeholder': 'your.email@company.com', - 'ui:help': 'Enter the email address associated with your account', - 'ui:autofocus': true - } - } - } - }; - } - - if (step === 2) { - return { - type: 'form', - data: { - jsonSchema: { - title: 'Verify One-Time Password', - description: 'Enter the 6-digit code sent to your email', - type: 'object', - required: ['email', 'otp'], - properties: { - email: { - type: 'string', - format: 'email', - title: 'Email Address', - readOnly: true - }, - otp: { - type: 'string', - title: 'Verification Code', - description: 'Check your email for the code', - minLength: 6, - maxLength: 6, - pattern: '^[0-9]{6}$' - } - } - }, - uiSchema: { - email: { - 'ui:readonly': true, - 'ui:disabled': true - }, - otp: { - 'ui:placeholder': '000000', - 'ui:help': 'Enter the 6-digit verification code from your email', - 'ui:autofocus': true, - 'ui:inputType': 'tel' - } - } - } - }; - } - - throw new Error(`Step ${step} is not defined for Test Form Auth`); - } - - static async processAuthorizationStep(api, step, stepData, sessionData = {}) { - if (step === 1) { - const { email } = stepData; - - // Validate email format - if (!email || !email.includes('@')) { - throw new Error('Valid email address is required'); - } - - console.log(`โœ“ Step 1: Sending OTP to ${email}`); - - return { - nextStep: 2, - stepData: { email }, - message: `Verification code sent to ${email}. Please check your email.` - }; - } - - if (step === 2) { - const { email, otp } = stepData; - - // Validate OTP format - if (!otp || !/^\d{6}$/.test(otp)) { - throw new Error('Verification code must be exactly 6 digits'); - } - - // Simulate OTP verification - if (otp === '123456') { - console.log(`โœ“ Step 2: OTP verification successful for ${email}`); - return { - completed: true, - authData: { - access_token: 'mock_access_token', - refresh_token: 'mock_refresh_token', - user: { - id: 'user_123', - email: email, - name: 'Test User' - }, - token_type: 'Bearer', - expires_in: 3600 - } - }; - } else { - throw new Error('Invalid verification code. Please try again.'); - } - } - - throw new Error(`Step ${step} is not implemented for Test Form Auth`); - } - - static async testAuth(authData) { - return authData.access_token === 'mock_access_token'; - } - - static async getEntityDetails(authData) { - return { - name: authData.user.email, - externalId: authData.user.id, - details: { - email: authData.user.email, - name: authData.user.name - } - }; - } -} - -// Test the module definition directly -async function testModuleDefinition() { - console.log('๐Ÿงช Testing Module Definition...\n'); - - try { - // Test step 1 requirements - console.log('1. Testing Step 1 Requirements:'); - const step1Reqs = await TestFormAuthModule.getAuthRequirementsForStep(1); - console.log(` โœ“ Step 1 type: ${step1Reqs.type}`); - console.log(` โœ“ Step 1 title: ${step1Reqs.data.jsonSchema.title}`); - console.log(` โœ“ Step 1 has email field: ${!!step1Reqs.data.jsonSchema.properties.email}`); - console.log(` โœ“ Step 1 has UI schema: ${!!step1Reqs.data.uiSchema.email}`); - - // Test step 2 requirements - console.log('\n2. Testing Step 2 Requirements:'); - const step2Reqs = await TestFormAuthModule.getAuthRequirementsForStep(2); - console.log(` โœ“ Step 2 type: ${step2Reqs.type}`); - console.log(` โœ“ Step 2 title: ${step2Reqs.data.jsonSchema.title}`); - console.log(` โœ“ Step 2 has OTP field: ${!!step2Reqs.data.jsonSchema.properties.otp}`); - console.log(` โœ“ Step 2 has UI schema: ${!!step2Reqs.data.uiSchema.otp}`); - - // Test step 1 processing - console.log('\n3. Testing Step 1 Processing:'); - const step1Result = await TestFormAuthModule.processAuthorizationStep( - {}, // mock API - 1, - { email: 'test@example.com' } - ); - console.log(` โœ“ Next step: ${step1Result.nextStep}`); - console.log(` โœ“ Message: ${step1Result.message}`); - console.log(` โœ“ Step data preserved: ${step1Result.stepData.email}`); - - // Test step 2 processing (success) - console.log('\n4. Testing Step 2 Processing (Success):'); - const step2Result = await TestFormAuthModule.processAuthorizationStep( - {}, // mock API - 2, - { email: 'test@example.com', otp: '123456' } - ); - console.log(` โœ“ Completed: ${step2Result.completed}`); - console.log(` โœ“ Has auth data: ${!!step2Result.authData}`); - console.log(` โœ“ User email: ${step2Result.authData.user.email}`); - - // Test step 2 processing (failure) - console.log('\n5. Testing Step 2 Processing (Failure):'); - try { - await TestFormAuthModule.processAuthorizationStep( - {}, // mock API - 2, - { email: 'test@example.com', otp: '999999' } - ); - console.log(' โŒ Should have thrown error for invalid OTP'); - } catch (error) { - console.log(` โœ“ Correctly rejected invalid OTP: ${error.message}`); - } - - // Test entity details - console.log('\n6. Testing Entity Details:'); - const entityDetails = await TestFormAuthModule.getEntityDetails(step2Result.authData); - console.log(` โœ“ Entity name: ${entityDetails.name}`); - console.log(` โœ“ External ID: ${entityDetails.externalId}`); - console.log(` โœ“ Has details: ${!!entityDetails.details}`); - - console.log('\nโœ… All Module Definition Tests Passed!\n'); - - } catch (error) { - console.error('โŒ Module Definition Test Failed:', error.message); - process.exit(1); - } -} - -// Test the API structure -function testAPIStructure() { - console.log('๐Ÿงช Testing API Structure...\n'); - - // Test FriggApiAdapter methods - const { FriggApiAdapter } = require('./packages/ui/lib/integration/infrastructure/adapters/FriggApiAdapter.js'); - - const api = new FriggApiAdapter({ - baseUrl: 'https://api.example.com', - authToken: 'test-token' - }); - - console.log('1. Testing FriggApiAdapter:'); - console.log(` โœ“ Has getModuleAuthorizationRequirements: ${typeof api.getModuleAuthorizationRequirements === 'function'}`); - console.log(` โœ“ Has submitModuleAuthorization: ${typeof api.submitModuleAuthorization === 'function'}`); - console.log(` โœ“ Has listCredentials: ${typeof api.listCredentials === 'function'}`); - console.log(` โœ“ Has testEntity: ${typeof api.testEntity === 'function'}`); - - // Test API.js methods - const API = require('./packages/ui/lib/api/api.js').default; - const legacyApi = new API('https://api.example.com', 'test-token'); - - console.log('\n2. Testing Legacy API (with new methods):'); - console.log(` โœ“ Has getModuleAuthorizationRequirements: ${typeof legacyApi.getModuleAuthorizationRequirements === 'function'}`); - console.log(` โœ“ Has submitModuleAuthorization: ${typeof legacyApi.submitModuleAuthorization === 'function'}`); - console.log(` โœ“ Has listCredentials: ${typeof legacyApi.listCredentials === 'function'}`); - console.log(` โœ“ Has testEntity: ${typeof legacyApi.testEntity === 'function'}`); - - console.log('\nโœ… All API Structure Tests Passed!\n'); -} - -// Test component structure -function testComponentStructure() { - console.log('๐Ÿงช Testing Component Structure...\n'); - - try { - // Test AuthorizationWizard component - const { AuthorizationWizard } = require('./packages/ui/lib/integration/presentation/components/AuthorizationWizard.jsx'); - console.log('1. Testing AuthorizationWizard:'); - console.log(` โœ“ Component exists: ${typeof AuthorizationWizard === 'function'}`); - - // Test EntityConnectionModal component - const { EntityConnectionModal } = require('./packages/ui/lib/integration/presentation/components/EntityConnectionModal.jsx'); - console.log('2. Testing EntityConnectionModal:'); - console.log(` โœ“ Component exists: ${typeof EntityConnectionModal === 'function'}`); - - console.log('\nโœ… All Component Structure Tests Passed!\n'); - - } catch (error) { - console.error('โŒ Component Structure Test Failed:', error.message); - process.exit(1); - } -} - -// Main test runner -async function runTests() { - console.log('๐Ÿš€ Starting Form Authentication Verification Tests\n'); - console.log('=' .repeat(60)); - - try { - await testModuleDefinition(); - testAPIStructure(); - testComponentStructure(); - - console.log('=' .repeat(60)); - console.log('๐ŸŽ‰ All Tests Passed! Form Authentication Implementation is Working!'); - console.log('\n๐Ÿ“‹ Summary:'); - console.log(' โœ… Module Definition: Multi-step form auth with email โ†’ OTP flow'); - console.log(' โœ… API Structure: New v2 endpoints with backward compatibility'); - console.log(' โœ… Component Structure: AuthorizationWizard and EntityConnectionModal'); - console.log(' โœ… DDD Patterns: Proper separation of concerns'); - console.log(' โœ… Hexagonal Architecture: Clean interfaces between layers'); - console.log('\n๐Ÿ”— Integration Points Verified:'); - console.log(' โ€ข UI Library โ†” Core API endpoints'); - console.log(' โ€ข AuthorizationWizard โ†” Module definitions'); - console.log(' โ€ข Form validation โ†” Business logic'); - console.log(' โ€ข Session management โ†” Multi-step flows'); - - } catch (error) { - console.error('โŒ Test Suite Failed:', error.message); - process.exit(1); - } -} - -// Run the tests -runTests(); From 8c08e05316bf5665618b453d34a5df35e472249a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Feb 2026 04:01:39 +0000 Subject: [PATCH 5/5] chore: update prisma layer build artifact from npm install https://claude.ai/code/session_01UTMSBwVwDXaGTmtnNJ8VX6 --- packages/devtools/layers/prisma/.build-complete | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/devtools/layers/prisma/.build-complete b/packages/devtools/layers/prisma/.build-complete index be5db6ce3..3df3452cf 100644 --- a/packages/devtools/layers/prisma/.build-complete +++ b/packages/devtools/layers/prisma/.build-complete @@ -1,3 +1,3 @@ -Build completed: 2025-12-19T16:09:52.095Z -Node: v23.5.0 -Platform: darwin +Build completed: 2026-02-22T03:42:25.135Z +Node: v22.22.0 +Platform: linux