diff --git a/CHANGELOG.md b/CHANGELOG.md index e1fa79ee..0a387a03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## Unreleased + +- feat: migrate the Convex plugin from Better Auth's deprecated + `oidc-provider` integration to `@better-auth/oauth-provider`. +- feat: add Convex-friendly MCP helper exports: + `withMcpAuth`, `oAuthDiscoveryMetadata`, and + `oAuthProtectedResourceMetadata`. +- feat: expose OAuth/OIDC discovery routes and `WWW-Authenticate` CORS headers + for MCP/OAuth clients. +- chore: pin `better-auth` and `@better-auth/oauth-provider` to `1.6.11`. + +Migration notes: + +- Regenerate local Better Auth schemas after upgrading. +- Existing `oauthApplication` / legacy `oidcApplication` rows must be migrated + to the new `oauthClient` table shape. Existing OAuth access and refresh + tokens should be invalidated and clients should reauthorize. +- Configure first-party clients that need seamless authorization with + `skip_consent: true`; configure clients that need RP-initiated logout with + `enable_end_session: true` and `post_logout_redirect_uris`. +- Set a stable Convex environment variable for `pairwiseSecret` before enabling + pairwise subject identifiers. Rotating this secret changes pairwise `sub` + values. + ## 0.12.2 - fix: strip hop-by-hop headers in framework proxy handlers (#360) @CipherSight diff --git a/MIGRATION_PLAN.md b/MIGRATION_PLAN.md new file mode 100644 index 00000000..15d0ab94 --- /dev/null +++ b/MIGRATION_PLAN.md @@ -0,0 +1,826 @@ +# Migration plan: replace `oidc-provider` with `@better-auth/oauth-provider` + +This document is the planning pass only. No implementation files should be +changed until this plan is reviewed. + +## 1. Surface inventory + +### Runtime imports and plugin composition + +- `src/plugins/convex/index.ts` + - Imports `oidcProvider` from `better-auth/plugins/oidc-provider`. + - Instantiates it inside `convex()` with: + - `loginPage: "/not-used"` + - `metadata.issuer: process.env.CONVEX_SITE_URL` + - `metadata.jwks_uri: ${CONVEX_SITE_URL}${basePath}/convex/jwks` + - `__skipDeprecationWarning: true` + - Normalizes and spreads `oidcProvider.hooks.after` into the Convex plugin + after-hooks. + - Proxies `oidcProvider.endpoints.getOpenIdConfig` through + `/convex/.well-known/openid-configuration`. + - Comments still describe `options.basePath` as "used to pass the basePath to + the oidcProvider plugin." + - Existing Convex-specific JWT handling is implemented here with an internal + `jwtPlugin()` instance, the `convex_jwt` cookie, `/convex/token`, + `/convex/jwks`, `/convex/latest-jwks`, and `/convex/rotate-keys`. + +- `src/auth-options.ts` + - Used to generate the component schema. + - Imports `oidcProvider` from `better-auth/plugins/oidc-provider`. + - Includes `oidcProvider({ loginPage: "/login", __skipDeprecationWarning: true })` + in the generated schema auth options. + - Also includes `jwt()` and `convex()` in the same generated schema auth + options. + +- `package.json` + - Does not depend on `@better-auth/oauth-provider`. + - Current Better Auth peer range is `>=1.6.9 <1.7.0`; current dev pin is + `better-auth@1.6.9`. + - Implementation should add exact pins for both `better-auth` and + `@better-auth/oauth-provider`. Latest observed during planning: + `better-auth@1.6.11` and `@better-auth/oauth-provider@1.6.11`. + +### Schema surfaces + +- `src/component/schema.ts` + - Currently contains the old/deprecated OIDC-provider schema: + - `oauthApplication` + - `name`, `icon`, `metadata`, `clientId`, `clientSecret`, + `redirectUrls`, `type`, `disabled`, `userId`, `createdAt`, `updatedAt` + - indexes: `clientId`, `userId` + - `oauthAccessToken` + - `accessToken`, `refreshToken`, `accessTokenExpiresAt`, + `refreshTokenExpiresAt`, `clientId`, `userId`, `scopes`, `createdAt`, + `updatedAt` + - indexes: `accessToken`, `refreshToken`, `clientId`, `userId` + - `oauthConsent` + - `clientId`, `userId`, `scopes`, `createdAt`, `updatedAt`, + `consentGiven` + - indexes: `clientId_userId`, `userId` + - `jwks` + - This file is generated from `src/auth-options.ts`, so the implementation + should regenerate it after replacing the schema plugin. + +- Generated component types: + - `src/component/_generated/component.ts` + - `src/component/_generated/dataModel.ts` + - These currently include `oauthApplication`, `oauthAccessToken`, + `oauthConsent`, and `jwks`. + +- Local-install example schemas: + - `examples/next/convex/betterAuth/generatedSchema.ts` + - Currently does not include OIDC/OAuth provider tables; it includes base + auth tables and `jwks`. + - `examples/next/convex/betterAuth/schema.ts` + - Wraps the generated schema and adds a custom `user` index. + - `examples/tanstack/convex/betterAuth/schema.ts` + - Currently includes base auth tables and `jwks`. + +- Schema generation helper: + - `src/client/create-schema.ts` + - Manually adds indexes for known schema models. + - Currently adds `oauthConsent: [["clientId", "userId"]]`. + - Needs to add indexes for the oauth-provider models and avoid producing + duplicate/ambiguous index names. + +### HTTP route and discovery surfaces + +- `src/client/create-client.ts` + - `registerRoutes()` and `registerRoutesLazy()` register GET/POST + `pathPrefix: ${basePath}/` and optional CORS handling. + - Both add a root `/.well-known/openid-configuration` redirect to + `${CONVEX_SITE_URL}${basePath}/convex/.well-known/openid-configuration`. + - CORS currently exposes only `Set-Better-Auth-Cookie` plus user-provided + exposed headers. + - CORS must expose `WWW-Authenticate` for MCP clients and other OAuth + clients to read challenge metadata. + +- Current public root discovery: + - `/.well-known/openid-configuration` exists as a redirect. + - There is no root `/.well-known/oauth-authorization-server`. + - There is no root `/.well-known/oauth-protected-resource`. + +- Current prefixed discovery: + - `/api/auth/convex/.well-known/openid-configuration` is a Convex wrapper over + the deprecated OIDC provider metadata. + - `/api/auth/convex/jwks` is the Convex-compatible JWKS endpoint. + +### Public API and exports + +- `src/plugins/index.ts` + - Exports only: + - `convex` + - `crossDomain` + - Needs to export new MCP/OAuth helper functions: + - `withMcpAuth` + - `oAuthDiscoveryMetadata` + - `oAuthProtectedResourceMetadata` + +- `src/client/index.ts` + - Exports `createClient`, `createApi`, and related types. + - The route registration API should remain compatible, but its internal + well-known and CORS behavior needs to expand. + +- `src/utils/index.ts` + - JWT cache helpers assume Convex identity JWTs and static JWKS. + - No OIDC import, but JWT/JWKS behavior must not regress. + +### Cross-domain login surfaces + +- `src/plugins/cross-domain/index.ts` + - Rewrites callback URLs for Better Auth sign-in flows. + - Preserves OAuth state in database mode and skips state cookie checks. + - Adds a one-time-token continuation flow after `/callback`, + `/oauth2/callback`, and `/magic-link/verify`. + - Needs to keep working when `oauth-provider` redirects to the SvelteKit app + `loginPage` with a signed `oauth_query`. + +- `src/plugins/cross-domain/index.test.ts` + - Covers callback URL defaulting for `/sign-in/oauth2`. + - Needs additional coverage for `oauth_query` continuation and the + `/oauth2/continue` path. + +### Docs and examples + +- `docs/content/docs/framework-guides/sveltekit.mdx` + - Current SvelteKit guide demonstrates Convex + Better Auth, but not OIDC + provider configuration or the `/sign-in` continuation for `oauth_query`. + - This guide is a required deliverable for the implementation pass. + +- Other framework guides reference `convex({ authConfig })` and should not need + broad rewrites unless the `convex()` options shape changes: + - `docs/content/docs/framework-guides/react.mdx` + - `docs/content/docs/framework-guides/expo.mdx` + - `docs/content/docs/framework-guides/tanstack-start.mdx` + - `docs/content/docs/framework-guides/next.mdx` + +- Existing migration docs: + - `docs/content/docs/migrations/migrate-to-0-11.mdx` + - Mentions the `oauthApplication.redirectURLs` to `redirectUrls` rename. + - `docs/content/docs/migrations/migrate-to-0-10.mdx` + - Documents static JWKS and `jwksRotateOnTokenGenerationError`. + - `docs/content/docs/migrations/migrate-to-0-8.mdx` + - Mentions OIDC discovery redirect behavior. + +- `README.md` + - Minimal package overview; needs pinned version note and OAuth provider + mention. + +- `CHANGELOG.md` + - Needs a migration entry and any unavoidable breaking changes. + +### Tests + +- Existing relevant tests: + - `src/plugins/convex/index.test.ts` + - `src/plugins/cross-domain/index.test.ts` + - `src/plugins/cross-domain/client.test.ts` + - `src/client/create-client.test.ts` + - `src/test/adapter-factory/*` + - `e2e/tests/*` + +- Missing tests to add during implementation: + - OAuth-provider schema adapter round-trips for every new table. + - Auth-code-with-PKCE end-to-end. + - Dynamic Client Registration. + - MCP discovery/auth/tool-call chain. + - RP-initiated logout. + +## 2. Bundling investigation + +### Fixture + +I created a throwaway fixture outside the repository at: + +```text +/tmp/convex-oauth-provider-fixture +``` + +Dependencies installed in the fixture: + +```text +convex@1.39.1 +better-auth@1.6.11 +@better-auth/oauth-provider@1.6.11 +``` + +Minimal `convex/auth.ts` used for the bundling check: + +```ts +import { betterAuth } from "better-auth"; +import { jwt } from "better-auth/plugins/jwt"; +import { oauthProvider } from "@better-auth/oauth-provider"; + +export const auth = betterAuth({ + baseURL: process.env.CONVEX_SITE_URL, + plugins: [ + jwt(), + oauthProvider({ + loginPage: "/sign-in", + allowUnauthenticatedClientRegistration: true, + }), + ], +}); +``` + +Minimal `convex/http.ts` routed GET/POST `/api/auth/*` to `auth.handler()`. + +Command run: + +```bash +npx convex dev --once --typecheck disable +``` + +Observed output: + +```text +Setting up a new project... +Configured a local deployment for http://127.0.0.1:3210 ... +- Preparing Convex functions... +Convex functions ready! (744.36ms) +``` + +### Node built-in / native module results + +No Convex bundler rejection occurred. No rejected built-ins or native modules +were listed. + +Additional static scan of `@better-auth/oauth-provider@1.6.11` found no direct +imports of the Node built-ins that caused better-auth issue #5314 (`constants`, +`fs`, `path`, `crypto`, `os`, `stream`, `http`, `https`, `buffer`, `util`, +`events`, `url`). + +### Strategy + +- Current strategy: use the published package directly; no shim, vendoring, or + `"use node"` split is planned for `@better-auth/oauth-provider@1.6.11`. +- Contingency during implementation: + - If full component integration reveals an indirect bundling failure that the + minimal fixture did not hit, keep the workaround inside this component. + - Prefer a small local shim only for the failing import if it is pure + compatibility surface. + - Use `"use node"` actions only for paths that cannot execute in Convex HTTP + routes and can safely be proxied without changing OAuth semantics. + - Vendoring is the last resort because it increases maintenance cost and must + track Better Auth security fixes. + +## 3. Schema diff and migration path + +### Deprecated OIDC-provider schema currently shipped by the component + +From `better-auth/plugins/oidc-provider` and `src/component/schema.ts`: + +- `oauthApplication` + - `clientId`, `clientSecret`, `type`, `name`, `icon`, `metadata`, + `disabled`, `redirectUrls`, `userId`, `createdAt`, `updatedAt` +- `oauthAccessToken` + - `accessToken`, `refreshToken`, `accessTokenExpiresAt`, + `refreshTokenExpiresAt`, `clientId`, `userId`, `scopes`, `createdAt`, + `updatedAt` +- `oauthConsent` + - `clientId`, `userId`, `scopes`, `createdAt`, `updatedAt`, `consentGiven` + +Some fork users may have even older table names such as `oidcApplication`, +`oidcAccessToken`, and `oidcConsent`; the implementation should document those +as legacy input tables even if the current package already uses `oauth*`. + +### New oauth-provider schema + +From `@better-auth/oauth-provider@1.6.11`: + +- `oauthClient` + - `clientId` required unique + - `clientSecret` optional + - `disabled` optional, default false + - `skipConsent` optional + - `enableEndSession` optional + - `subjectType` optional (`"public"` or `"pairwise"`) + - `scopes` optional `string[]` + - `userId` optional + - `createdAt`, `updatedAt` optional dates + - DCR metadata fields: + - `name`, `uri`, `icon`, `contacts`, `tos`, `policy`, `softwareId`, + `softwareVersion`, `softwareStatement` + - redirect/logout fields: + - `redirectUris` required `string[]` + - `postLogoutRedirectUris` optional `string[]` + - OAuth client behavior fields: + - `tokenEndpointAuthMethod`, `grantTypes`, `responseTypes`, `public`, + `type`, `requirePKCE`, `referenceId`, `metadata` + +- `oauthRefreshToken` + - `token` required unique + - `clientId` required + - `sessionId` optional + - `userId` required + - `referenceId` optional + - `expiresAt`, `createdAt` + - `revoked` optional + - `authTime` optional + - `scopes` required `string[]` + +- `oauthAccessToken` + - Reuses the old table name but with incompatible fields: + - `token` unique instead of `accessToken` + - `clientId` required + - `sessionId` optional + - `userId` optional + - `referenceId` optional + - `refreshId` optional + - `expiresAt`, `createdAt` + - `scopes` required `string[]` instead of a space-delimited string + +- `oauthConsent` + - Reuses the old table name but with changed fields: + - `clientId` required + - `userId` optional + - `referenceId` optional + - `scopes` required `string[]` + - `createdAt`, `updatedAt` + - no `consentGiven` + +### Convex schema generation changes + +- Replace the OIDC provider in `src/auth-options.ts` with + `oauthProvider(...)` and regenerate `src/component/schema.ts`. +- Update `src/client/create-schema.ts` manual indexes: + - Add `oauthClient` indexes for at least `clientId`, `userId`, and any + generated unique/reference fields not already handled by `specialFields`. + - Add `oauthRefreshToken` indexes for `token`, `clientId`, `sessionId`, + `userId`. + - Update `oauthAccessToken` indexes to `token`, `clientId`, `sessionId`, + `userId`, `refreshId`. + - Keep `oauthConsent` composite lookup as `clientId_userId`; include + `referenceId` if implementation discovers oauth-provider queries require + `clientId + userId + referenceId`. +- Ensure `string[]` fields generate as `v.array(v.string())`, which + `create-schema.ts` already supports. + +### Data migration path + +Because `oauthAccessToken` and `oauthConsent` reuse table names with different +field shapes, this should be a two-stage migration for deployed users: + +1. **Pre-upgrade backup and token invalidation** + - Document that old OIDC access/refresh tokens cannot be safely reused + because oauth-provider stores and hashes tokens differently and separates + refresh tokens into `oauthRefreshToken`. + - Users should expect existing OAuth clients to reauthorize after the + upgrade. + - Existing Better Auth user/session/account data and Convex identity JWT + behavior should remain intact. + +2. **Client migration** + - Migrate `oauthApplication` or legacy `oidcApplication` rows into + `oauthClient`: + - `clientId` -> `clientId` + - `clientSecret` -> `clientSecret` + - If old secrets were stored plaintext and new config uses hashed + secrets, require either secret rotation or a one-time admin re-create + because hashing cannot recover the original if already hashed. + - `name`, `icon`, `metadata`, `disabled`, `userId`, `createdAt`, + `updatedAt` -> same semantic fields. + - `redirectUrls` comma/string value -> `redirectUris: string[]`. + - `type`: + - old `"web"` -> new `type: "web"`, + `tokenEndpointAuthMethod: "client_secret_basic"` or default + - old `"native"` / `"public"` / `"user-agent-based"` -> + `tokenEndpointAuthMethod: "none"`, `public: true` + - first-party clients should be recreated/admin-updated with: + - `skipConsent: true` + - `enableEndSession: true` where RP-initiated logout is required + - `subjectType: "public"` unless explicitly configured for pairwise + - `postLogoutRedirectUris` must be populated for Capacitor and web logout + callbacks. + +3. **Consent migration** + - Migrate `oauthConsent` or legacy `oidcConsent` rows where + `consentGiven === true`. + - Convert `scopes` from space-delimited strings to `string[]`. + - Drop denied/false consent rows. + - If `referenceId` is not available, leave undefined. + +4. **Token cleanup** + - Delete old `oauthAccessToken` / `oidcAccessToken` rows after clients are + migrated. + - New `oauthAccessToken` and `oauthRefreshToken` rows will be created by + oauth-provider during fresh authorization. + +5. **Migration tooling** + - Add documented Convex migration helpers rather than automatic destructive + migration in request paths. + - For component installs, expose internal/admin functions or a documented + one-off script that users can copy into their app. + - For local installs, document `npx auth generate` plus a Convex migration + component recipe. + +## 4. JWT/JWKS plan + +### Current behavior to preserve + +- `convex()` issues Convex-compatible identity JWTs using Better Auth's JWT + plugin internals. +- The Convex identity JWT: + - issuer: `CONVEX_SITE_URL` + - audience: `"convex"` + - default payload: user fields except `id` and `image`, plus `sessionId` and + `iat` + - supports `jwt.definePayload` + - is stored in `better-auth.convex_jwt` +- Static JWKS optimization: + - `convex({ jwks: process.env.JWKS })` reads static JWKS instead of querying + the database on every `/convex/jwks` or token operation. + - `getAuthConfigProvider({ jwks })` points Convex to a data URI JWKS so + Convex WebSocket auth validation stays fast. + +### Required oauth-provider coordination + +`@better-auth/oauth-provider` expects the real Better Auth `jwt` plugin to be +registered unless `disableJwtPlugin: true`. Disabling the JWT plugin would fall +back to HS256 ID tokens for some clients and would violate the requirement that +RPs and Convex see the same JWKS-backed signing keys. Therefore the +implementation should keep `disableJwtPlugin: false`. + +Planned approach: + +1. Create exactly one shared JWT plugin configuration from the existing + `convex()` JWT/JWKS options. +2. Make that same JWT plugin visible to oauth-provider and use it for: + - Convex identity JWT cookie/token generation. + - OAuth/OIDC ID tokens. + - JWT access tokens when `resource`/audience is requested. + - `/jwks` and `/convex/jwks` public key output. +3. Keep `/convex/jwks` as the Convex-compatible JWKS URL and add/ensure the + standard `/jwks` endpoint from the shared JWT plugin is reachable for + oauth-provider metadata. +4. Configure oauth-provider metadata so: + - `issuer` is the Convex site origin (`CONVEX_SITE_URL`), not the SvelteKit + app origin. + - `jwks_uri` points to the shared JWKS endpoint. + - root and prefixed well-known routes return consistent metadata. +5. Audit `convex().jwt.definePayload`: + - Keep it scoped to Convex identity JWTs only. + - Use oauth-provider's `customIdTokenClaims`, `customUserInfoClaims`, and + `customAccessTokenClaims` for OAuth/OIDC tokens. + - Do not leak Convex-only `sessionId`, application-specific user fields, or + non-OIDC claims into ID tokens unless explicitly configured. + +Implementation risk to resolve in code: + +- The current `convex()` plugin internally instantiates `jwtPlugin()` but does + not register a plugin with id `"jwt"` in the user's Better Auth plugin list. + oauth-provider calls `ctx.getPlugin("jwt")`. +- The first implementation step should spike the least-breaking way to satisfy + this: + - Preferred: make `convex()` expose the shared JWT plugin to Better Auth's + plugin registry while preserving the existing `convex()` public export and + Convex endpoints. + - Acceptable if Better Auth registry constraints prevent that: document a new + helper/configuration that inserts `jwt(sharedOptions)` once and make + `convex()` reuse that instance. This would be a breaking or semi-breaking + configuration change and must be called out in `CHANGELOG.md`. + +## 5. OAuth-provider integration plan + +### Component options + +Extend `convex()` options conservatively: + +```ts +convex({ + authConfig, + jwks, + jwt, + oauthProvider: { + enabled: true, + loginPage, + consentPage, + allowDynamicClientRegistration, + allowUnauthenticatedClientRegistration, + allowPublicClientPrelogin, + scopes, + validAudiences, + cachedTrustedClients, + pairwiseSecret, + ...safePassThroughOptions + }, +}); +``` + +Notes: + +- `allowUnauthenticatedClientRegistration` should be configurable, but only + effective when `allowDynamicClientRegistration` is also true. +- `pairwiseSecret` should come from Convex env (`process.env.PAIRWISE_SECRET` + or documented user-chosen name). The plugin should validate the minimum + length before deployment fails at runtime. +- `loginPage` should support an absolute SvelteKit URL, not only a path, so + `.convex.site/oauth2/authorize` can redirect to + `https://app.example.com/sign-in?...`. +- First-party SvelteKit and Capacitor clients should be created/admin-updated + with `skipConsent: true`; Capacitor should also get `enableEndSession: true` + and `postLogoutRedirectUris`. + +### Endpoint behavior + +Replace OIDC provider endpoint/hook usage in `src/plugins/convex/index.ts`: + +- Remove `better-auth/plugins/oidc-provider` import. +- Add `@better-auth/oauth-provider`. +- Use oauth-provider hooks: + - Its before-hook verifies and stores `oauth_query` continuation state. + - Its after-hook continues authorization after login. + - Preserve Convex JWT cookie set/clear hooks. +- Use oauth-provider endpoints: + - `/oauth2/authorize` + - `/oauth2/token` + - `/oauth2/consent` + - `/oauth2/continue` + - `/oauth2/register` + - `/oauth2/userinfo` + - `/oauth2/end-session` + - `/oauth2/introspect` + - `/oauth2/revoke` + - client/consent management endpoints + - `/.well-known/oauth-authorization-server` + - `/.well-known/openid-configuration` +- Keep existing Convex-specific endpoints: + - `/convex/token` + - `/convex/jwks` + - `/convex/latest-jwks` + - `/convex/rotate-keys` + +### Well-known routes + +Add root and prefixed discovery support: + +- OpenID Connect: + - `/.well-known/openid-configuration` + - `${basePath}/.well-known/openid-configuration` + - Existing `${basePath}/convex/.well-known/openid-configuration` should + remain as a compatibility alias if possible. + +- OAuth Authorization Server (RFC 8414): + - `/.well-known/oauth-authorization-server` + - `/.well-known/oauth-authorization-server/api/auth` for issuer-path style + insertion when issuer/basePath requires it. + - `${basePath}/.well-known/oauth-authorization-server` + +- OAuth Protected Resource (RFC 9728): + - `/.well-known/oauth-protected-resource` + - `/.well-known/oauth-protected-resource/` where applicable. + - `${basePath}/.well-known/oauth-protected-resource` + +- CORS: + - Add `WWW-Authenticate` to default exposed headers whenever CORS is enabled. + - For metadata routes, allow GET from `*` or from configured trusted origins + depending on current route helper conventions. + +## 6. MCP surface plan + +Upstream status during planning: + +- `better-auth/plugins/mcp` still documents itself as based on the deprecated + OIDC Provider plugin and "soon deprecated in favor of the OAuth Provider + Plugin." +- It exports `withMcpAuth`, `oAuthDiscoveryMetadata`, and + `oAuthProtectedResourceMetadata`, but those helpers depend on `mcp()` / + `auth.api.getMcpSession`, not the new oauth-provider session/token model. +- `@better-auth/oauth-provider` exports `mcpHandler()` and a + `oauthProviderResourceClient()`, but not same-named helper exports. + +Therefore this component should implement Convex-adapted helpers now rather +than depend on the legacy MCP plugin. + +### Proposed exports + +Add a new module, likely `src/plugins/mcp/index.ts`, re-exported from +`src/plugins/index.ts`: + +- `withMcpAuth(authOrOptions, handler, opts?)` + - Accepts a Web-standard `Request` and returns `Response`, matching Convex + HTTP action ergonomics. + - Extracts bearer token. + - Verifies JWT access tokens using `better-auth/oauth2.verifyAccessToken` or + `oauthProviderResourceClient(auth).verifyAccessToken`. + - Supports required scopes and expected `audience`/resource. + - On unauthenticated/invalid token: + - returns 401 + - sets `WWW-Authenticate: + Bearer resource_metadata="/.well-known/oauth-protected-resource"` + - sets `Access-Control-Expose-Headers: WWW-Authenticate` + - Passes a typed session/payload object to the handler containing at least + `userId`/`sub`, `clientId`/`azp`, `scope`, and raw JWT payload. + +- `oAuthDiscoveryMetadata(auth, opts?)` + - Returns a Convex-compatible handler that emits RFC 8414 metadata from the + oauth-provider configuration. + - Should use `oauthProviderAuthServerMetadata(auth)` if it works with Convex + request/response paths; otherwise use `auth.api.getOAuthServerConfig` and + wrap in a Response. + +- `oAuthProtectedResourceMetadata(authOrOptions, opts?)` + - Returns RFC 9728 protected resource metadata. + - Prefer `oauthProviderResourceClient(auth).getProtectedResourceMetadata()`. + - Allow overriding `resource`, `authorization_servers`, `scopes_supported`, + and bearer methods. + +### Convex HTTP usage shape + +Example target API: + +```ts +http.route({ + path: "/mcp", + method: "POST", + handler: httpAction(async (ctx, req) => { + return withMcpAuth( + { + issuer: process.env.CONVEX_SITE_URL!, + jwksUrl: `${process.env.CONVEX_SITE_URL}/api/auth/convex/jwks`, + audience: `${process.env.CONVEX_SITE_URL}/mcp`, + scopes: ["openid"], + }, + async (req, session) => { + // call MCP server transport + } + )(req); + }), +}); +``` + +The docs should also show root discovery routes for MCP clients that ignore the +prefixed Better Auth metadata route. + +## 7. Cross-domain login redirect plan + +The oauth-provider login flow redirects unauthenticated `/oauth2/authorize` +requests to `loginPage` with a signed `oauth_query`. To keep Convex as the +issuer while the UI lives on SvelteKit: + +1. Allow `oauthProvider.loginPage` to be an absolute URL on the SvelteKit app + origin, e.g. `https://app.supp.co/sign-in`. +2. Ensure the signed `oauth_query` is preserved exactly. +3. Update the SvelteKit `/sign-in` page to: + - read `oauth_query` from `url.searchParams` + - pass it to Better Auth login calls in the request body where required + - after successful login, call `/api/auth/oauth2/continue` with the + `oauth_query` if oauth-provider does not auto-continue through the normal + login endpoint + - redirect the browser to the returned `url` +4. Keep the `crossDomain` plugin behavior: + - `trustedOrigins` includes the SvelteKit origin. + - callback URLs are rewritten to the app origin. + - `better-auth-cookie` / `Set-Better-Auth-Cookie` bridge still works for + browser flows. + - one-time-token flow remains for social login and magic links. +5. Add tests that simulate a Convex-site authorize request redirecting to an + app-origin sign-in and resuming via `oauth_query`. + +## 8. RP-initiated logout plan + +- Ensure `/oauth2/end-session` is mounted through the oauth-provider endpoints. +- First-party clients that need logout must be admin-created or migrated with: + - `enableEndSession: true` + - `postLogoutRedirectUris` containing the web and Capacitor callback URIs + - `skipConsent: true` +- Capacitor flow: + - client starts ASWebAuthenticationSession with `id_token_hint`. + - Convex `/oauth2/end-session` validates the hint. + - Better Auth session is destroyed. + - Convex `convex_jwt` cookie is cleared by existing sign-out/session-clear + hook or by an added matcher for `/oauth2/end-session`. + - Browser redirects to validated `post_logout_redirect_uri`. +- Add e2e coverage for the `id_token_hint` round-trip and session destruction. + +## 9. Test plan + +The implementation PR is not done until all of the following pass against a +fresh Convex deployment. + +### Unit tests + +- Schema adapter round-trips for all oauth-provider tables: + - `oauthClient` + - `oauthRefreshToken` + - `oauthAccessToken` + - `oauthConsent` +- Date conversion and `string[]` conversion through `convexAdapter`. +- Migration helpers: + - old `oauthApplication` / `oidcApplication` -> `oauthClient` + - old consent string scopes -> array scopes + - old token cleanup +- Route registration: + - root and prefixed OpenID metadata + - root and prefixed OAuth Authorization Server metadata + - root and prefixed Protected Resource metadata + - CORS exposes `WWW-Authenticate` +- JWT/JWKS: + - `convex()` identity JWT still has `aud: "convex"` and user/session payload. + - oauth-provider ID token uses same JWKS key set. + - static JWKS path avoids database lookup. +- Cross-domain: + - `oauth_query` survives login-page redirect and `/oauth2/continue`. +- MCP helpers: + - missing/invalid token returns 401 with `WWW-Authenticate`. + - valid token calls handler with session/payload. + +### E2E OAuth/OIDC test + +Add `tests/e2e/` or extend existing `e2e/` with an OAuth client-driven test +that: + +1. Starts against a fresh Convex deployment. +2. Performs RFC 7591 Dynamic Client Registration unauthenticated: + - `allowDynamicClientRegistration: true` + - `allowUnauthenticatedClientRegistration: true` + - public client with `token_endpoint_auth_method: "none"` +3. Walks auth-code-with-PKCE: + - request `/oauth2/authorize` + - login through first-party web flow + - continue consent or skip consent for trusted first-party client + - exchange code at `/oauth2/token` +4. Validates ID token signature against `/jwks` and/or `/convex/jwks`. +5. Calls `/oauth2/userinfo` with access token. +6. Calls `/oauth2/end-session` with `id_token_hint`. +7. Confirms Better Auth session and Convex identity cookie/token are destroyed. + +### E2E MCP test + +Add a test using `@modelcontextprotocol/inspector` against a stub MCP server +protected by the new `withMcpAuth` helper: + +1. Discover protected resource metadata. +2. Discover authorization server metadata. +3. Perform DCR. +4. Authorize and exchange token. +5. Call a stub MCP tool successfully. +6. Assert unauthenticated calls return `WWW-Authenticate` and that CORS exposes + the header. + +### Regression tests + +- Existing unit suite: `npm test`. +- Existing lint/typecheck: `npm run lint` and `npm run typecheck`. +- Existing e2e suite: `npm run test:e2e`. +- Existing examples should still typecheck, especially React, Expo, Next, and + TanStack Start. + +## 10. Documentation plan + +- `README.md` + - Add OAuth provider capability summary. + - Document exact pinned versions for `better-auth` and + `@better-auth/oauth-provider`. + - Mention static JWKS remains the recommended Convex WebSocket validation + optimization. + +- `CHANGELOG.md` + - Add migration entry. + - Clearly state any unavoidable breaking configuration changes. + - Document old OAuth/OIDC token invalidation if old tokens cannot be migrated. + +- `docs/content/docs/framework-guides/sveltekit.mdx` + - Add OIDC provider configuration using Convex as issuer. + - Add first-party SvelteKit client setup. + - Add `/sign-in` example that handles `oauth_query`. + - Add DCR/MCP notes where relevant. + +- New or updated migration doc: + - Existing data migration from: + - `oidcApplication`, `oidcAccessToken`, `oidcConsent` + - `oauthApplication`, old-shape `oauthAccessToken`, old-shape + `oauthConsent` + - Regenerate schema instructions for local installs. + - First-party client recreation/admin update instructions. + - Pairwise subject setup with `pairwiseSecret` in Convex env. + - RP-initiated logout setup. + +## 11. Risks and open questions + +- **JWT plugin visibility:** oauth-provider requires `ctx.getPlugin("jwt")`. + The current `convex()` plugin uses `jwtPlugin()` internally but does not + register a `"jwt"` plugin. This is the biggest design risk and must be + resolved before broad implementation. +- **Table name collision:** new `oauthAccessToken` reuses an existing table + name with incompatible fields. A careless schema replacement could break + deployments with old data. The implementation needs a documented migration + and likely a transitional schema/migration strategy. +- **Token migration:** old OIDC access and refresh tokens likely should be + invalidated instead of transformed. This is safer but causes reauthorization. +- **MCP helper compatibility:** upstream `better-auth/plugins/mcp` has not yet + migrated to oauth-provider. Local helpers must be carefully aligned with MCP + RFC 9728 / RFC 8414 expectations. +- **Cross-origin continuation:** oauth-provider uses signed `oauth_query`. + The SvelteKit app must preserve it exactly across login UI actions. +- **Pairwise subjects:** `pairwiseSecret` must be stable and secret. Rotating it + changes `sub` for pairwise clients and can break RP account linking. +- **Logout semantics:** `/oauth2/end-session` requires clients to be explicitly + enabled. First-party client migration must set `enableEndSession` and + `postLogoutRedirectUris`. +- **Shopify Customer Account API:** Shopify may enforce strict OIDC metadata, + subject, and claim expectations. Add a manual verification checklist after + the generic OIDC e2e passes. +- **Claude / Claude Code MCP:** MCP client behavior around unauthenticated DCR + is still evolving. Keep `allowUnauthenticatedClientRegistration` configurable + and documented as compatibility behavior. diff --git a/README.md b/README.md index d568004a..35e324d4 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,20 @@ management features. Allow users to sign in with their accounts, including GitHub, Google, Discord, Twitter, and more. +### OAuth 2.1 / OIDC provider + +**Serve OAuth and OIDC from Convex.** + +The Convex plugin uses `@better-auth/oauth-provider` to expose OAuth 2.1 and +OIDC endpoints from your Convex HTTP deployment, including Dynamic Client +Registration, `/oauth2/userinfo`, RP-initiated logout, and MCP discovery helper +exports. + +This package pins the provider integration to `better-auth@1.6.11` and +`@better-auth/oauth-provider@1.6.11`. Keep those versions aligned when +upgrading. Static JWKS remains supported and recommended for fast Convex +WebSocket identity validation. + ### Two Factor **Multi Factor Authentication.** diff --git a/docs/content/docs/framework-guides/sveltekit.mdx b/docs/content/docs/framework-guides/sveltekit.mdx index d8d793ab..e60f85f8 100644 --- a/docs/content/docs/framework-guides/sveltekit.mdx +++ b/docs/content/docs/framework-guides/sveltekit.mdx @@ -99,7 +99,7 @@ npm install convex @mmailaender/convex-svelte ```npm npm install @convex-dev/better-auth @mmailaender/convex-better-auth-svelte - npm install better-auth@1.5.3 --save-exact + npm install better-auth@1.6.11 @better-auth/oauth-provider@1.6.11 --save-exact ``` @@ -215,8 +215,20 @@ npm install convex @mmailaender/convex-svelte requireEmailVerification: false, }, plugins: [ - // The Convex plugin is required for Convex compatibility - convex({ authConfig }), + // The Convex plugin is required for Convex compatibility. + // It also exposes OAuth 2.1 / OIDC provider endpoints from Convex. + convex({ + authConfig, + oauthProvider: { + // Send the browser to the SvelteKit app to sign in, while + // keeping Convex as the OAuth/OIDC issuer. + loginPage: `${siteUrl}/sign-in`, + consentPage: `${siteUrl}/oauth/consent`, + allowDynamicClientRegistration: true, + allowUnauthenticatedClientRegistration: true, + pairwiseSecret: process.env.OAUTH_PAIRWISE_SECRET, + }, + }), ], }) } @@ -233,6 +245,65 @@ npm install convex @mmailaender/convex-svelte +
+ ### Handle OAuth authorization continuation on sign-in + + When an OAuth client starts at + `.convex.site/oauth2/authorize`, the Convex authorization + server redirects the browser to your SvelteKit `loginPage` with a signed + `oauth_query`. Preserve that value and send it back to Better Auth when the + user signs in so Convex can resume the authorization request. + + ```svelte title="src/routes/sign-in/+page.svelte" + + +
{ event.preventDefault(); signIn(); }}> + + + +
+ ``` + + For first-party web or Capacitor clients, create OAuth clients with + `skip_consent: true`. For RP-initiated logout, also set + `enable_end_session: true` and provide `post_logout_redirect_uris`. +
+
### Create a Better Auth client instance diff --git a/docs/content/docs/migrations/meta.json b/docs/content/docs/migrations/meta.json index c5bc92ec..8c339f11 100644 --- a/docs/content/docs/migrations/meta.json +++ b/docs/content/docs/migrations/meta.json @@ -1,5 +1,5 @@ { "title": "Migrations", - "pages": ["migrate-to-0-12", "migrate-to-0-11", "migrate-to-0-10", "migrate-to-0-9", "migrate-to-0-8"], + "pages": ["migrate-to-oauth-provider", "migrate-to-0-12", "migrate-to-0-11", "migrate-to-0-10", "migrate-to-0-9", "migrate-to-0-8"], "defaultOpen": true } diff --git a/docs/content/docs/migrations/migrate-to-oauth-provider.mdx b/docs/content/docs/migrations/migrate-to-oauth-provider.mdx new file mode 100644 index 00000000..78cc0ae4 --- /dev/null +++ b/docs/content/docs/migrations/migrate-to-oauth-provider.mdx @@ -0,0 +1,84 @@ +--- +title: Migrate to OAuth Provider +description: Move existing OIDC provider data to @better-auth/oauth-provider. +--- + +# Migrate to OAuth Provider + +This release replaces Better Auth's deprecated `oidc-provider` plugin with +`@better-auth/oauth-provider`. The new provider keeps Convex as the OAuth/OIDC +issuer and adds Dynamic Client Registration, OAuth 2.1 metadata, pairwise +subjects, RP-initiated logout, and MCP helper support. + +## 1. Upgrade packages + +Use the pinned versions documented by this component: + +```bash +npm install better-auth@1.6.11 @better-auth/oauth-provider@1.6.11 --save-exact +``` + +## 2. Regenerate schema + +If you use Local Install, regenerate your Better Auth schema: + +```bash +npx auth generate +``` + +The old provider tables are replaced by: + +- `oauthClient` +- `oauthRefreshToken` +- `oauthAccessToken` with the new oauth-provider shape +- `oauthConsent` with array `scopes` + +## 3. Migrate clients + +Migrate rows from `oauthApplication` (or older fork tables named +`oidcApplication`) to `oauthClient`: + +- `clientId` -> `clientId` +- `clientSecret` -> `clientSecret` +- `redirectUrls` -> `redirectUris` as a string array +- `name`, `icon`, `metadata`, `disabled`, `userId`, `createdAt`, `updatedAt` + -> matching fields +- public/native clients should use `tokenEndpointAuthMethod: "none"` and + `public: true` +- first-party clients should usually set `skipConsent: true` +- clients that use RP-initiated logout must set `enableEndSession: true` and + `postLogoutRedirectUris` + +Existing OAuth access and refresh tokens should be invalidated. The new +provider stores tokens differently and separates refresh tokens into +`oauthRefreshToken`, so users should reauthorize clients after migration. + +## 4. Configure provider options + +```ts +convex({ + authConfig, + oauthProvider: { + loginPage: `${process.env.SITE_URL}/sign-in`, + consentPage: `${process.env.SITE_URL}/oauth/consent`, + allowDynamicClientRegistration: true, + allowUnauthenticatedClientRegistration: true, + pairwiseSecret: process.env.OAUTH_PAIRWISE_SECRET, + }, +}); +``` + +Store `pairwiseSecret` in Convex environment variables and keep it stable. +Rotating it changes pairwise `sub` values for relying parties. + +## 5. Update discovery and MCP clients + +`registerRoutes()` now exposes root-level OAuth/OIDC discovery routes and CORS +exposes `WWW-Authenticate`. MCP clients should discover via: + +- `/.well-known/oauth-protected-resource` +- `/.well-known/oauth-authorization-server` + +Use `withMcpAuth`, `oAuthDiscoveryMetadata`, and +`oAuthProtectedResourceMetadata` from `@convex-dev/better-auth/plugins` for +custom MCP HTTP routes. diff --git a/e2e/backendHarness.js b/e2e/backendHarness.js index 032ca99c..8306865a 100644 --- a/e2e/backendHarness.js +++ b/e2e/backendHarness.js @@ -15,6 +15,9 @@ const AdmZip = require("adm-zip"); const backendCloudPort = 3210; const backendSitePort = 3211; +const instanceName = "anonymous-react"; +const instanceSecret = + "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; const parsedUrl = new URL(`http://127.0.0.1:${backendCloudPort}`); function logToStderr(...args) { @@ -137,7 +140,16 @@ async function downloadAndStartBackend() { chmodSync(binaryPath, 0o755); return spawn( binaryPath, - ["--port", String(backendCloudPort), "--site-proxy-port", String(backendSitePort)], + [ + "--port", + String(backendCloudPort), + "--site-proxy-port", + String(backendSitePort), + "--instance-secret", + instanceSecret, + "--instance-name", + instanceName, + ], { env: { CONVEX_TRACE_FILE: "1" } }, ); } diff --git a/e2e/run-e2e-tests.sh b/e2e/run-e2e-tests.sh index 99f866f0..cd490c27 100755 --- a/e2e/run-e2e-tests.sh +++ b/e2e/run-e2e-tests.sh @@ -9,7 +9,7 @@ source "$SCRIPT_DIR/.env.test" set +a CONVEX_URL="http://127.0.0.1:3210" -ADMIN_KEY="0135d8598650f8f5cb0f30c34ec2e2bb62793bc28717c8eb6fb577996d50be5f4281b59181095065c5d0f86a2c31ddbe9b597ec62b47ded69782cd" +ADMIN_KEY="${ADMIN_KEY:-anonymous-react|01d14f2e6aff25b56be22d89e5c120c4d216d0533ab439630a409350d9c9008074ba4bfce3}" EXAMPLE_DIR="$SCRIPT_DIR/../examples/react" # Run convex commands from the example directory so the CLI finds the convex dependency diff --git a/examples/next/package-lock.json b/examples/next/package-lock.json index 94229c47..a3809b45 100644 --- a/examples/next/package-lock.json +++ b/examples/next/package-lock.json @@ -49,52 +49,54 @@ }, "../..": { "name": "@convex-dev/better-auth", - "version": "0.12.1", + "version": "0.12.2", "license": "Apache-2.0", "dependencies": { + "@better-auth/oauth-provider": "1.6.11", "@better-fetch/fetch": "^1.1.18", "common-tags": "^1.8.2", "convex-helpers": "^0.1.95", "jose": "^6.1.0", "remeda": "^2.32.0", "semver": "^7.7.3", - "type-fest": "^4.39.1", + "type-fest": "^5.0.0", "zod": "^4.0.0" }, "devDependencies": { - "@better-auth/core": "1.6.9", - "@better-auth/test-utils": "1.6.9", + "@better-auth/core": "1.6.11", + "@better-auth/test-utils": "1.6.11", + "@convex-dev/eslint-plugin": "2.0.0", "@edge-runtime/vm": "5.0.0", "@eslint/eslintrc": "3.3.5", "@eslint/js": "9.39.4", - "@tanstack/react-start": "1.167.18", + "@tanstack/react-start": "1.167.65", "@types/common-tags": "1.8.4", - "@types/node": "24.12.2", + "@types/node": "24.12.3", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", "@types/semver": "7.7.1", - "better-auth": "1.6.9", + "better-auth": "1.6.11", "chokidar-cli": "3.0.0", "concurrently": "9.2.1", - "convex": "1.36.1", - "convex-test": "0.0.50", + "convex": "1.38.0", + "convex-test": "0.0.51", "eslint": "9.39.4", "eslint-plugin-import": "2.32.0", "eslint-plugin-react": "7.37.5", "eslint-plugin-react-hooks": "7.1.1", "eslint-plugin-react-refresh": "0.5.2", - "globals": "17.5.0", - "next": "16.2.3", - "pkg-pr-new": "0.0.67", + "globals": "17.6.0", + "next": "16.2.6", + "pkg-pr-new": "0.0.71", "prettier": "3.8.3", - "react": "19.2.5", - "react-dom": "19.2.5", + "react": "19.2.6", + "react-dom": "19.2.6", "typescript": "5.9.3", - "typescript-eslint": "8.59.0", - "vitest": "4.1.4" + "typescript-eslint": "8.59.2", + "vitest": "4.1.5" }, "peerDependencies": { - "better-auth": ">=1.6.9 <1.7.0", + "better-auth": "1.6.11", "convex": "^1.25.0", "react": "^18.3.1 || ^19.0.0" } diff --git a/examples/react/package-lock.json b/examples/react/package-lock.json index 973f9153..5ebf053e 100644 --- a/examples/react/package-lock.json +++ b/examples/react/package-lock.json @@ -48,52 +48,54 @@ }, "../..": { "name": "@convex-dev/better-auth", - "version": "0.12.1", + "version": "0.12.2", "license": "Apache-2.0", "dependencies": { + "@better-auth/oauth-provider": "1.6.11", "@better-fetch/fetch": "^1.1.18", "common-tags": "^1.8.2", "convex-helpers": "^0.1.95", "jose": "^6.1.0", "remeda": "^2.32.0", "semver": "^7.7.3", - "type-fest": "^4.39.1", + "type-fest": "^5.0.0", "zod": "^4.0.0" }, "devDependencies": { - "@better-auth/core": "1.6.9", - "@better-auth/test-utils": "1.6.9", + "@better-auth/core": "1.6.11", + "@better-auth/test-utils": "1.6.11", + "@convex-dev/eslint-plugin": "2.0.0", "@edge-runtime/vm": "5.0.0", "@eslint/eslintrc": "3.3.5", "@eslint/js": "9.39.4", - "@tanstack/react-start": "1.167.18", + "@tanstack/react-start": "1.167.65", "@types/common-tags": "1.8.4", - "@types/node": "24.12.2", + "@types/node": "24.12.3", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", "@types/semver": "7.7.1", - "better-auth": "1.6.9", + "better-auth": "1.6.11", "chokidar-cli": "3.0.0", "concurrently": "9.2.1", - "convex": "1.36.1", - "convex-test": "0.0.50", + "convex": "1.38.0", + "convex-test": "0.0.51", "eslint": "9.39.4", "eslint-plugin-import": "2.32.0", "eslint-plugin-react": "7.37.5", "eslint-plugin-react-hooks": "7.1.1", "eslint-plugin-react-refresh": "0.5.2", - "globals": "17.5.0", - "next": "16.2.3", - "pkg-pr-new": "0.0.67", + "globals": "17.6.0", + "next": "16.2.6", + "pkg-pr-new": "0.0.71", "prettier": "3.8.3", - "react": "19.2.5", - "react-dom": "19.2.5", + "react": "19.2.6", + "react-dom": "19.2.6", "typescript": "5.9.3", - "typescript-eslint": "8.59.0", - "vitest": "4.1.4" + "typescript-eslint": "8.59.2", + "vitest": "4.1.5" }, "peerDependencies": { - "better-auth": ">=1.6.9 <1.7.0", + "better-auth": "1.6.11", "convex": "^1.25.0", "react": "^18.3.1 || ^19.0.0" } diff --git a/examples/tanstack/package-lock.json b/examples/tanstack/package-lock.json index e3989455..7a727f91 100644 --- a/examples/tanstack/package-lock.json +++ b/examples/tanstack/package-lock.json @@ -57,52 +57,54 @@ }, "../..": { "name": "@convex-dev/better-auth", - "version": "0.12.1", + "version": "0.12.2", "license": "Apache-2.0", "dependencies": { + "@better-auth/oauth-provider": "1.6.11", "@better-fetch/fetch": "^1.1.18", "common-tags": "^1.8.2", "convex-helpers": "^0.1.95", "jose": "^6.1.0", "remeda": "^2.32.0", "semver": "^7.7.3", - "type-fest": "^4.39.1", + "type-fest": "^5.0.0", "zod": "^4.0.0" }, "devDependencies": { - "@better-auth/core": "1.6.9", - "@better-auth/test-utils": "1.6.9", + "@better-auth/core": "1.6.11", + "@better-auth/test-utils": "1.6.11", + "@convex-dev/eslint-plugin": "2.0.0", "@edge-runtime/vm": "5.0.0", "@eslint/eslintrc": "3.3.5", "@eslint/js": "9.39.4", - "@tanstack/react-start": "1.167.18", + "@tanstack/react-start": "1.167.65", "@types/common-tags": "1.8.4", - "@types/node": "24.12.2", + "@types/node": "24.12.3", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", "@types/semver": "7.7.1", - "better-auth": "1.6.9", + "better-auth": "1.6.11", "chokidar-cli": "3.0.0", "concurrently": "9.2.1", - "convex": "1.36.1", - "convex-test": "0.0.50", + "convex": "1.38.0", + "convex-test": "0.0.51", "eslint": "9.39.4", "eslint-plugin-import": "2.32.0", "eslint-plugin-react": "7.37.5", "eslint-plugin-react-hooks": "7.1.1", "eslint-plugin-react-refresh": "0.5.2", - "globals": "17.5.0", - "next": "16.2.3", - "pkg-pr-new": "0.0.67", + "globals": "17.6.0", + "next": "16.2.6", + "pkg-pr-new": "0.0.71", "prettier": "3.8.3", - "react": "19.2.5", - "react-dom": "19.2.5", + "react": "19.2.6", + "react-dom": "19.2.6", "typescript": "5.9.3", - "typescript-eslint": "8.59.0", - "vitest": "4.1.4" + "typescript-eslint": "8.59.2", + "vitest": "4.1.5" }, "peerDependencies": { - "better-auth": ">=1.6.9 <1.7.0", + "better-auth": "1.6.11", "convex": "^1.25.0", "react": "^18.3.1 || ^19.0.0" } diff --git a/package-lock.json b/package-lock.json index 94bb4a33..064cfecf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.12.2", "license": "Apache-2.0", "dependencies": { + "@better-auth/oauth-provider": "1.6.11", "@better-fetch/fetch": "^1.1.18", "common-tags": "^1.8.2", "convex-helpers": "^0.1.95", @@ -19,8 +20,8 @@ "zod": "^4.0.0" }, "devDependencies": { - "@better-auth/core": "1.6.9", - "@better-auth/test-utils": "1.6.9", + "@better-auth/core": "1.6.11", + "@better-auth/test-utils": "1.6.11", "@convex-dev/eslint-plugin": "2.0.0", "@edge-runtime/vm": "5.0.0", "@eslint/eslintrc": "3.3.5", @@ -31,7 +32,7 @@ "@types/react": "19.2.14", "@types/react-dom": "19.2.3", "@types/semver": "7.7.1", - "better-auth": "1.6.9", + "better-auth": "1.6.11", "chokidar-cli": "3.0.0", "concurrently": "9.2.1", "convex": "1.38.0", @@ -52,7 +53,7 @@ "vitest": "4.1.5" }, "peerDependencies": { - "better-auth": ">=1.6.9 <1.7.0", + "better-auth": "1.6.11", "convex": "^1.25.0", "react": "^18.3.1 || ^19.0.0" } @@ -61,7 +62,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", @@ -76,7 +77,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -86,7 +87,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -117,7 +118,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, + "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -127,7 +128,7 @@ "version": "7.29.1", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", @@ -144,7 +145,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", @@ -161,7 +162,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, + "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -171,7 +172,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -181,7 +182,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.6", @@ -195,7 +196,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -213,7 +214,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -223,7 +224,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -233,7 +234,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -243,7 +244,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -253,7 +254,7 @@ "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -267,7 +268,7 @@ "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -283,7 +284,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -299,7 +300,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -315,7 +316,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.28.6", @@ -330,7 +331,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -349,7 +350,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -360,10 +361,9 @@ } }, "node_modules/@better-auth/core": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.9.tgz", - "integrity": "sha512-ADFk5pwmLybmc+LvYvXJ6M1x2oY/EyYLkwLuH0x28FUq12DfjL0wnE7g+WRDf3yozDO+qIxTpFGXDGwLKbfz0w==", - "dev": true, + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.6.11.tgz", + "integrity": "sha512-LrwidLCV8azdMGjvtwp30nj9tIv1BwI3VhtC0UaGSjQkAVWw4bN42I8qwbxRziPeSQoj+zUVkOpxZzAWBDARtQ==", "license": "MIT", "dependencies": { "@opentelemetry/semantic-conventions": "^1.39.0", @@ -390,13 +390,12 @@ } }, "node_modules/@better-auth/drizzle-adapter": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@better-auth/drizzle-adapter/-/drizzle-adapter-1.6.9.tgz", - "integrity": "sha512-Lcco5hOGrMgc4XKAkvB6x72eQm4wCcya8IevMg4wBHY9W9GVg8pu23rpRX6VsVQSO4Ux13S7lFwUWtF7/r9aKw==", - "dev": true, + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@better-auth/drizzle-adapter/-/drizzle-adapter-1.6.11.tgz", + "integrity": "sha512-4jpkETIGZOHCf7BK4jnu22fdN6jjomH0/HhEzkaWy3+Eppi5PYlHTF/460jrTmA3Xc+Vqwp9t282ymHiEPypGw==", "license": "MIT", "peerDependencies": { - "@better-auth/core": "^1.6.9", + "@better-auth/core": "^1.6.11", "@better-auth/utils": "0.4.0", "drizzle-orm": "^0.45.2" }, @@ -407,15 +406,14 @@ } }, "node_modules/@better-auth/kysely-adapter": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@better-auth/kysely-adapter/-/kysely-adapter-1.6.9.tgz", - "integrity": "sha512-gyjuuxJtZ4o9G9z9q4kqn24X2kvMSp7F+KHogYxF03SnXY/2WleAcuj57iC4wP3e9mGDbjPOrnM5K6Kr3Ktdpw==", - "dev": true, + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@better-auth/kysely-adapter/-/kysely-adapter-1.6.11.tgz", + "integrity": "sha512-/g8M9RfIjdcZDnbstSUvQiINkvdNlCeZr248zwqx2/PVksQI1MhQofbzUn3RnQnbPKp0EPwpX/dR3oudRFenUg==", "license": "MIT", "peerDependencies": { - "@better-auth/core": "^1.6.9", + "@better-auth/core": "^1.6.11", "@better-auth/utils": "0.4.0", - "kysely": "^0.28.14" + "kysely": "^0.28.17" }, "peerDependenciesMeta": { "kysely": { @@ -424,24 +422,22 @@ } }, "node_modules/@better-auth/memory-adapter": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@better-auth/memory-adapter/-/memory-adapter-1.6.9.tgz", - "integrity": "sha512-XmIG4tUnOXZ+KEcWjHUjOI9Z5donD09dC2t/AQTXifAUIqx7cySg86w0KTM09ArzAxRx1fCqO36Wkt5nULnrkQ==", - "dev": true, + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@better-auth/memory-adapter/-/memory-adapter-1.6.11.tgz", + "integrity": "sha512-hpdfw0BBf8MuzLkIdmbcUZICbY9r/bhLO2RxSnkzT5+/O+0I0u2I8+m0YUP7vNllP/ZCKASHOYgXPLO75Z0f9Q==", "license": "MIT", "peerDependencies": { - "@better-auth/core": "^1.6.9", + "@better-auth/core": "^1.6.11", "@better-auth/utils": "0.4.0" } }, "node_modules/@better-auth/mongo-adapter": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@better-auth/mongo-adapter/-/mongo-adapter-1.6.9.tgz", - "integrity": "sha512-h+AiRJ/TsBSi+ZDjySASBpbJ/9QCXBre34PSKgCz7QmTHrFM9Cg2EM4AM7LjR5lPXipEE+2rWPBc9wfnUBjhcw==", - "dev": true, + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@better-auth/mongo-adapter/-/mongo-adapter-1.6.11.tgz", + "integrity": "sha512-3Tor8rSv8vSEIMEaV2PFpPEuVhqc1gNoZ6eGvoh3LwExXXuj8madew6ob+H1pH7Aphn3Ar5PQ08AguT8TbwFAA==", "license": "MIT", "peerDependencies": { - "@better-auth/core": "^1.6.9", + "@better-auth/core": "^1.6.11", "@better-auth/utils": "0.4.0", "mongodb": "^6.0.0 || ^7.0.0" }, @@ -451,14 +447,30 @@ } } }, + "node_modules/@better-auth/oauth-provider": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@better-auth/oauth-provider/-/oauth-provider-1.6.11.tgz", + "integrity": "sha512-iMywpOEAiAUdtvpaRS8yKye+wO3AieOB3Sfv8czkmPduzFuKBICCWuOEAElQEk5tQz3vzWx64zNlLBkgEAOhuw==", + "license": "MIT", + "dependencies": { + "jose": "^6.1.3", + "zod": "^4.3.6" + }, + "peerDependencies": { + "@better-auth/core": "^1.6.11", + "@better-auth/utils": "0.4.0", + "@better-fetch/fetch": "1.1.21", + "better-auth": "^1.6.11", + "better-call": "1.3.5" + } + }, "node_modules/@better-auth/prisma-adapter": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@better-auth/prisma-adapter/-/prisma-adapter-1.6.9.tgz", - "integrity": "sha512-XHks01ntK20orqK/jICq8wmEbJ/zT6dct49Fk8zTQKN9QNGDc+Ix5+7z/Kvui0DXGFf790GfvRozquzaLtXa8Q==", - "dev": true, + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@better-auth/prisma-adapter/-/prisma-adapter-1.6.11.tgz", + "integrity": "sha512-Pw+7q7zTp+VSci1V+CYMvuxIbAeVMZLe4lRo46LJoAKMHfjFl5T/ycsyFvWs/DkWC7n9gZZzRDEbHp0I5FiKKw==", "license": "MIT", "peerDependencies": { - "@better-auth/core": "^1.6.9", + "@better-auth/core": "^1.6.11", "@better-auth/utils": "0.4.0", "@prisma/client": "^5.0.0 || ^6.0.0 || ^7.0.0", "prisma": "^5.0.0 || ^6.0.0 || ^7.0.0" @@ -473,34 +485,32 @@ } }, "node_modules/@better-auth/telemetry": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@better-auth/telemetry/-/telemetry-1.6.9.tgz", - "integrity": "sha512-0u5zkhSCAQFoN3DHvUkLHOF6MBbVTDAa6mU8mhPwiysdz1x21vMzhzfaAKN/ZGWaQ09v91/F+2qu42G/bhUV4A==", - "dev": true, + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@better-auth/telemetry/-/telemetry-1.6.11.tgz", + "integrity": "sha512-hsjDHc8MZbm6/AHeNdtywrWedXevnBjmdvnHTcZub+rTVjOv+Td0roI8USKuC6uUibmrl//2rJfVCsGbopihNA==", "license": "MIT", "peerDependencies": { - "@better-auth/core": "^1.6.9", + "@better-auth/core": "^1.6.11", "@better-auth/utils": "0.4.0", "@better-fetch/fetch": "1.1.21" } }, "node_modules/@better-auth/test-utils": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@better-auth/test-utils/-/test-utils-1.6.9.tgz", - "integrity": "sha512-5/kfoM+zt9zeLU+5gXadKrymvNJY0SJsjpbm1LcPSN/iuU9P/8fyDEEsD+FZ3TDtz/XJ+s5fZKXrO5dPglsEsg==", + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@better-auth/test-utils/-/test-utils-1.6.11.tgz", + "integrity": "sha512-dnul49FbhPES5Ky2s32VGRz2Hw40dIXmWfNznlApNw25LK2QwXLcvC74T+feeuTbRFQcz+qilLt9T48IP/ksnA==", "dev": true, "license": "MIT", "peerDependencies": { - "@better-auth/core": "^1.6.9", - "better-auth": "^1.6.9", - "vitest": "^4.0.18" + "@better-auth/core": "^1.6.11", + "better-auth": "^1.6.11", + "vitest": "^4.1.5" } }, "node_modules/@better-auth/utils": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.4.0.tgz", "integrity": "sha512-RpMtLUIQAEWMgdPLNVbIF5ON2mm+CH0U3rCdUCU1VyeAUui4m38DyK7/aXMLZov2YDjG684pS1D0MBllrmgjQA==", - "dev": true, "license": "MIT", "dependencies": { "@noble/hashes": "^2.0.1" @@ -1895,7 +1905,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -1906,7 +1916,7 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -1917,7 +1927,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1927,14 +1937,14 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1964,7 +1974,7 @@ "version": "16.2.6", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.6.tgz", "integrity": "sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { @@ -2107,7 +2117,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.2.0.tgz", "integrity": "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 20.19.0" @@ -2120,7 +2129,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 20.19.0" @@ -2133,7 +2141,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-2.0.2.tgz", "integrity": "sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@oozcitak/infra": "^2.0.2", @@ -2148,7 +2156,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-2.0.2.tgz", "integrity": "sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@oozcitak/util": "^10.0.0" @@ -2161,7 +2169,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-3.0.0.tgz", "integrity": "sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@oozcitak/infra": "^2.0.2", @@ -2175,7 +2183,7 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-10.0.0.tgz", "integrity": "sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=20.0" @@ -2185,7 +2193,6 @@ "version": "1.40.0", "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=14" @@ -2195,7 +2202,7 @@ "version": "0.124.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" @@ -2462,7 +2469,7 @@ "version": "1.0.0-beta.40", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.40.tgz", "integrity": "sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@rtsao/scc": { @@ -2476,14 +2483,13 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "devOptional": true, "license": "MIT" }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.8.0" @@ -2493,7 +2499,7 @@ "version": "1.161.6", "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.161.6.tgz", "integrity": "sha512-NaOGLRrddszbQj9upGat6HG/4TKvXLvu+osAIgfxPYA+eIvYKv8GKDJOrY2D3/U9MRnKfMWD7bU4jeD4xmqyIg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=20.19" @@ -2507,7 +2513,7 @@ "version": "1.169.2", "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.169.2.tgz", "integrity": "sha512-OJM7Kguc7ERnweaNRWsyWgIKcl3z23rD1B4jaxjzd9RGdnzpt2HfrWa9rggbT0Hfzhfo4D2ZmsfoTme035tniQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@tanstack/history": "1.161.6", @@ -2531,7 +2537,7 @@ "version": "1.167.65", "resolved": "https://registry.npmjs.org/@tanstack/react-start/-/react-start-1.167.65.tgz", "integrity": "sha512-vCGga3RECeR4VpSVuXIU/+zxak5f2qdpUXdZ2yrgcwwKoYPtatdJm6zjS0Py7UOecRqLqMtSeuOjowBJ1higWQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@tanstack/react-router": "1.169.2", @@ -2573,7 +2579,7 @@ "version": "1.166.48", "resolved": "https://registry.npmjs.org/@tanstack/react-start-client/-/react-start-client-1.166.48.tgz", "integrity": "sha512-6fqwCwe6v+Nvtdf6vg6gxs/0gCXyZEHF18EslNeG/kca2wnXYFuXRhqGJjJaEgMk3WF4IE9mUgFuBSAOY3P7nQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@tanstack/react-router": "1.169.2", @@ -2596,7 +2602,7 @@ "version": "0.0.44", "resolved": "https://registry.npmjs.org/@tanstack/react-start-rsc/-/react-start-rsc-0.0.44.tgz", "integrity": "sha512-5iYUWSBjTwJbV8bTLJHZ5dHm8c/79J6spxPlKsjt9/R0mQaQQjLVNMpv5CrOZ2vPTaZx1ALoGdSWP4WdPcuKRA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@tanstack/react-router": "1.169.2", @@ -2640,7 +2646,7 @@ "version": "1.166.52", "resolved": "https://registry.npmjs.org/@tanstack/react-start-server/-/react-start-server-1.166.52.tgz", "integrity": "sha512-46Gx+byIndYywUtyna5h3qatHipJkPFqo/miexfuYPgeVAI6ypQzsw7wxF194H6VAP43m2q+fdLPBXStufoOGw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@tanstack/history": "1.161.6", @@ -2665,7 +2671,7 @@ "version": "0.9.3", "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.9.3.tgz", "integrity": "sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@tanstack/store": "0.9.3", @@ -2684,7 +2690,7 @@ "version": "1.169.2", "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.169.2.tgz", "integrity": "sha512-5sm0DJF1A7Mz+9gy4Gz/lLovNailK3yot4vYvz9MkBUPw26uLnhQiR8hSCYxucjE0wD6Mdlc5l+Z0/XTlZ7xHw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@tanstack/history": "1.161.6", @@ -2704,7 +2710,7 @@ "version": "1.166.42", "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.166.42.tgz", "integrity": "sha512-2qBWC0t78r6b3vI+AbnvCZcFAvbYBDlLuWZrTjQbcjUmwG3qyeQp983tJyDuj9wb5//adG1tgAGXZkJ3aDwdBg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.5", @@ -2728,7 +2734,7 @@ "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -2738,7 +2744,7 @@ "version": "1.167.35", "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.167.35.tgz", "integrity": "sha512-UAScU5VAzLYVY4FML/Cbc5S5TucT4I8Ata05yozGOe4ZfepTKRffA5xWLtD2N+ov5svdv0KTX/kqlZnYPe28mA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/core": "^7.28.5", @@ -2791,7 +2797,7 @@ "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -2801,7 +2807,7 @@ "version": "1.161.8", "resolved": "https://registry.npmjs.org/@tanstack/router-utils/-/router-utils-1.161.8.tgz", "integrity": "sha512-xyiLWEKjfBAVhauDSSjXxyf7s8elU6SM+V050sbkofvGmIIvkwPFtDsX7Gvwh14kBd6iCwAT+RiPvXTxAptY0Q==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/core": "^7.28.5", @@ -2826,7 +2832,7 @@ "version": "1.168.2", "resolved": "https://registry.npmjs.org/@tanstack/start-client-core/-/start-client-core-1.168.2.tgz", "integrity": "sha512-/bckv9k/yxY4VmSY2V2MeX7NBsS5uqGvdSPs5WIvW3Uv35DXPrdiumKXTNJeZRNRMtxrM+YfxQPjXLx3C7ykvg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@tanstack/router-core": "1.169.2", @@ -2846,7 +2852,7 @@ "version": "1.161.6", "resolved": "https://registry.npmjs.org/@tanstack/start-fn-stubs/-/start-fn-stubs-1.161.6.tgz", "integrity": "sha512-Y6QSlGiLga8cHfvxGGaonXIlt2bIUTVdH6AMjmpMp7+ANNCp+N96GQbjjhLye3JkaxDfP68x5iZA8NK4imgRig==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=22.12.0" @@ -2860,7 +2866,7 @@ "version": "1.169.20", "resolved": "https://registry.npmjs.org/@tanstack/start-plugin-core/-/start-plugin-core-1.169.20.tgz", "integrity": "sha512-MLSH5P3auFpnol1lMGQhUrpJH7+P5knzBXMnJjXG+nVOvmcYbY0JA+nQMl81kKiqfkEceAiaEdKhl8Zc5Ldolw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/code-frame": "7.27.1", @@ -2911,7 +2917,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -2926,7 +2932,7 @@ "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -2936,7 +2942,7 @@ "version": "1.167.30", "resolved": "https://registry.npmjs.org/@tanstack/start-server-core/-/start-server-core-1.167.30.tgz", "integrity": "sha512-GC0PXzYYSEwfAOC2NxGXFUyYvfbSjVoqnIrzJsyInKd8xQxGEQaVdrebbyx9TV5cj7A5e7EJcWAsf3G3wRDQBw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@tanstack/history": "1.161.6", @@ -2959,7 +2965,7 @@ "version": "1.166.35", "resolved": "https://registry.npmjs.org/@tanstack/start-storage-context/-/start-storage-context-1.166.35.tgz", "integrity": "sha512-ZKDkKiorJrKwfEHjatEwRHG7EP3raJPhh6CSl4CFmHW0naIvwaW5gQcxcT8IlHtoGDLYDAjBEcSr3MZyXgqmOA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@tanstack/router-core": "1.169.2" @@ -2976,7 +2982,7 @@ "version": "0.9.3", "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.9.3.tgz", "integrity": "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "type": "github", @@ -2987,7 +2993,7 @@ "version": "1.161.7", "resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.161.7.tgz", "integrity": "sha512-olW33+Cn+bsCsZKPwEGhlkqS6w3M2slFv11JIobdnCFKMLG97oAI2kWKdx5/zsywTL8flpnoIgaZZPlQTFYhdQ==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "intent": "bin/intent.js" @@ -3015,7 +3021,7 @@ "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/deep-eql": "*", @@ -3033,14 +3039,14 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/json-schema": { @@ -3380,7 +3386,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz", "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", @@ -3398,7 +3404,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz", "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/spy": "4.1.5", @@ -3425,7 +3431,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz", "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "tinyrainbow": "^3.1.0" @@ -3438,7 +3444,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz", "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/utils": "4.1.5", @@ -3452,7 +3458,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz", "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/pretty-format": "4.1.5", @@ -3468,7 +3474,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz", "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://opencollective.com/vitest" @@ -3478,7 +3484,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz", "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/pretty-format": "4.1.5", @@ -3559,7 +3565,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": ">=14" @@ -3569,7 +3575,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -3583,7 +3589,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -3596,7 +3602,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, + "devOptional": true, "license": "Python-2.0" }, "node_modules/array-buffer-byte-length": { @@ -3763,7 +3769,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -3799,7 +3805,7 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.12.tgz", "integrity": "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/core": "^7.23.7", @@ -3819,7 +3825,7 @@ "version": "2.10.17", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.17.tgz", "integrity": "sha512-HdrkN8eVG2CXxeifv/VdJ4A4RSra1DTW8dc/hdxzhGHN8QePs6gKaWM9pHPcpCoxYZJuOZ8drHmbdpLHjCYjLA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -3829,19 +3835,18 @@ } }, "node_modules/better-auth": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.6.9.tgz", - "integrity": "sha512-EBFURtglyiEZxbx4NJBoqUD8J65dX24yC+6I9AUbIXNgUkt76mshzGbHkxZ3n/lB7Dwq3kBC+hHt0hUQsnL7HA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@better-auth/core": "1.6.9", - "@better-auth/drizzle-adapter": "1.6.9", - "@better-auth/kysely-adapter": "1.6.9", - "@better-auth/memory-adapter": "1.6.9", - "@better-auth/mongo-adapter": "1.6.9", - "@better-auth/prisma-adapter": "1.6.9", - "@better-auth/telemetry": "1.6.9", + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.6.11.tgz", + "integrity": "sha512-Wwt6+q07dwIhsp6XiM7L1qSXVUWBEtNl+eZvwM778CguFqDZFBN9Pt6LtFaHl55t8Z+Zc//5kxcbgDY8/79vFQ==", + "license": "MIT", + "dependencies": { + "@better-auth/core": "1.6.11", + "@better-auth/drizzle-adapter": "1.6.11", + "@better-auth/kysely-adapter": "1.6.11", + "@better-auth/memory-adapter": "1.6.11", + "@better-auth/mongo-adapter": "1.6.11", + "@better-auth/prisma-adapter": "1.6.11", + "@better-auth/telemetry": "1.6.11", "@better-auth/utils": "0.4.0", "@better-fetch/fetch": "1.1.21", "@noble/ciphers": "^2.1.1", @@ -3849,7 +3854,7 @@ "better-call": "1.3.5", "defu": "^6.1.4", "jose": "^6.1.3", - "kysely": "^0.28.14", + "kysely": "^0.28.17", "nanostores": "^1.1.1", "zod": "^4.3.6" }, @@ -3938,7 +3943,6 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/better-call/-/better-call-1.3.5.tgz", "integrity": "sha512-kOFJkBP7utAQLEYrobZm3vkTH8mXq5GNgvjc5/XEST1ilVHaxXUXfeDeFlqoETMtyqS4+3/h4ONX2i++ebZrvA==", - "dev": true, "license": "MIT", "dependencies": { "@better-auth/utils": "^0.4.0", @@ -3959,7 +3963,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -3972,7 +3976,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/brace-expansion": { @@ -3990,7 +3994,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -4003,7 +4007,7 @@ "version": "4.28.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", - "dev": true, + "devOptional": true, "funding": [ { "type": "opencollective", @@ -4107,7 +4111,7 @@ "version": "1.0.30001787", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001787.tgz", "integrity": "sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==", - "dev": true, + "devOptional": true, "funding": [ { "type": "opencollective", @@ -4128,7 +4132,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -4168,7 +4172,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "cheerio-select": "^2.1.0", @@ -4194,7 +4198,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", @@ -4212,7 +4216,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -4256,7 +4260,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/cliui": { @@ -4463,7 +4467,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/convex": { @@ -4552,7 +4556,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz", "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -4574,7 +4578,7 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", @@ -4591,7 +4595,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">= 6" @@ -4665,7 +4669,7 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4736,14 +4740,13 @@ "version": "6.1.7", "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", - "dev": true, "license": "MIT" }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -4753,7 +4756,7 @@ "version": "8.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -4776,7 +4779,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", @@ -4791,7 +4794,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -4804,7 +4807,7 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" @@ -4820,7 +4823,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", @@ -4850,7 +4853,7 @@ "version": "1.5.334", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.334.tgz", "integrity": "sha512-mgjZAz7Jyx1SRCwEpy9wefDS7GvNPazLthHg8eQMJ76wBdGQQDW33TCrUTvQ4wzpmOrv2zrFoD3oNufMdyMpog==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/emoji-regex": { @@ -4864,7 +4867,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "iconv-lite": "^0.6.3", @@ -4878,7 +4881,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -5008,7 +5011,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/es-object-atoms": { @@ -5116,7 +5119,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -5473,7 +5476,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" @@ -5493,7 +5496,7 @@ "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, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=12.0.0" @@ -5503,7 +5506,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/fast-deep-equal": { @@ -5531,7 +5534,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -5549,7 +5552,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/fetchdts/-/fetchdts-0.1.7.tgz", "integrity": "sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/file-entry-cache": { @@ -5569,7 +5572,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -5702,7 +5705,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -5779,7 +5782,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -5836,7 +5839,7 @@ "version": "2.0.1-rc.20", "resolved": "https://registry.npmjs.org/h3/-/h3-2.0.1-rc.20.tgz", "integrity": "sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "rou3": "^0.8.1", @@ -5861,7 +5864,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.8.1.tgz", "integrity": "sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/has-bigints": { @@ -5979,7 +5982,7 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", - "dev": true, + "devOptional": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -5999,7 +6002,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -6012,7 +6015,7 @@ "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, + "devOptional": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -6131,7 +6134,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -6225,7 +6228,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6281,7 +6284,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -6320,7 +6323,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -6499,7 +6502,7 @@ "version": "5.1.37", "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.37.tgz", "integrity": "sha512-5bcicX81xf6NlTEV8rWdg7Pk01LFizDetuYGHx6d/f6y3lR2/oo8IfxjzJqn1UdDEyCcwT9e7NRloj8DwCYujQ==", - "dev": true, + "devOptional": true, "license": "Unlicense", "engines": { "node": ">=18" @@ -6534,7 +6537,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -6553,14 +6556,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -6573,7 +6576,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -6607,7 +6610,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -6643,10 +6646,9 @@ } }, "node_modules/kysely": { - "version": "0.28.16", - "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.16.tgz", - "integrity": "sha512-3i5pmOiZvMDj00qhrIVbH0AnioVTx22DMP7Vn5At4yJO46iy+FM8Y/g61ltenLVSo3fiO8h8Q3QOFgf/gQ72ww==", - "dev": true, + "version": "0.28.17", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.17.tgz", + "integrity": "sha512-nbD8lB9EB3wNdMhOCdx5Li8DxnLbvKByylRLcJ1h+4SkrowVeECAyZlyiKMThF7xFdRz0jSQ2MoJr+wXux2y0Q==", "license": "MIT", "engines": { "node": ">=20.0.0" @@ -6670,7 +6672,7 @@ "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, + "devOptional": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -6981,7 +6983,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -6991,7 +6993,7 @@ "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, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" @@ -7034,14 +7036,14 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, + "devOptional": 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, + "devOptional": true, "funding": [ { "type": "github", @@ -7060,7 +7062,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.2.0.tgz", "integrity": "sha512-F0wCzbsH80G7XXo0Jd9/AVQC7ouWY6idUCTnMwW5t/Rv9W8qmO6endavDwg7TNp5GbugwSukFMVZqzPSrSMndg==", - "dev": true, "funding": [ { "type": "github", @@ -7083,7 +7084,7 @@ "version": "16.2.6", "resolved": "https://registry.npmjs.org/next/-/next-16.2.6.tgz", "integrity": "sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@next/env": "16.2.6", @@ -7166,14 +7167,14 @@ "version": "2.0.37", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7183,7 +7184,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" @@ -7319,7 +7320,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true, + "devOptional": true, "funding": [ "https://github.com/sponsors/sxzz", "https://opencollective.com/debug" @@ -7421,7 +7422,7 @@ "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "entities": "^6.0.0" @@ -7434,7 +7435,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "domhandler": "^5.0.3", @@ -7448,7 +7449,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "parse5": "^7.0.0" @@ -7461,7 +7462,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -7501,21 +7502,21 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -7548,7 +7549,7 @@ "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "dev": true, + "devOptional": true, "funding": [ { "type": "opencollective", @@ -7634,7 +7635,7 @@ "version": "19.2.6", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "scheduler": "^0.27.0" @@ -7654,7 +7655,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -7667,7 +7668,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -7784,7 +7785,7 @@ "version": "1.0.0-rc.15", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@oxc-project/types": "=0.124.0", @@ -7818,14 +7819,13 @@ "version": "1.0.0-rc.15", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/rou3": { "version": "0.7.12", "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.7.12.tgz", "integrity": "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==", - "dev": true, "license": "MIT" }, "node_modules/rxjs": { @@ -7897,14 +7897,14 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/semver": { @@ -7923,7 +7923,7 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.4.tgz", "integrity": "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -7933,7 +7933,7 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.5.4.tgz", "integrity": "sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" @@ -7953,7 +7953,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz", "integrity": "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==", - "dev": true, "license": "MIT" }, "node_modules/set-function-length": { @@ -8167,14 +8166,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/source-map": { "version": "0.7.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">= 12" @@ -8184,7 +8183,7 @@ "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, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -8194,7 +8193,7 @@ "version": "0.11.15", "resolved": "https://registry.npmjs.org/srvx/-/srvx-0.11.15.tgz", "integrity": "sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "srvx": "bin/srvx.mjs" @@ -8207,14 +8206,14 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/std-env": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz", "integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/stop-iteration-iterator": { @@ -8384,7 +8383,7 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "client-only": "0.0.1" @@ -8449,14 +8448,14 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/tinyexec": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -8466,7 +8465,7 @@ "version": "0.2.16", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -8483,7 +8482,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=14.0.0" @@ -8493,7 +8492,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -8555,7 +8554,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, + "devOptional": true, "license": "0BSD" }, "node_modules/type-check": { @@ -8706,7 +8705,7 @@ "version": "1.6.4", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unbox-primitive": { @@ -8732,7 +8731,7 @@ "version": "7.25.0", "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=20.18.1" @@ -8749,7 +8748,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.5", @@ -8764,7 +8763,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, + "devOptional": true, "funding": [ { "type": "opencollective", @@ -8805,7 +8804,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -8815,7 +8814,7 @@ "version": "8.0.8", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", @@ -8893,7 +8892,7 @@ "version": "8.5.9", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz", "integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==", - "dev": true, + "devOptional": true, "funding": [ { "type": "opencollective", @@ -8922,7 +8921,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", - "dev": true, + "devOptional": true, "license": "MIT", "workspaces": [ "tests/deps/*", @@ -8942,7 +8941,7 @@ "version": "4.1.5", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz", "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@vitest/expect": "4.1.5", @@ -9032,7 +9031,7 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/whatwg-encoding": { @@ -9040,7 +9039,7 @@ "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, + "devOptional": true, "license": "MIT", "dependencies": { "iconv-lite": "0.6.3" @@ -9053,7 +9052,7 @@ "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, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -9175,7 +9174,7 @@ "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, + "devOptional": true, "license": "MIT", "dependencies": { "siginfo": "^2.0.0", @@ -9268,7 +9267,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-4.0.3.tgz", "integrity": "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@oozcitak/dom": "^2.0.2", @@ -9291,7 +9290,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/yargs": { diff --git a/package.json b/package.json index ff51d098..126e1935 100644 --- a/package.json +++ b/package.json @@ -101,13 +101,13 @@ } }, "peerDependencies": { - "better-auth": ">=1.6.9 <1.7.0", + "better-auth": "1.6.11", "convex": "^1.25.0", "react": "^18.3.1 || ^19.0.0" }, "devDependencies": { - "@better-auth/core": "1.6.9", - "@better-auth/test-utils": "1.6.9", + "@better-auth/core": "1.6.11", + "@better-auth/test-utils": "1.6.11", "@convex-dev/eslint-plugin": "2.0.0", "@edge-runtime/vm": "5.0.0", "@eslint/eslintrc": "3.3.5", @@ -118,7 +118,7 @@ "@types/react": "19.2.14", "@types/react-dom": "19.2.3", "@types/semver": "7.7.1", - "better-auth": "1.6.9", + "better-auth": "1.6.11", "chokidar-cli": "3.0.0", "concurrently": "9.2.1", "convex": "1.38.0", @@ -141,6 +141,7 @@ "types": "./dist/client/index.d.ts", "module": "./dist/client/index.js", "dependencies": { + "@better-auth/oauth-provider": "1.6.11", "@better-fetch/fetch": "^1.1.18", "common-tags": "^1.8.2", "convex-helpers": "^0.1.95", diff --git a/src/auth-options.ts b/src/auth-options.ts index 6281482f..eda273f4 100644 --- a/src/auth-options.ts +++ b/src/auth-options.ts @@ -5,7 +5,6 @@ import { emailOTP } from "better-auth/plugins/email-otp"; import { genericOAuth } from "better-auth/plugins/generic-oauth"; import { jwt } from "better-auth/plugins/jwt"; import { magicLink } from "better-auth/plugins/magic-link"; -import { oidcProvider } from "better-auth/plugins/oidc-provider"; import { oneTimeToken } from "better-auth/plugins/one-time-token"; import { phoneNumber } from "better-auth/plugins/phone-number"; import { twoFactor } from "better-auth/plugins/two-factor"; @@ -35,10 +34,6 @@ export const options = { }, ], }), - oidcProvider({ - loginPage: "/login", - __skipDeprecationWarning: true, - }), bearer(), oneTimeToken(), jwt(), diff --git a/src/client/adapter.ts b/src/client/adapter.ts index c5c88a3b..fea2c53f 100644 --- a/src/client/adapter.ts +++ b/src/client/adapter.ts @@ -269,7 +269,7 @@ export const convexAdapter = < )) as FunctionHandle<"mutation">) : undefined; return ctx.runMutation(api.adapter.create, { - input: { model: model as any, data }, + input: { model: model as any, data: data as any }, select, onCreateHandle: onCreateHandle, }); diff --git a/src/client/create-client.test.ts b/src/client/create-client.test.ts index 548bdf43..77941e40 100644 --- a/src/client/create-client.test.ts +++ b/src/client/create-client.test.ts @@ -52,6 +52,26 @@ describe("createClient route registration", () => { expect( getRouteHandler(http, "/.well-known/openid-configuration", "GET") ).toBeTruthy(); + expect( + getRouteHandler( + http, + "/.well-known/openid-configuration/custom/auth", + "GET" + ) + ).toBeTruthy(); + expect( + getRouteHandler(http, "/.well-known/oauth-authorization-server", "GET") + ).toBeTruthy(); + expect( + getRouteHandler( + http, + "/.well-known/oauth-authorization-server/custom/auth", + "GET" + ) + ).toBeTruthy(); + expect( + getRouteHandler(http, "/.well-known/oauth-protected-resource", "GET") + ).toBeTruthy(); }); it("registerRoutes uses auth options for CORS and basePath", async () => { @@ -100,15 +120,94 @@ describe("createClient route registration", () => { const getHandler = getRouteHandler(http, "/custom/auth/test", "GET"); expect(getHandler).toBeTruthy(); - await getHandler!._handler( + const getResponse = await getHandler!._handler( {}, new Request("https://deployment.convex.site/custom/auth/test", { method: "GET", + headers: { + origin: "https://app.example.com", + }, }) ); + expect(getResponse.headers.get("access-control-expose-headers")).toContain( + "WWW-Authenticate" + ); expect(createAuth).toHaveBeenCalledTimes(2); }); + it("registerRoutes exposes OAuth protected resource metadata", async () => { + const originalConvexSiteUrl = process.env.CONVEX_SITE_URL; + process.env.CONVEX_SITE_URL = "https://deployment.convex.site"; + try { + const client = createClient(component); + const http = httpRouter(); + const createAuth = vi.fn(() => ({ + handler: async () => new Response("ok"), + options: { + basePath: "/custom/auth", + trustedOrigins: ["https://app.example.com"], + }, + $context: Promise.resolve({ + options: { + trustedOrigins: ["https://app.example.com"], + }, + }), + })); + + client.registerRoutes(http, createAuth); + + const handler = getRouteHandler( + http, + "/.well-known/oauth-protected-resource/custom/auth", + "GET" + ); + expect(handler).toBeTruthy(); + const response = await handler!._handler( + {}, + new Request( + "https://deployment.convex.site/.well-known/oauth-protected-resource/custom/auth" + ) + ); + + expect(response.headers.get("content-type")).toContain( + "application/json" + ); + await expect(response.json()).resolves.toMatchObject({ + resource: "https://deployment.convex.site/custom/auth", + authorization_servers: ["https://deployment.convex.site"], + bearer_methods_supported: ["header"], + }); + + const mcpHandler = getRouteHandler( + http, + "/.well-known/oauth-protected-resource/mcp", + "GET" + ); + expect(mcpHandler).toBeTruthy(); + const mcpResponse = await mcpHandler!._handler( + {}, + new Request( + "https://deployment.convex.site/.well-known/oauth-protected-resource/mcp" + ) + ); + + expect(mcpResponse.headers.get("content-type")).toContain( + "application/json" + ); + await expect(mcpResponse.json()).resolves.toMatchObject({ + resource: "https://deployment.convex.site/mcp", + authorization_servers: ["https://deployment.convex.site"], + bearer_methods_supported: ["header"], + }); + } finally { + if (originalConvexSiteUrl === undefined) { + delete process.env.CONVEX_SITE_URL; + } else { + process.env.CONVEX_SITE_URL = originalConvexSiteUrl; + } + } + }); + it("restores preserved forwarded host headers before calling auth.handler", async () => { const client = createClient(component); const http = httpRouter(); @@ -145,7 +244,9 @@ describe("createClient route registration", () => { const forwardedRequest = handler.mock.calls[0]?.[0]; expect(forwardedRequest).toBeInstanceOf(Request); - expect(forwardedRequest.headers.get("x-forwarded-host")).toBe("app.example.com"); + expect(forwardedRequest.headers.get("x-forwarded-host")).toBe( + "app.example.com" + ); expect(forwardedRequest.headers.get("x-forwarded-proto")).toBe("https"); }); @@ -164,7 +265,10 @@ describe("createClient route registration", () => { }), })); - client.registerRoutesLazy(http, createAuth, { cors: true }); + client.registerRoutesLazy(http, createAuth, { + basePath: "/api/auth", + cors: true, + }); expect(createAuth).not.toHaveBeenCalled(); expect(getRouteHandler(http, "/api/auth/test", "GET")).toBeTruthy(); @@ -186,4 +290,77 @@ describe("createClient route registration", () => { ); expect(createAuth).toHaveBeenCalledTimes(1); }); + + it("registerRoutesLazy infers basePath from auth options", () => { + const client = createClient(component); + const http = httpRouter(); + const createAuth = vi.fn(() => ({ + handler: async () => new Response("ok"), + options: { + basePath: "/custom/auth", + }, + $context: Promise.resolve({ + options: { + trustedOrigins: ["https://app.example.com"], + }, + }), + })); + + client.registerRoutesLazy(http, createAuth); + + expect(createAuth).toHaveBeenCalledTimes(1); + expect(getRouteHandler(http, "/custom/auth/test", "GET")).toBeTruthy(); + expect( + getRouteHandler( + http, + "/.well-known/oauth-authorization-server/custom/auth", + "GET" + ) + ).toBeTruthy(); + }); + + it("fails fast when CONVEX_SITE_URL is missing for protected resource metadata", async () => { + const previousSiteUrl = process.env.CONVEX_SITE_URL; + delete process.env.CONVEX_SITE_URL; + + try { + const client = createClient(component); + const http = httpRouter(); + const createAuth = vi.fn(() => ({ + handler: async () => new Response("ok"), + options: { + basePath: "/custom/auth", + }, + $context: Promise.resolve({ + options: { + trustedOrigins: ["https://app.example.com"], + }, + }), + })); + + client.registerRoutes(http, createAuth); + + const handler = getRouteHandler( + http, + "/.well-known/oauth-protected-resource/custom/auth", + "GET" + ); + expect(handler).toBeTruthy(); + + await expect( + handler!._handler( + {}, + new Request( + "https://deployment.convex.site/.well-known/oauth-protected-resource/custom/auth" + ) + ) + ).rejects.toThrow("CONVEX_SITE_URL is not set"); + } finally { + if (previousSiteUrl === undefined) { + delete process.env.CONVEX_SITE_URL; + } else { + process.env.CONVEX_SITE_URL = previousSiteUrl; + } + } + }); }); diff --git a/src/client/create-client.ts b/src/client/create-client.ts index 9b4c3f77..41aefa45 100644 --- a/src/client/create-client.ts +++ b/src/client/create-client.ts @@ -106,6 +106,104 @@ const restoreOriginalForwardedHeaders = (request: Request) => { return new Request(request, { headers }); }; +const jsonResponse = (body: Record) => + new Response(JSON.stringify(body), { + headers: { + "content-type": "application/json", + "access-control-allow-methods": "GET", + "access-control-allow-origin": "*", + }, + }); + +const getConvexSiteUrl = () => { + const siteUrl = process.env.CONVEX_SITE_URL; + if (!siteUrl) { + throw new Error("CONVEX_SITE_URL is not set"); + } + return siteUrl; +}; + +const protectedResourceMetadata = (resourcePath: string) => { + const siteUrl = getConvexSiteUrl(); + const resource = + resourcePath === "/" ? siteUrl : `${siteUrl}${resourcePath}`; + return { + resource, + authorization_servers: [siteUrl], + scopes_supported: ["openid", "profile", "email", "offline_access"], + bearer_methods_supported: ["header"], + resource_documentation: `${siteUrl}${resourcePath}`, + }; +}; + +const routeIfMissing = ( + http: HttpRouter, + path: string, + handler: () => Response | Promise +) => { + if (http.lookup(path, "GET")) { + return; + } + http.route({ + path, + method: "GET", + handler: httpActionGeneric(async () => handler()), + }); +}; + +const registerWellKnownRoutes = (http: HttpRouter, path: string) => { + const issuerPath = path === "/" ? "" : path; + const authPath = path === "/" ? "" : path; + const protectedResourceRoute = "/.well-known/oauth-protected-resource"; + routeIfMissing(http, "/.well-known/openid-configuration", () => { + const url = `${getConvexSiteUrl()}${authPath}/convex/.well-known/openid-configuration`; + return Response.redirect(url); + }); + if (issuerPath) { + routeIfMissing( + http, + `/.well-known/openid-configuration${issuerPath}`, + () => { + const url = `${getConvexSiteUrl()}${authPath}/convex/.well-known/openid-configuration`; + return Response.redirect(url); + } + ); + } + routeIfMissing(http, "/.well-known/oauth-authorization-server", () => { + const url = `${getConvexSiteUrl()}${authPath}/convex/.well-known/oauth-authorization-server`; + return Response.redirect(url); + }); + if (issuerPath) { + routeIfMissing( + http, + `/.well-known/oauth-authorization-server${issuerPath}`, + () => { + const url = `${getConvexSiteUrl()}${authPath}/convex/.well-known/oauth-authorization-server`; + return Response.redirect(url); + } + ); + } + routeIfMissing(http, protectedResourceRoute, () => + jsonResponse(protectedResourceMetadata(path)) + ); + if (issuerPath) { + routeIfMissing(http, `${protectedResourceRoute}${issuerPath}`, () => + jsonResponse(protectedResourceMetadata(path)) + ); + } + if (!http.lookup(`${protectedResourceRoute}/_probe_`, "GET")) { + http.route({ + pathPrefix: `${protectedResourceRoute}/`, + method: "GET", + handler: httpActionGeneric(async (_ctx, request) => { + const pathname = new URL(request.url).pathname; + const resourcePath = pathname.slice(protectedResourceRoute.length); + return jsonResponse(protectedResourceMetadata(resourcePath)); + }), + }); + } +}; + /** * Backend API for the Better Auth component. * Responsible for exposing the `client` and `triggers` APIs to the client, http @@ -402,20 +500,7 @@ export const createClient = < } return response; }); - const wellKnown = http.lookup("/.well-known/openid-configuration", "GET"); - - // If registerRoutes is used multiple times, this may already be defined - if (!wellKnown) { - // Redirect root well-known to api well-known - http.route({ - path: "/.well-known/openid-configuration", - method: "GET", - handler: httpActionGeneric(async () => { - const url = `${process.env.CONVEX_SITE_URL}${path}/convex/.well-known/openid-configuration`; - return Response.redirect(url); - }), - }); - } + registerWellKnownRoutes(http, path); if (!opts.cors) { http.route({ @@ -472,7 +557,7 @@ export const createClient = < "Better-Auth-Cookie", "Authorization", ].concat(corsOpts.allowedHeaders ?? []), - exposedHeaders: ["Set-Better-Auth-Cookie"].concat( + exposedHeaders: ["Set-Better-Auth-Cookie", "WWW-Authenticate"].concat( corsOpts.exposedHeaders ?? [] ), debug: config?.verbose, @@ -504,7 +589,8 @@ export const createClient = < return registrationAuth; }; - const path = opts.basePath ?? "/api/auth"; + const path = + opts.basePath ?? getRegistrationAuth().options.basePath ?? "/api/auth"; let trustedOriginsOption = opts.trustedOrigins; const authRequestHandler = httpActionGeneric(async (ctx, request) => { if (config?.verbose) { @@ -522,20 +608,7 @@ export const createClient = < } return response; }); - const wellKnown = http.lookup("/.well-known/openid-configuration", "GET"); - - // If registerRoutes is used multiple times, this may already be defined - if (!wellKnown) { - // Redirect root well-known to api well-known - http.route({ - path: "/.well-known/openid-configuration", - method: "GET", - handler: httpActionGeneric(async () => { - const url = `${process.env.CONVEX_SITE_URL}${path}/convex/.well-known/openid-configuration`; - return Response.redirect(url); - }), - }); - } + registerWellKnownRoutes(http, path); if (!opts.cors) { http.route({ @@ -585,7 +658,7 @@ export const createClient = < "Better-Auth-Cookie", "Authorization", ].concat(corsOpts.allowedHeaders ?? []), - exposedHeaders: ["Set-Better-Auth-Cookie"].concat( + exposedHeaders: ["Set-Better-Auth-Cookie", "WWW-Authenticate"].concat( corsOpts.exposedHeaders ?? [] ), debug: config?.verbose, diff --git a/src/client/create-schema.test.ts b/src/client/create-schema.test.ts new file mode 100644 index 00000000..624e62b0 --- /dev/null +++ b/src/client/create-schema.test.ts @@ -0,0 +1,54 @@ +import { describe, expect, it } from "vitest"; +import { createSchema } from "./create-schema.js"; + +describe("createSchema oauth-provider tables", () => { + it("generates array fields and oauth-provider indexes", async () => { + const { code } = await createSchema({ + tables: { + oauthClient: { + modelName: "oauthClient", + fields: { + id: { type: "string" }, + clientId: { type: "string", required: true, unique: true }, + redirectUris: { type: "string[]", required: true }, + scopes: { type: "string[]", required: false }, + userId: { + type: "string", + required: false, + references: { model: "user", field: "id" }, + }, + referenceId: { type: "string", required: false }, + }, + }, + oauthConsent: { + modelName: "oauthConsent", + fields: { + id: { type: "string" }, + clientId: { + type: "string", + required: true, + references: { model: "oauthClient", field: "id" }, + }, + userId: { + type: "string", + required: false, + references: { model: "user", field: "id" }, + }, + referenceId: { type: "string", required: false }, + scopes: { type: "string[]", required: true }, + }, + }, + } as any, + }); + + expect(code).toContain("redirectUris: v.array(v.string())"); + expect(code).toContain( + "scopes: v.optional(v.union(v.null(), v.array(v.string())))" + ); + expect(code).toContain('.index("clientId", ["clientId"])'); + expect(code).toContain('.index("referenceId", ["referenceId"])'); + expect(code).toContain( + '.index("clientId_userId_referenceId", ["clientId","userId","referenceId"])' + ); + }); +}); diff --git a/src/client/create-schema.ts b/src/client/create-schema.ts index 464274c0..edc60f68 100644 --- a/src/client/create-schema.ts +++ b/src/client/create-schema.ts @@ -21,7 +21,22 @@ export const indexFields = { session: ["expiresAt", ["expiresAt", "userId"]], verification: ["expiresAt", "identifier"], user: [["email", "name"], "name", "userId"], - oauthConsent: [["clientId", "userId"]], + oauthClient: ["clientId", "userId", "referenceId"], + oauthRefreshToken: ["token", "clientId", "sessionId", "userId", "referenceId"], + oauthAccessToken: [ + "token", + "clientId", + "sessionId", + "userId", + "refreshId", + "referenceId", + ], + oauthConsent: [ + ["clientId", "userId"], + ["clientId", "userId", "referenceId"], + "userId", + "referenceId", + ], }; // Return map of unique, sortable, and reference fields @@ -167,7 +182,7 @@ export const tables = { mergedIndexFields(tables)[ tableKey as keyof typeof mergedIndexFields ]?.map((index) => { - const indexArray = Array.isArray(index) ? index.sort() : [index]; + const indexArray = Array.isArray(index) ? index : [index]; const indexName = indexArray.join("_"); return `.index("${indexName}", ${JSON.stringify(indexArray)})`; }) || []; diff --git a/src/component/_generated/component.ts b/src/component/_generated/component.ts index b7e27676..a93d28d0 100644 --- a/src/component/_generated/component.ts +++ b/src/component/_generated/component.ts @@ -97,53 +97,86 @@ export type ComponentApi = } | { data: { - clientId?: null | string; + createdAt: number; + expiresAt?: null | number; + privateKey: string; + publicKey: string; + }; + model: "jwks"; + } + | { + data: { + clientId: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; - model: "oauthApplication"; + model: "oauthClient"; } | { data: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes: Array; + sessionId?: null | string; + token: string; + userId: string; }; - model: "oauthAccessToken"; + model: "oauthRefreshToken"; } | { data: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; - model: "oauthConsent"; + model: "oauthAccessToken"; } | { data: { - createdAt: number; - expiresAt?: null | number; - privateKey: string; - publicKey: string; + clientId: string; + createdAt?: null | number; + referenceId?: null | string; + scopes: Array; + updatedAt?: null | number; + userId?: null | string; }; - model: "jwks"; + model: "oauthConsent"; } | { data: { count: number; key: string; lastRequest: number }; @@ -342,21 +375,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -381,19 +464,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -418,16 +502,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -452,14 +539,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -710,21 +799,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -749,19 +888,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -786,16 +926,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -820,14 +963,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -895,10 +1040,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit"; offset?: number; paginationOpts: { @@ -950,10 +1096,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit"; select?: Array; where?: Array<{ @@ -1222,34 +1369,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; update: { - clientId?: null | string; + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; + update: { + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -1274,30 +1495,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -1322,24 +1545,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -1364,20 +1593,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -1680,34 +1913,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; update: { - clientId?: null | string; + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; + update: { + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -1732,30 +2039,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -1780,24 +2089,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -1822,20 +2137,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -1973,53 +2292,86 @@ export type ComponentApi = } | { data: { - clientId?: null | string; + createdAt: number; + expiresAt?: null | number; + privateKey: string; + publicKey: string; + }; + model: "jwks"; + } + | { + data: { + clientId: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; - model: "oauthApplication"; + model: "oauthClient"; } | { data: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes: Array; + sessionId?: null | string; + token: string; + userId: string; }; - model: "oauthAccessToken"; + model: "oauthRefreshToken"; } | { data: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; - model: "oauthConsent"; + model: "oauthAccessToken"; } | { data: { - createdAt: number; - expiresAt?: null | number; - privateKey: string; - publicKey: string; + clientId: string; + createdAt?: null | number; + referenceId?: null | string; + scopes: Array; + updatedAt?: null | number; + userId?: null | string; }; - model: "jwks"; + model: "oauthConsent"; } | { data: { count: number; key: string; lastRequest: number }; @@ -2223,21 +2575,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -2262,19 +2664,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -2299,16 +2702,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -2333,14 +2739,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -2596,21 +3004,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -2635,19 +3093,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -2672,16 +3131,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -2706,14 +3168,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -2781,10 +3245,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit"; offset?: number; paginationOpts: { @@ -2836,10 +3301,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit"; select?: Array; where?: Array<{ @@ -3118,34 +3584,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -3170,30 +3710,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -3218,24 +3760,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -3260,20 +3808,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -3590,34 +4142,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -3642,30 +4268,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -3690,24 +4318,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -3732,20 +4366,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -3887,53 +4525,86 @@ export type ComponentApi = } | { data: { - clientId?: null | string; + createdAt: number; + expiresAt?: null | number; + privateKey: string; + publicKey: string; + }; + model: "jwks"; + } + | { + data: { + clientId: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; - model: "oauthApplication"; + model: "oauthClient"; } | { data: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes: Array; + sessionId?: null | string; + token: string; + userId: string; }; - model: "oauthAccessToken"; + model: "oauthRefreshToken"; } | { data: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; - model: "oauthConsent"; + model: "oauthAccessToken"; } | { data: { - createdAt: number; - expiresAt?: null | number; - privateKey: string; - publicKey: string; + clientId: string; + createdAt?: null | number; + referenceId?: null | string; + scopes: Array; + updatedAt?: null | number; + userId?: null | string; }; - model: "jwks"; + model: "oauthConsent"; } | { data: { count: number; key: string; lastRequest: number }; @@ -4257,21 +4928,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -4296,19 +5017,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -4333,16 +5055,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -4367,14 +5092,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -4976,21 +5703,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -5015,19 +5792,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -5052,16 +5830,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -5086,14 +5867,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -5506,10 +6289,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit" | "user_custom" | "user_table" @@ -5571,10 +6355,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit" | "user_custom" | "user_table" @@ -5865,34 +6650,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -5917,30 +6776,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -5965,24 +6826,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -6007,20 +6874,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; - update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + model: "oauthConsent"; + update: { + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -6776,34 +7647,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -6828,30 +7773,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -6876,24 +7823,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -6918,20 +7871,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -7510,53 +8467,86 @@ export type ComponentApi = } | { data: { - clientId?: null | string; + createdAt: number; + expiresAt?: null | number; + privateKey: string; + publicKey: string; + }; + model: "jwks"; + } + | { + data: { + clientId: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; - model: "oauthApplication"; + model: "oauthClient"; } | { data: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes: Array; + sessionId?: null | string; + token: string; + userId: string; }; - model: "oauthAccessToken"; + model: "oauthRefreshToken"; } | { data: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; - model: "oauthConsent"; + model: "oauthAccessToken"; } | { data: { - createdAt: number; - expiresAt?: null | number; - privateKey: string; - publicKey: string; + clientId: string; + createdAt?: null | number; + referenceId?: null | string; + scopes: Array; + updatedAt?: null | number; + userId?: null | string; }; - model: "jwks"; + model: "oauthConsent"; } | { data: { count: number; key: string; lastRequest: number }; @@ -7880,21 +8870,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -7919,19 +8959,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -7956,16 +8997,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -7990,14 +9034,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -8599,21 +9645,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -8638,19 +9734,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -8675,16 +9772,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -8709,14 +9809,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -9129,10 +10231,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit" | "user_custom" | "user_table" @@ -9194,10 +10297,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit" | "user_custom" | "user_table" @@ -9488,34 +10592,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -9540,30 +10718,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -9588,24 +10768,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -9630,20 +10816,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -10399,34 +11589,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -10451,30 +11715,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -10499,24 +11765,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -10541,20 +11813,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -11133,53 +12409,86 @@ export type ComponentApi = } | { data: { - clientId?: null | string; + createdAt: number; + expiresAt?: null | number; + privateKey: string; + publicKey: string; + }; + model: "jwks"; + } + | { + data: { + clientId: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; - model: "oauthApplication"; + model: "oauthClient"; } | { data: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes: Array; + sessionId?: null | string; + token: string; + userId: string; }; - model: "oauthAccessToken"; + model: "oauthRefreshToken"; } | { data: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; - model: "oauthConsent"; + model: "oauthAccessToken"; } | { data: { - createdAt: number; - expiresAt?: null | number; - privateKey: string; - publicKey: string; + clientId: string; + createdAt?: null | number; + referenceId?: null | string; + scopes: Array; + updatedAt?: null | number; + userId?: null | string; }; - model: "jwks"; + model: "oauthConsent"; } | { data: { count: number; key: string; lastRequest: number }; @@ -11471,14 +12780,46 @@ export type ComponentApi = }>; } | { - model: "twoFactor"; + model: "twoFactor"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "secret" + | "backupCodes" + | "userId" + | "verified" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "jwks"; where?: Array<{ connector?: "AND" | "OR"; field: - | "secret" - | "backupCodes" - | "userId" - | "verified" + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -11503,21 +12844,39 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -11542,19 +12901,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -11579,16 +12939,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -11613,14 +12976,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -12222,21 +13587,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -12261,19 +13676,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -12298,16 +13714,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -12332,14 +13751,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -12752,10 +14173,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit" | "user_custom" | "user_table" @@ -12817,10 +14239,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit" | "user_custom" | "user_table" @@ -13111,34 +14534,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -13163,30 +14660,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -13211,24 +14710,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -13253,20 +14758,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -14022,34 +15531,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -14074,30 +15657,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -14122,24 +15707,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -14164,20 +15755,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -14756,53 +16351,86 @@ export type ComponentApi = } | { data: { - clientId?: null | string; + createdAt: number; + expiresAt?: null | number; + privateKey: string; + publicKey: string; + }; + model: "jwks"; + } + | { + data: { + clientId: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; - model: "oauthApplication"; + model: "oauthClient"; } | { data: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes: Array; + sessionId?: null | string; + token: string; + userId: string; }; - model: "oauthAccessToken"; + model: "oauthRefreshToken"; } | { data: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; - model: "oauthConsent"; + model: "oauthAccessToken"; } | { data: { - createdAt: number; - expiresAt?: null | number; - privateKey: string; - publicKey: string; + clientId: string; + createdAt?: null | number; + referenceId?: null | string; + scopes: Array; + updatedAt?: null | number; + userId?: null | string; }; - model: "jwks"; + model: "oauthConsent"; } | { data: { count: number; key: string; lastRequest: number }; @@ -15126,21 +16754,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -15165,19 +16843,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -15202,16 +16881,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -15236,14 +16918,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -15845,21 +17529,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -15884,19 +17618,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -15921,16 +17656,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -15955,14 +17693,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -16375,10 +18115,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit" | "user_custom" | "user_table" @@ -16440,10 +18181,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit" | "user_custom" | "user_table" @@ -16698,18 +18440,56 @@ export type ComponentApi = | { model: "twoFactor"; update: { - backupCodes?: string; - secret?: string; - userId?: string; - verified?: null | boolean; + backupCodes?: string; + secret?: string; + userId?: string; + verified?: null | boolean; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "secret" + | "backupCodes" + | "userId" + | "verified" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "secret" - | "backupCodes" - | "userId" - | "verified" + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -16734,34 +18514,70 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -16786,30 +18602,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -16834,24 +18652,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -16876,20 +18700,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -17645,34 +19473,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -17697,30 +19599,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -17745,24 +19649,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -17787,20 +19697,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -18379,53 +20293,86 @@ export type ComponentApi = } | { data: { - clientId?: null | string; + createdAt: number; + expiresAt?: null | number; + privateKey: string; + publicKey: string; + }; + model: "jwks"; + } + | { + data: { + clientId: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; - model: "oauthApplication"; + model: "oauthClient"; } | { data: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes: Array; + sessionId?: null | string; + token: string; + userId: string; }; - model: "oauthAccessToken"; + model: "oauthRefreshToken"; } | { data: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; - model: "oauthConsent"; + model: "oauthAccessToken"; } | { data: { - createdAt: number; - expiresAt?: null | number; - privateKey: string; - publicKey: string; + clientId: string; + createdAt?: null | number; + referenceId?: null | string; + scopes: Array; + updatedAt?: null | number; + userId?: null | string; }; - model: "jwks"; + model: "oauthConsent"; } | { data: { count: number; key: string; lastRequest: number }; @@ -18749,21 +20696,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -18788,19 +20785,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -18825,16 +20823,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -18859,14 +20860,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -19468,21 +21471,71 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -19507,19 +21560,20 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -19544,16 +21598,19 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -19578,14 +21635,16 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -19998,10 +22057,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit" | "user_custom" | "user_table" @@ -20063,10 +22123,11 @@ export type ComponentApi = | "account" | "verification" | "twoFactor" - | "oauthApplication" + | "jwks" + | "oauthClient" + | "oauthRefreshToken" | "oauthAccessToken" | "oauthConsent" - | "jwks" | "rateLimit" | "user_custom" | "user_table" @@ -20357,34 +22418,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -20409,30 +22544,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -20457,24 +22594,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -20499,20 +22642,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -21268,34 +23415,108 @@ export type ComponentApi = }>; } | { - model: "oauthApplication"; + model: "jwks"; + update: { + createdAt?: number; + expiresAt?: null | number; + privateKey?: string; + publicKey?: string; + }; + where?: Array<{ + connector?: "AND" | "OR"; + field: + | "publicKey" + | "privateKey" + | "createdAt" + | "expiresAt" + | "_id"; + mode?: "sensitive" | "insensitive"; + operator?: + | "lt" + | "lte" + | "gt" + | "gte" + | "eq" + | "in" + | "not_in" + | "ne" + | "contains" + | "starts_with" + | "ends_with"; + value: + | string + | number + | boolean + | Array + | Array + | null; + }>; + } + | { + model: "oauthClient"; update: { - clientId?: null | string; + clientId?: string; clientSecret?: null | string; + contacts?: null | Array; createdAt?: null | number; disabled?: null | boolean; + enableEndSession?: null | boolean; + grantTypes?: null | Array; icon?: null | string; metadata?: null | string; name?: null | string; - redirectUrls?: null | string; + policy?: null | string; + postLogoutRedirectUris?: null | Array; + public?: null | boolean; + redirectUris?: Array; + referenceId?: null | string; + requirePKCE?: null | boolean; + responseTypes?: null | Array; + scopes?: null | Array; + skipConsent?: null | boolean; + softwareId?: null | string; + softwareStatement?: null | string; + softwareVersion?: null | string; + subjectType?: null | string; + tokenEndpointAuthMethod?: null | string; + tos?: null | string; type?: null | string; updatedAt?: null | number; + uri?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "name" - | "icon" - | "metadata" | "clientId" | "clientSecret" - | "redirectUrls" - | "type" | "disabled" + | "skipConsent" + | "enableEndSession" + | "subjectType" + | "scopes" | "userId" | "createdAt" | "updatedAt" + | "name" + | "uri" + | "icon" + | "contacts" + | "tos" + | "policy" + | "softwareId" + | "softwareVersion" + | "softwareStatement" + | "redirectUris" + | "postLogoutRedirectUris" + | "tokenEndpointAuthMethod" + | "grantTypes" + | "responseTypes" + | "public" + | "type" + | "requirePKCE" + | "referenceId" + | "metadata" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -21320,30 +23541,32 @@ export type ComponentApi = }>; } | { - model: "oauthAccessToken"; + model: "oauthRefreshToken"; update: { - accessToken?: null | string; - accessTokenExpiresAt?: null | number; - clientId?: null | string; + authTime?: null | number; + clientId?: string; createdAt?: null | number; - refreshToken?: null | string; - refreshTokenExpiresAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; - userId?: null | string; + expiresAt?: null | number; + referenceId?: null | string; + revoked?: null | number; + scopes?: Array; + sessionId?: null | string; + token?: string; + userId?: string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "accessToken" - | "refreshToken" - | "accessTokenExpiresAt" - | "refreshTokenExpiresAt" + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "expiresAt" | "createdAt" - | "updatedAt" + | "revoked" + | "authTime" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -21368,24 +23591,30 @@ export type ComponentApi = }>; } | { - model: "oauthConsent"; + model: "oauthAccessToken"; update: { - clientId?: null | string; - consentGiven?: null | boolean; + clientId?: string; createdAt?: null | number; - scopes?: null | string; - updatedAt?: null | number; + expiresAt?: null | number; + referenceId?: null | string; + refreshId?: null | string; + scopes?: Array; + sessionId?: null | string; + token?: null | string; userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: + | "token" | "clientId" + | "sessionId" | "userId" - | "scopes" + | "referenceId" + | "refreshId" + | "expiresAt" | "createdAt" - | "updatedAt" - | "consentGiven" + | "scopes" | "_id"; mode?: "sensitive" | "insensitive"; operator?: @@ -21410,20 +23639,24 @@ export type ComponentApi = }>; } | { - model: "jwks"; + model: "oauthConsent"; update: { - createdAt?: number; - expiresAt?: null | number; - privateKey?: string; - publicKey?: string; + clientId?: string; + createdAt?: null | number; + referenceId?: null | string; + scopes?: Array; + updatedAt?: null | number; + userId?: null | string; }; where?: Array<{ connector?: "AND" | "OR"; field: - | "publicKey" - | "privateKey" + | "clientId" + | "userId" + | "referenceId" + | "scopes" | "createdAt" - | "expiresAt" + | "updatedAt" | "_id"; mode?: "sensitive" | "insensitive"; operator?: diff --git a/src/component/schema.ts b/src/component/schema.ts index 8b5ecc1c..272f2a63 100644 --- a/src/component/schema.ts +++ b/src/component/schema.ts @@ -80,52 +80,92 @@ export const tables = { verified: v.optional(v.union(v.null(), v.boolean())), }) .index("userId", ["userId"]), - oauthApplication: defineTable({ - name: v.optional(v.union(v.null(), v.string())), - icon: v.optional(v.union(v.null(), v.string())), - metadata: v.optional(v.union(v.null(), v.string())), - clientId: v.optional(v.union(v.null(), v.string())), + jwks: defineTable({ + publicKey: v.string(), + privateKey: v.string(), + createdAt: v.number(), + expiresAt: v.optional(v.union(v.null(), v.number())), + }), + oauthClient: defineTable({ + clientId: v.string(), clientSecret: v.optional(v.union(v.null(), v.string())), - redirectUrls: v.optional(v.union(v.null(), v.string())), - type: v.optional(v.union(v.null(), v.string())), disabled: v.optional(v.union(v.null(), v.boolean())), + skipConsent: v.optional(v.union(v.null(), v.boolean())), + enableEndSession: v.optional(v.union(v.null(), v.boolean())), + subjectType: v.optional(v.union(v.null(), v.string())), + scopes: v.optional(v.union(v.null(), v.array(v.string()))), userId: v.optional(v.union(v.null(), v.string())), createdAt: v.optional(v.union(v.null(), v.number())), updatedAt: v.optional(v.union(v.null(), v.number())), + name: v.optional(v.union(v.null(), v.string())), + uri: v.optional(v.union(v.null(), v.string())), + icon: v.optional(v.union(v.null(), v.string())), + contacts: v.optional(v.union(v.null(), v.array(v.string()))), + tos: v.optional(v.union(v.null(), v.string())), + policy: v.optional(v.union(v.null(), v.string())), + softwareId: v.optional(v.union(v.null(), v.string())), + softwareVersion: v.optional(v.union(v.null(), v.string())), + softwareStatement: v.optional(v.union(v.null(), v.string())), + redirectUris: v.array(v.string()), + postLogoutRedirectUris: v.optional(v.union(v.null(), v.array(v.string()))), + tokenEndpointAuthMethod: v.optional(v.union(v.null(), v.string())), + grantTypes: v.optional(v.union(v.null(), v.array(v.string()))), + responseTypes: v.optional(v.union(v.null(), v.array(v.string()))), + public: v.optional(v.union(v.null(), v.boolean())), + type: v.optional(v.union(v.null(), v.string())), + requirePKCE: v.optional(v.union(v.null(), v.boolean())), + referenceId: v.optional(v.union(v.null(), v.string())), + metadata: v.optional(v.union(v.null(), v.string())), }) .index("clientId", ["clientId"]) - .index("userId", ["userId"]), + .index("userId", ["userId"]) + .index("referenceId", ["referenceId"]), + oauthRefreshToken: defineTable({ + token: v.string(), + clientId: v.string(), + sessionId: v.optional(v.union(v.null(), v.string())), + userId: v.string(), + referenceId: v.optional(v.union(v.null(), v.string())), + expiresAt: v.optional(v.union(v.null(), v.number())), + createdAt: v.optional(v.union(v.null(), v.number())), + revoked: v.optional(v.union(v.null(), v.number())), + authTime: v.optional(v.union(v.null(), v.number())), + scopes: v.array(v.string()), + }) + .index("token", ["token"]) + .index("clientId", ["clientId"]) + .index("sessionId", ["sessionId"]) + .index("userId", ["userId"]) + .index("referenceId", ["referenceId"]), oauthAccessToken: defineTable({ - accessToken: v.optional(v.union(v.null(), v.string())), - refreshToken: v.optional(v.union(v.null(), v.string())), - accessTokenExpiresAt: v.optional(v.union(v.null(), v.number())), - refreshTokenExpiresAt: v.optional(v.union(v.null(), v.number())), - clientId: v.optional(v.union(v.null(), v.string())), + token: v.optional(v.union(v.null(), v.string())), + clientId: v.string(), + sessionId: v.optional(v.union(v.null(), v.string())), userId: v.optional(v.union(v.null(), v.string())), - scopes: v.optional(v.union(v.null(), v.string())), + referenceId: v.optional(v.union(v.null(), v.string())), + refreshId: v.optional(v.union(v.null(), v.string())), + expiresAt: v.optional(v.union(v.null(), v.number())), createdAt: v.optional(v.union(v.null(), v.number())), - updatedAt: v.optional(v.union(v.null(), v.number())), + scopes: v.array(v.string()), }) - .index("accessToken", ["accessToken"]) - .index("refreshToken", ["refreshToken"]) + .index("token", ["token"]) .index("clientId", ["clientId"]) - .index("userId", ["userId"]), + .index("sessionId", ["sessionId"]) + .index("userId", ["userId"]) + .index("refreshId", ["refreshId"]) + .index("referenceId", ["referenceId"]), oauthConsent: defineTable({ - clientId: v.optional(v.union(v.null(), v.string())), + clientId: v.string(), userId: v.optional(v.union(v.null(), v.string())), - scopes: v.optional(v.union(v.null(), v.string())), + referenceId: v.optional(v.union(v.null(), v.string())), + scopes: v.array(v.string()), createdAt: v.optional(v.union(v.null(), v.number())), updatedAt: v.optional(v.union(v.null(), v.number())), - consentGiven: v.optional(v.union(v.null(), v.boolean())), }) .index("clientId_userId", ["clientId","userId"]) - .index("userId", ["userId"]), - jwks: defineTable({ - publicKey: v.string(), - privateKey: v.string(), - createdAt: v.number(), - expiresAt: v.optional(v.union(v.null(), v.number())), - }), + .index("clientId_userId_referenceId", ["clientId","userId","referenceId"]) + .index("userId", ["userId"]) + .index("referenceId", ["referenceId"]), rateLimit: defineTable({ key: v.string(), count: v.number(), diff --git a/src/plugins/convex/index.test.ts b/src/plugins/convex/index.test.ts index 8c7cb984..89ca30e9 100644 --- a/src/plugins/convex/index.test.ts +++ b/src/plugins/convex/index.test.ts @@ -27,6 +27,27 @@ const getJwtSetCookieMatcher = () => { return matcher; }; +const getJwtClearCookieMatcher = () => { + const plugin = convex({ authConfig }); + const afterHooks = plugin.hooks?.after ?? []; + const matcher = afterHooks.find((hook) => { + return ( + hook.matcher({ + path: "/sign-out", + context: { session: null }, + } as unknown as Parameters[0]) && + !hook.matcher({ + path: "/sign-in/email", + context: { session: { id: "s1" } }, + } as unknown as Parameters[0]) + ); + })?.matcher; + if (!matcher) { + throw new Error("Failed to find Convex JWT clear-cookie after hook matcher"); + } + return matcher; +}; + describe("convex plugin JWT cookie refresh matcher", () => { it("matches update-session", () => { const matcher = getJwtSetCookieMatcher(); @@ -53,3 +74,138 @@ describe("convex plugin JWT cookie refresh matcher", () => { expect(matcher(withoutSessionCtx as unknown as MatcherContext)).toBe(false); }); }); + +describe("convex plugin JWT cookie clearing matcher", () => { + it("matches oauth2 end-session", () => { + const matcher = getJwtClearCookieMatcher(); + type MatcherContext = Parameters[0]; + const ctx = { + path: "/oauth2/end-session", + context: { session: null }, + }; + expect(matcher(ctx as unknown as MatcherContext)).toBe(true); + }); +}); + +describe("convex plugin OAuth provider options", () => { + it("defaults to an inert login page unless OAuth is configured", () => { + const plugin = convex({ authConfig }); + expect(plugin.options?.oauthProvider.loginPage).toBe("/not-used"); + }); + + it("allows overriding the OAuth login page", () => { + const plugin = convex({ + authConfig, + oauthProvider: { loginPage: "https://app.example.com/sign-in" }, + }); + expect(plugin.options?.oauthProvider.loginPage).toBe( + "https://app.example.com/sign-in" + ); + }); +}); + +describe("convex plugin OAuth metadata", () => { + it("uses the Convex site URL for issuer and endpoints", async () => { + const originalConvexSiteUrl = process.env.CONVEX_SITE_URL; + process.env.CONVEX_SITE_URL = "https://deployment.convex.site"; + try { + const plugin = convex({ authConfig }); + const getOAuthServerConfig = plugin.endpoints?.getOAuthServerConfig; + expect(getOAuthServerConfig).toBeDefined(); + + const response = await getOAuthServerConfig!({ + context: { + baseURL: "https://app.example.com", + getPlugin(pluginId: string) { + if (pluginId !== "jwt") { + return null; + } + return { + options: { + jwt: { + issuer: "https://deployment.convex.site", + }, + jwks: { + jwksPath: "/convex/jwks", + keyPairConfig: { alg: "RS256" }, + }, + }, + }; + }, + }, + asResponse: false, + returnHeaders: false, + returnStatus: false, + } as any); + + expect(response).toMatchObject({ + issuer: "https://deployment.convex.site", + authorization_endpoint: + "https://deployment.convex.site/api/auth/oauth2/authorize", + token_endpoint: "https://deployment.convex.site/api/auth/oauth2/token", + jwks_uri: "https://deployment.convex.site/api/auth/convex/jwks", + }); + } finally { + if (originalConvexSiteUrl === undefined) { + delete process.env.CONVEX_SITE_URL; + } else { + process.env.CONVEX_SITE_URL = originalConvexSiteUrl; + } + } + }); + + it("uses the configured auth basePath for OAuth endpoints", async () => { + const originalConvexSiteUrl = process.env.CONVEX_SITE_URL; + process.env.CONVEX_SITE_URL = "https://deployment.convex.site"; + try { + const plugin = convex({ + authConfig, + options: { + basePath: "/custom/auth", + } as any, + }); + const getOAuthServerConfig = plugin.endpoints?.getOAuthServerConfig; + expect(getOAuthServerConfig).toBeDefined(); + + const response = await getOAuthServerConfig!({ + context: { + baseURL: "https://app.example.com", + getPlugin(pluginId: string) { + if (pluginId !== "jwt") { + return null; + } + return { + options: { + jwt: { + issuer: "https://deployment.convex.site", + }, + jwks: { + jwksPath: "/convex/jwks", + keyPairConfig: { alg: "RS256" }, + }, + }, + }; + }, + }, + asResponse: false, + returnHeaders: false, + returnStatus: false, + } as any); + + expect(response).toMatchObject({ + issuer: "https://deployment.convex.site", + authorization_endpoint: + "https://deployment.convex.site/custom/auth/oauth2/authorize", + token_endpoint: + "https://deployment.convex.site/custom/auth/oauth2/token", + jwks_uri: "https://deployment.convex.site/custom/auth/convex/jwks", + }); + } finally { + if (originalConvexSiteUrl === undefined) { + delete process.env.CONVEX_SITE_URL; + } else { + process.env.CONVEX_SITE_URL = originalConvexSiteUrl; + } + } + }); +}); diff --git a/src/plugins/convex/index.ts b/src/plugins/convex/index.ts index db4cce2c..9d6fc55d 100644 --- a/src/plugins/convex/index.ts +++ b/src/plugins/convex/index.ts @@ -1,5 +1,7 @@ import type { BetterAuthPlugin, Session, User } from "better-auth"; import type { BetterAuthOptions } from "better-auth/minimal"; +import { oauthProvider as oauthProviderPlugin } from "@better-auth/oauth-provider"; +import type { OAuthOptions, Scope } from "@better-auth/oauth-provider"; import { createAuthEndpoint, createAuthMiddleware, @@ -8,7 +10,6 @@ import { import { bearer as bearerPlugin } from "better-auth/plugins/bearer"; import { jwt as jwtPlugin } from "better-auth/plugins/jwt"; import type { JwtOptions, Jwk } from "better-auth/plugins/jwt"; -import { oidcProvider as oidcProviderPlugin } from "better-auth/plugins/oidc-provider"; import { omit } from "convex-helpers"; import type { AuthConfig, AuthProvider } from "convex/server"; import { VERSION } from "../../version.js"; @@ -18,15 +19,40 @@ export const JWT_COOKIE_NAME = "convex_jwt"; type BetterAuthAfterHooks = NonNullable< NonNullable["after"] >; +type BetterAuthBeforeHooks = NonNullable< + NonNullable["before"] +>; type BetterAuthAfterHook = BetterAuthAfterHooks[number]; +type BetterAuthBeforeHook = BetterAuthBeforeHooks[number]; type BetterAuthHookContext = Parameters[0]; +const normalizeBeforeHooks = ( + hooks: THook[] = [] +): BetterAuthBeforeHooks => { + return hooks.map((hook) => ({ + ...hook, + matcher: (ctx: BetterAuthHookContext) => { + try { + return Boolean(hook.matcher(ctx)); + } catch { + return false; + } + }, + })); +}; + const normalizeAfterHooks = ( - hooks: THook[] + hooks: THook[] = [] ): BetterAuthAfterHooks => { return hooks.map((hook) => ({ ...hook, - matcher: (ctx: BetterAuthHookContext) => Boolean(hook.matcher(ctx)), + matcher: (ctx: BetterAuthHookContext) => { + try { + return Boolean(hook.matcher(ctx)); + } catch { + return false; + } + }, })); }; @@ -74,6 +100,26 @@ const parseAuthConfig = (authConfig: AuthConfig, opts: { jwks?: string }) => { return providerConfig; }; +type ConvexOAuthProviderOptions = Partial< + Omit, "disableJwtPlugin" | "schema"> +>; + +const normalizeBasePath = (basePath?: string) => + !basePath || basePath === "/" ? "" : basePath; + +const withConvexSiteBaseURL = ( + ctx: TCtx, + basePath?: string +): TCtx => ({ + ...ctx, + context: { + ...ctx.context, + baseURL: process.env.CONVEX_SITE_URL + ? `${process.env.CONVEX_SITE_URL}${normalizeBasePath(basePath)}` + : ctx.context.baseURL, + }, +}); + export const convex = (opts: { /** * @param {AuthConfig} authConfig - Auth config from your Convex project. @@ -170,20 +216,19 @@ export const convex = (opts: { jwksRotateOnTokenGenerationError?: boolean; /** * @param {BetterAuthOptions} options - Better Auth options. Not required, - * currently used to pass the basePath to the oidcProvider plugin. + * currently used to pass the basePath to the oauthProvider plugin. */ options?: BetterAuthOptions; + /** + * OAuth 2.1 / OIDC authorization server configuration. + * + * The Convex plugin provides the required jwt plugin integration + * internally, so do not set disableJwtPlugin here. + */ + oauthProvider?: ConvexOAuthProviderOptions; }) => { const jwtExpirationSeconds = opts.jwt?.expirationSeconds ?? opts.jwtExpirationSeconds ?? 60 * 15; - const oidcProvider = oidcProviderPlugin({ - loginPage: "/not-used", - metadata: { - issuer: `${process.env.CONVEX_SITE_URL}`, - jwks_uri: `${process.env.CONVEX_SITE_URL}${opts.options?.basePath ?? "/api/auth"}/convex/jwks`, - }, - __skipDeprecationWarning: true, - }); const providerConfig = parseAuthConfig(opts.authConfig, opts); const jwtOptions = { @@ -242,6 +287,33 @@ export const convex = (opts: { }, }, }); + const oauthProviderOptions = opts.oauthProvider ?? {}; + const oauthProvider = oauthProviderPlugin({ + loginPage: oauthProviderOptions.loginPage ?? "/not-used", + consentPage: oauthProviderOptions.consentPage ?? "/oauth2/consent", + allowDynamicClientRegistration: + oauthProviderOptions.allowDynamicClientRegistration ?? false, + allowUnauthenticatedClientRegistration: + oauthProviderOptions.allowUnauthenticatedClientRegistration ?? false, + ...oauthProviderOptions, + disableJwtPlugin: false, + silenceWarnings: { + oauthAuthServerConfig: true, + openidConfig: true, + ...oauthProviderOptions.silenceWarnings, + }, + }); + const { + getOpenIdConfig: oauthProviderGetOpenIdConfig, + getOAuthServerConfig: oauthProviderGetOAuthServerConfig, + ...oauthProviderEndpoints + } = oauthProvider.endpoints; + const getOAuthProviderBasePath = (ctx?: { + context?: { options?: { basePath?: string } }; + }) => ctx?.context?.options?.basePath ?? opts.options?.basePath ?? "/api/auth"; + const publicOptions: Record = { + oauthProvider: oauthProvider.options, + }; // Bearer plugin converts the session token to a cookie // for cross domain social login after code verification, // and is required for the headers() helper to work. @@ -250,14 +322,29 @@ export const convex = (opts: { user: { fields: { userId: { type: "string", required: false, input: false } }, } as const, + ...oauthProvider.schema, ...jwt.schema, }; return { id: "convex", version: VERSION, - init: (ctx) => { + options: publicOptions, + init: async (ctx) => { const { options, logger: _logger } = ctx; + const getPlugin = ((pluginId: string) => { + if (pluginId === "jwt") { + return jwt; + } + if (pluginId === "oauth-provider") { + return oauthProvider; + } + return ctx.getPlugin(pluginId as any); + }) as typeof ctx.getPlugin; + await oauthProvider.init?.({ + ...ctx, + getPlugin, + } as any); if (options.basePath !== "/api/auth" && !opts.options?.basePath) { // eslint-disable-next-line no-console console.warn( @@ -273,9 +360,11 @@ export const convex = (opts: { `Better Auth basePath ${options.basePath} does not match Convex plugin basePath ${opts.options?.basePath}. This is probably a mistake.` ); } + return { context: { getPlugin } }; }, hooks: { before: [ + ...normalizeBeforeHooks(oauthProvider.hooks.before), ...bearer.hooks.before, // In query context, no writes can succeed. No-op adapter write // methods and session refresh to prevent errors from fire-and-forget @@ -314,7 +403,7 @@ export const convex = (opts: { }, ], after: [ - ...normalizeAfterHooks(oidcProvider.hooks.after), + ...normalizeAfterHooks(oauthProvider.hooks.after), { matcher: (ctx) => { return Boolean( @@ -360,6 +449,7 @@ export const convex = (opts: { matcher: (ctx) => { return Boolean( ctx.path?.startsWith("/sign-out") || + ctx.path?.startsWith("/oauth2/end-session") || ctx.path?.startsWith("/delete-user") || (ctx.path?.startsWith("/get-session") && !ctx.context.session) ); @@ -374,6 +464,43 @@ export const convex = (opts: { ], }, endpoints: { + ...oauthProviderEndpoints, + oauthProviderGetOpenIdConfig: createAuthEndpoint( + "/.well-known/openid-configuration", + { + method: "GET", + metadata: { + isAction: false, + }, + }, + async (ctx) => { + const response = await oauthProviderGetOpenIdConfig({ + ...withConvexSiteBaseURL(ctx, getOAuthProviderBasePath(ctx)), + asResponse: false, + returnHeaders: false, + returnStatus: false, + }); + return response; + } + ), + oauthProviderGetOAuthServerConfig: createAuthEndpoint( + "/.well-known/oauth-authorization-server", + { + method: "GET", + metadata: { + isAction: false, + }, + }, + async (ctx) => { + const response = await oauthProviderGetOAuthServerConfig({ + ...withConvexSiteBaseURL(ctx, getOAuthProviderBasePath(ctx)), + asResponse: false, + returnHeaders: false, + returnStatus: false, + }); + return response; + } + ), getOpenIdConfig: createAuthEndpoint( "/convex/.well-known/openid-configuration", { @@ -384,7 +511,45 @@ export const convex = (opts: { // TODO: properly type this }, async (ctx) => { - const response = await oidcProvider.endpoints.getOpenIdConfig({ + const response = await oauthProviderGetOpenIdConfig({ + ...withConvexSiteBaseURL(ctx, getOAuthProviderBasePath(ctx)), + asResponse: false, + returnHeaders: false, + returnStatus: false, + }); + return response; + } + ), + getOAuthServerConfig: createAuthEndpoint( + "/convex/.well-known/oauth-authorization-server", + { + method: "GET", + metadata: { + isAction: false, + }, + }, + async (ctx) => { + const response = await oauthProviderGetOAuthServerConfig({ + ...withConvexSiteBaseURL(ctx, getOAuthProviderBasePath(ctx)), + asResponse: false, + returnHeaders: false, + returnStatus: false, + }); + return response; + } + ), + getRootJwks: createAuthEndpoint( + "/jwks", + { + method: "GET", + metadata: { + openapi: { + description: "Get the JSON Web Key Set", + }, + }, + }, + async (ctx) => { + const response = await jwt.endpoints.getJwks({ ...ctx, asResponse: false, returnHeaders: false, diff --git a/src/plugins/index.ts b/src/plugins/index.ts index 6331420a..c7621e76 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -1,2 +1,3 @@ export * from "./convex/index.js"; export * from "./cross-domain/index.js"; +export * from "./mcp/index.js"; diff --git a/src/plugins/mcp/index.test.ts b/src/plugins/mcp/index.test.ts new file mode 100644 index 00000000..6b893904 --- /dev/null +++ b/src/plugins/mcp/index.test.ts @@ -0,0 +1,47 @@ +import { describe, expect, it } from "vitest"; +import { oAuthProtectedResourceMetadata, withMcpAuth } from "./index.js"; + +describe("MCP helpers", () => { + it("returns a WWW-Authenticate challenge for missing bearer tokens", async () => { + const handler = withMcpAuth( + { + verifyOptions: { + issuer: "https://auth.example.com", + audience: "https://api.example.com/mcp", + }, + jwksUrl: "https://auth.example.com/jwks", + }, + async () => new Response("ok") + ); + + const response = await handler( + new Request("https://api.example.com/mcp", { method: "POST" }) + ); + + expect(response.status).toBe(401); + expect(response.headers.get("WWW-Authenticate")).toContain( + "oauth-protected-resource" + ); + expect(response.headers.get("Access-Control-Expose-Headers")).toBe( + "WWW-Authenticate" + ); + }); + + it("returns OAuth protected resource metadata", async () => { + const handler = oAuthProtectedResourceMetadata({ + resource: "https://api.example.com/mcp", + authorizationServers: ["https://auth.example.com"], + scopesSupported: ["openid", "mcp:tools"], + }); + + const response = await handler(); + + expect(response.headers.get("content-type")).toContain("application/json"); + await expect(response.json()).resolves.toEqual({ + resource: "https://api.example.com/mcp", + authorization_servers: ["https://auth.example.com"], + scopes_supported: ["openid", "mcp:tools"], + bearer_methods_supported: ["header"], + }); + }); +}); diff --git a/src/plugins/mcp/index.ts b/src/plugins/mcp/index.ts new file mode 100644 index 00000000..f334227d --- /dev/null +++ b/src/plugins/mcp/index.ts @@ -0,0 +1,79 @@ +import { + mcpHandler, + oauthProviderAuthServerMetadata, +} from "@better-auth/oauth-provider"; +import type { ResourceServerMetadata } from "@better-auth/oauth-provider"; +import type { verifyAccessToken } from "better-auth/oauth2"; +import type { JWTPayload } from "jose"; + +type VerifyOptions = Parameters[1]; + +type Awaitable = T | Promise; + +type WithMcpAuthOptions = { + resourceMetadataMappings?: Record; +}; + +const exposeAuthenticateHeader = (response: Response) => { + if ( + response.status !== 401 || + !response.headers.has("WWW-Authenticate") + ) { + return response; + } + const headers = new Headers(response.headers); + const exposeHeader = "Access-Control-Expose-Headers"; + const authenticateHeader = "WWW-Authenticate"; + const exposedHeaders = + headers + .get(exposeHeader) + ?.split(",") + .map((header) => header.trim()) + .filter(Boolean) ?? []; + const hasAuthenticateHeader = exposedHeaders.some( + (header) => header.toLowerCase() === authenticateHeader.toLowerCase() + ); + if (!hasAuthenticateHeader) { + exposedHeaders.push(authenticateHeader); + } + headers.set(exposeHeader, exposedHeaders.join(", ")); + return new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers, + }); +}; + +export const withMcpAuth = ( + verifyOptions: VerifyOptions, + handler: (req: Request, jwt: JWTPayload) => Awaitable, + opts?: WithMcpAuthOptions +) => { + const protectedHandler = mcpHandler(verifyOptions, handler, { + resourceMetadataMappings: opts?.resourceMetadataMappings ?? {}, + }); + return async (req: Request) => { + const response = await protectedHandler(req); + return exposeAuthenticateHeader(response); + }; +}; + +export const oAuthDiscoveryMetadata = oauthProviderAuthServerMetadata; + +export const oAuthProtectedResourceMetadata = (opts: { + resource: string; + authorizationServers: string[]; + scopesSupported?: string[]; + bearerMethodsSupported?: Array<"header" | "body">; + extraMetadata?: Partial; +}) => { + return async () => { + return Response.json({ + resource: opts.resource, + authorization_servers: opts.authorizationServers, + scopes_supported: opts.scopesSupported, + bearer_methods_supported: opts.bearerMethodsSupported ?? ["header"], + ...opts.extraMetadata, + }); + }; +};