@rakomi/react-native 0.0.0 → 0.2.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/COMPLIANCE.md +90 -0
- package/LICENSE +21 -0
- package/README.md +327 -2
- package/SECURITY.md +206 -0
- package/THIRD-PARTY-NOTICES +11 -0
- package/dist/index.cjs +2788 -0
- package/dist/index.d.cts +698 -0
- package/dist/index.d.ts +698 -0
- package/dist/index.js +2681 -0
- package/dist/native/index.cjs +646 -0
- package/dist/native/index.d.cts +143 -0
- package/dist/native/index.d.ts +143 -0
- package/dist/native/index.js +637 -0
- package/dist/passkey-adapter-D_Z3Z7lV.d.cts +469 -0
- package/dist/passkey-adapter-D_Z3Z7lV.d.ts +469 -0
- package/package.json +96 -5
- package/sbom.cdx.json +72 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { AuthEvent, Locale, Translations, AuthMachineState, SignInOptions, SignInResult, TokenResult, AuthError, UserResource, HasParams, SwitchOrgResult, SessionResource, AuthConfig, BrandingConfig, OrgMembershipClaim, TranslationFn, OAuthTokenResponse, HttpClient, OpaqueUserHandle, PasskeyCeremonyAdapter, PasskeySummary, PasskeyError, AssertPasskeyResult, StepUpWithPasskeyResult, RegisterPasskeyResult, ListPasskeysResult, PasskeySummaryResult, DeletePasskeyResult, RequestResult, VerifyResult } from '@rakomi/sdk-core';
|
|
3
|
+
export { AssertPasskeyResult, AuthError, AuthEvent, AuthMachineState, CryptoProvider, DeletePasskeyResult, HasParams, HttpClient, KeyValueStore, ListPasskeysResult, Locale, MfaStepUpRequiredError, MfaStepUpUnavailableError, OpaqueUserHandle, PasskeyCeremonyAdapter, PasskeyError, PasskeyErrorCode, PasskeySummary, PasskeySummaryResult, PasskeyTokens, PkceChallenge, RegisterPasskeyResult, RegisterResult, SessionResource, SignInOptions, SignInResult, StepUpWithPasskeyResult, SwitchOrgResult, TokenResult, Translations, UserResource, base64url, createTranslator, decodeJwtPayload, decodeSession, decodeUser, generatePkce, getErrorMessage, hasPermission, hasRole, isSafeUrl, networkError, parseOAuthCallbackError, parseTokenEndpointError, scorePassword, selectPluralForm } from '@rakomi/sdk-core';
|
|
4
|
+
import { D as DpopProver, N as NativeAuthAdapter, T as TokenCache } from './passkey-adapter-D_Z3Z7lV.js';
|
|
5
|
+
export { A as AppLifecycle, a as AppStateValue, b as AttestationVerifier, B as BackgroundTask, c as BiometricGate, d as BiometricResult, e as BrowserAuthSessionOptions, f as BrowserAuthSessionResult, C as ConnectivityProvider, g as CreateDefaultExpoAdapterOptions, h as CreateNativeDpopProverOptions, i as CreateNativePasskeyAdapterOptions, j as DeepLinkProvider, k as DpopProofInput, l as NativeDpopModuleSpec, m as NativePasskeyCeremonyAdapter, n as NativePasskeyModuleSpec, P as ParClient, S as SystemBrowser, o as createDefaultExpoAdapter, p as createNativeDpopProver, q as createNativePasskeyAdapter } from './passkey-adapter-D_Z3Z7lV.js';
|
|
6
|
+
|
|
7
|
+
/** Reason a DPoP-requested session was downgraded to Bearer by the server. */
|
|
8
|
+
interface DpopDowngradeInfo {
|
|
9
|
+
/** The server returned `token_type: "Bearer"` for a session that presented a DPoP proof. */
|
|
10
|
+
reason: 'server_returned_bearer';
|
|
11
|
+
}
|
|
12
|
+
interface CreateDpopSessionOptions {
|
|
13
|
+
/**
|
|
14
|
+
* The native-keystore-backed prover for this session (one keypair per session).
|
|
15
|
+
* Wire the consumer's native adapter (`NativeAuthAdapter.dpopProver`) here. The
|
|
16
|
+
* SAME instance MUST serve issuance and refresh — never construct a new prover
|
|
17
|
+
* per refresh.
|
|
18
|
+
*/
|
|
19
|
+
prover: DpopProver;
|
|
20
|
+
/**
|
|
21
|
+
* Base URL of the Rakomi API (e.g. `https://api.rakomi.com`). Used to build the
|
|
22
|
+
* canonical `htu` of the proof; MUST match the host the refresh call targets or
|
|
23
|
+
* the server rejects the proof (`htu` mismatch, RFC 9449 §4.3).
|
|
24
|
+
*/
|
|
25
|
+
baseUrl: string;
|
|
26
|
+
/**
|
|
27
|
+
* Invoked at most once if the server downgrades a DPoP-requested session to
|
|
28
|
+
* `Bearer`. The session does NOT become bound. No secret material (proof / key
|
|
29
|
+
* / jwk / jti) is ever passed to this hook.
|
|
30
|
+
*/
|
|
31
|
+
onDowngrade?: (info: DpopDowngradeInfo) => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Opaque, session-scoped DPoP binding handle. Create ONE per logged-in session,
|
|
35
|
+
* pass it to the auth ceremony AND every refresh for that session. Never share an
|
|
36
|
+
* instance across distinct sessions or across a refresh-token boundary.
|
|
37
|
+
*
|
|
38
|
+
* @public — additive-only.
|
|
39
|
+
*/
|
|
40
|
+
declare class DpopSession {
|
|
41
|
+
private readonly prover;
|
|
42
|
+
private readonly baseUrl;
|
|
43
|
+
private readonly onDowngrade?;
|
|
44
|
+
private _bound;
|
|
45
|
+
private _downgraded;
|
|
46
|
+
private _downgradeNotified;
|
|
47
|
+
private _boundJkt;
|
|
48
|
+
constructor(options: CreateDpopSessionOptions);
|
|
49
|
+
/**
|
|
50
|
+
* `true` once the server has confirmed (`token_type === "DPoP"`) that this
|
|
51
|
+
* session's key is sender-bound. The SDK attaches a refresh proof IFF this is
|
|
52
|
+
* `true`. Starts `false`; set by observing issuance/refresh responses.
|
|
53
|
+
*/
|
|
54
|
+
get isBound(): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* `true` if a session that presented a DPoP proof was returned as `Bearer` by
|
|
57
|
+
* the server (a security downgrade — flag off / server-side downgrade).
|
|
58
|
+
*/
|
|
59
|
+
get isDowngraded(): boolean;
|
|
60
|
+
/** The committed RFC 7638 thumbprint (`jkt`) of the session keypair, once bound. */
|
|
61
|
+
get boundJkt(): string | undefined;
|
|
62
|
+
resolveProof(htm: string, target: string, opts?: {
|
|
63
|
+
nonce?: string;
|
|
64
|
+
}): Promise<string>;
|
|
65
|
+
jktHint(): Promise<string>;
|
|
66
|
+
observeTokenType(tokenType: string | undefined, attachedProof: boolean): Promise<void>;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Factory for a {@link DpopSession}. Equivalent to `new DpopSession(options)`.
|
|
70
|
+
*
|
|
71
|
+
* @public — additive-only.
|
|
72
|
+
*/
|
|
73
|
+
declare function createDpopSession(options: CreateDpopSessionOptions): DpopSession;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* `<RakomiProvider>` — RN context provider.
|
|
77
|
+
*
|
|
78
|
+
* Owns:
|
|
79
|
+
* - The frozen `NativeAuthAdapter`.
|
|
80
|
+
* - The auth-machine snapshot (`@rakomi/sdk-core` `MachineSnapshot`).
|
|
81
|
+
* - The HTTP client.
|
|
82
|
+
* - The `TokenRuntime` — drives the FSM, manages refresh + storage.
|
|
83
|
+
* - Deep-link callback subscription (single-use, idempotent).
|
|
84
|
+
* - AppState listener (debounced 300ms) for
|
|
85
|
+
* foreground refresh, with single in-flight Promise dedup.
|
|
86
|
+
* - Network connectivity listener for online/offline transitions.
|
|
87
|
+
*
|
|
88
|
+
* Hooks read from this context — they're thin wrappers.
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
interface RakomiProviderProps {
|
|
92
|
+
/** Tenant publishable key — used to derive base URL + tenant ID. */
|
|
93
|
+
publishableKey: string;
|
|
94
|
+
/** API base URL. Required if `publishableKey` is dev/local. */
|
|
95
|
+
baseUrl?: string;
|
|
96
|
+
/** Custom URL scheme for OAuth callback (RFC 8252). Reverse-DNS recommended. */
|
|
97
|
+
redirectUri: string;
|
|
98
|
+
/** Override the default Expo adapter. Bare-RN consumers MUST supply this. */
|
|
99
|
+
nativeAdapter?: NativeAuthAdapter;
|
|
100
|
+
/** Sugar override: replace only storage in the default adapter. */
|
|
101
|
+
tokenCache?: TokenCache;
|
|
102
|
+
/** Enable biometric gate before reading refresh tokens. */
|
|
103
|
+
biometric?: boolean;
|
|
104
|
+
/** When `biometric: true`, disable device passcode fallback. Default false. */
|
|
105
|
+
biometricStrict?: boolean;
|
|
106
|
+
/** Localized prompt for biometric reads. */
|
|
107
|
+
biometricPrompt?: string;
|
|
108
|
+
/** iOS ephemeral session toggle. Default true. */
|
|
109
|
+
browserPreferEphemeralSession?: boolean;
|
|
110
|
+
/** JWKS TTL ceiling (≤7 days). Default 24h. */
|
|
111
|
+
offlineMaxAgeSeconds?: number;
|
|
112
|
+
/** opt-out of automatic deep-link handling. */
|
|
113
|
+
deepLinkAutoHandle?: boolean;
|
|
114
|
+
/** Typed event bus. Consumer wires telemetry. */
|
|
115
|
+
onEvent?: (event: AuthEvent) => void;
|
|
116
|
+
/** i18n locale. Default 'en'. */
|
|
117
|
+
locale?: Locale;
|
|
118
|
+
/** Translation overrides — merged onto locale dictionary. */
|
|
119
|
+
translations?: Partial<Translations>;
|
|
120
|
+
/** Override the OAuth token endpoint. Default: `<baseUrl>/oauth/token`. */
|
|
121
|
+
tokenEndpoint?: string;
|
|
122
|
+
/** Tenant identifier for storage-key derivation. Defaults to `publishableKey`. */
|
|
123
|
+
tenantId?: string;
|
|
124
|
+
children: ReactNode;
|
|
125
|
+
}
|
|
126
|
+
declare function RakomiProvider(props: RakomiProviderProps): ReactNode;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* `useAuth()` — RN port of `@rakomi/react`'s `useAuth`. Parity-tested at type level.
|
|
130
|
+
* Returns the same discriminated-union AuthState shape so consumer code is portable.
|
|
131
|
+
*/
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Discriminated-union AuthState — identical to `@rakomi/react`'s `AuthState`.
|
|
135
|
+
*
|
|
136
|
+
* `state: AuthMachineState` is the addition.
|
|
137
|
+
*/
|
|
138
|
+
type AuthState = {
|
|
139
|
+
isLoaded: false;
|
|
140
|
+
isSignedIn: undefined;
|
|
141
|
+
userId: undefined;
|
|
142
|
+
user: undefined;
|
|
143
|
+
sessionId: undefined;
|
|
144
|
+
error: null;
|
|
145
|
+
state: AuthMachineState;
|
|
146
|
+
signIn: (options?: SignInOptions) => Promise<SignInResult>;
|
|
147
|
+
signOut: () => Promise<void>;
|
|
148
|
+
getToken: () => Promise<TokenResult>;
|
|
149
|
+
} | {
|
|
150
|
+
isLoaded: true;
|
|
151
|
+
isSignedIn: false;
|
|
152
|
+
userId: null;
|
|
153
|
+
user: null;
|
|
154
|
+
sessionId: null;
|
|
155
|
+
error: AuthError | null;
|
|
156
|
+
state: AuthMachineState;
|
|
157
|
+
signIn: (options?: SignInOptions) => Promise<SignInResult>;
|
|
158
|
+
signOut: () => Promise<void>;
|
|
159
|
+
getToken: () => Promise<TokenResult>;
|
|
160
|
+
} | {
|
|
161
|
+
isLoaded: true;
|
|
162
|
+
isSignedIn: true;
|
|
163
|
+
userId: string;
|
|
164
|
+
user: UserResource;
|
|
165
|
+
sessionId: string;
|
|
166
|
+
error: AuthError | null;
|
|
167
|
+
state: AuthMachineState;
|
|
168
|
+
isExpiringSoon: boolean;
|
|
169
|
+
has: (params: HasParams) => boolean;
|
|
170
|
+
signIn: (options?: SignInOptions) => Promise<SignInResult>;
|
|
171
|
+
signOut: () => Promise<void>;
|
|
172
|
+
getToken: () => Promise<TokenResult>;
|
|
173
|
+
switchOrganization: (orgId: string | null) => Promise<SwitchOrgResult>;
|
|
174
|
+
};
|
|
175
|
+
declare function useAuth(): AuthState;
|
|
176
|
+
|
|
177
|
+
interface UseSessionReturn {
|
|
178
|
+
isLoaded: boolean;
|
|
179
|
+
isSignedIn: boolean;
|
|
180
|
+
session: SessionResource | null;
|
|
181
|
+
}
|
|
182
|
+
declare function useSession(): UseSessionReturn;
|
|
183
|
+
|
|
184
|
+
interface UseUserReturn {
|
|
185
|
+
isLoaded: boolean;
|
|
186
|
+
isSignedIn: boolean;
|
|
187
|
+
user: UserResource | null;
|
|
188
|
+
}
|
|
189
|
+
declare function useUser(): UseUserReturn;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Hook surface — parity superset of `@rakomi/react`.
|
|
193
|
+
*
|
|
194
|
+
* 0.1.0 ships these as thin reads off `RakomiContextValue` + minimal stubs that
|
|
195
|
+
* preserve the `@rakomi/react` return-shape so the parity test (`test/parity.test.ts`)
|
|
196
|
+
* passes. Full data wiring (Org list, Linked accounts, Flag eval, Branding, BaaS
|
|
197
|
+
* plans/subscriptions) lands in a future release; the public types are LOCKED.
|
|
198
|
+
*/
|
|
199
|
+
|
|
200
|
+
interface UseFlagOptions {
|
|
201
|
+
/** Optional default value if the flag is unknown. */
|
|
202
|
+
defaultValue?: boolean | string | number;
|
|
203
|
+
/** Optional user context override (rarely needed — provider supplies it). */
|
|
204
|
+
user?: {
|
|
205
|
+
id?: string;
|
|
206
|
+
email?: string;
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
interface UseFlagReturn<T = unknown> {
|
|
210
|
+
isLoaded: boolean;
|
|
211
|
+
value: T | undefined;
|
|
212
|
+
isEnabled: boolean;
|
|
213
|
+
}
|
|
214
|
+
declare function useFlag<T = unknown>(flag: string, options?: UseFlagOptions): UseFlagReturn<T>;
|
|
215
|
+
/** The active organization context, from the `org` scope's JWT claims. */
|
|
216
|
+
interface OrgContext {
|
|
217
|
+
orgId: string;
|
|
218
|
+
orgRole: string;
|
|
219
|
+
orgMemberships: OrgMembershipClaim[];
|
|
220
|
+
}
|
|
221
|
+
interface UseOrganizationReturn {
|
|
222
|
+
isLoaded: boolean;
|
|
223
|
+
organization: OrgContext | null;
|
|
224
|
+
}
|
|
225
|
+
declare function useOrganization(): UseOrganizationReturn;
|
|
226
|
+
interface UseOrganizationListReturn {
|
|
227
|
+
isLoaded: boolean;
|
|
228
|
+
organizations: OrgMembershipClaim[];
|
|
229
|
+
}
|
|
230
|
+
declare function useOrganizationList(): UseOrganizationListReturn;
|
|
231
|
+
type LinkProvider = 'google' | 'github' | 'microsoft' | 'apple' | 'discord' | 'facebook' | 'slack' | 'twitter' | 'gitlab' | 'linkedin';
|
|
232
|
+
type LinkedVia = 'oauth' | 'password' | 'magic_link' | 'email_otp' | 'passkey' | 'anonymous';
|
|
233
|
+
interface LinkedMethod {
|
|
234
|
+
provider: LinkProvider | 'password' | 'magic_link' | 'email_otp' | 'passkey';
|
|
235
|
+
via: LinkedVia;
|
|
236
|
+
linkedAt: string;
|
|
237
|
+
}
|
|
238
|
+
type LinkedMethods = LinkedMethod[];
|
|
239
|
+
interface UseLinkedAccountsResult {
|
|
240
|
+
isLoaded: boolean;
|
|
241
|
+
methods: LinkedMethods;
|
|
242
|
+
link: (provider: LinkProvider) => Promise<{
|
|
243
|
+
status: 'redirect' | 'error';
|
|
244
|
+
}>;
|
|
245
|
+
unlink: (provider: LinkProvider | 'password' | 'magic_link' | 'email_otp' | 'passkey') => Promise<{
|
|
246
|
+
status: 'complete' | 'error';
|
|
247
|
+
}>;
|
|
248
|
+
}
|
|
249
|
+
declare function useLinkedAccounts(): UseLinkedAccountsResult;
|
|
250
|
+
declare function useTranslation(): {
|
|
251
|
+
t: TranslationFn;
|
|
252
|
+
locale: string;
|
|
253
|
+
};
|
|
254
|
+
interface UseAuthConfigReturn {
|
|
255
|
+
isLoaded: boolean;
|
|
256
|
+
config: AuthConfig | null;
|
|
257
|
+
}
|
|
258
|
+
declare function useAuthConfig(): UseAuthConfigReturn;
|
|
259
|
+
interface UseBrandingReturn {
|
|
260
|
+
isLoaded: boolean;
|
|
261
|
+
branding: BrandingConfig | null;
|
|
262
|
+
}
|
|
263
|
+
declare function useBranding(): UseBrandingReturn;
|
|
264
|
+
interface UseAnonymousSigninResult {
|
|
265
|
+
isLoaded: boolean;
|
|
266
|
+
signInAnonymously: (options?: {
|
|
267
|
+
publicMetadata?: Record<string, unknown>;
|
|
268
|
+
}) => Promise<{
|
|
269
|
+
status: 'complete' | 'error';
|
|
270
|
+
}>;
|
|
271
|
+
}
|
|
272
|
+
declare function useAnonymousSignin(): UseAnonymousSigninResult;
|
|
273
|
+
interface BaasPlanPublicItem {
|
|
274
|
+
id: string;
|
|
275
|
+
name: string;
|
|
276
|
+
price_cents: number;
|
|
277
|
+
currency: string;
|
|
278
|
+
interval: string;
|
|
279
|
+
trial_days: number | null;
|
|
280
|
+
features: string[] | null;
|
|
281
|
+
}
|
|
282
|
+
interface UseBaasPlansReturn {
|
|
283
|
+
isLoaded: boolean;
|
|
284
|
+
plans: BaasPlanPublicItem[];
|
|
285
|
+
error: string | null;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Fetch the public BaaS plan list for `tenantSlug` from `/v1/billing/baas/{slug}/public-plans`.
|
|
289
|
+
* Response is cached per `(baseUrl, tenantSlug)` for the provider lifetime.
|
|
290
|
+
*/
|
|
291
|
+
declare function useBaasPlans({ tenantSlug }: {
|
|
292
|
+
tenantSlug: string;
|
|
293
|
+
}): UseBaasPlansReturn;
|
|
294
|
+
interface BaasSubscription {
|
|
295
|
+
id: string;
|
|
296
|
+
user_id: string;
|
|
297
|
+
plan_id: string;
|
|
298
|
+
plan_name: string;
|
|
299
|
+
status: string;
|
|
300
|
+
current_period_start: string | null;
|
|
301
|
+
current_period_end: string | null;
|
|
302
|
+
trial_end: string | null;
|
|
303
|
+
cancelled_at: string | null;
|
|
304
|
+
created_at: string;
|
|
305
|
+
updated_at: string;
|
|
306
|
+
}
|
|
307
|
+
interface UseBaasSubscriptionReturn {
|
|
308
|
+
isLoaded: boolean;
|
|
309
|
+
subscription: BaasSubscription | null;
|
|
310
|
+
error: string | null;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Fetch the signed-in user's BaaS subscription for `tenantSlug`. Authenticated:
|
|
314
|
+
* sends `Authorization: Bearer <accessToken>` from `getToken()`.
|
|
315
|
+
*
|
|
316
|
+
* 404 (no subscription) → `subscription: null` + `isLoaded: true` (NOT an error).
|
|
317
|
+
*/
|
|
318
|
+
declare function useBaasSubscription({ tenantSlug }: {
|
|
319
|
+
tenantSlug: string;
|
|
320
|
+
}): UseBaasSubscriptionReturn;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Conditional render components — RN ports of `@rakomi/react`'s
|
|
324
|
+
* `<SignedIn>`, `<SignedOut>`, `<Protect>`, `<Feature>`. Identical contracts
|
|
325
|
+
* (parity test asserts).
|
|
326
|
+
*
|
|
327
|
+
* They render a `Fragment` (no DOM/RN primitive nesting) — pure logic gates.
|
|
328
|
+
*/
|
|
329
|
+
|
|
330
|
+
interface SignedInProps {
|
|
331
|
+
children: ReactNode;
|
|
332
|
+
}
|
|
333
|
+
declare function SignedIn({ children }: SignedInProps): ReactNode;
|
|
334
|
+
interface SignedOutProps {
|
|
335
|
+
children: ReactNode;
|
|
336
|
+
}
|
|
337
|
+
declare function SignedOut({ children }: SignedOutProps): ReactNode;
|
|
338
|
+
interface ProtectProps extends HasParams {
|
|
339
|
+
children: ReactNode;
|
|
340
|
+
/** Rendered when the predicate fails. Default: nothing. */
|
|
341
|
+
fallback?: ReactNode;
|
|
342
|
+
}
|
|
343
|
+
declare function Protect({ children, fallback, permission, role }: ProtectProps): ReactNode;
|
|
344
|
+
/**
|
|
345
|
+
* `<Feature flag="…">` — render only when a feature flag is enabled. v0.1.0 stub:
|
|
346
|
+
* checks `user.rawClaims.feature_flags?.[flag] === true`. Full wiring
|
|
347
|
+
* (`useFlag` with provider + targeting rules) lands later — surface stays stable.
|
|
348
|
+
*/
|
|
349
|
+
interface FeatureProps {
|
|
350
|
+
flag: string;
|
|
351
|
+
children: ReactNode;
|
|
352
|
+
fallback?: ReactNode;
|
|
353
|
+
}
|
|
354
|
+
declare function Feature({ flag, children, fallback }: FeatureProps): ReactNode;
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* `<SignIn />` — RN port.
|
|
358
|
+
*
|
|
359
|
+
* Renders a sign-in flow using ONLY RN primitives (`<View>`, `<Text>`,
|
|
360
|
+
* `<TextInput>`, `<Pressable>`) — no HTML. Supports:
|
|
361
|
+
* - Password (direct) sign-in.
|
|
362
|
+
* - Social provider list (Google, GitHub, …) via `startSocialSignIn`.
|
|
363
|
+
* - MFA TOTP code entry view (`keyboardType="number-pad"`,
|
|
364
|
+
* `textContentType="oneTimeCode"`, `autoComplete="sms-otp"`).
|
|
365
|
+
*
|
|
366
|
+
* Accessibility:
|
|
367
|
+
* - Every interactive element has `accessibilityLabel` + `accessibilityRole`.
|
|
368
|
+
* - i18n keys come from `useRakomiContext.translate`.
|
|
369
|
+
* - `branding`/`theme` props supported.
|
|
370
|
+
*/
|
|
371
|
+
|
|
372
|
+
interface SignInProps {
|
|
373
|
+
/** Authorization endpoint, default `${baseUrl}/oauth/authorize`. */
|
|
374
|
+
authorizationEndpoint?: string;
|
|
375
|
+
/** Token endpoint, default `${baseUrl}/v1/auth/oauth/callback`. */
|
|
376
|
+
tokenEndpoint?: string;
|
|
377
|
+
/** MFA TOTP verify endpoint, default `${baseUrl}/v1/auth/mfa/totp/verify`. */
|
|
378
|
+
totpVerifyEndpoint?: string;
|
|
379
|
+
/** Social providers to render. Default: ['google']. */
|
|
380
|
+
providers?: string[];
|
|
381
|
+
/** OAuth scope. Default `openid profile email`. */
|
|
382
|
+
scope?: string;
|
|
383
|
+
/** Customize the rendered title. */
|
|
384
|
+
title?: string;
|
|
385
|
+
/** RN style prop. */
|
|
386
|
+
style?: any;
|
|
387
|
+
}
|
|
388
|
+
declare function SignIn(props: SignInProps): ReactNode;
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* `<SignUp />` — RN port. Mirrors `<SignIn />`'s
|
|
392
|
+
* UX patterns; password strength scored via `@rakomi/sdk-core/scorePassword`.
|
|
393
|
+
*
|
|
394
|
+
* For 0.1.0 the registration POST is wired against the canonical
|
|
395
|
+
* `/v1/auth/register` endpoint via the injected `HttpClient`. Email-verification
|
|
396
|
+
* follow-up step (which the API returns) leaves the user on the
|
|
397
|
+
* "verification_required" view — the consumer typically renders their own
|
|
398
|
+
* confirmation copy after that.
|
|
399
|
+
*/
|
|
400
|
+
|
|
401
|
+
interface SignUpProps {
|
|
402
|
+
/** Registration endpoint, default `/v1/auth/register`. */
|
|
403
|
+
registerEndpoint?: string;
|
|
404
|
+
/** Optional return URL after email confirmation — validated via `isSafeUrl`. */
|
|
405
|
+
returnTo?: string;
|
|
406
|
+
style?: any;
|
|
407
|
+
}
|
|
408
|
+
declare function SignUp(props: SignUpProps): ReactNode;
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* `<UserButton />` — RN port. Renders a tap-target showing the current user's
|
|
412
|
+
* email/initials + a sign-out action when expanded.
|
|
413
|
+
*
|
|
414
|
+
* RN primitives only.
|
|
415
|
+
*/
|
|
416
|
+
|
|
417
|
+
interface UserButtonProps {
|
|
418
|
+
/** Show the email next to the avatar. Default true. */
|
|
419
|
+
showName?: boolean;
|
|
420
|
+
style?: any;
|
|
421
|
+
}
|
|
422
|
+
declare function UserButton(props: UserButtonProps): ReactNode;
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* `<UserProfile />` — RN port (PREVIEW).
|
|
426
|
+
*
|
|
427
|
+
* Marked `'preview'` until 0.2.0; on first mount in `__DEV__` builds we log a
|
|
428
|
+
* warning so consumers don't accidentally ship it to production.
|
|
429
|
+
*/
|
|
430
|
+
|
|
431
|
+
interface UserProfileProps {
|
|
432
|
+
style?: any;
|
|
433
|
+
}
|
|
434
|
+
declare function UserProfile(props: UserProfileProps): ReactNode;
|
|
435
|
+
|
|
436
|
+
/** RFC 9449 / three-class client-side refresh failure taxonomy (+ network). */
|
|
437
|
+
type DpopRefreshErrorClass = 'dpop_prover_unavailable' | 'invalid_dpop_proof' | 'invalid_refresh_token' | 'network';
|
|
438
|
+
interface DpopRefreshError {
|
|
439
|
+
/** Stable machine token for the failure class. */
|
|
440
|
+
class: DpopRefreshErrorClass;
|
|
441
|
+
/** Full `auth/<class>` code string — parity with `@rakomi/node`'s surfacing. */
|
|
442
|
+
code: `auth/${DpopRefreshErrorClass}`;
|
|
443
|
+
message: string;
|
|
444
|
+
}
|
|
445
|
+
type DpopRefreshResult = {
|
|
446
|
+
ok: true;
|
|
447
|
+
tokens: OAuthTokenResponse;
|
|
448
|
+
attachedProof: boolean;
|
|
449
|
+
} | {
|
|
450
|
+
ok: false;
|
|
451
|
+
error: DpopRefreshError;
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Default `HttpClient` for React Native — wraps WHATWG `fetch` with the
|
|
456
|
+
* SSRF guard required by the project security rules (`redirect: 'error'`).
|
|
457
|
+
*
|
|
458
|
+
* used by all OAuth/PKCE/refresh flows. Consumers can inject a
|
|
459
|
+
* custom `HttpClient` via `nativeAdapter` for telemetry / mTLS / retry layers.
|
|
460
|
+
*/
|
|
461
|
+
|
|
462
|
+
interface CreateRnHttpClientOptions {
|
|
463
|
+
/** Base URL prepended to relative paths (e.g. `https://api.rakomi.com`). */
|
|
464
|
+
baseUrl?: string;
|
|
465
|
+
/** Default request timeout in ms. Default: 30_000. */
|
|
466
|
+
defaultTimeoutMs?: number;
|
|
467
|
+
}
|
|
468
|
+
declare function createRnHttpClient(options?: CreateRnHttpClientOptions): HttpClient;
|
|
469
|
+
|
|
470
|
+
/** Default publisher replay window (seconds) and the hard max clamp. */
|
|
471
|
+
declare const DEFAULT_WEBHOOK_TOLERANCE = 300;
|
|
472
|
+
declare const MAX_WEBHOOK_TOLERANCE = 600;
|
|
473
|
+
/** Portable webhook-verify error class — the value IS the cross-SDK conformance `error_class`. */
|
|
474
|
+
type WebhookVerifyErrorClass = 'invalid_signature' | 'invalid_secret' | 'missing_header' | 'timestamp_too_old' | 'timestamp_too_new' | 'invalid_body';
|
|
475
|
+
/** Open-set publisher event type (the known catalog widened with the base string for forward-compat). */
|
|
476
|
+
type PublisherEventType = 'app.installed' | 'app.uninstalled' | 'app.install.scope_bump' | 'app.install.receipts_revoked' | 'publisher.created' | 'publisher.domain_verified' | 'publisher.dpa_accepted' | 'app.created' | 'app.version_published' | 'app.state_changed' | 'publisher.review_requested' | 'publisher.review_denied' | 'publisher.review_stale' | 'publisher.verified' | 'publisher.deverified' | 'publisher.subscription_activated' | 'publisher.subscription_lapsed';
|
|
477
|
+
type PublisherWebhookEventType = PublisherEventType | (string & {});
|
|
478
|
+
/** The flat publisher-webhook delivery body. Unknown fields tolerated (forward-compat). No end-user PII. */
|
|
479
|
+
interface PublisherWebhookEvent {
|
|
480
|
+
publisher_id: string;
|
|
481
|
+
correlation_id: string;
|
|
482
|
+
installation_id?: string;
|
|
483
|
+
app_id?: string;
|
|
484
|
+
app_version_id?: string;
|
|
485
|
+
actor_axis?: string;
|
|
486
|
+
install_state_from?: string;
|
|
487
|
+
install_state_to?: string;
|
|
488
|
+
revoked_count?: number;
|
|
489
|
+
already_revoked_count?: number;
|
|
490
|
+
[key: string]: unknown;
|
|
491
|
+
}
|
|
492
|
+
interface PublisherWebhookVerifyData {
|
|
493
|
+
/** Stable Standard Webhooks message id — the at-least-once dedup key. */
|
|
494
|
+
webhookId: string;
|
|
495
|
+
/** Per-delivery id (diagnostics/logging). */
|
|
496
|
+
deliveryId: string;
|
|
497
|
+
/** Event type from the X-Rakomi-Event header (open set). */
|
|
498
|
+
eventType: PublisherWebhookEventType;
|
|
499
|
+
timestamp: number;
|
|
500
|
+
payload: PublisherWebhookEvent;
|
|
501
|
+
}
|
|
502
|
+
type WebhookVerifyResult = {
|
|
503
|
+
ok: true;
|
|
504
|
+
data: PublisherWebhookVerifyData;
|
|
505
|
+
} | {
|
|
506
|
+
ok: false;
|
|
507
|
+
error: WebhookVerifyErrorClass;
|
|
508
|
+
};
|
|
509
|
+
type Headers = Record<string, string | string[] | undefined>;
|
|
510
|
+
/**
|
|
511
|
+
* Raw generic verify (advanced use). ASYNC (WebCrypto). Never throws except when WebCrypto is entirely
|
|
512
|
+
* absent (a misconfigured runtime) — that surfaces a clear error rather than a silent mis-verify.
|
|
513
|
+
*/
|
|
514
|
+
declare function verifyWebhook(body: string | Uint8Array, headers: Headers, secret: string, tolerance?: number): Promise<WebhookVerifyResult>;
|
|
515
|
+
/**
|
|
516
|
+
* Recommended publisher entry point. Pre-binds the 300 s window (clamped ≤600) and REJECTS a non-`rksec_`
|
|
517
|
+
* secret outright. ASYNC (WebCrypto) — `await` it. Mirrors `@rakomi/node`'s `verifyPublisherWebhook`.
|
|
518
|
+
*/
|
|
519
|
+
declare function verifyPublisherWebhook(body: string | Uint8Array, headers: Headers, secret: string, tolerance?: number): Promise<WebhookVerifyResult>;
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* RFC 8252 OAuth flow orchestrator for React Native / Expo.
|
|
523
|
+
*
|
|
524
|
+
* system browser ONLY (`expo-web-browser.openAuthSessionAsync`).
|
|
525
|
+
* PKCE S256 mandatory. State 32 bytes, single-use, 60s TTL, constant-time compare.
|
|
526
|
+
* Confused-deputy guard: redirect URI scheme/host re-checked client-side after callback ingest.
|
|
527
|
+
*
|
|
528
|
+
* No `WebView` (codebase guard the project lint guards enforces).
|
|
529
|
+
*/
|
|
530
|
+
|
|
531
|
+
interface StartSocialSignInInput {
|
|
532
|
+
adapter: NativeAuthAdapter;
|
|
533
|
+
http: HttpClient;
|
|
534
|
+
authorizationEndpoint: string;
|
|
535
|
+
tokenEndpoint: string;
|
|
536
|
+
clientId: string;
|
|
537
|
+
redirectUri: string;
|
|
538
|
+
provider: string;
|
|
539
|
+
scope?: string;
|
|
540
|
+
acrValues?: string;
|
|
541
|
+
preferEphemeralSession?: boolean;
|
|
542
|
+
/**
|
|
543
|
+
* Optional DPoP binding handle (opt-in at issuance). When supplied, a fresh RFC 9449 proof is
|
|
544
|
+
* attached to the code→token exchange so the server binds `dpop_jkt` to THIS
|
|
545
|
+
* session's native keypair; the SAME `DpopSession` must then be wired into the
|
|
546
|
+
* runtime so every refresh re-presents the bound key. Pass the session
|
|
547
|
+
* `<RakomiProvider>` auto-constructs from `NativeAuthAdapter.dpopProver`.
|
|
548
|
+
*
|
|
549
|
+
* Absent ⇒ a plain Bearer issuance (unchanged behaviour).
|
|
550
|
+
*/
|
|
551
|
+
dpopSession?: DpopSession;
|
|
552
|
+
}
|
|
553
|
+
type SocialSignInOutcome = {
|
|
554
|
+
ok: true;
|
|
555
|
+
tokens: {
|
|
556
|
+
access_token: string;
|
|
557
|
+
refresh_token?: string;
|
|
558
|
+
expires_in: number;
|
|
559
|
+
token_type: string;
|
|
560
|
+
};
|
|
561
|
+
} | {
|
|
562
|
+
ok: false;
|
|
563
|
+
error: AuthError;
|
|
564
|
+
};
|
|
565
|
+
/**
|
|
566
|
+
* Start a social-provider sign-in. Opens the system browser, waits for the
|
|
567
|
+
* deep-link callback, validates state + scheme, exchanges the code for tokens.
|
|
568
|
+
*
|
|
569
|
+
* Idempotent: only one OAuth ceremony can be in flight per call. Caller must
|
|
570
|
+
* serialize concurrent invocations themselves.
|
|
571
|
+
*/
|
|
572
|
+
declare function startSocialSignIn(input: StartSocialSignInInput): Promise<SocialSignInOutcome>;
|
|
573
|
+
|
|
574
|
+
interface UsePasskeysOptions {
|
|
575
|
+
/**
|
|
576
|
+
* Override the ceremony adapter. Intended for tests (`createFakePasskeyAdapter()` from
|
|
577
|
+
* `@rakomi/sdk-core/passkeys/testing`) and for a host that builds its adapter outside the provider.
|
|
578
|
+
* When omitted, the adapter comes from `nativeAdapter.passkeys`.
|
|
579
|
+
*/
|
|
580
|
+
adapter?: PasskeyCeremonyAdapter;
|
|
581
|
+
}
|
|
582
|
+
interface SignInWithPasskeyInput {
|
|
583
|
+
/**
|
|
584
|
+
* Identified sign-in. **An opaque, server-issued handle — NOT an email, NOT a username.** The type is
|
|
585
|
+
* branded (`OpaqueUserHandle`), so a raw string will not compile: passing a user-typed identifier here
|
|
586
|
+
* turns a usernameless flow into an account-enumeration oracle, and — because platform passkeys sync
|
|
587
|
+
* across a user's devices — can reveal which of their devices hold a credential. Omit it for the
|
|
588
|
+
* usernameless flow, which is what almost every app wants.
|
|
589
|
+
*/
|
|
590
|
+
userHandle?: OpaqueUserHandle;
|
|
591
|
+
}
|
|
592
|
+
interface RegisterPasskeyHookInput {
|
|
593
|
+
/** Minted by `stepUpWithPasskey()` or by the password step-up endpoint. */
|
|
594
|
+
stepUpToken: string;
|
|
595
|
+
nickname?: string;
|
|
596
|
+
}
|
|
597
|
+
interface ListPasskeysHookInput {
|
|
598
|
+
stepUpToken: string;
|
|
599
|
+
}
|
|
600
|
+
interface RenamePasskeyHookInput {
|
|
601
|
+
stepUpToken: string;
|
|
602
|
+
passkeyId: string;
|
|
603
|
+
nickname: string;
|
|
604
|
+
}
|
|
605
|
+
interface DeletePasskeyHookInput {
|
|
606
|
+
stepUpToken: string;
|
|
607
|
+
passkeyId: string;
|
|
608
|
+
}
|
|
609
|
+
interface UsePasskeysResult {
|
|
610
|
+
/** `null` until the capability probe resolves. `false` means this device cannot run a ceremony. */
|
|
611
|
+
isSupported: boolean | null;
|
|
612
|
+
/** `null` until probed, and `null` also means UNKNOWN (a module that cannot answer). A UI hint for
|
|
613
|
+
* wording ("Sign in with Face ID"), never a gate. */
|
|
614
|
+
hasPlatformAuthenticator: boolean | null;
|
|
615
|
+
/** `undefined` until `listPasskeys` is called — the hook fetches nothing on mount. */
|
|
616
|
+
passkeys: PasskeySummary[] | undefined;
|
|
617
|
+
error: PasskeyError | null;
|
|
618
|
+
isSigningIn: boolean;
|
|
619
|
+
isRegistering: boolean;
|
|
620
|
+
isSteppingUp: boolean;
|
|
621
|
+
isLoading: boolean;
|
|
622
|
+
isMutating: boolean;
|
|
623
|
+
signInWithPasskey: (input?: SignInWithPasskeyInput) => Promise<AssertPasskeyResult>;
|
|
624
|
+
stepUpWithPasskey: () => Promise<StepUpWithPasskeyResult>;
|
|
625
|
+
registerPasskey: (input: RegisterPasskeyHookInput) => Promise<RegisterPasskeyResult>;
|
|
626
|
+
listPasskeys: (input: ListPasskeysHookInput) => Promise<ListPasskeysResult>;
|
|
627
|
+
renamePasskey: (input: RenamePasskeyHookInput) => Promise<PasskeySummaryResult>;
|
|
628
|
+
deletePasskey: (input: DeletePasskeyHookInput) => Promise<DeletePasskeyResult>;
|
|
629
|
+
}
|
|
630
|
+
declare function usePasskeys(options?: UsePasskeysOptions): UsePasskeysResult;
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* `useSubmitOAuthTokens` — bridge between `startSocialSignIn` (free function) and the
|
|
634
|
+
* `<RakomiProvider>` runtime.
|
|
635
|
+
*
|
|
636
|
+
* this hook issues a fresh submit-nonce on every call (5-min TTL, single-use).
|
|
637
|
+
* The nonce is invisible to the consumer — the public surface stays a single-arg function,
|
|
638
|
+
* but the runtime is protected against arbitrary `OAuthTokenResponse` injection from
|
|
639
|
+
* third-party components.
|
|
640
|
+
*
|
|
641
|
+
* Consumer pattern:
|
|
642
|
+
* ```tsx
|
|
643
|
+
* const submit = useSubmitOAuthTokens;
|
|
644
|
+
* const outcome = await startSocialSignIn({... });
|
|
645
|
+
* if (outcome.ok) await submit(outcome.tokens);
|
|
646
|
+
* ```
|
|
647
|
+
*
|
|
648
|
+
* Calling `submit` persists the refresh token to secure storage and dispatches
|
|
649
|
+
* `SIGN_IN_SUCCESS` so `useAuth.isSignedIn` flips to `true` and `getToken` becomes available.
|
|
650
|
+
*/
|
|
651
|
+
|
|
652
|
+
declare function useSubmitOAuthTokens(): (tokens: OAuthTokenResponse) => Promise<void>;
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Direct-auth hooks — (magic-link, email-OTP, register).
|
|
656
|
+
*
|
|
657
|
+
* Wraps `@rakomi/sdk-core` direct-auth helpers with `useRakomiContext` wiring so
|
|
658
|
+
* consumers don't have to thread `http` / `baseUrl` / `clientId` themselves.
|
|
659
|
+
*
|
|
660
|
+
* On verify success:
|
|
661
|
+
* - `tokens` variant → calls `submitOAuthTokens` (dispatches SIGN_IN_SUCCESS).
|
|
662
|
+
* - `oauthCode` variant → caller is responsible for the code → token exchange (PKCE binding).
|
|
663
|
+
* - `mfa` variant → caller drives MFA UI; SDK does not auto-dispatch MFA_REQUIRED here
|
|
664
|
+
* (component layer owns that decision).
|
|
665
|
+
*/
|
|
666
|
+
|
|
667
|
+
interface UseMagicLinkResult {
|
|
668
|
+
request: (email: string) => Promise<RequestResult>;
|
|
669
|
+
verify: (token: string) => Promise<VerifyResult>;
|
|
670
|
+
}
|
|
671
|
+
declare function useMagicLink(): UseMagicLinkResult;
|
|
672
|
+
interface UseEmailOtpResult {
|
|
673
|
+
request: (email: string, mode?: 'login' | 'login_or_create') => Promise<RequestResult>;
|
|
674
|
+
verify: (email: string, code: string) => Promise<VerifyResult>;
|
|
675
|
+
}
|
|
676
|
+
declare function useEmailOtp(): UseEmailOtpResult;
|
|
677
|
+
interface UseRegisterResult {
|
|
678
|
+
register: (email: string, password: string) => Promise<RequestResult>;
|
|
679
|
+
}
|
|
680
|
+
declare function useRegister(): UseRegisterResult;
|
|
681
|
+
interface UseMfaResult {
|
|
682
|
+
/**
|
|
683
|
+
* Verify a TOTP code against the MFA challenge token surfaced by `verifyMagicLink`
|
|
684
|
+
* or `verifyEmailOtp` when their result is the `mfa` variant.
|
|
685
|
+
*
|
|
686
|
+
* On success, server-issued tokens are submitted to the runtime and `SIGN_IN_SUCCESS`
|
|
687
|
+
* is dispatched. On failure, returns the error so the caller can surface it in UI.
|
|
688
|
+
*/
|
|
689
|
+
verifyTotp: (challengeToken: string, code: string, endpoint?: string) => Promise<{
|
|
690
|
+
ok: true;
|
|
691
|
+
} | {
|
|
692
|
+
ok: false;
|
|
693
|
+
error: AuthError;
|
|
694
|
+
}>;
|
|
695
|
+
}
|
|
696
|
+
declare function useMfa(): UseMfaResult;
|
|
697
|
+
|
|
698
|
+
export { type AuthState, type CreateDpopSessionOptions, type CreateRnHttpClientOptions, DEFAULT_WEBHOOK_TOLERANCE, type DeletePasskeyHookInput, type DpopDowngradeInfo, DpopProver, type DpopRefreshError, type DpopRefreshErrorClass, type DpopRefreshResult, DpopSession, Feature, type FeatureProps, type LinkProvider, type LinkedMethod, type LinkedMethods, type LinkedVia, type ListPasskeysHookInput, MAX_WEBHOOK_TOLERANCE, NativeAuthAdapter, Protect, type ProtectProps, type PublisherEventType, type PublisherWebhookEvent, type PublisherWebhookEventType, type PublisherWebhookVerifyData, RakomiProvider, type RakomiProviderProps, type RegisterPasskeyHookInput, type RenamePasskeyHookInput, SignIn, type SignInProps, type SignInWithPasskeyInput, SignUp, type SignUpProps, SignedIn, type SignedInProps, SignedOut, type SignedOutProps, type SocialSignInOutcome, type StartSocialSignInInput, TokenCache, type UseAnonymousSigninResult, type UseAuthConfigReturn, type UseBaasPlansReturn, type UseBaasSubscriptionReturn, type UseBrandingReturn, type UseEmailOtpResult, type UseFlagOptions, type UseFlagReturn, type UseLinkedAccountsResult, type UseMagicLinkResult, type UseMfaResult, type UseOrganizationListReturn, type UseOrganizationReturn, type UsePasskeysOptions, type UsePasskeysResult, type UseRegisterResult, type UseSessionReturn, type UseUserReturn, UserButton, type UserButtonProps, UserProfile, type UserProfileProps, type WebhookVerifyErrorClass, type WebhookVerifyResult, createDpopSession, createRnHttpClient, startSocialSignIn, useAnonymousSignin, useAuth, useAuthConfig, useBaasPlans, useBaasSubscription, useBranding, useEmailOtp, useFlag, useLinkedAccounts, useMagicLink, useMfa, useOrganization, useOrganizationList, usePasskeys, useRegister, useSession, useSubmitOAuthTokens, useTranslation, useUser, verifyPublisherWebhook, verifyWebhook };
|