From 86a30eb2b8357e989330a58ea39c492bfa4da953 Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Thu, 6 Aug 2026 21:50:02 -0500 Subject: [PATCH 1/5] feat(tanstack-start): Add Tanstack Start integration package --- apps/tanstack-start/src/routeTree.gen.ts | 166 +++--- bun.lock | 105 ++-- deno.lock | 611 +++++++++++++++++++- packages/integration/deno.json | 6 +- packages/integration/package.json | 5 + packages/tanstack-start/CHANGELOG.md | 13 + packages/tanstack-start/README.md | 35 ++ packages/tanstack-start/deno.json | 50 ++ packages/tanstack-start/package.json | 101 ++++ packages/tanstack-start/src/@types/index.ts | 101 ++++ packages/tanstack-start/src/createAuth.ts | 46 ++ packages/tanstack-start/src/index.ts | 1 + packages/tanstack-start/src/lib/api.ts | 221 +++++++ packages/tanstack-start/tsconfig.json | 10 + packages/tanstack-start/tsdown.config.ts | 17 + pnpm-lock.yaml | 187 +++++- 16 files changed, 1527 insertions(+), 148 deletions(-) create mode 100644 packages/tanstack-start/CHANGELOG.md create mode 100644 packages/tanstack-start/README.md create mode 100644 packages/tanstack-start/deno.json create mode 100644 packages/tanstack-start/package.json create mode 100644 packages/tanstack-start/src/@types/index.ts create mode 100644 packages/tanstack-start/src/createAuth.ts create mode 100644 packages/tanstack-start/src/index.ts create mode 100644 packages/tanstack-start/src/lib/api.ts create mode 100644 packages/tanstack-start/tsconfig.json create mode 100644 packages/tanstack-start/tsdown.config.ts diff --git a/apps/tanstack-start/src/routeTree.gen.ts b/apps/tanstack-start/src/routeTree.gen.ts index e0e39f67..b9be7880 100644 --- a/apps/tanstack-start/src/routeTree.gen.ts +++ b/apps/tanstack-start/src/routeTree.gen.ts @@ -8,113 +8,115 @@ // You should NOT make any changes in this file as it will be overwritten. // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. -import { Route as rootRouteImport } from "./routes/__root" -import { Route as ServerRouteImport } from "./routes/server" -import { Route as ClientRouteImport } from "./routes/client" -import { Route as IndexRouteImport } from "./routes/index" -import { Route as ApiAuthSplatRouteImport } from "./routes/api/auth.$" +import { Route as rootRouteImport } from './routes/__root' +import { Route as ServerRouteImport } from './routes/server' +import { Route as ClientRouteImport } from './routes/client' +import { Route as IndexRouteImport } from './routes/index' +import { Route as ApiAuthSplatRouteImport } from './routes/api/auth.$' const ServerRoute = ServerRouteImport.update({ - id: "/server", - path: "/server", - getParentRoute: () => rootRouteImport, + id: '/server', + path: '/server', + getParentRoute: () => rootRouteImport, } as any) const ClientRoute = ClientRouteImport.update({ - id: "/client", - path: "/client", - getParentRoute: () => rootRouteImport, + id: '/client', + path: '/client', + getParentRoute: () => rootRouteImport, } as any) const IndexRoute = IndexRouteImport.update({ - id: "/", - path: "/", - getParentRoute: () => rootRouteImport, + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, } as any) const ApiAuthSplatRoute = ApiAuthSplatRouteImport.update({ - id: "/api/auth/$", - path: "/api/auth/$", - getParentRoute: () => rootRouteImport, + id: '/api/auth/$', + path: '/api/auth/$', + getParentRoute: () => rootRouteImport, } as any) export interface FileRoutesByFullPath { - "/": typeof IndexRoute - "/client": typeof ClientRoute - "/server": typeof ServerRoute - "/api/auth/$": typeof ApiAuthSplatRoute + '/': typeof IndexRoute + '/client': typeof ClientRoute + '/server': typeof ServerRoute + '/api/auth/$': typeof ApiAuthSplatRoute } export interface FileRoutesByTo { - "/": typeof IndexRoute - "/client": typeof ClientRoute - "/server": typeof ServerRoute - "/api/auth/$": typeof ApiAuthSplatRoute + '/': typeof IndexRoute + '/client': typeof ClientRoute + '/server': typeof ServerRoute + '/api/auth/$': typeof ApiAuthSplatRoute } export interface FileRoutesById { - __root__: typeof rootRouteImport - "/": typeof IndexRoute - "/client": typeof ClientRoute - "/server": typeof ServerRoute - "/api/auth/$": typeof ApiAuthSplatRoute + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/client': typeof ClientRoute + '/server': typeof ServerRoute + '/api/auth/$': typeof ApiAuthSplatRoute } export interface FileRouteTypes { - fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: "/" | "/client" | "/server" | "/api/auth/$" - fileRoutesByTo: FileRoutesByTo - to: "/" | "/client" | "/server" | "/api/auth/$" - id: "__root__" | "/" | "/client" | "/server" | "/api/auth/$" - fileRoutesById: FileRoutesById + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' | '/client' | '/server' | '/api/auth/$' + fileRoutesByTo: FileRoutesByTo + to: '/' | '/client' | '/server' | '/api/auth/$' + id: '__root__' | '/' | '/client' | '/server' | '/api/auth/$' + fileRoutesById: FileRoutesById } export interface RootRouteChildren { - IndexRoute: typeof IndexRoute - ClientRoute: typeof ClientRoute - ServerRoute: typeof ServerRoute - ApiAuthSplatRoute: typeof ApiAuthSplatRoute + IndexRoute: typeof IndexRoute + ClientRoute: typeof ClientRoute + ServerRoute: typeof ServerRoute + ApiAuthSplatRoute: typeof ApiAuthSplatRoute } -declare module "@tanstack/react-router" { - interface FileRoutesByPath { - "/server": { - id: "/server" - path: "/server" - fullPath: "/server" - preLoaderRoute: typeof ServerRouteImport - parentRoute: typeof rootRouteImport - } - "/client": { - id: "/client" - path: "/client" - fullPath: "/client" - preLoaderRoute: typeof ClientRouteImport - parentRoute: typeof rootRouteImport - } - "/": { - id: "/" - path: "/" - fullPath: "/" - preLoaderRoute: typeof IndexRouteImport - parentRoute: typeof rootRouteImport - } - "/api/auth/$": { - id: "/api/auth/$" - path: "/api/auth/$" - fullPath: "/api/auth/$" - preLoaderRoute: typeof ApiAuthSplatRouteImport - parentRoute: typeof rootRouteImport - } +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/server': { + id: '/server' + path: '/server' + fullPath: '/server' + preLoaderRoute: typeof ServerRouteImport + parentRoute: typeof rootRouteImport } + '/client': { + id: '/client' + path: '/client' + fullPath: '/client' + preLoaderRoute: typeof ClientRouteImport + parentRoute: typeof rootRouteImport + } + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/api/auth/$': { + id: '/api/auth/$' + path: '/api/auth/$' + fullPath: '/api/auth/$' + preLoaderRoute: typeof ApiAuthSplatRouteImport + parentRoute: typeof rootRouteImport + } + } } const rootRouteChildren: RootRouteChildren = { - IndexRoute: IndexRoute, - ClientRoute: ClientRoute, - ServerRoute: ServerRoute, - ApiAuthSplatRoute: ApiAuthSplatRoute, + IndexRoute: IndexRoute, + ClientRoute: ClientRoute, + ServerRoute: ServerRoute, + ApiAuthSplatRoute: ApiAuthSplatRoute, } -export const routeTree = rootRouteImport._addFileChildren(rootRouteChildren)._addFileTypes() +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() -import type { getRouter } from "./router.tsx" -import type { createStart } from "@tanstack/react-start" -declare module "@tanstack/react-start" { - interface Register { - ssr: true - router: Awaited> - } +import type { getRouter } from './router.tsx' +import type { createStart } from '@tanstack/react-start' +declare module '@tanstack/react-start' { + interface Register { + ssr: true + router: Awaited> + } } diff --git a/bun.lock b/bun.lock index d281811d..8702fad0 100644 --- a/bun.lock +++ b/bun.lock @@ -438,6 +438,7 @@ "version": "0.0.0", "dependencies": { "@aura-stack/auth": "workspace:*", + "path-to-regexp": "6.3.0", }, "devDependencies": { "@aura-stack/tsconfig": "workspace:*", @@ -520,6 +521,21 @@ "@aura-stack/auth": "workspace:*", }, }, + "packages/tanstack-start": { + "name": "@aura-stack/tanstack-start", + "version": "0.0.0", + "dependencies": { + "@aura-stack/react": "workspace:*", + }, + "devDependencies": { + "@aura-stack/tsconfig": "workspace:*", + "@aura-stack/tsdown-config": "workspace:*", + }, + "peerDependencies": { + "@tanstack/react-router": ">=1.0.0", + "@tanstack/react-start": ">=1.0.0", + }, + }, }, "overrides": { "brace-expansion": "^5.0.6", @@ -528,7 +544,6 @@ "h3": "^2.0.1-rc.17", "lodash": "^4.18.0", "lodash-es": "^4.18.0", - "path-to-regexp": "^1.9.0", "qs": "^6.15.2", "serialize-javascript": "^7.0.3", "seroval": "^1.4.1", @@ -664,6 +679,8 @@ "@aura-stack/shared": ["@aura-stack/shared@workspace:packages/shared"], + "@aura-stack/tanstack-start": ["@aura-stack/tanstack-start@workspace:packages/tanstack-start"], + "@aura-stack/tsconfig": ["@aura-stack/tsconfig@workspace:configs/tsconfig"], "@aura-stack/tsdown-config": ["@aura-stack/tsdown-config@workspace:configs/tsdown-config"], @@ -2154,7 +2171,7 @@ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "3.1.1", "shebang-command": "2.0.0", "which": "2.0.2" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - "crossws": ["crossws@0.4.6", "", { "peerDependencies": { "srvx": ">=0.11.5" }, "optionalPeers": ["srvx"] }, "sha512-/Wxe9Z007EbJ496j88nToZEvyPZ8PY/wjZJ18Agh/GCA9cYHyLbxtrpdFlFzAw3TV20F0SUYGl0g6PzChbwUrg=="], + "crossws": ["crossws@0.4.10", "", { "peerDependencies": { "srvx": ">=0.11.5" }, "optionalPeers": ["srvx"] }, "sha512-pz3oubH/dt12KjqsUB0IuXW4nwRDQ583iDsP4555Cpdqx0NoU7pGlWBcayyFI8f/l/idRpgjMEfwuOxSWJYlIA=="], "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "1.0.0", "css-what": "6.2.2", "domhandler": "5.0.3", "domutils": "3.2.2", "nth-check": "2.1.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], @@ -2356,7 +2373,7 @@ "env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="], - "env-runner": ["env-runner@0.1.14", "", { "dependencies": { "crossws": "^0.4.5", "exsolve": "^1.0.8", "httpxy": "^0.5.3", "srvx": "^0.11.16" }, "peerDependencies": { "@netlify/runtime": "^4.1.23", "@vercel/queue": "^0.2.0", "miniflare": "^4.20260515.0", "wrangler": "^4.0.0" }, "optionalPeers": ["@netlify/runtime", "@vercel/queue", "miniflare", "wrangler"], "bin": { "env-runner": "dist/cli.mjs" } }, "sha512-qdk5mmgFsd+zPg3r1bkZ+IbvpfUfypyDvNhMGypSMRpz7kOa/kI6SpW8fgyukuEM4Lo24M65r+1Ne0DtT7vFBA=="], + "env-runner": ["env-runner@0.1.16", "", { "dependencies": { "crossws": "^0.4.8", "exsolve": "^1.1.0", "httpxy": "^0.5.4", "srvx": "^0.11.19" }, "peerDependencies": { "@netlify/runtime": "^4.1.23", "@vercel/queue": ">=0.2.0", "miniflare": "^4.20260515.0", "wrangler": "^4.0.0" }, "optionalPeers": ["@netlify/runtime", "@vercel/queue", "miniflare", "wrangler"], "bin": { "env-runner": "dist/cli.mjs" } }, "sha512-2LRJM4P2KLX6J83QZZrMqvgCDt/D5ea7wPcI3yYiy5cG/9rX5QwdwZFx0D7ktWnjdRyZxYjttGGorb5nFqb1CA=="], "error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="], @@ -2556,6 +2573,8 @@ "h3": ["h3@2.0.1-rc.20", "", { "dependencies": { "rou3": "^0.8.1", "srvx": "^0.11.13" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"], "bin": { "h3": "bin/h3.mjs" } }, "sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg=="], + "h3-rules": ["h3-rules@0.1.0", "", { "dependencies": { "rou3": "^0.9.1", "ufo": "^1.6.4" }, "peerDependencies": { "h3": "^2.0.1-rc.25", "ocache": ">=0.2.0" }, "optionalPeers": ["ocache"] }, "sha512-MrUUH1E/yoM7hvpKVbLs/CFeindwiTn7Fcfo+zXDpfuRYbcpJDPkYGGttCSiHNJmjUQNYQ5yn9veUIqFonYXuw=="], + "h3-v2": ["h3@2.0.1-rc.20", "", { "dependencies": { "rou3": "^0.8.1", "srvx": "^0.11.13" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"], "bin": { "h3": "bin/h3.mjs" } }, "sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg=="], "hachure-fill": ["hachure-fill@0.5.2", "", {}, "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg=="], @@ -2614,7 +2633,7 @@ "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "7.1.4", "debug": "4.4.3" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], - "httpxy": ["httpxy@0.5.3", "", {}, "sha512-SMS9V6Sn7VWaS11lYhoAr0ceoaiolTWf4jYdJn0NJhCdKMu9R2H9Fh0LBDWBHQF6HRLI1PmaePYsjanSpE5PEw=="], + "httpxy": ["httpxy@0.5.5", "", {}, "sha512-uDjmnPyp1q4Sgzf3w+J/Fc6UqcCEj0x4Wjp7OqK5dGhNeDgpyrAmnS6ey8QWrX3SWDon2DMKf9sBa5X9+CVyMA=="], "human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="], @@ -2976,9 +2995,9 @@ "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], - "nf3": ["nf3@0.3.17", "", {}, "sha512-N9zEWySuJFw+gR0lhS5863YsvNeudOdqRyFvNb+jMXbeTJOdrjDqkCpDginIZfUm0LzT1t1nCRiDeqQm/8kirQ=="], + "nf3": ["nf3@0.3.23", "", {}, "sha512-RWVLAWozmVD3AaDmaU3qMGB3v+yNlH5d9qqStI4e/WLlNQVnJ4YErGDbYCIrGFyrHdbF6I6Baf0Ae6c7tFYmSg=="], - "nitro": ["nitro-nightly@3.0.1-20260617-160837-7765bcb7", "", { "dependencies": { "consola": "^3.4.2", "crossws": "^0.4.6", "db0": "^0.3.4", "env-runner": "^0.1.14", "h3": "^2.0.1-rc.22", "hookable": "^6.1.1", "nf3": "^0.3.17", "ocache": "^0.1.5", "ofetch": "^2.0.0-alpha.3", "ohash": "^2.0.11", "rolldown": "^1.1.1", "srvx": "^0.11.16", "unenv": "^2.0.0-rc.24", "unstorage": "^2.0.0-alpha.7" }, "peerDependencies": { "@vercel/queue": "^0.3.1", "dotenv": "*", "giget": "*", "jiti": "^2.7.0", "rollup": "^4.62.0", "vite": "^7 || ^8", "xml2js": "^0.6.2", "zephyr-agent": "^0.2.0" }, "optionalPeers": ["@vercel/queue", "dotenv", "giget", "jiti", "rollup", "vite", "xml2js", "zephyr-agent"], "bin": { "nitro": "dist/cli/index.mjs" } }, "sha512-3u2yin8pQZrVY+aGCAbFal8KYg9herHXv/CJpELqo9GVDM85iLemiQxxRwXwHLQ0239QltF57dRJgBG3kcw5vQ=="], + "nitro": ["nitro-nightly@3.0.1-20260731-205209-52abde8a", "", { "dependencies": { "consola": "^3.4.2", "crossws": "^0.4.10", "db0": "^0.3.4", "env-runner": "^0.1.16", "h3": "^2.0.1-rc.25", "h3-rules": "^0.1.0", "hookable": "^6.1.1", "nf3": "^0.3.22", "ocache": "^0.2.0", "ofetch": "^2.0.0-alpha.3", "ohash": "^2.0.11", "rolldown": "^1.2.0", "rou3": "^0.9.1", "srvx": "^0.11.22", "unenv": "^2.0.0-rc.24", "unstorage": "^2.0.0-alpha.7" }, "peerDependencies": { "@vercel/queue": "^0.4.0", "dotenv": "*", "giget": "*", "jiti": "^2.7.0", "rollup": "^4.62.2", "vite": "^7 || ^8", "xml2js": "^0.6.2", "zephyr-agent": "^1.1.2" }, "optionalPeers": ["@vercel/queue", "dotenv", "giget", "jiti", "rollup", "vite", "xml2js", "zephyr-agent"], "bin": { "nitro": "dist/cli/index.mjs" } }, "sha512-KI1rwOJPgD0U57mE+1AefoEPjd+aJPJ4GCTLym0cXyfBBi8JtVsHmtB/4D3g1RaDwntjoz8H5nWnWGg7agYnuA=="], "nitropack": ["nitropack@2.13.4", "", { "dependencies": { "@cloudflare/kv-asset-handler": "^0.4.2", "@rollup/plugin-alias": "^6.0.0", "@rollup/plugin-commonjs": "^29.0.2", "@rollup/plugin-inject": "^5.0.5", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.3", "@rollup/plugin-replace": "^6.0.3", "@rollup/plugin-terser": "^1.0.0", "@vercel/nft": "^1.5.0", "archiver": "^7.0.1", "c12": "^3.3.4", "chokidar": "^5.0.0", "citty": "^0.2.2", "compatx": "^0.2.0", "confbox": "^0.2.4", "consola": "^3.4.2", "cookie-es": "^2.0.1", "croner": "^10.0.1", "crossws": "^0.3.5", "db0": "^0.3.4", "defu": "^6.1.7", "destr": "^2.0.5", "dot-prop": "^10.1.0", "esbuild": "^0.28.0", "escape-string-regexp": "^5.0.0", "etag": "^1.8.1", "exsolve": "^1.0.8", "globby": "^16.2.0", "gzip-size": "^7.0.0", "h3": "^1.15.11", "hookable": "^5.5.3", "httpxy": "^0.5.1", "ioredis": "^5.10.1", "jiti": "^2.6.1", "klona": "^2.0.6", "knitwork": "^1.3.0", "listhen": "^1.9.1", "magic-string": "^0.30.21", "magicast": "^0.5.2", "mime": "^4.1.0", "mlly": "^1.8.2", "node-fetch-native": "^1.6.7", "node-mock-http": "^1.0.4", "ofetch": "^1.5.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.1.0", "pkg-types": "^2.3.1", "pretty-bytes": "^7.1.0", "radix3": "^1.1.2", "rollup": "^4.60.2", "rollup-plugin-visualizer": "^7.0.1", "scule": "^1.3.0", "semver": "^7.7.4", "serve-placeholder": "^2.0.2", "serve-static": "^2.2.1", "source-map": "^0.7.6", "std-env": "^4.1.0", "ufo": "^1.6.4", "ultrahtml": "^1.6.0", "uncrypto": "^0.1.3", "unctx": "^2.5.0", "unenv": "2.0.0-rc.24", "unimport": "^6.2.0", "unplugin-utils": "^0.3.1", "unstorage": "^1.17.5", "untyped": "^2.0.0", "unwasm": "^0.5.3", "youch": "^4.1.1", "youch-core": "^0.3.3" }, "peerDependencies": { "xml2js": "^0.6.2" }, "optionalPeers": ["xml2js"], "bin": { "nitro": "dist/cli/index.mjs", "nitropack": "dist/cli/index.mjs" } }, "sha512-tX7bT6zxNeMwkc6hxHiZeUoTOjVrcjoh1Z3cmxOlodIqjl4HISgqfGOmkWSayky3Nv9Z5+KQH52F8nmXJY5AAA=="], @@ -3022,7 +3041,7 @@ "obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="], - "ocache": ["ocache@0.1.5", "", { "dependencies": { "ohash": "^2.0.11" } }, "sha512-kNNnkkVQup/QDvmTz8Q84wc2ntiyoVHDxa6eHWKt5qdGAmFRBIxy83rxgCYEjW0x06UJ9E3P6VgM2yY4rOBH4w=="], + "ocache": ["ocache@0.2.0", "", { "dependencies": { "ohash": "^2.0.11" } }, "sha512-QE+SxXf/A8yR01rEOg2X5KwUe+mARHo1xQXl+iwLMzLIH06S5lBOZhhHQWp7T5etfFa8nOnRhvjGuo9YBCWwig=="], "ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "2.0.5", "node-fetch-native": "1.6.7", "ufo": "1.6.3" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], @@ -3090,7 +3109,7 @@ "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "11.2.7", "minipass": "7.1.3" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], - "path-to-regexp": ["path-to-regexp@1.9.0", "", { "dependencies": { "isarray": "0.0.1" } }, "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g=="], + "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], @@ -3444,7 +3463,7 @@ "sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], - "srvx": ["srvx@0.11.16", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-bp07zRuycfTY43IjAvvTFnmnJi8ikW0VFiHwOhhYcVW/L4xQ1XY4PAd4Nuum1rsA17C39zL7x+CDhrn5AL32Rw=="], + "srvx": ["srvx@0.11.22", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-LqZxxBDMKuMAZzFzJnDCkFOrs9MZQZr0LvHiO/SuSZVdQaXD7xQ5UWTUxheJrQPve1qk9MG2B/yttUvJxw8egQ=="], "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], @@ -3840,8 +3859,6 @@ "@astrojs/yaml2ts/yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="], - "@aura-stack/device/valibot": ["valibot@1.4.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-iC/x7fVcSyOwlm/VSt7RlHnzNGLGvR9GnxdifUeWoCJo0q4ZZvrVkIHC6faTlkxG47I2Y4UrFquPuVHCrOnrLg=="], - "@aura-stack/elysia/elysia": ["elysia@1.4.28", "", { "dependencies": { "cookie": "1.1.1", "fast-decode-uri-component": "1.0.1", "memoirist": "0.4.0" }, "optionalDependencies": { "@types/bun": "1.3.10", "typescript": "5.9.3" }, "peerDependencies": { "@sinclair/typebox": "0.34.48", "exact-mirror": "0.2.7", "file-type": "21.3.3", "openapi-types": "12.1.3" } }, "sha512-Vrx8sBnvq8squS/3yNBzR1jBXI+SgmnmvwawPjNuEHndUe5l1jV2Gp6JJ4ulDkEB8On6bWmmuyPpA+bq4t+WYg=="], "@aura-stack/express/express": ["express@4.22.1", "", { "dependencies": { "accepts": "1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.4", "content-disposition": "0.5.4", "content-type": "1.0.5", "cookie": "0.7.2", "cookie-signature": "1.0.7", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "2.0.0", "escape-html": "1.0.3", "etag": "1.8.1", "finalhandler": "1.3.2", "fresh": "0.5.2", "http-errors": "2.0.1", "merge-descriptors": "1.0.3", "methods": "1.1.2", "on-finished": "2.4.1", "parseurl": "1.3.3", "path-to-regexp": "1.9.0", "proxy-addr": "2.0.7", "qs": "6.14.2", "range-parser": "1.2.1", "safe-buffer": "5.2.1", "send": "0.19.2", "serve-static": "1.16.3", "setprototypeof": "1.2.0", "statuses": "2.0.2", "type-is": "1.6.18", "utils-merge": "1.0.1", "vary": "1.1.2" } }, "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g=="], @@ -3920,6 +3937,8 @@ "@nuxt/cli/semver": ["semver@7.8.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA=="], + "@nuxt/cli/srvx": ["srvx@0.11.16", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-bp07zRuycfTY43IjAvvTFnmnJi8ikW0VFiHwOhhYcVW/L4xQ1XY4PAd4Nuum1rsA17C39zL7x+CDhrn5AL32Rw=="], + "@nuxt/cli/std-env": ["std-env@4.1.0", "", {}, "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ=="], "@nuxt/cli/tinyexec": ["tinyexec@1.2.4", "", {}, "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg=="], @@ -4086,6 +4105,8 @@ "@tanstack/start-plugin-core/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "7.28.5", "js-tokens": "4.0.0", "picocolors": "1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + "@tanstack/start-plugin-core/srvx": ["srvx@0.11.16", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-bp07zRuycfTY43IjAvvTFnmnJi8ikW0VFiHwOhhYcVW/L4xQ1XY4PAd4Nuum1rsA17C39zL7x+CDhrn5AL32Rw=="], + "@tanstack/start-plugin-core/tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], "@tanstack/start-plugin-core/zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], @@ -4252,6 +4273,8 @@ "elysia/elysia": ["elysia@1.4.28", "", { "dependencies": { "cookie": "1.1.1", "fast-decode-uri-component": "1.0.1", "memoirist": "0.4.0" }, "optionalDependencies": { "@types/bun": "1.3.10", "typescript": "5.9.3" }, "peerDependencies": { "@sinclair/typebox": "0.34.48", "exact-mirror": "0.2.7", "file-type": "21.3.3", "openapi-types": "12.1.3" } }, "sha512-Vrx8sBnvq8squS/3yNBzR1jBXI+SgmnmvwawPjNuEHndUe5l1jV2Gp6JJ4ulDkEB8On6bWmmuyPpA+bq4t+WYg=="], + "env-runner/exsolve": ["exsolve@1.1.1", "", {}, "sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g=="], + "express/express": ["express@4.22.1", "", { "dependencies": { "accepts": "1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.4", "content-disposition": "0.5.4", "content-type": "1.0.5", "cookie": "0.7.2", "cookie-signature": "1.0.7", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "2.0.0", "escape-html": "1.0.3", "etag": "1.8.1", "finalhandler": "1.3.2", "fresh": "0.5.2", "http-errors": "2.0.1", "merge-descriptors": "1.0.3", "methods": "1.1.2", "on-finished": "2.4.1", "parseurl": "1.3.3", "path-to-regexp": "1.9.0", "proxy-addr": "2.0.7", "qs": "6.14.2", "range-parser": "1.2.1", "safe-buffer": "5.2.1", "send": "0.19.2", "serve-static": "1.16.3", "setprototypeof": "1.2.0", "statuses": "2.0.2", "type-is": "1.6.18", "utils-merge": "1.0.1", "vary": "1.1.2" } }, "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g=="], "fdir/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], @@ -4260,6 +4283,8 @@ "fumadocs-core/next": ["next@16.1.7", "", { "dependencies": { "@next/env": "16.1.7", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "2.10.8", "caniuse-lite": "1.0.30001780", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.1.7", "@next/swc-darwin-x64": "16.1.7", "@next/swc-linux-arm64-gnu": "16.1.7", "@next/swc-linux-arm64-musl": "16.1.7", "@next/swc-linux-x64-gnu": "16.1.7", "@next/swc-linux-x64-musl": "16.1.7", "@next/swc-win32-arm64-msvc": "16.1.7", "@next/swc-win32-x64-msvc": "16.1.7", "babel-plugin-react-compiler": "1.0.0", "sharp": "0.34.5" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" }, "bin": { "next": "dist/bin/next" } }, "sha512-WM0L7WrSvKwoLegLYr6V+mz+RIofqQgVAfHhMp9a88ms0cFX8iX9ew+snpWlSBwpkURJOUdvCEt3uLl3NNzvWg=="], + "fumadocs-core/path-to-regexp": ["path-to-regexp@1.9.0", "", { "dependencies": { "isarray": "0.0.1" } }, "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g=="], + "fumadocs-core/react-router": ["react-router@7.12.0", "", { "dependencies": { "cookie": "1.1.1", "set-cookie-parser": "2.7.2" }, "optionalDependencies": { "react-dom": "19.2.4" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-kTPDYPFzDVGIIGNLS5VJykK0HfHLY5MF3b+xj0/tTyNYL1gF1qs7u67Z9jEhQk2sQ98SUaHxlG31g1JtF7IfVw=="], "fumadocs-core/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "6.5.0", "picomatch": "4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], @@ -4286,6 +4311,8 @@ "h3/srvx": ["srvx@0.11.15", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg=="], + "h3-rules/rou3": ["rou3@0.9.1", "", {}, "sha512-z/sSmzvtwMDDnxsPVhfWMuG6F6mbmhFDXoVqLmMfbpDD9qfV3GDmSQpf0+W296/ZDIpW2wcMmBfpVFzcnOi/nA=="], + "h3-v2/srvx": ["srvx@0.11.15", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg=="], "hast-util-from-html/parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "6.0.1" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], @@ -4306,6 +4333,8 @@ "lazystream/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "1.0.3", "inherits": "2.0.4", "isarray": "1.0.0", "process-nextick-args": "2.0.1", "safe-buffer": "5.1.2", "string_decoder": "1.1.1", "util-deprecate": "1.0.2" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + "listhen/crossws": ["crossws@0.4.6", "", { "peerDependencies": { "srvx": ">=0.11.5" }, "optionalPeers": ["srvx"] }, "sha512-/Wxe9Z007EbJ496j88nToZEvyPZ8PY/wjZJ18Agh/GCA9cYHyLbxtrpdFlFzAw3TV20F0SUYGl0g6PzChbwUrg=="], + "listhen/std-env": ["std-env@4.1.0", "", {}, "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ=="], "local-pkg/mlly": ["mlly@1.8.1", "", { "dependencies": { "acorn": "8.16.0", "pathe": "2.0.3", "pkg-types": "1.3.1", "ufo": "1.6.3" } }, "sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ=="], @@ -4332,7 +4361,9 @@ "nitro/ofetch": ["ofetch@2.0.0-alpha.3", "", {}, "sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA=="], - "nitro/rolldown": ["rolldown@1.1.1", "", { "dependencies": { "@oxc-project/types": "=0.135.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.1.1", "@rolldown/binding-darwin-arm64": "1.1.1", "@rolldown/binding-darwin-x64": "1.1.1", "@rolldown/binding-freebsd-x64": "1.1.1", "@rolldown/binding-linux-arm-gnueabihf": "1.1.1", "@rolldown/binding-linux-arm64-gnu": "1.1.1", "@rolldown/binding-linux-arm64-musl": "1.1.1", "@rolldown/binding-linux-ppc64-gnu": "1.1.1", "@rolldown/binding-linux-s390x-gnu": "1.1.1", "@rolldown/binding-linux-x64-gnu": "1.1.1", "@rolldown/binding-linux-x64-musl": "1.1.1", "@rolldown/binding-openharmony-arm64": "1.1.1", "@rolldown/binding-wasm32-wasi": "1.1.1", "@rolldown/binding-win32-arm64-msvc": "1.1.1", "@rolldown/binding-win32-x64-msvc": "1.1.1" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-IN750c0p+s3jqJIsFLRZrQazmbAB1kkQDTtQjSt/gbS2ywLhlv4R5Shazer0FZKmuo/BsO3/w2UoYnUjuOZqHg=="], + "nitro/rolldown": ["rolldown@1.2.3", "", { "dependencies": { "@oxc-project/types": "=0.143.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.2.3", "@rolldown/binding-darwin-arm64": "1.2.3", "@rolldown/binding-darwin-x64": "1.2.3", "@rolldown/binding-freebsd-x64": "1.2.3", "@rolldown/binding-linux-arm-gnueabihf": "1.2.3", "@rolldown/binding-linux-arm64-gnu": "1.2.3", "@rolldown/binding-linux-arm64-musl": "1.2.3", "@rolldown/binding-linux-ppc64-gnu": "1.2.3", "@rolldown/binding-linux-s390x-gnu": "1.2.3", "@rolldown/binding-linux-x64-gnu": "1.2.3", "@rolldown/binding-linux-x64-musl": "1.2.3", "@rolldown/binding-openharmony-arm64": "1.2.3", "@rolldown/binding-win32-arm64-msvc": "1.2.3", "@rolldown/binding-win32-x64-msvc": "1.2.3" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-rn9wpmxplLf7NLNyCk9FyWh3FM43DbY8jOzCdEPzH7uflhTftRbCEpqi6Ly2osgoU8OwObtmavMbWLaWy4LX7A=="], + + "nitro/rou3": ["rou3@0.9.1", "", {}, "sha512-z/sSmzvtwMDDnxsPVhfWMuG6F6mbmhFDXoVqLmMfbpDD9qfV3GDmSQpf0+W296/ZDIpW2wcMmBfpVFzcnOi/nA=="], "nitro/unstorage": ["unstorage@2.0.0-alpha.7", "", { "peerDependencies": { "@azure/app-configuration": "^1.11.0", "@azure/cosmos": "^4.9.1", "@azure/data-tables": "^13.3.2", "@azure/identity": "^4.13.0", "@azure/keyvault-secrets": "^4.10.0", "@azure/storage-blob": "^12.31.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.13.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.36.2", "@vercel/blob": ">=0.27.3", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "chokidar": "^4 || ^5", "db0": ">=0.3.4", "idb-keyval": "^6.2.2", "ioredis": "^5.9.3", "lru-cache": "^11.2.6", "mongodb": "^6 || ^7", "ofetch": "*", "uploadthing": "^7.7.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "chokidar", "db0", "idb-keyval", "ioredis", "lru-cache", "mongodb", "ofetch", "uploadthing"] }, "sha512-ELPztchk2zgFJnakyodVY3vJWGW9jy//keJ32IOJVGUMyaPydwcA1FtVvWqT0TNRch9H+cMNEGllfVFfScImog=="], @@ -4346,6 +4377,8 @@ "nitropack/hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], + "nitropack/httpxy": ["httpxy@0.5.3", "", {}, "sha512-SMS9V6Sn7VWaS11lYhoAr0ceoaiolTWf4jYdJn0NJhCdKMu9R2H9Fh0LBDWBHQF6HRLI1PmaePYsjanSpE5PEw=="], + "nitropack/ioredis": ["ioredis@5.11.1", "", { "dependencies": { "@ioredis/commands": "1.10.0", "cluster-key-slot": "1.1.1", "debug": "4.4.3", "denque": "2.1.0", "redis-errors": "1.2.0", "redis-parser": "3.0.0", "standard-as-callback": "2.1.0" } }, "sha512-ehuGcf94bQXhfagULNXrJdfnWO38v070jxSx/qE87Kjzmu2fU7ro5EFAb+OPituLqgfyuQaym5DlrNydW2sJ9A=="], "nitropack/mime": ["mime@4.1.0", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw=="], @@ -4520,6 +4553,8 @@ "wrangler/miniflare": ["miniflare@4.20260317.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "0.34.5", "undici": "7.24.4", "workerd": "1.20260317.1", "ws": "8.18.0", "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-xuwk5Kjv+shi5iUBAdCrRl9IaWSGnTU8WuTQzsUS2GlSDIMCJuu8DiF/d9ExjMXYiQG5ml+k9SVKnMj8cRkq0w=="], + "wrangler/path-to-regexp": ["path-to-regexp@1.9.0", "", { "dependencies": { "isarray": "0.0.1" } }, "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g=="], + "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -4546,6 +4581,8 @@ "@aura-stack/express/express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + "@aura-stack/express/express/path-to-regexp": ["path-to-regexp@1.9.0", "", { "dependencies": { "isarray": "0.0.1" } }, "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g=="], + "@babel/core/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "@babel/generator/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0", "", {}, "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg=="], @@ -4626,6 +4663,8 @@ "@cloudflare/vitest-pool-workers/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], + "@cloudflare/vitest-pool-workers/wrangler/path-to-regexp": ["path-to-regexp@1.9.0", "", { "dependencies": { "isarray": "0.0.1" } }, "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd": ["workerd@1.20260310.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260310.1", "@cloudflare/workerd-darwin-arm64": "1.20260310.1", "@cloudflare/workerd-linux-64": "1.20260310.1", "@cloudflare/workerd-linux-arm64": "1.20260310.1", "@cloudflare/workerd-windows-64": "1.20260310.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-yawXhypXXHtArikJj15HOMknNGikpBbSg2ZDe6lddUbqZnJXuCVSkgc/0ArUeVMG1jbbGvpst+REFtKwILvRTQ=="], "@dxup/nuxt/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], @@ -4740,6 +4779,8 @@ "@react-router/serve/express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + "@react-router/serve/express/path-to-regexp": ["path-to-regexp@1.9.0", "", { "dependencies": { "isarray": "0.0.1" } }, "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="], "@tailwindcss/vite/@tailwindcss/node/enhanced-resolve": ["enhanced-resolve@5.20.1", "", { "dependencies": { "graceful-fs": "4.2.11", "tapable": "2.3.0" } }, "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA=="], @@ -4990,6 +5031,8 @@ "express/express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + "express/express/path-to-regexp": ["path-to-regexp@1.9.0", "", { "dependencies": { "isarray": "0.0.1" } }, "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g=="], + "fumadocs-core/@tanstack/react-router/@tanstack/history": ["@tanstack/history@1.161.6", "", {}, "sha512-NaOGLRrddszbQj9upGat6HG/4TKvXLvu+osAIgfxPYA+eIvYKv8GKDJOrY2D3/U9MRnKfMWD7bU4jeD4xmqyIg=="], "fumadocs-core/@tanstack/react-router/@tanstack/react-store": ["@tanstack/react-store@0.9.2", "", { "dependencies": { "@tanstack/store": "0.9.2", "use-sync-external-store": "1.6.0" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-Vt5usJE5sHG/cMechQfmwvwne6ktGCELe89Lmvoxe3LKRoFrhPa8OCKWs0NliG8HTJElEIj7PLtaBQIcux5pAQ=="], @@ -5112,37 +5155,35 @@ "next/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "nitro/rolldown/@oxc-project/types": ["@oxc-project/types@0.135.0", "", {}, "sha512-wR+xRdFkUBMvcAjBJ2q2kcZM6d+DKu2NgoOyxZgYwZdLhmiv6+rnO8PZ/P68kMiZtIKm+pW7zyEJ4kSOs0vo+Q=="], - - "nitro/rolldown/@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.1.1", "", { "os": "android", "cpu": "arm64" }, "sha512-BLf9Wak/gfwVb7NQTQW4wBgL3oAfPy7ArEkhwV543OVw/uY6B47z5xYsqPSZ9PDOorvURPinws6ThaFuNgGLgA=="], + "nitro/rolldown/@oxc-project/types": ["@oxc-project/types@0.143.0", "", {}, "sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA=="], - "nitro/rolldown/@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.1.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rRZRPy/Ynb+Mxu0O6tfPldHeDgAn0sRij+IOUy6sFdUlv3hArGW/DloE3GfAxtqpOJuRNgF74Nr5gM4xBeU2jQ=="], + "nitro/rolldown/@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.2.3", "", { "os": "android", "cpu": "arm64" }, "sha512-zrJtHDcaZJ1Fp7xf4hNl+7seH9Cn/N5TwLYkhgXREtBwAd/jaqW3uqeHxpDugJLVICWg4eW44kOQEGJ1r6jCGw=="], - "nitro/rolldown/@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.1.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-/MtefPxhKPyWWFM8L45OWiEqRf+eSU2Qv9ZAyTaoZOoGcoPKxbbhjTJO2/U2IThv0uDZ4NWHc3/oTsR6IEOtww=="], + "nitro/rolldown/@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.2.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ieIiibVCp0tX7TLu2cafoNPv8wJyYi01ekXpbf8q2j7F4rGAhhXb/eQh7ge9DRBY78GwmRQtvjZDux7EDbA8kA=="], - "nitro/rolldown/@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.1.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-202K+cpIi1kx/Zn7AtxBi4LTXSY67Aszb2K9rNsuW7FeBeh0nqoNmYLOSZidV0p88VPBzMmTZcHAdPNo3kRYzQ=="], + "nitro/rolldown/@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.2.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-Zh9tCon19eDXJoihx0rqKhMUlMYqzwj3aPsSuHmI4RWZh62dWUL+DJN4C5YQya5TcQBJU/Fe8+rY0jhXTQITqA=="], - "nitro/rolldown/@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.1.1", "", { "os": "linux", "cpu": "arm" }, "sha512-wl9NfeXNUwrXtUc063tddmZFUI6qiNs1CNOwni0OL4vC7MqVSYugra3ZgtDmtVy8e0DluJTENmzIv2BwqLzT4Q=="], + "nitro/rolldown/@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.2.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-nGbJWewA1wrXXZiQhjAT5rhibGfns5ZNkDVqxsO6zJ3f3YvpoDNNmGMSbbhLuXKjNScaBJVOAboztAWVespQMg=="], - "nitro/rolldown/@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-at2EO4o7D/PJLC4Xik16bU4CcjQE2tSv1LfqMA0TRYQYQihRm3gZeDB8xaX28A9SFedibcAk5DeMCKt4REKG0A=="], + "nitro/rolldown/@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.2.3", "", { "os": "linux", "cpu": "arm" }, "sha512-QNniJr5Kml0kDEB98jiDOJjXNroxIIi0IXIbdYzY26Xt1pVbeP62+KnoIZLwirOymX/0jDk/2gI/bNUv7A7OIw=="], - "nitro/rolldown/@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-5PUjZx366h9tkJTPJF5eibxOlK3sGoeRiBJLLjjEB5/kLDuhr6qB3LkhqLz1smXNgsX+pBhnbcJBrPE30HznAA=="], + "nitro/rolldown/@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-TkqEAcmmvH3I/q4114NB4RVt6241Dao48pF45uLcFGrwAaIn0iITgTAKP/dLjbN0R4buJjGb91+UHSoFmpgIWw=="], - "nitro/rolldown/@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.1.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1WK84XPeio3tjP1sM/TMXiC0G1i1iq1qGZ71KfNQjEFLU1kwD+Cv5T8nGySg/JUFwLbaScu6ve9DmeXlmqpkFA=="], + "nitro/rolldown/@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-NHqjnxpsndf4MPymxteFAWHHfkTL8HjWh1KB7z23ofZ6QO2euONuxDXjat69dKZRALnGypg8k8SsK8vZJoXv1Q=="], - "nitro/rolldown/@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.1.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-1nS1X5z1uMJ369RU25hTpKCFvUwXZp12dIzlzk4S+UxCTcSVGsAE6tzkOSufv/7jnmAtK0ZlrsJxh2fGmsnVSw=="], + "nitro/rolldown/@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.2.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-6tbrbwfz5GB9DQ4Jwo6hy9v+vR31xZlvzZ6n5Xut6Hhx5PvrA9q/HsK8KMaYQp063iqZGXwNvZtYNLD7EM/x0w=="], - "nitro/rolldown/@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-NwX/wspnq4vYyMFsqbYvzums3ki/Tk8FZbMzMAovPDp3OfLeYKby/D+9osokadXuYEV3OvpeHlwnr/bG8QMixA=="], + "nitro/rolldown/@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.2.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-oyuXxXmoZHjXC917IAPFAAv4wWAa0cM9afk8nx1+9/jNNOX1uPf8yDA6p7G0RypOfw/X0PQt5IfoquY1um+zSg=="], - "nitro/rolldown/@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-+n46LhDrJFQM+229y4oXtVpj1G50U/+XuHMlpnisFTEXhrg9f/YIjp/HymX+PVJjBEr7XHRs3CFLelV464pqwA=="], + "nitro/rolldown/@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-TytMwF2KVGqP2tgd0I1OY0PAv78dZRAYcF5ssDzjM34SUXCED3uXvSd5+lHoC0bTD6eEdFz7LdQNCO1y0oVk9w=="], - "nitro/rolldown/@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.1.1", "", { "os": "none", "cpu": "arm64" }, "sha512-qGwEu47zOWYo7LdRHhCWTNhzwGtxXpdY6CERs8QEOqC0PXGGics/e3vHnyEUKt8xK6YkbZXFUCeklrpB6js8ag=="], + "nitro/rolldown/@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-/E9m3qstrJFVPoULV25mVQblSNExY2+kBsYe4sy0Tn0yOOgJ8wZbZt3KnRbF/XeU2Gl1STKUQnDNTqhIE5MD4A=="], - "nitro/rolldown/@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.1.1", "", { "dependencies": { "@emnapi/core": "1.11.0", "@emnapi/runtime": "1.11.0", "@napi-rs/wasm-runtime": "^1.1.5" }, "cpu": "none" }, "sha512-qczfgEH8u0wHGGOXtA7UMAybNKuQjjEXairyQaw4WzjiMztfbgatG1h4OKays/smhtwbWltpKCRGtVhU6h40Sg=="], + "nitro/rolldown/@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.2.3", "", { "os": "none", "cpu": "arm64" }, "sha512-Kr0OcsoQI816i6HOl3vFHpd1K0eZyh76zgfj4c1nTyaTsd5r2Mj1lwM4R90y/qaCfmTn9eHy0SKwi98eitRxug=="], - "nitro/rolldown/@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.1.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-4psXSh63mSbwJF+mB8/9yfUUEzBiHYcUjxa32EO9ZwKy0Ypwjcg4F10D8SvVXgd+isy2UUUjF9HJJnDu1T/4Gg=="], + "nitro/rolldown/@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.2.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-hOtMwTqnME+/gJcH/PCZ0wn0zPUjiWOgkHpxbSJpfGKMezHltx1S7/k1SitzVa7Ww2cqrDDaFbZEhcJZO8o+Jw=="], - "nitro/rolldown/@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.1.1", "", { "os": "win32", "cpu": "x64" }, "sha512-MUvC/HLXVjzkQkWiExdVTEEWf0py+GfWm8WKSZsekG3ih6a21iy0BHPF07X3JIf3ifoklZXTIaHTLPBgH1C3dw=="], + "nitro/rolldown/@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.2.3", "", { "os": "win32", "cpu": "x64" }, "sha512-ekcqMMkI2PlhYnfzQnB/cEdYUVVJViWvoUyLrbzgDoi3Snfc1mVBwdnc306ufA5ejy8JSPjT2RlW1nQSjW7efg=="], "nitro/rolldown/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="], @@ -5758,10 +5799,6 @@ "mlly/pkg-types/mlly/ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], - "nitro/rolldown/@rolldown/binding-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q=="], - - "nitro/rolldown/@rolldown/binding-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg=="], - "nitropack/ioredis/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "nitropack/serve-static/send/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], @@ -5966,8 +6003,6 @@ "lucide-vue-next/vue/@vue/compiler-sfc/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "nitro/rolldown/@rolldown/binding-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="], - "nitropack/serve-static/send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], "rollup-plugin-visualizer/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], diff --git a/deno.lock b/deno.lock index ba136a83..17b0e4bc 100644 --- a/deno.lock +++ b/deno.lock @@ -20,6 +20,8 @@ "npm:@prisma/adapter-pg@^7.9.1": "7.9.1", "npm:@prisma/client@7.9.1": "7.9.1_prisma@7.9.1__react@19.2.3_react@19.2.3", "npm:@prisma/client@^7.9.1": "7.9.1_prisma@7.9.1__react@19.2.3_react@19.2.3", + "npm:@tanstack/react-router@1.170.15": "1.170.15_react@19.2.3_react-dom@19.2.8__react@19.2.3", + "npm:@tanstack/react-start@1.168.25": "1.168.25_react@19.2.3_react-dom@19.2.8__react@19.2.3_@tanstack+react-router@1.170.15__react@19.2.3__react-dom@19.2.8___react@19.2.3", "npm:@types/pg@^8.20.0": "8.20.4", "npm:@types/supertest@^7.2.0": "7.2.1", "npm:arktype@2.2.0": "2.2.0", @@ -133,13 +135,62 @@ "cookie@1.1.1", "typebox", "valibot@1.4.0", - "zod" + "zod@4.3.5" ], "optionalPeers": [ "arktype", "typebox", "valibot@1.4.0", - "zod" + "zod@4.3.5" + ] + }, + "@babel/code-frame@7.27.1": { + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dependencies": [ + "@babel/helper-validator-identifier@7.29.7", + "js-tokens", + "picocolors" + ] + }, + "@babel/code-frame@7.29.7": { + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dependencies": [ + "@babel/helper-validator-identifier@7.29.7", + "js-tokens", + "picocolors" + ] + }, + "@babel/compat-data@7.29.7": { + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==" + }, + "@babel/core@7.29.7": { + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dependencies": [ + "@babel/code-frame@7.29.7", + "@babel/generator@7.29.8", + "@babel/helper-compilation-targets", + "@babel/helper-module-transforms", + "@babel/helpers", + "@babel/parser@7.29.8", + "@babel/template", + "@babel/traverse", + "@babel/types@7.29.8", + "@jridgewell/remapping", + "convert-source-map", + "debug@4.4.3", + "gensync", + "json5", + "semver@6.3.1" + ] + }, + "@babel/generator@7.29.8": { + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dependencies": [ + "@babel/parser@7.29.8", + "@babel/types@7.29.8", + "@jridgewell/gen-mapping", + "@jridgewell/trace-mapping", + "jsesc" ] }, "@babel/generator@8.0.0-rc.3": { @@ -153,15 +204,67 @@ "jsesc" ] }, + "@babel/helper-compilation-targets@7.29.7": { + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dependencies": [ + "@babel/compat-data", + "@babel/helper-validator-option", + "browserslist", + "lru-cache", + "semver@6.3.1" + ] + }, + "@babel/helper-globals@7.29.7": { + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==" + }, + "@babel/helper-module-imports@7.29.7": { + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dependencies": [ + "@babel/traverse", + "@babel/types@7.29.8" + ] + }, + "@babel/helper-module-transforms@7.29.7_@babel+core@7.29.7": { + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dependencies": [ + "@babel/core", + "@babel/helper-module-imports", + "@babel/helper-validator-identifier@7.29.7", + "@babel/traverse" + ] + }, + "@babel/helper-string-parser@7.29.7": { + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==" + }, "@babel/helper-string-parser@8.0.0": { "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==" }, + "@babel/helper-validator-identifier@7.29.7": { + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==" + }, "@babel/helper-validator-identifier@8.0.0-rc.3": { "integrity": "sha512-8AWCJ2VJJyDFlGBep5GpaaQ9AAaE/FjAcrqI7jyssYhtL7WGV0DOKpJsQqM037xDbpRLHXsY8TwU7zDma7coOw==" }, "@babel/helper-validator-identifier@8.0.4": { "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==" }, + "@babel/helper-validator-option@7.29.7": { + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==" + }, + "@babel/helpers@7.29.7": { + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dependencies": [ + "@babel/template", + "@babel/types@7.29.8" + ] + }, + "@babel/parser@7.29.8": { + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dependencies": [ + "@babel/types@7.29.8" + ], + "bin": true + }, "@babel/parser@8.0.0-rc.3": { "integrity": "sha512-B20dvP3MfNc/XS5KKCHy/oyWl5IA6Cn9YjXRdDlCjNmUFrjvLXMNUfQq/QUy9fnG2gYkKKcrto2YaF9B32ToOQ==", "dependencies": [ @@ -176,17 +279,44 @@ ], "bin": true }, + "@babel/template@7.29.7": { + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dependencies": [ + "@babel/code-frame@7.29.7", + "@babel/parser@7.29.8", + "@babel/types@7.29.8" + ] + }, + "@babel/traverse@7.29.8": { + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dependencies": [ + "@babel/code-frame@7.29.7", + "@babel/generator@7.29.8", + "@babel/helper-globals", + "@babel/parser@7.29.8", + "@babel/template", + "@babel/types@7.29.8", + "debug@4.4.3" + ] + }, + "@babel/types@7.29.8": { + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dependencies": [ + "@babel/helper-string-parser@7.29.7", + "@babel/helper-validator-identifier@7.29.7" + ] + }, "@babel/types@8.0.0-rc.3": { "integrity": "sha512-mOm5ZrYmphGfqVWoH5YYMTITb3cDXsFgmvFlvkvWDMsR9X8RFnt7a0Wb6yNIdoFsiMO9WjYLq+U/FMtqIYAF8Q==", "dependencies": [ - "@babel/helper-string-parser", + "@babel/helper-string-parser@8.0.0", "@babel/helper-validator-identifier@8.0.4" ] }, "@babel/types@8.0.4": { "integrity": "sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==", "dependencies": [ - "@babel/helper-string-parser", + "@babel/helper-string-parser@8.0.0", "@babel/helper-validator-identifier@8.0.4" ] }, @@ -396,6 +526,13 @@ "@jridgewell/trace-mapping" ] }, + "@jridgewell/remapping@2.3.5": { + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dependencies": [ + "@jridgewell/gen-mapping", + "@jridgewell/trace-mapping" + ] + }, "@jridgewell/resolve-uri@3.1.2": { "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==" }, @@ -472,6 +609,30 @@ "@noble/hashes@1.8.0": { "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==" }, + "@oozcitak/dom@2.0.2": { + "integrity": "sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==", + "dependencies": [ + "@oozcitak/infra", + "@oozcitak/url", + "@oozcitak/util" + ] + }, + "@oozcitak/infra@2.0.2": { + "integrity": "sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==", + "dependencies": [ + "@oozcitak/util" + ] + }, + "@oozcitak/url@3.0.0": { + "integrity": "sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==", + "dependencies": [ + "@oozcitak/infra", + "@oozcitak/util" + ] + }, + "@oozcitak/util@10.0.0": { + "integrity": "sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==" + }, "@oxc-project/types@0.127.0": { "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==" }, @@ -1021,6 +1182,195 @@ "tslib" ] }, + "@tanstack/history@1.162.0": { + "integrity": "sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==" + }, + "@tanstack/react-router@1.170.15_react@19.2.3_react-dom@19.2.8__react@19.2.3": { + "integrity": "sha512-GawYz7HEjj8rTUUDoT/SemDEVm63pZUO+2mOcXHY9Jl3EwMS5gFBnPu/2UvcrwRm1jN1k79fokc0d4aFmrLatg==", + "dependencies": [ + "@tanstack/history", + "@tanstack/react-store", + "@tanstack/router-core", + "isbot", + "react", + "react-dom" + ] + }, + "@tanstack/react-start-client@1.168.13_react@19.2.3_react-dom@19.2.8__react@19.2.3": { + "integrity": "sha512-enr4hL0Fifqz7jO8Zy4CuEpunEfH1LbvMw/mRjG49j699Bo3CaR7mPDcgN/9tSSjjUT5ZDj9M6TiTp9cSgehww==", + "dependencies": [ + "@tanstack/react-router", + "@tanstack/router-core", + "@tanstack/start-client-core", + "react", + "react-dom" + ] + }, + "@tanstack/react-start-rsc@0.1.24_react@19.2.3_react-dom@19.2.8__react@19.2.3_@tanstack+react-router@1.170.15__react@19.2.3__react-dom@19.2.8___react@19.2.3": { + "integrity": "sha512-8zBLV68t6byrbtIyKYNTCpcc7qFbb0kQiu0yFtFIvsi70fpBeG3VP8bmkN95/Cqpvz1lLio+E4JApRyV52MpxQ==", + "dependencies": [ + "@tanstack/react-router", + "@tanstack/router-core", + "@tanstack/router-utils", + "@tanstack/start-client-core", + "@tanstack/start-fn-stubs", + "@tanstack/start-plugin-core", + "@tanstack/start-server-core", + "@tanstack/start-storage-context", + "pathe", + "react", + "react-dom" + ] + }, + "@tanstack/react-start-server@1.167.19_react@19.2.3_react-dom@19.2.8__react@19.2.3": { + "integrity": "sha512-+eMpAwDreQvCwgX45MdUHTUCF/Wad36+PwQafe6W5wa3qVkGyN3P131ShGyRwT/0WwKa5EVGdW1zFgwby8UNqA==", + "dependencies": [ + "@tanstack/react-router", + "@tanstack/router-core", + "@tanstack/start-server-core", + "react", + "react-dom" + ] + }, + "@tanstack/react-start@1.168.25_react@19.2.3_react-dom@19.2.8__react@19.2.3_@tanstack+react-router@1.170.15__react@19.2.3__react-dom@19.2.8___react@19.2.3": { + "integrity": "sha512-aHlg9YTSeL12gWrYIHAEzoncPHc5JUbQ60Sc26OQ7J1zcsXqdKwdcqaApG4YV12S/keFdbndHjxaiYkUcJlx7Q==", + "dependencies": [ + "@tanstack/react-router", + "@tanstack/react-start-client", + "@tanstack/react-start-rsc", + "@tanstack/react-start-server", + "@tanstack/router-utils", + "@tanstack/start-client-core", + "@tanstack/start-plugin-core", + "@tanstack/start-server-core", + "pathe", + "react", + "react-dom" + ] + }, + "@tanstack/react-store@0.9.3_react@19.2.3_react-dom@19.2.8__react@19.2.3": { + "integrity": "sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==", + "dependencies": [ + "@tanstack/store", + "react", + "react-dom", + "use-sync-external-store" + ] + }, + "@tanstack/router-core@1.171.13_seroval@1.6.2": { + "integrity": "sha512-+NOwEj1kO/6IGmpHRIZHasYxYWpyBQGNIZAST9aNrk9Q3YlU9SgqVnl1pbLa9qAKfeNdXQIRve0RQb/0kyDeDA==", + "dependencies": [ + "@tanstack/history", + "cookie-es", + "seroval", + "seroval-plugins" + ] + }, + "@tanstack/router-generator@1.167.17": { + "integrity": "sha512-xtB9tB2Ws0tWR6Pi7nc3Qk9IYgoh1mQCKWjHqIl9tf6BNUpKoqniJoPAQ4+LGrK8FeZYU0o0p/qlZEyj9FAulA==", + "dependencies": [ + "@babel/types@7.29.8", + "@tanstack/router-core", + "@tanstack/router-utils", + "@tanstack/virtual-file-routes", + "jiti", + "magic-string", + "prettier", + "zod@4.4.3" + ] + }, + "@tanstack/router-plugin@1.168.18_@tanstack+react-router@1.170.15__react@19.2.3__react-dom@19.2.8___react@19.2.3_react@19.2.3_react-dom@19.2.8__react@19.2.3": { + "integrity": "sha512-MofS28/axfnfnhOD2RSgJEaU882aX5RsAzhGz5Vc4XhAmvCjy919u9JrNs4QsTWFbTD1P7IJ8WFlFVsrg0pStg==", + "dependencies": [ + "@babel/core", + "@babel/template", + "@babel/types@7.29.8", + "@tanstack/react-router", + "@tanstack/router-core", + "@tanstack/router-generator", + "@tanstack/router-utils", + "chokidar", + "unplugin", + "zod@4.4.3" + ], + "optionalPeers": [ + "@tanstack/react-router" + ] + }, + "@tanstack/router-utils@1.162.2": { + "integrity": "sha512-hTWqJtqIFFdvuCl8WXNyrodp2L9zo2G37xKRrcVmVRWpAB2h+U1LuRAfS4tsFTiWOIoE/B+WDVFB8JpoEdw6jQ==", + "dependencies": [ + "@babel/generator@7.29.8", + "@babel/parser@7.29.8", + "@babel/types@7.29.8", + "ansis", + "babel-dead-code-elimination", + "diff", + "pathe", + "tinyglobby" + ] + }, + "@tanstack/start-client-core@1.170.12": { + "integrity": "sha512-gwtZRMPUIAxmDV2AIQUhC0kSW262SV7BkHXEgy5B1woHQdrdsELuGOdJwdweLxrjyefORxk+9MYGqDY0Cxn0bw==", + "dependencies": [ + "@tanstack/router-core", + "@tanstack/start-fn-stubs", + "@tanstack/start-storage-context", + "seroval" + ] + }, + "@tanstack/start-fn-stubs@1.162.0": { + "integrity": "sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==" + }, + "@tanstack/start-plugin-core@1.171.17_@tanstack+react-router@1.170.15__react@19.2.3__react-dom@19.2.8___react@19.2.3_react@19.2.3_react-dom@19.2.8__react@19.2.3": { + "integrity": "sha512-ngKkp3wn/U3nyeqZl7KcMzjbgTbcypC5ES7O92JpA5/tz4PufFOf5l+eX3pY+4Z6jE6Jb6ekQgnryG7XMjpK7Q==", + "dependencies": [ + "@babel/code-frame@7.27.1", + "@babel/core", + "@babel/types@7.29.8", + "@tanstack/router-core", + "@tanstack/router-generator", + "@tanstack/router-plugin", + "@tanstack/router-utils", + "@tanstack/start-server-core", + "exsolve", + "lightningcss", + "pathe", + "picomatch", + "seroval", + "source-map", + "srvx@0.11.22", + "tinyglobby", + "ufo", + "vitefu", + "xmlbuilder2", + "zod@4.4.3" + ] + }, + "@tanstack/start-server-core@1.169.14": { + "integrity": "sha512-cSCTNbKARrkddPOfavF/soRFDxH+b+v3m4TeW6AvEy419R3E0ZsoZAm5UI6uNR1y4UU9WTOmaxLQ4nzIZPKmXg==", + "dependencies": [ + "@tanstack/history", + "@tanstack/router-core", + "@tanstack/start-client-core", + "@tanstack/start-storage-context", + "fetchdts", + "h3-v2@npm:h3@2.0.1-rc.26", + "seroval" + ] + }, + "@tanstack/start-storage-context@1.167.15": { + "integrity": "sha512-Jy0q4vdG6pv76N92+X+ag3fuOV2zINQagYyMN1/es7tPI1vzpKECIU8AqHqzI6ahkwaph7XDvmfUkiLJ3i4LOA==", + "dependencies": [ + "@tanstack/router-core" + ] + }, + "@tanstack/store@0.9.3": { + "integrity": "sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==" + }, + "@tanstack/virtual-file-routes@1.162.0": { + "integrity": "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==" + }, "@tokenizer/inflate@0.4.1": { "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", "dependencies": [ @@ -1298,6 +1648,9 @@ "ansis@4.3.1": { "integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==" }, + "argparse@2.0.1": { + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, "arkregex@0.0.5": { "integrity": "sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==", "dependencies": [ @@ -1332,6 +1685,15 @@ "aws-ssl-profiles@1.1.2": { "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==" }, + "babel-dead-code-elimination@1.0.12": { + "integrity": "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==", + "dependencies": [ + "@babel/core", + "@babel/parser@7.29.8", + "@babel/traverse", + "@babel/types@7.29.8" + ] + }, "baseline-browser-mapping@2.11.12": { "integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==", "bin": true @@ -1359,6 +1721,17 @@ "unpipe" ] }, + "browserslist@4.28.7": { + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "dependencies": [ + "baseline-browser-mapping", + "caniuse-lite", + "electron-to-chromium", + "node-releases", + "update-browserslist-db" + ], + "bin": true + }, "bytes@3.1.2": { "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, @@ -1432,6 +1805,12 @@ "content-type@1.0.5": { "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, + "convert-source-map@2.0.0": { + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "cookie-es@3.1.1": { + "integrity": "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==" + }, "cookie-signature@1.0.7": { "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==" }, @@ -1577,6 +1956,9 @@ "wrappy" ] }, + "diff@8.0.4": { + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==" + }, "dotenv@17.4.2": { "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==" }, @@ -1610,6 +1992,9 @@ "fast-check" ] }, + "electron-to-chromium@1.5.402": { + "integrity": "sha512-/oOpMaPT6Yg+6/1XQhyIPlzgj7Ye9zf+nNM2Uh6OcE2G2oNptWazFa+qB2Pdqqbsc9KnIDzgAntoYN0dbwOXwA==" + }, "elkjs@0.11.1": { "integrity": "sha512-zxxR9k+rx5ktMwT/FwyLdPCrq7xN6e4VGGHH8hA01vVYKjTFik7nHOxBnAYtrgYUB1RpAiLvA1/U2YraWxyKKg==" }, @@ -1655,6 +2040,9 @@ "hasown" ] }, + "escalade@3.2.0": { + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==" + }, "escape-html@1.0.3": { "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, @@ -1751,6 +2139,9 @@ "picomatch" ] }, + "fetchdts@0.1.7": { + "integrity": "sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==" + }, "file-type@21.3.4": { "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", "dependencies": [ @@ -1830,6 +2221,9 @@ "is-property" ] }, + "gensync@1.0.0-beta.2": { + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, "get-intrinsic@1.3.0": { "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dependencies": [ @@ -1877,6 +2271,14 @@ "graphmatch@1.1.1": { "integrity": "sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==" }, + "h3@2.0.1-rc.26": { + "integrity": "sha512-GDxlvDsKxgjRvG5UBRJYyGJTMWLV30CJ4cV+e7QCTgftDHihrvio1fVPbNembhEr6J4WNm8IWy3fookgyTweLw==", + "dependencies": [ + "rou3", + "srvx@0.12.5" + ], + "bin": true + }, "has-symbols@1.1.0": { "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" }, @@ -1947,6 +2349,9 @@ "isarray@0.0.1": { "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" }, + "isbot@5.2.1": { + "integrity": "sha512-dJ+LpKyClQZ7NG+j3OensC/mAZkGpukE9YUrgPYvAZj2doVL0edfDgywTUh5CXa0o+nW9a1V9e5+CJTX8+SxRw==" + }, "isexe@2.0.0": { "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, @@ -1957,6 +2362,16 @@ "jose@6.2.8": { "integrity": "sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==" }, + "js-tokens@4.0.0": { + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml@4.3.1": { + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "dependencies": [ + "argparse" + ], + "bin": true + }, "jsesc@3.1.0": { "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "bin": true @@ -1964,15 +2379,105 @@ "json-schema-traverse@1.0.0": { "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, + "json5@2.2.3": { + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": true + }, + "lightningcss-android-arm64@1.33.0": { + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "os": ["android"], + "cpu": ["arm64"] + }, + "lightningcss-darwin-arm64@1.33.0": { + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "lightningcss-darwin-x64@1.33.0": { + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "lightningcss-freebsd-x64@1.33.0": { + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "os": ["freebsd"], + "cpu": ["x64"] + }, + "lightningcss-linux-arm-gnueabihf@1.33.0": { + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "os": ["linux"], + "cpu": ["arm"] + }, + "lightningcss-linux-arm64-gnu@1.33.0": { + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "lightningcss-linux-arm64-musl@1.33.0": { + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "lightningcss-linux-x64-gnu@1.33.0": { + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "os": ["linux"], + "cpu": ["x64"] + }, + "lightningcss-linux-x64-musl@1.33.0": { + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "os": ["linux"], + "cpu": ["x64"] + }, + "lightningcss-win32-arm64-msvc@1.33.0": { + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "lightningcss-win32-x64-msvc@1.33.0": { + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "os": ["win32"], + "cpu": ["x64"] + }, + "lightningcss@1.33.0": { + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dependencies": [ + "detect-libc" + ], + "optionalDependencies": [ + "lightningcss-android-arm64", + "lightningcss-darwin-arm64", + "lightningcss-darwin-x64", + "lightningcss-freebsd-x64", + "lightningcss-linux-arm-gnueabihf", + "lightningcss-linux-arm64-gnu", + "lightningcss-linux-arm64-musl", + "lightningcss-linux-x64-gnu", + "lightningcss-linux-x64-musl", + "lightningcss-win32-arm64-msvc", + "lightningcss-win32-x64-msvc" + ] + }, "lodash@4.18.1": { "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" }, "long@5.3.2": { "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==" }, + "lru-cache@5.1.1": { + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": [ + "yallist" + ] + }, "lru.min@1.1.4": { "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==" }, + "magic-string@0.30.21": { + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dependencies": [ + "@jridgewell/sourcemap-codec" + ] + }, "math-intrinsics@1.1.0": { "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" }, @@ -2087,6 +2592,9 @@ "type-is" ] }, + "node-releases@2.0.53": { + "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==" + }, "object-inspect@1.13.4": { "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==" }, @@ -2118,10 +2626,10 @@ "form-data-encoder", "formdata-node", "node-fetch", - "zod" + "zod@4.3.5" ], "optionalPeers": [ - "zod" + "zod@4.3.5" ], "bin": true }, @@ -2292,6 +2800,10 @@ "postgres@3.4.7": { "integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==" }, + "prettier@3.9.6": { + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "bin": true + }, "prisma@7.9.1_react@19.2.3": { "integrity": "sha512-aPqePoZIqwlAchbgbFDO/wHqGB+7H1nj9gaM+OsL9h77S5S3TnLd9BgD3LnoeDikULo7cl2HSUrEyQ55Z7DYbg==", "dependencies": [ @@ -2394,7 +2906,7 @@ "rolldown-plugin-dts@0.23.2_rolldown@1.0.0-rc.17": { "integrity": "sha512-PbSqLawLgZBGcOGT3yqWBGn4cX+wh2nt5FuBGdcMHyOhoukmjbhYAl8NT9sE4U38Cm9tqLOIQeOrvzeayM0DLQ==", "dependencies": [ - "@babel/generator", + "@babel/generator@8.0.0-rc.3", "@babel/helper-validator-identifier@8.0.0-rc.3", "@babel/parser@8.0.0-rc.3", "@babel/types@8.0.0-rc.3", @@ -2432,6 +2944,9 @@ ], "bin": true }, + "rou3@0.9.1": { + "integrity": "sha512-z/sSmzvtwMDDnxsPVhfWMuG6F6mbmhFDXoVqLmMfbpDD9qfV3GDmSQpf0+W296/ZDIpW2wcMmBfpVFzcnOi/nA==" + }, "safe-buffer@5.2.1": { "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, @@ -2448,6 +2963,10 @@ "scheduler@0.27.0": { "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==" }, + "semver@6.3.1": { + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": true + }, "semver@7.8.5": { "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "bin": true @@ -2473,6 +2992,15 @@ "seq-queue@0.0.5": { "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" }, + "seroval-plugins@1.6.2_seroval@1.6.2": { + "integrity": "sha512-TfxuUjlbBESzUOWdTkTKqvSmav0ABym+itetDXLK6mDz8SmrpdI30aF8RTXE8Bvq+tH/1yIDkvy3W0lfQb1ipQ==", + "dependencies": [ + "seroval" + ] + }, + "seroval@1.6.2": { + "integrity": "sha512-mPT+SD2TrlB6wvte1KkYOYUkubaTbd6pZ/6Kk3C9nxzrHmCZyhxOO7XGAeL7f+yLKZglzGtM9odUVvg/EhO+vQ==" + }, "serve-static@1.16.3": { "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", "dependencies": [ @@ -2493,7 +3021,7 @@ "dependencies": [ "@img/colour", "detect-libc", - "semver" + "semver@7.8.5" ], "optionalDependencies": [ "@img/sharp-darwin-arm64", @@ -2577,12 +3105,23 @@ "source-map-js@1.2.1": { "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" }, + "source-map@0.7.6": { + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==" + }, "split2@4.2.0": { "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" }, "sqlstring@2.3.3": { "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" }, + "srvx@0.11.22": { + "integrity": "sha512-LqZxxBDMKuMAZzFzJnDCkFOrs9MZQZr0LvHiO/SuSZVdQaXD7xQ5UWTUxheJrQPve1qk9MG2B/yttUvJxw8egQ==", + "bin": true + }, + "srvx@0.12.5": { + "integrity": "sha512-IuvtDNQg5EIwv3c6dleyau7u8hCyGQ7D6+V/QM799Aud07z0wCUcurKLTRfyG33C8oUY+UWcVBFkfHMcbtmRLA==", + "bin": true + }, "statuses@2.0.2": { "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==" }, @@ -2686,7 +3225,7 @@ "picomatch", "rolldown", "rolldown-plugin-dts", - "semver", + "semver@7.8.5", "tinyexec", "tinyglobby", "tree-kill", @@ -2720,6 +3259,9 @@ "typebox@1.1.38": { "integrity": "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==" }, + "ufo@1.6.4": { + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==" + }, "uint8array-extras@1.5.0": { "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==" }, @@ -2736,6 +3278,14 @@ "unpipe@1.0.0": { "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, + "unplugin@3.3.0": { + "integrity": "sha512-qa66K+crbfyE6JK10GjvbJeRrOsuC/JpbnHctfyp/i4oBTxWOzJfRZyDiOk1PtErMFRu8JhsU/wPvOdBNWe5Rg==", + "dependencies": [ + "@jridgewell/remapping", + "picomatch", + "webpack-virtual-modules" + ] + }, "unrun@0.2.39": { "integrity": "sha512-h9FxYVpztY/wwq+bauLOh6Y3CWu2IVeRLq5lxzneBiIU9Tn86OGp9xiQrGhnYspAmg5dzdY0Cc8+Y70kuTARCg==", "dependencies": [ @@ -2743,6 +3293,21 @@ ], "bin": true }, + "update-browserslist-db@1.3.0_browserslist@4.28.7": { + "integrity": "sha512-x/M6q3w4Ybp91CNaS4S69UnliqR3BzRpOT6LWbksjth0S/+jhfaPJsWjt/TewpT8j9eLIojUf5jr29WextHroA==", + "dependencies": [ + "browserslist", + "escalade", + "picocolors" + ], + "bin": true + }, + "use-sync-external-store@1.6.0_react@19.2.3": { + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "dependencies": [ + "react" + ] + }, "utils-merge@1.0.1": { "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, @@ -2755,12 +3320,18 @@ "vary@1.1.2": { "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, + "vitefu@1.1.3": { + "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==" + }, "web-streams-polyfill@4.0.0-beta.3": { "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==" }, "webidl-conversions@3.0.1": { "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, + "webpack-virtual-modules@0.6.2": { + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==" + }, "whatwg-url@5.0.0": { "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dependencies": [ @@ -2778,9 +3349,21 @@ "wrappy@1.0.2": { "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "xmlbuilder2@4.0.3": { + "integrity": "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==", + "dependencies": [ + "@oozcitak/dom", + "@oozcitak/infra", + "@oozcitak/util", + "js-yaml" + ] + }, "xtend@4.0.2": { "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, + "yallist@3.1.1": { + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "zeptomatch@2.1.0": { "integrity": "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==", "dependencies": [ @@ -2790,6 +3373,9 @@ }, "zod@4.3.5": { "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==" + }, + "zod@4.4.3": { + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==" } }, "workspace": { @@ -2945,6 +3531,13 @@ "npm:react-router@^7.12.0", "npm:react@^19.2.3" ] + }, + "packages/tanstack-start": { + "dependencies": [ + "npm:@aura-stack/auth@0.9.0", + "npm:@tanstack/react-router@1.170.15", + "npm:@tanstack/react-start@1.168.25" + ] } } } diff --git a/packages/integration/deno.json b/packages/integration/deno.json index 4b0fc0af..dd75d67d 100644 --- a/packages/integration/deno.json +++ b/packages/integration/deno.json @@ -10,7 +10,11 @@ }, "exports": { ".": "./src/index.ts", - "./identity": "./src/_core/identity.ts", + "./identity": "./src/identity/index.ts", + "./identity/zod": "./src/identity/zod.ts", + "./identity/valibot": "./src/identity/valibot.ts", + "./identity/arktype": "./src/identity/arktype.ts", + "./identity/typebox": "./src/identity/typebox.ts", "./crypto": "./src/_core/crypto.ts", "./shared": "./src/_core/shared.ts", "./cookies": "./src/_core/cookies.ts", diff --git a/packages/integration/package.json b/packages/integration/package.json index 32fdf780..c527bc25 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -73,6 +73,11 @@ "import": "./dist/_core/identity.js", "require": "./dist/_core/identity.cjs" }, + "./identity/*": { + "types": "./dist/_core/identity/*.d.ts", + "import": "./dist/_core/identity/*.js", + "require": "./dist/_core/identity/*.cjs" + }, "./crypto": { "types": "./dist/_core/crypto.d.ts", "import": "./dist/_core/crypto.js", diff --git a/packages/tanstack-start/CHANGELOG.md b/packages/tanstack-start/CHANGELOG.md new file mode 100644 index 00000000..4869ff5d --- /dev/null +++ b/packages/tanstack-start/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog - `@aura-stack/tanstack-start` + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +--- + +## [Unreleased] + +### Added + +- Introduced the `@aura-stack/tanstack-start` integration package, delivering seamless authentication for TanStack Start applications across server-side rendering (SSR) and client-side rendering (CSR). Built on top of `@aura-stack/react`, the package provides first-class support for TanStack Start server functions, while client-side APIs are available through the `/client` entry point. [#255](https://github.com/aura-stack-ts/auth/pull/255) diff --git a/packages/tanstack-start/README.md b/packages/tanstack-start/README.md new file mode 100644 index 00000000..eae41ea1 --- /dev/null +++ b/packages/tanstack-start/README.md @@ -0,0 +1,35 @@ +
+ +

@aura-stack/integration

+ +**Integration authentication library for the Aura Stack ecosystem** + +[![npm version](https://img.shields.io/npm/v/@aura-stack/integration.svg)](https://www.npmjs.com/package/@aura-stack/integration) +[![JSR version](https://jsr.io/badges/@aura-stack/integration)](https://jsr.io/@aura-stack/integration) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) + +[Official Docs](https://aura-stack-auth.vercel.app/docs) · [Core Package Docs](https://aura-stack-auth.vercel.app/docs/packages/core) + +
+ +## Features + +## Installation + +```bash +pnpm add @aura-stack/integration +``` + +## Documentation + +Visit the [**official documentation website**](https://aura-stack-auth.vercel.app). + +## License + +Licensed under the [MIT License](../../LICENSE). © [Aura Stack](https://github.com/aura-stack-ts) + +--- + +

+ Made with ❤️ by Aura Stack team +

diff --git a/packages/tanstack-start/deno.json b/packages/tanstack-start/deno.json new file mode 100644 index 00000000..1f00b145 --- /dev/null +++ b/packages/tanstack-start/deno.json @@ -0,0 +1,50 @@ +{ + "name": "@aura-stack/tanstack-start", + "version": "0.0.0", + "license": "MIT", + "tasks": { + "dev": "deno run --watch src/index.ts" + }, + "imports": { + "@/": "./src/", + "@aura-stack/auth": "npm:@aura-stack/auth@0.9.0", + "@tanstack/react-start": "npm:@tanstack/react-start@1.168.25", + "@tanstack/react-router": "npm:@tanstack/react-router@1.170.15" + }, + "exports": { + ".": "./src/index.ts", + "./identity": "./src/identity/index.ts", + "./identity/zod": "./src/identity/zod.ts", + "./identity/valibot": "./src/identity/valibot.ts", + "./identity/arktype": "./src/identity/arktype.ts", + "./identity/typebox": "./src/identity/typebox.ts", + "./crypto": "./src/_core/crypto.ts", + "./shared": "./src/_core/shared.ts", + "./cookies": "./src/_core/cookies.ts", + "./oauth": "./src/oauth/index.ts", + "./oauth/atlassian": "./src/oauth/atlassian.ts", + "./oauth/authentik": "./src/oauth/authentik.ts", + "./oauth/bitbucket": "./src/oauth/bitbucket.ts", + "./oauth/click-up": "./src/oauth/click-up.ts", + "./oauth/discord": "./src/oauth/discord.ts", + "./oauth/dribbble": "./src/oauth/dribbble.ts", + "./oauth/dropbox": "./src/oauth/dropbox.ts", + "./oauth/figma": "./src/oauth/figma.ts", + "./oauth/github": "./src/oauth/github.ts", + "./oauth/gitlab": "./src/oauth/gitlab.ts", + "./oauth/google": "./src/oauth/google.ts", + "./oauth/hubspot": "./src/oauth/hubspot.ts", + "./oauth/huggingface": "./src/oauth/huggingface.ts", + "./oauth/mailchimp": "./src/oauth/mailchimp.ts", + "./oauth/notion": "./src/oauth/notion.ts", + "./oauth/pinterest": "./src/oauth/pinterest.ts", + "./oauth/spotify": "./src/oauth/spotify.ts", + "./oauth/strava": "./src/oauth/strava.ts", + "./oauth/twitch": "./src/oauth/twitch.ts", + "./oauth/x": "./src/oauth/x.ts" + }, + "publish": { + "include": ["src/**/*.ts", "src/**/*.tsx", "src/_core", "src/oauth", "src/identity", "README.md", "CHANGELOG.md"], + "exclude": ["dist", "node_modules"] + } +} diff --git a/packages/tanstack-start/package.json b/packages/tanstack-start/package.json new file mode 100644 index 00000000..5384313b --- /dev/null +++ b/packages/tanstack-start/package.json @@ -0,0 +1,101 @@ +{ + "name": "@aura-stack/tanstack-start", + "version": "0.0.0", + "private": true, + "type": "module", + "description": "Tanstack Start for Aura Stack authentication library", + "scripts": { + "dev": "tsdown --watch", + "build": "pnpm sync:modules && tsdown", + "lint": "oxlint", + "lint:fix": "oxlint --fix", + "test": "vitest --run", + "test:watch": "vitest", + "test:coverage": "vitest --run --coverage", + "format": "oxfmt", + "format:check": "oxfmt --check", + "type-check": "tsc --noEmit", + "clean": "rm -rf dist src/_core src/oauth", + "clean:cts": "[ -d dist ] && find dist -type f -name \"*.cts\" -delete || true", + "prepublishOnly": "pnpm clean:cts && pnpm build && pnpm clean:cts", + "sync:modules": "node ../shared/scripts/modules.js" + }, + "homepage": "https://aura-stack-auth.vercel.app", + "bugs": { + "url": "https://github.com/aura-stack-ts/auth/issues", + "email": "aurastackjs@gmail.com" + }, + "license": "MIT", + "author": "Aura Stack | Hernan Alvarado ", + "repository": { + "type": "git", + "url": "git+https://github.com/aura-stack-ts/auth" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/halvaradop" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "sideEffects": false, + "files": [ + "dist" + ], + "keywords": [], + "dependencies": { + "@aura-stack/react": "workspace:*" + }, + "devDependencies": { + "@aura-stack/tsconfig": "workspace:*", + "@aura-stack/tsdown-config": "workspace:*" + }, + "peerDependencies": { + "@tanstack/react-start": ">=1.0.0", + "@tanstack/react-router": ">=1.0.0" + }, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, + "./oauth": { + "types": "./dist/oauth/index.d.ts", + "import": "./dist/oauth/index.js", + "require": "./dist/oauth/index.cjs" + }, + "./oauth/*": { + "types": "./dist/oauth/*.d.ts", + "import": "./dist/oauth/*.js", + "require": "./dist/oauth/*.cjs" + }, + "./identity": { + "types": "./dist/_core/identity.d.ts", + "import": "./dist/_core/identity.js", + "require": "./dist/_core/identity.cjs" + }, + "./identity/*": { + "types": "./dist/_core/identity/*.d.ts", + "import": "./dist/_core/identity/*.js", + "require": "./dist/_core/identity/*.cjs" + }, + "./crypto": { + "types": "./dist/_core/crypto.d.ts", + "import": "./dist/_core/crypto.js", + "require": "./dist/_core/crypto.cjs" + }, + "./shared": { + "types": "./dist/_core/shared.d.ts", + "import": "./dist/_core/shared.js", + "require": "./dist/_core/shared.cjs" + }, + "./cookies": { + "types": "./dist/_core/cookies.d.ts", + "import": "./dist/_core/cookies.js", + "require": "./dist/_core/cookies.cjs" + } + }, + "packageManager": "pnpm@10.15.0" +} diff --git a/packages/tanstack-start/src/@types/index.ts b/packages/tanstack-start/src/@types/index.ts new file mode 100644 index 00000000..97f008d3 --- /dev/null +++ b/packages/tanstack-start/src/@types/index.ts @@ -0,0 +1,101 @@ +import type { AuthInstance } from "@aura-stack/react" +import type { + LiteralUnion, + SignInAPIOptions, + BuiltInOAuthProvider, + Prettify, + SignInCredentialsAPIOptions, + SignOutAPIOptions, + UpdateSessionAPIOptions, + User, + SignUpAPIOptions, + GetProviderTokensAPIOptions, + AccessTokenAPIOptions, + RefreshUserInfoAPIOptions, + RevokeTokenAPIOptions, + DisconnectProviderAPIOptions, + ProviderConnectedAPIOptions, +} from "@aura-stack/react/types" +import type { FromShapeToObject, Identities, SchemaTypes } from "@aura-stack/react/identity" +import type { + SignInAPIReturn, + SignInCredentialsAPIReturn, + SignOutAPIReturn, + UpdateSessionAPIReturn, + SignUpAPIReturn, + GetProviderTokensAPIReturn, + AccessTokenAPIReturn, + RefreshUserInfoAPIReturn, + RevokeTokenAPIReturn, + DisconnectProviderAPIReturn, + ProviderConnectedAPIReturn, +} from "@aura-stack/react/types" + +export type TanstackStartInstance< + Identity extends Identities = Identities, + SignUpSchema extends SchemaTypes = SchemaTypes, +> = AuthInstance, SignUpSchema> + +export type TanstackStartSignInOptions = Prettify< + Omit & { providerId: LiteralUnion } +> + +export type TanstackStartSignInReturn = Prettify> + +export type TanstackStartSignInCredentialsOptions = Prettify> + +export type TanstackStartSignInCredentialsReturn = Prettify> + +export type TanstackStartSignOutOptions = Prettify> + +export type TanstackStartSignOutReturn = Prettify> + +export type TanstackStartUpdateSessionOptions = Prettify< + Omit, "headers" | "request"> +> + +export type TanstackStartUpdateSessionReturn = Prettify< + Omit, "headers" | "toResponse" | "session"> +> + +export type TanstackStartSignUpOptions = Prettify> + +export type TanstackStartSignUpReturn = Prettify> + +export type TanstackStartGetProviderTokensOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartGetProviderTokensReturn = Prettify> + +export type TanstackStartGetAccessTokenOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartGetAccessTokenReturn = Prettify> + +export type TanstackStartRefreshUserInfoOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartRefreshUserInfoReturn = Prettify< + Omit, "headers" | "toResponse"> +> + +export type TanstackStartRevokeTokenOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartRevokeTokenReturn = Prettify> + +export type TanstackStartDisconnectProviderOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartDisconnectProviderReturn = Prettify> + +export type TanstackStartIsProviderConnectedOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartIsProviderConnectedReturn = Prettify> diff --git a/packages/tanstack-start/src/createAuth.ts b/packages/tanstack-start/src/createAuth.ts new file mode 100644 index 00000000..e8dbeb7d --- /dev/null +++ b/packages/tanstack-start/src/createAuth.ts @@ -0,0 +1,46 @@ +import { api } from "@/lib/api.ts" +import { createAuth as createAuthInstance } from "@aura-stack/react/server" +import type { AuthConfig } from "@aura-stack/react/types" +import type { FromShapeToObject, Identities, SchemaTypes } from "@aura-stack/react/identity" + +/** + * Create an auth instance built on top of the Aura Stack Auth library, + * providing a higher-level API for common authentication tasks. + * + * @param config - The auth configuration including OAuth providers, credentials, and session strategy. + * @returns An auth instance with a higher-level API for common authentication tasks. + * + * @example + * import { createAuth } from "@aura-stack/tanstack-start" + * + * const auth = createAuth({ + * oauth: ["github", "google"], + * credentials: { + * authorize: async (credentials) => { + * // Custom authorization logic + * } + * } + * }) + */ +export const createAuth = ( + config: AuthConfig +) => { + const auth = createAuthInstance(config) + return { + /** + * The core auth instance. It can be used to advanced use cases, such as creating custom behaviors. + * For most use cases, the `api` property should be sufficient, as it provides a higher-level API for common authentication tasks. + */ + core: auth, + /** + * Built-in API functions for server-side operations related to the auth flows. + * These functions can be used in server functions to handle authentication requests. + * They automatically handle request headers and provide a simplified interface for common auth operations. + */ + api: api>(auth), + /** + * The handlers object contains the HTTP request handlers. + */ + handlers: auth.handlers, + } +} diff --git a/packages/tanstack-start/src/index.ts b/packages/tanstack-start/src/index.ts new file mode 100644 index 00000000..7405f43d --- /dev/null +++ b/packages/tanstack-start/src/index.ts @@ -0,0 +1 @@ +export { createAuth } from "@/createAuth.ts" diff --git a/packages/tanstack-start/src/lib/api.ts b/packages/tanstack-start/src/lib/api.ts new file mode 100644 index 00000000..ae2aa201 --- /dev/null +++ b/packages/tanstack-start/src/lib/api.ts @@ -0,0 +1,221 @@ +import type { + TanstackStartSignInCredentialsOptions, + TanstackStartSignInCredentialsReturn, + TanstackStartSignInOptions, + TanstackStartSignInReturn, + TanstackStartSignOutOptions, + TanstackStartSignOutReturn, + TanstackStartUpdateSessionOptions, + TanstackStartUpdateSessionReturn, + TanstackStartSignUpOptions, + TanstackStartSignUpReturn, + TanstackStartGetProviderTokensOptions, + TanstackStartGetProviderTokensReturn, + TanstackStartGetAccessTokenOptions, + TanstackStartGetAccessTokenReturn, + TanstackStartRefreshUserInfoOptions, + TanstackStartRefreshUserInfoReturn, + TanstackStartRevokeTokenOptions, + TanstackStartRevokeTokenReturn, + TanstackStartDisconnectProviderOptions, + TanstackStartDisconnectProviderReturn, + TanstackStartIsProviderConnectedOptions, + TanstackStartIsProviderConnectedReturn, +} from "@/@types/index.ts" +import type { AuthInstance, User } from "@aura-stack/auth" +import { createServerFn, type OptionalFetcher } from "@tanstack/react-start" +import { getRequest, getRequestHeaders } from "@tanstack/react-start/server" + +export const getSession = ({ api }: AuthInstance) => { + return createServerFn({ + method: "GET", + strict: true, + }).handler(async () => { + const session = await api.getSession({ + headers: getRequestHeaders(), + }) + if (!session.success) return null + return session.session + }) as OptionalFetcher> +} + +export const signIn = ({ api }: AuthInstance) => { + return createServerFn({ method: "POST" }) + .validator((data: TanstackStartSignInOptions) => data) + .handler>(async ({ data }) => { + const { providerId, ...options } = data + const output = await api.signIn(providerId, { + ...options, + headers: getRequestHeaders(), + request: getRequest(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread + }) +} + +export const signInCredentials = ({ api }: AuthInstance) => { + return createServerFn({ method: "POST" }) + .validator((data: TanstackStartSignInCredentialsOptions) => data) + .handler>(async ({ data }) => { + const output = await api.signInCredentials({ + ...data, + headers: getRequestHeaders(), + request: getRequest(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread + }) +} + +export const signOut = ({ api }: AuthInstance) => { + return createServerFn({ method: "POST" }) + .validator((data: TanstackStartSignOutOptions = {}) => data) + .handler>(async ({ data }) => { + const output = await api.signOut({ + ...data, + headers: getRequestHeaders(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread + }) +} + +export const updateSession = ({ api }: AuthInstance) => { + return createServerFn({ method: "POST" }) + .validator((data: TanstackStartUpdateSessionOptions) => data) + .handler>>(async ({ data }) => { + const output = await api.updateSession({ + ...data, + headers: getRequestHeaders(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread + }) +} + +export const signUp = ({ api }: AuthInstance) => { + return createServerFn({ method: "POST" }) + .validator((data: TanstackStartSignUpOptions) => data) + .handler>(async ({ data }) => { + const output = await api.signUp({ + ...data, + headers: getRequestHeaders(), + request: getRequest(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread + }) +} + +export const getProviderTokens = ({ api }: AuthInstance) => { + return createServerFn({ method: "GET" }) + .validator((data: TanstackStartGetProviderTokensOptions) => data) + .handler>(async ({ data }) => { + const { oauth, ...options } = data + const output = await api.getProviderTokens(oauth, { + ...options, + headers: getRequestHeaders(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread + }) +} + +export const getAccessToken = ({ api }: AuthInstance) => { + return createServerFn({ method: "GET" }) + .validator((data: TanstackStartGetAccessTokenOptions) => data) + .handler>(async ({ data }) => { + const { oauth, ...options } = data + const output = await api.getAccessToken(oauth, { + ...options, + headers: getRequestHeaders(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread + }) +} + +createServerFn({ + method: "GET", +}).handler(() => { + return { + name: "jose", + data: { + id: 1, + }, + } +}) + +export const refreshUserInfo = ({ api }: AuthInstance) => { + return createServerFn({ method: "POST" }) + .validator((data: TanstackStartRefreshUserInfoOptions) => data) + .handler(async ({ data }) => { + const { oauth, ...options } = data + const output = await api.refreshUserInfo(oauth, { + ...options, + headers: getRequestHeaders(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread + }) as OptionalFetcher>> +} + +export const revokeToken = ({ api }: AuthInstance) => { + return createServerFn({ method: "POST" }) + .validator((data: TanstackStartRevokeTokenOptions) => data) + .handler>(async ({ data }) => { + const { oauth, ...options } = data + const output = await api.revokeToken(oauth, { + ...options, + headers: getRequestHeaders(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread + }) +} + +export const disconnectProvider = ({ api }: AuthInstance) => { + return createServerFn({ method: "POST" }) + .validator((data: TanstackStartDisconnectProviderOptions) => data) + .handler>(async ({ data }) => { + const { oauth, ...options } = data + const output = await api.disconnectProvider(oauth, { + ...options, + headers: getRequestHeaders(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread + }) +} + +export const isProviderConnected = ({ api }: AuthInstance) => { + return createServerFn({ method: "GET" }) + .validator((data: TanstackStartIsProviderConnectedOptions) => data) + .handler>(async ({ data }) => { + const { oauth, ...options } = data + const output = await api.isProviderConnected(oauth, { + ...options, + headers: getRequestHeaders(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread + }) +} + +export const api = (config: AuthInstance) => { + return { + getSession: getSession(config), + signIn: signIn(config), + signInCredentials: signInCredentials(config), + signOut: signOut(config), + updateSession: updateSession(config), + signUp: signUp(config), + getProviderTokens: getProviderTokens(config), + getAccessToken: getAccessToken(config), + refreshUserInfo: refreshUserInfo(config), + revokeToken: revokeToken(config), + disconnectProvider: disconnectProvider(config), + isProviderConnected: isProviderConnected(config), + } +} diff --git a/packages/tanstack-start/tsconfig.json b/packages/tanstack-start/tsconfig.json new file mode 100644 index 00000000..2aca6a65 --- /dev/null +++ b/packages/tanstack-start/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@aura-stack/tsconfig/tsconfig.base.json", + "compilerOptions": { + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"], + "exclude": ["dist", "node_modules"] +} diff --git a/packages/tanstack-start/tsdown.config.ts b/packages/tanstack-start/tsdown.config.ts new file mode 100644 index 00000000..4d93134a --- /dev/null +++ b/packages/tanstack-start/tsdown.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from "tsdown" +import { tsdownConfig } from "@aura-stack/tsdown-config" + +export default defineConfig({ + ...tsdownConfig, + entry: [ + "src/index.ts", + "src/identity.ts", + "src/identity/*.ts", + "src/oauth/index.ts", + "src/oauth/*.ts", + "src/_core/identity.ts", + "src/_core/crypto.ts", + "src/_core/shared.ts", + "src/_core/cookies.ts", + ], +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d77f9a22..468f0263 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1028,6 +1028,25 @@ importers: specifier: workspace:* version: link:../core + packages/tanstack-start: + dependencies: + '@aura-stack/react': + specifier: workspace:* + version: link:../react + '@tanstack/react-router': + specifier: '>=1.0.0' + version: 1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start': + specifier: '>=1.0.0' + version: 1.168.25(crossws@0.4.10(srvx@0.12.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) + devDependencies: + '@aura-stack/tsconfig': + specifier: workspace:* + version: link:../../configs/tsconfig + '@aura-stack/tsdown-config': + specifier: workspace:* + version: link:../../configs/tsdown-config + packages: '@acemir/cssom@0.9.31': @@ -10642,16 +10661,16 @@ snapshots: '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.0.2 '@babel/generator@8.0.0-rc.3': dependencies: - '@babel/parser': 8.0.0-rc.3 - '@babel/types': 8.0.0-rc.3 + '@babel/parser': 8.0.0-rc.6 + '@babel/types': 8.0.0-rc.6 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 '@types/jsesc': 2.5.1 @@ -10761,7 +10780,7 @@ snapshots: '@babel/parser@7.29.2': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 '@babel/parser@7.29.7': dependencies: @@ -10769,7 +10788,7 @@ snapshots: '@babel/parser@8.0.0-rc.3': dependencies: - '@babel/types': 8.0.0-rc.3 + '@babel/types': 8.0.0-rc.6 '@babel/parser@8.0.0-rc.6': dependencies: @@ -10838,9 +10857,9 @@ snapshots: '@babel/code-frame': 7.29.0 '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.7 '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -10858,7 +10877,7 @@ snapshots: '@babel/types@8.0.0-rc.3': dependencies: '@babel/helper-string-parser': 8.0.0-rc.6 - '@babel/helper-validator-identifier': 8.0.0-rc.3 + '@babel/helper-validator-identifier': 8.0.0-rc.6 '@babel/types@8.0.0-rc.6': dependencies: @@ -13867,6 +13886,27 @@ snapshots: - vite-plugin-solid - webpack + '@tanstack/react-start-rsc@0.1.24(crossws@0.4.10(srvx@0.12.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0))': + dependencies: + '@tanstack/react-router': 1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.171.13 + '@tanstack/router-utils': 1.162.2 + '@tanstack/start-client-core': 1.170.12 + '@tanstack/start-fn-stubs': 1.162.0 + '@tanstack/start-plugin-core': 1.171.17(@tanstack/react-router@1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.10(srvx@0.12.4))(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) + '@tanstack/start-server-core': 1.169.14(crossws@0.4.10(srvx@0.12.4)) + '@tanstack/start-storage-context': 1.167.15 + pathe: 2.0.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - '@rsbuild/core' + - crossws + - supports-color + - vite + - vite-plugin-solid + - webpack + '@tanstack/react-start-server@1.167.19(crossws@0.4.10(srvx@0.11.22))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/react-router': 1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -13877,6 +13917,16 @@ snapshots: transitivePeerDependencies: - crossws + '@tanstack/react-start-server@1.167.19(crossws@0.4.10(srvx@0.12.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/react-router': 1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.171.13 + '@tanstack/start-server-core': 1.169.14(crossws@0.4.10(srvx@0.12.4)) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - crossws + '@tanstack/react-start@1.168.25(crossws@0.4.10(srvx@0.11.22))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@24.12.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@tanstack/react-router': 1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -13900,6 +13950,29 @@ snapshots: - vite-plugin-solid - webpack + '@tanstack/react-start@1.168.25(crossws@0.4.10(srvx@0.12.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0))': + dependencies: + '@tanstack/react-router': 1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-client': 1.168.13(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-rsc': 0.1.24(crossws@0.4.10(srvx@0.12.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) + '@tanstack/react-start-server': 1.167.19(crossws@0.4.10(srvx@0.12.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-utils': 1.162.2 + '@tanstack/start-client-core': 1.170.12 + '@tanstack/start-plugin-core': 1.171.17(@tanstack/react-router@1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.10(srvx@0.12.4))(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) + '@tanstack/start-server-core': 1.169.14(crossws@0.4.10(srvx@0.12.4)) + pathe: 2.0.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + vite: 7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) + transitivePeerDependencies: + - '@rspack/core' + - crossws + - react-server-dom-rspack + - supports-color + - vite-plugin-solid + - webpack + '@tanstack/react-store@0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/store': 0.9.3 @@ -13952,6 +14025,23 @@ snapshots: transitivePeerDependencies: - supports-color + '@tanstack/router-plugin@1.168.18(@tanstack/react-router@1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0))': + dependencies: + '@babel/core': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.7 + '@tanstack/router-core': 1.171.13 + '@tanstack/router-generator': 1.167.17 + '@tanstack/router-utils': 1.162.2 + chokidar: 5.0.0 + unplugin: 3.0.0 + zod: 4.4.3 + optionalDependencies: + '@tanstack/react-router': 1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + vite: 7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) + transitivePeerDependencies: + - supports-color + '@tanstack/router-ssr-query-core@1.169.1(@tanstack/query-core@5.91.0)(@tanstack/router-core@1.171.13)': dependencies: '@tanstack/query-core': 5.91.0 @@ -13989,13 +14079,13 @@ snapshots: '@tanstack/router-plugin': 1.168.18(@tanstack/react-router@1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.5(@types/node@24.12.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) '@tanstack/router-utils': 1.162.2 '@tanstack/start-server-core': 1.169.14(crossws@0.4.10(srvx@0.11.22)) - exsolve: 1.0.8 + exsolve: 1.1.1 lightningcss: 1.32.0 pathe: 2.0.3 picomatch: 4.0.4 seroval: 1.5.4 source-map: 0.7.6 - srvx: 0.11.16 + srvx: 0.11.22 tinyglobby: 0.2.17 ufo: 1.6.4 vitefu: 1.1.2(vite@7.3.5(@types/node@24.12.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) @@ -14010,6 +14100,37 @@ snapshots: - vite-plugin-solid - webpack + '@tanstack/start-plugin-core@1.171.17(@tanstack/react-router@1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(crossws@0.4.10(srvx@0.12.4))(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0))': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/core': 7.29.0 + '@babel/types': 7.29.7 + '@tanstack/router-core': 1.171.13 + '@tanstack/router-generator': 1.167.17 + '@tanstack/router-plugin': 1.168.18(@tanstack/react-router@1.170.15(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) + '@tanstack/router-utils': 1.162.2 + '@tanstack/start-server-core': 1.169.14(crossws@0.4.10(srvx@0.12.4)) + exsolve: 1.1.1 + lightningcss: 1.32.0 + pathe: 2.0.3 + picomatch: 4.0.4 + seroval: 1.5.4 + source-map: 0.7.6 + srvx: 0.11.22 + tinyglobby: 0.2.17 + ufo: 1.6.4 + vitefu: 1.1.2(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) + xmlbuilder2: 4.0.3 + zod: 4.4.3 + optionalDependencies: + vite: 7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0) + transitivePeerDependencies: + - '@tanstack/react-router' + - crossws + - supports-color + - vite-plugin-solid + - webpack + '@tanstack/start-server-core@1.169.14(crossws@0.4.10(srvx@0.11.22))': dependencies: '@tanstack/history': 1.162.0 @@ -14022,6 +14143,18 @@ snapshots: transitivePeerDependencies: - crossws + '@tanstack/start-server-core@1.169.14(crossws@0.4.10(srvx@0.12.4))': + dependencies: + '@tanstack/history': 1.162.0 + '@tanstack/router-core': 1.171.13 + '@tanstack/start-client-core': 1.170.12 + '@tanstack/start-storage-context': 1.167.15 + fetchdts: 0.1.7 + h3-v2: h3@2.0.1-rc.20(crossws@0.4.10(srvx@0.12.4)) + seroval: 1.5.4 + transitivePeerDependencies: + - crossws + '@tanstack/start-storage-context@1.167.15': dependencies: '@tanstack/router-core': 1.171.13 @@ -14109,8 +14242,8 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 @@ -14974,7 +15107,7 @@ snapshots: ast-kit@3.0.0-beta.1: dependencies: - '@babel/parser': 8.0.0-rc.3 + '@babel/parser': 8.0.0-rc.6 estree-walker: 3.0.3 pathe: 2.0.3 @@ -15109,7 +15242,7 @@ snapshots: babel-dead-code-elimination@1.0.12: dependencies: '@babel/core': 7.29.0 - '@babel/parser': 7.29.2 + '@babel/parser': 7.29.7 '@babel/traverse': 7.29.0 '@babel/types': 7.29.7 transitivePeerDependencies: @@ -15254,7 +15387,7 @@ snapshots: confbox: 0.2.4 defu: 6.1.7 dotenv: 17.4.2 - exsolve: 1.0.8 + exsolve: 1.1.1 giget: 3.3.0 jiti: 2.7.0 ohash: 2.0.11 @@ -15478,6 +15611,11 @@ snapshots: optionalDependencies: srvx: 0.11.22 + crossws@0.4.10(srvx@0.12.4): + optionalDependencies: + srvx: 0.12.4 + optional: true + crossws@0.4.6(srvx@0.11.16): optionalDependencies: srvx: 0.11.16 @@ -16712,6 +16850,13 @@ snapshots: optionalDependencies: crossws: 0.4.10(srvx@0.11.22) + h3@2.0.1-rc.20(crossws@0.4.10(srvx@0.12.4)): + dependencies: + rou3: 0.8.1 + srvx: 0.11.22 + optionalDependencies: + crossws: 0.4.10(srvx@0.12.4) + h3@2.0.1-rc.26(crossws@0.4.10(srvx@0.11.22)): dependencies: rou3: 0.9.1 @@ -18062,7 +18207,7 @@ snapshots: esbuild: 0.28.0 escape-string-regexp: 5.0.0 etag: 1.8.1 - exsolve: 1.0.8 + exsolve: 1.1.1 globby: 16.2.0 gzip-size: 7.0.0 h3: 1.15.11 @@ -20312,7 +20457,7 @@ snapshots: unwasm@0.5.3: dependencies: - exsolve: 1.0.8 + exsolve: 1.1.1 knitwork: 1.3.0 magic-string: 0.30.21 mlly: 1.8.2 @@ -20539,7 +20684,7 @@ snapshots: vite-plugin-vue-tracer@1.3.0(vite@7.3.5(@types/node@24.12.0)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3)): dependencies: estree-walker: 3.0.3 - exsolve: 1.0.8 + exsolve: 1.1.1 magic-string: 0.30.21 pathe: 2.0.3 source-map-js: 1.2.1 @@ -20550,7 +20695,7 @@ snapshots: vite-plugin-vue-tracer@1.3.0(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3)): dependencies: estree-walker: 3.0.3 - exsolve: 1.0.8 + exsolve: 1.1.1 magic-string: 0.30.21 pathe: 2.0.3 source-map-js: 1.2.1 @@ -20994,7 +21139,7 @@ snapshots: '@oozcitak/dom': 2.0.2 '@oozcitak/infra': 2.0.2 '@oozcitak/util': 10.0.0 - js-yaml: 4.1.1 + js-yaml: 4.2.0 xmlchars@2.2.0: {} From 1a1d2ebe389e02057ec283ac61e7c5539a194e7c Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Fri, 7 Aug 2026 12:13:25 -0500 Subject: [PATCH 2/5] chore(tanstack-start): fix and test type definitions --- packages/tanstack-start/README.md | 8 +- packages/tanstack-start/package.json | 19 ++-- packages/tanstack-start/src/@types/api.ts | 106 +++++++++++++++++++ packages/tanstack-start/src/@types/core.ts | 1 + packages/tanstack-start/src/@types/index.ts | 103 +----------------- packages/tanstack-start/src/createAuth.ts | 5 +- packages/tanstack-start/src/index.ts | 1 + packages/tanstack-start/src/lib/api.ts | 58 +++++----- packages/tanstack-start/test/types.test-d.ts | 59 +++++++++++ packages/tanstack-start/tsconfig.json | 7 +- packages/tanstack-start/tsdown.config.ts | 1 - packages/tanstack-start/vitest.config.ts | 18 ++++ 12 files changed, 236 insertions(+), 150 deletions(-) create mode 100644 packages/tanstack-start/src/@types/api.ts create mode 100644 packages/tanstack-start/src/@types/core.ts create mode 100644 packages/tanstack-start/test/types.test-d.ts create mode 100644 packages/tanstack-start/vitest.config.ts diff --git a/packages/tanstack-start/README.md b/packages/tanstack-start/README.md index eae41ea1..bd91c992 100644 --- a/packages/tanstack-start/README.md +++ b/packages/tanstack-start/README.md @@ -1,11 +1,11 @@
-

@aura-stack/integration

+

@aura-stack/tanstack-start

**Integration authentication library for the Aura Stack ecosystem** -[![npm version](https://img.shields.io/npm/v/@aura-stack/integration.svg)](https://www.npmjs.com/package/@aura-stack/integration) -[![JSR version](https://jsr.io/badges/@aura-stack/integration)](https://jsr.io/@aura-stack/integration) +[![npm version](https://img.shields.io/npm/v/@aura-stack/tanstack-start.svg)](https://www.npmjs.com/package/@aura-stack/tanstack-start) +[![JSR version](https://jsr.io/badges/@aura-stack/tanstack-start)](https://jsr.io/@aura-stack/tanstack-start) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [Official Docs](https://aura-stack-auth.vercel.app/docs) · [Core Package Docs](https://aura-stack-auth.vercel.app/docs/packages/core) @@ -17,7 +17,7 @@ ## Installation ```bash -pnpm add @aura-stack/integration +pnpm add @aura-stack/tanstack-start ``` ## Documentation diff --git a/packages/tanstack-start/package.json b/packages/tanstack-start/package.json index 5384313b..24f2c1b6 100644 --- a/packages/tanstack-start/package.json +++ b/packages/tanstack-start/package.json @@ -1,7 +1,7 @@ { "name": "@aura-stack/tanstack-start", "version": "0.0.0", - "private": true, + "private": false, "type": "module", "description": "Tanstack Start for Aura Stack authentication library", "scripts": { @@ -18,7 +18,7 @@ "clean": "rm -rf dist src/_core src/oauth", "clean:cts": "[ -d dist ] && find dist -type f -name \"*.cts\" -delete || true", "prepublishOnly": "pnpm clean:cts && pnpm build && pnpm clean:cts", - "sync:modules": "node ../shared/scripts/modules.js" + "sync:modules": "node ../shared/scripts/modules.js --from react" }, "homepage": "https://aura-stack-auth.vercel.app", "bugs": { @@ -72,14 +72,14 @@ "require": "./dist/oauth/*.cjs" }, "./identity": { - "types": "./dist/_core/identity.d.ts", - "import": "./dist/_core/identity.js", - "require": "./dist/_core/identity.cjs" + "types": "./dist/identity.d.ts", + "import": "./dist/identity.js", + "require": "./dist/identity.cjs" }, "./identity/*": { - "types": "./dist/_core/identity/*.d.ts", - "import": "./dist/_core/identity/*.js", - "require": "./dist/_core/identity/*.cjs" + "types": "./dist/identity/*.d.ts", + "import": "./dist/identity/*.js", + "require": "./dist/identity/*.cjs" }, "./crypto": { "types": "./dist/_core/crypto.d.ts", @@ -95,7 +95,8 @@ "types": "./dist/_core/cookies.d.ts", "import": "./dist/_core/cookies.js", "require": "./dist/_core/cookies.cjs" - } + }, + "./types": "./dist/@types/index.d.ts" }, "packageManager": "pnpm@10.15.0" } diff --git a/packages/tanstack-start/src/@types/api.ts b/packages/tanstack-start/src/@types/api.ts new file mode 100644 index 00000000..2670ba01 --- /dev/null +++ b/packages/tanstack-start/src/@types/api.ts @@ -0,0 +1,106 @@ +import type { AuthInstance } from "@aura-stack/react" +import type { + LiteralUnion, + SignInAPIOptions, + BuiltInOAuthProvider, + Prettify, + SignInCredentialsAPIOptions, + SignOutAPIOptions, + UpdateSessionAPIOptions, + User, + SignUpAPIOptions, + GetProviderTokensAPIOptions, + AccessTokenAPIOptions, + RefreshUserInfoAPIOptions, + RevokeTokenAPIOptions, + DisconnectProviderAPIOptions, + ProviderConnectedAPIOptions, +} from "@aura-stack/react/types" +import type { FromShapeToObject, Identities, SchemaTypes } from "@aura-stack/react/identity" +import type { + SignInAPIReturn, + SignInCredentialsAPIReturn, + SignOutAPIReturn, + UpdateSessionAPIReturn, + SignUpAPIReturn, + GetProviderTokensAPIReturn, + AccessTokenAPIReturn, + RefreshUserInfoAPIReturn, + RevokeTokenAPIReturn, + DisconnectProviderAPIReturn, + ProviderConnectedAPIReturn, +} from "@aura-stack/react/types" + +export type TanstackStartInstance< + Identity extends Identities = Identities, + SignUpSchema extends SchemaTypes = SchemaTypes, +> = AuthInstance, SignUpSchema> + +export type TanstackStartSignInOptions = Prettify< + Omit & { providerId: LiteralUnion } +> + +export type TanstackStartSignInReturn = Prettify> + +export type TanstackStartSignInCredentialsOptions = Prettify> + +export type TanstackStartSignInCredentialsReturn = Prettify> + +export type TanstackStartSignOutOptions = Prettify> + +export type TanstackStartSignOutReturn = Prettify> + +export type TanstackStartUpdateSessionOptions = Prettify< + Omit, "headers" | "request"> +> + +/** + * @todo is this type correct? The session property should be ignored or not ? + */ +export type TanstackStartUpdateSessionReturn = Prettify< + Omit, "headers" | "toResponse" | "session"> +> + +export type TanstackStartSignUpOptions = Record> = Prettify< + Omit, "headers" | "request"> +> + +export type TanstackStartSignUpReturn = Prettify> + +export type TanstackStartGetProviderTokensOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartGetProviderTokensReturn = Prettify> + +export type TanstackStartGetAccessTokenOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartGetAccessTokenReturn = Prettify> + +export type TanstackStartRefreshUserInfoOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartRefreshUserInfoReturn = Prettify< + Omit, "headers" | "toResponse"> +> + +export type TanstackStartRevokeTokenOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartRevokeTokenReturn = Prettify> + +export type TanstackStartDisconnectProviderOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartDisconnectProviderReturn = Prettify> + +export type TanstackStartIsProviderConnectedOptions = Prettify< + Omit & { oauth: LiteralUnion } +> + +export type TanstackStartIsProviderConnectedReturn = Prettify> diff --git a/packages/tanstack-start/src/@types/core.ts b/packages/tanstack-start/src/@types/core.ts new file mode 100644 index 00000000..b3e3e144 --- /dev/null +++ b/packages/tanstack-start/src/@types/core.ts @@ -0,0 +1 @@ +export type * from "@aura-stack/react/types" diff --git a/packages/tanstack-start/src/@types/index.ts b/packages/tanstack-start/src/@types/index.ts index 97f008d3..d1e40189 100644 --- a/packages/tanstack-start/src/@types/index.ts +++ b/packages/tanstack-start/src/@types/index.ts @@ -1,101 +1,2 @@ -import type { AuthInstance } from "@aura-stack/react" -import type { - LiteralUnion, - SignInAPIOptions, - BuiltInOAuthProvider, - Prettify, - SignInCredentialsAPIOptions, - SignOutAPIOptions, - UpdateSessionAPIOptions, - User, - SignUpAPIOptions, - GetProviderTokensAPIOptions, - AccessTokenAPIOptions, - RefreshUserInfoAPIOptions, - RevokeTokenAPIOptions, - DisconnectProviderAPIOptions, - ProviderConnectedAPIOptions, -} from "@aura-stack/react/types" -import type { FromShapeToObject, Identities, SchemaTypes } from "@aura-stack/react/identity" -import type { - SignInAPIReturn, - SignInCredentialsAPIReturn, - SignOutAPIReturn, - UpdateSessionAPIReturn, - SignUpAPIReturn, - GetProviderTokensAPIReturn, - AccessTokenAPIReturn, - RefreshUserInfoAPIReturn, - RevokeTokenAPIReturn, - DisconnectProviderAPIReturn, - ProviderConnectedAPIReturn, -} from "@aura-stack/react/types" - -export type TanstackStartInstance< - Identity extends Identities = Identities, - SignUpSchema extends SchemaTypes = SchemaTypes, -> = AuthInstance, SignUpSchema> - -export type TanstackStartSignInOptions = Prettify< - Omit & { providerId: LiteralUnion } -> - -export type TanstackStartSignInReturn = Prettify> - -export type TanstackStartSignInCredentialsOptions = Prettify> - -export type TanstackStartSignInCredentialsReturn = Prettify> - -export type TanstackStartSignOutOptions = Prettify> - -export type TanstackStartSignOutReturn = Prettify> - -export type TanstackStartUpdateSessionOptions = Prettify< - Omit, "headers" | "request"> -> - -export type TanstackStartUpdateSessionReturn = Prettify< - Omit, "headers" | "toResponse" | "session"> -> - -export type TanstackStartSignUpOptions = Prettify> - -export type TanstackStartSignUpReturn = Prettify> - -export type TanstackStartGetProviderTokensOptions = Prettify< - Omit & { oauth: LiteralUnion } -> - -export type TanstackStartGetProviderTokensReturn = Prettify> - -export type TanstackStartGetAccessTokenOptions = Prettify< - Omit & { oauth: LiteralUnion } -> - -export type TanstackStartGetAccessTokenReturn = Prettify> - -export type TanstackStartRefreshUserInfoOptions = Prettify< - Omit & { oauth: LiteralUnion } -> - -export type TanstackStartRefreshUserInfoReturn = Prettify< - Omit, "headers" | "toResponse"> -> - -export type TanstackStartRevokeTokenOptions = Prettify< - Omit & { oauth: LiteralUnion } -> - -export type TanstackStartRevokeTokenReturn = Prettify> - -export type TanstackStartDisconnectProviderOptions = Prettify< - Omit & { oauth: LiteralUnion } -> - -export type TanstackStartDisconnectProviderReturn = Prettify> - -export type TanstackStartIsProviderConnectedOptions = Prettify< - Omit & { oauth: LiteralUnion } -> - -export type TanstackStartIsProviderConnectedReturn = Prettify> +export type * from "@/@types/api.ts" +export type * from "@/@types/core.ts" diff --git a/packages/tanstack-start/src/createAuth.ts b/packages/tanstack-start/src/createAuth.ts index e8dbeb7d..f1055c56 100644 --- a/packages/tanstack-start/src/createAuth.ts +++ b/packages/tanstack-start/src/createAuth.ts @@ -1,6 +1,7 @@ import { api } from "@/lib/api.ts" import { createAuth as createAuthInstance } from "@aura-stack/react/server" import type { AuthConfig } from "@aura-stack/react/types" +import type { zod } from "@aura-stack/react/identity/zod" import type { FromShapeToObject, Identities, SchemaTypes } from "@aura-stack/react/identity" /** @@ -22,7 +23,7 @@ import type { FromShapeToObject, Identities, SchemaTypes } from "@aura-stack/rea * } * }) */ -export const createAuth = ( +export const createAuth = >( config: AuthConfig ) => { const auth = createAuthInstance(config) @@ -37,7 +38,7 @@ export const createAuth = >(auth), + api: api, SignUpSchema>(auth), /** * The handlers object contains the HTTP request handlers. */ diff --git a/packages/tanstack-start/src/index.ts b/packages/tanstack-start/src/index.ts index 7405f43d..3f4f6a5b 100644 --- a/packages/tanstack-start/src/index.ts +++ b/packages/tanstack-start/src/index.ts @@ -1 +1,2 @@ export { createAuth } from "@/createAuth.ts" +export type { User, Session, AuthConfig, AuthInstance } from "@aura-stack/react/types" diff --git a/packages/tanstack-start/src/lib/api.ts b/packages/tanstack-start/src/lib/api.ts index ae2aa201..f5b99f98 100644 --- a/packages/tanstack-start/src/lib/api.ts +++ b/packages/tanstack-start/src/lib/api.ts @@ -1,3 +1,5 @@ +import { createServerFn, type OptionalFetcher } from "@tanstack/react-start" +import { getRequest, getRequestHeaders } from "@tanstack/react-start/server" import type { TanstackStartSignInCredentialsOptions, TanstackStartSignInCredentialsReturn, @@ -21,10 +23,9 @@ import type { TanstackStartDisconnectProviderReturn, TanstackStartIsProviderConnectedOptions, TanstackStartIsProviderConnectedReturn, -} from "@/@types/index.ts" +} from "@/@types/api.ts" import type { AuthInstance, User } from "@aura-stack/auth" -import { createServerFn, type OptionalFetcher } from "@tanstack/react-start" -import { getRequest, getRequestHeaders } from "@tanstack/react-start/server" +import type { InferSchema, RemoveIndexSignature, SchemaTypes, Wrap } from "@aura-stack/react/types" export const getSession = ({ api }: AuthInstance) => { return createServerFn({ @@ -94,18 +95,24 @@ export const updateSession = ({ api }: AuthInst }) } -export const signUp = ({ api }: AuthInstance) => { - return createServerFn({ method: "POST" }) - .validator((data: TanstackStartSignUpOptions) => data) - .handler>(async ({ data }) => { - const output = await api.signUp({ - ...data, - headers: getRequestHeaders(), - request: getRequest(), +export const signUp = = Record>({ + api, +}: AuthInstance) => { + return ( + createServerFn({ method: "POST" }) + // @ts-ignore + .validator((data: TanstackStartSignUpOptions) => data) + .handler>(async ({ data }) => { + const output = await api.signUp({ + ...data, + payload: data.payload as T, + headers: getRequestHeaders(), + request: getRequest(), + }) + const { headers: _h, toResponse: _t, ...spread } = output + return spread }) - const { headers: _h, toResponse: _t, ...spread } = output - return spread - }) + ) } export const getProviderTokens = ({ api }: AuthInstance) => { @@ -136,17 +143,6 @@ export const getAccessToken = ({ api }: AuthIns }) } -createServerFn({ - method: "GET", -}).handler(() => { - return { - name: "jose", - data: { - id: 1, - }, - } -}) - export const refreshUserInfo = ({ api }: AuthInstance) => { return createServerFn({ method: "POST" }) .validator((data: TanstackStartRefreshUserInfoOptions) => data) @@ -158,7 +154,7 @@ export const refreshUserInfo = ({ api }: AuthIn }) const { headers: _h, toResponse: _t, ...spread } = output return spread - }) as OptionalFetcher>> + }) as OptionalFetcher>> } export const revokeToken = ({ api }: AuthInstance) => { @@ -203,17 +199,19 @@ export const isProviderConnected = ({ api }: Au }) } -export const api = (config: AuthInstance) => { +export const api = ( + config: AuthInstance +) => { return { getSession: getSession(config), signIn: signIn(config), signInCredentials: signInCredentials(config), signOut: signOut(config), - updateSession: updateSession(config), - signUp: signUp(config), + updateSession: updateSession(config), + signUp: signUp>>>(config), getProviderTokens: getProviderTokens(config), getAccessToken: getAccessToken(config), - refreshUserInfo: refreshUserInfo(config), + refreshUserInfo: refreshUserInfo(config), revokeToken: revokeToken(config), disconnectProvider: disconnectProvider(config), isProviderConnected: isProviderConnected(config), diff --git a/packages/tanstack-start/test/types.test-d.ts b/packages/tanstack-start/test/types.test-d.ts new file mode 100644 index 00000000..ebd0a62d --- /dev/null +++ b/packages/tanstack-start/test/types.test-d.ts @@ -0,0 +1,59 @@ +import { describe, expectTypeOf } from "vitest" +import { createAuth } from "@/createAuth" +import { zod, identitySchema, type IdentityShape } from "@aura-stack/react/identity/zod" +import type { FromShapeToObject } from "@/identity" +import type { DeepPartial, Session } from "@/@types" + +describe("createAuth", () => { + describe("with custom identity", () => { + const auth = createAuth({ + oauth: [], + identity: { + schema: identitySchema.extend({ + role: zod.string(), + nickname: zod.string().optional(), + }), + }, + }) + type Identity = FromShapeToObject }> + + expectTypeOf>>().toEqualTypeOf | null>() + + expectTypeOf[0]["data"]["session"]>().toEqualTypeOf<{ + user?: DeepPartial + expires?: string | undefined + }>() + expectTypeOf>>().toEqualTypeOf<{ + success: boolean + redirect: boolean + redirectURL: string | null + }>() + + expectTypeOf>>().toEqualTypeOf<{ + success: boolean + session: Session> | null + }>() + + expectTypeOf[0]["data"]["payload"]>().toEqualTypeOf<{}>() + }) + + describe("with custom identity and sign up schema", () => { + const auth = createAuth({ + oauth: [], + signUp: { + schema: zod.object({ + nickname: zod.string(), + email: zod.email(), + password: zod.string().min(8), + }), + onCreateUser: () => null, + }, + }) + + expectTypeOf[0]["data"]["payload"]>().toEqualTypeOf<{ + nickname: string + email: string + password: string + }>() + }) +}) diff --git a/packages/tanstack-start/tsconfig.json b/packages/tanstack-start/tsconfig.json index 2aca6a65..2bd6d079 100644 --- a/packages/tanstack-start/tsconfig.json +++ b/packages/tanstack-start/tsconfig.json @@ -1,10 +1,11 @@ { - "extends": "@aura-stack/tsconfig/tsconfig.base.json", + "extends": "@aura-stack/tsconfig/tanstack.json", "compilerOptions": { "paths": { - "@/*": ["./src/*"] + "@/*": ["./src/*"], + "@test/*": ["./test/*"] } }, - "include": ["src"], + "include": ["src", "test"], "exclude": ["dist", "node_modules"] } diff --git a/packages/tanstack-start/tsdown.config.ts b/packages/tanstack-start/tsdown.config.ts index 4d93134a..87150f1b 100644 --- a/packages/tanstack-start/tsdown.config.ts +++ b/packages/tanstack-start/tsdown.config.ts @@ -9,7 +9,6 @@ export default defineConfig({ "src/identity/*.ts", "src/oauth/index.ts", "src/oauth/*.ts", - "src/_core/identity.ts", "src/_core/crypto.ts", "src/_core/shared.ts", "src/_core/cookies.ts", diff --git a/packages/tanstack-start/vitest.config.ts b/packages/tanstack-start/vitest.config.ts new file mode 100644 index 00000000..4faaced2 --- /dev/null +++ b/packages/tanstack-start/vitest.config.ts @@ -0,0 +1,18 @@ +import path from "path" +import { defineConfig } from "vitest/config" + +export default defineConfig({ + test: { + include: ["test/**/*.test.tsx", "test/**/*.test.ts"], + environment: "jsdom", + globals: true, + clearMocks: true, + restoreMocks: true, + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + "@test": path.resolve(__dirname, "./test"), + }, + }, +}) From ac1d5ee9fa147296c378463e6dd6335acab310ad Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Fri, 7 Aug 2026 15:36:47 -0500 Subject: [PATCH 3/5] test(tanstack-start): add test coverage --- packages/tanstack-start/package.json | 3 +- .../test/api/disconnectProvider.test.ts | 93 +++++++++++ .../test/api/getAccessToken.test.ts | 100 ++++++++++++ .../test/api/getProviderTokens.test.ts | 109 +++++++++++++ .../test/api/getSession.test.ts | 81 ++++++++++ .../test/api/isProviderConnected.test.ts | 114 ++++++++++++++ .../test/api/refreshUserInfo.test.ts | 101 ++++++++++++ .../test/api/revokeToken.test.ts | 92 +++++++++++ .../tanstack-start/test/api/signIn.test.ts | 137 +++++++++++++++++ .../test/api/signInCredentials.test.ts | 144 ++++++++++++++++++ .../tanstack-start/test/api/signOut.test.ts | 116 ++++++++++++++ .../tanstack-start/test/api/signUp.test.ts | 140 +++++++++++++++++ .../tanstack-start/test/api/test-utils.ts | 112 ++++++++++++++ .../test/api/updateSession.test.ts | 131 ++++++++++++++++ 14 files changed, 1472 insertions(+), 1 deletion(-) create mode 100644 packages/tanstack-start/test/api/disconnectProvider.test.ts create mode 100644 packages/tanstack-start/test/api/getAccessToken.test.ts create mode 100644 packages/tanstack-start/test/api/getProviderTokens.test.ts create mode 100644 packages/tanstack-start/test/api/getSession.test.ts create mode 100644 packages/tanstack-start/test/api/isProviderConnected.test.ts create mode 100644 packages/tanstack-start/test/api/refreshUserInfo.test.ts create mode 100644 packages/tanstack-start/test/api/revokeToken.test.ts create mode 100644 packages/tanstack-start/test/api/signIn.test.ts create mode 100644 packages/tanstack-start/test/api/signInCredentials.test.ts create mode 100644 packages/tanstack-start/test/api/signOut.test.ts create mode 100644 packages/tanstack-start/test/api/signUp.test.ts create mode 100644 packages/tanstack-start/test/api/test-utils.ts create mode 100644 packages/tanstack-start/test/api/updateSession.test.ts diff --git a/packages/tanstack-start/package.json b/packages/tanstack-start/package.json index 24f2c1b6..5647deb6 100644 --- a/packages/tanstack-start/package.json +++ b/packages/tanstack-start/package.json @@ -49,7 +49,8 @@ }, "devDependencies": { "@aura-stack/tsconfig": "workspace:*", - "@aura-stack/tsdown-config": "workspace:*" + "@aura-stack/tsdown-config": "workspace:*", + "vitest": "catalog:vitest" }, "peerDependencies": { "@tanstack/react-start": ">=1.0.0", diff --git a/packages/tanstack-start/test/api/disconnectProvider.test.ts b/packages/tanstack-start/test/api/disconnectProvider.test.ts new file mode 100644 index 00000000..4b9f261f --- /dev/null +++ b/packages/tanstack-start/test/api/disconnectProvider.test.ts @@ -0,0 +1,93 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders } from "@test/api/test-utils" +// don't change the import order. +import { disconnectProvider } from "@/lib/api" + +beforeEachSetup() + +describe("disconnectProvider", () => { + test("returns success: false when the API reports failure", async () => { + const auth = authInstance({ + disconnectProvider: vi.fn().mockResolvedValue({ + success: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const disconnectProviderFn = disconnectProvider(auth) + const handler = disconnectProviderFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "POST" }) + expect(output).toEqual({ success: false }) + }) + + test("returns success: true when the API reports success", async () => { + const auth = authInstance({ + disconnectProvider: vi.fn().mockResolvedValue({ + success: true, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const disconnectProviderFn = disconnectProvider(auth) + const handler = disconnectProviderFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "POST" }) + expect(output).toEqual({ success: true }) + }) + + test("calls disconnectProvider with oauth provider extracted from options", async () => { + const disconnectProviderAPI = vi.fn().mockResolvedValue({ + success: true, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + disconnectProvider: disconnectProviderAPI, + }) + + const disconnectProviderFn = disconnectProvider(auth) + const handler = disconnectProviderFn.__executeServer + await handler({ data: { oauth: "github" }, method: "POST" }) + + expect(disconnectProviderAPI).toHaveBeenCalledWith("github", { headers: expect.any(Headers) }) + }) + + test("calls disconnectProvider with headers from getRequestHeaders", async () => { + const disconnectProviderAPI = vi.fn().mockResolvedValue({ + success: true, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + disconnectProvider: disconnectProviderAPI, + }) + const headers = new Headers({ "x-custom-header": "value" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const disconnectProviderFn = disconnectProvider(auth) + const handler = disconnectProviderFn.__executeServer + + await handler({ data: { oauth: "github" }, method: "POST" }) + expect(disconnectProviderAPI).toHaveBeenCalledWith("github", { headers }) + }) + + test("passes additional options to the API call", async () => { + const disconnectProviderAPI = vi.fn().mockResolvedValue({ + success: true, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + disconnectProvider: disconnectProviderAPI, + }) + + const disconnectProviderFn = disconnectProvider(auth) + const handler = disconnectProviderFn.__executeServer + + await handler({ data: { oauth: "github", someOption: "value" }, method: "POST" }) + expect(disconnectProviderAPI).toHaveBeenCalledWith("github", { someOption: "value", headers: expect.any(Headers) }) + }) +}) diff --git a/packages/tanstack-start/test/api/getAccessToken.test.ts b/packages/tanstack-start/test/api/getAccessToken.test.ts new file mode 100644 index 00000000..d55222fb --- /dev/null +++ b/packages/tanstack-start/test/api/getAccessToken.test.ts @@ -0,0 +1,100 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders } from "./test-utils" +import { getAccessToken } from "@/lib/api" + +beforeEachSetup() + +describe("getAccessToken", () => { + test("returns success: false when the API reports failure", async () => { + const auth = authInstance({ + getAccessToken: vi.fn().mockResolvedValue({ + success: false, + accessToken: null, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const getAccessTokenFn = getAccessToken(auth) + const handler = getAccessTokenFn.__executeServer + const output = await handler({ data: { oauth: "github" }, method: "GET" }) + + expect(output).toEqual({ success: false, accessToken: null }) + }) + + test("returns success: true and accessToken when the API reports success", async () => { + const auth = authInstance({ + getAccessToken: vi.fn().mockResolvedValue({ + success: true, + accessToken: "xyz789", + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const getAccessTokenFn = getAccessToken(auth) + const handler = getAccessTokenFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "GET" }) + expect(output).toEqual({ + success: true, + accessToken: "xyz789", + }) + }) + + test("calls getAccessToken with oauth provider extracted from options", async () => { + const getAcessTokenAPI = vi.fn().mockResolvedValue({ + success: true, + accessToken: "xyz789", + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + getAccessToken: getAcessTokenAPI, + }) + + const getAccessTokenFn = getAccessToken(auth) + const handler = getAccessTokenFn.__executeServer + + await handler({ data: { oauth: "github" }, method: "GET" }) + expect(getAcessTokenAPI).toHaveBeenCalledWith("github", { headers: expect.any(Headers) }) + }) + + test("calls getAccessToken with headers from getRequestHeaders", async () => { + const getAcessTokenAPI = vi.fn().mockResolvedValue({ + success: true, + accessToken: "xyz789", + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + getAccessToken: getAcessTokenAPI, + }) + const headers = new Headers({ "x-custom-header": "value" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const getAccessTokenFn = getAccessToken(auth) + const handler = getAccessTokenFn.__executeServer + + await handler({ data: { oauth: "github" }, method: "GET" }) + expect(getAcessTokenAPI).toHaveBeenCalledWith("github", { headers }) + }) + + test("passes additional options to the API call", async () => { + const getAcessTokenAPI = vi.fn().mockResolvedValue({ + success: true, + accessToken: "xyz789", + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + getAccessToken: getAcessTokenAPI, + }) + + const getAccessTokenFn = getAccessToken(auth) + const handler = getAccessTokenFn.__executeServer + + await handler({ data: { oauth: "github", someOption: "value" }, method: "GET" }) + expect(getAcessTokenAPI).toHaveBeenCalledWith("github", { someOption: "value", headers: expect.any(Headers) }) + }) +}) diff --git a/packages/tanstack-start/test/api/getProviderTokens.test.ts b/packages/tanstack-start/test/api/getProviderTokens.test.ts new file mode 100644 index 00000000..77b6d30d --- /dev/null +++ b/packages/tanstack-start/test/api/getProviderTokens.test.ts @@ -0,0 +1,109 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders } from "./test-utils" +import { getProviderTokens } from "@/lib/api" + +beforeEachSetup() + +describe("getProviderTokens", () => { + test("returns success: false when the API reports failure", async () => { + const auth = authInstance({ + getProviderTokens: vi.fn().mockResolvedValue({ + success: false, + tokens: null, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const getProviderTokensFn = getProviderTokens(auth) + const handler = getProviderTokensFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "GET" }) + expect(output).toEqual({ success: false, tokens: null }) + }) + + test("returns success: true and tokens when the API reports success", async () => { + const auth = authInstance({ + getProviderTokens: vi.fn().mockResolvedValue({ + success: true, + tokens: { accessToken: "abc123", refreshToken: "def456" }, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const getProviderTokensFn = getProviderTokens(auth) + const handler = getProviderTokensFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "GET" }) + expect(output).toEqual({ + success: true, + tokens: { accessToken: "abc123", refreshToken: "def456" }, + }) + }) + + test("calls getProviderTokens with oauth provider extracted from options", async () => { + const getProviderTokensAPI = vi.fn().mockResolvedValue({ + success: true, + tokens: { + accessToken: "abc123", + refreshToken: "def456", + }, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + getProviderTokens: getProviderTokensAPI, + }) + + const getProviderTokensFn = getProviderTokens(auth) + const handler = getProviderTokensFn.__executeServer + + await handler({ data: { oauth: "github" }, method: "GET" }) + expect(getProviderTokensAPI).toHaveBeenCalledWith("github", { headers: expect.any(Headers) }) + }) + + test("calls getProviderTokens with headers from getRequestHeaders", async () => { + const getProviderTokensAPI = vi.fn().mockResolvedValue({ + success: true, + tokens: { + accessToken: "abc123", + refreshToken: "def456", + }, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + getProviderTokens: getProviderTokensAPI, + }) + const headers = new Headers({ "x-custom-header": "value" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const getProviderTokensFn = getProviderTokens(auth) + const handler = getProviderTokensFn.__executeServer + + await handler({ data: { oauth: "github" }, method: "GET" }) + expect(getProviderTokensAPI).toHaveBeenCalledWith("github", { headers }) + }) + + test("passes additional options to the API call", async () => { + const getProviderTokensAPI = vi.fn().mockResolvedValue({ + success: true, + tokens: { + accessToken: "abc123", + refreshToken: "def456", + }, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + getProviderTokens: getProviderTokensAPI, + }) + + const getProviderTokensFn = getProviderTokens(auth) + const handler = getProviderTokensFn.__executeServer + + await handler({ data: { oauth: "github", someOption: "value" }, method: "GET" }) + expect(getProviderTokensAPI).toHaveBeenCalledWith("github", { headers: expect.any(Headers), someOption: "value" }) + }) +}) diff --git a/packages/tanstack-start/test/api/getSession.test.ts b/packages/tanstack-start/test/api/getSession.test.ts new file mode 100644 index 00000000..f767b552 --- /dev/null +++ b/packages/tanstack-start/test/api/getSession.test.ts @@ -0,0 +1,81 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders } from "./test-utils" +import { getSession } from "@/lib/api" + +beforeEachSetup() + +describe("getSession", () => { + test("returns null when the API reports success: false", async () => { + const auth = authInstance({ + getSession: vi.fn().mockResolvedValue({ + success: false, + session: null, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const getSessionFn = getSession(auth) + const handler = getSessionFn.__executeServer + + const output = await handler({ method: "GET", data: undefined }) + expect(output).toBeNull() + }) + + test("returns the session object when the API reports success: true", async () => { + const session = { user: { sub: "u1", name: "Alice" }, expires: "2099-01-01" } + const auth = authInstance({ + getSession: vi.fn().mockResolvedValue({ + success: true, + session, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const getSessionFn = getSession(auth) + const handler = getSessionFn.__executeServer + + const output = await handler({ method: "GET", data: undefined }) + expect(output).toEqual(session) + }) + + test("calls getSession with headers from getRequestHeaders", async () => { + const apiGetSession = vi.fn().mockResolvedValue({ + success: true, + session: null, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ getSession: apiGetSession }) + const headers = new Headers({ "x-test": "val" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const getSessionFn = getSession(auth) + const handler = getSessionFn.__executeServer + + await handler({ method: "GET", data: undefined }) + expect(apiGetSession).toHaveBeenCalledWith({ headers: headers }) + }) + + test("removes headers and toResponse from the response", async () => { + const session = { user: { sub: "u1", name: "Alice" }, expires: "2099-01-01" } + const responseHeaders = new Headers({ "x-custom": "value" }) + const auth = authInstance({ + getSession: vi.fn().mockResolvedValue({ + success: true, + session, + headers: responseHeaders, + toResponse: vi.fn(), + }), + }) + + const getSessionFn = getSession(auth) + const handler = getSessionFn.__executeServer + const output = await handler({ method: "GET", data: undefined }) + + expect(output).toEqual(session) + expect(output).not.toHaveProperty("headers") + expect(output).not.toHaveProperty("toResponse") + }) +}) diff --git a/packages/tanstack-start/test/api/isProviderConnected.test.ts b/packages/tanstack-start/test/api/isProviderConnected.test.ts new file mode 100644 index 00000000..c756c7a8 --- /dev/null +++ b/packages/tanstack-start/test/api/isProviderConnected.test.ts @@ -0,0 +1,114 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders } from "@test/api/test-utils" +import { isProviderConnected } from "@/lib/api" + +beforeEachSetup() + +describe("isProviderConnected", () => { + test("returns success: false and connected: false when the API reports failure", async () => { + const auth = authInstance({ + isProviderConnected: vi.fn().mockResolvedValue({ + success: false, + connected: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const isProviderConnectedFn = isProviderConnected(auth) + const handler = isProviderConnectedFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "GET" }) + expect(output).toEqual({ success: false, connected: false }) + }) + + test("returns success: true and connected: true when the API reports connected", async () => { + const auth = authInstance({ + isProviderConnected: vi.fn().mockResolvedValue({ + success: true, + connected: true, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const isProviderConnectedFn = isProviderConnected(auth) + const handler = isProviderConnectedFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "GET" }) + expect(output).toEqual({ success: true, connected: true }) + }) + + test("returns success: true and connected: false when the API reports not connected", async () => { + const auth = authInstance({ + isProviderConnected: vi.fn().mockResolvedValue({ + success: true, + connected: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const isProviderConnectedFn = isProviderConnected(auth) + const handler = isProviderConnectedFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "GET" }) + expect(output).toEqual({ success: true, connected: false }) + }) + + test("calls isProviderConnected with oauth provider extracted from options", async () => { + const isProviderConnectedAPI = vi.fn().mockResolvedValue({ + success: true, + connected: true, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + isProviderConnected: isProviderConnectedAPI, + }) + + const isProviderConnectedFn = isProviderConnected(auth) + const handler = isProviderConnectedFn.__executeServer + + await handler({ data: { oauth: "github" }, method: "GET" }) + expect(isProviderConnectedAPI).toHaveBeenCalledWith("github", { headers: expect.any(Headers) }) + }) + + test("calls isProviderConnected with headers from getRequestHeaders", async () => { + const isProviderConnectedAPI = vi.fn().mockResolvedValue({ + success: true, + connected: true, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + isProviderConnected: isProviderConnectedAPI, + }) + const headers = new Headers({ "x-custom-header": "value" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const isProviderConnectedFn = isProviderConnected(auth) + const handler = isProviderConnectedFn.__executeServer + + await handler({ data: { oauth: "github" }, method: "GET" }) + expect(isProviderConnectedAPI).toHaveBeenCalledWith("github", { headers }) + }) + + test("passes additional options to the API call", async () => { + const isProviderConnectedAPI = vi.fn().mockResolvedValue({ + success: true, + connected: true, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + isProviderConnected: isProviderConnectedAPI, + }) + + const isProviderConnectedFn = isProviderConnected(auth) + const handler = isProviderConnectedFn.__executeServer + + await handler({ data: { oauth: "github", someOption: "value" }, method: "GET" }) + expect(isProviderConnectedAPI).toHaveBeenCalledWith("github", { headers: expect.any(Headers), someOption: "value" }) + }) +}) diff --git a/packages/tanstack-start/test/api/refreshUserInfo.test.ts b/packages/tanstack-start/test/api/refreshUserInfo.test.ts new file mode 100644 index 00000000..ab93be8e --- /dev/null +++ b/packages/tanstack-start/test/api/refreshUserInfo.test.ts @@ -0,0 +1,101 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders } from "./test-utils" +import { refreshUserInfo } from "@/lib/api" + +beforeEachSetup() + +describe("refreshUserInfo", () => { + test("returns success: false when the API reports failure", async () => { + const auth = authInstance({ + refreshUserInfo: vi.fn().mockResolvedValue({ + success: false, + session: null, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const refreshUserInfoFn = refreshUserInfo(auth) + const handler = refreshUserInfoFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "POST" }) + expect(output).toEqual({ success: false, session: null }) + }) + + test("returns success: true and session when the API reports success", async () => { + const session = { user: { sub: "u1", name: "Alice Updated" }, expires: "2099-01-01" } + const auth = authInstance({ + refreshUserInfo: vi.fn().mockResolvedValue({ + success: true, + session, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const refreshUserInfoFn = refreshUserInfo(auth) + const handler = refreshUserInfoFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "POST" }) + expect(output).toEqual({ + success: true, + session, + }) + }) + + test("calls refreshUserInfo with oauth provider extracted from options", async () => { + const refreshUserInfoAPI = vi.fn().mockResolvedValue({ + success: true, + session: { user: { sub: "u1", name: "Alice" }, expires: "2099-01-01" }, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + refreshUserInfo: refreshUserInfoAPI, + }) + + const refreshUserInfoFn = refreshUserInfo(auth) + const handler = refreshUserInfoFn.__executeServer + + await handler({ data: { oauth: "github" }, method: "POST" }) + expect(refreshUserInfoAPI).toHaveBeenCalledWith("github", { headers: expect.any(Headers) }) + }) + + test("calls refreshUserInfo with headers from getRequestHeaders", async () => { + const refreshUserInfoAPI = vi.fn().mockResolvedValue({ + success: true, + session: { user: { sub: "u1", name: "Alice" }, expires: "2099-01-01" }, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + refreshUserInfo: refreshUserInfoAPI, + }) + const headers = new Headers({ "x-custom-header": "value" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const refreshUserInfoFn = refreshUserInfo(auth) + const handler = refreshUserInfoFn.__executeServer + + await handler({ data: { oauth: "github" }, method: "POST" }) + expect(refreshUserInfoAPI).toHaveBeenCalledWith("github", { headers }) + }) + + test("passes additional options to the API call", async () => { + const refreshUserInfoAPI = vi.fn().mockResolvedValue({ + success: true, + session: { user: { sub: "u1", name: "Alice" }, expires: "2099-01-01" }, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + refreshUserInfo: refreshUserInfoAPI, + }) + + const refreshUserInfoFn = refreshUserInfo(auth) + const handler = refreshUserInfoFn.__executeServer + + await handler({ data: { oauth: "github", someOption: "value" }, method: "POST" }) + expect(refreshUserInfoAPI).toHaveBeenCalledWith("github", { headers: expect.any(Headers), someOption: "value" }) + }) +}) diff --git a/packages/tanstack-start/test/api/revokeToken.test.ts b/packages/tanstack-start/test/api/revokeToken.test.ts new file mode 100644 index 00000000..c0c92bfa --- /dev/null +++ b/packages/tanstack-start/test/api/revokeToken.test.ts @@ -0,0 +1,92 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders } from "./test-utils" +import { revokeToken } from "@/lib/api" + +beforeEachSetup() + +describe("revokeToken", () => { + test("returns success: false when the API reports failure", async () => { + const auth = authInstance({ + revokeToken: vi.fn().mockResolvedValue({ + success: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const revokeTokenFn = revokeToken(auth) + const handler = revokeTokenFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "POST" }) + expect(output).toEqual({ success: false }) + }) + + test("returns success: true when the API reports success", async () => { + const auth = authInstance({ + revokeToken: vi.fn().mockResolvedValue({ + success: true, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const revokeTokenFn = revokeToken(auth) + const handler = revokeTokenFn.__executeServer + + const output = await handler({ data: { oauth: "github" }, method: "POST" }) + expect(output).toEqual({ success: true }) + }) + + test("calls revokeToken with oauth provider extracted from options", async () => { + const revokeTokenAPI = vi.fn().mockResolvedValue({ + success: true, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + revokeToken: revokeTokenAPI, + }) + + const revokeTokenFn = revokeToken(auth) + const handler = revokeTokenFn.__executeServer + + await handler({ data: { oauth: "github" }, method: "POST" }) + expect(revokeTokenAPI).toHaveBeenCalledWith("github", { headers: expect.any(Headers) }) + }) + + test("calls revokeToken with headers from getRequestHeaders", async () => { + const revokeTokenAPI = vi.fn().mockResolvedValue({ + success: true, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + revokeToken: revokeTokenAPI, + }) + const headers = new Headers({ "x-custom-header": "value" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const revokeTokenFn = revokeToken(auth) + const handler = revokeTokenFn.__executeServer + + await handler({ data: { oauth: "github" }, method: "POST" }) + expect(revokeTokenAPI).toHaveBeenCalledWith("github", { headers }) + }) + + test("passes additional options to the API call", async () => { + const revokeTokenAPI = vi.fn().mockResolvedValue({ + success: true, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ + revokeToken: revokeTokenAPI, + }) + + const revokeTokenFn = revokeToken(auth) + const handler = revokeTokenFn.__executeServer + + await handler({ data: { oauth: "github", someOption: "value" }, method: "POST" }) + expect(revokeTokenAPI).toHaveBeenCalledWith("github", { headers: expect.any(Headers), someOption: "value" }) + }) +}) diff --git a/packages/tanstack-start/test/api/signIn.test.ts b/packages/tanstack-start/test/api/signIn.test.ts new file mode 100644 index 00000000..b6d94f2a --- /dev/null +++ b/packages/tanstack-start/test/api/signIn.test.ts @@ -0,0 +1,137 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders, mockGetRequest } from "./test-utils" +import { signIn } from "@/lib/api" + +beforeEachSetup() + +describe("signIn", () => { + test("returns the API data when redirect option is false", async () => { + const apiData = { success: true, signInURL: "https://oauth.example.com", redirect: false } + const auth = authInstance({ + signIn: vi.fn().mockResolvedValue({ + ...apiData, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const signInFn = signIn(auth) + const handler = signInFn.__executeServer + + const output = await handler({ data: { providerId: "github", redirect: false }, method: "POST" }) + expect(output).toEqual({ success: true, signInURL: "https://oauth.example.com", redirect: false }) + }) + + test("includes redirect: true when redirect option is not provided", async () => { + const apiData = { success: true, signInURL: "https://oauth.example.com", redirect: true } + const auth = authInstance({ + signIn: vi.fn().mockResolvedValue({ + ...apiData, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const signInFn = signIn(auth) + const handler = signInFn.__executeServer + + const output = await handler({ data: { providerId: "github" }, method: "POST" }) + expect(output).toEqual({ success: true, signInURL: "https://oauth.example.com", redirect: true }) + }) + + test("returns success: false when sign-in fails", async () => { + const auth = authInstance({ + signIn: vi.fn().mockResolvedValue({ + success: false, + signInURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const signInFn = signIn(auth) + const handler = signInFn.__executeServer + + const output = await handler({ data: { providerId: "github" }, method: "POST" }) + expect(output).toEqual({ success: false, signInURL: null, redirect: false }) + }) + + test("calls signIn with providerId extracted from options", async () => { + const signInAPI = vi.fn().mockResolvedValue({ + success: false, + signInURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ signIn: signInAPI }) + + const signInFn = signIn(auth) + const handler = signInFn.__executeServer + + await handler({ data: { providerId: "github", redirectTo: "/home" }, method: "POST" }) + expect(signInAPI).toHaveBeenCalledWith("github", { + redirectTo: "/home", + headers: expect.any(Headers), + request: expect.any(Request), + }) + }) + + test("calls signIn with headers from getRequestHeaders", async () => { + const signInAPI = vi.fn().mockResolvedValue({ + success: false, + signInURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ signIn: signInAPI }) + const headers = new Headers({ "x-custom": "value" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const signInFn = signIn(auth) + const handler = signInFn.__executeServer + + await handler({ data: { providerId: "github" }, method: "POST" }) + expect(signInAPI).toHaveBeenCalledWith("github", { headers: headers, request: expect.any(Request) }) + }) + + test("calls signIn with request from getRequest", async () => { + const signInAPI = vi.fn().mockResolvedValue({ + success: false, + signInURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ signIn: signInAPI }) + const request = new Request("http://localhost:3000") + mockGetRequest.mockReturnValue(request) + + const signInFn = signIn(auth) + const handler = signInFn.__executeServer + await handler({ data: { providerId: "github" }, method: "POST" }) + + expect(signInAPI).toHaveBeenCalledWith("github", { request: request, headers: expect.any(Headers) }) + }) + + test("removes headers and toResponse from the response", async () => { + const responseHeaders = new Headers({ "x-custom": "value" }) + const auth = authInstance({ + signIn: vi.fn().mockResolvedValue({ + success: true, + signInURL: "https://oauth.example.com", + redirect: false, + headers: responseHeaders, + toResponse: vi.fn(), + }), + }) + + const signInFn = signIn(auth) + const handler = signInFn.__executeServer + + const output = await handler({ data: { providerId: "github", redirect: false }, method: "POST" }) + expect(output).toEqual({ success: true, signInURL: "https://oauth.example.com", redirect: false }) + }) +}) diff --git a/packages/tanstack-start/test/api/signInCredentials.test.ts b/packages/tanstack-start/test/api/signInCredentials.test.ts new file mode 100644 index 00000000..5ece416a --- /dev/null +++ b/packages/tanstack-start/test/api/signInCredentials.test.ts @@ -0,0 +1,144 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders, mockGetRequest } from "./test-utils" +import { signInCredentials } from "@/lib/api" + +beforeEachSetup() + +describe("signInCredentials", () => { + const payload = { username: "alice", password: "secret" } + + test("returns API data when redirect option is false", async () => { + const apiData = { + success: true, + redirectURL: "/dashboard", + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + } + const auth = authInstance({ signInCredentials: vi.fn().mockResolvedValue(apiData) }) + + const signInCredentialsFn = signInCredentials(auth) + const handler = signInCredentialsFn.__executeServer + const output = await handler({ data: { payload, redirect: false }, method: "POST" }) + + expect(output).toEqual({ success: true, redirectURL: "/dashboard", redirect: false }) + }) + + test("includes redirect: true when redirect option is not provided", async () => { + const apiData = { + success: true, + redirectURL: "/dashboard", + redirect: true, + headers: new Headers(), + toResponse: vi.fn(), + } + const auth = authInstance({ signInCredentials: vi.fn().mockResolvedValue(apiData) }) + + const signInCredentialsFn = signInCredentials(auth) + const handler = signInCredentialsFn.__executeServer + + const output = await handler({ data: { payload }, method: "POST" }) + expect(output).toEqual({ success: true, redirectURL: "/dashboard", redirect: true }) + }) + + test("returns success: false when sign-in fails", async () => { + const auth = authInstance({ + signInCredentials: vi.fn().mockResolvedValue({ + success: false, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const signInCredentialsFn = signInCredentials(auth) + const handler = signInCredentialsFn.__executeServer + + const output = await handler({ data: { payload }, method: "POST" }) + expect(output).toEqual({ success: false, redirectURL: null, redirect: false }) + }) + + test("calls signInCredentials with payload and options", async () => { + const signInCredentialsAPI = vi.fn().mockResolvedValue({ + success: false, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ signInCredentials: signInCredentialsAPI }) + + const signInCredentialsFn = signInCredentials(auth) + const handler = signInCredentialsFn.__executeServer + await handler({ data: { payload, redirectTo: "/dashboard" }, method: "POST" }) + + expect(signInCredentialsAPI).toHaveBeenCalledWith({ + payload, + redirectTo: "/dashboard", + request: expect.any(Request), + headers: expect.any(Headers), + }) + }) + + test("calls signInCredentials with headers from getRequestHeaders", async () => { + const signInCredentialsAPI = vi.fn().mockResolvedValue({ + success: false, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ signInCredentials: signInCredentialsAPI }) + const headers = new Headers({ "x-custom": "value" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const signInCredentialsFn = signInCredentials(auth) + const handler = signInCredentialsFn.__executeServer + await handler({ data: { payload }, method: "POST" }) + + expect(signInCredentialsAPI).toHaveBeenCalledWith({ headers: headers, request: expect.any(Request), payload }) + }) + + test("calls signInCredentials with request from getRequest", async () => { + const signInCredentialsAPI = vi.fn().mockResolvedValue({ + success: false, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ signInCredentials: signInCredentialsAPI }) + const request = new Request("http://localhost:3000") + mockGetRequest.mockReturnValue(request) + + const signInCredentialsFn = signInCredentials(auth) + const handler = signInCredentialsFn.__executeServer + await handler({ data: { payload }, method: "POST" }) + + expect(signInCredentialsAPI).toHaveBeenCalledWith({ + request: request, + headers: expect.any(Headers), + payload, + }) + }) + + test("removes headers and toResponse from the response", async () => { + const responseHeaders = new Headers({ "x-custom": "value" }) + const auth = authInstance({ + signInCredentials: vi.fn().mockResolvedValue({ + success: true, + redirectURL: "/dashboard", + redirect: false, + headers: responseHeaders, + toResponse: vi.fn(), + }), + }) + + const signInCredentialsFn = signInCredentials(auth) + const handler = signInCredentialsFn.__executeServer + + const output = await handler({ data: { payload, redirect: false }, method: "POST" }) + expect(output).toEqual({ success: true, redirectURL: "/dashboard", redirect: false }) + }) +}) diff --git a/packages/tanstack-start/test/api/signOut.test.ts b/packages/tanstack-start/test/api/signOut.test.ts new file mode 100644 index 00000000..ccf510bc --- /dev/null +++ b/packages/tanstack-start/test/api/signOut.test.ts @@ -0,0 +1,116 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders } from "./test-utils" +import { signOut } from "@/lib/api" + +beforeEachSetup() + +describe("signOut", () => { + test("returns API data when no redirectURL is in the response", async () => { + const auth = authInstance({ + signOut: vi.fn().mockResolvedValue({ + success: true, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const signOutFn = signOut(auth) + const handler = signOutFn.__executeServer + + const output = await handler({ data: {}, method: "POST" }) + expect(output).toEqual({ success: true, redirectURL: null, redirect: false }) + }) + + test("returns redirectURL when sign-out succeeds and URL is returned", async () => { + const auth = authInstance({ + signOut: vi.fn().mockResolvedValue({ + success: true, + redirectURL: "/goodbye", + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const signOutFn = signOut(auth) + const handler = signOutFn.__executeServer + + const output = await handler({ data: {}, method: "POST" }) + expect(output).toEqual({ success: true, redirectURL: "/goodbye", redirect: false }) + }) + + test("returns success: false when sign-out fails", async () => { + const auth = authInstance({ + signOut: vi.fn().mockResolvedValue({ + success: false, + redirectURL: "/goodbye", + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const signOutFn = signOut(auth) + const handler = signOutFn.__executeServer + + const output = await handler({ data: {}, method: "POST" }) + expect(output).toEqual({ success: false, redirectURL: "/goodbye", redirect: false }) + }) + + test("calls signOut with options", async () => { + const signOutAPI = vi.fn().mockResolvedValue({ + success: true, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ signOut: signOutAPI }) + + const signOutFn = signOut(auth) + const handler = signOutFn.__executeServer + + await handler({ data: { redirectTo: "/goodbye" }, method: "POST" }) + expect(signOutAPI).toHaveBeenCalledWith({ redirectTo: "/goodbye", headers: expect.any(Headers) }) + }) + + test("calls signOut with headers from getRequestHeaders", async () => { + const signOutAPI = vi.fn().mockResolvedValue({ + success: true, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ signOut: signOutAPI }) + const headers = new Headers({ "x-custom": "value" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const signOutFn = signOut(auth) + const handler = signOutFn.__executeServer + + await handler({ data: {}, method: "POST" }) + expect(signOutAPI).toHaveBeenCalledWith({ headers: headers }) + }) + + test("removes headers and toResponse from the response", async () => { + const responseHeaders = new Headers({ "x-custom": "value" }) + const auth = authInstance({ + signOut: vi.fn().mockResolvedValue({ + success: true, + redirectURL: null, + redirect: false, + headers: responseHeaders, + toResponse: vi.fn(), + }), + }) + + const signOutFn = signOut(auth) + const handler = signOutFn.__executeServer + + const output = await handler({ data: {}, method: "POST" }) + expect(output).toEqual({ success: true, redirectURL: null, redirect: false }) + }) +}) diff --git a/packages/tanstack-start/test/api/signUp.test.ts b/packages/tanstack-start/test/api/signUp.test.ts new file mode 100644 index 00000000..11a3cbcd --- /dev/null +++ b/packages/tanstack-start/test/api/signUp.test.ts @@ -0,0 +1,140 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders, mockGetRequest } from "./test-utils" +import { signUp } from "@/lib/api" + +beforeEachSetup() + +describe("signUp", () => { + const payload = { email: "alice@example.com", password: "secret" } + + test("returns API data when redirect option is false", async () => { + const apiData = { + success: true, + redirectURL: "/dashboard", + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + } + const auth = authInstance({ signUp: vi.fn().mockResolvedValue(apiData) }) + + const signUpFn = signUp(auth) + const handler = signUpFn.__executeServer + + const output = await handler({ data: { payload, redirect: false }, method: "POST" }) + expect(output).toEqual({ success: true, redirectURL: "/dashboard", redirect: false }) + }) + + test("includes redirect: true when redirect option is not provided", async () => { + const apiData = { + success: true, + redirectURL: "/dashboard", + redirect: true, + headers: new Headers(), + toResponse: vi.fn(), + } + const auth = authInstance({ signUp: vi.fn().mockResolvedValue(apiData) }) + + const signUpFn = signUp(auth) + const handler = signUpFn.__executeServer + + const output = await handler({ data: { payload }, method: "POST" }) + expect(output).toEqual({ success: true, redirectURL: "/dashboard", redirect: true }) + }) + + test("returns success: false when sign-up fails", async () => { + const auth = authInstance({ + signUp: vi.fn().mockResolvedValue({ + success: false, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const signUpFn = signUp(auth) + const handler = signUpFn.__executeServer + + const output = await handler({ data: { payload }, method: "POST" }) + expect(output).toEqual({ success: false, redirectURL: null, redirect: false }) + }) + + test("calls signUp with payload and options", async () => { + const signUpAPI = vi.fn().mockResolvedValue({ + success: false, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ signUp: signUpAPI }) + + const signUpFn = signUp(auth) + const handler = signUpFn.__executeServer + + await handler({ data: { payload, redirectTo: "/dashboard" }, method: "POST" }) + expect(signUpAPI).toHaveBeenCalledWith({ + payload, + redirectTo: "/dashboard", + headers: expect.any(Headers), + request: expect.any(Request), + }) + }) + + test("calls signUp with headers from getRequestHeaders", async () => { + const signUpAPI = vi.fn().mockResolvedValue({ + success: false, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ signUp: signUpAPI }) + const headers = new Headers({ "x-custom": "value" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const signUpFn = signUp(auth) + const handler = signUpFn.__executeServer + + await handler({ data: { payload }, method: "POST" }) + expect(signUpAPI).toHaveBeenCalledWith({ headers, request: expect.any(Request), payload }) + }) + + test("calls signUp with request from getRequest", async () => { + const signUpAPI = vi.fn().mockResolvedValue({ + success: false, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ signUp: signUpAPI }) + const request = new Request("http://localhost:3000") + mockGetRequest.mockReturnValue(request) + + const signUpFn = signUp(auth) + const handler = signUpFn.__executeServer + + await handler({ data: { payload }, method: "POST" }) + expect(signUpAPI).toHaveBeenCalledWith({ request: request, headers: expect.any(Headers), payload }) + }) + + test("removes headers and toResponse from the response", async () => { + const responseHeaders = new Headers({ "x-custom": "value" }) + const auth = authInstance({ + signUp: vi.fn().mockResolvedValue({ + success: true, + redirectURL: "/dashboard", + redirect: false, + headers: responseHeaders, + toResponse: vi.fn(), + }), + }) + + const signUpFn = signUp(auth) + const handler = signUpFn.__executeServer + + const output = await handler({ data: { payload, redirect: false }, method: "POST" }) + expect(output).toEqual({ success: true, redirectURL: "/dashboard", redirect: false }) + }) +}) diff --git a/packages/tanstack-start/test/api/test-utils.ts b/packages/tanstack-start/test/api/test-utils.ts new file mode 100644 index 00000000..d8dfa004 --- /dev/null +++ b/packages/tanstack-start/test/api/test-utils.ts @@ -0,0 +1,112 @@ +import { beforeEach, vi } from "vitest" +import type { AuthInstance } from "@aura-stack/auth" + +const mocks = vi.hoisted(() => ({ + mockGetRequest: vi.fn(), + mockGetRequestHeaders: vi.fn(), +})) + +// @ts-ignore +export const mockGetRequest = mocks.mockGetRequest +// @ts-ignore +export const mockGetRequestHeaders = mocks.mockGetRequestHeaders + +vi.mock("@tanstack/react-start", () => { + const createServerFn = () => { + const builder = { + validator: () => builder, + handler: (handler: (...args: any[]) => any) => { + const serverFn = Object.assign(async (...args: any[]) => handler(...args), { + __executeServer: async (...args: any[]) => handler(...args), + }) + return serverFn + }, + } + + return builder + } + + return { createServerFn } +}) + +vi.mock("@tanstack/react-start/server", () => ({ + getRequestHeaders: () => mocks.mockGetRequestHeaders(), + getRequest: () => mocks.mockGetRequest(), +})) + +export const authInstance = (apiOverrides: Partial = {}): AuthInstance => { + return { + api: { + getSession: vi.fn().mockResolvedValue({ success: false, session: null, headers: new Headers(), toResponse: vi.fn() }), + signIn: vi.fn().mockResolvedValue({ success: false, signInURL: null, headers: new Headers(), toResponse: vi.fn() }), + signInCredentials: vi.fn().mockResolvedValue({ + success: false, + redirectURL: null, + headers: new Headers(), + toResponse: vi.fn(), + }), + updateSession: vi.fn().mockResolvedValue({ + success: false, + session: null, + redirectURL: null, + headers: new Headers(), + toResponse: vi.fn(), + }), + signOut: vi.fn().mockResolvedValue({ + success: false, + redirectURL: null, + headers: new Headers(), + toResponse: vi.fn(), + }), + signUp: vi.fn().mockResolvedValue({ + success: false, + redirectURL: null, + headers: new Headers(), + toResponse: vi.fn(), + }), + getProviderTokens: vi.fn().mockResolvedValue({ + success: false, + tokens: null, + headers: new Headers(), + toResponse: vi.fn(), + }), + getAccessToken: vi.fn().mockResolvedValue({ + success: false, + accessToken: null, + headers: new Headers(), + toResponse: vi.fn(), + }), + refreshUserInfo: vi.fn().mockResolvedValue({ + success: false, + session: null, + headers: new Headers(), + toResponse: vi.fn(), + }), + revokeToken: vi.fn().mockResolvedValue({ + success: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + disconnectProvider: vi.fn().mockResolvedValue({ + success: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + isProviderConnected: vi.fn().mockResolvedValue({ + success: false, + connected: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + ...apiOverrides, + }, + } as unknown as AuthInstance +} + +export const beforeEachSetup = () => { + beforeEach(() => { + vi.clearAllMocks() + mockGetRequestHeaders.mockReturnValue(new Headers()) + mockGetRequest.mockReturnValue(new Request("http://localhost")) + }) +} diff --git a/packages/tanstack-start/test/api/updateSession.test.ts b/packages/tanstack-start/test/api/updateSession.test.ts new file mode 100644 index 00000000..3c60b72b --- /dev/null +++ b/packages/tanstack-start/test/api/updateSession.test.ts @@ -0,0 +1,131 @@ +import { describe, expect, test, vi } from "vitest" +import { authInstance, beforeEachSetup, mockGetRequestHeaders } from "./test-utils" +import { updateSession } from "@/lib/api" + +beforeEachSetup() + +describe("updateSession", () => { + test("returns updated session data when no redirectTo is given", async () => { + const session = { user: { sub: "u1", name: "Updated" }, expires: "2099-01-01" } + const auth = authInstance({ + updateSession: vi.fn().mockResolvedValue({ + success: true, + session, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const updateSessionFn = updateSession(auth) + const handler = updateSessionFn.__executeServer + + const output = await handler({ data: { session: { user: { name: "Updated" } } }, method: "POST" }) + expect(output).toEqual({ success: true, session, redirect: false, redirectURL: null }) + }) + + test("returns redirectURL when redirectTo is set and update succeeds", async () => { + const auth = authInstance({ + updateSession: vi.fn().mockResolvedValue({ + success: true, + session: { user: { name: "Bob" } }, + redirectURL: "/profile", + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const updateSessionFn = updateSession(auth) + const handler = updateSessionFn.__executeServer + + const output = await handler({ + data: { session: { user: { name: "Alice" } }, redirectTo: "/profile" }, + method: "POST", + }) + expect(output).toEqual({ success: true, redirectURL: "/profile", redirect: false, session: { user: { name: "Bob" } } }) + }) + + test("returns success: false when update fails", async () => { + const auth = authInstance({ + updateSession: vi.fn().mockResolvedValue({ + success: false, + session: null, + redirectURL: "/profile", + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }), + }) + + const updateSessionFn = updateSession(auth) + const handler = updateSessionFn.__executeServer + + const output = await handler({ data: { session: { user: { name: "Bob" } }, redirectTo: "/profile" }, method: "POST" }) + expect(output).toEqual({ success: false, session: null, redirectURL: "/profile", redirect: false }) + }) + + test("calls updateSession with session and options", async () => { + const updateSessionAPI = vi.fn().mockResolvedValue({ + success: true, + session: {}, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ updateSession: updateSessionAPI }) + + const updateSessionFn = updateSession(auth) + const handler = updateSessionFn.__executeServer + const payload = { user: { name: "Alice" } } + + await handler({ data: { session: payload, redirectTo: "/profile" }, method: "POST" }) + expect(updateSessionAPI).toHaveBeenCalledWith({ + headers: expect.any(Headers), + session: payload, + redirectTo: "/profile", + }) + }) + + test("calls updateSession with headers from getRequestHeaders", async () => { + const updateSessionAPI = vi.fn().mockResolvedValue({ + success: true, + session: {}, + redirectURL: null, + redirect: false, + headers: new Headers(), + toResponse: vi.fn(), + }) + const auth = authInstance({ updateSession: updateSessionAPI }) + const headers = new Headers({ "x-custom": "value" }) + mockGetRequestHeaders.mockReturnValue(headers) + + const updateSessionFn = updateSession(auth) + const handler = updateSessionFn.__executeServer + + await handler({ data: { session: { user: { name: "Alice" } } }, method: "POST" }) + expect(updateSessionAPI).toHaveBeenCalledWith({ headers, session: { user: { name: "Alice" } } }) + }) + + test("removes headers and toResponse from the response", async () => { + const responseHeaders = new Headers({ "x-custom": "value" }) + const auth = authInstance({ + updateSession: vi.fn().mockResolvedValue({ + success: true, + session: {}, + redirectURL: null, + redirect: false, + headers: responseHeaders, + toResponse: vi.fn(), + }), + }) + + const updateSessionFn = updateSession(auth) + const handler = updateSessionFn.__executeServer + + const output = await handler({ data: { session: { user: { name: "Alice" } } }, method: "POST" }) + expect(output).toEqual({ success: true, session: {}, redirectURL: null, redirect: false }) + }) +}) From a224986986444bf7cf6e5ef0844ca7b92c46cb98 Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Fri, 7 Aug 2026 16:38:41 -0500 Subject: [PATCH 4/5] chore(apps): update TanStack Start demo app --- apps/tanstack-start/package.json | 2 +- apps/tanstack-start/src/components/header.tsx | 5 +- apps/tanstack-start/src/contexts/auth.tsx | 2 +- apps/tanstack-start/src/lib/auth-client.ts | 2 +- apps/tanstack-start/src/lib/auth-server.ts | 116 ---------- apps/tanstack-start/src/lib/auth.ts | 15 +- apps/tanstack-start/src/routes/api/auth.$.ts | 3 + apps/tanstack-start/src/routes/client.tsx | 11 +- apps/tanstack-start/src/routes/server.tsx | 34 +-- bun.lock | 6 + packages/integration/package.json | 12 +- packages/integration/tsdown.config.ts | 3 +- packages/tanstack-start/package.json | 13 +- packages/tanstack-start/src/@types/api.ts | 6 - packages/tanstack-start/src/@types/index.ts | 204 ++++++++++++++++++ packages/tanstack-start/src/client.tsx | 18 ++ packages/tanstack-start/src/context.tsx | 32 +++ packages/tanstack-start/src/createAuth.ts | 3 +- packages/tanstack-start/src/lib/api.ts | 7 +- packages/tanstack-start/tsdown.config.ts | 1 + pnpm-lock.yaml | 47 ++-- 21 files changed, 363 insertions(+), 179 deletions(-) delete mode 100644 apps/tanstack-start/src/lib/auth-server.ts create mode 100644 packages/tanstack-start/src/client.tsx create mode 100644 packages/tanstack-start/src/context.tsx diff --git a/apps/tanstack-start/package.json b/apps/tanstack-start/package.json index 51f6a57d..614a6013 100644 --- a/apps/tanstack-start/package.json +++ b/apps/tanstack-start/package.json @@ -11,7 +11,7 @@ "format:check": "oxfmt --check" }, "dependencies": { - "@aura-stack/react": "workspace:*", + "@aura-stack/tanstack-start": "workspace:*", "@hookform/resolvers": "^5.2.2", "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-slot": "^1.2.4", diff --git a/apps/tanstack-start/src/components/header.tsx b/apps/tanstack-start/src/components/header.tsx index f54da1fe..b256a7b0 100644 --- a/apps/tanstack-start/src/components/header.tsx +++ b/apps/tanstack-start/src/components/header.tsx @@ -1,11 +1,12 @@ import { useState } from "react" import { Link } from "@tanstack/react-router" import { Menu, X } from "lucide-react" -import { useAuth } from "@aura-stack/react" +import { useAuthActions, useSession } from "@aura-stack/tanstack-start/client" import { Button } from "@/components/ui/button" export const Header = () => { - const { status, isPending, signOut, signIn } = useAuth() + const { status } = useSession() + const { isPending, signOut, signIn } = useAuthActions() const isAuthenticated = status === "authenticated" const [mobileMenuOpen, setMobileMenuOpen] = useState(false) diff --git a/apps/tanstack-start/src/contexts/auth.tsx b/apps/tanstack-start/src/contexts/auth.tsx index 63d05484..c24f48e5 100644 --- a/apps/tanstack-start/src/contexts/auth.tsx +++ b/apps/tanstack-start/src/contexts/auth.tsx @@ -1,4 +1,4 @@ -import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/react" +import { AuthProvider as AuraAuthProvider, type AuthProviderProps } from "@aura-stack/tanstack-start/client" import { authClient } from "@/lib/auth-client" export const AuthProvider = ({ children, initialSession }: Omit) => { diff --git a/apps/tanstack-start/src/lib/auth-client.ts b/apps/tanstack-start/src/lib/auth-client.ts index 3eade0ef..1ff9beeb 100644 --- a/apps/tanstack-start/src/lib/auth-client.ts +++ b/apps/tanstack-start/src/lib/auth-client.ts @@ -1,4 +1,4 @@ -import { createAuthClient } from "@aura-stack/react" +import { createAuthClient } from "@aura-stack/tanstack-start/client" export const authClient = createAuthClient({ basePath: "/api/auth", diff --git a/apps/tanstack-start/src/lib/auth-server.ts b/apps/tanstack-start/src/lib/auth-server.ts deleted file mode 100644 index 0a3cdb10..00000000 --- a/apps/tanstack-start/src/lib/auth-server.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { api } from "@/lib/auth" -import { redirect } from "@tanstack/react-router" -import { createServerFn } from "@tanstack/react-start" -import { getRequest, getRequestHeaders } from "@tanstack/react-start/server" - -export const getSession = createServerFn({ method: "GET" }).handler(async () => { - try { - const session = await api.getSession({ - headers: getRequestHeaders(), - }) - if (!session.success) return null - return session.session as any - } catch (error) { - console.error("[error:server] getSession", error) - return null - } -}) - -export const signOutFn = createServerFn({ method: "POST" }).handler(async () => { - const response = await api - .signOut({ - headers: getRequestHeaders(), - }) - .catch((error) => { - console.error("[error:server] signOut", error) - return null - }) - throw redirect({ to: "/", headers: response?.headers, reloadDocument: true }) -}) - -export const signInFn = createServerFn({ method: "POST" }) - .inputValidator((data: { provider: string }) => { - if (!data || typeof data.provider !== "string" || !data.provider.trim()) { - throw new Error("provider must be a non-empty string") - } - return data - }) - .handler(async ({ data }) => { - const response = await api - .signIn(data.provider, { - request: getRequest(), - redirect: false, - }) - .catch((error) => { - console.error("[error:server] signIn", error) - return null - }) - throw redirect({ - href: response?.signInURL ?? "/", - }) - }) - -export const signInCredentialsFn = createServerFn({ method: "POST" }) - .inputValidator((data: { username: string; password: string }) => { - if (!data || typeof data.username !== "string" || typeof data.password !== "string") { - throw new Error("credentials payload is invalid") - } - return data - }) - .handler(async ({ data }) => { - const response = await api - .signInCredentials({ - payload: { - username: data.username, - password: data.password, - }, - request: getRequest(), - headers: getRequestHeaders(), - redirectTo: "/server", - }) - .catch((error) => { - console.error("[error:server] signInCredentials", error) - return null - }) - - if (response?.redirectURL) { - throw redirect({ - href: response.redirectURL, - headers: response.headers, - }) - } - - return null - }) - -export const updateSessionFn = createServerFn({ method: "POST" }) - .inputValidator((data: { username?: string; email?: string }) => { - if (!data || typeof data !== "object") { - throw new Error("update session payload is invalid") - } - if (data.username !== undefined && typeof data.username !== "string") { - throw new Error("username must be a string") - } - if (data.email !== undefined && typeof data.email !== "string") { - throw new Error("email must be a string") - } - return data - }) - .handler(async ({ data }) => { - const response = await api - .updateSession({ - session: { - user: { - name: data.username, - email: data.email, - }, - }, - headers: getRequestHeaders(), - }) - .catch((error) => { - console.error("[error:server] updateSession", error) - return null - }) - - return { success: Boolean(response?.success) } - }) diff --git a/apps/tanstack-start/src/lib/auth.ts b/apps/tanstack-start/src/lib/auth.ts index c676a671..a281d168 100644 --- a/apps/tanstack-start/src/lib/auth.ts +++ b/apps/tanstack-start/src/lib/auth.ts @@ -1,13 +1,16 @@ -import { createAuth } from "@aura-stack/react/server" -import { createSecretValue } from "@aura-stack/react/crypto" -import { builtInOAuthProviders, type BuiltInOAuthProvider } from "@aura-stack/react/oauth" +import { createAuth } from "@aura-stack/tanstack-start" +import { createSecretValue } from "@aura-stack/tanstack-start/crypto" +import { builtInOAuthProviders, type BuiltInOAuthProvider } from "@aura-stack/tanstack-start/oauth" export const oauth = Object.keys(builtInOAuthProviders) as BuiltInOAuthProvider[] -export const { handlers, jose, api } = createAuth({ - oauth, +export const { + handlers, + api, + core: { jose }, +} = createAuth({ + oauth: ["github", "google", "gitlab"], basePath: "/api/auth", - trustedProxyHeaders: true, credentials: { authorize: (ctx) => { const { username, password } = ctx.credentials diff --git a/apps/tanstack-start/src/routes/api/auth.$.ts b/apps/tanstack-start/src/routes/api/auth.$.ts index add153bb..2f0ca8fc 100644 --- a/apps/tanstack-start/src/routes/api/auth.$.ts +++ b/apps/tanstack-start/src/routes/api/auth.$.ts @@ -13,6 +13,9 @@ export const Route = createFileRoute("/api/auth/$")({ PATCH: async ({ request }) => { return await handlers.PATCH(request) }, + DELETE: async ({ request }) => { + return await handlers.DELETE(request) + }, }, }, }) diff --git a/apps/tanstack-start/src/routes/client.tsx b/apps/tanstack-start/src/routes/client.tsx index c02e5172..738afbb2 100644 --- a/apps/tanstack-start/src/routes/client.tsx +++ b/apps/tanstack-start/src/routes/client.tsx @@ -1,6 +1,6 @@ import { Link } from "@tanstack/react-router" import { createFileRoute } from "@tanstack/react-router" -import { useAuth } from "@aura-stack/react" +import { useAuthActions, useSession } from "@aura-stack/tanstack-start/client" import { Button } from "@/components/ui/button" import { EditProfile } from "@/components/edit-profile" import type { SyntheticEvent } from "react" @@ -10,7 +10,8 @@ export const Route = createFileRoute("/client")({ }) function AuthClientPage() { - const { session, status, isPending, signIn, signOut, signInCredentials, updateSession } = useAuth() + const { isPending, signIn, signOut, signInCredentials, updateSession } = useAuthActions() + const { session, status } = useSession() const isAuthenticated = status === "authenticated" const handleSignInCredentials = async (event: SyntheticEvent) => { @@ -50,8 +51,8 @@ function AuthClientPage() {

Aura Auth + TanStack Start Client Components

- Official TanStack Start demo to showcase @aura-stack/react authentication library with Client Side - Rendering (CSR), for Server-Side Rendering (SSR) visit{" "} + Official TanStack Start demo to showcase @aura-stack/tanstack-start authentication library with Client + Side Rendering (CSR), for Server-Side Rendering (SSR) visit{" "} here @@ -141,6 +142,7 @@ function AuthClientPage() { type="text" id="username" name="username" + aria-label="Username" className="w-full h-9 mt-1 font-medium border border-input rounded-none bg-background hover:text-accent-foreground hover:bg-input/50 focus:outline-1" />

@@ -152,6 +154,7 @@ function AuthClientPage() { type="password" id="password" name="password" + aria-label="Password" className="w-full h-9 mt-1 font-medium border border-input rounded-none bg-background hover:text-accent-foreground hover:bg-input/50 focus:outline-1" />
diff --git a/apps/tanstack-start/src/routes/server.tsx b/apps/tanstack-start/src/routes/server.tsx index 24298c48..70ae37f3 100644 --- a/apps/tanstack-start/src/routes/server.tsx +++ b/apps/tanstack-start/src/routes/server.tsx @@ -3,12 +3,12 @@ import { Link, createFileRoute, useRouter } from "@tanstack/react-router" import { useServerFn } from "@tanstack/react-start" import { Button } from "@/components/ui/button" import { EditProfile } from "@/components/edit-profile" -import { getSession, signInCredentialsFn, signInFn, signOutFn, updateSessionFn } from "@/lib/auth-server" +import { api } from "@/lib/auth" export const Route = createFileRoute("/server")({ component: AuthServerPage, loader: async () => { - const session = await getSession() + const session = await api.getSession() return { session } }, }) @@ -17,15 +17,15 @@ function AuthServerPage() { const router = useRouter() const { session } = Route.useLoaderData() - const signIn = useServerFn(signInFn) - const signOut = useServerFn(signOutFn) - const signInCredentials = useServerFn(signInCredentialsFn) - const updateSession = useServerFn(updateSessionFn) + const signIn = useServerFn(api.signIn) + const signOut = useServerFn(api.signOut) + const signInCredentials = useServerFn(api.signInCredentials) + const updateSession = useServerFn(api.updateSession) const isAuthenticated = Boolean(session && session.user) const handleSignIn = async (provider: string) => { - await signIn({ data: { provider } }) + await signIn({ data: { providerId: provider } }) } const handleSignOut = async () => { @@ -41,8 +41,10 @@ function AuthServerPage() { await signInCredentials({ data: { - username, - password, + payload: { + username, + password, + }, }, }) await router.invalidate() @@ -51,8 +53,12 @@ function AuthServerPage() { const handleUpdateSession = async (formData: FormData) => { await updateSession({ data: { - username: formData.get("username") ? (formData.get("username") as string) : undefined, - email: formData.get("email") ? (formData.get("email") as string) : undefined, + session: { + user: { + name: formData.get("username") ? (formData.get("username") as string) : undefined, + email: formData.get("email") ? (formData.get("email") as string) : undefined, + }, + }, }, }) await router.invalidate() @@ -64,8 +70,8 @@ function AuthServerPage() {

Aura Auth + TanStack Start Server Components

- Official TanStack Start demo to showcase @aura-stack/react authentication library with server functions - and route loaders for Server Side Rendering (SSR), for Client-Side Rendering (CSR) visit{" "} + Official TanStack Start demo to showcase @aura-stack/tanstack-start authentication library with server + functions and route loaders for Server Side Rendering (SSR), for Client-Side Rendering (CSR) visit{" "} here @@ -152,6 +158,7 @@ function AuthServerPage() { type="text" id="username" name="username" + aria-label="Username" className="w-full h-9 mt-1 font-medium border border-input rounded-none bg-background hover:text-accent-foreground hover:bg-input/50 focus:outline-1" />

@@ -163,6 +170,7 @@ function AuthServerPage() { type="password" id="password" name="password" + aria-label="Password" className="w-full h-9 mt-1 font-medium border border-input rounded-none bg-background hover:text-accent-foreground hover:bg-input/50 focus:outline-1" /> diff --git a/bun.lock b/bun.lock index 8702fad0..cd37465a 100644 --- a/bun.lock +++ b/bun.lock @@ -203,6 +203,7 @@ "name": "tanstack-start", "dependencies": { "@aura-stack/react": "workspace:*", + "@aura-stack/tanstack-start": "workspace:*", "@hookform/resolvers": "^5.2.2", "@radix-ui/react-label": "^2.1.8", "@radix-ui/react-slot": "^1.2.4", @@ -530,6 +531,11 @@ "devDependencies": { "@aura-stack/tsconfig": "workspace:*", "@aura-stack/tsdown-config": "workspace:*", + "@types/react": "catalog:react", + "@types/react-dom": "catalog:react", + "react": "catalog:react", + "react-dom": "catalog:react", + "vitest": "catalog:vitest", }, "peerDependencies": { "@tanstack/react-router": ">=1.0.0", diff --git a/packages/integration/package.json b/packages/integration/package.json index c527bc25..f87f0644 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -69,14 +69,14 @@ "require": "./dist/oauth/*.cjs" }, "./identity": { - "types": "./dist/_core/identity.d.ts", - "import": "./dist/_core/identity.js", - "require": "./dist/_core/identity.cjs" + "types": "./dist/identity.d.ts", + "import": "./dist/identity.js", + "require": "./dist/identity.cjs" }, "./identity/*": { - "types": "./dist/_core/identity/*.d.ts", - "import": "./dist/_core/identity/*.js", - "require": "./dist/_core/identity/*.cjs" + "types": "./dist/identity/*.d.ts", + "import": "./dist/identity/*.js", + "require": "./dist/identity/*.cjs" }, "./crypto": { "types": "./dist/_core/crypto.d.ts", diff --git a/packages/integration/tsdown.config.ts b/packages/integration/tsdown.config.ts index 69396e75..108bcd99 100644 --- a/packages/integration/tsdown.config.ts +++ b/packages/integration/tsdown.config.ts @@ -7,7 +7,8 @@ export default defineConfig({ "src/index.ts", "src/oauth/index.ts", "src/oauth/*.ts", - "src/_core/identity.ts", + "src/identity.ts", + "src/identity/*.ts", "src/_core/crypto.ts", "src/_core/shared.ts", "src/_core/cookies.ts", diff --git a/packages/tanstack-start/package.json b/packages/tanstack-start/package.json index 5647deb6..2c6175a5 100644 --- a/packages/tanstack-start/package.json +++ b/packages/tanstack-start/package.json @@ -50,7 +50,11 @@ "devDependencies": { "@aura-stack/tsconfig": "workspace:*", "@aura-stack/tsdown-config": "workspace:*", - "vitest": "catalog:vitest" + "react": "catalog:react", + "react-dom": "catalog:react", + "vitest": "catalog:vitest", + "@types/react": "catalog:react", + "@types/react-dom": "catalog:react" }, "peerDependencies": { "@tanstack/react-start": ">=1.0.0", @@ -62,6 +66,11 @@ "import": "./dist/index.js", "require": "./dist/index.cjs" }, + "./client": { + "types": "./dist/client.d.ts", + "import": "./dist/client.js", + "require": "./dist/client.cjs" + }, "./oauth": { "types": "./dist/oauth/index.d.ts", "import": "./dist/oauth/index.js", @@ -100,4 +109,4 @@ "./types": "./dist/@types/index.d.ts" }, "packageManager": "pnpm@10.15.0" -} +} \ No newline at end of file diff --git a/packages/tanstack-start/src/@types/api.ts b/packages/tanstack-start/src/@types/api.ts index 2670ba01..45dc16f5 100644 --- a/packages/tanstack-start/src/@types/api.ts +++ b/packages/tanstack-start/src/@types/api.ts @@ -16,7 +16,6 @@ import type { DisconnectProviderAPIOptions, ProviderConnectedAPIOptions, } from "@aura-stack/react/types" -import type { FromShapeToObject, Identities, SchemaTypes } from "@aura-stack/react/identity" import type { SignInAPIReturn, SignInCredentialsAPIReturn, @@ -31,11 +30,6 @@ import type { ProviderConnectedAPIReturn, } from "@aura-stack/react/types" -export type TanstackStartInstance< - Identity extends Identities = Identities, - SignUpSchema extends SchemaTypes = SchemaTypes, -> = AuthInstance, SignUpSchema> - export type TanstackStartSignInOptions = Prettify< Omit & { providerId: LiteralUnion } > diff --git a/packages/tanstack-start/src/@types/index.ts b/packages/tanstack-start/src/@types/index.ts index d1e40189..972aadb6 100644 --- a/packages/tanstack-start/src/@types/index.ts +++ b/packages/tanstack-start/src/@types/index.ts @@ -1,2 +1,206 @@ +import { zod } from "@aura-stack/react/identity/zod" +import type { AuthInstance, Session } from "@aura-stack/react" +import type { OptionalFetcher, RequiredFetcher } from "@tanstack/react-start" +import type { FromShapeToObject, Identities, SchemaTypes } from "@aura-stack/react/identity" +import type { TanstackStartSignInCredentialsOptions, TanstackStartSignOutOptions } from "@/@types/api.ts" +import type { + BuiltInOAuthProvider, + CredentialsPayload, + DeepPartial, + Handlers, + InferSchema, + LiteralUnion, + OAuthTokenPayload, + RemoveIndexSignature, + Wrap, +} from "@aura-stack/react/types" + export type * from "@/@types/api.ts" export type * from "@/@types/core.ts" + +type GetSession = OptionalFetcher< + undefined, + undefined, + Promise> | null> +> + +type SignIn = RequiredFetcher< + undefined, + (data: { + redirect?: boolean | undefined + redirectTo?: string | undefined + providerId: LiteralUnion + }) => { + redirect?: boolean | undefined + redirectTo?: string | undefined + providerId: LiteralUnion + }, + Promise<{ + redirect: boolean + success: boolean + signInURL: string | null + }> +> + +type SignInCredentials = RequiredFetcher< + undefined, + (data: TanstackStartSignInCredentialsOptions) => { + redirect?: boolean | undefined + redirectTo?: string | undefined + payload: CredentialsPayload + skipCSRFCheck?: boolean | undefined + doubleSubmitToken?: string | undefined + }, + Promise<{ + redirect: boolean + success: boolean + redirectURL: string | null + }> +> + +type SignOut = OptionalFetcher< + undefined, + (data?: TanstackStartSignOutOptions) => { + redirect?: boolean | undefined + redirectTo?: string | undefined + skipCSRFCheck?: boolean | undefined + doubleSubmitToken?: string | undefined + }, + Promise<{ + redirect: boolean + success: boolean + redirectURL: string | null + }> +> + +type UpdateSession = RequiredFetcher< + undefined, + (data: { + redirect?: boolean | undefined + redirectTo?: string | undefined + skipCSRFCheck?: boolean | undefined + doubleSubmitToken?: string | undefined + session: DeepPartial>> + }) => { + redirect?: boolean | undefined + redirectTo?: string | undefined + skipCSRFCheck?: boolean | undefined + doubleSubmitToken?: string | undefined + session: DeepPartial>> + }, + Promise<{ + redirect: boolean + success: boolean + redirectURL: string | null + }> +> + +type GetProviderTokens = RequiredFetcher< + undefined, + (data: { oauth: LiteralUnion }) => { + oauth: LiteralUnion + }, + Promise<{ + success: boolean + tokens: OAuthTokenPayload | null + }> +> +type GetAccessToken = RequiredFetcher< + undefined, + (data: { oauth: LiteralUnion }) => { + oauth: LiteralUnion + }, + Promise<{ + success: boolean + accessToken: string | null + }> +> + +type DisconnectProvider = RequiredFetcher< + undefined, + (data: { + skipCSRFCheck?: boolean | undefined + doubleSubmitToken?: string | undefined + oauth: LiteralUnion + }) => { + skipCSRFCheck?: boolean | undefined + doubleSubmitToken?: string | undefined + oauth: LiteralUnion + }, + Promise<{ success: boolean }> +> + +type IsProviderConnected = RequiredFetcher< + undefined, + (data: { oauth: LiteralUnion }) => { + oauth: LiteralUnion + }, + Promise<{ + success: boolean + connected: boolean + }> +> + +type RevokeToken = RequiredFetcher< + undefined, + (data: { + skipCSRFCheck?: boolean | undefined + doubleSubmitToken?: string | undefined + oauth: LiteralUnion + }) => { + skipCSRFCheck?: boolean | undefined + doubleSubmitToken?: string | undefined + oauth: LiteralUnion + }, + Promise<{ success: boolean }> +> + +type RefreshUserInfo = OptionalFetcher< + undefined, + any, + Promise<{ + success: boolean + session: Session> | null + }> +> + +type SignUp> = RequiredFetcher< + undefined, + (data: { + redirect?: boolean | undefined + redirectTo?: string | undefined + payload: Wrap>> + skipCSRFCheck?: boolean | undefined + doubleSubmitToken?: string | undefined + }) => { + redirect?: boolean | undefined + redirectTo?: string | undefined + payload: Wrap>> + skipCSRFCheck?: boolean | undefined + doubleSubmitToken?: string | undefined + }, + Promise<{ + redirect: boolean + success: boolean + redirectURL: string | null + }> +> + +export type TanstackStartInstance = { + core: AuthInstance, SignUpSchema> + api: { + getSession: GetSession + signIn: SignIn + signInCredentials: SignInCredentials + signOut: SignOut + updateSession: UpdateSession + signUp: SignUp + getProviderTokens: GetProviderTokens + getAccessToken: GetAccessToken + refreshUserInfo: RefreshUserInfo + revokeToken: RevokeToken + disconnectProvider: DisconnectProvider + isProviderConnected: IsProviderConnected + } + handlers: Handlers +} diff --git a/packages/tanstack-start/src/client.tsx b/packages/tanstack-start/src/client.tsx new file mode 100644 index 00000000..5ef16c04 --- /dev/null +++ b/packages/tanstack-start/src/client.tsx @@ -0,0 +1,18 @@ +export { + createAuthClient, + useAuthActions, + useSession, + useSignIn, + useSignInCredentials, + useUpdateSession, + useSignOut, + useSignUp, + useProviderTokens, + useAccessToken, + useDisconnectProvider, + useRevokeToken, + useIsProviderConnected, + useRefreshUserInfo, + type AuthClientOptions, +} from "@aura-stack/react" +export { AuthProvider, type AuthProviderProps } from "@/context" diff --git a/packages/tanstack-start/src/context.tsx b/packages/tanstack-start/src/context.tsx new file mode 100644 index 00000000..fb4be5b7 --- /dev/null +++ b/packages/tanstack-start/src/context.tsx @@ -0,0 +1,32 @@ +import { AuthProvider as Provider, type AuthProviderProps } from "@aura-stack/react/context" +import { useNavigate } from "@tanstack/react-router" +import type { User } from "@aura-stack/react" + +/** + * Wrapper component that provides authentication context for TanStack React applications. + * + * @example + * const client = createAuthClient({ baseURL: "http://localhost:3000" }) + * + * + * + * + */ +const AuthProvider = ({ + client, + children, + initialSession, + redirect, +}: AuthProviderProps) => { + const router = useNavigate() + + const onRedirect = redirect ?? ((to: string) => router({ to })) + + return ( + + {children} + + ) +} + +export { AuthProvider, type AuthProviderProps } diff --git a/packages/tanstack-start/src/createAuth.ts b/packages/tanstack-start/src/createAuth.ts index f1055c56..b436ddbf 100644 --- a/packages/tanstack-start/src/createAuth.ts +++ b/packages/tanstack-start/src/createAuth.ts @@ -2,6 +2,7 @@ import { api } from "@/lib/api.ts" import { createAuth as createAuthInstance } from "@aura-stack/react/server" import type { AuthConfig } from "@aura-stack/react/types" import type { zod } from "@aura-stack/react/identity/zod" +import type { TanstackStartInstance } from "@/@types/index" import type { FromShapeToObject, Identities, SchemaTypes } from "@aura-stack/react/identity" /** @@ -25,7 +26,7 @@ import type { FromShapeToObject, Identities, SchemaTypes } from "@aura-stack/rea */ export const createAuth = >( config: AuthConfig -) => { +): TanstackStartInstance => { const auth = createAuthInstance(config) return { /** diff --git a/packages/tanstack-start/src/lib/api.ts b/packages/tanstack-start/src/lib/api.ts index f5b99f98..c428a854 100644 --- a/packages/tanstack-start/src/lib/api.ts +++ b/packages/tanstack-start/src/lib/api.ts @@ -24,8 +24,9 @@ import type { TanstackStartIsProviderConnectedOptions, TanstackStartIsProviderConnectedReturn, } from "@/@types/api.ts" -import type { AuthInstance, User } from "@aura-stack/auth" +import type { AuthInstance, Session, User } from "@aura-stack/auth" import type { InferSchema, RemoveIndexSignature, SchemaTypes, Wrap } from "@aura-stack/react/types" +import type { zod } from "@/identity/zod" export const getSession = ({ api }: AuthInstance) => { return createServerFn({ @@ -37,7 +38,7 @@ export const getSession = ({ api }: AuthInstanc }) if (!session.success) return null return session.session - }) as OptionalFetcher> + }) as OptionalFetcher | null>> } export const signIn = ({ api }: AuthInstance) => { @@ -199,7 +200,7 @@ export const isProviderConnected = ({ api }: Au }) } -export const api = ( +export const api = >( config: AuthInstance ) => { return { diff --git a/packages/tanstack-start/tsdown.config.ts b/packages/tanstack-start/tsdown.config.ts index 87150f1b..58fdb6c7 100644 --- a/packages/tanstack-start/tsdown.config.ts +++ b/packages/tanstack-start/tsdown.config.ts @@ -5,6 +5,7 @@ export default defineConfig({ ...tsdownConfig, entry: [ "src/index.ts", + "src/client.tsx", "src/identity.ts", "src/identity/*.ts", "src/oauth/index.ts", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 468f0263..f7a2b78e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -479,9 +479,9 @@ importers: apps/tanstack-start: dependencies: - '@aura-stack/react': + '@aura-stack/tanstack-start': specifier: workspace:* - version: link:../../packages/react + version: link:../../packages/tanstack-start '@hookform/resolvers': specifier: ^5.2.2 version: 5.2.2(react-hook-form@7.71.2(react@19.2.4)) @@ -1046,6 +1046,21 @@ importers: '@aura-stack/tsdown-config': specifier: workspace:* version: link:../../configs/tsdown-config + '@types/react': + specifier: catalog:react + version: 19.2.14 + '@types/react-dom': + specifier: catalog:react + version: 19.2.3(@types/react@19.2.14) + react: + specifier: catalog:react + version: 19.2.4 + react-dom: + specifier: catalog:react + version: 19.2.4(react@19.2.4) + vitest: + specifier: catalog:vitest + version: 4.1.4(@types/node@25.9.3)(@vitest/coverage-v8@4.1.4)(jsdom@27.4.0(@noble/hashes@1.8.0))(vite@7.3.5(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.9.0)) packages: @@ -11618,7 +11633,7 @@ snapshots: '@mdx-js/mdx@3.1.1': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 '@types/mdx': 2.0.13 @@ -14430,7 +14445,7 @@ snapshots: '@types/estree-jsx@1.0.5': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/estree@1.0.8': {} @@ -16302,7 +16317,7 @@ snapshots: estree-util-attach-comments@3.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-util-build-jsx@3.0.1: dependencies: @@ -16315,7 +16330,7 @@ snapshots: estree-util-scope@1.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 estree-util-to-js@2.0.0: @@ -16326,7 +16341,7 @@ snapshots: estree-util-value-to-estree@3.5.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-util-visit@2.0.0: dependencies: @@ -16924,7 +16939,7 @@ snapshots: hast-util-to-estree@3.1.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 comma-separated-tokens: 2.0.3 @@ -16959,7 +16974,7 @@ snapshots: hast-util-to-jsx-runtime@2.3.6: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/hast': 3.0.4 '@types/unist': 3.0.3 comma-separated-tokens: 2.0.3 @@ -17763,7 +17778,7 @@ snapshots: micromark-extension-mdx-expression@3.0.1: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 micromark-factory-mdx-expression: 2.0.3 micromark-factory-space: 2.0.1 @@ -17774,7 +17789,7 @@ snapshots: micromark-extension-mdx-jsx@3.0.2: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 micromark-factory-mdx-expression: 2.0.3 @@ -17791,7 +17806,7 @@ snapshots: micromark-extension-mdxjs-esm@3.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-util-character: 2.1.1 @@ -19323,7 +19338,7 @@ snapshots: recma-build-jsx@1.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-util-build-jsx: 3.0.1 vfile: 6.0.3 @@ -19338,14 +19353,14 @@ snapshots: recma-parse@1.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esast-util-from-js: 2.0.1 unified: 11.0.5 vfile: 6.0.3 recma-stringify@1.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-util-to-js: 2.0.0 unified: 11.0.5 vfile: 6.0.3 @@ -19382,7 +19397,7 @@ snapshots: rehype-recma@1.0.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/hast': 3.0.4 hast-util-to-estree: 3.1.3 transitivePeerDependencies: From d81f4333c2af522b2f226f3e2b6a7847ea85cf4e Mon Sep 17 00:00:00 2001 From: Hernan Alvarado Date: Sun, 9 Aug 2026 12:00:28 -0500 Subject: [PATCH 5/5] chore(tanstack-start): update dependencies and identify potential issues --- .oxfmtrc.json | 2 +- apps/tanstack-start/.cta.json | 12 - apps/tanstack-start/package.json | 22 +- apps/tanstack-start/src/lib/auth-server.ts | 116 + apps/tanstack-start/src/lib/auth.ts | 10 +- apps/tanstack-start/src/routeTree.gen.ts | 36 +- apps/tanstack-start/src/router.tsx | 1 + apps/tanstack-start/src/routes/__root.tsx | 2 +- apps/tanstack-start/src/routes/client.tsx | 4 +- apps/tanstack-start/src/routes/server.tsx | 36 +- apps/tanstack-start/vite.config.ts | 22 +- bun.lock | 210 +- configs/tsconfig/tanstack.json | 2 +- package.json | 3 + packages/core/src/oauth/index.ts | 6 +- packages/tanstack-start/package.json | 2 + packages/tanstack-start/src/@types/index.ts | 4 + packages/tanstack-start/src/createAuth.ts | 10 +- .../src/lib/{api.ts => api.functions.ts} | 0 pnpm-lock.yaml | 2308 ++++++++++------- pnpm-workspace.yaml | 6 +- 21 files changed, 1669 insertions(+), 1145 deletions(-) delete mode 100644 apps/tanstack-start/.cta.json create mode 100644 apps/tanstack-start/src/lib/auth-server.ts rename packages/tanstack-start/src/lib/{api.ts => api.functions.ts} (100%) diff --git a/.oxfmtrc.json b/.oxfmtrc.json index 3116419b..82056e40 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -13,5 +13,5 @@ } ], "sortPackageJson": false, - "ignorePatterns": ["pnpm-lock.yaml", "deno.lock", "bun.lock", "dist", "node_modules", "coverage"] + "ignorePatterns": ["pnpm-lock.yaml", "deno.lock", "bun.lock", "dist", "node_modules", "coverage", "routeTree.gen.ts"] } diff --git a/apps/tanstack-start/.cta.json b/apps/tanstack-start/.cta.json deleted file mode 100644 index 2d4926d7..00000000 --- a/apps/tanstack-start/.cta.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "projectName": "tanstack-start", - "mode": "file-router", - "typescript": true, - "packageManager": "pnpm", - "tailwind": true, - "addOnOptions": {}, - "git": true, - "version": 1, - "framework": "react-cra", - "chosenAddOns": ["nitro", "start"] -} diff --git a/apps/tanstack-start/package.json b/apps/tanstack-start/package.json index 614a6013..23be94b2 100644 --- a/apps/tanstack-start/package.json +++ b/apps/tanstack-start/package.json @@ -17,23 +17,17 @@ "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", "@tailwindcss/vite": "catalog:@tailwindcss/vite", - "@tanstack/react-devtools": "^0.10.5", - "@tanstack/react-router": "^1.170.15", - "@tanstack/react-router-devtools": "^1.167.0", - "@tanstack/react-router-ssr-query": "^1.167.1", - "@tanstack/react-start": "^1.168.25", - "@tanstack/router-plugin": "^1.168.18", + "@tanstack/react-devtools": "^0.10.9", + "@tanstack/react-router": "^1.170.24", + "@tanstack/react-router-devtools": "^1.167.1", + "@tanstack/react-start": "^1.168.41", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "catalog:lucide-react", - "nitro": "npm:nitro-nightly@latest", "react": "catalog:react", "react-dom": "catalog:react", "react-hook-form": "^7.71.1", - "tailwind-merge": "^3.4.0", - "tailwindcss": "catalog:tailwindcss", - "vite-tsconfig-paths": "^6.0.2", - "zod": "catalog:zod-v4" + "tailwind-merge": "^3.4.0" }, "devDependencies": { "@aura-stack/tsconfig": "workspace:*", @@ -43,11 +37,13 @@ "@types/node": "catalog:node", "@types/react": "catalog:react", "@types/react-dom": "catalog:react", - "@vitejs/plugin-react": "^5.0.4", + "@vitejs/plugin-react": "^5.2.0", "jsdom": "^27.0.0", + "nitro": "^3.0.260610-beta", + "tailwindcss": "catalog:tailwindcss", "tw-animate-css": "^1.4.0", "typescript": "catalog:typescript", - "vite": "catalog:vite", + "vite": "catalog:vite-v8", "web-vitals": "^5.1.0" } } diff --git a/apps/tanstack-start/src/lib/auth-server.ts b/apps/tanstack-start/src/lib/auth-server.ts new file mode 100644 index 00000000..1283d619 --- /dev/null +++ b/apps/tanstack-start/src/lib/auth-server.ts @@ -0,0 +1,116 @@ +import { core } from "@/lib/auth" +import { redirect } from "@tanstack/react-router" +import { createServerFn } from "@tanstack/react-start" +import { getRequest, getRequestHeaders } from "@tanstack/react-start/server" + +export const getSession = createServerFn({ method: "GET" }).handler(async () => { + try { + const session = await core.api.getSession({ + headers: getRequestHeaders(), + }) + if (!session.success) return null + return session.session as any + } catch (error) { + console.error("[error:server] getSession", error) + return null + } +}) + +export const signOutFn = createServerFn({ method: "POST" }).handler(async () => { + const response = await core.api + .signOut({ + headers: getRequestHeaders(), + }) + .catch((error) => { + console.error("[error:server] signOut", error) + return null + }) + throw redirect({ to: "/", headers: response?.headers, reloadDocument: true }) +}) + +export const signInFn = createServerFn({ method: "POST" }) + .validator((data: { provider: string }) => { + if (!data || typeof data.provider !== "string" || !data.provider.trim()) { + throw new Error("provider must be a non-empty string") + } + return data + }) + .handler(async ({ data }) => { + const response = await core.api + .signIn(data.provider, { + request: getRequest(), + redirect: false, + }) + .catch((error) => { + console.error("[error:server] signIn", error) + return null + }) + throw redirect({ + href: response?.signInURL ?? "/", + }) + }) + +export const signInCredentialsFn = createServerFn({ method: "POST" }) + .validator((data: { username: string; password: string }) => { + if (!data || typeof data.username !== "string" || typeof data.password !== "string") { + throw new Error("credentials payload is invalid") + } + return data + }) + .handler(async ({ data }) => { + const response = await core.api + .signInCredentials({ + payload: { + username: data.username, + password: data.password, + }, + request: getRequest(), + headers: getRequestHeaders(), + redirectTo: "/server", + }) + .catch((error) => { + console.error("[error:server] signInCredentials", error) + return null + }) + + if (response?.redirectURL) { + throw redirect({ + href: response.redirectURL, + headers: response.headers, + }) + } + + return null + }) + +export const updateSessionFn = createServerFn({ method: "POST" }) + .validator((data: { username?: string; email?: string }) => { + if (!data || typeof data !== "object") { + throw new Error("update session payload is invalid") + } + if (data.username !== undefined && typeof data.username !== "string") { + throw new Error("username must be a string") + } + if (data.email !== undefined && typeof data.email !== "string") { + throw new Error("email must be a string") + } + return data + }) + .handler(async ({ data }) => { + const response = await core.api + .updateSession({ + session: { + user: { + name: data.username, + email: data.email, + }, + }, + headers: getRequestHeaders(), + }) + .catch((error) => { + console.error("[error:server] updateSession", error) + return null + }) + + return { success: Boolean(response?.success) } + }) diff --git a/apps/tanstack-start/src/lib/auth.ts b/apps/tanstack-start/src/lib/auth.ts index a281d168..2325d983 100644 --- a/apps/tanstack-start/src/lib/auth.ts +++ b/apps/tanstack-start/src/lib/auth.ts @@ -1,14 +1,7 @@ import { createAuth } from "@aura-stack/tanstack-start" import { createSecretValue } from "@aura-stack/tanstack-start/crypto" -import { builtInOAuthProviders, type BuiltInOAuthProvider } from "@aura-stack/tanstack-start/oauth" -export const oauth = Object.keys(builtInOAuthProviders) as BuiltInOAuthProvider[] - -export const { - handlers, - api, - core: { jose }, -} = createAuth({ +export const auth = createAuth({ oauth: ["github", "google", "gitlab"], basePath: "/api/auth", credentials: { @@ -24,3 +17,4 @@ export const { }, }, }) +export const { handlers, api, core, __unstable_fn } = auth diff --git a/apps/tanstack-start/src/routeTree.gen.ts b/apps/tanstack-start/src/routeTree.gen.ts index b9be7880..929fa110 100644 --- a/apps/tanstack-start/src/routeTree.gen.ts +++ b/apps/tanstack-start/src/routeTree.gen.ts @@ -9,14 +9,14 @@ // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. import { Route as rootRouteImport } from './routes/__root' -import { Route as ServerRouteImport } from './routes/server' -import { Route as ClientRouteImport } from './routes/client' import { Route as IndexRouteImport } from './routes/index' +import { Route as ClientRouteImport } from './routes/client' +import { Route as ServerRouteImport } from './routes/server' import { Route as ApiAuthSplatRouteImport } from './routes/api/auth.$' -const ServerRoute = ServerRouteImport.update({ - id: '/server', - path: '/server', +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', getParentRoute: () => rootRouteImport, } as any) const ClientRoute = ClientRouteImport.update({ @@ -24,9 +24,9 @@ const ClientRoute = ClientRouteImport.update({ path: '/client', getParentRoute: () => rootRouteImport, } as any) -const IndexRoute = IndexRouteImport.update({ - id: '/', - path: '/', +const ServerRoute = ServerRouteImport.update({ + id: '/server', + path: '/server', getParentRoute: () => rootRouteImport, } as any) const ApiAuthSplatRoute = ApiAuthSplatRouteImport.update({ @@ -71,11 +71,11 @@ export interface RootRouteChildren { declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/server': { - id: '/server' - path: '/server' - fullPath: '/server' - preLoaderRoute: typeof ServerRouteImport + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRouteImport } '/client': { @@ -85,11 +85,11 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ClientRouteImport parentRoute: typeof rootRouteImport } - '/': { - id: '/' - path: '/' - fullPath: '/' - preLoaderRoute: typeof IndexRouteImport + '/server': { + id: '/server' + path: '/server' + fullPath: '/server' + preLoaderRoute: typeof ServerRouteImport parentRoute: typeof rootRouteImport } '/api/auth/$': { diff --git a/apps/tanstack-start/src/router.tsx b/apps/tanstack-start/src/router.tsx index b86736ba..85d697f8 100644 --- a/apps/tanstack-start/src/router.tsx +++ b/apps/tanstack-start/src/router.tsx @@ -7,6 +7,7 @@ export const getRouter = () => { context: {}, scrollRestoration: true, defaultPreloadStaleTime: 0, + defaultNotFoundComponent: () =>
404 Not Found
, }) return router } diff --git a/apps/tanstack-start/src/routes/__root.tsx b/apps/tanstack-start/src/routes/__root.tsx index 2e2f88a0..aae862ed 100644 --- a/apps/tanstack-start/src/routes/__root.tsx +++ b/apps/tanstack-start/src/routes/__root.tsx @@ -37,7 +37,7 @@ function RootDocument({ children }: PropsWithChildren) { - +
{children} diff --git a/apps/tanstack-start/src/routes/client.tsx b/apps/tanstack-start/src/routes/client.tsx index 738afbb2..63f71713 100644 --- a/apps/tanstack-start/src/routes/client.tsx +++ b/apps/tanstack-start/src/routes/client.tsx @@ -1,8 +1,8 @@ import { Link } from "@tanstack/react-router" import { createFileRoute } from "@tanstack/react-router" -import { useAuthActions, useSession } from "@aura-stack/tanstack-start/client" import { Button } from "@/components/ui/button" import { EditProfile } from "@/components/edit-profile" +import { useAuthActions, useSession } from "@aura-stack/tanstack-start/client" import type { SyntheticEvent } from "react" export const Route = createFileRoute("/client")({ @@ -133,7 +133,7 @@ function AuthClientPage() { Or continue with

-
+