@horus-wallet/sdk-react 0.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +398 -0
- package/dist/index.cjs +682 -0
- package/dist/index.d.cts +314 -0
- package/dist/index.d.ts +314 -0
- package/dist/index.js +648 -0
- package/package.json +69 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { ReactNode, ButtonHTMLAttributes } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Public types for `@horus-wallet/sdk-react`.
|
|
5
|
+
*
|
|
6
|
+
* The React package targets the partner's BACKEND-PROXY pattern:
|
|
7
|
+
* partner runs a thin proxy on their server (which holds the
|
|
8
|
+
* `hk_sk_*` secret) and the React hooks call that proxy. Each hook's
|
|
9
|
+
* `apiBase` defaults to `/api/horus` — partners can override via
|
|
10
|
+
* provider config. v0.2 will add a publishable-key tier that lets
|
|
11
|
+
* the React SDK call Horus directly without the partner-backend hop.
|
|
12
|
+
*/
|
|
13
|
+
/** Tokens returned from any successful auth flow. */
|
|
14
|
+
interface AuthTokens {
|
|
15
|
+
idToken: string;
|
|
16
|
+
refreshToken: string;
|
|
17
|
+
expiresIn: number;
|
|
18
|
+
/** Local epoch-seconds when the cached idToken expires. Computed on receipt. */
|
|
19
|
+
localExpiresAt: number;
|
|
20
|
+
localId: string;
|
|
21
|
+
email?: string;
|
|
22
|
+
emailVerified?: boolean;
|
|
23
|
+
displayName?: string;
|
|
24
|
+
photoUrl?: string;
|
|
25
|
+
providerId?: string;
|
|
26
|
+
}
|
|
27
|
+
/** Subset of the tokens that's safe to expose to consuming hooks. */
|
|
28
|
+
interface User {
|
|
29
|
+
uid: string;
|
|
30
|
+
email?: string;
|
|
31
|
+
emailVerified?: boolean;
|
|
32
|
+
displayName?: string;
|
|
33
|
+
photoUrl?: string;
|
|
34
|
+
/** Provider id from the sign-in path: 'password' | 'emailLink' | 'google.com' | etc. */
|
|
35
|
+
providerId?: string;
|
|
36
|
+
}
|
|
37
|
+
type AuthState = {
|
|
38
|
+
status: 'loading';
|
|
39
|
+
} | {
|
|
40
|
+
status: 'unauthenticated';
|
|
41
|
+
} | {
|
|
42
|
+
status: 'authenticated';
|
|
43
|
+
user: User;
|
|
44
|
+
tokens: AuthTokens;
|
|
45
|
+
};
|
|
46
|
+
/** Branding the partner can pass to the popup-opened auth flows. Mirrors the SDK's HorusAuthBranding shape. */
|
|
47
|
+
interface HorusBranding {
|
|
48
|
+
logoUrl?: string;
|
|
49
|
+
brandName?: string;
|
|
50
|
+
primaryColor?: string;
|
|
51
|
+
backgroundColor?: string;
|
|
52
|
+
fontFamily?: string;
|
|
53
|
+
termsUrl?: string;
|
|
54
|
+
privacyUrl?: string;
|
|
55
|
+
showPoweredByHorus?: boolean;
|
|
56
|
+
}
|
|
57
|
+
/** Configuration for `<HorusProvider>`. */
|
|
58
|
+
interface HorusProviderConfig {
|
|
59
|
+
/** Server-assigned id of the partner's app. Used by the popup for white-label policy lookup. */
|
|
60
|
+
appId: string;
|
|
61
|
+
/**
|
|
62
|
+
* URL prefix where the partner's backend exposes the Horus proxy
|
|
63
|
+
* routes. Defaults to `/api/horus`. The proxy routes the SDK
|
|
64
|
+
* expects:
|
|
65
|
+
* - POST {apiBase}/auth/email/signin → tokens
|
|
66
|
+
* - POST {apiBase}/auth/email/signup → tokens
|
|
67
|
+
* - POST {apiBase}/auth/email-link/send → ok
|
|
68
|
+
* - POST {apiBase}/auth/email-link/verify → tokens
|
|
69
|
+
* - POST {apiBase}/auth/oauth → tokens (federate Google/Apple/etc.)
|
|
70
|
+
* - POST {apiBase}/auth/refresh → tokens
|
|
71
|
+
* - GET {apiBase}/wallets → wallets list
|
|
72
|
+
* - GET {apiBase}/wallets/:network → wallet details
|
|
73
|
+
* - POST {apiBase}/sign-message → signature
|
|
74
|
+
* - POST {apiBase}/transfer/native → tx hash
|
|
75
|
+
* - POST {apiBase}/transfer/token → tx hash
|
|
76
|
+
*
|
|
77
|
+
* The README shows a reference backend implementation in <50 lines.
|
|
78
|
+
*/
|
|
79
|
+
apiBase?: string;
|
|
80
|
+
/**
|
|
81
|
+
* Auth-page URL. Defaults to `https://auth.horuswallet.com`. The
|
|
82
|
+
* popup-based loginWithGoogle / loginWithEmailLink / loginWithPhone
|
|
83
|
+
* methods open this URL.
|
|
84
|
+
*/
|
|
85
|
+
authPageUrl?: string;
|
|
86
|
+
/** Per-popup branding — passed to HorusAuth. White-label tier is gated server-side. */
|
|
87
|
+
branding?: HorusBranding;
|
|
88
|
+
/** Where to persist tokens between page loads. Default 'localStorage'. */
|
|
89
|
+
tokenStorage?: 'localStorage' | 'sessionStorage' | 'memory';
|
|
90
|
+
/**
|
|
91
|
+
* If a fetch returns 401, retry once after refreshing the token.
|
|
92
|
+
* Default true. Disable when you're handling expiry manually.
|
|
93
|
+
*/
|
|
94
|
+
autoRefresh?: boolean;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Provider component — partner wraps their app once, hooks Just Work
|
|
99
|
+
* everywhere underneath.
|
|
100
|
+
*
|
|
101
|
+
* <HorusProvider appId="app_acme123">
|
|
102
|
+
* <App />
|
|
103
|
+
* </HorusProvider>
|
|
104
|
+
*
|
|
105
|
+
* Reads tokens from the configured store on mount, exposes them via
|
|
106
|
+
* Context, and refreshes proactively when they near expiry. Multiple
|
|
107
|
+
* tabs stay in sync via a `storage` event listener.
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
interface HorusProviderProps extends HorusProviderConfig {
|
|
111
|
+
children: ReactNode;
|
|
112
|
+
}
|
|
113
|
+
declare function HorusProvider(props: HorusProviderProps): JSX.Element;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The main auth hook. Returns the current state plus every sign-in
|
|
117
|
+
* method we expose. Mirrors Privy's `usePrivy()` shape so partners
|
|
118
|
+
* coming from there have a familiar API.
|
|
119
|
+
*
|
|
120
|
+
* const {
|
|
121
|
+
* ready, // SDK initialized
|
|
122
|
+
* authenticated, // true if user is signed in
|
|
123
|
+
* user, // { uid, email, ... } or undefined
|
|
124
|
+
* loginWithEmail,
|
|
125
|
+
* signUpWithEmail,
|
|
126
|
+
* loginWithGoogle, // popup
|
|
127
|
+
* loginWithEmailLink,
|
|
128
|
+
* loginWithPhone, // popup (SMS verification via auth.horuswallet.com)
|
|
129
|
+
* sendEmailLink,
|
|
130
|
+
* verifyEmailLink,
|
|
131
|
+
* logout,
|
|
132
|
+
* refresh,
|
|
133
|
+
* } = useHorusAuth();
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
interface EmailPasswordInput {
|
|
137
|
+
email: string;
|
|
138
|
+
password: string;
|
|
139
|
+
}
|
|
140
|
+
interface SendEmailLinkInput {
|
|
141
|
+
email: string;
|
|
142
|
+
/** URL on the partner's site that the magic-link returns to. */
|
|
143
|
+
continueUrl: string;
|
|
144
|
+
}
|
|
145
|
+
interface VerifyEmailLinkInput {
|
|
146
|
+
email: string;
|
|
147
|
+
oobCode: string;
|
|
148
|
+
}
|
|
149
|
+
interface UseHorusAuthResult {
|
|
150
|
+
/** True once the provider has hydrated from storage. */
|
|
151
|
+
ready: boolean;
|
|
152
|
+
/** True if there's a valid cached idToken. */
|
|
153
|
+
authenticated: boolean;
|
|
154
|
+
/** Current user's identity claims, or undefined when unauthenticated. */
|
|
155
|
+
user: User | undefined;
|
|
156
|
+
/** Email + password sign-in. */
|
|
157
|
+
loginWithEmail: (input: EmailPasswordInput) => Promise<User>;
|
|
158
|
+
/** Email + password sign-up. */
|
|
159
|
+
signUpWithEmail: (input: EmailPasswordInput) => Promise<User>;
|
|
160
|
+
/** Send a magic link to the given email. Two-step — call verifyEmailLink with the oobCode after the user clicks. */
|
|
161
|
+
sendEmailLink: (input: SendEmailLinkInput) => Promise<void>;
|
|
162
|
+
/** Complete a magic-link sign-in given the oobCode the partner extracted from the redirect URL. */
|
|
163
|
+
verifyEmailLink: (input: VerifyEmailLinkInput) => Promise<User>;
|
|
164
|
+
/** Open the auth.horuswallet.com popup for Google sign-in. */
|
|
165
|
+
loginWithGoogle: () => Promise<User>;
|
|
166
|
+
/** Open the popup for email-link UI (alternative to send/verify if the partner doesn't have a redirect page). */
|
|
167
|
+
loginWithEmailLink: () => Promise<User>;
|
|
168
|
+
/** Open the popup for phone (SMS) sign-in. */
|
|
169
|
+
loginWithPhone: (opts?: {
|
|
170
|
+
phone?: string;
|
|
171
|
+
}) => Promise<User>;
|
|
172
|
+
/** Sign out — clears tokens locally; partner's backend should also revoke if applicable. */
|
|
173
|
+
logout: () => void;
|
|
174
|
+
/** Manually refresh the cached idToken. */
|
|
175
|
+
refresh: () => Promise<AuthTokens>;
|
|
176
|
+
}
|
|
177
|
+
declare function useHorusAuth(): UseHorusAuthResult;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Convenience hook — partners that only want the current user object
|
|
181
|
+
* without the full auth surface. Returns `undefined` when
|
|
182
|
+
* unauthenticated; never throws.
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
declare function useUser(): User | undefined;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* `useWallets()` — fetches the signed-in user's wallets from the
|
|
189
|
+
* partner's backend proxy. Refetches when auth state changes.
|
|
190
|
+
*
|
|
191
|
+
* Mirror of Privy's `useWallets()` — partners coming from there get
|
|
192
|
+
* a familiar `{ wallets, ready }` shape. Each wallet is a thin
|
|
193
|
+
* descriptor; signing happens via `useSignMessage` / `useTransfer`
|
|
194
|
+
* (kept as separate hooks so a single re-render of one doesn't
|
|
195
|
+
* invalidate the other).
|
|
196
|
+
*/
|
|
197
|
+
interface WalletDescriptor {
|
|
198
|
+
network: string;
|
|
199
|
+
networkType?: string;
|
|
200
|
+
/** Public address — chain-specific shape (0x… for EVM, base58 for ICP, etc.). */
|
|
201
|
+
publicKey: string;
|
|
202
|
+
defaultReceivingAddress?: string;
|
|
203
|
+
hasPassword?: boolean;
|
|
204
|
+
}
|
|
205
|
+
interface UseWalletsResult {
|
|
206
|
+
ready: boolean;
|
|
207
|
+
wallets: WalletDescriptor[];
|
|
208
|
+
/** Manual refetch — useful after wallets.create or import. */
|
|
209
|
+
refresh: () => Promise<void>;
|
|
210
|
+
/** Last error from the load, if any. */
|
|
211
|
+
error: Error | undefined;
|
|
212
|
+
}
|
|
213
|
+
declare function useWallets(): UseWalletsResult;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* `useSignMessage()` — signs a UTF-8 message with the user's wallet.
|
|
217
|
+
* EVM applies EIP-191 prefix server-side; Casper raw-signs; other
|
|
218
|
+
* chains follow their conventions. Returns a stable callback that
|
|
219
|
+
* `useState`-loop-friendly forms can wire to a submit handler.
|
|
220
|
+
*/
|
|
221
|
+
interface SignMessageInput {
|
|
222
|
+
network: string;
|
|
223
|
+
networkType: 'MAINNET' | 'TESTNET';
|
|
224
|
+
message: string;
|
|
225
|
+
walletIndex?: number;
|
|
226
|
+
/** Wallet password if the user has one. Many partners prompt + pass inline. */
|
|
227
|
+
password?: string;
|
|
228
|
+
}
|
|
229
|
+
interface UseSignMessageResult {
|
|
230
|
+
signMessage: (input: SignMessageInput) => Promise<string>;
|
|
231
|
+
/** True while a signature request is in flight. */
|
|
232
|
+
pending: boolean;
|
|
233
|
+
/** Last error, if any. Cleared on the next attempt. */
|
|
234
|
+
error: Error | undefined;
|
|
235
|
+
}
|
|
236
|
+
declare function useSignMessage(): UseSignMessageResult;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* `useTransfer()` — native + token transfer helpers backed by the
|
|
240
|
+
* partner's proxy. Each variant returns `{ pending, error }` so
|
|
241
|
+
* forms can drive disabled-state without local plumbing.
|
|
242
|
+
*/
|
|
243
|
+
interface NativeTransferInput {
|
|
244
|
+
network: string;
|
|
245
|
+
networkType: 'MAINNET' | 'TESTNET';
|
|
246
|
+
/** One or more recipient addresses. */
|
|
247
|
+
recipients: string[];
|
|
248
|
+
/** Amount in the chain's smallest unit (wei / sats / motes / e8s). String / bigint / number. */
|
|
249
|
+
amount: string | bigint | number;
|
|
250
|
+
walletIndex?: number;
|
|
251
|
+
password?: string;
|
|
252
|
+
}
|
|
253
|
+
interface TokenTransferInput {
|
|
254
|
+
network: string;
|
|
255
|
+
networkType: 'MAINNET' | 'TESTNET';
|
|
256
|
+
tokenAddress: string;
|
|
257
|
+
recipient: string;
|
|
258
|
+
amount: string | bigint | number;
|
|
259
|
+
walletIndex?: number;
|
|
260
|
+
password?: string;
|
|
261
|
+
}
|
|
262
|
+
interface UseTransferResult {
|
|
263
|
+
native: (input: NativeTransferInput) => Promise<{
|
|
264
|
+
txHash: string;
|
|
265
|
+
}>;
|
|
266
|
+
token: (input: TokenTransferInput) => Promise<{
|
|
267
|
+
txHash: string;
|
|
268
|
+
}>;
|
|
269
|
+
pending: boolean;
|
|
270
|
+
error: Error | undefined;
|
|
271
|
+
}
|
|
272
|
+
declare function useTransfer(): UseTransferResult;
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* `<HorusLoginButton>` — the simplest "drop in and ship" component.
|
|
276
|
+
* Renders a styled button that opens the auth.horuswallet.com popup
|
|
277
|
+
* for the configured flow. Partners that want full UI control build
|
|
278
|
+
* their own button + call `useHorusAuth()` methods directly.
|
|
279
|
+
*
|
|
280
|
+
* <HorusLoginButton flow="google">Continue with Google</HorusLoginButton>
|
|
281
|
+
*
|
|
282
|
+
* Picks up branding + appId from the HorusProvider automatically.
|
|
283
|
+
* Auto-disables itself while the popup is open so a double-click
|
|
284
|
+
* doesn't open a second window.
|
|
285
|
+
*/
|
|
286
|
+
|
|
287
|
+
type PopupFlow = 'google' | 'email_link' | 'phone';
|
|
288
|
+
interface HorusLoginButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'onError'> {
|
|
289
|
+
/** Which flow to open. Defaults to 'google' — the most common one-click signup. */
|
|
290
|
+
flow?: PopupFlow;
|
|
291
|
+
/** Pre-fill for the phone flow. Ignored otherwise. */
|
|
292
|
+
phone?: string;
|
|
293
|
+
/** Called after a successful sign-in. Receives the new user. */
|
|
294
|
+
onAuthenticated?: (user: ReturnType<typeof useHorusAuth>['user']) => void;
|
|
295
|
+
/** Called on user cancel / popup-blocked / auth error. */
|
|
296
|
+
onError?: (err: Error) => void;
|
|
297
|
+
children?: ReactNode;
|
|
298
|
+
}
|
|
299
|
+
declare function HorusLoginButton({ flow, phone, onAuthenticated, onError, children, disabled, style, ...rest }: HorusLoginButtonProps): JSX.Element;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Fetch wrapper for calls to the partner's backend proxy. Handles
|
|
303
|
+
* the auto-refresh-on-401 dance + JSON serialization + a typed
|
|
304
|
+
* error so consuming hooks can branch on `err.status`.
|
|
305
|
+
*/
|
|
306
|
+
|
|
307
|
+
declare class HorusHttpError extends Error {
|
|
308
|
+
readonly status: number;
|
|
309
|
+
readonly code?: string;
|
|
310
|
+
readonly body: unknown;
|
|
311
|
+
constructor(status: number, message: string, body: unknown, code?: string);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export { type AuthState, type AuthTokens, type HorusBranding, HorusHttpError, HorusLoginButton, type HorusLoginButtonProps, HorusProvider, type HorusProviderConfig, type HorusProviderProps, type NativeTransferInput, type SignMessageInput, type TokenTransferInput, type UseHorusAuthResult, type User, type WalletDescriptor, useHorusAuth, useSignMessage, useTransfer, useUser, useWallets };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { ReactNode, ButtonHTMLAttributes } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Public types for `@horus-wallet/sdk-react`.
|
|
5
|
+
*
|
|
6
|
+
* The React package targets the partner's BACKEND-PROXY pattern:
|
|
7
|
+
* partner runs a thin proxy on their server (which holds the
|
|
8
|
+
* `hk_sk_*` secret) and the React hooks call that proxy. Each hook's
|
|
9
|
+
* `apiBase` defaults to `/api/horus` — partners can override via
|
|
10
|
+
* provider config. v0.2 will add a publishable-key tier that lets
|
|
11
|
+
* the React SDK call Horus directly without the partner-backend hop.
|
|
12
|
+
*/
|
|
13
|
+
/** Tokens returned from any successful auth flow. */
|
|
14
|
+
interface AuthTokens {
|
|
15
|
+
idToken: string;
|
|
16
|
+
refreshToken: string;
|
|
17
|
+
expiresIn: number;
|
|
18
|
+
/** Local epoch-seconds when the cached idToken expires. Computed on receipt. */
|
|
19
|
+
localExpiresAt: number;
|
|
20
|
+
localId: string;
|
|
21
|
+
email?: string;
|
|
22
|
+
emailVerified?: boolean;
|
|
23
|
+
displayName?: string;
|
|
24
|
+
photoUrl?: string;
|
|
25
|
+
providerId?: string;
|
|
26
|
+
}
|
|
27
|
+
/** Subset of the tokens that's safe to expose to consuming hooks. */
|
|
28
|
+
interface User {
|
|
29
|
+
uid: string;
|
|
30
|
+
email?: string;
|
|
31
|
+
emailVerified?: boolean;
|
|
32
|
+
displayName?: string;
|
|
33
|
+
photoUrl?: string;
|
|
34
|
+
/** Provider id from the sign-in path: 'password' | 'emailLink' | 'google.com' | etc. */
|
|
35
|
+
providerId?: string;
|
|
36
|
+
}
|
|
37
|
+
type AuthState = {
|
|
38
|
+
status: 'loading';
|
|
39
|
+
} | {
|
|
40
|
+
status: 'unauthenticated';
|
|
41
|
+
} | {
|
|
42
|
+
status: 'authenticated';
|
|
43
|
+
user: User;
|
|
44
|
+
tokens: AuthTokens;
|
|
45
|
+
};
|
|
46
|
+
/** Branding the partner can pass to the popup-opened auth flows. Mirrors the SDK's HorusAuthBranding shape. */
|
|
47
|
+
interface HorusBranding {
|
|
48
|
+
logoUrl?: string;
|
|
49
|
+
brandName?: string;
|
|
50
|
+
primaryColor?: string;
|
|
51
|
+
backgroundColor?: string;
|
|
52
|
+
fontFamily?: string;
|
|
53
|
+
termsUrl?: string;
|
|
54
|
+
privacyUrl?: string;
|
|
55
|
+
showPoweredByHorus?: boolean;
|
|
56
|
+
}
|
|
57
|
+
/** Configuration for `<HorusProvider>`. */
|
|
58
|
+
interface HorusProviderConfig {
|
|
59
|
+
/** Server-assigned id of the partner's app. Used by the popup for white-label policy lookup. */
|
|
60
|
+
appId: string;
|
|
61
|
+
/**
|
|
62
|
+
* URL prefix where the partner's backend exposes the Horus proxy
|
|
63
|
+
* routes. Defaults to `/api/horus`. The proxy routes the SDK
|
|
64
|
+
* expects:
|
|
65
|
+
* - POST {apiBase}/auth/email/signin → tokens
|
|
66
|
+
* - POST {apiBase}/auth/email/signup → tokens
|
|
67
|
+
* - POST {apiBase}/auth/email-link/send → ok
|
|
68
|
+
* - POST {apiBase}/auth/email-link/verify → tokens
|
|
69
|
+
* - POST {apiBase}/auth/oauth → tokens (federate Google/Apple/etc.)
|
|
70
|
+
* - POST {apiBase}/auth/refresh → tokens
|
|
71
|
+
* - GET {apiBase}/wallets → wallets list
|
|
72
|
+
* - GET {apiBase}/wallets/:network → wallet details
|
|
73
|
+
* - POST {apiBase}/sign-message → signature
|
|
74
|
+
* - POST {apiBase}/transfer/native → tx hash
|
|
75
|
+
* - POST {apiBase}/transfer/token → tx hash
|
|
76
|
+
*
|
|
77
|
+
* The README shows a reference backend implementation in <50 lines.
|
|
78
|
+
*/
|
|
79
|
+
apiBase?: string;
|
|
80
|
+
/**
|
|
81
|
+
* Auth-page URL. Defaults to `https://auth.horuswallet.com`. The
|
|
82
|
+
* popup-based loginWithGoogle / loginWithEmailLink / loginWithPhone
|
|
83
|
+
* methods open this URL.
|
|
84
|
+
*/
|
|
85
|
+
authPageUrl?: string;
|
|
86
|
+
/** Per-popup branding — passed to HorusAuth. White-label tier is gated server-side. */
|
|
87
|
+
branding?: HorusBranding;
|
|
88
|
+
/** Where to persist tokens between page loads. Default 'localStorage'. */
|
|
89
|
+
tokenStorage?: 'localStorage' | 'sessionStorage' | 'memory';
|
|
90
|
+
/**
|
|
91
|
+
* If a fetch returns 401, retry once after refreshing the token.
|
|
92
|
+
* Default true. Disable when you're handling expiry manually.
|
|
93
|
+
*/
|
|
94
|
+
autoRefresh?: boolean;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Provider component — partner wraps their app once, hooks Just Work
|
|
99
|
+
* everywhere underneath.
|
|
100
|
+
*
|
|
101
|
+
* <HorusProvider appId="app_acme123">
|
|
102
|
+
* <App />
|
|
103
|
+
* </HorusProvider>
|
|
104
|
+
*
|
|
105
|
+
* Reads tokens from the configured store on mount, exposes them via
|
|
106
|
+
* Context, and refreshes proactively when they near expiry. Multiple
|
|
107
|
+
* tabs stay in sync via a `storage` event listener.
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
interface HorusProviderProps extends HorusProviderConfig {
|
|
111
|
+
children: ReactNode;
|
|
112
|
+
}
|
|
113
|
+
declare function HorusProvider(props: HorusProviderProps): JSX.Element;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The main auth hook. Returns the current state plus every sign-in
|
|
117
|
+
* method we expose. Mirrors Privy's `usePrivy()` shape so partners
|
|
118
|
+
* coming from there have a familiar API.
|
|
119
|
+
*
|
|
120
|
+
* const {
|
|
121
|
+
* ready, // SDK initialized
|
|
122
|
+
* authenticated, // true if user is signed in
|
|
123
|
+
* user, // { uid, email, ... } or undefined
|
|
124
|
+
* loginWithEmail,
|
|
125
|
+
* signUpWithEmail,
|
|
126
|
+
* loginWithGoogle, // popup
|
|
127
|
+
* loginWithEmailLink,
|
|
128
|
+
* loginWithPhone, // popup (SMS verification via auth.horuswallet.com)
|
|
129
|
+
* sendEmailLink,
|
|
130
|
+
* verifyEmailLink,
|
|
131
|
+
* logout,
|
|
132
|
+
* refresh,
|
|
133
|
+
* } = useHorusAuth();
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
interface EmailPasswordInput {
|
|
137
|
+
email: string;
|
|
138
|
+
password: string;
|
|
139
|
+
}
|
|
140
|
+
interface SendEmailLinkInput {
|
|
141
|
+
email: string;
|
|
142
|
+
/** URL on the partner's site that the magic-link returns to. */
|
|
143
|
+
continueUrl: string;
|
|
144
|
+
}
|
|
145
|
+
interface VerifyEmailLinkInput {
|
|
146
|
+
email: string;
|
|
147
|
+
oobCode: string;
|
|
148
|
+
}
|
|
149
|
+
interface UseHorusAuthResult {
|
|
150
|
+
/** True once the provider has hydrated from storage. */
|
|
151
|
+
ready: boolean;
|
|
152
|
+
/** True if there's a valid cached idToken. */
|
|
153
|
+
authenticated: boolean;
|
|
154
|
+
/** Current user's identity claims, or undefined when unauthenticated. */
|
|
155
|
+
user: User | undefined;
|
|
156
|
+
/** Email + password sign-in. */
|
|
157
|
+
loginWithEmail: (input: EmailPasswordInput) => Promise<User>;
|
|
158
|
+
/** Email + password sign-up. */
|
|
159
|
+
signUpWithEmail: (input: EmailPasswordInput) => Promise<User>;
|
|
160
|
+
/** Send a magic link to the given email. Two-step — call verifyEmailLink with the oobCode after the user clicks. */
|
|
161
|
+
sendEmailLink: (input: SendEmailLinkInput) => Promise<void>;
|
|
162
|
+
/** Complete a magic-link sign-in given the oobCode the partner extracted from the redirect URL. */
|
|
163
|
+
verifyEmailLink: (input: VerifyEmailLinkInput) => Promise<User>;
|
|
164
|
+
/** Open the auth.horuswallet.com popup for Google sign-in. */
|
|
165
|
+
loginWithGoogle: () => Promise<User>;
|
|
166
|
+
/** Open the popup for email-link UI (alternative to send/verify if the partner doesn't have a redirect page). */
|
|
167
|
+
loginWithEmailLink: () => Promise<User>;
|
|
168
|
+
/** Open the popup for phone (SMS) sign-in. */
|
|
169
|
+
loginWithPhone: (opts?: {
|
|
170
|
+
phone?: string;
|
|
171
|
+
}) => Promise<User>;
|
|
172
|
+
/** Sign out — clears tokens locally; partner's backend should also revoke if applicable. */
|
|
173
|
+
logout: () => void;
|
|
174
|
+
/** Manually refresh the cached idToken. */
|
|
175
|
+
refresh: () => Promise<AuthTokens>;
|
|
176
|
+
}
|
|
177
|
+
declare function useHorusAuth(): UseHorusAuthResult;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Convenience hook — partners that only want the current user object
|
|
181
|
+
* without the full auth surface. Returns `undefined` when
|
|
182
|
+
* unauthenticated; never throws.
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
declare function useUser(): User | undefined;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* `useWallets()` — fetches the signed-in user's wallets from the
|
|
189
|
+
* partner's backend proxy. Refetches when auth state changes.
|
|
190
|
+
*
|
|
191
|
+
* Mirror of Privy's `useWallets()` — partners coming from there get
|
|
192
|
+
* a familiar `{ wallets, ready }` shape. Each wallet is a thin
|
|
193
|
+
* descriptor; signing happens via `useSignMessage` / `useTransfer`
|
|
194
|
+
* (kept as separate hooks so a single re-render of one doesn't
|
|
195
|
+
* invalidate the other).
|
|
196
|
+
*/
|
|
197
|
+
interface WalletDescriptor {
|
|
198
|
+
network: string;
|
|
199
|
+
networkType?: string;
|
|
200
|
+
/** Public address — chain-specific shape (0x… for EVM, base58 for ICP, etc.). */
|
|
201
|
+
publicKey: string;
|
|
202
|
+
defaultReceivingAddress?: string;
|
|
203
|
+
hasPassword?: boolean;
|
|
204
|
+
}
|
|
205
|
+
interface UseWalletsResult {
|
|
206
|
+
ready: boolean;
|
|
207
|
+
wallets: WalletDescriptor[];
|
|
208
|
+
/** Manual refetch — useful after wallets.create or import. */
|
|
209
|
+
refresh: () => Promise<void>;
|
|
210
|
+
/** Last error from the load, if any. */
|
|
211
|
+
error: Error | undefined;
|
|
212
|
+
}
|
|
213
|
+
declare function useWallets(): UseWalletsResult;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* `useSignMessage()` — signs a UTF-8 message with the user's wallet.
|
|
217
|
+
* EVM applies EIP-191 prefix server-side; Casper raw-signs; other
|
|
218
|
+
* chains follow their conventions. Returns a stable callback that
|
|
219
|
+
* `useState`-loop-friendly forms can wire to a submit handler.
|
|
220
|
+
*/
|
|
221
|
+
interface SignMessageInput {
|
|
222
|
+
network: string;
|
|
223
|
+
networkType: 'MAINNET' | 'TESTNET';
|
|
224
|
+
message: string;
|
|
225
|
+
walletIndex?: number;
|
|
226
|
+
/** Wallet password if the user has one. Many partners prompt + pass inline. */
|
|
227
|
+
password?: string;
|
|
228
|
+
}
|
|
229
|
+
interface UseSignMessageResult {
|
|
230
|
+
signMessage: (input: SignMessageInput) => Promise<string>;
|
|
231
|
+
/** True while a signature request is in flight. */
|
|
232
|
+
pending: boolean;
|
|
233
|
+
/** Last error, if any. Cleared on the next attempt. */
|
|
234
|
+
error: Error | undefined;
|
|
235
|
+
}
|
|
236
|
+
declare function useSignMessage(): UseSignMessageResult;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* `useTransfer()` — native + token transfer helpers backed by the
|
|
240
|
+
* partner's proxy. Each variant returns `{ pending, error }` so
|
|
241
|
+
* forms can drive disabled-state without local plumbing.
|
|
242
|
+
*/
|
|
243
|
+
interface NativeTransferInput {
|
|
244
|
+
network: string;
|
|
245
|
+
networkType: 'MAINNET' | 'TESTNET';
|
|
246
|
+
/** One or more recipient addresses. */
|
|
247
|
+
recipients: string[];
|
|
248
|
+
/** Amount in the chain's smallest unit (wei / sats / motes / e8s). String / bigint / number. */
|
|
249
|
+
amount: string | bigint | number;
|
|
250
|
+
walletIndex?: number;
|
|
251
|
+
password?: string;
|
|
252
|
+
}
|
|
253
|
+
interface TokenTransferInput {
|
|
254
|
+
network: string;
|
|
255
|
+
networkType: 'MAINNET' | 'TESTNET';
|
|
256
|
+
tokenAddress: string;
|
|
257
|
+
recipient: string;
|
|
258
|
+
amount: string | bigint | number;
|
|
259
|
+
walletIndex?: number;
|
|
260
|
+
password?: string;
|
|
261
|
+
}
|
|
262
|
+
interface UseTransferResult {
|
|
263
|
+
native: (input: NativeTransferInput) => Promise<{
|
|
264
|
+
txHash: string;
|
|
265
|
+
}>;
|
|
266
|
+
token: (input: TokenTransferInput) => Promise<{
|
|
267
|
+
txHash: string;
|
|
268
|
+
}>;
|
|
269
|
+
pending: boolean;
|
|
270
|
+
error: Error | undefined;
|
|
271
|
+
}
|
|
272
|
+
declare function useTransfer(): UseTransferResult;
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* `<HorusLoginButton>` — the simplest "drop in and ship" component.
|
|
276
|
+
* Renders a styled button that opens the auth.horuswallet.com popup
|
|
277
|
+
* for the configured flow. Partners that want full UI control build
|
|
278
|
+
* their own button + call `useHorusAuth()` methods directly.
|
|
279
|
+
*
|
|
280
|
+
* <HorusLoginButton flow="google">Continue with Google</HorusLoginButton>
|
|
281
|
+
*
|
|
282
|
+
* Picks up branding + appId from the HorusProvider automatically.
|
|
283
|
+
* Auto-disables itself while the popup is open so a double-click
|
|
284
|
+
* doesn't open a second window.
|
|
285
|
+
*/
|
|
286
|
+
|
|
287
|
+
type PopupFlow = 'google' | 'email_link' | 'phone';
|
|
288
|
+
interface HorusLoginButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'onError'> {
|
|
289
|
+
/** Which flow to open. Defaults to 'google' — the most common one-click signup. */
|
|
290
|
+
flow?: PopupFlow;
|
|
291
|
+
/** Pre-fill for the phone flow. Ignored otherwise. */
|
|
292
|
+
phone?: string;
|
|
293
|
+
/** Called after a successful sign-in. Receives the new user. */
|
|
294
|
+
onAuthenticated?: (user: ReturnType<typeof useHorusAuth>['user']) => void;
|
|
295
|
+
/** Called on user cancel / popup-blocked / auth error. */
|
|
296
|
+
onError?: (err: Error) => void;
|
|
297
|
+
children?: ReactNode;
|
|
298
|
+
}
|
|
299
|
+
declare function HorusLoginButton({ flow, phone, onAuthenticated, onError, children, disabled, style, ...rest }: HorusLoginButtonProps): JSX.Element;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Fetch wrapper for calls to the partner's backend proxy. Handles
|
|
303
|
+
* the auto-refresh-on-401 dance + JSON serialization + a typed
|
|
304
|
+
* error so consuming hooks can branch on `err.status`.
|
|
305
|
+
*/
|
|
306
|
+
|
|
307
|
+
declare class HorusHttpError extends Error {
|
|
308
|
+
readonly status: number;
|
|
309
|
+
readonly code?: string;
|
|
310
|
+
readonly body: unknown;
|
|
311
|
+
constructor(status: number, message: string, body: unknown, code?: string);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export { type AuthState, type AuthTokens, type HorusBranding, HorusHttpError, HorusLoginButton, type HorusLoginButtonProps, HorusProvider, type HorusProviderConfig, type HorusProviderProps, type NativeTransferInput, type SignMessageInput, type TokenTransferInput, type UseHorusAuthResult, type User, type WalletDescriptor, useHorusAuth, useSignMessage, useTransfer, useUser, useWallets };
|