diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..1dad68d --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(bun run:*)" + ] + } +} diff --git a/.env.example b/.env.example index 1de69cf..8115924 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,5 @@ # docker compose exec backend ./generate_admin_key.sh CONVEX_SELF_HOSTED_ADMIN_KEY= -CONVEX_SELF_HOSTED_URL=http://localhost:3210 \ No newline at end of file +CONVEX_SELF_HOSTED_URL=http://localhost:3210 +# CONVEX_SELF_HOSTED_URL=https://convex.kevisual.cn +CONVEX_SITE_URL=https://api-convex.kevisual.cn \ No newline at end of file diff --git a/convex/_generated/api.d.ts b/convex/_generated/api.d.ts index 49207d5..436ad48 100644 --- a/convex/_generated/api.d.ts +++ b/convex/_generated/api.d.ts @@ -9,7 +9,13 @@ */ import type * as abcv from "../abcv.js"; +<<<<<<< HEAD import type * as xiong from "../xiong.js"; +======= +import type * as actions_jwt from "../actions/jwt.js"; +import type * as actions_redis from "../actions/redis.js"; +import type * as http from "../http.js"; +>>>>>>> 5657bffd39687b05f44247a0318fee65990aa3db import type { ApiFromModules, @@ -19,7 +25,13 @@ import type { declare const fullApi: ApiFromModules<{ abcv: typeof abcv; +<<<<<<< HEAD xiong: typeof xiong; +======= + "actions/jwt": typeof actions_jwt; + "actions/redis": typeof actions_redis; + http: typeof http; +>>>>>>> 5657bffd39687b05f44247a0318fee65990aa3db }>; /** diff --git a/convex/abcv.ts b/convex/abcv.ts index d635bea..c8a3a72 100644 --- a/convex/abcv.ts +++ b/convex/abcv.ts @@ -5,7 +5,10 @@ export const get = query({ args: {}, handler: async (ctx) => { const auth = await ctx.auth.getUserIdentity(); - console.log("Query abcv.get called", auth); + console.log("Query abcv.get called, auth:", auth); + if (auth) { + console.log("Authenticated user ID:", auth.subject); + } return await ctx.db.query("abcv").collect(); }, }); diff --git a/convex/actions/jwt.ts b/convex/actions/jwt.ts new file mode 100644 index 0000000..81c8a86 --- /dev/null +++ b/convex/actions/jwt.ts @@ -0,0 +1,83 @@ +'use node'; + +import * as jose from "jose"; +import type { GenericId } from "convex/values"; + +// JWT 验证配置 +const JWT_CONFIG = { + // jwksUri: "https://kevisual.cn/root/convex/jwks.json", + jwksUri: "http://convex.kevisual.cn:3211/root/convex/jwks.json", + issuer: "https://kevisual.cn", + audience: "test-convex-app", + algorithms: ["RS256"], +}; + +// 创建 JWKS 缓存 +let jwksCache: jose.JWTVerifyGetKey | null = null; + +function getJWKS() { + if (!jwksCache) { + jwksCache = jose.createRemoteJWKSet(new URL(JWT_CONFIG.jwksUri)); + } + return jwksCache; +} + +export const createJwt = async (payload: jose.JWTPayload): Promise => { + const secret = new TextEncoder().encode("your-256-bit-secret"); + const token = await new jose.SignJWT(payload) + .setProtectedHeader({ alg: "HS256", typ: "JWT" }) + .setIssuedAt() + .setExpirationTime("2h") + .sign(secret); + return token; +} +// 验证 JWT token 并返回 payload +export async function verifyToken(token: string): Promise { + const JWKS = getJWKS(); + const { payload } = await jose.jwtVerify(token, JWKS, { + issuer: JWT_CONFIG.issuer, + audience: JWT_CONFIG.audience, + algorithms: JWT_CONFIG.algorithms, + }); + return payload; +} + +// 从请求 header 中提取 Bearer token +export function extractBearerToken(authHeader: string | null): string | null { + if (!authHeader) return null; + const match = authHeader.match(/^Bearer\s+(.+)$/i); + return match ? match[1] : null; +} + +// 获取或创建用户(演示用) +export async function getOrCreateUser( + db: any, + tokenPayload: jose.JWTPayload +): Promise> { + const externalId = tokenPayload.sub as string; + + // 查找已存在的用户 + const existingUser = await db + .query("users") + .withIndex("id", (q: any) => q.eq("id", externalId)) + .first(); + + if (existingUser) { + // 更新最后登录时间 + await db + .table("users") + .doc(existingUser._id) + .patch({ lastLoginAt: new Date().toISOString() }); + return existingUser._id; + } + + // 创建新用户 + return await db + .table("users") + .insert({ + id: externalId, + name: (tokenPayload.name as string) || "Unknown", + email: (tokenPayload.email as string) || "", + createdAt: new Date().toISOString(), + }); +} diff --git a/convex/actions/redis.ts b/convex/actions/redis.ts new file mode 100644 index 0000000..8407254 --- /dev/null +++ b/convex/actions/redis.ts @@ -0,0 +1,22 @@ +'use node'; + +import { query, mutation, action } from "../_generated/server"; +import { Kevisual } from '@kevisual/ai/browser' +import { v } from "convex/values"; +import { Redis } from "ioredis"; +const redisClient = new Redis({ + host: process.env.REDIS_HOST, + password: process.env.REDIS_PASSWORD, +}); +let time: any = null; +export const isConnected = action({ + args: {}, + handler: async (ctx) => { + const result = await redisClient.ping(); + if (time === null) { + time = new Date(); + } + console.log("Redis PING at", new Date().toISOString(), "since", time); + return result === "PONG"; + }, +}); \ No newline at end of file diff --git a/convex/auth.config.ts b/convex/auth.config.ts new file mode 100644 index 0000000..a9ffde1 --- /dev/null +++ b/convex/auth.config.ts @@ -0,0 +1,13 @@ +import { AuthConfig } from "convex/server"; + +export default { + providers: [ + { + type: "customJwt", + applicationID: "convex-app", + issuer: "https://convex.kevisual.cn", + jwks: "https://api-convex.kevisual.cn/root/convex/jwks.json", + algorithm: "RS256", + }, + ], +}; \ No newline at end of file diff --git a/convex/http.ts b/convex/http.ts new file mode 100644 index 0000000..65b482c --- /dev/null +++ b/convex/http.ts @@ -0,0 +1,38 @@ +import { httpRouter } from "convex/server"; +import { httpAction } from "./_generated/server"; +const http = httpRouter(); + +http.route({ + path: "/auth", + method: "POST", + handler: httpAction(async (ctx, request) => { + // 处理请求并返回响应 + return new Response(JSON.stringify({ message: "Hello from custom endpoint!" }), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); + }), +}) + +http.route({ + path: '/root/convex/jwks.json', + method: 'GET', + handler: httpAction(async (ctx, request) => { + // 返回 JWKS 数据 + const jwks = { + "keys": [ + { + "kty": "RSA", + "n": "km4cjJJOMFkl2G5qWMuFmWwF7rmeqRYzYdR8SddKeeMW0e9yIf5pv2Mfwv0aMJUpb-_j3j9M7whx_SEGc_2jx1vxCu1AlYURhnnLTWdsR-ZRPr2LK9UstMrgpWV425R2RliqXTDTYlSxUUlD9nPue_tqbfwN2aM9MCarm67xK_ZCcKRlW9o9L2-9UMfzRA7uiy4VQtOemP0PTXp-E9RxNiMPOQXIRls9wTW_EkDT3dGy7JCZhj7_qib3T8k9m84SwU7wI2R_3IH4DcHSMAn1BRRMXZ1_wPhbP39laNtdJgbDjGCqUccGhLUaoo2WGkZ52eb7NPqamp0K1Dh2jwTIJQ", + "e": "AQAB", + "kid": "kid-key-1" + } + ] + }; + return new Response(JSON.stringify(jwks), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); + }), +}) +export default http; \ No newline at end of file diff --git a/convex/schema.ts b/convex/schema.ts index 4e173e0..dd9f1ae 100644 --- a/convex/schema.ts +++ b/convex/schema.ts @@ -1,6 +1,6 @@ import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; - +import { authTables } from "@convex-dev/auth/server"; // Define a messages table with an index. export default defineSchema({ abcv: defineTable({ @@ -9,4 +9,16 @@ export default defineSchema({ xiong: defineTable({ name: v.string(), }), + users: defineTable({ + id: v.string(), // 外部系统的用户 ID + name: v.string(), + createdAt: v.string(), + lastLoginAt: v.optional(v.string()), + }).index("id", ["id"]), + sessions: defineTable({ + userId: v.id("users"), + createdAt: v.string(), + expiresAt: v.optional(v.string()), + token: v.optional(v.string()), + }).index("token", ["token"]), }); \ No newline at end of file diff --git a/demos/auth.config.ts b/demos/auth.config.ts new file mode 100644 index 0000000..1027710 --- /dev/null +++ b/demos/auth.config.ts @@ -0,0 +1,6 @@ +import { getAuthConfigProvider } from "@convex-dev/better-auth/auth-config"; +import type { AuthConfig } from "convex/server"; + +export default { + providers: [getAuthConfigProvider()], +} satisfies AuthConfig; \ No newline at end of file diff --git a/demos/convex.config.ts b/demos/convex.config.ts new file mode 100644 index 0000000..a49fc73 --- /dev/null +++ b/demos/convex.config.ts @@ -0,0 +1,7 @@ +import { defineApp } from "convex/server"; +import betterAuth from "@convex-dev/better-auth/convex.config"; + +const app = defineApp(); +app.use(betterAuth); + +export default app; \ No newline at end of file diff --git a/generate-jwks.ts b/generate-jwks.ts new file mode 100644 index 0000000..012c976 --- /dev/null +++ b/generate-jwks.ts @@ -0,0 +1,40 @@ +import * as jose from 'jose'; +import fs from 'node:fs' +async function generateKeyPair() { + const { privateKey, publicKey } = await jose.generateKeyPair('RS256', { + modulusLength: 2048, + extractable: true, + }); + + return { privateKey, publicKey }; +} + +async function createJWKS(publicKey: CryptoKey) { + const jwk = await jose.exportJWK(publicKey); + // 添加 kid 字段 + jwk.kid = 'kid-key-1'; + const jwks = { + keys: [jwk] + }; + return jwks; +} + +async function main() { + const { privateKey, publicKey } = await generateKeyPair(); + const jwks = await createJWKS(publicKey); + + // 将私钥和 JWKS 保存到文件 + const privateJWK = await jose.exportJWK(privateKey); + const privatePEM = await jose.exportPKCS8(privateKey); + const publicPEM = await jose.exportSPKI(publicKey); + fs.writeFileSync('jwt/publicKey.txt', publicPEM); + + fs.writeFileSync('jwt/privateKey.txt', privatePEM); + + fs.writeFileSync('jwt/privateKey.json', JSON.stringify(privateJWK, null, 2)); + fs.writeFileSync('jwt/jwks.json', JSON.stringify(jwks, null, 2)); + + console.log('Private key and JWKS have been saved to files.'); +} + +main().catch(console.error); \ No newline at end of file diff --git a/html/index.html b/html/index.html new file mode 100644 index 0000000..6ed4d1e --- /dev/null +++ b/html/index.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/html/src/b.ts b/html/src/b.ts new file mode 100644 index 0000000..8de1466 --- /dev/null +++ b/html/src/b.ts @@ -0,0 +1,35 @@ +// const jwtToken = "..."; +console.log("jose loaded:", Math.floor(Date.now() / 1000) + 3600); +import { api } from "../../convex/_generated/api.js"; +import { ConvexClient, AuthTokenFetcher } from "convex/browser"; +const CONVEX_URL = "https://convex.kevisual.cn"; +const client = new ConvexClient(CONVEX_URL, { +}); +// 生成 RS256 JWT +const jwtToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InRlc3Qta2V5LTEifQ.eyJpc3MiOiJodHRwczovL2NvbnZleC5rZXZpc3VhbC5jbiIsInN1YiI6InVzZXI6OGZhMmJlNzNjMjIyOWU4NSIsImF1ZCI6InRlc3QtY29udmV4LWFwcCIsImV4cCI6MTc2OTE4MDE1MSwibmFtZSI6IlRlc3QgVXNlciIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSJ9.Kqkzs9qvisOjo4QGvUgc1J9m0MFO2H2KKnghx00LMsBoMciOGggGYwnn1tuhHwNmxUBhUHl9M2nmA8L2ict24mV28iKaFbbDEVTMAFkNsHHrkEO1VCtBypwMfC8xwmWMfAb_lrz0u5DXv19xhAA6LZN55DGrP3SibWyrNejhd3o64VGr9NEP-Ko8c8fZZdtM6dMW8HN2jKC2RaO3wpD8DUfZA1UQrKeWRBoQ1g5zPA4zwfIREoVx7Iudnb-wVqXojj5BIfnS2mWB76Ukyb_OkpJDn2Oh-wBFqj8YRpUpH_-oh_rsS2gpO5aHzwmVEQ4JRG1YASlV5jKlPiwDz7xHFQ" +const main = async () => { + const res = await fetch("https://api-convex.kevisual.cn/abcv/get", { + headers: { + Authorization: `Bearer ${jwtToken}`, + }, + }).then((r) => r.text()); + console.log("Fetch response:", res); +} +// main(); + +const main2 = async () => { + client.setAuth(async ({ forceRefreshToken }: { forceRefreshToken: boolean }) => { + console.log("AuthTokenFetcher called, forceRefreshToken:", forceRefreshToken); + return jwtToken; + }, async (isAuthenticated) => { + console.log("Auth state isAuthenticated", isAuthenticated); + if (isAuthenticated) { + const list = await client.query(api.abcv.get, {}); + console.log("Initial list:", list); + } + const isAuth = client.client.hasAuth(); + console.log("Has auth:", isAuth); + }); + +} +main2(); \ No newline at end of file diff --git a/html/src/index.ts b/html/src/index.ts new file mode 100644 index 0000000..e7912a6 --- /dev/null +++ b/html/src/index.ts @@ -0,0 +1,24 @@ +import { ConvexClient, AuthTokenFetcher } from "convex/browser"; +import { api } from "../../convex/_generated/api.js"; +const CONVEX_URL = "https://convex.kevisual.cn"; +const client = new ConvexClient(CONVEX_URL, { + unsavedChangesWarning: true, +}); + +client.setAuth(async ({ forceRefreshToken }: { forceRefreshToken: boolean }) => { + console.log("AuthTokenFetcher called, forceRefreshToken:", forceRefreshToken); + return null; +}, (isAuthenticated) => { + console.log("Auth state isAuthenticated", isAuthenticated); +}); +client.onUpdate(api.abcv.get, {}, (tasks) => + console.log('api.abcv.get', tasks), +); + + +const list = await client.query(api.abcv.get, {}); +console.log("Initial list:", list); + + +// const list = await client.action(api.abcv.chat, { message: "Hello, 1+1=?" }); +// console.log("Chat response:", list); \ No newline at end of file diff --git a/index.ts b/index.ts index 5a3e865..35ca8b5 100644 --- a/index.ts +++ b/index.ts @@ -1,22 +1,52 @@ import { ConvexClient, AuthTokenFetcher } from "convex/browser"; import { api } from "./convex/_generated/api.js"; +import * as jose from "jose"; const url = process.env["CONVEX_URL"] const client = new ConvexClient(url!); -console.log("Client created", url); + +// 加载测试私钥 +const keys = JSON.parse(await Bun.file("./jwt/privateKey.json").text()); +const privateKey = await jose.importJWK(keys, "RS256"); + +// 生成 RS256 JWT +const payload = { + iss: "https://convex.kevisual.cn", + sub: "user:8fa2be73c2229e85", + aud: "convex-app", + exp: Math.floor(Date.now() / 1000) + 3600, + name: "Test User AA", + email: "test@example.com", +}; +const token = await new jose.SignJWT(payload) + .setProtectedHeader({ + "alg": "RS256", + "typ": "JWT", + "kid": "kid-key-1" + }) + .setIssuedAt() + .sign(privateKey); + +console.log("Generated RS256 token:", token); + const authTokenFetcher: AuthTokenFetcher = async ({ forceRefreshToken }: { forceRefreshToken: boolean }) => { console.log("AuthTokenFetcher called, forceRefreshToken:", forceRefreshToken); - return null; + return token; } -const _auth = await client.setAuth(authTokenFetcher, () => { }) -const auth = client.getAuth(); -console.log("Client auth", auth); +client.setAuth(authTokenFetcher, (isAuthenticated) => { + console.log("Auth isAuthenticated:", isAuthenticated); +}); +// console.log("Auth set up", auth); +await Bun.sleep(1000); +// const auth = client.getAuth(); +// console.log("Client auth", auth); const unsubscribe = client.onUpdate(api.abcv.get, {}, async (tasks) => { console.log(tasks); }); -// const list = await client.query(api.abcv.get, {}); -// console.log("Initial list:", list); +const list = await client.query(api.abcv.get, {}); +console.log("Initial list:", list); + // for (let i = 0; i < list.length; i++) { // const a = list[i]; // console.log(`Item ${i}:`, a.title); @@ -25,6 +55,18 @@ const unsubscribe = client.onUpdate(api.abcv.get, {}, async (tasks) => { // console.log("Chat response:", list); const xiongList = await client.query(api.xiong.get, {}); console.log("Xiong list:", xiongList); +// const redisIsConnected = await client.action(api.actions.redis.isConnected, {}); +// console.log("Redis isConnected:", redisIsConnected); +// const sign = await api.auth.signIn({ provider: "convex" }) +// const sign = await httpClient.action("/auth", { method: "POST" }); +// console.log("Sign in result:", sign); + +const res = await fetch("http://convex.kevisual.cn:3211/auth", { + method: "POST", +}); + +const data = await res.json(); +console.log("Custom endpoint response:", data); await Bun.sleep(1000); unsubscribe(); await client.close(); \ No newline at end of file diff --git a/jwt/jwks.json b/jwt/jwks.json new file mode 100644 index 0000000..41ea0b7 --- /dev/null +++ b/jwt/jwks.json @@ -0,0 +1,10 @@ +{ + "keys": [ + { + "kty": "RSA", + "n": "km4cjJJOMFkl2G5qWMuFmWwF7rmeqRYzYdR8SddKeeMW0e9yIf5pv2Mfwv0aMJUpb-_j3j9M7whx_SEGc_2jx1vxCu1AlYURhnnLTWdsR-ZRPr2LK9UstMrgpWV425R2RliqXTDTYlSxUUlD9nPue_tqbfwN2aM9MCarm67xK_ZCcKRlW9o9L2-9UMfzRA7uiy4VQtOemP0PTXp-E9RxNiMPOQXIRls9wTW_EkDT3dGy7JCZhj7_qib3T8k9m84SwU7wI2R_3IH4DcHSMAn1BRRMXZ1_wPhbP39laNtdJgbDjGCqUccGhLUaoo2WGkZ52eb7NPqamp0K1Dh2jwTIJQ", + "e": "AQAB", + "kid": "kid-key-1" + } + ] +} \ No newline at end of file diff --git a/jwt/privateKey.json b/jwt/privateKey.json new file mode 100644 index 0000000..5972c3a --- /dev/null +++ b/jwt/privateKey.json @@ -0,0 +1,11 @@ +{ + "kty": "RSA", + "n": "km4cjJJOMFkl2G5qWMuFmWwF7rmeqRYzYdR8SddKeeMW0e9yIf5pv2Mfwv0aMJUpb-_j3j9M7whx_SEGc_2jx1vxCu1AlYURhnnLTWdsR-ZRPr2LK9UstMrgpWV425R2RliqXTDTYlSxUUlD9nPue_tqbfwN2aM9MCarm67xK_ZCcKRlW9o9L2-9UMfzRA7uiy4VQtOemP0PTXp-E9RxNiMPOQXIRls9wTW_EkDT3dGy7JCZhj7_qib3T8k9m84SwU7wI2R_3IH4DcHSMAn1BRRMXZ1_wPhbP39laNtdJgbDjGCqUccGhLUaoo2WGkZ52eb7NPqamp0K1Dh2jwTIJQ", + "e": "AQAB", + "d": "Ewq7rrIV9eaZ68_MB5kL2hw4l0dPMSjgbK_vq8CSAFC-NnW_b1lA0jEnP7mfTsMO_O4CwXOU4x7DiAnj53CL_FBiA6w_slH4Kfcrr3isFZuHZDPM5dnWcvpRBWExOsjPKq28FdtUGdzupCX1bxa7ZCcZO41EFdHLErhsp5Wz6iXtNwkQUDSBnyCVbWh7Pn8M1TT5iw3hF9GBTrrN-Nfy6C_7G1W1QuotLoUEbyn0QH-9Xttt0wFgNkEBjDe4SrvRWzuUvucBAP8GXUKxEKsv3pQX5lZWxR85fJyLhJSeZK84lzydDkZuQWTCXQprsSzUNFaB5UC6ZqKzCARZPBFhMQ", + "p": "xaLneraHzmgkfeyr5I1cUpTbSy2thtiGJnu5StMWcNqYIJtTsdf4nIcIx97VUxhE3BRAxyaPa2aLQjo-o1sMMZu_b4iqEppNrSblueOUojOm8DJ6UwTUM8hZYp07T6ufq9MYPWEJF_lrJNH9zXRAlpAb7H2inixpWCoBXDEqTMk", + "q": "vawSZQcxEMj__EVl-gxQA6GPwmCAdUUFE38Z9PMJMcBPGjEdBT7ll9l2PrsyFnAm6KPAR3MKF7EqcIPwRC4ZsXmE3pgfV7x9GB0fOGnjWh_XxVGvJjPrH52JSHcQUiqO0ym5evTfYNwH7b2N0wYZbmelDV8l5JG76nRJDujZ-n0", + "dp": "PXiNxv0_AFQkBYa3cD8HmCf0jU2Hy4lNMGsLFtrRAAj9iCbHwWkLSqQ1dvU4JMBHqqwh-c9kjGM4rUCwet62zDdFM8uuGlskDdcrXMYMVOb75XnN0kSOPAz0wFdnO0CGSUs_Htgvm-VYDfvClUSzUiFAji4Fhm0J1wI5qhMgtQE", + "dq": "VY2dCnbw-cpANRE0i1IscUbZqmqO5taIEKA_HA7X8dn1lDHdDjWtqA3N2UPkttxFoJ_kJhZM0hz2sKPCp25H5paSiTkCwjdiEZNpNrAEfe1pDTboEwpOHweXGdmiwf0ySStD36M-ctkstl7O7wWMSRF1EI__bpcRtRJYteHwGJ0", + "qi": "sxCqC7NKEkPWyBSKiGfGrjLxf3OL2dOjyUBvdxQUiK0L4JJTXfPf2PAYCwY3J1CawDC8weEislOSo4Q4pcKkH3nkI2zVC7fnwRXWttmEXNr-Px5pJg8yoIcFjwVa-mBSgjCo_v72sRGBHGQZY1Y7Xh5P78LpsfGEaBK6g_fWfZs" +} \ No newline at end of file diff --git a/jwt/privateKey.txt b/jwt/privateKey.txt new file mode 100644 index 0000000..6d14bc9 --- /dev/null +++ b/jwt/privateKey.txt @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCSbhyMkk4wWSXY +bmpYy4WZbAXuuZ6pFjNh1HxJ10p54xbR73Ih/mm/Yx/C/RowlSlv7+PeP0zvCHH9 +IQZz/aPHW/EK7UCVhRGGectNZ2xH5lE+vYsr1Sy0yuClZXjblHZGWKpdMNNiVLFR +SUP2c+57+2pt/A3Zoz0wJqubrvEr9kJwpGVb2j0vb71Qx/NEDu6LLhVC056Y/Q9N +en4T1HE2Iw85BchGWz3BNb8SQNPd0bLskJmGPv+qJvdPyT2bzhLBTvAjZH/cgfgN +wdIwCfUFFExdnX/A+Fs/f2Vo210mBsOMYKpRxwaEtRqijZYaRnnZ5vs0+pqanQrU +OHaPBMglAgMBAAECggEAEwq7rrIV9eaZ68/MB5kL2hw4l0dPMSjgbK/vq8CSAFC+ +NnW/b1lA0jEnP7mfTsMO/O4CwXOU4x7DiAnj53CL/FBiA6w/slH4Kfcrr3isFZuH +ZDPM5dnWcvpRBWExOsjPKq28FdtUGdzupCX1bxa7ZCcZO41EFdHLErhsp5Wz6iXt +NwkQUDSBnyCVbWh7Pn8M1TT5iw3hF9GBTrrN+Nfy6C/7G1W1QuotLoUEbyn0QH+9 +Xttt0wFgNkEBjDe4SrvRWzuUvucBAP8GXUKxEKsv3pQX5lZWxR85fJyLhJSeZK84 +lzydDkZuQWTCXQprsSzUNFaB5UC6ZqKzCARZPBFhMQKBgQDFoud6tofOaCR97Kvk +jVxSlNtLLa2G2IYme7lK0xZw2pggm1Ox1/ichwjH3tVTGETcFEDHJo9rZotCOj6j +Wwwxm79viKoSmk2tJuW545SiM6bwMnpTBNQzyFlinTtPq5+r0xg9YQkX+Wsk0f3N +dECWkBvsfaKeLGlYKgFcMSpMyQKBgQC9rBJlBzEQyP/8RWX6DFADoY/CYIB1RQUT +fxn08wkxwE8aMR0FPuWX2XY+uzIWcCboo8BHcwoXsSpwg/BELhmxeYTemB9XvH0Y +HR84aeNaH9fFUa8mM+sfnYlIdxBSKo7TKbl69N9g3AftvY3TBhluZ6UNXyXkkbvq +dEkO6Nn6fQKBgD14jcb9PwBUJAWGt3A/B5gn9I1Nh8uJTTBrCxba0QAI/Ygmx8Fp +C0qkNXb1OCTAR6qsIfnPZIxjOK1AsHretsw3RTPLrhpbJA3XK1zGDFTm++V5zdJE +jjwM9MBXZztAhklLPx7YL5vlWA37wpVEs1IhQI4uBYZtCdcCOaoTILUBAoGAVY2d +Cnbw+cpANRE0i1IscUbZqmqO5taIEKA/HA7X8dn1lDHdDjWtqA3N2UPkttxFoJ/k +JhZM0hz2sKPCp25H5paSiTkCwjdiEZNpNrAEfe1pDTboEwpOHweXGdmiwf0ySStD +36M+ctkstl7O7wWMSRF1EI//bpcRtRJYteHwGJ0CgYEAsxCqC7NKEkPWyBSKiGfG +rjLxf3OL2dOjyUBvdxQUiK0L4JJTXfPf2PAYCwY3J1CawDC8weEislOSo4Q4pcKk +H3nkI2zVC7fnwRXWttmEXNr+Px5pJg8yoIcFjwVa+mBSgjCo/v72sRGBHGQZY1Y7 +Xh5P78LpsfGEaBK6g/fWfZs= +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/jwt/publicKey.txt b/jwt/publicKey.txt new file mode 100644 index 0000000..aefc132 --- /dev/null +++ b/jwt/publicKey.txt @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkm4cjJJOMFkl2G5qWMuF +mWwF7rmeqRYzYdR8SddKeeMW0e9yIf5pv2Mfwv0aMJUpb+/j3j9M7whx/SEGc/2j +x1vxCu1AlYURhnnLTWdsR+ZRPr2LK9UstMrgpWV425R2RliqXTDTYlSxUUlD9nPu +e/tqbfwN2aM9MCarm67xK/ZCcKRlW9o9L2+9UMfzRA7uiy4VQtOemP0PTXp+E9Rx +NiMPOQXIRls9wTW/EkDT3dGy7JCZhj7/qib3T8k9m84SwU7wI2R/3IH4DcHSMAn1 +BRRMXZ1/wPhbP39laNtdJgbDjGCqUccGhLUaoo2WGkZ52eb7NPqamp0K1Dh2jwTI +JQIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/package.json b/package.json index d4c09cc..ac306de 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,17 @@ "type": "module", "private": true, "devDependencies": { + "@convex-dev/better-auth": "^0.10.10", "@kevisual/ai": "^0.0.21", - "@types/bun": "latest" + "@types/bun": "latest", + "ioredis": "^5.9.2" }, "peerDependencies": { "typescript": "^5" }, "dependencies": { - "convex": "^1.31.6" + "@convex-dev/auth": "^0.0.90", + "convex": "^1.31.6", + "jose": "^6.1.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f0d2c8..162a1f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,19 +8,98 @@ importers: .: dependencies: + '@convex-dev/auth': + specifier: ^0.0.90 + version: 0.0.90(@auth/core@0.37.4)(convex@1.31.6(react@19.2.3))(react@19.2.3) convex: specifier: ^1.31.6 - version: 1.31.6 + version: 1.31.6(react@19.2.3) + jose: + specifier: ^6.1.3 + version: 6.1.3 + typescript: + specifier: ^5 + version: 5.9.3 devDependencies: + '@convex-dev/better-auth': + specifier: ^0.10.10 + version: 0.10.10(@better-auth/core@1.4.9(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.7(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0))(@better-auth/utils@0.3.0)(@standard-schema/spec@1.1.0)(better-auth@1.4.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(better-call@1.1.7(zod@4.3.6))(convex@1.31.6(react@19.2.3))(nanostores@1.1.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) '@kevisual/ai': specifier: ^0.0.21 version: 0.0.21 '@types/bun': specifier: latest version: 1.3.6 + ioredis: + specifier: ^5.9.2 + version: 5.9.2 packages: + '@auth/core@0.37.4': + resolution: {integrity: sha512-HOXJwXWXQRhbBDHlMU0K/6FT1v+wjtzdKhsNg0ZN7/gne6XPsIrjZ4daMcFnbq0Z/vsAbYBinQhhua0d77v7qw==} + peerDependencies: + '@simplewebauthn/browser': ^9.0.1 + '@simplewebauthn/server': ^9.0.2 + nodemailer: ^6.8.0 + peerDependenciesMeta: + '@simplewebauthn/browser': + optional: true + '@simplewebauthn/server': + optional: true + nodemailer: + optional: true + + '@better-auth/core@1.4.9': + resolution: {integrity: sha512-JT2q4NDkQzN22KclUEoZ7qU6tl9HUTfK1ctg2oWlT87SEagkwJcnrUwS9VznL+u9ziOIfY27P0f7/jSnmvLcoQ==} + peerDependencies: + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.21 + better-call: 1.1.7 + jose: ^6.1.0 + kysely: ^0.28.5 + nanostores: ^1.0.1 + + '@better-auth/passkey@1.4.9': + resolution: {integrity: sha512-fPsV0LYbmPytxrTaltM2RXbJnmSttX9UWr4wkZtJYgCBGeFqN8+8ZzBTZXOymWDJTVQ0kVZrD7c7/HyxXEG1zA==} + peerDependencies: + '@better-auth/core': 1.4.9 + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.21 + better-auth: 1.4.9 + better-call: 1.1.7 + nanostores: ^1.0.1 + + '@better-auth/telemetry@1.4.9': + resolution: {integrity: sha512-Tthy1/Gmx+pYlbvRQPBTKfVei8+pJwvH1NZp+5SbhwA6K2EXIaoonx/K6N/AXYs2aKUpyR4/gzqDesDjL7zd6A==} + peerDependencies: + '@better-auth/core': 1.4.9 + + '@better-auth/utils@0.3.0': + resolution: {integrity: sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==} + + '@better-fetch/fetch@1.1.21': + resolution: {integrity: sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==} + + '@convex-dev/auth@0.0.90': + resolution: {integrity: sha512-aqw88EB042HvnaF4wcf/f/wTocmT2Bus2VDQRuV79cM0+8kORM0ICK/ByZ6XsHgQ9qr6TmidNbXm6QAgndrdpQ==} + hasBin: true + peerDependencies: + '@auth/core': ^0.37.0 + convex: ^1.17.0 + react: ^18.2.0 || ^19.0.0-0 + peerDependenciesMeta: + react: + optional: true + + '@convex-dev/better-auth@0.10.10': + resolution: {integrity: sha512-BpwQ2kph43O7hmtGQAJ+ie3KrjONp83659QDjKDdH+X8yIdGevgehaqS5GHB0iJo7zQTtvs687GnAeLZ4Xx3/w==} + peerDependencies: + better-auth: 1.4.9 + convex: ^1.25.0 + react: ^18.3.1 || ^19.0.0 + react-dom: ^18.3.1 || ^19.0.0 + '@esbuild/aix-ppc64@0.27.0': resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==} engines: {node: '>=18'} @@ -177,6 +256,12 @@ packages: cpu: [x64] os: [win32] + '@hexagon/base64@1.1.28': + resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} + + '@ioredis/commands@1.5.0': + resolution: {integrity: sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow==} + '@kevisual/ai@0.0.21': resolution: {integrity: sha512-4YvnEDpgCje3jDZug95pXzmIS4jHHulDjXONXSWLScsSLiqIRZnZQ6K+2IbCnIDAFmGIBYR/xFt0fyJIKJmrDQ==} @@ -189,15 +274,189 @@ packages: '@kevisual/query@0.0.35': resolution: {integrity: sha512-80dyy2LMCmEC72g+X4QWUKlZErhawQPgnGSBNR4yhrBcFgHIJQ14LR1Z+bS5S1I7db+1PDNpaxBTjIaoYoXunw==} + '@levischuck/tiny-cbor@0.2.11': + resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==} + + '@noble/ciphers@2.1.1': + resolution: {integrity: sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw==} + engines: {node: '>= 20.19.0'} + + '@noble/hashes@2.0.1': + resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} + engines: {node: '>= 20.19.0'} + + '@oslojs/asn1@1.0.0': + resolution: {integrity: sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==} + + '@oslojs/binary@1.0.0': + resolution: {integrity: sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==} + + '@oslojs/crypto@1.0.1': + resolution: {integrity: sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==} + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + + '@panva/hkdf@1.2.1': + resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} + + '@peculiar/asn1-android@2.6.0': + resolution: {integrity: sha512-cBRCKtYPF7vJGN76/yG8VbxRcHLPF3HnkoHhKOZeHpoVtbMYfY9ROKtH3DtYUY9m8uI1Mh47PRhHf2hSK3xcSQ==} + + '@peculiar/asn1-cms@2.6.0': + resolution: {integrity: sha512-2uZqP+ggSncESeUF/9Su8rWqGclEfEiz1SyU02WX5fUONFfkjzS2Z/F1Li0ofSmf4JqYXIOdCAZqIXAIBAT1OA==} + + '@peculiar/asn1-csr@2.6.0': + resolution: {integrity: sha512-BeWIu5VpTIhfRysfEp73SGbwjjoLL/JWXhJ/9mo4vXnz3tRGm+NGm3KNcRzQ9VMVqwYS2RHlolz21svzRXIHPQ==} + + '@peculiar/asn1-ecc@2.6.0': + resolution: {integrity: sha512-FF3LMGq6SfAOwUG2sKpPXblibn6XnEIKa+SryvUl5Pik+WR9rmRA3OCiwz8R3lVXnYnyRkSZsSLdml8H3UiOcw==} + + '@peculiar/asn1-pfx@2.6.0': + resolution: {integrity: sha512-rtUvtf+tyKGgokHHmZzeUojRZJYPxoD/jaN1+VAB4kKR7tXrnDCA/RAWXAIhMJJC+7W27IIRGe9djvxKgsldCQ==} + + '@peculiar/asn1-pkcs8@2.6.0': + resolution: {integrity: sha512-KyQ4D8G/NrS7Fw3XCJrngxmjwO/3htnA0lL9gDICvEQ+GJ+EPFqldcJQTwPIdvx98Tua+WjkdKHSC0/Km7T+lA==} + + '@peculiar/asn1-pkcs9@2.6.0': + resolution: {integrity: sha512-b78OQ6OciW0aqZxdzliXGYHASeCvvw5caqidbpQRYW2mBtXIX2WhofNXTEe7NyxTb0P6J62kAAWLwn0HuMF1Fw==} + + '@peculiar/asn1-rsa@2.6.0': + resolution: {integrity: sha512-Nu4C19tsrTsCp9fDrH+sdcOKoVfdfoQQ7S3VqjJU6vedR7tY3RLkQ5oguOIB3zFW33USDUuYZnPEQYySlgha4w==} + + '@peculiar/asn1-schema@2.6.0': + resolution: {integrity: sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==} + + '@peculiar/asn1-x509-attr@2.6.0': + resolution: {integrity: sha512-MuIAXFX3/dc8gmoZBkwJWxUWOSvG4MMDntXhrOZpJVMkYX+MYc/rUAU2uJOved9iJEoiUx7//3D8oG83a78UJA==} + + '@peculiar/asn1-x509@2.6.0': + resolution: {integrity: sha512-uzYbPEpoQiBoTq0/+jZtpM6Gq6zADBx+JNFP3yqRgziWBxQ/Dt/HcuvRfm9zJTPdRcBqPNdaRHTVwpyiq6iNMA==} + + '@peculiar/x509@1.14.3': + resolution: {integrity: sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==} + engines: {node: '>=20.0.0'} + + '@simplewebauthn/browser@13.2.2': + resolution: {integrity: sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA==} + + '@simplewebauthn/server@13.2.2': + resolution: {integrity: sha512-HcWLW28yTMGXpwE9VLx9J+N2KEUaELadLrkPEEI9tpI5la70xNEVEsu/C+m3u7uoq4FulLqZQhgBCzR9IZhFpA==} + engines: {node: '>=20.0.0'} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@types/bun@1.3.6': resolution: {integrity: sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA==} '@types/node@25.0.10': resolution: {integrity: sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg==} + asn1js@3.0.7: + resolution: {integrity: sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==} + engines: {node: '>=12.0.0'} + + better-auth@1.4.9: + resolution: {integrity: sha512-usSdjuyTzZwIvM8fjF8YGhPncxV3MAg3dHUO9uPUnf0yklXUSYISiH1+imk6/Z+UBqsscyyPRnbIyjyK97p7YA==} + peerDependencies: + '@lynx-js/react': '*' + '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 + '@sveltejs/kit': ^2.0.0 + '@tanstack/react-start': ^1.0.0 + better-sqlite3: ^12.0.0 + drizzle-kit: '>=0.31.4' + drizzle-orm: '>=0.41.0' + mongodb: ^6.0.0 || ^7.0.0 + mysql2: ^3.0.0 + next: ^14.0.0 || ^15.0.0 || ^16.0.0 + pg: ^8.0.0 + prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + solid-js: ^1.0.0 + svelte: ^4.0.0 || ^5.0.0 + vitest: ^2.0.0 || ^3.0.0 || ^4.0.0 + vue: ^3.0.0 + peerDependenciesMeta: + '@lynx-js/react': + optional: true + '@prisma/client': + optional: true + '@sveltejs/kit': + optional: true + '@tanstack/react-start': + optional: true + better-sqlite3: + optional: true + drizzle-kit: + optional: true + drizzle-orm: + optional: true + mongodb: + optional: true + mysql2: + optional: true + next: + optional: true + pg: + optional: true + prisma: + optional: true + react: + optional: true + react-dom: + optional: true + solid-js: + optional: true + svelte: + optional: true + vitest: + optional: true + vue: + optional: true + + better-call@1.1.7: + resolution: {integrity: sha512-6gaJe1bBIEgVebQu/7q9saahVzvBsGaByEnE8aDVncZEDiJO7sdNB28ot9I6iXSbR25egGmmZ6aIURXyQHRraQ==} + peerDependencies: + zod: ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + bun-types@1.3.6: resolution: {integrity: sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ==} + cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + + common-tags@1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + + convex-helpers@0.1.111: + resolution: {integrity: sha512-0O59Ohi8HVc3+KULxSC6JHsw8cQJyc8gZ7OAfNRVX7T5Wy6LhPx3l8veYN9avKg7UiPlO7m1eBiQMHKclIyXyQ==} + hasBin: true + peerDependencies: + '@standard-schema/spec': ^1.0.0 + convex: ^1.25.4 + hono: ^4.0.5 + react: ^17.0.2 || ^18.0.0 || ^19.0.0 + typescript: ^5.5 + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + '@standard-schema/spec': + optional: true + hono: + optional: true + react: + optional: true + typescript: + optional: true + zod: + optional: true + convex@1.31.6: resolution: {integrity: sha512-9cIsOzepa3s9DURRF+fZHxbNuzLgilg9XGQCc45v0Xx4FemqeIezpPFSJF9WHC9ckk43TDUUXLecvLVt9djPkw==} engines: {node: '>=18.0.0', npm: '>=7.0.0'} @@ -214,24 +473,248 @@ packages: react: optional: true + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + esbuild@0.27.0: resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==} engines: {node: '>=18'} hasBin: true + ioredis@5.9.2: + resolution: {integrity: sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==} + engines: {node: '>=12.22.0'} + + is-network-error@1.3.0: + resolution: {integrity: sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw==} + engines: {node: '>=16'} + + jose@5.10.0: + resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} + + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + + jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} + + kysely@0.28.10: + resolution: {integrity: sha512-ksNxfzIW77OcZ+QWSAPC7yDqUSaIVwkTWnTPNiIy//vifNbwsSgQ57OkkncHxxpcBHM3LRfLAZVEh7kjq5twVA==} + engines: {node: '>=20.0.0'} + + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.isarguments@3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + + lucia@3.2.2: + resolution: {integrity: sha512-P1FlFBGCMPMXu+EGdVD9W4Mjm0DqsusmKgO7Xc33mI5X1bklmsQb0hfzPhXomQr9waWIBDsiOjvr1e6BTaUqpA==} + deprecated: This package has been deprecated. Please see https://lucia-auth.com/lucia-v3/migrate. + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanostores@1.1.0: + resolution: {integrity: sha512-yJBmDJr18xy47dbNVlHcgdPrulSn1nhSE6Ns9vTG+Nx9VPT6iV1MD6aQFp/t52zpf82FhLLTXAXr30NuCnxvwA==} + engines: {node: ^20.0.0 || >=22.0.0} + + oauth4webapi@3.8.3: + resolution: {integrity: sha512-pQ5BsX3QRTgnt5HxgHwgunIRaDXBdkT23tf8dfzmtTIL2LTpdmxgbpbBm0VgFWAIDlezQvQCTgnVIUmHupXHxw==} + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + preact-render-to-string@6.5.11: + resolution: {integrity: sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==} + peerDependencies: + preact: '>=10' + + preact@10.24.3: + resolution: {integrity: sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==} + prettier@3.8.1: resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} engines: {node: '>=14'} hasBin: true + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.5: + resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} + engines: {node: '>=16.0.0'} + + react-dom@19.2.3: + resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} + peerDependencies: + react: ^19.2.3 + + react@19.2.3: + resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} + engines: {node: '>=0.10.0'} + + redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + + redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} + + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + + remeda@2.33.4: + resolution: {integrity: sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==} + + rou3@0.7.12: + resolution: {integrity: sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + server-only@0.0.1: + resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} + + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + + standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsyringe@4.10.0: + resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} + engines: {node: '>= 6.0.0'} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + snapshots: + '@auth/core@0.37.4': + dependencies: + '@panva/hkdf': 1.2.1 + jose: 5.10.0 + oauth4webapi: 3.8.3 + preact: 10.24.3 + preact-render-to-string: 6.5.11(preact@10.24.3) + + '@better-auth/core@1.4.9(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.7(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0)': + dependencies: + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.21 + '@standard-schema/spec': 1.1.0 + better-call: 1.1.7(zod@4.3.6) + jose: 6.1.3 + kysely: 0.28.10 + nanostores: 1.1.0 + zod: 4.3.6 + + '@better-auth/passkey@1.4.9(@better-auth/core@1.4.9(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.7(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0))(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-auth@1.4.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(better-call@1.1.7(zod@4.3.6))(nanostores@1.1.0)': + dependencies: + '@better-auth/core': 1.4.9(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.7(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0) + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.21 + '@simplewebauthn/browser': 13.2.2 + '@simplewebauthn/server': 13.2.2 + better-auth: 1.4.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + better-call: 1.1.7(zod@4.3.6) + nanostores: 1.1.0 + zod: 4.3.6 + + '@better-auth/telemetry@1.4.9(@better-auth/core@1.4.9(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.7(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0))': + dependencies: + '@better-auth/core': 1.4.9(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.7(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0) + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.21 + + '@better-auth/utils@0.3.0': {} + + '@better-fetch/fetch@1.1.21': {} + + '@convex-dev/auth@0.0.90(@auth/core@0.37.4)(convex@1.31.6(react@19.2.3))(react@19.2.3)': + dependencies: + '@auth/core': 0.37.4 + '@oslojs/crypto': 1.0.1 + '@oslojs/encoding': 1.1.0 + convex: 1.31.6(react@19.2.3) + cookie: 1.1.1 + is-network-error: 1.3.0 + jose: 5.10.0 + jwt-decode: 4.0.0 + lucia: 3.2.2 + oauth4webapi: 3.8.3 + path-to-regexp: 6.3.0 + server-only: 0.0.1 + optionalDependencies: + react: 19.2.3 + + '@convex-dev/better-auth@0.10.10(@better-auth/core@1.4.9(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.7(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0))(@better-auth/utils@0.3.0)(@standard-schema/spec@1.1.0)(better-auth@1.4.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(better-call@1.1.7(zod@4.3.6))(convex@1.31.6(react@19.2.3))(nanostores@1.1.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + dependencies: + '@better-auth/passkey': 1.4.9(@better-auth/core@1.4.9(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.7(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0))(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-auth@1.4.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(better-call@1.1.7(zod@4.3.6))(nanostores@1.1.0) + '@better-fetch/fetch': 1.1.21 + better-auth: 1.4.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + common-tags: 1.8.2 + convex: 1.31.6(react@19.2.3) + convex-helpers: 0.1.111(@standard-schema/spec@1.1.0)(convex@1.31.6(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(zod@4.3.6) + jose: 6.1.3 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + remeda: 2.33.4 + semver: 7.7.3 + type-fest: 4.41.0 + zod: 4.3.6 + transitivePeerDependencies: + - '@better-auth/core' + - '@better-auth/utils' + - '@standard-schema/spec' + - better-call + - hono + - nanostores + - typescript + '@esbuild/aix-ppc64@0.27.0': optional: true @@ -310,6 +793,10 @@ snapshots: '@esbuild/win32-x64@0.27.0': optional: true + '@hexagon/base64@1.1.28': {} + + '@ioredis/commands@1.5.0': {} + '@kevisual/ai@0.0.21': dependencies: '@kevisual/logger': 0.0.4 @@ -324,6 +811,138 @@ snapshots: dependencies: tslib: 2.8.1 + '@levischuck/tiny-cbor@0.2.11': {} + + '@noble/ciphers@2.1.1': {} + + '@noble/hashes@2.0.1': {} + + '@oslojs/asn1@1.0.0': + dependencies: + '@oslojs/binary': 1.0.0 + + '@oslojs/binary@1.0.0': {} + + '@oslojs/crypto@1.0.1': + dependencies: + '@oslojs/asn1': 1.0.0 + '@oslojs/binary': 1.0.0 + + '@oslojs/encoding@1.1.0': {} + + '@panva/hkdf@1.2.1': {} + + '@peculiar/asn1-android@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-cms@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + '@peculiar/asn1-x509-attr': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-csr@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-ecc@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pfx@2.6.0': + dependencies: + '@peculiar/asn1-cms': 2.6.0 + '@peculiar/asn1-pkcs8': 2.6.0 + '@peculiar/asn1-rsa': 2.6.0 + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs8@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs9@2.6.0': + dependencies: + '@peculiar/asn1-cms': 2.6.0 + '@peculiar/asn1-pfx': 2.6.0 + '@peculiar/asn1-pkcs8': 2.6.0 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + '@peculiar/asn1-x509-attr': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-rsa@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-schema@2.6.0': + dependencies: + asn1js: 3.0.7 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509-attr@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-x509@2.6.0': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.7 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/x509@1.14.3': + dependencies: + '@peculiar/asn1-cms': 2.6.0 + '@peculiar/asn1-csr': 2.6.0 + '@peculiar/asn1-ecc': 2.6.0 + '@peculiar/asn1-pkcs9': 2.6.0 + '@peculiar/asn1-rsa': 2.6.0 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + pvtsutils: 1.3.6 + reflect-metadata: 0.2.2 + tslib: 2.8.1 + tsyringe: 4.10.0 + + '@simplewebauthn/browser@13.2.2': {} + + '@simplewebauthn/server@13.2.2': + dependencies: + '@hexagon/base64': 1.1.28 + '@levischuck/tiny-cbor': 0.2.11 + '@peculiar/asn1-android': 2.6.0 + '@peculiar/asn1-ecc': 2.6.0 + '@peculiar/asn1-rsa': 2.6.0 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.0 + '@peculiar/x509': 1.14.3 + + '@standard-schema/spec@1.1.0': {} + '@types/bun@1.3.6': dependencies: bun-types: 1.3.6 @@ -332,14 +951,72 @@ snapshots: dependencies: undici-types: 7.16.0 + asn1js@3.0.7: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + + better-auth@1.4.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + '@better-auth/core': 1.4.9(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.7(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0) + '@better-auth/telemetry': 1.4.9(@better-auth/core@1.4.9(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.7(zod@4.3.6))(jose@6.1.3)(kysely@0.28.10)(nanostores@1.1.0)) + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.21 + '@noble/ciphers': 2.1.1 + '@noble/hashes': 2.0.1 + better-call: 1.1.7(zod@4.3.6) + defu: 6.1.4 + jose: 6.1.3 + kysely: 0.28.10 + nanostores: 1.1.0 + zod: 4.3.6 + optionalDependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + better-call@1.1.7(zod@4.3.6): + dependencies: + '@better-auth/utils': 0.3.0 + '@better-fetch/fetch': 1.1.21 + rou3: 0.7.12 + set-cookie-parser: 2.7.2 + optionalDependencies: + zod: 4.3.6 + bun-types@1.3.6: dependencies: '@types/node': 25.0.10 - convex@1.31.6: + cluster-key-slot@1.1.2: {} + + common-tags@1.8.2: {} + + convex-helpers@0.1.111(@standard-schema/spec@1.1.0)(convex@1.31.6(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(zod@4.3.6): + dependencies: + convex: 1.31.6(react@19.2.3) + optionalDependencies: + '@standard-schema/spec': 1.1.0 + react: 19.2.3 + typescript: 5.9.3 + zod: 4.3.6 + + convex@1.31.6(react@19.2.3): dependencies: esbuild: 0.27.0 prettier: 3.8.1 + optionalDependencies: + react: 19.2.3 + + cookie@1.1.1: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + defu@6.1.4: {} + + denque@2.1.0: {} esbuild@0.27.0: optionalDependencies: @@ -370,8 +1047,102 @@ snapshots: '@esbuild/win32-ia32': 0.27.0 '@esbuild/win32-x64': 0.27.0 + ioredis@5.9.2: + dependencies: + '@ioredis/commands': 1.5.0 + cluster-key-slot: 1.1.2 + debug: 4.4.3 + denque: 2.1.0 + lodash.defaults: 4.2.0 + lodash.isarguments: 3.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + + is-network-error@1.3.0: {} + + jose@5.10.0: {} + + jose@6.1.3: {} + + jwt-decode@4.0.0: {} + + kysely@0.28.10: {} + + lodash.defaults@4.2.0: {} + + lodash.isarguments@3.1.0: {} + + lucia@3.2.2: + dependencies: + '@oslojs/crypto': 1.0.1 + '@oslojs/encoding': 1.1.0 + + ms@2.1.3: {} + + nanostores@1.1.0: {} + + oauth4webapi@3.8.3: {} + + path-to-regexp@6.3.0: {} + + preact-render-to-string@6.5.11(preact@10.24.3): + dependencies: + preact: 10.24.3 + + preact@10.24.3: {} + prettier@3.8.1: {} + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.5: {} + + react-dom@19.2.3(react@19.2.3): + dependencies: + react: 19.2.3 + scheduler: 0.27.0 + + react@19.2.3: {} + + redis-errors@1.2.0: {} + + redis-parser@3.0.0: + dependencies: + redis-errors: 1.2.0 + + reflect-metadata@0.2.2: {} + + remeda@2.33.4: {} + + rou3@0.7.12: {} + + scheduler@0.27.0: {} + + semver@7.7.3: {} + + server-only@0.0.1: {} + + set-cookie-parser@2.7.2: {} + + standard-as-callback@2.1.0: {} + + tslib@1.14.1: {} + tslib@2.8.1: {} + tsyringe@4.10.0: + dependencies: + tslib: 1.14.1 + + type-fest@4.41.0: {} + + typescript@5.9.3: {} + undici-types@7.16.0: {} + + zod@4.3.6: {}