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**
+
+[](https://www.npmjs.com/package/@aura-stack/integration)
+[](https://jsr.io/@aura-stack/integration)
+[](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**
-[](https://www.npmjs.com/package/@aura-stack/integration)
-[](https://jsr.io/@aura-stack/integration)
+[](https://www.npmjs.com/package/@aura-stack/tanstack-start)
+[](https://jsr.io/@aura-stack/tanstack-start)
[](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
-