@microcosmmoney/auth-react 1.0.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/callback.d.ts +10 -0
- package/dist/callback.js +60 -0
- package/dist/hooks/use-api-query.d.ts +14 -0
- package/dist/hooks/use-api-query.js +50 -0
- package/dist/hooks/use-auctions.d.ts +3 -0
- package/dist/hooks/use-auctions.js +11 -0
- package/dist/hooks/use-dashboard-summary.d.ts +23 -0
- package/dist/hooks/use-dashboard-summary.js +53 -0
- package/dist/hooks/use-mcc-price.d.ts +12 -0
- package/dist/hooks/use-mcc-price.js +11 -0
- package/dist/hooks/use-mcc-stats.d.ts +3 -0
- package/dist/hooks/use-mcc-stats.js +11 -0
- package/dist/hooks/use-mcc.d.ts +10 -0
- package/dist/hooks/use-mcc.js +47 -0
- package/dist/hooks/use-mcd-stats.d.ts +3 -0
- package/dist/hooks/use-mcd-stats.js +11 -0
- package/dist/hooks/use-mcd.d.ts +9 -0
- package/dist/hooks/use-mcd.js +40 -0
- package/dist/hooks/use-mining-records.d.ts +4 -0
- package/dist/hooks/use-mining-records.js +13 -0
- package/dist/hooks/use-mining-stats.d.ts +3 -0
- package/dist/hooks/use-mining-stats.js +12 -0
- package/dist/hooks/use-organizations.d.ts +3 -0
- package/dist/hooks/use-organizations.js +12 -0
- package/dist/hooks/use-price-history.d.ts +5 -0
- package/dist/hooks/use-price-history.js +11 -0
- package/dist/hooks/use-profile.d.ts +13 -0
- package/dist/hooks/use-profile.js +102 -0
- package/dist/hooks/use-reincarnation-pool.d.ts +10 -0
- package/dist/hooks/use-reincarnation-pool.js +11 -0
- package/dist/hooks/use-tech-tree.d.ts +3 -0
- package/dist/hooks/use-tech-tree.js +12 -0
- package/dist/hooks/use-territory-nfts.d.ts +3 -0
- package/dist/hooks/use-territory-nfts.js +12 -0
- package/dist/hooks/use-user-level.d.ts +10 -0
- package/dist/hooks/use-user-level.js +12 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +47 -0
- package/dist/provider.d.ts +13 -0
- package/dist/provider.js +54 -0
- package/dist/require-role.d.ts +8 -0
- package/dist/require-role.js +12 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +7 -0
- package/dist/server/token-exchange.d.ts +12 -0
- package/dist/server/token-exchange.js +112 -0
- package/dist/with-auth.d.ts +10 -0
- package/dist/with-auth.js +23 -0
- package/package.json +39 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface AuthCallbackProps {
|
|
3
|
+
redirectTo?: string;
|
|
4
|
+
onSuccess?: (user: unknown) => void;
|
|
5
|
+
onError?: (error: Error) => void;
|
|
6
|
+
loadingComponent?: React.ReactNode;
|
|
7
|
+
errorComponent?: (error: Error) => React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export declare function AuthCallback({ redirectTo, onSuccess, onError, loadingComponent, errorComponent, }: AuthCallbackProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
package/dist/callback.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthCallback = AuthCallback;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
// AI-generated · AI-managed · AI-maintained
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const provider_1 = require("./provider");
|
|
8
|
+
function AuthCallback({ redirectTo = '/dashboard', onSuccess, onError, loadingComponent, errorComponent, }) {
|
|
9
|
+
const { client } = (0, provider_1.useAuth)();
|
|
10
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
11
|
+
(0, react_1.useEffect)(() => {
|
|
12
|
+
let cancelled = false;
|
|
13
|
+
const handleCallback = async () => {
|
|
14
|
+
try {
|
|
15
|
+
const user = await client.handleCallback();
|
|
16
|
+
if (cancelled)
|
|
17
|
+
return;
|
|
18
|
+
onSuccess?.(user);
|
|
19
|
+
window.location.href = redirectTo;
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
if (cancelled)
|
|
23
|
+
return;
|
|
24
|
+
const error = err instanceof Error ? err : new Error('Unknown error');
|
|
25
|
+
setError(error);
|
|
26
|
+
onError?.(error);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
handleCallback();
|
|
30
|
+
return () => {
|
|
31
|
+
cancelled = true;
|
|
32
|
+
};
|
|
33
|
+
}, []);
|
|
34
|
+
if (error) {
|
|
35
|
+
if (errorComponent) {
|
|
36
|
+
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: errorComponent(error) });
|
|
37
|
+
}
|
|
38
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: { padding: 40, textAlign: 'center', fontFamily: 'monospace' }, children: [(0, jsx_runtime_1.jsx)("h2", { style: { color: '#ef4444', marginBottom: 8 }, children: "Login Failed" }), (0, jsx_runtime_1.jsx)("p", { style: { color: '#71717a', marginBottom: 16 }, children: error.message }), (0, jsx_runtime_1.jsx)("button", { onClick: () => (window.location.href = '/'), style: {
|
|
39
|
+
padding: '8px 16px',
|
|
40
|
+
border: '1px solid #3f3f46',
|
|
41
|
+
borderRadius: 4,
|
|
42
|
+
background: 'transparent',
|
|
43
|
+
color: '#a1a1aa',
|
|
44
|
+
cursor: 'pointer',
|
|
45
|
+
fontFamily: 'monospace',
|
|
46
|
+
}, children: "Back to Home" })] }));
|
|
47
|
+
}
|
|
48
|
+
if (loadingComponent) {
|
|
49
|
+
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: loadingComponent });
|
|
50
|
+
}
|
|
51
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: { padding: 40, textAlign: 'center', fontFamily: 'monospace' }, children: [(0, jsx_runtime_1.jsx)("div", { style: {
|
|
52
|
+
width: 32,
|
|
53
|
+
height: 32,
|
|
54
|
+
border: '2px solid #6366f1',
|
|
55
|
+
borderTopColor: 'transparent',
|
|
56
|
+
borderRadius: '50%',
|
|
57
|
+
animation: 'mc-spin 1s linear infinite',
|
|
58
|
+
margin: '0 auto 16px',
|
|
59
|
+
} }), (0, jsx_runtime_1.jsx)("p", { style: { color: '#71717a' }, children: "Processing login..." }), (0, jsx_runtime_1.jsx)("style", { children: `@keyframes mc-spin { to { transform: rotate(360deg) } }` })] }));
|
|
60
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface UseApiQueryOptions {
|
|
2
|
+
path: string;
|
|
3
|
+
requireAuth?: boolean;
|
|
4
|
+
refetchInterval?: number;
|
|
5
|
+
skip?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface UseApiQueryResult<T> {
|
|
8
|
+
data: T | null;
|
|
9
|
+
loading: boolean;
|
|
10
|
+
error: Error | null;
|
|
11
|
+
refresh: () => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export declare function useApiQuery<T = any>(options: UseApiQueryOptions): UseApiQueryResult<T>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useApiQuery = useApiQuery;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const provider_1 = require("../provider");
|
|
7
|
+
function useApiQuery(options) {
|
|
8
|
+
const { client, isAuthenticated } = (0, provider_1.useAuth)();
|
|
9
|
+
const [data, setData] = (0, react_1.useState)(null);
|
|
10
|
+
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
11
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
12
|
+
const mountedRef = (0, react_1.useRef)(true);
|
|
13
|
+
const shouldSkip = options.skip || (options.requireAuth && !isAuthenticated);
|
|
14
|
+
const fetchData = (0, react_1.useCallback)(async () => {
|
|
15
|
+
if (shouldSkip) {
|
|
16
|
+
setData(null);
|
|
17
|
+
setLoading(false);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const api = client.getApiClient();
|
|
21
|
+
try {
|
|
22
|
+
setLoading(true);
|
|
23
|
+
const res = await api.get(options.path);
|
|
24
|
+
if (mountedRef.current) {
|
|
25
|
+
setData(res.data);
|
|
26
|
+
setError(null);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
if (mountedRef.current) {
|
|
31
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
if (mountedRef.current)
|
|
36
|
+
setLoading(false);
|
|
37
|
+
}
|
|
38
|
+
}, [client, options.path, shouldSkip]);
|
|
39
|
+
(0, react_1.useEffect)(() => {
|
|
40
|
+
mountedRef.current = true;
|
|
41
|
+
fetchData();
|
|
42
|
+
const interval = options.refetchInterval;
|
|
43
|
+
if (interval && interval > 0 && !shouldSkip) {
|
|
44
|
+
const timer = setInterval(fetchData, interval);
|
|
45
|
+
return () => { mountedRef.current = false; clearInterval(timer); };
|
|
46
|
+
}
|
|
47
|
+
return () => { mountedRef.current = false; };
|
|
48
|
+
}, [fetchData, options.refetchInterval, shouldSkip]);
|
|
49
|
+
return { data, loading, error, refresh: fetchData };
|
|
50
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useAuctions = useAuctions;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function useAuctions(options) {
|
|
7
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
8
|
+
path: '/auction-solana/active',
|
|
9
|
+
refetchInterval: options?.refetchInterval ?? 60000,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface DashboardSummary {
|
|
2
|
+
market: {
|
|
3
|
+
price_usd: number;
|
|
4
|
+
price_change_24h: number;
|
|
5
|
+
volume_24h: number;
|
|
6
|
+
liquidity_usd: number;
|
|
7
|
+
fdv: number;
|
|
8
|
+
market_cap: number;
|
|
9
|
+
} | null;
|
|
10
|
+
user: {
|
|
11
|
+
level: any;
|
|
12
|
+
mcc_balance: any;
|
|
13
|
+
} | null;
|
|
14
|
+
}
|
|
15
|
+
export declare function useDashboardSummary(wallet?: string, options?: {
|
|
16
|
+
refetchInterval?: number;
|
|
17
|
+
}): {
|
|
18
|
+
data: DashboardSummary | null;
|
|
19
|
+
loading: boolean;
|
|
20
|
+
error: Error | null;
|
|
21
|
+
refresh: () => Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useDashboardSummary = useDashboardSummary;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const provider_1 = require("../provider");
|
|
7
|
+
function useDashboardSummary(wallet, options) {
|
|
8
|
+
const { client, isAuthenticated } = (0, provider_1.useAuth)();
|
|
9
|
+
const [data, setData] = (0, react_1.useState)(null);
|
|
10
|
+
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
11
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
12
|
+
const mountedRef = (0, react_1.useRef)(true);
|
|
13
|
+
const fetchData = (0, react_1.useCallback)(async () => {
|
|
14
|
+
const api = client.getApiClient();
|
|
15
|
+
try {
|
|
16
|
+
setLoading(true);
|
|
17
|
+
const promises = [
|
|
18
|
+
api.get('/dashboard/market').catch(() => null),
|
|
19
|
+
];
|
|
20
|
+
if (wallet) {
|
|
21
|
+
promises.push(api.get(`/dashboard/user/${wallet}`).catch(() => null));
|
|
22
|
+
}
|
|
23
|
+
const [marketRes, userRes] = await Promise.all(promises);
|
|
24
|
+
if (mountedRef.current) {
|
|
25
|
+
setData({
|
|
26
|
+
market: marketRes?.data ?? null,
|
|
27
|
+
user: userRes?.data ?? null,
|
|
28
|
+
});
|
|
29
|
+
setError(null);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
if (mountedRef.current) {
|
|
34
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
if (mountedRef.current)
|
|
39
|
+
setLoading(false);
|
|
40
|
+
}
|
|
41
|
+
}, [client, wallet]);
|
|
42
|
+
(0, react_1.useEffect)(() => {
|
|
43
|
+
mountedRef.current = true;
|
|
44
|
+
fetchData();
|
|
45
|
+
const interval = options?.refetchInterval ?? 120000;
|
|
46
|
+
if (interval > 0) {
|
|
47
|
+
const timer = setInterval(fetchData, interval);
|
|
48
|
+
return () => { mountedRef.current = false; clearInterval(timer); };
|
|
49
|
+
}
|
|
50
|
+
return () => { mountedRef.current = false; };
|
|
51
|
+
}, [fetchData, options?.refetchInterval]);
|
|
52
|
+
return { data, loading, error, refresh: fetchData };
|
|
53
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface MCCPriceData {
|
|
2
|
+
price: number;
|
|
3
|
+
price_change_24h?: number;
|
|
4
|
+
volume_24h?: number;
|
|
5
|
+
market_cap?: number;
|
|
6
|
+
source: string;
|
|
7
|
+
updated_at: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function useMCCPrice(options?: {
|
|
10
|
+
refetchInterval?: number;
|
|
11
|
+
}): import("./use-api-query").UseApiQueryResult<MCCPriceData>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useMCCPrice = useMCCPrice;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function useMCCPrice(options) {
|
|
7
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
8
|
+
path: '/mcc/price',
|
|
9
|
+
refetchInterval: options?.refetchInterval ?? 30000,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useMCCStats = useMCCStats;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function useMCCStats(options) {
|
|
7
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
8
|
+
path: '/mcc/stats',
|
|
9
|
+
refetchInterval: options?.refetchInterval ?? 300000,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { MCCBalance, MCCPrice } from '@microcosmmoney/auth-core';
|
|
2
|
+
interface UseMCCResult {
|
|
3
|
+
balance: MCCBalance | null;
|
|
4
|
+
price: MCCPrice | null;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
error: Error | null;
|
|
7
|
+
refresh: () => Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare function useMCC(refreshInterval?: number): UseMCCResult;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useMCC = useMCC;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const provider_1 = require("../provider");
|
|
7
|
+
function useMCC(refreshInterval) {
|
|
8
|
+
const { client, isAuthenticated } = (0, provider_1.useAuth)();
|
|
9
|
+
const [balance, setBalance] = (0, react_1.useState)(null);
|
|
10
|
+
const [price, setPrice] = (0, react_1.useState)(null);
|
|
11
|
+
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
12
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
13
|
+
const fetchData = (0, react_1.useCallback)(async () => {
|
|
14
|
+
const api = client.getApiClient();
|
|
15
|
+
try {
|
|
16
|
+
setLoading(true);
|
|
17
|
+
const pricePromise = api.get('/mcc/price')
|
|
18
|
+
.then(res => setPrice(res.data))
|
|
19
|
+
.catch(() => { });
|
|
20
|
+
if (isAuthenticated) {
|
|
21
|
+
const balancePromise = api.get('/mcc/balance')
|
|
22
|
+
.then(res => setBalance(res.data))
|
|
23
|
+
.catch(() => { });
|
|
24
|
+
await Promise.all([pricePromise, balancePromise]);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
await pricePromise;
|
|
28
|
+
setBalance(null);
|
|
29
|
+
}
|
|
30
|
+
setError(null);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
setError(err instanceof Error ? err : new Error('Failed to fetch MCC data'));
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
setLoading(false);
|
|
37
|
+
}
|
|
38
|
+
}, [client, isAuthenticated]);
|
|
39
|
+
(0, react_1.useEffect)(() => {
|
|
40
|
+
fetchData();
|
|
41
|
+
if (refreshInterval && refreshInterval > 0) {
|
|
42
|
+
const timer = setInterval(fetchData, refreshInterval);
|
|
43
|
+
return () => clearInterval(timer);
|
|
44
|
+
}
|
|
45
|
+
}, [fetchData, refreshInterval]);
|
|
46
|
+
return { balance, price, loading, error, refresh: fetchData };
|
|
47
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useMCDStats = useMCDStats;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function useMCDStats(options) {
|
|
7
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
8
|
+
path: '/mcd/stats',
|
|
9
|
+
refetchInterval: options?.refetchInterval ?? 300000,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MCDBalance } from '@microcosmmoney/auth-core';
|
|
2
|
+
interface UseMCDResult {
|
|
3
|
+
balance: MCDBalance | null;
|
|
4
|
+
loading: boolean;
|
|
5
|
+
error: Error | null;
|
|
6
|
+
refresh: () => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export declare function useMCD(refreshInterval?: number): UseMCDResult;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useMCD = useMCD;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const provider_1 = require("../provider");
|
|
7
|
+
function useMCD(refreshInterval) {
|
|
8
|
+
const { client, isAuthenticated } = (0, provider_1.useAuth)();
|
|
9
|
+
const [balance, setBalance] = (0, react_1.useState)(null);
|
|
10
|
+
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
11
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
12
|
+
const fetchBalance = (0, react_1.useCallback)(async () => {
|
|
13
|
+
if (!isAuthenticated) {
|
|
14
|
+
setBalance(null);
|
|
15
|
+
setLoading(false);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
setLoading(true);
|
|
20
|
+
const api = client.getApiClient();
|
|
21
|
+
const data = await api.get('/mcd/balance');
|
|
22
|
+
setBalance(data.data?.attributes || null);
|
|
23
|
+
setError(null);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
setError(err instanceof Error ? err : new Error('Failed to fetch MCD balance'));
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
setLoading(false);
|
|
30
|
+
}
|
|
31
|
+
}, [client, isAuthenticated]);
|
|
32
|
+
(0, react_1.useEffect)(() => {
|
|
33
|
+
fetchBalance();
|
|
34
|
+
if (refreshInterval && refreshInterval > 0) {
|
|
35
|
+
const timer = setInterval(fetchBalance, refreshInterval);
|
|
36
|
+
return () => clearInterval(timer);
|
|
37
|
+
}
|
|
38
|
+
}, [fetchBalance, refreshInterval]);
|
|
39
|
+
return { balance, loading, error, refresh: fetchBalance };
|
|
40
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useMiningRecords = useMiningRecords;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function useMiningRecords(options) {
|
|
7
|
+
const limit = options?.limit ?? 20;
|
|
8
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
9
|
+
path: `/mining/records?limit=${limit}`,
|
|
10
|
+
requireAuth: true,
|
|
11
|
+
refetchInterval: options?.refetchInterval ?? 0,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useMiningStats = useMiningStats;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function useMiningStats(options) {
|
|
7
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
8
|
+
path: '/mining/stats',
|
|
9
|
+
requireAuth: true,
|
|
10
|
+
refetchInterval: options?.refetchInterval ?? 120000,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useOrganizations = useOrganizations;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function useOrganizations(options) {
|
|
7
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
8
|
+
path: '/organizations',
|
|
9
|
+
requireAuth: true,
|
|
10
|
+
refetchInterval: options?.refetchInterval ?? 120000,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.usePriceHistory = usePriceHistory;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function usePriceHistory(range = '7D', options) {
|
|
7
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
8
|
+
path: `/mcc/price/history?range=${range}`,
|
|
9
|
+
refetchInterval: options?.refetchInterval ?? 300000,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { User } from '@microcosmmoney/auth-core';
|
|
2
|
+
interface UseProfileResult {
|
|
3
|
+
profile: User | null;
|
|
4
|
+
loading: boolean;
|
|
5
|
+
error: Error | null;
|
|
6
|
+
updateProfile: (data: {
|
|
7
|
+
display_name?: string;
|
|
8
|
+
}) => Promise<void>;
|
|
9
|
+
uploadAvatar: (file: File) => Promise<string | null>;
|
|
10
|
+
refresh: () => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare function useProfile(): UseProfileResult;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useProfile = useProfile;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const provider_1 = require("../provider");
|
|
7
|
+
function useProfile() {
|
|
8
|
+
const { user, client, isAuthenticated } = (0, provider_1.useAuth)();
|
|
9
|
+
const [profile, setProfile] = (0, react_1.useState)(user);
|
|
10
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
11
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
12
|
+
(0, react_1.useEffect)(() => {
|
|
13
|
+
setProfile(user);
|
|
14
|
+
}, [user]);
|
|
15
|
+
const refresh = (0, react_1.useCallback)(async () => {
|
|
16
|
+
if (!isAuthenticated)
|
|
17
|
+
return;
|
|
18
|
+
try {
|
|
19
|
+
setLoading(true);
|
|
20
|
+
const api = client.getApiClient();
|
|
21
|
+
const data = await api.get('/users/me/profile');
|
|
22
|
+
const raw = data.user || data;
|
|
23
|
+
const updated = {
|
|
24
|
+
uid: raw.uid || profile?.uid || '',
|
|
25
|
+
email: raw.email || profile?.email || '',
|
|
26
|
+
displayName: raw.display_name || null,
|
|
27
|
+
avatarUrl: raw.avatar_url || null,
|
|
28
|
+
role: raw.role || 'user',
|
|
29
|
+
level: raw.level,
|
|
30
|
+
title: raw.title,
|
|
31
|
+
stationId: raw.station_id || null,
|
|
32
|
+
};
|
|
33
|
+
setProfile(updated);
|
|
34
|
+
client.setUser(updated);
|
|
35
|
+
setError(null);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
setError(err instanceof Error ? err : new Error('Failed to fetch profile'));
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
setLoading(false);
|
|
42
|
+
}
|
|
43
|
+
}, [client, isAuthenticated, profile]);
|
|
44
|
+
const updateProfile = (0, react_1.useCallback)(async (data) => {
|
|
45
|
+
if (!isAuthenticated)
|
|
46
|
+
throw new Error('Not authenticated');
|
|
47
|
+
try {
|
|
48
|
+
setLoading(true);
|
|
49
|
+
const api = client.getApiClient();
|
|
50
|
+
await api.patch('/users/me/profile', data);
|
|
51
|
+
if (profile && data.display_name !== undefined) {
|
|
52
|
+
const updated = { ...profile, displayName: data.display_name };
|
|
53
|
+
setProfile(updated);
|
|
54
|
+
client.setUser(updated);
|
|
55
|
+
}
|
|
56
|
+
setError(null);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
const error = err instanceof Error ? err : new Error('Failed to update profile');
|
|
60
|
+
setError(error);
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
setLoading(false);
|
|
65
|
+
}
|
|
66
|
+
}, [client, isAuthenticated, profile]);
|
|
67
|
+
const uploadAvatar = (0, react_1.useCallback)(async (file) => {
|
|
68
|
+
if (!isAuthenticated)
|
|
69
|
+
throw new Error('Not authenticated');
|
|
70
|
+
try {
|
|
71
|
+
setLoading(true);
|
|
72
|
+
const token = await client.getAccessToken();
|
|
73
|
+
const formData = new FormData();
|
|
74
|
+
formData.append('avatar', file);
|
|
75
|
+
const response = await fetch('https://api.microcosm.money/v1/users/me/avatar', {
|
|
76
|
+
method: 'POST',
|
|
77
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
78
|
+
body: formData,
|
|
79
|
+
});
|
|
80
|
+
if (!response.ok)
|
|
81
|
+
throw new Error('Failed to upload avatar');
|
|
82
|
+
const data = await response.json();
|
|
83
|
+
const avatarUrl = data.avatar_url || null;
|
|
84
|
+
if (profile && avatarUrl) {
|
|
85
|
+
const updated = { ...profile, avatarUrl };
|
|
86
|
+
setProfile(updated);
|
|
87
|
+
client.setUser(updated);
|
|
88
|
+
}
|
|
89
|
+
setError(null);
|
|
90
|
+
return avatarUrl;
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
const error = err instanceof Error ? err : new Error('Failed to upload avatar');
|
|
94
|
+
setError(error);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
setLoading(false);
|
|
99
|
+
}
|
|
100
|
+
}, [client, isAuthenticated, profile]);
|
|
101
|
+
return { profile, loading, error, updateProfile, uploadAvatar, refresh };
|
|
102
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface PoolData {
|
|
2
|
+
usdc_balance?: number;
|
|
3
|
+
usdt_balance?: number;
|
|
4
|
+
mcc_balance?: number;
|
|
5
|
+
total_stablecoin?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function useReincarnationPool(options?: {
|
|
8
|
+
refetchInterval?: number;
|
|
9
|
+
}): import("./use-api-query").UseApiQueryResult<PoolData>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useReincarnationPool = useReincarnationPool;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function useReincarnationPool(options) {
|
|
7
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
8
|
+
path: '/reincarnation/pool',
|
|
9
|
+
refetchInterval: options?.refetchInterval ?? 300000,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useTechTree = useTechTree;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function useTechTree(options) {
|
|
7
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
8
|
+
path: '/tech-tree/user',
|
|
9
|
+
requireAuth: true,
|
|
10
|
+
refetchInterval: options?.refetchInterval ?? 120000,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useTerritoryNFTs = useTerritoryNFTs;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function useTerritoryNFTs(wallet, options) {
|
|
7
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
8
|
+
path: `/territory/nfts/${wallet}`,
|
|
9
|
+
skip: !wallet,
|
|
10
|
+
refetchInterval: options?.refetchInterval ?? 0,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface UserLevelData {
|
|
2
|
+
level: string;
|
|
3
|
+
title?: string | null;
|
|
4
|
+
upgrade_progress?: Record<string, any>;
|
|
5
|
+
mining_weight?: Record<string, number>;
|
|
6
|
+
}
|
|
7
|
+
export declare function useUserLevel(options?: {
|
|
8
|
+
refetchInterval?: number;
|
|
9
|
+
}): import("./use-api-query").UseApiQueryResult<UserLevelData>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useUserLevel = useUserLevel;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
const use_api_query_1 = require("./use-api-query");
|
|
6
|
+
function useUserLevel(options) {
|
|
7
|
+
return (0, use_api_query_1.useApiQuery)({
|
|
8
|
+
path: '/users/me/level',
|
|
9
|
+
requireAuth: true,
|
|
10
|
+
refetchInterval: options?.refetchInterval ?? 120000,
|
|
11
|
+
});
|
|
12
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { MicrocosmAuthProvider, useAuth } from './provider';
|
|
2
|
+
export { AuthCallback } from './callback';
|
|
3
|
+
export { withAuth } from './with-auth';
|
|
4
|
+
export { RequireRole } from './require-role';
|
|
5
|
+
export { useMCD } from './hooks/use-mcd';
|
|
6
|
+
export { useMCC } from './hooks/use-mcc';
|
|
7
|
+
export { useProfile } from './hooks/use-profile';
|
|
8
|
+
export { useApiQuery } from './hooks/use-api-query';
|
|
9
|
+
export { useMCCPrice } from './hooks/use-mcc-price';
|
|
10
|
+
export { useMCCStats } from './hooks/use-mcc-stats';
|
|
11
|
+
export { useMCDStats } from './hooks/use-mcd-stats';
|
|
12
|
+
export { useMiningStats } from './hooks/use-mining-stats';
|
|
13
|
+
export { useMiningRecords } from './hooks/use-mining-records';
|
|
14
|
+
export { useUserLevel } from './hooks/use-user-level';
|
|
15
|
+
export { useReincarnationPool } from './hooks/use-reincarnation-pool';
|
|
16
|
+
export { useTerritoryNFTs } from './hooks/use-territory-nfts';
|
|
17
|
+
export { useAuctions } from './hooks/use-auctions';
|
|
18
|
+
export { useOrganizations } from './hooks/use-organizations';
|
|
19
|
+
export { useTechTree } from './hooks/use-tech-tree';
|
|
20
|
+
export { usePriceHistory } from './hooks/use-price-history';
|
|
21
|
+
export { useDashboardSummary } from './hooks/use-dashboard-summary';
|
|
22
|
+
export type { MicrocosmAuthConfig, MicrocosmAPIConfig, User, AuthState, LoginOptions, MCDBalance, MCCBalance, MCCPrice, } from '@microcosmmoney/auth-core';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useDashboardSummary = exports.usePriceHistory = exports.useTechTree = exports.useOrganizations = exports.useAuctions = exports.useTerritoryNFTs = exports.useReincarnationPool = exports.useUserLevel = exports.useMiningRecords = exports.useMiningStats = exports.useMCDStats = exports.useMCCStats = exports.useMCCPrice = exports.useApiQuery = exports.useProfile = exports.useMCC = exports.useMCD = exports.RequireRole = exports.withAuth = exports.AuthCallback = exports.useAuth = exports.MicrocosmAuthProvider = void 0;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
var provider_1 = require("./provider");
|
|
6
|
+
Object.defineProperty(exports, "MicrocosmAuthProvider", { enumerable: true, get: function () { return provider_1.MicrocosmAuthProvider; } });
|
|
7
|
+
Object.defineProperty(exports, "useAuth", { enumerable: true, get: function () { return provider_1.useAuth; } });
|
|
8
|
+
var callback_1 = require("./callback");
|
|
9
|
+
Object.defineProperty(exports, "AuthCallback", { enumerable: true, get: function () { return callback_1.AuthCallback; } });
|
|
10
|
+
var with_auth_1 = require("./with-auth");
|
|
11
|
+
Object.defineProperty(exports, "withAuth", { enumerable: true, get: function () { return with_auth_1.withAuth; } });
|
|
12
|
+
var require_role_1 = require("./require-role");
|
|
13
|
+
Object.defineProperty(exports, "RequireRole", { enumerable: true, get: function () { return require_role_1.RequireRole; } });
|
|
14
|
+
var use_mcd_1 = require("./hooks/use-mcd");
|
|
15
|
+
Object.defineProperty(exports, "useMCD", { enumerable: true, get: function () { return use_mcd_1.useMCD; } });
|
|
16
|
+
var use_mcc_1 = require("./hooks/use-mcc");
|
|
17
|
+
Object.defineProperty(exports, "useMCC", { enumerable: true, get: function () { return use_mcc_1.useMCC; } });
|
|
18
|
+
var use_profile_1 = require("./hooks/use-profile");
|
|
19
|
+
Object.defineProperty(exports, "useProfile", { enumerable: true, get: function () { return use_profile_1.useProfile; } });
|
|
20
|
+
var use_api_query_1 = require("./hooks/use-api-query");
|
|
21
|
+
Object.defineProperty(exports, "useApiQuery", { enumerable: true, get: function () { return use_api_query_1.useApiQuery; } });
|
|
22
|
+
var use_mcc_price_1 = require("./hooks/use-mcc-price");
|
|
23
|
+
Object.defineProperty(exports, "useMCCPrice", { enumerable: true, get: function () { return use_mcc_price_1.useMCCPrice; } });
|
|
24
|
+
var use_mcc_stats_1 = require("./hooks/use-mcc-stats");
|
|
25
|
+
Object.defineProperty(exports, "useMCCStats", { enumerable: true, get: function () { return use_mcc_stats_1.useMCCStats; } });
|
|
26
|
+
var use_mcd_stats_1 = require("./hooks/use-mcd-stats");
|
|
27
|
+
Object.defineProperty(exports, "useMCDStats", { enumerable: true, get: function () { return use_mcd_stats_1.useMCDStats; } });
|
|
28
|
+
var use_mining_stats_1 = require("./hooks/use-mining-stats");
|
|
29
|
+
Object.defineProperty(exports, "useMiningStats", { enumerable: true, get: function () { return use_mining_stats_1.useMiningStats; } });
|
|
30
|
+
var use_mining_records_1 = require("./hooks/use-mining-records");
|
|
31
|
+
Object.defineProperty(exports, "useMiningRecords", { enumerable: true, get: function () { return use_mining_records_1.useMiningRecords; } });
|
|
32
|
+
var use_user_level_1 = require("./hooks/use-user-level");
|
|
33
|
+
Object.defineProperty(exports, "useUserLevel", { enumerable: true, get: function () { return use_user_level_1.useUserLevel; } });
|
|
34
|
+
var use_reincarnation_pool_1 = require("./hooks/use-reincarnation-pool");
|
|
35
|
+
Object.defineProperty(exports, "useReincarnationPool", { enumerable: true, get: function () { return use_reincarnation_pool_1.useReincarnationPool; } });
|
|
36
|
+
var use_territory_nfts_1 = require("./hooks/use-territory-nfts");
|
|
37
|
+
Object.defineProperty(exports, "useTerritoryNFTs", { enumerable: true, get: function () { return use_territory_nfts_1.useTerritoryNFTs; } });
|
|
38
|
+
var use_auctions_1 = require("./hooks/use-auctions");
|
|
39
|
+
Object.defineProperty(exports, "useAuctions", { enumerable: true, get: function () { return use_auctions_1.useAuctions; } });
|
|
40
|
+
var use_organizations_1 = require("./hooks/use-organizations");
|
|
41
|
+
Object.defineProperty(exports, "useOrganizations", { enumerable: true, get: function () { return use_organizations_1.useOrganizations; } });
|
|
42
|
+
var use_tech_tree_1 = require("./hooks/use-tech-tree");
|
|
43
|
+
Object.defineProperty(exports, "useTechTree", { enumerable: true, get: function () { return use_tech_tree_1.useTechTree; } });
|
|
44
|
+
var use_price_history_1 = require("./hooks/use-price-history");
|
|
45
|
+
Object.defineProperty(exports, "usePriceHistory", { enumerable: true, get: function () { return use_price_history_1.usePriceHistory; } });
|
|
46
|
+
var use_dashboard_summary_1 = require("./hooks/use-dashboard-summary");
|
|
47
|
+
Object.defineProperty(exports, "useDashboardSummary", { enumerable: true, get: function () { return use_dashboard_summary_1.useDashboardSummary; } });
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { MicrocosmAuthClient, MicrocosmAuthConfig, AuthState, LoginOptions } from '@microcosmmoney/auth-core';
|
|
3
|
+
interface AuthContextType extends AuthState {
|
|
4
|
+
login: (options?: LoginOptions) => void;
|
|
5
|
+
logout: () => Promise<void>;
|
|
6
|
+
getAccessToken: () => Promise<string | null>;
|
|
7
|
+
client: MicrocosmAuthClient;
|
|
8
|
+
}
|
|
9
|
+
export declare function MicrocosmAuthProvider({ children, ...config }: MicrocosmAuthConfig & {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function useAuth(): AuthContextType;
|
|
13
|
+
export {};
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MicrocosmAuthProvider = MicrocosmAuthProvider;
|
|
4
|
+
exports.useAuth = useAuth;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
// AI-generated · AI-managed · AI-maintained
|
|
7
|
+
const react_1 = require("react");
|
|
8
|
+
const auth_core_1 = require("@microcosmmoney/auth-core");
|
|
9
|
+
const AuthContext = (0, react_1.createContext)(null);
|
|
10
|
+
function MicrocosmAuthProvider({ children, ...config }) {
|
|
11
|
+
const [state, setState] = (0, react_1.useState)({
|
|
12
|
+
user: null,
|
|
13
|
+
isAuthenticated: false,
|
|
14
|
+
isLoading: true,
|
|
15
|
+
error: null,
|
|
16
|
+
});
|
|
17
|
+
const client = (0, react_1.useMemo)(() => new auth_core_1.MicrocosmAuthClient(config), [config.clientId]);
|
|
18
|
+
(0, react_1.useEffect)(() => {
|
|
19
|
+
const user = client.getUser();
|
|
20
|
+
setState({
|
|
21
|
+
user,
|
|
22
|
+
isAuthenticated: client.isAuthenticated(),
|
|
23
|
+
isLoading: false,
|
|
24
|
+
error: null,
|
|
25
|
+
});
|
|
26
|
+
const unsubscribe = client.onAuthStateChange((updatedUser) => {
|
|
27
|
+
setState(prev => ({
|
|
28
|
+
...prev,
|
|
29
|
+
user: updatedUser,
|
|
30
|
+
isAuthenticated: !!updatedUser,
|
|
31
|
+
}));
|
|
32
|
+
});
|
|
33
|
+
return unsubscribe;
|
|
34
|
+
}, [client]);
|
|
35
|
+
const login = (0, react_1.useCallback)((options) => client.login(options), [client]);
|
|
36
|
+
const logout = (0, react_1.useCallback)(() => client.logout(), [client]);
|
|
37
|
+
const getAccessToken = (0, react_1.useCallback)(() => client.getAccessToken(), [client]);
|
|
38
|
+
const value = {
|
|
39
|
+
...state,
|
|
40
|
+
login,
|
|
41
|
+
logout,
|
|
42
|
+
getAccessToken,
|
|
43
|
+
client,
|
|
44
|
+
};
|
|
45
|
+
return (0, jsx_runtime_1.jsx)(AuthContext.Provider, { value: value, children: children });
|
|
46
|
+
}
|
|
47
|
+
function useAuth() {
|
|
48
|
+
const context = (0, react_1.useContext)(AuthContext);
|
|
49
|
+
if (!context) {
|
|
50
|
+
throw new Error('useAuth must be used within <MicrocosmAuthProvider>. ' +
|
|
51
|
+
'Wrap your app with <MicrocosmAuthProvider clientId="..." redirectUri="/auth/callback">');
|
|
52
|
+
}
|
|
53
|
+
return context;
|
|
54
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface RequireRoleProps {
|
|
3
|
+
roles: string[];
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
fallback?: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export declare function RequireRole({ roles, children, fallback }: RequireRoleProps): import("react/jsx-runtime").JSX.Element | null;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RequireRole = RequireRole;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const provider_1 = require("./provider");
|
|
6
|
+
function RequireRole({ roles, children, fallback }) {
|
|
7
|
+
const { user } = (0, provider_1.useAuth)();
|
|
8
|
+
if (!user || !roles.includes(user.role)) {
|
|
9
|
+
return fallback ? (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: fallback }) : null;
|
|
10
|
+
}
|
|
11
|
+
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children });
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createTokenExchangeHandler, createProfileHandler } from './token-exchange';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createProfileHandler = exports.createTokenExchangeHandler = void 0;
|
|
4
|
+
// AI-generated · AI-managed · AI-maintained
|
|
5
|
+
var token_exchange_1 = require("./token-exchange");
|
|
6
|
+
Object.defineProperty(exports, "createTokenExchangeHandler", { enumerable: true, get: function () { return token_exchange_1.createTokenExchangeHandler; } });
|
|
7
|
+
Object.defineProperty(exports, "createProfileHandler", { enumerable: true, get: function () { return token_exchange_1.createProfileHandler; } });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface TokenExchangeConfig {
|
|
2
|
+
clientId: string;
|
|
3
|
+
clientSecret: string;
|
|
4
|
+
tokenEndpoint?: string;
|
|
5
|
+
redirectUri?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function createTokenExchangeHandler(config: TokenExchangeConfig): (request: Request) => Promise<Response>;
|
|
8
|
+
export declare function createProfileHandler(config?: {
|
|
9
|
+
openApiBase?: string;
|
|
10
|
+
enrich?: (profile: Record<string, unknown>, token: string) => Promise<Record<string, unknown>>;
|
|
11
|
+
}): (request: Request) => Promise<Response>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTokenExchangeHandler = createTokenExchangeHandler;
|
|
4
|
+
exports.createProfileHandler = createProfileHandler;
|
|
5
|
+
function createTokenExchangeHandler(config) {
|
|
6
|
+
const tokenEndpoint = config.tokenEndpoint || 'https://microcosm.money/api/oauth/token';
|
|
7
|
+
return async function POST(request) {
|
|
8
|
+
try {
|
|
9
|
+
const body = await request.json();
|
|
10
|
+
if (!config.clientSecret) {
|
|
11
|
+
return jsonResponse({ error: 'server_error', error_description: 'OAuth not configured' }, 500);
|
|
12
|
+
}
|
|
13
|
+
const grantType = body.grant_type || 'authorization_code';
|
|
14
|
+
const tokenBody = {
|
|
15
|
+
grant_type: grantType,
|
|
16
|
+
client_id: config.clientId,
|
|
17
|
+
client_secret: config.clientSecret,
|
|
18
|
+
};
|
|
19
|
+
if (grantType === 'authorization_code') {
|
|
20
|
+
if (!body.code) {
|
|
21
|
+
return jsonResponse({ error: 'invalid_request', error_description: 'Missing authorization code' }, 400);
|
|
22
|
+
}
|
|
23
|
+
tokenBody.code = body.code;
|
|
24
|
+
const origin = request.headers.get('origin') || '';
|
|
25
|
+
tokenBody.redirect_uri = origin
|
|
26
|
+
? `${origin}/auth/callback`
|
|
27
|
+
: config.redirectUri || '';
|
|
28
|
+
}
|
|
29
|
+
else if (grantType === 'refresh_token') {
|
|
30
|
+
if (!body.refresh_token) {
|
|
31
|
+
return jsonResponse({ error: 'invalid_request', error_description: 'Missing refresh token' }, 400);
|
|
32
|
+
}
|
|
33
|
+
tokenBody.refresh_token = body.refresh_token;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return jsonResponse({ error: 'unsupported_grant_type', error_description: `Unsupported: ${grantType}` }, 400);
|
|
37
|
+
}
|
|
38
|
+
const tokenResponse = await fetch(tokenEndpoint, {
|
|
39
|
+
method: 'POST',
|
|
40
|
+
headers: { 'Content-Type': 'application/json' },
|
|
41
|
+
body: JSON.stringify(tokenBody),
|
|
42
|
+
});
|
|
43
|
+
if (!tokenResponse.ok) {
|
|
44
|
+
const errorData = await safeJson(tokenResponse);
|
|
45
|
+
console.error('[MicrocosmAuth] Token exchange failed:', errorData);
|
|
46
|
+
return jsonResponse({
|
|
47
|
+
error: errorData.error || 'token_error',
|
|
48
|
+
error_description: errorData.error_description || 'Token exchange failed',
|
|
49
|
+
}, tokenResponse.status);
|
|
50
|
+
}
|
|
51
|
+
const tokenData = await tokenResponse.json();
|
|
52
|
+
return jsonResponse({
|
|
53
|
+
access_token: tokenData.access_token,
|
|
54
|
+
refresh_token: tokenData.refresh_token,
|
|
55
|
+
expires_in: tokenData.expires_in,
|
|
56
|
+
user_id: tokenData.user_id,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.error('[MicrocosmAuth] Exchange error:', error);
|
|
61
|
+
return jsonResponse({
|
|
62
|
+
error: 'server_error',
|
|
63
|
+
error_description: error instanceof Error ? error.message : 'Internal server error',
|
|
64
|
+
}, 500);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function createProfileHandler(config) {
|
|
69
|
+
const openApiBase = config?.openApiBase || 'https://api.microcosm.money';
|
|
70
|
+
return async function GET(request) {
|
|
71
|
+
try {
|
|
72
|
+
const authHeader = request.headers.get('authorization');
|
|
73
|
+
if (!authHeader) {
|
|
74
|
+
return jsonResponse({ error: 'unauthorized', message: 'Missing authorization header' }, 401);
|
|
75
|
+
}
|
|
76
|
+
const token = authHeader.replace('Bearer ', '');
|
|
77
|
+
const profileRes = await fetch(`${openApiBase}/v1/users/me/profile`, {
|
|
78
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
79
|
+
});
|
|
80
|
+
if (!profileRes.ok) {
|
|
81
|
+
return jsonResponse({ error: 'profile_error', message: 'Failed to fetch profile' }, profileRes.status);
|
|
82
|
+
}
|
|
83
|
+
let profile = await profileRes.json();
|
|
84
|
+
if (profile.data)
|
|
85
|
+
profile = profile.data;
|
|
86
|
+
if (profile.user)
|
|
87
|
+
profile = profile.user;
|
|
88
|
+
if (config?.enrich) {
|
|
89
|
+
profile = await config.enrich(profile, token);
|
|
90
|
+
}
|
|
91
|
+
return jsonResponse(profile);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error('[MicrocosmAuth] Profile error:', error);
|
|
95
|
+
return jsonResponse({ error: 'server_error', message: error instanceof Error ? error.message : 'Internal error' }, 500);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function jsonResponse(data, status = 200) {
|
|
100
|
+
return new Response(JSON.stringify(data), {
|
|
101
|
+
status,
|
|
102
|
+
headers: { 'Content-Type': 'application/json' },
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async function safeJson(response) {
|
|
106
|
+
const contentType = response.headers.get('content-type');
|
|
107
|
+
if (contentType?.includes('application/json')) {
|
|
108
|
+
return response.json();
|
|
109
|
+
}
|
|
110
|
+
const text = await response.text();
|
|
111
|
+
return { error: 'Non-JSON Response', error_description: text.substring(0, 200) };
|
|
112
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface WithAuthOptions {
|
|
3
|
+
redirectTo?: string;
|
|
4
|
+
loadingComponent?: React.ReactNode;
|
|
5
|
+
}
|
|
6
|
+
export declare function withAuth<P extends object>(Component: React.ComponentType<P>, options?: WithAuthOptions): {
|
|
7
|
+
(props: P): import("react/jsx-runtime").JSX.Element | null;
|
|
8
|
+
displayName: string;
|
|
9
|
+
};
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withAuth = withAuth;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const provider_1 = require("./provider");
|
|
6
|
+
function withAuth(Component, options = {}) {
|
|
7
|
+
const { redirectTo = '/login', loadingComponent } = options;
|
|
8
|
+
function WithAuthComponent(props) {
|
|
9
|
+
const { user, isLoading } = (0, provider_1.useAuth)();
|
|
10
|
+
if (isLoading) {
|
|
11
|
+
return loadingComponent ? (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: loadingComponent }) : null;
|
|
12
|
+
}
|
|
13
|
+
if (!user) {
|
|
14
|
+
if (typeof window !== 'undefined') {
|
|
15
|
+
window.location.href = redirectTo;
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return (0, jsx_runtime_1.jsx)(Component, { ...props });
|
|
20
|
+
}
|
|
21
|
+
WithAuthComponent.displayName = `withAuth(${Component.displayName || Component.name || 'Component'})`;
|
|
22
|
+
return WithAuthComponent;
|
|
23
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@microcosmmoney/auth-react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Microcosm OAuth 2.0 React/Next.js adapter",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./server": {
|
|
13
|
+
"types": "./dist/server/index.d.ts",
|
|
14
|
+
"default": "./dist/server/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": ["dist"],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"dev": "tsc --watch"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"react": ">=18.0.0",
|
|
24
|
+
"react-dom": ">=18.0.0"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@microcosmmoney/auth-core": "^1.0.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/react": "^18.0.0",
|
|
31
|
+
"react": "^18.0.0",
|
|
32
|
+
"typescript": "^5.3.0"
|
|
33
|
+
},
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/MicrocosmMoney/Microcosm"
|
|
38
|
+
}
|
|
39
|
+
}
|