From 5c3790fe98021771395e52b1144599552c17b4a5 Mon Sep 17 00:00:00 2001 From: Walker Lockard Date: Wed, 8 Oct 2025 16:54:28 -0700 Subject: [PATCH 1/5] create sha 256 code challenge --- .speakeasy/gen.lock | 2 +- .speakeasy/gen.yaml | 3 +- .speakeasy/workflow.lock | 2 - package-lock.json | 1524 ++++++++++++++++- package.json | 3 +- .../oAuthCreateSHA256CodeChallenge.test.ts | 189 ++ .../custom/oAuthCreateSHA256CodeChallenge.ts | 90 + 7 files changed, 1807 insertions(+), 6 deletions(-) create mode 100644 src/funcs/custom/oAuthCreateSHA256CodeChallenge.test.ts create mode 100644 src/funcs/custom/oAuthCreateSHA256CodeChallenge.ts diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 4cf49876..06574d9f 100644 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -6,7 +6,7 @@ management: speakeasyVersion: 1.636.2 generationVersion: 2.723.8 releaseVersion: 0.0.0-beta.38 - configChecksum: f01dbb000ab200e49a61999f65cc4fd7 + configChecksum: 45ac5e4bc0f54b03301449edf0dacc02 repoURL: https://github.com/OpenRouterTeam/typescript-sdk.git installationURL: https://github.com/OpenRouterTeam/typescript-sdk published: true diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index 467ad239..309aa1e0 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -31,7 +31,8 @@ typescript: acceptHeaderEnum: false additionalDependencies: dependencies: {} - devDependencies: {} + devDependencies: + vitest: ^3.2.4 peerDependencies: {} additionalPackageJSON: {} author: OpenRouter diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index 0da3edd5..0c5ba073 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -13,8 +13,6 @@ targets: sourceNamespace: open-router-chat-completions-api sourceRevisionDigest: sha256:c2e2e5da1b9a37b494867bb17c7bb41a4959ceeafd85543abc062675303a6e0c sourceBlobDigest: sha256:598248a264c5fac83e1bbae64cf68a4a95f6213b95bd17917299b192604c72c7 - codeSamplesNamespace: open-router-chat-completions-api-typescript-code-samples - codeSamplesRevisionDigest: sha256:913a09a43f1caf8c07c46f4378283b2c87dd447b2eaa4c6af213079ed186182e workflow: workflowVersion: 1.0.0 speakeasyVersion: latest diff --git a/package-lock.json b/package-lock.json index 92d93f8b..83389991 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,8 @@ "globals": "^15.14.0", "tshy": "^2.0.0", "typescript": "~5.8.3", - "typescript-eslint": "^8.26.0" + "typescript-eslint": "^8.26.0", + "vitest": "^3.2.4" }, "peerDependencies": { "@tanstack/react-query": "^5", @@ -37,6 +38,448 @@ } } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", + "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", + "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", + "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", + "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", + "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", + "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", + "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", + "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", + "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", + "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", + "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", + "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", + "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", + "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", + "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", + "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", + "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", + "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", + "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", + "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", + "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", + "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", + "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", + "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", + "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", @@ -275,6 +718,13 @@ "node": ">=12" } }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -324,6 +774,314 @@ "node": ">=14" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", + "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz", + "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz", + "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz", + "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz", + "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz", + "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz", + "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz", + "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz", + "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz", + "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz", + "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz", + "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz", + "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz", + "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz", + "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", + "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz", + "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz", + "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz", + "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz", + "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz", + "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz", + "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@tanstack/query-core": { "version": "5.90.2", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.2.tgz", @@ -352,6 +1110,23 @@ "react": "^18 || ^19" } }, + "node_modules/@types/chai": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", + "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -642,6 +1417,121 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -732,6 +1622,16 @@ "dev": true, "license": "Python-2.0" }, + "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/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -776,6 +1676,16 @@ "node": ">=8" } }, + "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/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -786,6 +1696,23 @@ "node": ">=6" } }, + "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/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -803,6 +1730,16 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -908,6 +1845,16 @@ } } }, + "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/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -929,6 +1876,55 @@ "dev": true, "license": "MIT" }, + "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/esbuild": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" + } + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -1087,6 +2083,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", @@ -1097,6 +2103,16 @@ "node": ">=0.10.0" } }, + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1460,6 +2476,13 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -1541,6 +2564,13 @@ "dev": true, "license": "MIT" }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", @@ -1548,6 +2578,16 @@ "dev": true, "license": "ISC" }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -1618,6 +2658,25 @@ "dev": true, "license": "MIT" }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "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/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -1742,6 +2801,30 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "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/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -1768,6 +2851,35 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "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", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -1887,6 +2999,48 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rollup": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", + "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.4", + "@rollup/rollup-android-arm64": "4.52.4", + "@rollup/rollup-darwin-arm64": "4.52.4", + "@rollup/rollup-darwin-x64": "4.52.4", + "@rollup/rollup-freebsd-arm64": "4.52.4", + "@rollup/rollup-freebsd-x64": "4.52.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", + "@rollup/rollup-linux-arm-musleabihf": "4.52.4", + "@rollup/rollup-linux-arm64-gnu": "4.52.4", + "@rollup/rollup-linux-arm64-musl": "4.52.4", + "@rollup/rollup-linux-loong64-gnu": "4.52.4", + "@rollup/rollup-linux-ppc64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-musl": "4.52.4", + "@rollup/rollup-linux-s390x-gnu": "4.52.4", + "@rollup/rollup-linux-x64-gnu": "4.52.4", + "@rollup/rollup-linux-x64-musl": "4.52.4", + "@rollup/rollup-openharmony-arm64": "4.52.4", + "@rollup/rollup-win32-arm64-msvc": "4.52.4", + "@rollup/rollup-win32-ia32-msvc": "4.52.4", + "@rollup/rollup-win32-x64-gnu": "4.52.4", + "@rollup/rollup-win32-x64-msvc": "4.52.4", + "fsevents": "~2.3.2" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -1947,6 +3101,13 @@ "node": ">=8" } }, + "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": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -1960,6 +3121,30 @@ "url": "https://github.com/sponsors/isaacs" } }, + "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==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "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/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "dev": true, + "license": "MIT" + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -2077,6 +3262,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2112,6 +3310,98 @@ "url": "https://github.com/sponsors/isaacs" } }, + "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/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/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2264,6 +3554,221 @@ "punycode": "^2.1.0" } }, + "node_modules/vite": { + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.9.tgz", + "integrity": "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "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/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/walk-up-path": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", @@ -2287,6 +3792,23 @@ "node": ">= 8" } }, + "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/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index 04ca850c..cdafaafa 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,8 @@ "globals": "^15.14.0", "tshy": "^2.0.0", "typescript": "~5.8.3", - "typescript-eslint": "^8.26.0" + "typescript-eslint": "^8.26.0", + "vitest": "^3.2.4" }, "dependencies": { "zod": "^3.20.0" diff --git a/src/funcs/custom/oAuthCreateSHA256CodeChallenge.test.ts b/src/funcs/custom/oAuthCreateSHA256CodeChallenge.test.ts new file mode 100644 index 00000000..7e4eb838 --- /dev/null +++ b/src/funcs/custom/oAuthCreateSHA256CodeChallenge.test.ts @@ -0,0 +1,189 @@ +import { describe, it, expect } from "vitest"; +import { oAuthCreateSHA256CodeChallenge } from "./oAuthCreateSHA256CodeChallenge.js"; + +describe("oAuthCreateSHA256CodeChallenge", () => { + it("should generate code challenge from provided code verifier", async () => { + // Use RFC 7636 compliant verifier (43 chars minimum) + const codeVerifier = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"; + const result = await oAuthCreateSHA256CodeChallenge({ codeVerifier }); + + expect(result.ok).toBe(true); + if (result.ok) { + expect(result.value.codeVerifier).toBe(codeVerifier); + expect(result.value.codeChallenge).toBeTruthy(); + expect(typeof result.value.codeChallenge).toBe("string"); + // Code challenge should be base64url encoded (no +, /, or = characters) + expect(result.value.codeChallenge).not.toMatch(/[+/=]/); + } + }); + + it("should generate consistent code challenge for same verifier", async () => { + // RFC compliant verifier (43+ chars) + const codeVerifier = "a".repeat(43); + const result1 = await oAuthCreateSHA256CodeChallenge({ codeVerifier }); + const result2 = await oAuthCreateSHA256CodeChallenge({ codeVerifier }); + + expect(result1.ok).toBe(true); + expect(result2.ok).toBe(true); + if (result1.ok && result2.ok) { + expect(result1.value.codeChallenge).toBe(result2.value.codeChallenge); + } + }); + + it("should generate RFC 7636 compliant random code verifier when not provided", async () => { + const result = await oAuthCreateSHA256CodeChallenge(); + + expect(result.ok).toBe(true); + if (result.ok) { + expect(result.value.codeVerifier).toBeTruthy(); + expect(result.value.codeChallenge).toBeTruthy(); + expect(typeof result.value.codeVerifier).toBe("string"); + // RFC 7636: verifier should be exactly 43 characters (32 bytes base64url encoded) + expect(result.value.codeVerifier.length).toBe(43); + // Should only contain base64url characters + expect(result.value.codeVerifier).toMatch(/^[A-Za-z0-9_-]+$/); + } + }); + + it("should generate different code verifiers on successive calls", async () => { + const result1 = await oAuthCreateSHA256CodeChallenge(); + const result2 = await oAuthCreateSHA256CodeChallenge(); + + expect(result1.ok).toBe(true); + expect(result2.ok).toBe(true); + if (result1.ok && result2.ok) { + expect(result1.value.codeVerifier).not.toBe(result2.value.codeVerifier); + expect(result1.value.codeChallenge).not.toBe(result2.value.codeChallenge); + } + }); + + it("should generate base64url encoded challenge (RFC 7636)", async () => { + const codeVerifier = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"; + const result = await oAuthCreateSHA256CodeChallenge({ codeVerifier }); + + expect(result.ok).toBe(true); + if (result.ok) { + // Should be base64url encoded (no standard base64 chars) + expect(result.value.codeChallenge).not.toMatch(/\+/); + expect(result.value.codeChallenge).not.toMatch(/\//); + expect(result.value.codeChallenge).not.toMatch(/=/); + // Should only contain base64url characters + expect(result.value.codeChallenge).toMatch(/^[A-Za-z0-9_-]+$/); + } + }); + + it("should handle invalid input type", async () => { + const result = await oAuthCreateSHA256CodeChallenge({ + codeVerifier: 123 as any, + }); + + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.error).toBeDefined(); + } + }); + + it("should produce SHA-256 hash of correct length", async () => { + const codeVerifier = "a".repeat(43); // RFC compliant length + const result = await oAuthCreateSHA256CodeChallenge({ codeVerifier }); + + expect(result.ok).toBe(true); + if (result.ok) { + // SHA-256 produces 256 bits = 32 bytes + // Base64url encoding of 32 bytes should be 43 characters (no padding) + expect(result.value.codeChallenge.length).toBe(43); + } + }); + + it("should reject empty string code verifier (RFC 7636 violation)", async () => { + const result = await oAuthCreateSHA256CodeChallenge({ codeVerifier: "" }); + + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.error).toBeDefined(); + expect((result.error as Error).message).toContain("at least 43 characters"); + } + }); + + it("should reject code verifier shorter than 43 characters", async () => { + const result = await oAuthCreateSHA256CodeChallenge({ + codeVerifier: "too-short", + }); + + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.error).toBeDefined(); + expect((result.error as Error).message).toContain("at least 43 characters"); + } + }); + + it("should reject code verifier longer than 128 characters (RFC 7636)", async () => { + const longVerifier = "a".repeat(129); + const result = await oAuthCreateSHA256CodeChallenge({ + codeVerifier: longVerifier, + }); + + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.error).toBeDefined(); + expect((result.error as Error).message).toContain("at most 128 characters"); + } + }); + + it("should accept code verifier at maximum length (128 characters)", async () => { + const maxVerifier = "a".repeat(128); + const result = await oAuthCreateSHA256CodeChallenge({ + codeVerifier: maxVerifier, + }); + + expect(result.ok).toBe(true); + if (result.ok) { + expect(result.value.codeVerifier).toBe(maxVerifier); + expect(result.value.codeChallenge).toBeTruthy(); + // SHA-256 always produces same length output regardless of input length + expect(result.value.codeChallenge.length).toBe(43); + } + }); + + it("should accept RFC 7636 unreserved characters in code verifier", async () => { + // RFC 7636 allows: [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~" + const validVerifier = "aZ09-._~" + "a".repeat(35); // 43 chars total + const result = await oAuthCreateSHA256CodeChallenge({ + codeVerifier: validVerifier, + }); + + expect(result.ok).toBe(true); + if (result.ok) { + expect(result.value.codeVerifier).toBe(validVerifier); + expect(result.value.codeChallenge).toBeTruthy(); + expect(result.value.codeChallenge.length).toBe(43); + } + }); + + it("should reject code verifier with invalid characters", async () => { + // Contains invalid characters like ! @ # $ etc. + const invalidVerifier = "test!@#$%^&*()+=[]{}|;:',.<>?/`" + "a".repeat(13); + const result = await oAuthCreateSHA256CodeChallenge({ + codeVerifier: invalidVerifier, + }); + + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.error).toBeDefined(); + expect((result.error as Error).message).toContain("unreserved characters"); + } + }); + + it("should reject code verifier with spaces", async () => { + const verifierWithSpaces = "test verifier with spaces" + "a".repeat(18); + const result = await oAuthCreateSHA256CodeChallenge({ + codeVerifier: verifierWithSpaces, + }); + + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.error).toBeDefined(); + expect((result.error as Error).message).toContain("unreserved characters"); + } + }); +}); diff --git a/src/funcs/custom/oAuthCreateSHA256CodeChallenge.ts b/src/funcs/custom/oAuthCreateSHA256CodeChallenge.ts new file mode 100644 index 00000000..cedaa6a4 --- /dev/null +++ b/src/funcs/custom/oAuthCreateSHA256CodeChallenge.ts @@ -0,0 +1,90 @@ +import z from "zod/v3"; +import { Result } from "../../types/fp.js"; + +const CreateSHA256CodeChallengeSchema = z.object({ + /** + * If not provided, a random code verifier will be generated. + * If provided, must be 43-128 characters and contain only unreserved + * characters [A-Za-z0-9-._~] per RFC 7636. + */ + codeVerifier: z + .string() + .min(43, "Code verifier must be at least 43 characters") + .max(128, "Code verifier must be at most 128 characters") + .regex( + /^[A-Za-z0-9\-._~]+$/, + "Code verifier must only contain unreserved characters: [A-Za-z0-9-._~]", + ) + .optional(), +}); + +type CreateSHA256CodeChallenge = z.infer< + typeof CreateSHA256CodeChallengeSchema +>; + +type CreateSHA256CodeChallengeResponse = { + codeChallenge: string; + codeVerifier: string; +}; + +/** + * Convert a Uint8Array to base64url encoding (RFC 4648) + */ +function arrayBufferToBase64Url(buffer: Uint8Array): string { + let binary = ""; + for (let i = 0; i < buffer.length; i++) { + binary += String.fromCharCode(buffer[i]!); + } + return btoa(binary) + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=+$/, ""); +} + +/** + * Generate a cryptographically random code verifier per RFC 7636 + */ +function generateCodeVerifier(): string { + // RFC 7636 recommends 32 octets of random data, base64url encoded = 43 chars + const randomBytes = crypto.getRandomValues(new Uint8Array(32)); + return arrayBufferToBase64Url(randomBytes); +} + +/** + * Generate a SHA-256 code challenge for PKCE + * + * @remarks + * Generates a SHA-256 code challenge and corresponding code verifier for use + * in the PKCE extension to OAuth2. If no code verifier is provided, a random + * one will be generated according to RFC 7636 (32 random bytes, base64url + * encoded). If a code verifier is provided, it must be 43-128 characters and + * contain only unreserved characters [A-Za-z0-9-._~]. + * + * @see {@link https://openrouter.ai/docs/use-cases/oauth-pkce} + * @see {@link https://datatracker.ietf.org/doc/html/rfc7636} + */ +export async function oAuthCreateSHA256CodeChallenge( + params: CreateSHA256CodeChallenge = {}, +): Promise> { + const parsedParams = CreateSHA256CodeChallengeSchema.safeParse(params); + if (!parsedParams.success) return { ok: false, error: parsedParams.error }; + + const { codeVerifier = generateCodeVerifier() } = parsedParams.data; + + // Generate SHA-256 hash + const encoder = new TextEncoder(); + const data = encoder.encode(codeVerifier); + const hash = await crypto.subtle.digest("SHA-256", data); + + // Convert hash to base64url + const hashArray = new Uint8Array(hash); + const codeChallenge = arrayBufferToBase64Url(hashArray); + + return { + ok: true, + value: { + codeChallenge, + codeVerifier, + }, + }; +} From 35c693f17439577c4983d78a83348f2eee79ef25 Mon Sep 17 00:00:00 2001 From: Walker Lockard Date: Wed, 8 Oct 2025 17:05:18 -0700 Subject: [PATCH 2/5] auth url builder --- .../oAuthCreateAuthorizationUrl.test.ts | 265 ++++++++++++++++++ .../custom/oAuthCreateAuthorizationUrl.ts | 69 +++++ 2 files changed, 334 insertions(+) create mode 100644 src/funcs/custom/oAuthCreateAuthorizationUrl.test.ts create mode 100644 src/funcs/custom/oAuthCreateAuthorizationUrl.ts diff --git a/src/funcs/custom/oAuthCreateAuthorizationUrl.test.ts b/src/funcs/custom/oAuthCreateAuthorizationUrl.test.ts new file mode 100644 index 00000000..0874d3da --- /dev/null +++ b/src/funcs/custom/oAuthCreateAuthorizationUrl.test.ts @@ -0,0 +1,265 @@ +import { describe, it, expect } from "vitest"; +import { OpenRouterCore } from "../../core.js"; +import { oAuthCreateAuthorizationUrl } from "./oAuthCreateAuthorizationUrl.js"; + +describe("oAuthCreateAuthorizationUrl", () => { + const createMockClient = (serverURL?: string) => { + return new OpenRouterCore({ serverURL }); + }; + + it("should generate authorization URL with callback URL", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback", + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("callback_url")).toBe( + "https://example.com/callback", + ); + } + }); + + it("should generate authorization URL with URL object as callback", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const callbackUrl = new URL("https://example.com/callback"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl, + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("callback_url")).toBe( + "https://example.com/callback", + ); + } + }); + + it("should include code challenge with S256 method", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback", + codeChallenge: "test-code-challenge-abc123", + codeChallengeMethod: "S256", + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("code_challenge")).toBe( + "test-code-challenge-abc123", + ); + expect(url.searchParams.get("code_challenge_method")).toBe("S256"); + } + }); + + it("should include code challenge with plain method", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback", + codeChallenge: "plain-code-challenge", + codeChallengeMethod: "plain", + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("code_challenge")).toBe( + "plain-code-challenge", + ); + expect(url.searchParams.get("code_challenge_method")).toBe("plain"); + } + }); + + it("should include limit parameter when provided", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback", + limit: 100, + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("limit")).toBe("100"); + } + }); + + it("should handle callback URL with query parameters", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback?state=abc123&redirect=true", + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("callback_url")).toBe( + "https://example.com/callback?state=abc123&redirect=true", + ); + } + }); + + it("should handle callback URL with special characters", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback?data=hello%20world", + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("callback_url")).toBe( + "https://example.com/callback?data=hello%20world", + ); + } + }); + + it("should return error for invalid callback URL string", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "not-a-valid-url" as any, + }); + + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.error).toBeDefined(); + } + }); + + it("should handle callback URL with localhost", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "http://localhost:3000/callback", + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("callback_url")).toBe( + "http://localhost:3000/callback", + ); + } + }); + + it("should use default production server when no serverURL provided", () => { + const client = createMockClient(); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback", + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.origin).toBe("https://openrouter.ai"); + expect(url.pathname).toBe("/auth"); + } + }); + + it("should use custom server URL when provided", () => { + const client = createMockClient("https://custom.example.com/api"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback", + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.origin).toBe("https://custom.example.com"); + expect(url.pathname).toBe("/auth"); + } + }); + + it("should preserve all parameters with PKCE", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback?state=xyz", + codeChallenge: "challenge123", + codeChallengeMethod: "S256", + limit: 50, + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("callback_url")).toBe( + "https://example.com/callback?state=xyz", + ); + expect(url.searchParams.get("code_challenge")).toBe("challenge123"); + expect(url.searchParams.get("code_challenge_method")).toBe("S256"); + expect(url.searchParams.get("limit")).toBe("50"); + } + }); + + it("should handle callback URL with fragment", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback#section", + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("callback_url")).toBe( + "https://example.com/callback#section", + ); + } + }); + + it("should return error for invalid input types", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: 12345 as any, + }); + + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.error).toBeDefined(); + } + }); + + it("should handle URL with port number in callback", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com:8443/callback", + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("callback_url")).toBe( + "https://example.com:8443/callback", + ); + } + }); + + it("should not omit limit parameter when value is 0", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback", + limit: 0, + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.get("limit")).toBe("0"); + } + }); + + it("should omit limit parameter when not provided", () => { + const client = createMockClient("https://openrouter.ai/api/v1"); + const result = oAuthCreateAuthorizationUrl(client, { + callbackUrl: "https://example.com/callback", + }); + + expect(result.ok).toBe(true); + if (result.ok) { + const url = new URL(result.value); + expect(url.searchParams.has("limit")).toBe(false); + } + }); +}); diff --git a/src/funcs/custom/oAuthCreateAuthorizationUrl.ts b/src/funcs/custom/oAuthCreateAuthorizationUrl.ts new file mode 100644 index 00000000..254342bd --- /dev/null +++ b/src/funcs/custom/oAuthCreateAuthorizationUrl.ts @@ -0,0 +1,69 @@ +import z from "zod/v3"; +import { OpenRouterCore } from "../../core.js"; +import { serverURLFromOptions } from "../../lib/config.js"; +import { Result } from "../../types/fp.js"; + +const CreateAuthorizationUrlBaseSchema = z.object({ + callbackUrl: z.union([z.string().url(), z.instanceof(URL)]), + limit: z.number().optional(), +}); + +const CreateAuthorizationurlParamsSchema = z.union([ + CreateAuthorizationUrlBaseSchema.extend({ + codeChallengeMethod: z.enum(["S256", "plain"]), + codeChallenge: z.string(), + }), + CreateAuthorizationUrlBaseSchema, +]); + +type CreateAuthorizationUrlParams = z.infer< + typeof CreateAuthorizationurlParamsSchema +>; + +/** + * Generate a OAuth2 authorization URL + * + * @remarks + * Generates a URL to redirect users to for authorizing your application. The + * URL includes the provided callback URL and, if applicable, the code + * challenge parameters for PKCE. + * + * @see {@link https://openrouter.ai/docs/use-cases/oauth-pkce} + */ +export function oAuthCreateAuthorizationUrl( + client: OpenRouterCore, + params: CreateAuthorizationUrlParams, +): Result { + const parsedParams = CreateAuthorizationurlParamsSchema.safeParse(params); + if (!parsedParams.success) return { ok: false, error: parsedParams.error }; + + const baseURL = serverURLFromOptions(client._options); + if (!baseURL) { + return { ok: false, error: new Error("No server URL configured") }; + } + + // Clone the URL to avoid mutating the original + const authURL = new URL("/auth", baseURL); + + authURL.searchParams.set( + "callback_url", + parsedParams.data.callbackUrl.toString(), + ); + + if ("codeChallengeMethod" in parsedParams.data) { + authURL.searchParams.set( + "code_challenge", + parsedParams.data.codeChallenge, + ); + authURL.searchParams.set( + "code_challenge_method", + parsedParams.data.codeChallengeMethod, + ); + } + + if (parsedParams.data.limit !== undefined) { + authURL.searchParams.set("limit", parsedParams.data.limit.toString()); + } + + return { ok: true, value: authURL.toString() }; +} From cc9851b28a0a3f690c1f377760ac44421ee97ab6 Mon Sep 17 00:00:00 2001 From: Walker Lockard Date: Wed, 8 Oct 2025 17:05:57 -0700 Subject: [PATCH 3/5] formatting ftw --- src/funcs/custom/oAuthCreateAuthorizationUrl.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/funcs/custom/oAuthCreateAuthorizationUrl.ts b/src/funcs/custom/oAuthCreateAuthorizationUrl.ts index 254342bd..9195e1d9 100644 --- a/src/funcs/custom/oAuthCreateAuthorizationUrl.ts +++ b/src/funcs/custom/oAuthCreateAuthorizationUrl.ts @@ -51,10 +51,7 @@ export function oAuthCreateAuthorizationUrl( ); if ("codeChallengeMethod" in parsedParams.data) { - authURL.searchParams.set( - "code_challenge", - parsedParams.data.codeChallenge, - ); + authURL.searchParams.set("code_challenge", parsedParams.data.codeChallenge); authURL.searchParams.set( "code_challenge_method", parsedParams.data.codeChallengeMethod, From c90a5d78a9826dd99092d69c92fadb219c65420e Mon Sep 17 00:00:00 2001 From: Walker Lockard Date: Wed, 8 Oct 2025 17:24:06 -0700 Subject: [PATCH 4/5] adding custom funcs to sdk body --- .../custom/oAuthCreateAuthorizationUrl.ts | 4 +- .../custom/oAuthCreateSHA256CodeChallenge.ts | 12 +-- src/sdk/oauth.ts | 73 ++++++++++++++++--- 3 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/funcs/custom/oAuthCreateAuthorizationUrl.ts b/src/funcs/custom/oAuthCreateAuthorizationUrl.ts index 9195e1d9..add4da57 100644 --- a/src/funcs/custom/oAuthCreateAuthorizationUrl.ts +++ b/src/funcs/custom/oAuthCreateAuthorizationUrl.ts @@ -16,7 +16,7 @@ const CreateAuthorizationurlParamsSchema = z.union([ CreateAuthorizationUrlBaseSchema, ]); -type CreateAuthorizationUrlParams = z.infer< +export type CreateAuthorizationUrlRequest = z.infer< typeof CreateAuthorizationurlParamsSchema >; @@ -32,7 +32,7 @@ type CreateAuthorizationUrlParams = z.infer< */ export function oAuthCreateAuthorizationUrl( client: OpenRouterCore, - params: CreateAuthorizationUrlParams, + params: CreateAuthorizationUrlRequest, ): Result { const parsedParams = CreateAuthorizationurlParamsSchema.safeParse(params); if (!parsedParams.success) return { ok: false, error: parsedParams.error }; diff --git a/src/funcs/custom/oAuthCreateSHA256CodeChallenge.ts b/src/funcs/custom/oAuthCreateSHA256CodeChallenge.ts index cedaa6a4..7939e147 100644 --- a/src/funcs/custom/oAuthCreateSHA256CodeChallenge.ts +++ b/src/funcs/custom/oAuthCreateSHA256CodeChallenge.ts @@ -1,7 +1,7 @@ import z from "zod/v3"; import { Result } from "../../types/fp.js"; -const CreateSHA256CodeChallengeSchema = z.object({ +const CreateSHA256CodeChallengeRequestSchema = z.object({ /** * If not provided, a random code verifier will be generated. * If provided, must be 43-128 characters and contain only unreserved @@ -18,11 +18,11 @@ const CreateSHA256CodeChallengeSchema = z.object({ .optional(), }); -type CreateSHA256CodeChallenge = z.infer< - typeof CreateSHA256CodeChallengeSchema +export type CreateSHA256CodeChallengeRequest = z.infer< + typeof CreateSHA256CodeChallengeRequestSchema >; -type CreateSHA256CodeChallengeResponse = { +export type CreateSHA256CodeChallengeResponse = { codeChallenge: string; codeVerifier: string; }; @@ -64,9 +64,9 @@ function generateCodeVerifier(): string { * @see {@link https://datatracker.ietf.org/doc/html/rfc7636} */ export async function oAuthCreateSHA256CodeChallenge( - params: CreateSHA256CodeChallenge = {}, + params: CreateSHA256CodeChallengeRequest = {}, ): Promise> { - const parsedParams = CreateSHA256CodeChallengeSchema.safeParse(params); + const parsedParams = CreateSHA256CodeChallengeRequestSchema.safeParse(params); if (!parsedParams.success) return { ok: false, error: parsedParams.error }; const { codeVerifier = generateCodeVerifier() } = parsedParams.data; diff --git a/src/sdk/oauth.ts b/src/sdk/oauth.ts index 3e5bab72..c3ab6a3e 100644 --- a/src/sdk/oauth.ts +++ b/src/sdk/oauth.ts @@ -8,6 +8,18 @@ import { ClientSDK, RequestOptions } from "../lib/sdks.js"; import * as operations from "../models/operations/index.js"; import { unwrapAsync } from "../types/fp.js"; +// #region imports +import { + oAuthCreateAuthorizationUrl, + CreateAuthorizationUrlRequest, +} from "../funcs/custom/oAuthCreateAuthorizationUrl.js"; +import { + CreateSHA256CodeChallengeRequest, + CreateSHA256CodeChallengeResponse, + oAuthCreateSHA256CodeChallenge, +} from "../funcs/custom/oAuthCreateSHA256CodeChallenge.js"; +// #endregion imports + export class OAuth extends ClientSDK { /** * Exchange authorization code for API key @@ -19,11 +31,7 @@ export class OAuth extends ClientSDK { request: operations.ExchangeAuthorizationCodeRequest, options?: RequestOptions, ): Promise { - return unwrapAsync(oAuthExchangeAuthorizationCode( - this, - request, - options, - )); + return unwrapAsync(oAuthExchangeAuthorizationCode(this, request, options)); } /** @@ -36,10 +44,55 @@ export class OAuth extends ClientSDK { request: operations.CreateAuthorizationCodeRequest, options?: RequestOptions, ): Promise { - return unwrapAsync(oAuthCreateAuthorizationCode( - this, - request, - options, - )); + return unwrapAsync(oAuthCreateAuthorizationCode(this, request, options)); + } + + // #region sdk-class-body + /** + * Generate a OAuth2 authorization URL + * + * @remarks + * Generates a URL to redirect users to for authorizing your application. The + * URL includes the provided callback URL and, if applicable, the code + * challenge parameters for PKCE. + * + * @see {@link https://openrouter.ai/docs/use-cases/oauth-pkce} + */ + async createAuthorizationUrl( + request: CreateAuthorizationUrlRequest, + ): Promise { + const result = oAuthCreateAuthorizationUrl(this, request); + + if (!result.ok) { + throw result.error; + } + + return result.value; + } + + /** + * Generate a SHA-256 code challenge for PKCE + * + * @remarks + * Generates a SHA-256 code challenge and corresponding code verifier for use + * in the PKCE extension to OAuth2. If no code verifier is provided, a random + * one will be generated according to RFC 7636 (32 random bytes, base64url + * encoded). If a code verifier is provided, it must be 43-128 characters and + * contain only unreserved characters [A-Za-z0-9-._~]. + * + * @see {@link https://openrouter.ai/docs/use-cases/oauth-pkce} + * @see {@link https://datatracker.ietf.org/doc/html/rfc7636} + */ + async createSHA256CodeChallenge( + request: CreateSHA256CodeChallengeRequest = {}, + ): Promise { + const result = await oAuthCreateSHA256CodeChallenge(request); + + if (!result.ok) { + throw result.error; + } + + return result.value; } + // #endregion sdk-class-body } From 3cc1ca943d52f93996301d607a925bf59a794aa8 Mon Sep 17 00:00:00 2001 From: Walker Lockard Date: Wed, 8 Oct 2025 17:25:38 -0700 Subject: [PATCH 5/5] regen --- src/sdk/oauth.ts | 63 +++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/src/sdk/oauth.ts b/src/sdk/oauth.ts index c3ab6a3e..a57c74ab 100644 --- a/src/sdk/oauth.ts +++ b/src/sdk/oauth.ts @@ -7,11 +7,10 @@ import { oAuthExchangeAuthorizationCode } from "../funcs/oAuthExchangeAuthorizat import { ClientSDK, RequestOptions } from "../lib/sdks.js"; import * as operations from "../models/operations/index.js"; import { unwrapAsync } from "../types/fp.js"; - // #region imports import { - oAuthCreateAuthorizationUrl, CreateAuthorizationUrlRequest, + oAuthCreateAuthorizationUrl, } from "../funcs/custom/oAuthCreateAuthorizationUrl.js"; import { CreateSHA256CodeChallengeRequest, @@ -21,32 +20,6 @@ import { // #endregion imports export class OAuth extends ClientSDK { - /** - * Exchange authorization code for API key - * - * @remarks - * Exchange an authorization code from the PKCE flow for a user-controlled API key - */ - async exchangeAuthorizationCode( - request: operations.ExchangeAuthorizationCodeRequest, - options?: RequestOptions, - ): Promise { - return unwrapAsync(oAuthExchangeAuthorizationCode(this, request, options)); - } - - /** - * Create authorization code - * - * @remarks - * Create an authorization code for the PKCE flow to generate a user-controlled API key - */ - async createAuthorizationCode( - request: operations.CreateAuthorizationCodeRequest, - options?: RequestOptions, - ): Promise { - return unwrapAsync(oAuthCreateAuthorizationCode(this, request, options)); - } - // #region sdk-class-body /** * Generate a OAuth2 authorization URL @@ -95,4 +68,38 @@ export class OAuth extends ClientSDK { return result.value; } // #endregion sdk-class-body + + /** + * Exchange authorization code for API key + * + * @remarks + * Exchange an authorization code from the PKCE flow for a user-controlled API key + */ + async exchangeAuthorizationCode( + request: operations.ExchangeAuthorizationCodeRequest, + options?: RequestOptions, + ): Promise { + return unwrapAsync(oAuthExchangeAuthorizationCode( + this, + request, + options, + )); + } + + /** + * Create authorization code + * + * @remarks + * Create an authorization code for the PKCE flow to generate a user-controlled API key + */ + async createAuthorizationCode( + request: operations.CreateAuthorizationCodeRequest, + options?: RequestOptions, + ): Promise { + return unwrapAsync(oAuthCreateAuthorizationCode( + this, + request, + options, + )); + } }