@ackplus/nest-auth-react-native 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # @ackplus/nest-auth-react-native
2
+
3
+ React Native / Expo SDK for [`@ackplus/nest-auth`](https://github.com/ack-solutions/nest-auth).
4
+
5
+ It adds the two things React Native needs on top of the React SDK:
6
+
7
+ 1. **Native token storage** — `AsyncStorageAdapter` and `SecureStoreAdapter` so sessions survive app restarts.
8
+ 2. **A header-mode client factory** — RN can't use http-only cookies, so tokens are sent in the `Authorization` header and persisted to your storage adapter.
9
+
10
+ The provider, hooks, and guards from [`@ackplus/nest-auth-react`](../nest-auth-react) are re-exported and run unchanged on RN (their web-only code paths are feature-detected). Next.js helpers are intentionally **not** re-exported.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install @ackplus/nest-auth-react-native @ackplus/nest-auth-react @ackplus/nest-auth-client react
16
+ # pick a storage backend:
17
+ npm install @react-native-async-storage/async-storage # Bare RN / Expo
18
+ # or
19
+ npx expo install expo-secure-store # Expo, keychain-backed
20
+ ```
21
+
22
+ This package never imports the native storage module directly — you pass it in — so it stays dependency-light and testable.
23
+
24
+ ## Quick start
25
+
26
+ ```tsx
27
+ // auth.ts
28
+ import AsyncStorage from '@react-native-async-storage/async-storage';
29
+ import { createNestAuthClient, AsyncStorageAdapter } from '@ackplus/nest-auth-react-native';
30
+
31
+ export const authClient = createNestAuthClient({
32
+ baseUrl: 'https://api.example.com',
33
+ storage: new AsyncStorageAdapter(AsyncStorage),
34
+ });
35
+ ```
36
+
37
+ ```tsx
38
+ // App.tsx
39
+ import { AuthProvider } from '@ackplus/nest-auth-react-native';
40
+ import { authClient } from './auth';
41
+
42
+ export default function App() {
43
+ return (
44
+ <AuthProvider client={authClient}>
45
+ <RootNavigator />
46
+ </AuthProvider>
47
+ );
48
+ }
49
+ ```
50
+
51
+ ```tsx
52
+ // LoginScreen.tsx
53
+ import { useNestAuth } from '@ackplus/nest-auth-react-native';
54
+
55
+ export function LoginScreen() {
56
+ const { login, sessionData, isAuthenticated } = useNestAuth();
57
+
58
+ const onSubmit = async (email: string, password: string) => {
59
+ await login({ providerName: 'email', credentials: { email, password } });
60
+ };
61
+
62
+ if (isAuthenticated) return <Text>Welcome, {sessionData?.email}</Text>;
63
+ // ...render your form, call onSubmit
64
+ }
65
+ ```
66
+
67
+ ### Secure storage (recommended for production)
68
+
69
+ ```ts
70
+ import * as SecureStore from 'expo-secure-store';
71
+ import { createNestAuthClient, SecureStoreAdapter } from '@ackplus/nest-auth-react-native';
72
+
73
+ export const authClient = createNestAuthClient({
74
+ baseUrl: 'https://api.example.com',
75
+ storage: new SecureStoreAdapter(SecureStore),
76
+ });
77
+ ```
78
+
79
+ ## Backend setup
80
+
81
+ Your nest-auth backend should run in **header token mode** so tokens are returned in the response body:
82
+
83
+ ```ts
84
+ NestAuthModule.forRoot({
85
+ session: { jwt: { secret: env.JWT_SECRET }, accessTokenType: 'header' },
86
+ // ...
87
+ });
88
+ ```
89
+
90
+ ## API
91
+
92
+ | Export | Purpose |
93
+ | --- | --- |
94
+ | `createNestAuthClient(config)` | Build a header-mode `AuthClient` with required `storage`. |
95
+ | `AsyncStorageAdapter(storage, prefix?)` | `StorageAdapter` over AsyncStorage (or any compatible store). |
96
+ | `SecureStoreAdapter(store, prefix?)` | `StorageAdapter` over Expo SecureStore. |
97
+ | `AuthProvider`, `useNestAuth`, `useUser`, `useSession`, `useAccessToken`, `useAuthStatus`, `useHasRole`, `useHasPermission`, `useAuthHeaderFn` | Re-exported from the React SDK. |
98
+ | `AuthGuard`, `GuestGuard`, `RequireRole`, `RequirePermission` | Conditional-render guards. |
99
+ | `AuthClient`, `hasRole`, `hasPermission`, … + all `@ackplus/nest-auth-contracts` types | Re-exported from the core client. |
100
+
101
+ ## Social login
102
+
103
+ Acquire the provider token natively (e.g. `@react-native-google-signin/google-signin`, Apple authentication) and pass it to `authClient.socialLogin(provider, token, opts)`.
104
+
105
+ ## Testing
106
+
107
+ This package ships a real, no-mock E2E suite: it spawns a real nest-auth backend and drives the client through signup → login → refresh → logout over HTTP.
108
+
109
+ ```bash
110
+ pnpm -F @ackplus/nest-auth-react-native test
111
+ ```
112
+
113
+ ## License
114
+
115
+ MIT
@@ -0,0 +1,6 @@
1
+ import { AuthClient } from '@ackplus/nest-auth-client';
2
+ import type { AuthClientConfig, StorageAdapter } from '@ackplus/nest-auth-client';
3
+ export interface NestAuthRNConfig extends Omit<AuthClientConfig, 'storage'> {
4
+ storage: StorageAdapter;
5
+ }
6
+ export declare function createNestAuthClient(config: NestAuthRNConfig): AuthClient;
@@ -0,0 +1,8 @@
1
+ import { AuthClient } from '@ackplus/nest-auth-client';
2
+ export function createNestAuthClient(config) {
3
+ return new AuthClient({
4
+ accessTokenType: 'header',
5
+ ...config,
6
+ });
7
+ }
8
+ //# sourceMappingURL=create-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-client.js","sourceRoot":"","sources":["../src/create-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAkCvD,MAAM,UAAU,oBAAoB,CAAC,MAAwB;IACzD,OAAO,IAAI,UAAU,CAAC;QAElB,eAAe,EAAE,QAAQ;QACzB,GAAG,MAAM;KACZ,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,13 @@
1
+ export { AsyncStorageAdapter } from './storage/async-storage.adapter';
2
+ export type { AsyncStorageLike } from './storage/async-storage.adapter';
3
+ export { SecureStoreAdapter } from './storage/secure-store.adapter';
4
+ export type { SecureStoreLike } from './storage/secure-store.adapter';
5
+ export { createNestAuthClient } from './create-client';
6
+ export type { NestAuthRNConfig } from './create-client';
7
+ export { signInWithGoogle, signInWithApple } from './native-signin';
8
+ export type { GoogleSigninLike, AppleAuthLike } from './native-signin';
9
+ export { AuthClient, MemoryStorage, hasRole, hasPermission, hasAnyAccess, hasAllAccess, } from '@ackplus/nest-auth-client';
10
+ export type { AuthClientConfig, StorageAdapter, AccessTokenType, EndpointConfig, } from '@ackplus/nest-auth-client';
11
+ export * from '@ackplus/nest-auth-contracts';
12
+ export { AuthProvider, useNestAuth, useUser, useSession, useAccessToken, useAuthStatus, useHasRole, useHasPermission, useAuthHeaderFn, useAuthHeaderFnSync, AuthGuard, GuestGuard, RequireRole, RequirePermission, } from '@ackplus/nest-auth-react';
13
+ export type { AuthContextValue, AuthProviderProps, AuthStatusResult, } from '@ackplus/nest-auth-react';
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { AsyncStorageAdapter } from './storage/async-storage.adapter';
2
+ export { SecureStoreAdapter } from './storage/secure-store.adapter';
3
+ export { createNestAuthClient } from './create-client';
4
+ export { signInWithGoogle, signInWithApple } from './native-signin';
5
+ export { AuthClient, MemoryStorage, hasRole, hasPermission, hasAnyAccess, hasAllAccess, } from '@ackplus/nest-auth-client';
6
+ export * from '@ackplus/nest-auth-contracts';
7
+ export { AuthProvider, useNestAuth, useUser, useSession, useAccessToken, useAuthStatus, useHasRole, useHasPermission, useAuthHeaderFn, useAuthHeaderFnSync, AuthGuard, GuestGuard, RequireRole, RequirePermission, } from '@ackplus/nest-auth-react';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAIpE,OAAO,EACH,UAAU,EACV,aAAa,EACb,OAAO,EACP,aAAa,EACb,YAAY,EACZ,YAAY,GACf,MAAM,2BAA2B,CAAC;AASnC,cAAc,8BAA8B,CAAC;AAG7C,OAAO,EACH,YAAY,EACZ,WAAW,EACX,OAAO,EACP,UAAU,EACV,cAAc,EACd,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,UAAU,EACV,WAAW,EACX,iBAAiB,GACpB,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { AuthClient, IAuthResponse } from '@ackplus/nest-auth-client';
2
+ export interface GoogleSigninLike {
3
+ hasPlayServices?(options?: unknown): Promise<unknown>;
4
+ signIn(): Promise<unknown>;
5
+ }
6
+ export declare function signInWithGoogle(client: AuthClient, googleSignin: GoogleSigninLike): Promise<IAuthResponse>;
7
+ export interface AppleAuthLike {
8
+ signInAsync(options?: unknown): Promise<unknown>;
9
+ AppleAuthenticationScope?: {
10
+ FULL_NAME: unknown;
11
+ EMAIL: unknown;
12
+ };
13
+ }
14
+ export declare function signInWithApple(client: AuthClient, appleAuth: AppleAuthLike, options?: {
15
+ nonce?: string;
16
+ }): Promise<IAuthResponse>;
@@ -0,0 +1,28 @@
1
+ export async function signInWithGoogle(client, googleSignin) {
2
+ await googleSignin.hasPlayServices?.();
3
+ const result = (await googleSignin.signIn());
4
+ const idToken = result?.data?.idToken ?? result?.idToken ?? result?.user?.idToken;
5
+ if (!idToken) {
6
+ throw new Error('Google Sign-In returned no idToken. Configure the native SDK with your webClientId/serverClientId.');
7
+ }
8
+ return client.socialLogin('google', idToken, { type: 'idToken' });
9
+ }
10
+ export async function signInWithApple(client, appleAuth, options) {
11
+ const requestedScopes = appleAuth.AppleAuthenticationScope
12
+ ? [appleAuth.AppleAuthenticationScope.FULL_NAME, appleAuth.AppleAuthenticationScope.EMAIL]
13
+ : undefined;
14
+ const credential = (await appleAuth.signInAsync({
15
+ requestedScopes,
16
+ nonce: options?.nonce,
17
+ }));
18
+ const identityToken = credential?.identityToken;
19
+ if (!identityToken) {
20
+ throw new Error('Apple Sign-In returned no identityToken.');
21
+ }
22
+ const fullName = credential?.fullName;
23
+ const name = fullName
24
+ ? [fullName.givenName, fullName.familyName].filter(Boolean).join(' ') || undefined
25
+ : undefined;
26
+ return client.socialLogin('apple', identityToken, { nonce: options?.nonce, name });
27
+ }
28
+ //# sourceMappingURL=native-signin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-signin.js","sourceRoot":"","sources":["../src/native-signin.ts"],"names":[],"mappings":"AAmCA,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAClC,MAAkB,EAClB,YAA8B;IAE9B,MAAM,YAAY,CAAC,eAAe,EAAE,EAAE,CAAC;IACvC,MAAM,MAAM,GAAG,CAAC,MAAM,YAAY,CAAC,MAAM,EAAE,CAAQ,CAAC;IAEpD,MAAM,OAAO,GACT,MAAM,EAAE,IAAI,EAAE,OAAO,IAAI,MAAM,EAAE,OAAO,IAAI,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;IACtE,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACX,oGAAoG,CACvG,CAAC;IACN,CAAC;IACD,OAAO,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;AACtE,CAAC;AAqBD,MAAM,CAAC,KAAK,UAAU,eAAe,CACjC,MAAkB,EAClB,SAAwB,EACxB,OAA4B;IAE5B,MAAM,eAAe,GAAG,SAAS,CAAC,wBAAwB;QACtD,CAAC,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,SAAS,EAAE,SAAS,CAAC,wBAAwB,CAAC,KAAK,CAAC;QAC1F,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,UAAU,GAAG,CAAC,MAAM,SAAS,CAAC,WAAW,CAAC;QAC5C,eAAe;QACf,KAAK,EAAE,OAAO,EAAE,KAAK;KACxB,CAAC,CAAQ,CAAC;IAEX,MAAM,aAAa,GAAuB,UAAU,EAAE,aAAa,CAAC;IACpE,IAAI,CAAC,aAAa,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,EAAE,QAAQ,CAAC;IACtC,MAAM,IAAI,GAAG,QAAQ;QACjB,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS;QAClF,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACvF,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { StorageAdapter } from '@ackplus/nest-auth-client';
2
+ export interface AsyncStorageLike {
3
+ getItem(key: string): Promise<string | null>;
4
+ setItem(key: string, value: string): Promise<void>;
5
+ removeItem(key: string): Promise<void>;
6
+ getAllKeys?(): Promise<readonly string[]>;
7
+ multiRemove?(keys: string[]): Promise<void>;
8
+ }
9
+ export declare class AsyncStorageAdapter implements StorageAdapter {
10
+ private readonly storage;
11
+ private readonly prefix;
12
+ constructor(storage: AsyncStorageLike, prefix?: string);
13
+ private k;
14
+ get(key: string): Promise<string | null>;
15
+ set(key: string, value: string): Promise<void>;
16
+ remove(key: string): Promise<void>;
17
+ clear(): Promise<void>;
18
+ }
@@ -0,0 +1,28 @@
1
+ export class AsyncStorageAdapter {
2
+ constructor(storage, prefix = 'nest_auth.') {
3
+ this.storage = storage;
4
+ this.prefix = prefix;
5
+ }
6
+ k(key) {
7
+ return this.prefix + key;
8
+ }
9
+ get(key) {
10
+ return this.storage.getItem(this.k(key));
11
+ }
12
+ async set(key, value) {
13
+ await this.storage.setItem(this.k(key), value);
14
+ }
15
+ async remove(key) {
16
+ await this.storage.removeItem(this.k(key));
17
+ }
18
+ async clear() {
19
+ if (this.storage.getAllKeys && this.storage.multiRemove) {
20
+ const all = await this.storage.getAllKeys();
21
+ const mine = all.filter((k) => k.startsWith(this.prefix));
22
+ if (mine.length) {
23
+ await this.storage.multiRemove(mine);
24
+ }
25
+ }
26
+ }
27
+ }
28
+ //# sourceMappingURL=async-storage.adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-storage.adapter.js","sourceRoot":"","sources":["../../src/storage/async-storage.adapter.ts"],"names":[],"mappings":"AAgCA,MAAM,OAAO,mBAAmB;IAC5B,YACqB,OAAyB,EACzB,SAAS,YAAY;QADrB,YAAO,GAAP,OAAO,CAAkB;QACzB,WAAM,GAAN,MAAM,CAAe;IACvC,CAAC;IAEI,CAAC,CAAC,GAAW;QACjB,OAAO,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;IAC7B,CAAC;IAED,GAAG,CAAC,GAAW;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAa;QAChC,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACpB,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,KAAK;QACP,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YACtD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAC1D,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBACd,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACzC,CAAC;QACL,CAAC;IACL,CAAC;CACJ"}
@@ -0,0 +1,15 @@
1
+ import type { StorageAdapter } from '@ackplus/nest-auth-client';
2
+ export interface SecureStoreLike {
3
+ getItemAsync(key: string): Promise<string | null>;
4
+ setItemAsync(key: string, value: string): Promise<void>;
5
+ deleteItemAsync(key: string): Promise<void>;
6
+ }
7
+ export declare class SecureStoreAdapter implements StorageAdapter {
8
+ private readonly store;
9
+ private readonly prefix;
10
+ constructor(store: SecureStoreLike, prefix?: string);
11
+ private k;
12
+ get(key: string): Promise<string | null>;
13
+ set(key: string, value: string): Promise<void>;
14
+ remove(key: string): Promise<void>;
15
+ }
@@ -0,0 +1,19 @@
1
+ export class SecureStoreAdapter {
2
+ constructor(store, prefix = 'nest_auth.') {
3
+ this.store = store;
4
+ this.prefix = prefix;
5
+ }
6
+ k(key) {
7
+ return this.prefix + key;
8
+ }
9
+ get(key) {
10
+ return this.store.getItemAsync(this.k(key));
11
+ }
12
+ async set(key, value) {
13
+ await this.store.setItemAsync(this.k(key), value);
14
+ }
15
+ async remove(key) {
16
+ await this.store.deleteItemAsync(this.k(key));
17
+ }
18
+ }
19
+ //# sourceMappingURL=secure-store.adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-store.adapter.js","sourceRoot":"","sources":["../../src/storage/secure-store.adapter.ts"],"names":[],"mappings":"AA+BA,MAAM,OAAO,kBAAkB;IAC3B,YACqB,KAAsB,EACtB,SAAS,YAAY;QADrB,UAAK,GAAL,KAAK,CAAiB;QACtB,WAAM,GAAN,MAAM,CAAe;IACvC,CAAC;IAEI,CAAC,CAAC,GAAW;QACjB,OAAO,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;IAC7B,CAAC;IAED,GAAG,CAAC,GAAW;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAa;QAChC,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACpB,MAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;CACJ"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@ackplus/nest-auth-react-native",
3
+ "version": "2.0.1",
4
+ "description": "React Native / Expo SDK for NestJS authentication - hooks, guards, and secure token storage",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "keywords": [
22
+ "auth",
23
+ "authentication",
24
+ "react-native",
25
+ "expo",
26
+ "hooks",
27
+ "nestjs",
28
+ "jwt",
29
+ "oauth",
30
+ "asyncstorage"
31
+ ],
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/ack-solutions/nest-auth"
35
+ },
36
+ "license": "MIT",
37
+ "author": "Ackplus",
38
+ "peerDependencies": {
39
+ "react": "^18.0.0 || ^19.0.0"
40
+ },
41
+ "dependencies": {
42
+ "@ackplus/nest-auth-client": "2.0.1",
43
+ "@ackplus/nest-auth-react": "2.0.1",
44
+ "@ackplus/nest-auth-contracts": "2.0.1"
45
+ },
46
+ "devDependencies": {
47
+ "typescript": "^5.7.3",
48
+ "@types/react": "^18.0.0",
49
+ "vitest": "^3.0.0",
50
+ "jsonwebtoken": "^9.0.0",
51
+ "@types/jsonwebtoken": "^9.0.5"
52
+ },
53
+ "scripts": {
54
+ "clean": "rm -rf dist tsconfig.build.tsbuildinfo",
55
+ "build": "pnpm clean && tsc -p tsconfig.build.json",
56
+ "test": "vitest run",
57
+ "typecheck": "tsc -p tsconfig.json --noEmit"
58
+ }
59
+ }