delta-auth-next 0.1.0
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/dist/DeltaProvider.d.ts +9 -0
- package/dist/DeltaProvider.d.ts.map +1 -0
- package/dist/DeltaProvider.js +78 -0
- package/dist/DeltaProvider.js.map +1 -0
- package/dist/client/authClient.d.ts +4 -0
- package/dist/client/authClient.d.ts.map +1 -0
- package/dist/client/authClient.js +11 -0
- package/dist/client/authClient.js.map +1 -0
- package/dist/context.d.ts +11 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +11 -0
- package/dist/context.js.map +1 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +7 -0
- package/dist/hooks.js.map +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +26 -0
- package/src/DeltaProvider.tsx +100 -0
- package/src/client/authClient.ts +13 -0
- package/src/context.ts +21 -0
- package/src/hooks.ts +7 -0
- package/src/types.ts +24 -0
- package/tsconfig.json +37 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DeltaAuthConfig } from './types';
|
|
3
|
+
interface Props {
|
|
4
|
+
config: DeltaAuthConfig;
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare function DeltaAuthProvider({ config, children }: Props): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=DeltaProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeltaProvider.d.ts","sourceRoot":"","sources":["../src/DeltaProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAGhE,OAAO,EAAE,eAAe,EAAiB,MAAM,SAAS,CAAC;AAGzD,UAAU,KAAK;IACb,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,KAAK,2CAsF5D"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// src/DeltaAuthProvider.tsx
|
|
2
|
+
'use client';
|
|
3
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
4
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
5
|
+
import { AuthContext } from './context';
|
|
6
|
+
import { createAuthClient } from './client/authClient';
|
|
7
|
+
import toast from 'react-hot-toast';
|
|
8
|
+
export function DeltaAuthProvider({ config, children }) {
|
|
9
|
+
if (!config?.publishableKey)
|
|
10
|
+
throw new Error('DeltaAuth: publishableKey is required');
|
|
11
|
+
const [session, setSession] = useState(null);
|
|
12
|
+
const [loading, setLoading] = useState(true);
|
|
13
|
+
const client = createAuthClient(config.backendUrl ? { backendUrl: config.backendUrl } : {});
|
|
14
|
+
// 🔹 Fetch current session
|
|
15
|
+
const fetchSession = useCallback(async () => {
|
|
16
|
+
try {
|
|
17
|
+
const res = await client.get('/auth/me'); // cookie-based
|
|
18
|
+
if (res.data?.data?.user) {
|
|
19
|
+
setSession(res.data.data);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
setSession(null);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
setSession(null);
|
|
27
|
+
if (config.showAlerts ?? true) {
|
|
28
|
+
toast.error(err.response?.data?.error ?? 'Auth failed');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
setLoading(false);
|
|
33
|
+
}
|
|
34
|
+
}, [client, config.showAlerts]);
|
|
35
|
+
// 🔹 Fetch detailed user info
|
|
36
|
+
const fetchUserDetails = useCallback(async () => {
|
|
37
|
+
if (!session?.user)
|
|
38
|
+
return null;
|
|
39
|
+
try {
|
|
40
|
+
const res = await client.get(`/users/${session.user.id}`);
|
|
41
|
+
setSession((prev) => (prev ? { ...prev, user: res.data } : null));
|
|
42
|
+
return res.data;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return session.user; // fallback
|
|
46
|
+
}
|
|
47
|
+
}, [client, session]);
|
|
48
|
+
// 🔹 Bootstrap session
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
// block test/live key misuse
|
|
51
|
+
const isLocalhost = typeof window !== 'undefined' &&
|
|
52
|
+
window.location.hostname.includes('localhost');
|
|
53
|
+
const isProd = typeof window !== 'undefined' && window.location.protocol === 'https:';
|
|
54
|
+
if (isLocalhost && config.publishableKey.startsWith('pk_live')) {
|
|
55
|
+
throw new Error('Cannot use live key on localhost');
|
|
56
|
+
}
|
|
57
|
+
if (isProd && config.publishableKey.startsWith('pk_test')) {
|
|
58
|
+
throw new Error('Cannot use test key in production');
|
|
59
|
+
}
|
|
60
|
+
fetchSession();
|
|
61
|
+
}, [fetchSession, config.publishableKey]);
|
|
62
|
+
// 🔹 Auto refresh
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (!config.autoRefresh)
|
|
65
|
+
return;
|
|
66
|
+
const interval = setInterval(fetchSession, config.refreshInterval ?? 5 * 60 * 1000);
|
|
67
|
+
return () => clearInterval(interval);
|
|
68
|
+
}, [fetchSession, config.autoRefresh, config.refreshInterval]);
|
|
69
|
+
return (_jsx(AuthContext.Provider, { value: {
|
|
70
|
+
session,
|
|
71
|
+
user: session?.user ?? null,
|
|
72
|
+
loading,
|
|
73
|
+
isAuthenticated: !!session,
|
|
74
|
+
client,
|
|
75
|
+
fetchUser: fetchUserDetails,
|
|
76
|
+
}, children: children }));
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=DeltaProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeltaProvider.js","sourceRoot":"","sources":["../src/DeltaProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authClient.d.ts","sourceRoot":"","sources":["../../src/client/authClient.ts"],"names":[],"mappings":"AAGA,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,iCAS/D"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/client/authClient.ts
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
export function createAuthClient(config) {
|
|
4
|
+
const baseURL = config.backendUrl ?? '/api';
|
|
5
|
+
const client = axios.create({
|
|
6
|
+
baseURL,
|
|
7
|
+
withCredentials: true, // send cookies
|
|
8
|
+
});
|
|
9
|
+
return client;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=authClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authClient.js","sourceRoot":"","sources":["../../src/client/authClient.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,gBAAgB,CAAC,MAA+B;IAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC;IAE5C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC1B,OAAO;QACP,eAAe,EAAE,IAAI,EAAE,eAAe;KACvC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Session, User } from './types';
|
|
2
|
+
export interface AuthContextValue {
|
|
3
|
+
session: Session | null;
|
|
4
|
+
user: User | null;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
isAuthenticated: boolean;
|
|
7
|
+
client: ReturnType<typeof import('./client/authClient').createAuthClient>;
|
|
8
|
+
fetchUser: () => Promise<User | null>;
|
|
9
|
+
}
|
|
10
|
+
export declare const AuthContext: import("react").Context<AuthContextValue>;
|
|
11
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,UAAU,CAAC,cAAc,qBAAqB,EAAE,gBAAgB,CAAC,CAAC;IAC1E,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;CACvC;AAED,eAAO,MAAM,WAAW,2CAOtB,CAAC"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/context.ts
|
|
2
|
+
import { createContext } from 'react';
|
|
3
|
+
export const AuthContext = createContext({
|
|
4
|
+
session: null,
|
|
5
|
+
user: null,
|
|
6
|
+
loading: true,
|
|
7
|
+
isAuthenticated: false,
|
|
8
|
+
client: {},
|
|
9
|
+
fetchUser: async () => null,
|
|
10
|
+
});
|
|
11
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAYtC,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAmB;IACzD,OAAO,EAAE,IAAI;IACb,IAAI,EAAE,IAAI;IACV,OAAO,EAAE,IAAI;IACb,eAAe,EAAE,KAAK;IACtB,MAAM,EAAE,EAAS;IACjB,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI;CAC5B,CAAC,CAAC"}
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAIA,wBAAgB,YAAY,yCAE3B"}
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,UAAU,YAAY;IAC1B,OAAO,UAAU,CAAC,WAAW,CAAC,CAAC;AACjC,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface DeltaAuthConfig {
|
|
2
|
+
publishableKey: string;
|
|
3
|
+
autoRefresh?: boolean;
|
|
4
|
+
refreshInterval?: number;
|
|
5
|
+
showAlerts?: boolean;
|
|
6
|
+
backendUrl?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface User {
|
|
9
|
+
id: string;
|
|
10
|
+
email: string;
|
|
11
|
+
first_name: string;
|
|
12
|
+
last_name: string;
|
|
13
|
+
role: string;
|
|
14
|
+
public_metadata?: Record<string, any>;
|
|
15
|
+
}
|
|
16
|
+
export interface Session {
|
|
17
|
+
access_token: string;
|
|
18
|
+
refresh_token: string;
|
|
19
|
+
expires_at: string;
|
|
20
|
+
user: User;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,OAAO;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,IAAI,CAAC;CACZ"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "delta-auth-next",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"prepare": "npm run build"
|
|
9
|
+
},
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"react": "^18.2.0 || ^19.0.0",
|
|
12
|
+
"react-dom": "^18.2.0 || ^19.0.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "^25.2.0",
|
|
16
|
+
"@types/react": "^19.2.10",
|
|
17
|
+
"@types/react-dom": "^19.2.3",
|
|
18
|
+
"@types/uuid": "^10.0.0",
|
|
19
|
+
"typescript": "^5.9.3"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"axios": "^1.13.4",
|
|
23
|
+
"react-hot-toast": "^2.6.0",
|
|
24
|
+
"uuid": "^13.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// src/DeltaAuthProvider.tsx
|
|
2
|
+
'use client';
|
|
3
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
|
4
|
+
import { AuthContext } from './context';
|
|
5
|
+
import { createAuthClient } from './client/authClient';
|
|
6
|
+
import { DeltaAuthConfig, Session, User } from './types';
|
|
7
|
+
import toast from 'react-hot-toast';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
config: DeltaAuthConfig;
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function DeltaAuthProvider({ config, children }: Props) {
|
|
15
|
+
if (!config?.publishableKey)
|
|
16
|
+
throw new Error('DeltaAuth: publishableKey is required');
|
|
17
|
+
|
|
18
|
+
const [session, setSession] = useState<Session | null>(null);
|
|
19
|
+
const [loading, setLoading] = useState(true);
|
|
20
|
+
|
|
21
|
+
const client = createAuthClient(
|
|
22
|
+
config.backendUrl ? { backendUrl: config.backendUrl } : {}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
// 🔹 Fetch current session
|
|
27
|
+
const fetchSession = useCallback(async () => {
|
|
28
|
+
try {
|
|
29
|
+
const res = await client.get('/auth/me'); // cookie-based
|
|
30
|
+
if (res.data?.data?.user) {
|
|
31
|
+
setSession(res.data.data);
|
|
32
|
+
} else {
|
|
33
|
+
setSession(null);
|
|
34
|
+
}
|
|
35
|
+
} catch (err: any) {
|
|
36
|
+
setSession(null);
|
|
37
|
+
if (config.showAlerts ?? true) {
|
|
38
|
+
toast.error(err.response?.data?.error ?? 'Auth failed');
|
|
39
|
+
}
|
|
40
|
+
} finally {
|
|
41
|
+
setLoading(false);
|
|
42
|
+
}
|
|
43
|
+
}, [client, config.showAlerts]);
|
|
44
|
+
|
|
45
|
+
// 🔹 Fetch detailed user info
|
|
46
|
+
const fetchUserDetails = useCallback(async () => {
|
|
47
|
+
if (!session?.user) return null;
|
|
48
|
+
try {
|
|
49
|
+
const res = await client.get(`/users/${session.user.id}`);
|
|
50
|
+
setSession((prev) => (prev ? { ...prev, user: res.data } : null));
|
|
51
|
+
return res.data as User;
|
|
52
|
+
} catch {
|
|
53
|
+
return session.user; // fallback
|
|
54
|
+
}
|
|
55
|
+
}, [client, session]);
|
|
56
|
+
|
|
57
|
+
// 🔹 Bootstrap session
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
// block test/live key misuse
|
|
60
|
+
const isLocalhost =
|
|
61
|
+
typeof window !== 'undefined' &&
|
|
62
|
+
window.location.hostname.includes('localhost');
|
|
63
|
+
const isProd =
|
|
64
|
+
typeof window !== 'undefined' && window.location.protocol === 'https:';
|
|
65
|
+
|
|
66
|
+
if (isLocalhost && config.publishableKey.startsWith('pk_live')) {
|
|
67
|
+
throw new Error('Cannot use live key on localhost');
|
|
68
|
+
}
|
|
69
|
+
if (isProd && config.publishableKey.startsWith('pk_test')) {
|
|
70
|
+
throw new Error('Cannot use test key in production');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fetchSession();
|
|
74
|
+
}, [fetchSession, config.publishableKey]);
|
|
75
|
+
|
|
76
|
+
// 🔹 Auto refresh
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (!config.autoRefresh) return;
|
|
79
|
+
const interval = setInterval(
|
|
80
|
+
fetchSession,
|
|
81
|
+
config.refreshInterval ?? 5 * 60 * 1000
|
|
82
|
+
);
|
|
83
|
+
return () => clearInterval(interval);
|
|
84
|
+
}, [fetchSession, config.autoRefresh, config.refreshInterval]);
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<AuthContext.Provider
|
|
88
|
+
value={{
|
|
89
|
+
session,
|
|
90
|
+
user: session?.user ?? null,
|
|
91
|
+
loading,
|
|
92
|
+
isAuthenticated: !!session,
|
|
93
|
+
client,
|
|
94
|
+
fetchUser: fetchUserDetails,
|
|
95
|
+
}}
|
|
96
|
+
>
|
|
97
|
+
{children}
|
|
98
|
+
</AuthContext.Provider>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// src/client/authClient.ts
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
|
|
4
|
+
export function createAuthClient(config: { backendUrl?: string }) {
|
|
5
|
+
const baseURL = config.backendUrl ?? '/api';
|
|
6
|
+
|
|
7
|
+
const client = axios.create({
|
|
8
|
+
baseURL,
|
|
9
|
+
withCredentials: true, // send cookies
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
return client;
|
|
13
|
+
}
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/context.ts
|
|
2
|
+
import { createContext } from 'react';
|
|
3
|
+
import { Session, User } from './types';
|
|
4
|
+
|
|
5
|
+
export interface AuthContextValue {
|
|
6
|
+
session: Session | null;
|
|
7
|
+
user: User | null;
|
|
8
|
+
loading: boolean;
|
|
9
|
+
isAuthenticated: boolean;
|
|
10
|
+
client: ReturnType<typeof import('./client/authClient').createAuthClient>;
|
|
11
|
+
fetchUser: () => Promise<User | null>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const AuthContext = createContext<AuthContextValue>({
|
|
15
|
+
session: null,
|
|
16
|
+
user: null,
|
|
17
|
+
loading: true,
|
|
18
|
+
isAuthenticated: false,
|
|
19
|
+
client: {} as any,
|
|
20
|
+
fetchUser: async () => null,
|
|
21
|
+
});
|
package/src/hooks.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
export interface DeltaAuthConfig {
|
|
3
|
+
publishableKey: string;
|
|
4
|
+
autoRefresh?: boolean;
|
|
5
|
+
refreshInterval?: number; // ms
|
|
6
|
+
showAlerts?: boolean; // toggle alerts
|
|
7
|
+
backendUrl?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface User {
|
|
11
|
+
id: string;
|
|
12
|
+
email: string;
|
|
13
|
+
first_name: string;
|
|
14
|
+
last_name: string;
|
|
15
|
+
role: string;
|
|
16
|
+
public_metadata?: Record<string, any>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface Session {
|
|
20
|
+
access_token: string;
|
|
21
|
+
refresh_token: string;
|
|
22
|
+
expires_at: string;
|
|
23
|
+
user: User;
|
|
24
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Input / Output
|
|
4
|
+
"rootDir": "src",
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationMap": true,
|
|
8
|
+
"sourceMap": true,
|
|
9
|
+
|
|
10
|
+
// Module / Target
|
|
11
|
+
"module": "ESNext",
|
|
12
|
+
"target": "ES2022",
|
|
13
|
+
"moduleResolution": "node",
|
|
14
|
+
|
|
15
|
+
// JSX support
|
|
16
|
+
"jsx": "react-jsx",
|
|
17
|
+
|
|
18
|
+
// Type Checking
|
|
19
|
+
"strict": true,
|
|
20
|
+
"noImplicitAny": true,
|
|
21
|
+
"exactOptionalPropertyTypes": true,
|
|
22
|
+
"noUncheckedIndexedAccess": true,
|
|
23
|
+
"isolatedModules": true,
|
|
24
|
+
|
|
25
|
+
// Skip library type checks for faster compilation
|
|
26
|
+
"skipLibCheck": true,
|
|
27
|
+
|
|
28
|
+
// Types
|
|
29
|
+
"types": ["node", "react", "react-dom"],
|
|
30
|
+
|
|
31
|
+
// Helps with ES modules and npm publishing
|
|
32
|
+
"esModuleInterop": true,
|
|
33
|
+
"forceConsistentCasingInFileNames": true
|
|
34
|
+
},
|
|
35
|
+
"include": ["src"],
|
|
36
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
|
|
37
|
+
}
|