@permi/react 0.0.3

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Permi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,229 @@
1
+ # @permi/react
2
+
3
+ React SDK for Permi - OAuth2 + PKCE authentication and wallet management hooks for React applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @permi/react @tanstack/react-query react react-dom
9
+ # or
10
+ pnpm add @permi/react @tanstack/react-query react react-dom
11
+ # or
12
+ yarn add @permi/react @tanstack/react-query react react-dom
13
+ ```
14
+
15
+ ## Peer Dependencies
16
+
17
+ This package requires:
18
+
19
+ - `react` ^18.0.0
20
+ - `react-dom` ^18.0.0
21
+ - `@tanstack/react-query` ^5.0.0
22
+
23
+ ## Usage
24
+
25
+ ### Setup
26
+
27
+ Wrap your application with the `PermiProvider`:
28
+
29
+ ```tsx
30
+ import { PermiProvider } from "@permi/react";
31
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
32
+
33
+ const queryClient = new QueryClient();
34
+
35
+ function App() {
36
+ return (
37
+ <QueryClientProvider client={queryClient}>
38
+ <PermiProvider
39
+ baseUrl="https://permi.xyz"
40
+ clientId="your-client-id"
41
+ redirectUri="http://localhost:3000/callback"
42
+ >
43
+ <YourApp />
44
+ </PermiProvider>
45
+ </QueryClientProvider>
46
+ );
47
+ }
48
+ ```
49
+
50
+ ### Authentication
51
+
52
+ Use the `useAuth` hook to handle authentication:
53
+
54
+ ```tsx
55
+ import { useAuth } from "@permi/react";
56
+
57
+ function LoginButton() {
58
+ const { isAuthenticated, isLoading, login, logout } = useAuth();
59
+
60
+ if (isLoading) return <div>Loading...</div>;
61
+
62
+ if (isAuthenticated) {
63
+ return <button onClick={logout}>Logout</button>;
64
+ }
65
+
66
+ return <button onClick={login}>Login</button>;
67
+ }
68
+ ```
69
+
70
+ ### Wallet Hooks
71
+
72
+ #### Get Wallet Address
73
+
74
+ ```tsx
75
+ import { useAddress } from "@permi/react";
76
+
77
+ function WalletAddress() {
78
+ const { data: address, isLoading, error } = useAddress();
79
+
80
+ if (isLoading) return <div>Loading...</div>;
81
+ if (error) return <div>Error: {error.message}</div>;
82
+
83
+ return <div>Address: {address}</div>;
84
+ }
85
+ ```
86
+
87
+ #### Get Wallet Balance
88
+
89
+ ```tsx
90
+ import { useBalance } from "@permi/react";
91
+
92
+ function WalletBalance() {
93
+ const { data: balance, isLoading } = useBalance();
94
+
95
+ if (isLoading) return <div>Loading...</div>;
96
+
97
+ return (
98
+ <div>
99
+ Balance: {balance?.formatted} {balance?.symbol}
100
+ </div>
101
+ );
102
+ }
103
+ ```
104
+
105
+ #### Get Viem Account
106
+
107
+ The `useAccount` hook returns a [viem](https://viem.sh) compatible account that can be used with viem clients:
108
+
109
+ ```tsx
110
+ import { useAccount } from "@permi/react";
111
+ import { createWalletClient, http } from "viem";
112
+ import { mainnet } from "viem/chains";
113
+
114
+ function SendTransaction() {
115
+ const { data: account, isLoading } = useAccount();
116
+
117
+ const sendTransaction = async () => {
118
+ if (!account) return;
119
+
120
+ const walletClient = createWalletClient({
121
+ account,
122
+ chain: mainnet,
123
+ transport: http(),
124
+ });
125
+
126
+ const hash = await walletClient.sendTransaction({
127
+ to: "0x...",
128
+ value: BigInt(1000000000000000000), // 1 ETH
129
+ });
130
+
131
+ console.log("Transaction hash:", hash);
132
+ };
133
+
134
+ if (isLoading) return <div>Loading...</div>;
135
+
136
+ return (
137
+ <button onClick={sendTransaction} disabled={!account}>
138
+ Send Transaction
139
+ </button>
140
+ );
141
+ }
142
+ ```
143
+
144
+ ## API Reference
145
+
146
+ ### Components
147
+
148
+ #### `PermiProvider`
149
+
150
+ Provider component that must wrap your application.
151
+
152
+ **Props:**
153
+
154
+ - `baseUrl: string` - Permi API base URL
155
+ - `clientId: string` - Your OAuth2 client ID
156
+ - `redirectUri: string` - OAuth2 redirect URI
157
+ - `children: ReactNode` - Your application components
158
+
159
+ ### Hooks
160
+
161
+ #### `useAuth()`
162
+
163
+ Authentication hook for login/logout functionality.
164
+
165
+ **Returns:**
166
+
167
+ - `isAuthenticated: boolean` - Whether user is authenticated
168
+ - `isLoading: boolean` - Whether authentication is loading
169
+ - `user: User | undefined` - Current user info
170
+ - `login: () => void` - Function to initiate login
171
+ - `logout: () => void` - Function to logout
172
+ - `getAccessToken: () => string` - Function to get current access token
173
+
174
+ #### `useAddress(queryOptions?)`
175
+
176
+ Hook to get the wallet address.
177
+
178
+ **Returns:** React Query result with wallet address as `Address`
179
+
180
+ #### `useBalance(queryOptions?)`
181
+
182
+ Hook to get the wallet balance.
183
+
184
+ **Returns:** React Query result with balance data
185
+
186
+ #### `useAccount()`
187
+
188
+ Hook to get a viem-compatible account object.
189
+
190
+ **Returns:**
191
+
192
+ - `data: Account | undefined` - Viem account object
193
+ - `isLoading: boolean` - Loading state
194
+
195
+ #### `usePermiContext()`
196
+
197
+ Access the Permi context directly.
198
+
199
+ **Returns:**
200
+
201
+ - `baseUrl: string` - API base URL
202
+ - `getAccessToken: () => string` - Function to get access token
203
+
204
+ ## Advanced Usage
205
+
206
+ ### Custom Query Options
207
+
208
+ All query hooks accept TanStack Query options:
209
+
210
+ ```tsx
211
+ const { data: address } = useAddress({
212
+ refetchInterval: 5000, // Refetch every 5 seconds
213
+ staleTime: 10000, // Consider data stale after 10 seconds
214
+ });
215
+ ```
216
+
217
+ ### Error Handling
218
+
219
+ ```tsx
220
+ const { data, error, isError } = useBalance();
221
+
222
+ if (isError) {
223
+ console.error("Failed to fetch balance:", error);
224
+ }
225
+ ```
226
+
227
+ ## License
228
+
229
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ PermiProvider: () => PermiProvider,
24
+ useAccount: () => useAccount,
25
+ useAddress: () => useAddress,
26
+ useAuth: () => useAuth2,
27
+ useBalance: () => useBalance,
28
+ usePermiContext: () => usePermiContext
29
+ });
30
+ module.exports = __toCommonJS(index_exports);
31
+
32
+ // src/hooks/index.ts
33
+ var import_react4 = require("react");
34
+ var import_react_query2 = require("@tanstack/react-query");
35
+ var import_accounts = require("viem/accounts");
36
+ var import_hooks = require("@permi/core/hooks");
37
+ var import_core = require("@permi/core");
38
+
39
+ // src/providers/index.tsx
40
+ var import_react2 = require("react");
41
+ var import_react_query = require("@tanstack/react-query");
42
+ var import_react_oidc_context2 = require("react-oidc-context");
43
+
44
+ // src/providers/auth.tsx
45
+ var import_react = require("react");
46
+ var import_oidc_client_ts = require("oidc-client-ts");
47
+ var import_react_oidc_context = require("react-oidc-context");
48
+ var import_jsx_runtime = require("react/jsx-runtime");
49
+ var AuthProvider = ({
50
+ children,
51
+ clientId,
52
+ userStore: userStoreProp,
53
+ baseUrl = "https://permi.xyz"
54
+ }) => {
55
+ const userStore = (0, import_react.useMemo)(() => {
56
+ return userStoreProp ?? new import_oidc_client_ts.WebStorageStateStore({
57
+ store: window.localStorage,
58
+ prefix: "permi-auth"
59
+ });
60
+ }, [userStoreProp]);
61
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
62
+ import_react_oidc_context.AuthProvider,
63
+ {
64
+ userManager: new import_oidc_client_ts.UserManager({
65
+ authority: baseUrl,
66
+ client_id: clientId,
67
+ redirect_uri: window.location.origin,
68
+ silentRequestTimeoutInSeconds: 10,
69
+ automaticSilentRenew: true,
70
+ silent_redirect_uri: window.location.origin,
71
+ metadata: {
72
+ authorization_endpoint: `${baseUrl}/api/oauth/authorize`,
73
+ token_endpoint: `${baseUrl}/api/oauth/token`,
74
+ userinfo_endpoint: `${baseUrl}/api/oauth/userinfo`,
75
+ issuer: baseUrl
76
+ },
77
+ userStore
78
+ }),
79
+ onSigninCallback: () => {
80
+ if (window.location.search.includes("code=")) {
81
+ window.history.replaceState(
82
+ {},
83
+ document.title,
84
+ window.location.pathname
85
+ );
86
+ }
87
+ },
88
+ children
89
+ }
90
+ );
91
+ };
92
+
93
+ // src/providers/index.tsx
94
+ var import_jsx_runtime2 = require("react/jsx-runtime");
95
+ var PermiContext = (0, import_react2.createContext)(null);
96
+ var usePermiContext = () => {
97
+ const context = (0, import_react2.useContext)(PermiContext);
98
+ if (!context) {
99
+ throw new Error("usePermiContext must be used within PermiProvider");
100
+ }
101
+ return context;
102
+ };
103
+ var PermiProvider = ({
104
+ children,
105
+ queryClient,
106
+ ...props
107
+ }) => {
108
+ const defaultQueryClient = (0, import_react2.useMemo)(() => new import_react_query.QueryClient(), []);
109
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_query.QueryClientProvider, { client: queryClient ?? defaultQueryClient, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AuthProvider, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PermiProviderRaw, { baseUrl: props.baseUrl, children }) }) });
110
+ };
111
+ var PermiProviderRaw = ({
112
+ children,
113
+ baseUrl
114
+ }) => {
115
+ const { user } = (0, import_react_oidc_context2.useAuth)();
116
+ const contextValue = (0, import_react2.useMemo)(
117
+ () => ({
118
+ baseUrl: baseUrl ? `${baseUrl}/api` : void 0,
119
+ getAccessToken: () => user?.access_token ?? ""
120
+ }),
121
+ [user, baseUrl]
122
+ );
123
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PermiContext.Provider, { value: contextValue, children });
124
+ };
125
+
126
+ // src/hooks/use-auth.ts
127
+ var import_react3 = require("react");
128
+ var import_react_oidc_context3 = require("react-oidc-context");
129
+ var useAuth2 = () => {
130
+ const auth = (0, import_react_oidc_context3.useAuth)();
131
+ const { isAuthenticated, isLoading, error } = auth;
132
+ const signIn = (0, import_react3.useCallback)(() => {
133
+ if (isLoading || isAuthenticated) {
134
+ throw new Error("Already authenticated");
135
+ }
136
+ return auth.signinRedirect();
137
+ }, [auth, isLoading, isAuthenticated]);
138
+ const signOut = (0, import_react3.useCallback)(() => {
139
+ if (!isAuthenticated) {
140
+ throw new Error("Not authenticated");
141
+ }
142
+ return auth.signoutRedirect();
143
+ }, [auth, isAuthenticated]);
144
+ return {
145
+ signIn,
146
+ signOut,
147
+ isAuthenticated,
148
+ isLoading,
149
+ error
150
+ };
151
+ };
152
+
153
+ // src/hooks/index.ts
154
+ var getOptions = (options, getAccessToken) => {
155
+ return {
156
+ ...options,
157
+ throwOnError: true,
158
+ headers: {
159
+ ...options.headers,
160
+ Authorization: `Bearer ${getAccessToken()}`
161
+ }
162
+ };
163
+ };
164
+ var useOptions = (options) => {
165
+ const { baseUrl, getAccessToken } = usePermiContext();
166
+ return (0, import_react4.useMemo)(
167
+ () => getOptions(
168
+ {
169
+ baseUrl,
170
+ ...options ?? {}
171
+ },
172
+ getAccessToken
173
+ ),
174
+ [options, baseUrl, getAccessToken]
175
+ );
176
+ };
177
+ var useBalance = (queryOptions) => (0, import_react_query2.useQuery)({ ...(0, import_hooks.balanceOptions)(useOptions()), ...queryOptions });
178
+ var useAddress = (queryOptions) => (0, import_react_query2.useQuery)({ ...(0, import_hooks.addressOptions)(useOptions()), ...queryOptions });
179
+ var useAccount = () => {
180
+ const { data: address, isLoading: isAddressLoading } = useAddress();
181
+ const { baseUrl, getAccessToken } = usePermiContext();
182
+ const getAuthOptions = (options) => {
183
+ return getOptions(
184
+ {
185
+ baseUrl,
186
+ ...options
187
+ },
188
+ getAccessToken
189
+ );
190
+ };
191
+ const account = !address ? void 0 : (0, import_accounts.toAccount)({
192
+ address,
193
+ signMessage: async (params) => {
194
+ return await (0, import_core.signMessage)(
195
+ getAuthOptions({
196
+ body: params
197
+ })
198
+ ).then((res) => res.data);
199
+ },
200
+ signTransaction: async (params) => {
201
+ return await (0, import_core.signTransaction)(
202
+ getAuthOptions({ body: params })
203
+ ).then((res) => res.data);
204
+ },
205
+ signTypedData: async (params) => {
206
+ return await (0, import_core.signTypedData)(getAuthOptions({ body: params })).then(
207
+ (res) => res.data
208
+ );
209
+ }
210
+ });
211
+ return {
212
+ data: account,
213
+ isLoading: isAddressLoading
214
+ };
215
+ };
216
+ // Annotate the CommonJS export names for ESM import in node:
217
+ 0 && (module.exports = {
218
+ PermiProvider,
219
+ useAccount,
220
+ useAddress,
221
+ useAuth,
222
+ useBalance,
223
+ usePermiContext
224
+ });
225
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/hooks/index.ts","../src/providers/index.tsx","../src/providers/auth.tsx","../src/hooks/use-auth.ts"],"sourcesContent":["export * from \"./hooks\";\nexport { PermiProvider, usePermiContext } from \"./providers\";\n","import { useMemo } from \"react\";\n\nimport { useQuery } from \"@tanstack/react-query\";\n\nimport { toAccount } from \"viem/accounts\";\n\nimport { balanceOptions, addressOptions } from \"@permi/core/hooks\";\nimport {\n signMessage as coreSignMessage,\n signTransaction as coreSignTransaction,\n signTypedData as coreSignTypedData,\n} from \"@permi/core\";\n\nimport { usePermiContext } from \"../providers\";\n\nimport type { AddressData, BalanceData, Options } from \"@permi/core\";\nimport type { TDataShape } from \"@permi/core/client\";\nimport type { Hex, Address } from \"viem\";\n\nconst getOptions = <T extends TDataShape>(\n options: Options<T>,\n getAccessToken: () => string,\n): Options<T> => {\n return {\n ...options,\n throwOnError: true,\n headers: {\n ...options.headers,\n Authorization: `Bearer ${getAccessToken()}`,\n },\n };\n};\n\n/**\n * Wraps options with auth headers and baseUrl\n */\nconst useOptions = <T extends TDataShape>(options?: Options<T>) => {\n const { baseUrl, getAccessToken } = usePermiContext();\n\n return useMemo(\n () =>\n getOptions<T>(\n {\n baseUrl,\n ...(options ?? ({} as Options<T>)),\n },\n getAccessToken,\n ),\n [options, baseUrl, getAccessToken],\n );\n};\n\n/**\n * Hook to get the balance of the user's app wallet\n */\nexport const useBalance = (queryOptions?: ReturnType<typeof balanceOptions>) =>\n useQuery({ ...balanceOptions(useOptions<BalanceData>()), ...queryOptions });\n\nexport const useAddress = (queryOptions?: ReturnType<typeof addressOptions>) =>\n useQuery({ ...addressOptions(useOptions<AddressData>()), ...queryOptions });\n\nexport const useAccount = () => {\n const { data: address, isLoading: isAddressLoading } = useAddress();\n\n const { baseUrl, getAccessToken } = usePermiContext();\n\n const getAuthOptions = <T extends TDataShape>(options: Options<T>) => {\n return getOptions<T>(\n {\n baseUrl,\n ...options,\n },\n getAccessToken,\n );\n };\n\n const account = !address\n ? undefined\n : toAccount({\n address: address as Address,\n signMessage: async (params) => {\n return await coreSignMessage(\n getAuthOptions({\n body: params,\n }),\n ).then((res) => res.data as Hex);\n },\n signTransaction: async (params) => {\n return await coreSignTransaction(\n getAuthOptions({ body: params }),\n ).then((res) => res.data as Hex);\n },\n signTypedData: async (params) => {\n return await coreSignTypedData(getAuthOptions({ body: params })).then(\n (res) => res.data as Hex,\n );\n },\n });\n\n return {\n data: account,\n isLoading: isAddressLoading,\n };\n};\n\nexport { useAuth } from \"./use-auth\";\n","import React, { useMemo, createContext, useContext } from \"react\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { useAuth } from \"react-oidc-context\";\nimport { AuthProvider } from \"./auth\";\nimport { PermiConfig } from \"src/types/config\";\n\ninterface Props extends PermiConfig {\n children: React.ReactNode;\n queryClient?: QueryClient;\n}\n\ninterface PermiContextValue {\n baseUrl?: string;\n getAccessToken: () => string;\n}\n\nconst PermiContext = createContext<PermiContextValue | null>(null);\n\nexport const usePermiContext = () => {\n const context = useContext(PermiContext);\n if (!context) {\n throw new Error(\"usePermiContext must be used within PermiProvider\");\n }\n return context;\n};\n\nexport const PermiProvider: React.FC<Props> = ({\n children,\n queryClient,\n ...props\n}) => {\n const defaultQueryClient = useMemo(() => new QueryClient(), []);\n\n return (\n <QueryClientProvider client={queryClient ?? defaultQueryClient}>\n <AuthProvider {...props}>\n <PermiProviderRaw baseUrl={props.baseUrl}>{children}</PermiProviderRaw>\n </AuthProvider>\n </QueryClientProvider>\n );\n};\n\nconst PermiProviderRaw = ({\n children,\n baseUrl,\n}: {\n children: React.ReactNode;\n baseUrl?: string;\n}) => {\n const { user } = useAuth();\n\n const contextValue = useMemo<PermiContextValue>(\n () => ({\n baseUrl: baseUrl ? `${baseUrl}/api` : undefined,\n getAccessToken: () => user?.access_token ?? \"\",\n }),\n [user, baseUrl],\n );\n\n return (\n <PermiContext.Provider value={contextValue}>\n {children}\n </PermiContext.Provider>\n );\n};\n","import { ReactNode, useMemo } from \"react\";\n\nimport { StateStore, UserManager, WebStorageStateStore } from \"oidc-client-ts\";\n\nimport { AuthProvider as AuthProviderComponent } from \"react-oidc-context\";\nimport { PermiConfig } from \"src/types/config\";\n\ninterface AuthProviderProps extends PermiConfig {\n children: ReactNode;\n userStore?: StateStore;\n}\n\nexport const AuthProvider: React.FC<AuthProviderProps> = ({\n children,\n clientId,\n userStore: userStoreProp,\n baseUrl = \"https://permi.xyz\",\n}) => {\n const userStore = useMemo(() => {\n return (\n userStoreProp ??\n new WebStorageStateStore({\n store: window.localStorage,\n prefix: \"permi-auth\",\n })\n );\n }, [userStoreProp]);\n\n return (\n <AuthProviderComponent\n userManager={\n new UserManager({\n authority: baseUrl,\n client_id: clientId,\n redirect_uri: window.location.origin,\n silentRequestTimeoutInSeconds: 10,\n automaticSilentRenew: true,\n silent_redirect_uri: window.location.origin,\n metadata: {\n authorization_endpoint: `${baseUrl}/api/oauth/authorize`,\n token_endpoint: `${baseUrl}/api/oauth/token`,\n userinfo_endpoint: `${baseUrl}/api/oauth/userinfo`,\n issuer: baseUrl,\n },\n userStore,\n })\n }\n onSigninCallback={() => {\n if (window.location.search.includes(\"code=\")) {\n window.history.replaceState(\n {},\n document.title,\n window.location.pathname,\n );\n }\n }}\n >\n {children}\n </AuthProviderComponent>\n );\n};\n","import { useCallback } from \"react\";\nimport { useAuth as useAuthContext } from \"react-oidc-context\";\n\nexport const useAuth = () => {\n const auth = useAuthContext();\n const { isAuthenticated, isLoading, error } = auth;\n\n const signIn = useCallback(() => {\n if (isLoading || isAuthenticated) {\n throw new Error(\"Already authenticated\");\n }\n return auth.signinRedirect();\n }, [auth, isLoading, isAuthenticated]);\n\n const signOut = useCallback(() => {\n if (!isAuthenticated) {\n throw new Error(\"Not authenticated\");\n }\n return auth.signoutRedirect();\n }, [auth, isAuthenticated]);\n\n return {\n signIn,\n signOut,\n isAuthenticated,\n isLoading,\n error,\n };\n};\n"],"mappings":"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","names":["useAuth","import_react","import_react_query","import_react","import_react_oidc_context","AuthProviderComponent","import_jsx_runtime","import_react","import_react_oidc_context","useAuth","useAuthContext","coreSignMessage","coreSignTransaction","coreSignTypedData"]}
@@ -0,0 +1,63 @@
1
+ import * as viem_accounts from 'viem/accounts';
2
+ import * as viem from 'viem';
3
+ import { Address, Hex } from 'viem';
4
+ import * as _tanstack_react_query from '@tanstack/react-query';
5
+ import { QueryClient } from '@tanstack/react-query';
6
+ import * as _permi_core from '@permi/core';
7
+ import { balanceOptions, addressOptions } from '@permi/core/hooks';
8
+ import React from 'react';
9
+ import * as react_oidc_context from 'react-oidc-context';
10
+
11
+ declare const useAuth: () => {
12
+ signIn: () => Promise<void>;
13
+ signOut: () => Promise<void>;
14
+ isAuthenticated: boolean;
15
+ isLoading: boolean;
16
+ error: react_oidc_context.ErrorContext | undefined;
17
+ };
18
+
19
+ /**
20
+ * Hook to get the balance of the user's app wallet
21
+ */
22
+ declare const useBalance: (queryOptions?: ReturnType<typeof balanceOptions>) => _tanstack_react_query.UseQueryResult<number, _permi_core.BalanceError>;
23
+ declare const useAddress: (queryOptions?: ReturnType<typeof addressOptions>) => _tanstack_react_query.UseQueryResult<string, _permi_core.AddressError>;
24
+ declare const useAccount: () => {
25
+ data: {
26
+ address: Address;
27
+ nonceManager?: viem.NonceManager | undefined;
28
+ sign?: ((parameters: {
29
+ hash: viem.Hash;
30
+ }) => Promise<Hex>) | undefined | undefined;
31
+ signAuthorization?: ((parameters: viem.AuthorizationRequest) => Promise<viem_accounts.SignAuthorizationReturnType>) | undefined | undefined;
32
+ signMessage: ({ message }: {
33
+ message: viem.SignableMessage;
34
+ }) => Promise<Hex>;
35
+ signTransaction: <serializer extends viem.SerializeTransactionFn<viem.TransactionSerializable> = viem.SerializeTransactionFn<viem.TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
36
+ serializer?: serializer | undefined;
37
+ } | undefined) => Promise<Hex>;
38
+ signTypedData: <const typedData extends viem.TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: viem.TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
39
+ publicKey: Hex;
40
+ source: string;
41
+ type: "local";
42
+ } | undefined;
43
+ isLoading: boolean;
44
+ };
45
+
46
+ interface PermiConfig {
47
+ clientId: string;
48
+ baseUrl?: string;
49
+ storagePrefix?: string;
50
+ }
51
+
52
+ interface Props extends PermiConfig {
53
+ children: React.ReactNode;
54
+ queryClient?: QueryClient;
55
+ }
56
+ interface PermiContextValue {
57
+ baseUrl?: string;
58
+ getAccessToken: () => string;
59
+ }
60
+ declare const usePermiContext: () => PermiContextValue;
61
+ declare const PermiProvider: React.FC<Props>;
62
+
63
+ export { PermiProvider, useAccount, useAddress, useAuth, useBalance, usePermiContext };
@@ -0,0 +1,63 @@
1
+ import * as viem_accounts from 'viem/accounts';
2
+ import * as viem from 'viem';
3
+ import { Address, Hex } from 'viem';
4
+ import * as _tanstack_react_query from '@tanstack/react-query';
5
+ import { QueryClient } from '@tanstack/react-query';
6
+ import * as _permi_core from '@permi/core';
7
+ import { balanceOptions, addressOptions } from '@permi/core/hooks';
8
+ import React from 'react';
9
+ import * as react_oidc_context from 'react-oidc-context';
10
+
11
+ declare const useAuth: () => {
12
+ signIn: () => Promise<void>;
13
+ signOut: () => Promise<void>;
14
+ isAuthenticated: boolean;
15
+ isLoading: boolean;
16
+ error: react_oidc_context.ErrorContext | undefined;
17
+ };
18
+
19
+ /**
20
+ * Hook to get the balance of the user's app wallet
21
+ */
22
+ declare const useBalance: (queryOptions?: ReturnType<typeof balanceOptions>) => _tanstack_react_query.UseQueryResult<number, _permi_core.BalanceError>;
23
+ declare const useAddress: (queryOptions?: ReturnType<typeof addressOptions>) => _tanstack_react_query.UseQueryResult<string, _permi_core.AddressError>;
24
+ declare const useAccount: () => {
25
+ data: {
26
+ address: Address;
27
+ nonceManager?: viem.NonceManager | undefined;
28
+ sign?: ((parameters: {
29
+ hash: viem.Hash;
30
+ }) => Promise<Hex>) | undefined | undefined;
31
+ signAuthorization?: ((parameters: viem.AuthorizationRequest) => Promise<viem_accounts.SignAuthorizationReturnType>) | undefined | undefined;
32
+ signMessage: ({ message }: {
33
+ message: viem.SignableMessage;
34
+ }) => Promise<Hex>;
35
+ signTransaction: <serializer extends viem.SerializeTransactionFn<viem.TransactionSerializable> = viem.SerializeTransactionFn<viem.TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
36
+ serializer?: serializer | undefined;
37
+ } | undefined) => Promise<Hex>;
38
+ signTypedData: <const typedData extends viem.TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: viem.TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
39
+ publicKey: Hex;
40
+ source: string;
41
+ type: "local";
42
+ } | undefined;
43
+ isLoading: boolean;
44
+ };
45
+
46
+ interface PermiConfig {
47
+ clientId: string;
48
+ baseUrl?: string;
49
+ storagePrefix?: string;
50
+ }
51
+
52
+ interface Props extends PermiConfig {
53
+ children: React.ReactNode;
54
+ queryClient?: QueryClient;
55
+ }
56
+ interface PermiContextValue {
57
+ baseUrl?: string;
58
+ getAccessToken: () => string;
59
+ }
60
+ declare const usePermiContext: () => PermiContextValue;
61
+ declare const PermiProvider: React.FC<Props>;
62
+
63
+ export { PermiProvider, useAccount, useAddress, useAuth, useBalance, usePermiContext };
package/dist/index.js ADDED
@@ -0,0 +1,197 @@
1
+ // src/hooks/index.ts
2
+ import { useMemo as useMemo3 } from "react";
3
+ import { useQuery } from "@tanstack/react-query";
4
+ import { toAccount } from "viem/accounts";
5
+ import { balanceOptions, addressOptions } from "@permi/core/hooks";
6
+ import {
7
+ signMessage as coreSignMessage,
8
+ signTransaction as coreSignTransaction,
9
+ signTypedData as coreSignTypedData
10
+ } from "@permi/core";
11
+
12
+ // src/providers/index.tsx
13
+ import { useMemo as useMemo2, createContext, useContext } from "react";
14
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
15
+ import { useAuth } from "react-oidc-context";
16
+
17
+ // src/providers/auth.tsx
18
+ import { useMemo } from "react";
19
+ import { UserManager, WebStorageStateStore } from "oidc-client-ts";
20
+ import { AuthProvider as AuthProviderComponent } from "react-oidc-context";
21
+ import { jsx } from "react/jsx-runtime";
22
+ var AuthProvider = ({
23
+ children,
24
+ clientId,
25
+ userStore: userStoreProp,
26
+ baseUrl = "https://permi.xyz"
27
+ }) => {
28
+ const userStore = useMemo(() => {
29
+ return userStoreProp ?? new WebStorageStateStore({
30
+ store: window.localStorage,
31
+ prefix: "permi-auth"
32
+ });
33
+ }, [userStoreProp]);
34
+ return /* @__PURE__ */ jsx(
35
+ AuthProviderComponent,
36
+ {
37
+ userManager: new UserManager({
38
+ authority: baseUrl,
39
+ client_id: clientId,
40
+ redirect_uri: window.location.origin,
41
+ silentRequestTimeoutInSeconds: 10,
42
+ automaticSilentRenew: true,
43
+ silent_redirect_uri: window.location.origin,
44
+ metadata: {
45
+ authorization_endpoint: `${baseUrl}/api/oauth/authorize`,
46
+ token_endpoint: `${baseUrl}/api/oauth/token`,
47
+ userinfo_endpoint: `${baseUrl}/api/oauth/userinfo`,
48
+ issuer: baseUrl
49
+ },
50
+ userStore
51
+ }),
52
+ onSigninCallback: () => {
53
+ if (window.location.search.includes("code=")) {
54
+ window.history.replaceState(
55
+ {},
56
+ document.title,
57
+ window.location.pathname
58
+ );
59
+ }
60
+ },
61
+ children
62
+ }
63
+ );
64
+ };
65
+
66
+ // src/providers/index.tsx
67
+ import { jsx as jsx2 } from "react/jsx-runtime";
68
+ var PermiContext = createContext(null);
69
+ var usePermiContext = () => {
70
+ const context = useContext(PermiContext);
71
+ if (!context) {
72
+ throw new Error("usePermiContext must be used within PermiProvider");
73
+ }
74
+ return context;
75
+ };
76
+ var PermiProvider = ({
77
+ children,
78
+ queryClient,
79
+ ...props
80
+ }) => {
81
+ const defaultQueryClient = useMemo2(() => new QueryClient(), []);
82
+ return /* @__PURE__ */ jsx2(QueryClientProvider, { client: queryClient ?? defaultQueryClient, children: /* @__PURE__ */ jsx2(AuthProvider, { ...props, children: /* @__PURE__ */ jsx2(PermiProviderRaw, { baseUrl: props.baseUrl, children }) }) });
83
+ };
84
+ var PermiProviderRaw = ({
85
+ children,
86
+ baseUrl
87
+ }) => {
88
+ const { user } = useAuth();
89
+ const contextValue = useMemo2(
90
+ () => ({
91
+ baseUrl: baseUrl ? `${baseUrl}/api` : void 0,
92
+ getAccessToken: () => user?.access_token ?? ""
93
+ }),
94
+ [user, baseUrl]
95
+ );
96
+ return /* @__PURE__ */ jsx2(PermiContext.Provider, { value: contextValue, children });
97
+ };
98
+
99
+ // src/hooks/use-auth.ts
100
+ import { useCallback } from "react";
101
+ import { useAuth as useAuthContext } from "react-oidc-context";
102
+ var useAuth2 = () => {
103
+ const auth = useAuthContext();
104
+ const { isAuthenticated, isLoading, error } = auth;
105
+ const signIn = useCallback(() => {
106
+ if (isLoading || isAuthenticated) {
107
+ throw new Error("Already authenticated");
108
+ }
109
+ return auth.signinRedirect();
110
+ }, [auth, isLoading, isAuthenticated]);
111
+ const signOut = useCallback(() => {
112
+ if (!isAuthenticated) {
113
+ throw new Error("Not authenticated");
114
+ }
115
+ return auth.signoutRedirect();
116
+ }, [auth, isAuthenticated]);
117
+ return {
118
+ signIn,
119
+ signOut,
120
+ isAuthenticated,
121
+ isLoading,
122
+ error
123
+ };
124
+ };
125
+
126
+ // src/hooks/index.ts
127
+ var getOptions = (options, getAccessToken) => {
128
+ return {
129
+ ...options,
130
+ throwOnError: true,
131
+ headers: {
132
+ ...options.headers,
133
+ Authorization: `Bearer ${getAccessToken()}`
134
+ }
135
+ };
136
+ };
137
+ var useOptions = (options) => {
138
+ const { baseUrl, getAccessToken } = usePermiContext();
139
+ return useMemo3(
140
+ () => getOptions(
141
+ {
142
+ baseUrl,
143
+ ...options ?? {}
144
+ },
145
+ getAccessToken
146
+ ),
147
+ [options, baseUrl, getAccessToken]
148
+ );
149
+ };
150
+ var useBalance = (queryOptions) => useQuery({ ...balanceOptions(useOptions()), ...queryOptions });
151
+ var useAddress = (queryOptions) => useQuery({ ...addressOptions(useOptions()), ...queryOptions });
152
+ var useAccount = () => {
153
+ const { data: address, isLoading: isAddressLoading } = useAddress();
154
+ const { baseUrl, getAccessToken } = usePermiContext();
155
+ const getAuthOptions = (options) => {
156
+ return getOptions(
157
+ {
158
+ baseUrl,
159
+ ...options
160
+ },
161
+ getAccessToken
162
+ );
163
+ };
164
+ const account = !address ? void 0 : toAccount({
165
+ address,
166
+ signMessage: async (params) => {
167
+ return await coreSignMessage(
168
+ getAuthOptions({
169
+ body: params
170
+ })
171
+ ).then((res) => res.data);
172
+ },
173
+ signTransaction: async (params) => {
174
+ return await coreSignTransaction(
175
+ getAuthOptions({ body: params })
176
+ ).then((res) => res.data);
177
+ },
178
+ signTypedData: async (params) => {
179
+ return await coreSignTypedData(getAuthOptions({ body: params })).then(
180
+ (res) => res.data
181
+ );
182
+ }
183
+ });
184
+ return {
185
+ data: account,
186
+ isLoading: isAddressLoading
187
+ };
188
+ };
189
+ export {
190
+ PermiProvider,
191
+ useAccount,
192
+ useAddress,
193
+ useAuth2 as useAuth,
194
+ useBalance,
195
+ usePermiContext
196
+ };
197
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/index.ts","../src/providers/index.tsx","../src/providers/auth.tsx","../src/hooks/use-auth.ts"],"sourcesContent":["import { useMemo } from \"react\";\n\nimport { useQuery } from \"@tanstack/react-query\";\n\nimport { toAccount } from \"viem/accounts\";\n\nimport { balanceOptions, addressOptions } from \"@permi/core/hooks\";\nimport {\n signMessage as coreSignMessage,\n signTransaction as coreSignTransaction,\n signTypedData as coreSignTypedData,\n} from \"@permi/core\";\n\nimport { usePermiContext } from \"../providers\";\n\nimport type { AddressData, BalanceData, Options } from \"@permi/core\";\nimport type { TDataShape } from \"@permi/core/client\";\nimport type { Hex, Address } from \"viem\";\n\nconst getOptions = <T extends TDataShape>(\n options: Options<T>,\n getAccessToken: () => string,\n): Options<T> => {\n return {\n ...options,\n throwOnError: true,\n headers: {\n ...options.headers,\n Authorization: `Bearer ${getAccessToken()}`,\n },\n };\n};\n\n/**\n * Wraps options with auth headers and baseUrl\n */\nconst useOptions = <T extends TDataShape>(options?: Options<T>) => {\n const { baseUrl, getAccessToken } = usePermiContext();\n\n return useMemo(\n () =>\n getOptions<T>(\n {\n baseUrl,\n ...(options ?? ({} as Options<T>)),\n },\n getAccessToken,\n ),\n [options, baseUrl, getAccessToken],\n );\n};\n\n/**\n * Hook to get the balance of the user's app wallet\n */\nexport const useBalance = (queryOptions?: ReturnType<typeof balanceOptions>) =>\n useQuery({ ...balanceOptions(useOptions<BalanceData>()), ...queryOptions });\n\nexport const useAddress = (queryOptions?: ReturnType<typeof addressOptions>) =>\n useQuery({ ...addressOptions(useOptions<AddressData>()), ...queryOptions });\n\nexport const useAccount = () => {\n const { data: address, isLoading: isAddressLoading } = useAddress();\n\n const { baseUrl, getAccessToken } = usePermiContext();\n\n const getAuthOptions = <T extends TDataShape>(options: Options<T>) => {\n return getOptions<T>(\n {\n baseUrl,\n ...options,\n },\n getAccessToken,\n );\n };\n\n const account = !address\n ? undefined\n : toAccount({\n address: address as Address,\n signMessage: async (params) => {\n return await coreSignMessage(\n getAuthOptions({\n body: params,\n }),\n ).then((res) => res.data as Hex);\n },\n signTransaction: async (params) => {\n return await coreSignTransaction(\n getAuthOptions({ body: params }),\n ).then((res) => res.data as Hex);\n },\n signTypedData: async (params) => {\n return await coreSignTypedData(getAuthOptions({ body: params })).then(\n (res) => res.data as Hex,\n );\n },\n });\n\n return {\n data: account,\n isLoading: isAddressLoading,\n };\n};\n\nexport { useAuth } from \"./use-auth\";\n","import React, { useMemo, createContext, useContext } from \"react\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { useAuth } from \"react-oidc-context\";\nimport { AuthProvider } from \"./auth\";\nimport { PermiConfig } from \"src/types/config\";\n\ninterface Props extends PermiConfig {\n children: React.ReactNode;\n queryClient?: QueryClient;\n}\n\ninterface PermiContextValue {\n baseUrl?: string;\n getAccessToken: () => string;\n}\n\nconst PermiContext = createContext<PermiContextValue | null>(null);\n\nexport const usePermiContext = () => {\n const context = useContext(PermiContext);\n if (!context) {\n throw new Error(\"usePermiContext must be used within PermiProvider\");\n }\n return context;\n};\n\nexport const PermiProvider: React.FC<Props> = ({\n children,\n queryClient,\n ...props\n}) => {\n const defaultQueryClient = useMemo(() => new QueryClient(), []);\n\n return (\n <QueryClientProvider client={queryClient ?? defaultQueryClient}>\n <AuthProvider {...props}>\n <PermiProviderRaw baseUrl={props.baseUrl}>{children}</PermiProviderRaw>\n </AuthProvider>\n </QueryClientProvider>\n );\n};\n\nconst PermiProviderRaw = ({\n children,\n baseUrl,\n}: {\n children: React.ReactNode;\n baseUrl?: string;\n}) => {\n const { user } = useAuth();\n\n const contextValue = useMemo<PermiContextValue>(\n () => ({\n baseUrl: baseUrl ? `${baseUrl}/api` : undefined,\n getAccessToken: () => user?.access_token ?? \"\",\n }),\n [user, baseUrl],\n );\n\n return (\n <PermiContext.Provider value={contextValue}>\n {children}\n </PermiContext.Provider>\n );\n};\n","import { ReactNode, useMemo } from \"react\";\n\nimport { StateStore, UserManager, WebStorageStateStore } from \"oidc-client-ts\";\n\nimport { AuthProvider as AuthProviderComponent } from \"react-oidc-context\";\nimport { PermiConfig } from \"src/types/config\";\n\ninterface AuthProviderProps extends PermiConfig {\n children: ReactNode;\n userStore?: StateStore;\n}\n\nexport const AuthProvider: React.FC<AuthProviderProps> = ({\n children,\n clientId,\n userStore: userStoreProp,\n baseUrl = \"https://permi.xyz\",\n}) => {\n const userStore = useMemo(() => {\n return (\n userStoreProp ??\n new WebStorageStateStore({\n store: window.localStorage,\n prefix: \"permi-auth\",\n })\n );\n }, [userStoreProp]);\n\n return (\n <AuthProviderComponent\n userManager={\n new UserManager({\n authority: baseUrl,\n client_id: clientId,\n redirect_uri: window.location.origin,\n silentRequestTimeoutInSeconds: 10,\n automaticSilentRenew: true,\n silent_redirect_uri: window.location.origin,\n metadata: {\n authorization_endpoint: `${baseUrl}/api/oauth/authorize`,\n token_endpoint: `${baseUrl}/api/oauth/token`,\n userinfo_endpoint: `${baseUrl}/api/oauth/userinfo`,\n issuer: baseUrl,\n },\n userStore,\n })\n }\n onSigninCallback={() => {\n if (window.location.search.includes(\"code=\")) {\n window.history.replaceState(\n {},\n document.title,\n window.location.pathname,\n );\n }\n }}\n >\n {children}\n </AuthProviderComponent>\n );\n};\n","import { useCallback } from \"react\";\nimport { useAuth as useAuthContext } from \"react-oidc-context\";\n\nexport const useAuth = () => {\n const auth = useAuthContext();\n const { isAuthenticated, isLoading, error } = auth;\n\n const signIn = useCallback(() => {\n if (isLoading || isAuthenticated) {\n throw new Error(\"Already authenticated\");\n }\n return auth.signinRedirect();\n }, [auth, isLoading, isAuthenticated]);\n\n const signOut = useCallback(() => {\n if (!isAuthenticated) {\n throw new Error(\"Not authenticated\");\n }\n return auth.signoutRedirect();\n }, [auth, isAuthenticated]);\n\n return {\n signIn,\n signOut,\n isAuthenticated,\n isLoading,\n error,\n };\n};\n"],"mappings":"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","names":["useMemo","useMemo","jsx","useMemo","useAuth","useMemo"]}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@permi/react",
3
+ "version": "0.0.3",
4
+ "description": "React SDK for Permi OAuth2 + PKCE authentication and token management",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/permi/permi.git",
9
+ "directory": "sdks/react"
10
+ },
11
+ "author": "Permi",
12
+ "type": "module",
13
+ "main": "./dist/index.cjs",
14
+ "module": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js",
20
+ "require": "./dist/index.cjs"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
28
+ "keywords": [
29
+ "permi",
30
+ "sdk",
31
+ "react",
32
+ "oauth2",
33
+ "pkce",
34
+ "authentication"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "peerDependencies": {
40
+ "@tanstack/react-query": "^5.90.12",
41
+ "react": "^18.0.0 || ^19.0.0",
42
+ "react-dom": "^18.0.0 || ^19.0.0"
43
+ },
44
+ "dependencies": {
45
+ "oidc-client-ts": "^3.2.1",
46
+ "react-oidc-context": "^3.3.0",
47
+ "viem": "^2.41.2",
48
+ "@permi/core": "0.0.1"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^20",
52
+ "@types/react": "19.2.2",
53
+ "@types/react-dom": "19.2.2",
54
+ "eslint": "^9",
55
+ "tsup": "^8.5.1",
56
+ "typescript": "^5",
57
+ "@permi/typescript-config": "0.0.0",
58
+ "@permi/eslint-config": "0.0.0"
59
+ },
60
+ "scripts": {
61
+ "build": "tsup",
62
+ "dev": "tsup --watch",
63
+ "clean": "rm -rf dist",
64
+ "types:check": "tsc --noEmit",
65
+ "knip": "pnpm -w knip --workspace ./sdks/react",
66
+ "format": "pnpm -w format:dir ./sdks/react",
67
+ "format:check": "pnpm -w format:check:dir ./sdks/react",
68
+ "publish:check": "pnpm pack --dry-run"
69
+ }
70
+ }