@edge-markets/connect-react-native 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.
@@ -0,0 +1,355 @@
1
+ import { EdgeEnvironment, EdgeLinkSuccess, EdgeLinkExit, EdgeScope } from '@edge-markets/connect';
2
+ export { ALL_EDGE_SCOPES, Balance, EDGE_ENVIRONMENTS, EdgeApiError, EdgeAuthenticationError, EdgeConsentRequiredError, EdgeEnvironment, EdgeError, EdgeLinkExit, EdgeLinkSuccess, EdgeNetworkError, EdgePopupBlockedError, EdgeScope, EdgeStateMismatchError, EdgeTokenExchangeError, EdgeTokens, SCOPE_DESCRIPTIONS, Transfer, User, formatScopesForEnvironment, getEnvironmentConfig, isApiError, isAuthenticationError, isConsentRequiredError, isNetworkError } from '@edge-markets/connect';
3
+
4
+ /**
5
+ * EdgeLink for React Native - Plaid-Style Authentication Flow
6
+ *
7
+ * Unlike the browser SDK which uses popups, the React Native SDK uses:
8
+ * - In-App Browser (SFSafariViewController / Chrome Custom Tabs)
9
+ * - Deep Links for OAuth callback
10
+ * - Secure storage for PKCE state
11
+ *
12
+ * This provides a native, secure authentication experience similar to Plaid Link.
13
+ *
14
+ * @module @edge-markets/connect-react-native
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { EdgeLink } from '@edge-markets/connect-react-native'
19
+ *
20
+ * const link = new EdgeLink({
21
+ * clientId: 'your-client-id',
22
+ * environment: 'staging',
23
+ * redirectUri: 'myapp://oauth/callback',
24
+ * onSuccess: async (result) => {
25
+ * await sendToBackend(result.code, result.codeVerifier)
26
+ * },
27
+ * onExit: (metadata) => {
28
+ * console.log('User exited:', metadata.reason)
29
+ * },
30
+ * })
31
+ *
32
+ * // Open from a button press
33
+ * <Button onPress={() => link.open()} title="Connect EdgeBoost" />
34
+ * ```
35
+ */
36
+
37
+ /**
38
+ * Configuration for EdgeLink React Native.
39
+ */
40
+ interface EdgeLinkConfig {
41
+ /**
42
+ * Your OAuth client ID from the EdgeBoost partner portal.
43
+ */
44
+ clientId: string;
45
+ /**
46
+ * Environment to connect to.
47
+ */
48
+ environment: EdgeEnvironment;
49
+ /**
50
+ * Deep link URI for OAuth callback.
51
+ *
52
+ * This must be registered in your app's URL schemes (iOS) and
53
+ * intent filters (Android), and in your EdgeBoost OAuth client settings.
54
+ *
55
+ * @example
56
+ * - Custom scheme: `myapp://oauth/callback`
57
+ * - Universal link: `https://myapp.com/oauth/callback`
58
+ */
59
+ redirectUri: string;
60
+ /**
61
+ * Called when user successfully authenticates and grants consent.
62
+ */
63
+ onSuccess: (result: EdgeLinkSuccess) => void;
64
+ /**
65
+ * Called when user exits the flow.
66
+ */
67
+ onExit?: (metadata: EdgeLinkExit) => void;
68
+ /**
69
+ * Called for various events during the flow.
70
+ */
71
+ onEvent?: (event: EdgeLinkEvent) => void;
72
+ /**
73
+ * OAuth scopes to request.
74
+ * @default All available scopes
75
+ */
76
+ scopes?: EdgeScope[];
77
+ /**
78
+ * Custom URL for the Link page (development only).
79
+ */
80
+ linkUrl?: string;
81
+ /**
82
+ * Use external browser instead of in-app browser.
83
+ * @default false
84
+ */
85
+ useExternalBrowser?: boolean;
86
+ }
87
+ /**
88
+ * Event emitted during the Link flow.
89
+ */
90
+ interface EdgeLinkEvent {
91
+ eventName: EdgeLinkEventName;
92
+ timestamp: number;
93
+ metadata?: Record<string, unknown>;
94
+ }
95
+ type EdgeLinkEventName = 'OPEN' | 'CLOSE' | 'HANDOFF' | 'SUCCESS' | 'ERROR' | 'REDIRECT';
96
+ /**
97
+ * EdgeLink for React Native - handles OAuth flow with in-app browser.
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * const link = new EdgeLink({
102
+ * clientId: 'your-client-id',
103
+ * environment: 'staging',
104
+ * redirectUri: 'myapp://oauth/callback',
105
+ * onSuccess: handleSuccess,
106
+ * onExit: handleExit,
107
+ * })
108
+ *
109
+ * // Later, in response to user action
110
+ * await link.open()
111
+ * ```
112
+ */
113
+ declare class EdgeLink {
114
+ private readonly config;
115
+ private pkce;
116
+ private state;
117
+ private linkListener;
118
+ private isOpen;
119
+ private isDestroyed;
120
+ constructor(config: EdgeLinkConfig);
121
+ /**
122
+ * Opens the EdgeLink authentication flow.
123
+ *
124
+ * This launches an in-app browser with the EdgeBoost login/consent page.
125
+ * When complete, the browser redirects to your redirectUri and the
126
+ * onSuccess/onExit callback is called.
127
+ */
128
+ open(): Promise<void>;
129
+ /**
130
+ * Manually handles a deep link URL.
131
+ *
132
+ * Use this if you're handling deep links yourself instead of relying
133
+ * on the automatic listener.
134
+ *
135
+ * @param url - The deep link URL received
136
+ * @returns true if the URL was handled, false otherwise
137
+ */
138
+ handleDeepLink(url: string): boolean;
139
+ /**
140
+ * Closes the EdgeLink flow.
141
+ */
142
+ close(): Promise<void>;
143
+ /**
144
+ * Destroys the EdgeLink instance.
145
+ */
146
+ destroy(): void;
147
+ private buildLinkUrl;
148
+ private setupLinkListener;
149
+ private removeLinkListener;
150
+ private processCallback;
151
+ private cleanup;
152
+ private emitEvent;
153
+ }
154
+
155
+ /**
156
+ * React Hooks for EdgeLink React Native
157
+ *
158
+ * These hooks provide a convenient, React-idiomatic way to integrate
159
+ * EdgeLink into your React Native application.
160
+ *
161
+ * @module @edge-markets/connect-react-native/hooks
162
+ */
163
+
164
+ /**
165
+ * Configuration for useEdgeLink hook.
166
+ */
167
+ interface UseEdgeLinkConfig {
168
+ /** Your OAuth client ID */
169
+ clientId: string;
170
+ /** Environment to connect to */
171
+ environment: EdgeEnvironment;
172
+ /** Deep link URI for OAuth callback */
173
+ redirectUri: string;
174
+ /** OAuth scopes to request */
175
+ scopes?: EdgeScope[];
176
+ /** Custom Link URL (development only) */
177
+ linkUrl?: string;
178
+ /** Use external browser instead of in-app browser */
179
+ useExternalBrowser?: boolean;
180
+ }
181
+ /**
182
+ * Return type for useEdgeLink hook.
183
+ */
184
+ interface UseEdgeLinkReturn {
185
+ /** Opens the EdgeLink flow */
186
+ open: () => Promise<void>;
187
+ /** Closes the EdgeLink flow */
188
+ close: () => Promise<void>;
189
+ /** Whether the Link flow is currently open */
190
+ isOpen: boolean;
191
+ /** Whether the flow completed successfully */
192
+ isSuccess: boolean;
193
+ /** Whether there was an error */
194
+ isError: boolean;
195
+ /** The success result (code, codeVerifier, state) */
196
+ result: EdgeLinkSuccess | null;
197
+ /** Error information if the flow failed */
198
+ error: {
199
+ code: string;
200
+ message: string;
201
+ } | null;
202
+ /** Resets the state to allow another attempt */
203
+ reset: () => void;
204
+ }
205
+ /**
206
+ * React hook for EdgeLink integration.
207
+ *
208
+ * Provides a simple, declarative API for connecting EdgeBoost accounts.
209
+ *
210
+ * @example
211
+ * ```tsx
212
+ * function ConnectButton() {
213
+ * const { open, isOpen, isSuccess, result, error } = useEdgeLink({
214
+ * clientId: 'your-client-id',
215
+ * environment: 'staging',
216
+ * redirectUri: 'myapp://oauth/callback',
217
+ * })
218
+ *
219
+ * useEffect(() => {
220
+ * if (isSuccess && result) {
221
+ * // Send to your backend
222
+ * exchangeCode(result.code, result.codeVerifier)
223
+ * }
224
+ * }, [isSuccess, result])
225
+ *
226
+ * return (
227
+ * <Button
228
+ * onPress={open}
229
+ * disabled={isOpen}
230
+ * title={isOpen ? 'Connecting...' : 'Connect EdgeBoost'}
231
+ * />
232
+ * )
233
+ * }
234
+ * ```
235
+ */
236
+ declare function useEdgeLink(config: UseEdgeLinkConfig): UseEdgeLinkReturn;
237
+ /**
238
+ * Hook to manually handle EdgeLink deep links.
239
+ *
240
+ * Use this if you have custom deep link routing and want to
241
+ * handle EdgeLink callbacks yourself.
242
+ *
243
+ * @example
244
+ * ```tsx
245
+ * function App() {
246
+ * const { handleUrl, isHandled } = useEdgeLinkHandler({
247
+ * redirectUri: 'myapp://oauth/callback',
248
+ * onSuccess: (result) => {
249
+ * console.log('Auth code:', result.code)
250
+ * },
251
+ * onExit: (error) => {
252
+ * console.log('Auth failed:', error)
253
+ * },
254
+ * })
255
+ *
256
+ * useEffect(() => {
257
+ * const sub = Linking.addEventListener('url', ({ url }) => {
258
+ * if (!handleUrl(url)) {
259
+ * // Handle other deep links
260
+ * }
261
+ * })
262
+ * return () => sub.remove()
263
+ * }, [handleUrl])
264
+ *
265
+ * return <YourApp />
266
+ * }
267
+ * ```
268
+ */
269
+ interface UseEdgeLinkHandlerConfig {
270
+ /** Your redirect URI prefix */
271
+ redirectUri: string;
272
+ /** Called on successful auth */
273
+ onSuccess: (result: EdgeLinkSuccess) => void;
274
+ /** Called on error or user exit */
275
+ onError?: (error: {
276
+ code: string;
277
+ message: string;
278
+ }) => void;
279
+ }
280
+ interface UseEdgeLinkHandlerReturn {
281
+ /** Process a URL. Returns true if it was an EdgeLink callback. */
282
+ handleUrl: (url: string) => boolean;
283
+ }
284
+ declare function useEdgeLinkHandler(config: UseEdgeLinkHandlerConfig): UseEdgeLinkHandlerReturn;
285
+ /**
286
+ * Hook to listen to EdgeLink events for analytics.
287
+ *
288
+ * @example
289
+ * ```tsx
290
+ * function MyComponent() {
291
+ * useEdgeLinkEvents((event) => {
292
+ * analytics.track('edge_link_event', {
293
+ * name: event.eventName,
294
+ * timestamp: event.timestamp,
295
+ * ...event.metadata,
296
+ * })
297
+ * })
298
+ *
299
+ * // ...
300
+ * }
301
+ * ```
302
+ */
303
+ declare function useEdgeLinkEvents(onEvent: (event: EdgeLinkEvent) => void, deps?: React.DependencyList): void;
304
+
305
+ /**
306
+ * PKCE (Proof Key for Code Exchange) Utilities for React Native
307
+ *
308
+ * React Native doesn't have Web Crypto API natively, so we use a
309
+ * compatible implementation that works across platforms.
310
+ *
311
+ * For production apps, consider installing:
312
+ * - `react-native-get-random-values` (polyfill for crypto.getRandomValues)
313
+ * - `expo-crypto` (if using Expo)
314
+ *
315
+ * @module @edge-markets/connect-react-native/pkce
316
+ */
317
+ /**
318
+ * A PKCE code verifier and challenge pair.
319
+ */
320
+ interface PKCEPair {
321
+ /** High-entropy random string (43-128 characters). Keep secret until token exchange. */
322
+ verifier: string;
323
+ /** SHA-256 hash of verifier, base64url encoded. Include in authorization URL. */
324
+ challenge: string;
325
+ }
326
+ /**
327
+ * Generates a PKCE code verifier and challenge pair.
328
+ *
329
+ * @example
330
+ * ```typescript
331
+ * const pkce = await generatePKCE()
332
+ *
333
+ * // Include challenge in authorization URL
334
+ * const authUrl = `https://auth.example.com/authorize?code_challenge=${pkce.challenge}&code_challenge_method=S256`
335
+ *
336
+ * // Later, include verifier in token exchange
337
+ * const tokens = await exchangeCode(code, pkce.verifier)
338
+ * ```
339
+ */
340
+ declare function generatePKCE(): Promise<PKCEPair>;
341
+ /**
342
+ * Generates a random state parameter for CSRF protection.
343
+ *
344
+ * @returns 64-character hex string (32 bytes of entropy)
345
+ */
346
+ declare function generateState(): string;
347
+ /**
348
+ * Checks if secure crypto is available.
349
+ *
350
+ * Returns false if only Math.random fallback is being used.
351
+ * Use this to warn users in development.
352
+ */
353
+ declare function isSecureCryptoAvailable(): boolean;
354
+
355
+ export { EdgeLink, type EdgeLinkConfig, type EdgeLinkEvent, type EdgeLinkEventName, type PKCEPair, type UseEdgeLinkConfig, type UseEdgeLinkHandlerConfig, type UseEdgeLinkHandlerReturn, type UseEdgeLinkReturn, generatePKCE, generateState, isSecureCryptoAvailable, useEdgeLink, useEdgeLinkEvents, useEdgeLinkHandler };