diff --git a/.env.example b/.env.example deleted file mode 100644 index c783a49a..00000000 --- a/.env.example +++ /dev/null @@ -1,6 +0,0 @@ -# ------------------------------------------------------------------------------ -# This is an example .env file. -# -# All of these environment vars must be defined either in your environment or in -# a local .env file in order to run this project. -# ------------------------------------------------------------------------------ diff --git a/apps/api/.env.example b/apps/api/.env.example index e5fe9539..d854ed16 100644 --- a/apps/api/.env.example +++ b/apps/api/.env.example @@ -7,10 +7,15 @@ DATABASE_URL= -JWT_SECRET= +BETTER_AUTH_SECRET= +BETTER_AUTH_URL= +JWT_SECRET= SENTRY_DSN= STRIPE_PUBLISHABLE_KEY= STRIPE_SECRET_KEY= STRIPE_WEBHOOK_SECRET= + +GITHUB_CLIENT_ID= +GITHUB_CLIENT_SECRET= diff --git a/apps/api/package.json b/apps/api/package.json index 455b8e59..51111f83 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -34,6 +34,7 @@ "@hono/zod-openapi": "^0.19.6", "@redocly/openapi-core": "^1.34.3", "@sentry/node": "^9.19.0", + "better-auth": "^1.2.8", "eventid": "^2.0.1", "exit-hook": "catalog:", "hono": "^4.7.9", diff --git a/apps/api/src/api-v1/index.ts b/apps/api/src/api-v1/index.ts index 58c80adb..1c3fcc62 100644 --- a/apps/api/src/api-v1/index.ts +++ b/apps/api/src/api-v1/index.ts @@ -2,6 +2,7 @@ import { OpenAPIHono } from '@hono/zod-openapi' import { fromError } from 'zod-validation-error' import type { AuthenticatedEnv } from '@/lib/types' +import { auth } from '@/lib/auth' import * as middleware from '@/lib/middleware' import { registerOpenAPIErrorResponses } from '@/lib/openapi-utils' @@ -17,6 +18,7 @@ import { registerV1DeploymentsListDeployments } from './deployments/list-deploym import { registerV1DeploymentsPublishDeployment } from './deployments/publish-deployment' import { registerV1DeploymentsUpdateDeployment } from './deployments/update-deployment' import { registerHealthCheck } from './health-check' +// import { registerV1OAuthRedirect } from './oauth-redirect' import { registerV1ProjectsCreateProject } from './projects/create-project' import { registerV1ProjectsGetProject } from './projects/get-project' import { registerV1ProjectsListProjects } from './projects/list-projects' @@ -98,11 +100,16 @@ registerV1DeploymentsUpdateDeployment(privateRouter) registerV1DeploymentsListDeployments(privateRouter) registerV1DeploymentsPublishDeployment(privateRouter) +// Internal admin routes +registerV1AdminConsumersGetConsumerByToken(privateRouter) + // Webhook event handlers registerV1StripeWebhook(publicRouter) -// Admin routes -registerV1AdminConsumersGetConsumerByToken(privateRouter) +// OAuth redirect +// registerV1OAuthRedirect(publicRouter) + +publicRouter.on(['POST', 'GET'], 'auth/**', (c) => auth.handler(c.req.raw)) // Setup routes and middleware apiV1.route('/', publicRouter) diff --git a/apps/api/src/api-v1/oauth-redirect.ts b/apps/api/src/api-v1/oauth-redirect.ts new file mode 100644 index 00000000..eea2b5b6 --- /dev/null +++ b/apps/api/src/api-v1/oauth-redirect.ts @@ -0,0 +1,42 @@ +import type { OpenAPIHono } from '@hono/zod-openapi' +import { assert } from '@agentic/platform-core' + +// TODO: Unused in favor of `better-auth` +export function registerV1OAuthRedirect(app: OpenAPIHono) { + return app.all('oauth', async (ctx) => { + if (ctx.req.query('state')) { + const { state: state64, ...query } = ctx.req.query() + + // google oauth + others + const { uri, ...state } = JSON.parse( + Buffer.from(state64!, 'base64').toString() + ) as any + + assert( + uri, + 404, + `Error oauth redirect not found "${new URLSearchParams(ctx.req.query()).toString()}"` + ) + + const searchParams = new URLSearchParams({ + ...state, + ...query + }) + + ctx.redirect(`${uri}?${searchParams.toString()}`) + } else { + // github oauth + // https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/#redirect-urls + const { uri, ...params } = ctx.req.query() + + assert( + uri, + 404, + `Error oauth redirect not found "${new URLSearchParams(ctx.req.query()).toString()}"` + ) + + const searchParams = new URLSearchParams(params) + ctx.redirect(`${uri}?${searchParams.toString()}`) + } + }) +} diff --git a/apps/api/src/api-v1/temp b/apps/api/src/api-v1/temp deleted file mode 100644 index 08ef76b9..00000000 --- a/apps/api/src/api-v1/temp +++ /dev/null @@ -1,27 +0,0 @@ -import type { hc } from 'hono/client' -import { expectTypeOf, test } from 'vitest' - -import type { User } from '@/db' - -import type { ApiRoutes } from './index' - -type ApiClient = ReturnType> - -type GetUserResponse = Awaited< - ReturnType>['json']> -> - -test('User types are compatible', async () => { - expectTypeOf().toEqualTypeOf() - - // const client = hc('http://localhost:3000/v1') - - // const user = await client.users[':userId'].$post({ - // param: { - // userId: '123' - // }, - // json: { - // firstName: 'John' - // } - // }) -}) diff --git a/apps/api/src/api-v1/webhooks/stripe-webhook.ts b/apps/api/src/api-v1/webhooks/stripe-webhook.ts index 2ad43c86..ca57afcb 100644 --- a/apps/api/src/api-v1/webhooks/stripe-webhook.ts +++ b/apps/api/src/api-v1/webhooks/stripe-webhook.ts @@ -12,7 +12,7 @@ const relevantStripeEvents = new Set([ ]) export function registerV1StripeWebhook(app: OpenAPIHono) { - return app.post('/webhooks/stripe', async (ctx) => { + return app.post('webhooks/stripe', async (ctx) => { const body = await ctx.req.text() const signature = ctx.req.header('Stripe-Signature') assert(signature, 400, 'missing signature') diff --git a/apps/api/src/lib/auth.ts b/apps/api/src/lib/auth.ts new file mode 100644 index 00000000..6c0c8196 --- /dev/null +++ b/apps/api/src/lib/auth.ts @@ -0,0 +1,61 @@ +// import { validators } from '@agentic/platform-validators' +import { betterAuth } from 'better-auth' +import { drizzleAdapter } from 'better-auth/adapters/drizzle' + +import { createIdForModel, db } from '@/db' + +import { env } from './env' + +export const auth = betterAuth({ + adapter: drizzleAdapter(db, { + provider: 'pg' + }), + emailAndPassword: { + enabled: true + }, + socialProviders: { + github: { + clientId: env.GITHUB_CLIENT_ID, + clientSecret: env.GITHUB_CLIENT_SECRET + } + }, + user: { + modelName: 'users', + additionalFields: { + role: { + type: 'string', + required: false, + defaultValue: 'user', + input: false // don't allow user to set role + }, + // username: { + // type: 'string', + // required: false + // }, + stripeCustomerId: { + type: 'string', + required: false + } + } + }, + session: { + modelName: 'sessions' + }, + account: { + modelName: 'accounts' + }, + verification: { + modelName: 'verifications' + }, + advanced: { + database: { + generateId: ({ model }) => createIdForModel(model as any) + } + } + // TODO + // plugins: [ + // username({ + // usernameValidator: validators.username + // }) + // ] +}) diff --git a/apps/api/src/lib/env.ts b/apps/api/src/lib/env.ts index 01689972..c11d93fa 100644 --- a/apps/api/src/lib/env.ts +++ b/apps/api/src/lib/env.ts @@ -12,14 +12,19 @@ export const envSchema = z.object({ DATABASE_URL: z.string().url(), + BETTER_AUTH_SECRET: z.string().nonempty(), + BETTER_AUTH_URL: z.string().url(), + JWT_SECRET: z.string().nonempty(), SENTRY_DSN: z.string().url(), PORT: z.number().default(3000), LOG_LEVEL: logLevelsSchema.default('info'), STRIPE_SECRET_KEY: z.string().nonempty(), - STRIPE_PUBLISHABLE_KEY: z.string().nonempty(), - STRIPE_WEBHOOK_SECRET: z.string().nonempty() + STRIPE_WEBHOOK_SECRET: z.string().nonempty(), + + GITHUB_CLIENT_ID: z.string().nonempty(), + GITHUB_CLIENT_SECRET: z.string().nonempty() }) export type Env = z.infer @@ -32,4 +37,4 @@ export const isDev = env.NODE_ENV === 'development' export const isProd = env.NODE_ENV === 'production' export const isBrowser = (globalThis as any).window !== undefined -export const isStripeLive = env.STRIPE_PUBLISHABLE_KEY.startsWith('pk_live_') +export const isStripeLive = env.STRIPE_SECRET_KEY.startsWith('sk_live_') diff --git a/apps/api/src/lib/github.ts b/apps/api/src/lib/github.ts new file mode 100644 index 00000000..6d6b5f0f --- /dev/null +++ b/apps/api/src/lib/github.ts @@ -0,0 +1,158 @@ +import ky from 'ky' + +import { env } from './env' + +const USER_AGENT = 'agentic-platform' + +/** + * GitHub (user-level) OAuth token response. + * + * @see https://docs.github.com/apps/oauth + */ +export interface GitHubUserTokenResponse { + /** + * The user access token (always starts with `ghu_`). + * Example: `ghu_xxx…` + */ + access_token: string + + /** + * Seconds until `access_token` expires. + * Omitted (`undefined`) if you’ve disabled token expiration. + * Constant `28800` (8 hours) when present. + */ + expires_in?: number + + /** + * Refresh token for renewing the user access token (starts with `ghr_`). + * Omitted (`undefined`) if you’ve disabled token expiration. + */ + refresh_token?: string + + /** + * Seconds until `refresh_token` expires. + * Omitted (`undefined`) if you’ve disabled token expiration. + * Constant `15897600` (6 months) when present. + */ + refresh_token_expires_in?: number + + /** + * Scopes granted to the token. + * Always an empty string because the token is limited to + * the intersection of app-level and user-level permissions. + */ + scope: '' + + /** + * Token type – always `'bearer'`. + */ + token_type: 'bearer' +} + +export interface GitHubUser { + login: string + id: number + user_view_type?: string + node_id: string + avatar_url: string + gravatar_id: string | null + url: string + html_url: string + followers_url: string + following_url: string + gists_url: string + starred_url: string + subscriptions_url: string + organizations_url: string + repos_url: string + events_url: string + received_events_url: string + type: string + site_admin: boolean + name: string | null + company: string | null + blog: string | null + location: string | null + email: string | null + notification_email?: string | null + hireable: boolean | null + bio: string | null + twitter_username?: string | null + public_repos: number + public_gists: number + followers: number + following: number + created_at: string + updated_at: string + plan?: { + collaborators: number + name: string + space: number + private_repos: number + [k: string]: unknown + } + private_gists?: number + total_private_repos?: number + owned_private_repos?: number + disk_usage?: number + collaborators?: number +} + +export interface GitHubUserEmail { + email: string + primary: boolean + verified: boolean + visibility?: string | null +} + +export async function exchangeOAuthCodeForAccessToken({ + code, + clientId = env.GITHUB_CLIENT_ID, + clientSecret = env.GITHUB_CLIENT_SECRET, + redirectUri +}: { + code: string + clientId?: string + clientSecret?: string + redirectUri?: string +}): Promise { + return ky + .post('https://github.com/login/oauth/access_token', { + json: { + code, + client_id: clientId, + client_secret: clientSecret, + redirect_uri: redirectUri + }, + headers: { + 'user-agent': USER_AGENT + } + }) + .json() +} + +export async function getMe({ token }: { token: string }): Promise { + return ky + .get('https://api.github.com/user', { + headers: { + Authorization: `Bearer ${token}`, + 'user-agent': USER_AGENT + } + }) + .json() +} + +export async function getUserEmails({ + token +}: { + token: string +}): Promise { + return ky + .get('https://api.github.com/user/emails', { + headers: { + Authorization: `Bearer ${token}`, + 'user-agent': USER_AGENT + } + }) + .json() +} diff --git a/apps/api/src/lib/middleware/authenticate.ts b/apps/api/src/lib/middleware/authenticate.ts index dc953055..c25d0d31 100644 --- a/apps/api/src/lib/middleware/authenticate.ts +++ b/apps/api/src/lib/middleware/authenticate.ts @@ -1,42 +1,55 @@ import { assert } from '@agentic/platform-core' import { createMiddleware } from 'hono/factory' -import * as jwt from 'hono/jwt' +// import * as jwt from 'hono/jwt' import type { AuthenticatedEnv } from '@/lib/types' -import { db, eq, schema } from '@/db' -import { env } from '@/lib/env' +import { auth } from '@/lib/auth' export const authenticate = createMiddleware( async function authenticateMiddleware(ctx, next) { - const credentials = ctx.req.raw.headers.get('Authorization') - assert(credentials, 401, 'Unauthorized') - - const parts = credentials.split(/\s+/) - assert( - parts.length === 1 || - (parts.length === 2 && parts[0]?.toLowerCase() === 'bearer'), - 401, - 'Unauthorized' - ) - const token = parts.at(-1) - assert(token, 401, 'Unauthorized') - - const payload = await jwt.verify(token, env.JWT_SECRET) - assert(payload, 401, 'Unauthorized') - assert(payload.type === 'user', 401, 'Unauthorized') - assert( - payload.userId && typeof payload.userId === 'string', - 401, - 'Unauthorized' - ) - ctx.set('userId', payload.userId) - - const user = await db.query.users.findFirst({ - where: eq(schema.users.id, payload.userId) + const session = await auth.api.getSession({ + // TODO: investigate this type issue + headers: ctx.req.raw.headers as any }) - assert(user, 401, 'Unauthorized') - ctx.set('user', user as any) + assert(session, 401, 'Unauthorized') + assert(session.user?.id, 401, 'Unauthorized') + assert(session.session, 401, 'Unauthorized') + + ctx.set('userId', session.user.id) + ctx.set('user', session.user) + ctx.set('session', session.session) await next() + + // const credentials = ctx.req.raw.headers.get('Authorization') + // assert(credentials, 401, 'Unauthorized') + + // const parts = credentials.split(/\s+/) + // assert( + // parts.length === 1 || + // (parts.length === 2 && parts[0]?.toLowerCase() === 'bearer'), + // 401, + // 'Unauthorized' + // ) + // const token = parts.at(-1) + // assert(token, 401, 'Unauthorized') + + // const payload = await jwt.verify(token, env.JWT_SECRET) + // assert(payload, 401, 'Unauthorized') + // assert(payload.type === 'user', 401, 'Unauthorized') + // assert( + // payload.userId && typeof payload.userId === 'string', + // 401, + // 'Unauthorized' + // ) + // ctx.set('userId', payload.userId) + + // const user = await db.query.users.findFirst({ + // where: eq(schema.users.id, payload.userId) + // }) + // assert(user, 401, 'Unauthorized') + // ctx.set('user', user as any) + + // await next() } ) diff --git a/apps/api/src/lib/middleware/team.ts b/apps/api/src/lib/middleware/team.ts index 01a04d95..0120201d 100644 --- a/apps/api/src/lib/middleware/team.ts +++ b/apps/api/src/lib/middleware/team.ts @@ -12,13 +12,13 @@ import { aclTeamMember } from '@/lib/acl-team-member' export const team = createMiddleware( async function teamMiddleware(ctx, next) { const teamId = ctx.req.query('teamId') - const user = ctx.get('user') + const userId = ctx.get('userId') - if (teamId && user) { + if (teamId && userId) { const teamMember = await db.query.teamMembers.findFirst({ where: and( eq(schema.teamMembers.teamId, teamId), - eq(schema.teamMembers.userId, user.id) + eq(schema.teamMembers.userId, userId) ) }) assert(teamMember, 403, 'Unauthorized') diff --git a/apps/api/src/lib/types.ts b/apps/api/src/lib/types.ts index 9594156c..3935a1ff 100644 --- a/apps/api/src/lib/types.ts +++ b/apps/api/src/lib/types.ts @@ -1,7 +1,8 @@ import type { Context } from 'hono' -import type { RawTeamMember, RawUser } from '@/db' +import type { RawTeamMember } from '@/db' +import type { auth } from './auth' import type { Env } from './env' import type { Logger } from './logger' @@ -10,6 +11,9 @@ export type { OpenAPI3 as LooseOpenAPI3Spec } from 'openapi-typescript' export type Environment = Env['NODE_ENV'] export type Service = 'api' +export type AuthUser = typeof auth.$Infer.Session.user +export type AuthSession = typeof auth.$Infer.Session.session + export type DefaultEnvVariables = { requestId: string logger: Logger @@ -17,7 +21,8 @@ export type DefaultEnvVariables = { export type AuthenticatedEnvVariables = DefaultEnvVariables & { userId: string - user?: RawUser + user?: AuthUser + session?: AuthSession teamMember?: RawTeamMember } diff --git a/packages/api-client/src/agentic-api-client.ts b/packages/api-client/src/agentic-api-client.ts index a09fa4ce..ed82b4c0 100644 --- a/packages/api-client/src/agentic-api-client.ts +++ b/packages/api-client/src/agentic-api-client.ts @@ -1,8 +1,8 @@ import type { Simplify } from 'type-fest' +import { getEnv, sanitizeSearchParams } from '@agentic/platform-core' import defaultKy, { type KyInstance } from 'ky' import type { operations } from './openapi' -import { getEnv, sanitizeSearchParams } from './utils' export class AgenticApiClient { static readonly DEFAULT_API_BASE_URL = 'https://api.agentic.so' diff --git a/packages/api-client/src/utils.ts b/packages/api-client/src/utils.ts deleted file mode 100644 index f0745916..00000000 --- a/packages/api-client/src/utils.ts +++ /dev/null @@ -1,57 +0,0 @@ -export function getEnv(name: string): string | undefined { - try { - return typeof process !== 'undefined' - ? // eslint-disable-next-line no-process-env - process.env?.[name] - : undefined - } catch { - return undefined - } -} - -/** - * Creates a new `URLSearchParams` object with all values coerced to strings - * that correctly handles arrays of values as repeated keys (or CSV) and - * correctly removes `undefined` keys and values. - */ -export function sanitizeSearchParams( - searchParams: - | Record< - string, - string | number | boolean | string[] | number[] | boolean[] | undefined - > - | object, - { - csv = false - }: { - /** - * Whether to use comma-separated-values for arrays or multiple entries. - * - * Defaults to `false` and will use multiple entries. - */ - csv?: boolean - } = {} -): URLSearchParams { - const entries = Object.entries(searchParams).flatMap(([key, value]) => { - if (key === undefined || value === undefined) { - return [] - } - - if (Array.isArray(value)) { - return value.map((v) => [key, String(v)]) - } - - return [[key, String(value)]] - }) as [string, string][] - - if (!csv) { - return new URLSearchParams(entries) - } - - const csvEntries: Record = {} - for (const [key, value] of entries) { - csvEntries[key] = csvEntries[key] ? `${csvEntries[key]},${value}` : value - } - - return new URLSearchParams(csvEntries) -} diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index eb0e333c..3bfc7d59 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -115,3 +115,61 @@ export function hashObject( ...options }) } + +export function getEnv(name: string): string | undefined { + try { + return typeof process !== 'undefined' + ? // eslint-disable-next-line no-process-env + process.env?.[name] + : undefined + } catch { + return undefined + } +} + +/** + * Creates a new `URLSearchParams` object with all values coerced to strings + * that correctly handles arrays of values as repeated keys (or CSV) and + * correctly removes `undefined` keys and values. + */ +export function sanitizeSearchParams( + searchParams: + | Record< + string, + string | number | boolean | string[] | number[] | boolean[] | undefined + > + | object, + { + csv = false + }: { + /** + * Whether to use comma-separated-values for arrays or multiple entries. + * + * Defaults to `false` and will use multiple entries. + */ + csv?: boolean + } = {} +): URLSearchParams { + const entries = Object.entries(searchParams).flatMap(([key, value]) => { + if (key === undefined || value === undefined) { + return [] + } + + if (Array.isArray(value)) { + return value.map((v) => [key, String(v)]) + } + + return [[key, String(value)]] + }) as [string, string][] + + if (!csv) { + return new URLSearchParams(entries) + } + + const csvEntries: Record = {} + for (const [key, value] of entries) { + csvEntries[key] = csvEntries[key] ? `${csvEntries[key]},${value}` : value + } + + return new URLSearchParams(csvEntries) +} diff --git a/packages/db/src/schema/auth.ts b/packages/db/src/schema/auth.ts new file mode 100644 index 00000000..5b20d2fe --- /dev/null +++ b/packages/db/src/schema/auth.ts @@ -0,0 +1,50 @@ +import { pgTable, text, timestamp } from '@fisch0920/drizzle-orm/pg-core' + +import { + accountPrimaryId, + sessionPrimaryId, + timestamps, + userId, + verificationPrimaryId +} from './common' +import { users } from './user' + +// These tables are all managed by better-auth. + +export const sessions = pgTable('sessions', { + ...sessionPrimaryId, + ...timestamps, + + expiresAt: timestamp('expiresAt').notNull(), + ipAddress: text('ipAddress'), + userAgent: text('userAgent'), + userId: userId() + .notNull() + .references(() => users.id) +}) + +export const accounts = pgTable('accounts', { + ...accountPrimaryId, + ...timestamps, + + accountId: text('accountId').notNull(), + providerId: text('providerId').notNull(), + userId: userId() + .notNull() + .references(() => users.id), + accessToken: text('accessToken'), + refreshToken: text('refreshToken'), + idToken: text('idToken'), + expiresAt: timestamp('expiresAt').notNull(), + password: text('password') +}) + +export const verifications = pgTable('verifications', { + ...verificationPrimaryId, + ...timestamps, + + identifier: text('identifier').notNull(), + value: text('value').notNull(), + + expiresAt: timestamp('expiresAt').notNull() +}) diff --git a/packages/db/src/schema/common.ts b/packages/db/src/schema/common.ts index e4da03c0..a37972a7 100644 --- a/packages/db/src/schema/common.ts +++ b/packages/db/src/schema/common.ts @@ -16,19 +16,31 @@ import { createId as createCuid2 } from '@paralleldrive/cuid2' const usernameAndTeamSlugLength = 64 as const -// prefix is max 4 characters +// prefix is max 5 characters // separator is 1 character // cuid2 is max 24 characters // so use 32 characters to be safe for storing ids export const idMaxLength = 32 as const export const idPrefixMap = { - user: 'user', team: 'team', project: 'proj', deployment: 'depl', consumer: 'csmr', - logEntry: 'log' + logEntry: 'log', + + // better-auth + user: 'user', + account: 'acct', + session: 'sess', + verification: 'veri', + 'rate-limit': 'ratel', + organization: 'org', + member: 'mem', + invitation: 'inv', + jwks: 'jwks', + passkey: 'passk', + 'two-factor': '2fa' } as const export type ModelType = keyof typeof idPrefixMap @@ -57,6 +69,9 @@ export const consumerPrimaryId = getPrimaryId('consumer') export const logEntryPrimaryId = getPrimaryId('logEntry') export const teamPrimaryId = getPrimaryId('team') export const userPrimaryId = getPrimaryId('user') +export const sessionPrimaryId = getPrimaryId('session') +export const accountPrimaryId = getPrimaryId('account') +export const verificationPrimaryId = getPrimaryId('verification') /** * All of our model primary ids have the following format: diff --git a/packages/db/src/schema/index.ts b/packages/db/src/schema/index.ts index ebf2cec2..2136901b 100644 --- a/packages/db/src/schema/index.ts +++ b/packages/db/src/schema/index.ts @@ -1,3 +1,4 @@ +export * from './auth' export * from './common' export * from './consumer' export * from './deployment' diff --git a/packages/db/src/schema/schemas.ts b/packages/db/src/schema/schemas.ts index 90c63c6d..21e99d3e 100644 --- a/packages/db/src/schema/schemas.ts +++ b/packages/db/src/schema/schemas.ts @@ -1,61 +1,61 @@ import { z } from '@hono/zod-openapi' import parseJson from 'parse-json' -export const authProviderTypeSchema = z - .union([ - z.literal('github'), - z.literal('google'), - z.literal('spotify'), - z.literal('twitter'), - z.literal('linkedin'), - z.literal('stripe') - ]) - .openapi('AuthProviderType') -export type AuthProviderType = z.infer +// export const authProviderTypeSchema = z +// .union([ +// z.literal('github'), +// z.literal('google'), +// z.literal('spotify'), +// z.literal('twitter'), +// z.literal('linkedin'), +// z.literal('stripe') +// ]) +// .openapi('AuthProviderType') +// export type AuthProviderType = z.infer -export const authProviderSchema = z.object({ - provider: authProviderTypeSchema, +// export const authProviderSchema = z.object({ +// provider: authProviderTypeSchema, - /** Provider-specific user id */ - id: z.string(), +// /** Provider-specific user id */ +// id: z.string(), - /** Provider-specific username */ - username: z.string().optional(), +// /** Provider-specific username */ +// username: z.string().optional(), - /** Standard oauth2 access token */ - accessToken: z.string().optional(), +// /** Standard oauth2 access token */ +// accessToken: z.string().optional(), - /** Standard oauth2 refresh token */ - refreshToken: z.string().optional(), +// /** Standard oauth2 refresh token */ +// refreshToken: z.string().optional(), - /** Stripe public key */ - publicKey: z.string().optional(), +// /** Stripe public key */ +// publicKey: z.string().optional(), - /** OAuth scope(s) */ - scope: z.string().optional() -}) -export type AuthProvider = z.infer +// /** OAuth scope(s) */ +// scope: z.string().optional() +// }) +// export type AuthProvider = z.infer -export const publicAuthProviderSchema = authProviderSchema - .omit({ - accessToken: true, - refreshToken: true, - publicKey: true - }) - .strip() - .openapi('AuthProvider') -export type PublicAuthProvider = z.infer +// export const publicAuthProviderSchema = authProviderSchema +// .omit({ +// accessToken: true, +// refreshToken: true, +// publicKey: true +// }) +// .strip() +// .openapi('AuthProvider') +// export type PublicAuthProvider = z.infer -export const authProvidersSchema = z.record( - authProviderTypeSchema, - authProviderSchema.optional() -) -export type AuthProviders = z.infer +// export const authProvidersSchema = z.record( +// authProviderTypeSchema, +// authProviderSchema.optional() +// ) +// export type AuthProviders = z.infer -export const publicAuthProvidersSchema = z - .record(authProviderTypeSchema, publicAuthProviderSchema.optional()) - .openapi('AuthProviders') -export type PublicAuthProviders = z.infer +// export const publicAuthProvidersSchema = z +// .record(authProviderTypeSchema, publicAuthProviderSchema.optional()) +// .openapi('AuthProviders') +// export type PublicAuthProviders = z.infer export const webhookSchema = z .object({ diff --git a/packages/db/src/schema/user.ts b/packages/db/src/schema/user.ts index 43aec3d6..ff39260a 100644 --- a/packages/db/src/schema/user.ts +++ b/packages/db/src/schema/user.ts @@ -1,64 +1,46 @@ -import { sha256 } from '@agentic/platform-core' -import { validators } from '@agentic/platform-validators' import { relations } from '@fisch0920/drizzle-orm' import { boolean, index, - jsonb, pgTable, text, uniqueIndex } from '@fisch0920/drizzle-orm/pg-core' -import { hashSync } from 'bcryptjs' import { - createInsertSchema, createSelectSchema, - createUpdateSchema, stripeId, - timestamp, timestamps, - username, + // username, userPrimaryId, userRoleEnum } from './common' -import { type AuthProviders, publicAuthProvidersSchema } from './schemas' import { teams } from './team' +// This table is mostly managed by better-auth. + export const users = pgTable( 'users', { ...userPrimaryId, ...timestamps, - username: username().notNull().unique(), + name: text('name').notNull(), + email: text('email').notNull().unique(), + emailVerified: boolean('emailVerified').default(false).notNull(), + image: text('image'), + + // TODO: re-add username + // username: username().notNull().unique(), role: userRoleEnum().default('user').notNull(), - email: text().unique(), - password: text(), - - // metadata - firstName: text(), - lastName: text(), - image: text(), - - emailConfirmed: boolean().default(false).notNull(), - emailConfirmedAt: timestamp(), - emailConfirmToken: text().unique().notNull(), - passwordResetToken: text().unique(), - isStripeConnectEnabledByDefault: boolean().default(true).notNull(), - // third-party auth providers - authProviders: jsonb().$type().default({}).notNull(), - stripeCustomerId: stripeId() }, (table) => [ uniqueIndex('user_email_idx').on(table.email), - uniqueIndex('user_username_idx').on(table.username), - uniqueIndex('user_emailConfirmToken_idx').on(table.emailConfirmToken), - uniqueIndex('user_passwordResetToken_idx').on(table.passwordResetToken), + // uniqueIndex('user_username_idx').on(table.username), index('user_createdAt_idx').on(table.createdAt), index('user_updatedAt_idx').on(table.updatedAt), index('user_deletedAt_idx').on(table.deletedAt) @@ -70,49 +52,49 @@ export const usersRelations = relations(users, ({ many }) => ({ })) export const userSelectSchema = createSelectSchema(users, { - authProviders: publicAuthProvidersSchema + // authProviders: publicAuthProvidersSchema }) - .omit({ password: true, emailConfirmToken: true, passwordResetToken: true }) + // .omit({ password: true, emailConfirmToken: true, passwordResetToken: true }) .strip() .openapi('User') -export const userInsertSchema = createInsertSchema(users, { - username: (schema) => - schema.refine((username) => validators.username(username), { - message: 'Invalid username' - }), +// export const userInsertSchema = createInsertSchema(users, { +// username: (schema) => +// schema.refine((username) => validators.username(username), { +// message: 'Invalid username' +// }), - email: (schema) => schema.email().optional() -}) - .pick({ - username: true, - email: true, - password: true, - firstName: true, - lastName: true, - image: true - }) - .strict() - .transform((user) => { - return { - ...user, - emailConfirmToken: sha256(), - password: user.password ? hashSync(user.password) : undefined - } - }) +// email: (schema) => schema.email().optional() +// }) +// .pick({ +// username: true, +// email: true, +// password: true, +// firstName: true, +// lastName: true, +// image: true +// }) +// .strict() +// .transform((user) => { +// return { +// ...user, +// emailConfirmToken: sha256(), +// password: user.password ? hashSync(user.password) : undefined +// } +// }) -export const userUpdateSchema = createUpdateSchema(users) - .pick({ - firstName: true, - lastName: true, - image: true, - password: true, - isStripeConnectEnabledByDefault: true - }) - .strict() - .transform((user) => { - return { - ...user, - password: user.password ? hashSync(user.password) : undefined - } - }) +// export const userUpdateSchema = createUpdateSchema(users) +// .pick({ +// firstName: true, +// lastName: true, +// image: true, +// password: true, +// isStripeConnectEnabledByDefault: true +// }) +// .strict() +// .transform((user) => { +// return { +// ...user, +// password: user.password ? hashSync(user.password) : undefined +// } +// }) diff --git a/packages/db/src/types.ts b/packages/db/src/types.ts index e1ab21fc..4a40fcce 100644 --- a/packages/db/src/types.ts +++ b/packages/db/src/types.ts @@ -77,3 +77,5 @@ export type RawConsumerUpdate = Partial< export type LogEntry = z.infer export type RawLogEntry = InferSelectModel + +export type RawSession = InferSelectModel diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10ee3abb..81854ca9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,6 +152,9 @@ importers: '@sentry/node': specifier: ^9.19.0 version: 9.19.0 + better-auth: + specifier: ^1.2.8 + version: 1.2.8 eventid: specifier: ^2.0.1 version: 2.0.1 @@ -197,7 +200,7 @@ importers: version: 0.31.1 drizzle-orm: specifier: ^0.43.1 - version: 0.43.1(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(postgres@3.4.5) + version: 0.43.1(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(kysely@0.28.2)(postgres@3.4.5) openapi-typescript: specifier: ^7.8.0 version: 7.8.0(typescript@5.8.3) @@ -232,6 +235,9 @@ importers: conf: specifier: ^13.1.0 version: 13.1.0 + inquirer: + specifier: ^9.2.15 + version: 9.3.7 ora: specifier: ^8.2.0 version: 8.2.0 @@ -242,12 +248,12 @@ importers: specifier: 'catalog:' version: 3.24.4 devDependencies: - '@agentic/platform-db': - specifier: workspace:* - version: link:../db '@commander-js/extra-typings': specifier: ^14.0.0 version: 14.0.0(commander@14.0.0) + '@types/inquirer': + specifier: ^9.0.7 + version: 9.0.8 packages/core: dependencies: @@ -275,10 +281,10 @@ importers: version: link:../validators '@fisch0920/drizzle-orm': specifier: ^0.43.7 - version: 0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(postgres@3.4.5) + version: 0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(kysely@0.28.2)(postgres@3.4.5) '@fisch0920/drizzle-zod': specifier: ^0.7.9 - version: 0.7.9(@fisch0920/drizzle-orm@0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(postgres@3.4.5))(zod@3.24.4) + version: 0.7.9(@fisch0920/drizzle-orm@0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(kysely@0.28.2)(postgres@3.4.5))(zod@3.24.4) '@hono/zod-openapi': specifier: ^0.19.6 version: 0.19.6(hono@4.7.9)(zod@3.24.4) @@ -335,6 +341,12 @@ packages: resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} engines: {node: '>=6.9.0'} + '@better-auth/utils@0.2.5': + resolution: {integrity: sha512-uI2+/8h/zVsH8RrYdG8eUErbuGBk16rZKQfz8CjxQOyCE6v7BqFYEbFwvOkvl1KbUdxhqOnXp78+uE5h8qVEgQ==} + + '@better-fetch/fetch@1.1.18': + resolution: {integrity: sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA==} + '@commander-js/extra-typings@14.0.0': resolution: {integrity: sha512-hIn0ncNaJRLkZrxBIp5AsW/eXEHNKYQBh0aPdoUqNgD+Io3NIykQqpKFyKcuasZhicGaEZJX/JBSIkZ4e5x8Dg==} peerDependencies: @@ -780,6 +792,9 @@ packages: '@fisch0920/drizzle-orm': '>=0.36.0' zod: '>=3.0.0' + '@hexagon/base64@1.1.28': + resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} + '@hono/node-server@1.14.1': resolution: {integrity: sha512-vmbuM+HPinjWzPe7FFPWMMQMsbKE9gDPhaH0FFdqbGpkT5lp++tcWDTxwBl5EgS5y6JVgIaCdjeHRfQ4XRBRjQ==} engines: {node: '>=18.14.1'} @@ -824,6 +839,10 @@ packages: resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} engines: {node: '>=18.18'} + '@inquirer/figures@1.0.11': + resolution: {integrity: sha512-eOg92lvrn/aRUqbxRyvpEWnrvRuTYRifixHkYVpJiygTgVSBIHDqLh0SrMQXkafvULg3ck11V7xvR+zcgvpHFw==} + engines: {node: '>=18'} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -846,10 +865,16 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@levischuck/tiny-cbor@0.2.11': + resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==} + '@modelcontextprotocol/sdk@1.11.2': resolution: {integrity: sha512-H9vwztj5OAqHg9GockCQC06k1natgcxWQSRpQcPJf6i5+MWBzfKkRtxGbjQf0X2ihii0ffLZCRGbYV2f2bjNCQ==} engines: {node: '>=18'} + '@noble/ciphers@0.6.0': + resolution: {integrity: sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ==} + '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} @@ -1057,6 +1082,21 @@ packages: '@paralleldrive/cuid2@2.2.2': resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==} + '@peculiar/asn1-android@2.3.16': + resolution: {integrity: sha512-a1viIv3bIahXNssrOIkXZIlI2ePpZaNmR30d4aBL99mu2rO+mT9D6zBsp7H6eROWGtmwv0Ionp5olJurIo09dw==} + + '@peculiar/asn1-ecc@2.3.15': + resolution: {integrity: sha512-/HtR91dvgog7z/WhCVdxZJ/jitJuIu8iTqiyWVgRE9Ac5imt2sT/E4obqIVGKQw7PIy+X6i8lVBoT6wC73XUgA==} + + '@peculiar/asn1-rsa@2.3.15': + resolution: {integrity: sha512-p6hsanvPhexRtYSOHihLvUUgrJ8y0FtOM97N5UEpC+VifFYyZa0iZ5cXjTkZoDwxJ/TTJ1IJo3HVTB2JJTpXvg==} + + '@peculiar/asn1-schema@2.3.15': + resolution: {integrity: sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==} + + '@peculiar/asn1-x509@2.3.15': + resolution: {integrity: sha512-0dK5xqTqSLaxv1FHXIcd4Q/BZNuopg+u1l23hT9rOmQ1g4dNtw0g/RnEi+TboB0gOwGtrWn269v27cMgchFIIg==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1210,6 +1250,13 @@ packages: resolution: {integrity: sha512-A4srR9mEBFdVXwSEKjQ94msUbVkMr8JeFiEj9ouOFORw/Y/ux/WV2bWVD/ZI9wq0TcTNK8L1wBgU8UMS5lIq3A==} engines: {node: '>=14.18'} + '@simplewebauthn/browser@13.1.0': + resolution: {integrity: sha512-WuHZ/PYvyPJ9nxSzgHtOEjogBhwJfC8xzYkPC+rR/+8chl/ft4ngjiK8kSU5HtRJfczupyOh33b25TjYbvwAcg==} + + '@simplewebauthn/server@13.1.1': + resolution: {integrity: sha512-1hsLpRHfSuMB9ee2aAdh0Htza/X3f4djhYISrggqGe3xopNjOcePiSDkDDoPzDYaaMCrbqGP1H2TYU7bgL9PmA==} + engines: {node: '>=20.0.0'} + '@sindresorhus/merge-streams@2.3.0': resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} @@ -1223,6 +1270,9 @@ packages: '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/inquirer@9.0.8': + resolution: {integrity: sha512-CgPD5kFGWsb8HJ5K7rfWlifao87m4ph8uioU7OTncJevmE/VLIqAAjfQtko578JZg7/f69K4FgqYym3gNr7DeA==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -1259,6 +1309,9 @@ packages: '@types/tedious@4.0.14': resolution: {integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==} + '@types/through@0.0.33': + resolution: {integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==} + '@typescript-eslint/eslint-plugin@8.31.0': resolution: {integrity: sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1389,6 +1442,10 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + ansi-escapes@7.0.0: resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} engines: {node: '>=18'} @@ -1451,6 +1508,10 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} + asn1js@3.0.6: + resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==} + engines: {node: '>=12.0.0'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -1480,10 +1541,22 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + bcryptjs@3.0.2: resolution: {integrity: sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==} hasBin: true + better-auth@1.2.8: + resolution: {integrity: sha512-y8ry7ZW3/3ZIr82Eo1zUDtMzdoQlFnwNuZ0+b0RxoNZgqmvgTIc/0tCDC7NDJerqSu4UCzer0dvYxBsv3WMIGg==} + + better-call@1.0.9: + resolution: {integrity: sha512-Qfm0gjk0XQz0oI7qvTK1hbqTsBY4xV2hsHAxF8LZfUYl3RaECCIifXuVqtPpZJWvlCCMlQSvkvhhyuApGUba6g==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + body-parser@2.2.0: resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} engines: {node: '>=18'} @@ -1509,6 +1582,9 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + builtin-modules@5.0.0: resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==} engines: {node: '>=18.20'} @@ -1561,6 +1637,9 @@ packages: change-case@5.4.4: resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + check-error@2.1.1: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} @@ -1580,6 +1659,10 @@ packages: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} @@ -1592,6 +1675,14 @@ packages: resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} engines: {node: '>=18'} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1711,6 +1802,9 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -1719,6 +1813,9 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + del-cli@6.0.0: resolution: {integrity: sha512-9nitGV2W6KLFyya4qYt4+9AKQFL+c0Ehj5K7V7IwlxTc6RMCfQUGY9E9pLG6e8TQjtwXpuiWIGGZb3mfVxyZkw==} engines: {node: '>=18'} @@ -2119,6 +2216,10 @@ packages: resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} engines: {node: '>= 18'} + external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -2311,10 +2412,17 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -2345,6 +2453,10 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + inquirer@9.3.7: + resolution: {integrity: sha512-LJKFHCSeIRq9hanN14IlOtPSTe3lNES7TYDTE2xxdAy1LS5rYphajK1qtwvj3YmQXvvk0U2Vbmcni8P9EIQW9w==} + engines: {node: '>=18'} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -2421,6 +2533,10 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + is-interactive@2.0.0: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} @@ -2484,6 +2600,10 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} @@ -2521,6 +2641,9 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jose@5.10.0: + resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} + joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -2590,6 +2713,10 @@ packages: resolution: {integrity: sha512-7Bp3TpsE+L+TARSnnDpk3xg8Idi8RwSLdj6CMbNWoOARIrGrbuLGusV0dYwbZOm4bB3jHNxSw8Wk/ByDqJEnDw==} engines: {node: '>=18'} + kysely@0.28.2: + resolution: {integrity: sha512-4YAVLoF0Sf0UTqlhgQMFU9iQECdah7n+13ANkiuVfRvlK+uI0Etbgd7bVP36dKlG+NXWbhGua8vnGt+sdhvT7A==} + engines: {node: '>=18.0.0'} + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -2652,6 +2779,10 @@ packages: lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + log-symbols@6.0.0: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} @@ -2709,6 +2840,10 @@ packages: resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} engines: {node: '>= 0.6'} + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} @@ -2745,6 +2880,10 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mute-stream@1.0.0: + resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -2757,6 +2896,10 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanostores@0.11.4: + resolution: {integrity: sha512-k1oiVNN4hDK8NcNERSZLQiMfRzEGtfnvZvdBvey3SQbgn8Dcrk0h1I6vpxApjb10PFUflZrgJ2WEZyJQ+5v7YQ==} + engines: {node: ^18.0.0 || >=20.0.0} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -2819,6 +2962,10 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + onetime@7.0.0: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} @@ -2840,10 +2987,18 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + ora@8.2.0: resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} engines: {node: '>=18'} + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + own-keys@1.0.1: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} @@ -3018,6 +3173,13 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.3: + resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} + engines: {node: '>=6.0.0'} + qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} @@ -3048,6 +3210,10 @@ packages: resolution: {integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==} engines: {node: '>=18'} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -3103,6 +3269,10 @@ packages: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + restore-cursor@5.1.0: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} @@ -3119,13 +3289,23 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rou3@0.5.1: + resolution: {integrity: sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==} + router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} + run-async@3.0.0: + resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} + engines: {node: '>=0.12.0'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -3164,6 +3344,9 @@ packages: resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} engines: {node: '>= 18'} + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3213,6 +3396,9 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -3317,6 +3503,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -3395,6 +3584,10 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -3435,6 +3628,9 @@ packages: tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsup@8.4.0: resolution: {integrity: sha512-b+eZbPCjz10fRryaAA7C8xlIHnf8VnsaRqydheLIqwG/Mcpfk8Z5zp3HayX7GaTygkigHl5cBUs+IhcySiIexQ==} engines: {node: '>=18'} @@ -3497,6 +3693,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} @@ -3541,6 +3741,9 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -3568,6 +3771,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true @@ -3660,6 +3866,9 @@ packages: jsdom: optional: true + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} @@ -3708,6 +3917,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -3743,6 +3956,10 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yoctocolors-cjs@2.1.2: + resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} + engines: {node: '>=18'} + zod-to-json-schema@3.24.5: resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} peerDependencies: @@ -3776,6 +3993,13 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 + '@better-auth/utils@0.2.5': + dependencies: + typescript: 5.8.3 + uncrypto: 0.1.3 + + '@better-fetch/fetch@1.1.18': {} + '@commander-js/extra-typings@14.0.0(commander@14.0.0)': dependencies: commander: 14.0.0 @@ -4016,17 +4240,20 @@ snapshots: - supports-color - vitest - '@fisch0920/drizzle-orm@0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(postgres@3.4.5)': + '@fisch0920/drizzle-orm@0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(kysely@0.28.2)(postgres@3.4.5)': optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/pg': 8.6.1 + kysely: 0.28.2 postgres: 3.4.5 - '@fisch0920/drizzle-zod@0.7.9(@fisch0920/drizzle-orm@0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(postgres@3.4.5))(zod@3.24.4)': + '@fisch0920/drizzle-zod@0.7.9(@fisch0920/drizzle-orm@0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(kysely@0.28.2)(postgres@3.4.5))(zod@3.24.4)': dependencies: - '@fisch0920/drizzle-orm': 0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(postgres@3.4.5) + '@fisch0920/drizzle-orm': 0.43.7(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(kysely@0.28.2)(postgres@3.4.5) zod: 3.24.4 + '@hexagon/base64@1.1.28': {} + '@hono/node-server@1.14.1(hono@4.7.9)': dependencies: hono: 4.7.9 @@ -4061,6 +4288,8 @@ snapshots: '@humanwhocodes/retry@0.4.2': {} + '@inquirer/figures@1.0.11': {} + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -4087,6 +4316,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@levischuck/tiny-cbor@0.2.11': {} + '@modelcontextprotocol/sdk@1.11.2': dependencies: content-type: 1.0.5 @@ -4102,6 +4333,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@noble/ciphers@0.6.0': {} + '@noble/hashes@1.8.0': {} '@nodelib/fs.scandir@2.1.5': @@ -4362,6 +4595,39 @@ snapshots: dependencies: '@noble/hashes': 1.8.0 + '@peculiar/asn1-android@2.3.16': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-ecc@2.3.15': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + '@peculiar/asn1-x509': 2.3.15 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-rsa@2.3.15': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + '@peculiar/asn1-x509': 2.3.15 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-schema@2.3.15': + dependencies: + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509@2.3.15': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + '@pkgjs/parseargs@0.11.0': optional: true @@ -4519,6 +4785,18 @@ snapshots: dependencies: '@sentry/types': 8.9.2 + '@simplewebauthn/browser@13.1.0': {} + + '@simplewebauthn/server@13.1.1': + dependencies: + '@hexagon/base64': 1.1.28 + '@levischuck/tiny-cbor': 0.2.11 + '@peculiar/asn1-android': 2.3.16 + '@peculiar/asn1-ecc': 2.3.15 + '@peculiar/asn1-rsa': 2.3.15 + '@peculiar/asn1-schema': 2.3.15 + '@peculiar/asn1-x509': 2.3.15 + '@sindresorhus/merge-streams@2.3.0': {} '@total-typescript/ts-reset@0.6.1': {} @@ -4529,6 +4807,11 @@ snapshots: '@types/estree@1.0.7': {} + '@types/inquirer@9.0.8': + dependencies: + '@types/through': 0.0.33 + rxjs: 7.8.2 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -4568,6 +4851,10 @@ snapshots: dependencies: '@types/node': 22.15.18 + '@types/through@0.0.33': + dependencies: + '@types/node': 22.15.18 + '@typescript-eslint/eslint-plugin@8.31.0(@typescript-eslint/parser@8.31.0(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0)(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -4730,6 +5017,10 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + ansi-escapes@7.0.0: dependencies: environment: 1.1.0 @@ -4815,6 +5106,12 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + asn1js@3.0.6: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.3 + tslib: 2.8.1 + assertion-error@2.0.1: {} ast-types-flow@0.0.8: {} @@ -4836,8 +5133,38 @@ snapshots: balanced-match@1.0.2: {} + base64-js@1.5.1: {} + bcryptjs@3.0.2: {} + better-auth@1.2.8: + dependencies: + '@better-auth/utils': 0.2.5 + '@better-fetch/fetch': 1.1.18 + '@noble/ciphers': 0.6.0 + '@noble/hashes': 1.8.0 + '@simplewebauthn/browser': 13.1.0 + '@simplewebauthn/server': 13.1.1 + better-call: 1.0.9 + defu: 6.1.4 + jose: 5.10.0 + kysely: 0.28.2 + nanostores: 0.11.4 + zod: 3.24.4 + + better-call@1.0.9: + dependencies: + '@better-fetch/fetch': 1.1.18 + rou3: 0.5.1 + set-cookie-parser: 2.7.1 + uncrypto: 0.1.3 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + body-parser@2.2.0: dependencies: bytes: 3.1.2 @@ -4876,6 +5203,11 @@ snapshots: buffer-from@1.1.2: {} + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + builtin-modules@5.0.0: {} bundle-require@5.1.0(esbuild@0.25.4): @@ -4925,6 +5257,8 @@ snapshots: change-case@5.4.4: {} + chardet@0.7.0: {} + check-error@2.1.1: {} chokidar@4.0.3: @@ -4939,6 +5273,10 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 @@ -4950,6 +5288,10 @@ snapshots: slice-ansi: 5.0.0 string-width: 7.2.0 + cli-width@4.1.0: {} + + clone@1.0.4: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -5051,6 +5393,10 @@ snapshots: deep-is@0.1.4: {} + defaults@1.0.4: + dependencies: + clone: 1.0.4 + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 @@ -5063,6 +5409,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + defu@6.1.4: {} + del-cli@6.0.0: dependencies: del: 8.0.0 @@ -5098,10 +5446,11 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.43.1(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(postgres@3.4.5): + drizzle-orm@0.43.1(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(kysely@0.28.2)(postgres@3.4.5): optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/pg': 8.6.1 + kysely: 0.28.2 postgres: 3.4.5 dunder-proto@1.0.1: @@ -5573,6 +5922,12 @@ snapshots: transitivePeerDependencies: - supports-color + external-editor@3.1.0: + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -5782,10 +6137,16 @@ snapshots: transitivePeerDependencies: - supports-color + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 + ieee754@1.2.1: {} + ignore@5.3.2: {} ignore@7.0.4: {} @@ -5810,6 +6171,21 @@ snapshots: inherits@2.0.4: {} + inquirer@9.3.7: + dependencies: + '@inquirer/figures': 1.0.11 + ansi-escapes: 4.3.2 + cli-width: 4.1.0 + external-editor: 3.1.0 + mute-stream: 1.0.0 + ora: 5.4.1 + run-async: 3.0.0 + rxjs: 7.8.2 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.2 + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -5889,6 +6265,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-interactive@1.0.0: {} + is-interactive@2.0.0: {} is-map@2.0.3: {} @@ -5942,6 +6320,8 @@ snapshots: dependencies: which-typed-array: 1.1.19 + is-unicode-supported@0.1.0: {} + is-unicode-supported@1.3.0: {} is-unicode-supported@2.1.0: {} @@ -5978,6 +6358,8 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jose@5.10.0: {} + joycon@3.1.1: {} js-levenshtein@1.1.6: {} @@ -6045,6 +6427,8 @@ snapshots: ky@1.8.1: {} + kysely@0.28.2: {} + language-subtag-registry@0.3.23: {} language-tags@1.0.9: @@ -6108,6 +6492,11 @@ snapshots: lodash.sortby@4.7.0: {} + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + log-symbols@6.0.0: dependencies: chalk: 5.4.1 @@ -6156,6 +6545,8 @@ snapshots: dependencies: mime-db: 1.54.0 + mimic-fn@2.1.0: {} + mimic-function@5.0.1: {} min-indent@1.0.1: {} @@ -6184,6 +6575,8 @@ snapshots: ms@2.1.3: {} + mute-stream@1.0.0: {} + mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -6194,6 +6587,8 @@ snapshots: nanoid@3.3.11: {} + nanostores@0.11.4: {} + natural-compare@1.4.0: {} negotiator@1.0.0: {} @@ -6269,6 +6664,10 @@ snapshots: dependencies: wrappy: 1.0.2 + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + onetime@7.0.0: dependencies: mimic-function: 5.0.1 @@ -6300,6 +6699,18 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + ora@8.2.0: dependencies: chalk: 5.4.1 @@ -6312,6 +6723,8 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.0 + os-tmpdir@1.0.2: {} + own-keys@1.0.1: dependencies: get-intrinsic: 1.3.0 @@ -6438,6 +6851,12 @@ snapshots: punycode@2.3.1: {} + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.3: {} + qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -6474,6 +6893,12 @@ snapshots: type-fest: 4.41.0 unicorn-magic: 0.1.0 + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + readdirp@4.1.2: {} reflect.getprototypeof@1.0.10: @@ -6534,6 +6959,11 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + restore-cursor@5.1.0: dependencies: onetime: 7.0.0 @@ -6569,6 +6999,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.40.0 fsevents: 2.3.3 + rou3@0.5.1: {} + router@2.2.0: dependencies: debug: 4.4.1(supports-color@10.0.0) @@ -6579,10 +7011,16 @@ snapshots: transitivePeerDependencies: - supports-color + run-async@3.0.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -6639,6 +7077,8 @@ snapshots: transitivePeerDependencies: - supports-color + set-cookie-parser@2.7.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -6703,6 +7143,8 @@ snapshots: siginfo@2.0.0: {} + signal-exit@3.0.7: {} + signal-exit@4.1.0: {} simple-git-hooks@2.13.0: {} @@ -6828,6 +7270,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -6893,6 +7339,10 @@ snapshots: tinyspy@3.0.2: {} + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -6928,6 +7378,8 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 + tslib@2.8.1: {} + tsup@8.4.0(postcss@8.5.3)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.7.1): dependencies: bundle-require: 5.1.0(esbuild@0.25.4) @@ -6993,6 +7445,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@0.21.3: {} + type-fest@4.41.0: {} type-is@2.0.1: @@ -7055,6 +7509,8 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + uncrypto@0.1.3: {} + undici-types@6.21.0: {} unicorn-magic@0.1.0: {} @@ -7075,6 +7531,8 @@ snapshots: dependencies: punycode: 2.3.1 + util-deprecate@1.0.2: {} + uuid@8.3.2: {} validate-npm-package-license@3.0.4: @@ -7169,6 +7627,10 @@ snapshots: - tsx - yaml + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + webidl-conversions@4.0.2: {} whatwg-url@7.1.0: @@ -7237,6 +7699,12 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -7267,6 +7735,8 @@ snapshots: yocto-queue@0.1.0: {} + yoctocolors-cjs@2.1.2: {} + zod-to-json-schema@3.24.5(zod@3.24.4): dependencies: zod: 3.24.4