@synqauth/react 0.2.0 → 0.3.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/README.md +2 -2
- package/dist/index.d.ts +1175 -132
- package/dist/index.js +5230 -274
- package/dist/styles.css +1712 -56
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import { InputHTMLAttributes, ReactNode } from "react";
|
|
3
|
-
import { AccountComponents, ChallengeMethod, ChallengeProblem, DeniedReason, RedirectReason, SynqError } from "@synqauth/js";
|
|
2
|
+
import { CSSProperties, InputHTMLAttributes, KeyboardEvent, MouseEvent, PointerEvent, ReactNode, RefObject } from "react";
|
|
3
|
+
import { AccountComponents, AvatarInfo, AvatarPerson, ChallengeMethod, ChallengeProblem, DeniedReason, RedirectReason, SignInMethodInfo, SynqError } from "@synqauth/js";
|
|
4
4
|
//#region src/sign-in.d.ts
|
|
5
5
|
/** Where a sign-in is: what the form shows. */
|
|
6
6
|
type SignInStep = 'start' | 'code' | 'verify-email' | 'done';
|
|
@@ -94,6 +94,232 @@ interface UseSignIn {
|
|
|
94
94
|
/** One sign-in on the app's own screens, through the route mount's `sign-in/flow`. */
|
|
95
95
|
export declare function useSignIn(options?: UseSignInOptions): UseSignIn;
|
|
96
96
|
//#endregion
|
|
97
|
+
//#region src/types.d.ts
|
|
98
|
+
/** A call's outcome: its data, or the `SynqError` it failed with (branch on `error.code`). */
|
|
99
|
+
type SynqResult<T> = {
|
|
100
|
+
readonly data: T;
|
|
101
|
+
readonly error: null;
|
|
102
|
+
} | {
|
|
103
|
+
readonly data: null;
|
|
104
|
+
readonly error: SynqError;
|
|
105
|
+
};
|
|
106
|
+
/** A signed-in person, from the ID token Synq issued at sign-in. */
|
|
107
|
+
interface SynqUser {
|
|
108
|
+
/** The user's id at the brand (`usr_…`). */
|
|
109
|
+
readonly sub: string;
|
|
110
|
+
readonly email?: string;
|
|
111
|
+
readonly email_verified?: boolean;
|
|
112
|
+
readonly name?: string;
|
|
113
|
+
readonly preferred_username?: string;
|
|
114
|
+
/** The picture they chose: none, and your app shows its own default, from `avatar_seed`. */
|
|
115
|
+
readonly picture?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Where `picture` came from (AERO-2700): `none`, `upload`, `url` or
|
|
118
|
+
* `linked:<provider>`. Absent from a token issued before Synq said.
|
|
119
|
+
*/
|
|
120
|
+
readonly picture_source?: string;
|
|
121
|
+
/**
|
|
122
|
+
* What to draw their default avatar from (AERO-2704): theirs in every app
|
|
123
|
+
* of the brand, for as long as the account lasts. Absent from a token
|
|
124
|
+
* issued before seeds, where `sub` stands in (`useAvatar`).
|
|
125
|
+
*/
|
|
126
|
+
readonly avatar_seed?: string;
|
|
127
|
+
/** The brand's own default avatar for them, where it uploaded a set. */
|
|
128
|
+
readonly default_picture?: string;
|
|
129
|
+
/** When they signed in, in seconds since the epoch. */
|
|
130
|
+
readonly auth_time?: number;
|
|
131
|
+
/** How they signed in: `pwd`, `otp`, `wallet`, `hwk`, `fed`... */
|
|
132
|
+
readonly amr?: readonly string[];
|
|
133
|
+
/**
|
|
134
|
+
* The way in of the sign-in this session came from, when the app turned
|
|
135
|
+
* its sign-in claims on (`sign_in_claims`, AERO-2691): `google`, `wallet`,
|
|
136
|
+
* `email`, `password`, `passkey`…
|
|
137
|
+
*/
|
|
138
|
+
readonly sign_in_method?: string;
|
|
139
|
+
/** For a wallet sign-in, the address that signed and the wallet app's name, when it said. */
|
|
140
|
+
readonly sign_in_wallet?: {
|
|
141
|
+
readonly address: string;
|
|
142
|
+
readonly app: string | null;
|
|
143
|
+
};
|
|
144
|
+
/** Whether that sign-in made the account: true in its first ID token only. */
|
|
145
|
+
readonly new_user?: boolean;
|
|
146
|
+
readonly [claim: string]: unknown;
|
|
147
|
+
}
|
|
148
|
+
/** The way this browser last signed in to the app (AERO-2691): never who, never an address. */
|
|
149
|
+
interface LastUsedMethod {
|
|
150
|
+
/** The method's id: one of `SignInMethods`, or one Synq adds later. */
|
|
151
|
+
readonly method: SignInMethod | (string & Record<never, never>);
|
|
152
|
+
/** For a wallet, the wallet app's name as it announced itself (`Phantom`). */
|
|
153
|
+
readonly walletApp?: string;
|
|
154
|
+
}
|
|
155
|
+
/** A sign-in that just finished (AERO-2691): what `useSignInEvent()` tells the page once. */
|
|
156
|
+
interface SignInEvent {
|
|
157
|
+
/** This sign-in's own id: two sign-ins the same way can share `at`, never this. */
|
|
158
|
+
readonly id: string;
|
|
159
|
+
/** Whether it made the account: their first sign-in. */
|
|
160
|
+
readonly isNewUser: boolean;
|
|
161
|
+
/** The way in: one of `SignInMethods`, or one Synq adds later. */
|
|
162
|
+
readonly method: SignInMethod | (string & Record<never, never>);
|
|
163
|
+
/** For a wallet sign-in, the address that signed and its wallet app, when it said. */
|
|
164
|
+
readonly wallet: {
|
|
165
|
+
readonly address: string;
|
|
166
|
+
readonly app: string | null;
|
|
167
|
+
} | null;
|
|
168
|
+
/** When they signed in, in seconds since the epoch. */
|
|
169
|
+
readonly at: number;
|
|
170
|
+
}
|
|
171
|
+
/** Who is signed in, as the app's server tells the browser: `await synq.getSession()`, or the route mount's `session`. */
|
|
172
|
+
interface SynqSessionInfo {
|
|
173
|
+
readonly user: SynqUser | null;
|
|
174
|
+
/** When the session's main access token expires, in seconds since the epoch. */
|
|
175
|
+
readonly expiresAt: number | null;
|
|
176
|
+
/**
|
|
177
|
+
* The way this browser last signed in to the app, signed in or out, from
|
|
178
|
+
* the app's sign-in claims (AERO-2691). Absent from a mount that doesn't
|
|
179
|
+
* keep it.
|
|
180
|
+
*/
|
|
181
|
+
readonly lastUsed?: LastUsedMethod | null;
|
|
182
|
+
/** The sign-in that just finished, until the page hears of it (AERO-2691). */
|
|
183
|
+
readonly event?: SignInEvent | null;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* What the brand keeps for the person (the account API's `metadata`).
|
|
187
|
+
* Augment it to type what the app reads:
|
|
188
|
+
*
|
|
189
|
+
* ```ts
|
|
190
|
+
* declare module '@synqauth/react' {
|
|
191
|
+
* interface UserMetadata {
|
|
192
|
+
* plan?: 'free' | 'pro'
|
|
193
|
+
* }
|
|
194
|
+
* }
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
interface UserMetadata {
|
|
198
|
+
readonly [field: string]: unknown;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* The ways a brand signs people in, as `synq_method` names them: the hosted
|
|
202
|
+
* page goes straight to one. A brand's own connection joins them the same way:
|
|
203
|
+
*
|
|
204
|
+
* ```ts
|
|
205
|
+
* declare module '@synqauth/react' {
|
|
206
|
+
* interface SignInMethods {
|
|
207
|
+
* okta: true
|
|
208
|
+
* }
|
|
209
|
+
* }
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
interface SignInMethods {
|
|
213
|
+
readonly password: true;
|
|
214
|
+
readonly email: true;
|
|
215
|
+
readonly passkey: true;
|
|
216
|
+
readonly wallet: true;
|
|
217
|
+
readonly google: true;
|
|
218
|
+
readonly github: true;
|
|
219
|
+
readonly microsoft: true;
|
|
220
|
+
readonly apple: true;
|
|
221
|
+
readonly facebook: true;
|
|
222
|
+
readonly x: true;
|
|
223
|
+
readonly discord: true;
|
|
224
|
+
readonly telegram: true;
|
|
225
|
+
readonly matrica: true;
|
|
226
|
+
}
|
|
227
|
+
/** One of the brand's sign-in methods. */
|
|
228
|
+
type SignInMethod = Extract<keyof SignInMethods, string>;
|
|
229
|
+
/** How to send the person to sign in. */
|
|
230
|
+
interface SignInOptions {
|
|
231
|
+
/** Where to come back to: a path on the app, the current page by default. */
|
|
232
|
+
readonly returnTo?: string;
|
|
233
|
+
/** Go straight to one sign-in method. */
|
|
234
|
+
readonly method?: SignInMethod;
|
|
235
|
+
/** Fills in their email address. */
|
|
236
|
+
readonly loginHint?: string;
|
|
237
|
+
/** `create` opens the hosted page on its sign-up screen. */
|
|
238
|
+
readonly prompt?: 'login' | 'none' | 'consent' | 'select_account' | 'create';
|
|
239
|
+
/** Ask them to sign in again when their last sign-in is older than this many seconds. */
|
|
240
|
+
readonly maxAge?: number;
|
|
241
|
+
/** Offer a new passkey once they've signed in again. */
|
|
242
|
+
readonly intent?: 'add-passkey';
|
|
243
|
+
}
|
|
244
|
+
/** The person's profile at the brand. */
|
|
245
|
+
type Profile = AccountComponents['schemas']['Profile'];
|
|
246
|
+
/** Changes to it: only the fields given change, and `null` clears one. */
|
|
247
|
+
type ProfileUpdate = AccountComponents['schemas']['ProfileUpdate'];
|
|
248
|
+
/** A Solana wallet the person signs in with. */
|
|
249
|
+
type Wallet = AccountComponents['schemas']['Wallet'];
|
|
250
|
+
/** A way the person signs in: their email address, a wallet, a Google account... */
|
|
251
|
+
type LinkedAccount = AccountComponents['schemas']['Identity'];
|
|
252
|
+
/** One of the person's passkeys: `synced` when it lives in a password manager across their devices. */
|
|
253
|
+
type Passkey = AccountComponents['schemas']['Passkey'];
|
|
254
|
+
/** One of the person's sessions at the brand, on some device. */
|
|
255
|
+
type AccountSession = AccountComponents['schemas']['Session'];
|
|
256
|
+
/** One of the person's API keys for the brand's APIs (AERO-1693): never the key itself. */
|
|
257
|
+
type ApiKey = AccountComponents['schemas']['UserApiKey'];
|
|
258
|
+
/** A key just made: `key` is the key itself, in this answer only. */
|
|
259
|
+
type NewApiKey = AccountComponents['schemas']['NewUserApiKey'];
|
|
260
|
+
/** What making an API key takes: the API's identifier, a name, its scopes, an expiry if any. */
|
|
261
|
+
type ApiKeyInput = AccountComponents['schemas']['UserApiKeyCreate'];
|
|
262
|
+
/** One of the brand's APIs the person may make keys for, with the scopes it defines. */
|
|
263
|
+
type KeyableApi = AccountComponents['schemas']['KeyableApi'];
|
|
264
|
+
/** A way to sign in the person can add (AERO-2080): what `useAuth().link` takes, with its name. */
|
|
265
|
+
type LinkableMethod = AccountComponents['schemas']['LinkableMethod'];
|
|
266
|
+
/** How `signOut` signs the person out. */
|
|
267
|
+
interface SignOutOptions {
|
|
268
|
+
/**
|
|
269
|
+
* Stay on the page (AERO-2684): the app's server ends the brand's session
|
|
270
|
+
* itself and the browser goes nowhere. For an app whose server holds a
|
|
271
|
+
* secret (`@synqauth/nextjs` does). By default the browser goes to the
|
|
272
|
+
* brand's sign-out page, which asks first.
|
|
273
|
+
*/
|
|
274
|
+
readonly stay?: boolean;
|
|
275
|
+
}
|
|
276
|
+
//#endregion
|
|
277
|
+
//#region src/username.d.ts
|
|
278
|
+
/** Where the draft stands: nothing typed, being checked, free, taken, not a username, or theirs already. */
|
|
279
|
+
type UsernameStatus = 'idle' | 'checking' | 'available' | 'taken' | 'format' | 'same';
|
|
280
|
+
/** What to say of the draft: its status, or for `format` which rule it breaks. */
|
|
281
|
+
type UsernameCode = 'same' | 'available' | 'taken' |
|
|
282
|
+
/** Fewer than 3 characters. */
|
|
283
|
+
'too_short' |
|
|
284
|
+
/** More than 64. */
|
|
285
|
+
'too_long' |
|
|
286
|
+
/** Something other than a letter, digit, `.`, `_` or `-`. */
|
|
287
|
+
'characters' |
|
|
288
|
+
/** Starting or ending with `.`, `_` or `-`. */
|
|
289
|
+
'edges';
|
|
290
|
+
/** A username the brand takes: 3 to 64 of `a-z 0-9 . _ -`, starting and ending with a letter or digit. */
|
|
291
|
+
export declare const USERNAME_FORMAT: RegExp;
|
|
292
|
+
/** The draft as the brand keeps usernames: no spaces around it, no leading at sign, lowercase. */
|
|
293
|
+
export declare function normalizeUsername(value: string): string;
|
|
294
|
+
/** Which format rule `username` breaks, or null when it is one. */
|
|
295
|
+
export declare function usernameFormatCode(username: string): Extract<UsernameCode, 'too_short' | 'too_long' | 'characters' | 'edges'> | null;
|
|
296
|
+
/** What `useUsernameField()` answers. */
|
|
297
|
+
interface UseUsernameField {
|
|
298
|
+
/** The username being typed, as the brand would keep it; their own until they type. */
|
|
299
|
+
readonly draft: string;
|
|
300
|
+
/** Takes what they typed (or a suggestion they tapped), and checks it again. */
|
|
301
|
+
readonly setDraft: (value: string) => void;
|
|
302
|
+
readonly status: UsernameStatus;
|
|
303
|
+
/** What to say of it, by code: `messages.usernameCodes` has the words. */
|
|
304
|
+
readonly code: UsernameCode | null;
|
|
305
|
+
/** That, in the provider's words (`<SynqProvider messages>`), or null when there is nothing to say. */
|
|
306
|
+
readonly message: string | null;
|
|
307
|
+
/** When it is taken: up to three free ones like it, from the brand, to offer. */
|
|
308
|
+
readonly suggestions: readonly string[];
|
|
309
|
+
/**
|
|
310
|
+
* Makes the draft their username. `same` answers the profile as it is; a
|
|
311
|
+
* draft that isn't a username answers `invalid_username`; one taken since
|
|
312
|
+
* the check answers `username_taken`, and the field shows it with its
|
|
313
|
+
* suggestions.
|
|
314
|
+
*/
|
|
315
|
+
readonly save: () => Promise<SynqResult<Profile>>;
|
|
316
|
+
readonly saving: boolean;
|
|
317
|
+
/** Why the last check or save failed outright (the network, say). */
|
|
318
|
+
readonly error: SynqError | null;
|
|
319
|
+
}
|
|
320
|
+
/** A username field for the signed-in person (AERO-2693): live availability, suggestions and saving. */
|
|
321
|
+
export declare function useUsernameField(): UseUsernameField;
|
|
322
|
+
//#endregion
|
|
97
323
|
//#region src/messages.d.ts
|
|
98
324
|
/** Every word the components show, for `<SynqProvider messages>`; any left out stay English. */
|
|
99
325
|
interface SynqMessages {
|
|
@@ -111,6 +337,14 @@ interface SynqMessages {
|
|
|
111
337
|
readonly name: string;
|
|
112
338
|
readonly username: string;
|
|
113
339
|
readonly waysToSignIn: string;
|
|
340
|
+
/** Choosing their picture (AERO-2700): uploading one. */
|
|
341
|
+
readonly uploadPicture: string;
|
|
342
|
+
readonly uploadingPicture: string;
|
|
343
|
+
/** Using a linked account's picture: "Use my Google picture". */
|
|
344
|
+
readonly usePictureFrom: (provider: string) => string;
|
|
345
|
+
/** The same, for one of two or more accounts at a provider: "Use my GitHub picture (@ana)". */
|
|
346
|
+
readonly usePictureFromAccount: (provider: string, account: string) => string;
|
|
347
|
+
readonly removePicture: string;
|
|
114
348
|
readonly remove: string;
|
|
115
349
|
/** The label of the button that stops a way signing them in. */
|
|
116
350
|
readonly removeAccount: (provider: string, subject: string) => string;
|
|
@@ -193,111 +427,148 @@ interface SynqMessages {
|
|
|
193
427
|
readonly signInProblems: Readonly<Partial<Record<SignInProblem['code'], string>>>;
|
|
194
428
|
/** Why this person can't sign in here, by `SignInProblem.reason`. */
|
|
195
429
|
readonly signInRefusals: Readonly<Partial<Record<DeniedReason, string>>>;
|
|
430
|
+
/** The button that adds a wallet: Synq asks them to sign in again, then for the wallet. */
|
|
431
|
+
readonly connectWallet: string;
|
|
432
|
+
/**
|
|
433
|
+
* The mark on a way to sign in they proved is theirs: every wallet (by a
|
|
434
|
+
* signature) and provider account, and their email address once verified.
|
|
435
|
+
*/
|
|
436
|
+
readonly verified: string;
|
|
437
|
+
/** When a wallet or a way to sign in was added. */
|
|
438
|
+
readonly connectedOn: (date: string) => string;
|
|
439
|
+
readonly copyAddress: (address: string) => string;
|
|
440
|
+
readonly removeWallet: (name: string) => string;
|
|
441
|
+
/** The question before a wallet goes. */
|
|
442
|
+
readonly removeWalletTitle: string;
|
|
443
|
+
readonly removeWalletBody: string;
|
|
444
|
+
/** The question before a way to sign in goes. */
|
|
445
|
+
readonly removeAccountTitle: string;
|
|
446
|
+
readonly removeAccountBody: string;
|
|
447
|
+
/** The heading over the ways they could add. */
|
|
448
|
+
readonly addWayToSignIn: string;
|
|
449
|
+
/** Under that heading: adding one asks them to sign in again first. */
|
|
450
|
+
readonly signInAgainToAdd: string;
|
|
451
|
+
/** The label of the button that adds a way to sign in. */
|
|
452
|
+
readonly linkMethod: (provider: string) => string;
|
|
453
|
+
readonly connect: string;
|
|
454
|
+
readonly passkeys: string;
|
|
455
|
+
/** What passkeys are for, under the heading. */
|
|
456
|
+
readonly passkeysHint: string;
|
|
457
|
+
readonly noPasskeys: string;
|
|
458
|
+
readonly addPasskey: string;
|
|
459
|
+
/** A passkey's name: when it was made. */
|
|
460
|
+
readonly passkeyMade: (date: string) => string;
|
|
461
|
+
/** The mark on a passkey that a password manager keeps on all their devices. */
|
|
462
|
+
readonly synced: string;
|
|
463
|
+
readonly removePasskey: (name: string) => string;
|
|
464
|
+
readonly deleteAccount: string;
|
|
465
|
+
/**
|
|
466
|
+
* What deleting the account does, beside the button and in the question
|
|
467
|
+
* before it. It promises no way back: asking signs them out everywhere,
|
|
468
|
+
* and unless the brand lets a sign-in cancel it, they can't sign in again.
|
|
469
|
+
*/
|
|
470
|
+
readonly deleteAccountBody: string;
|
|
471
|
+
/** The word they type to confirm the deletion. */
|
|
472
|
+
readonly deleteConfirmWord: string;
|
|
473
|
+
readonly typeToConfirm: (word: string) => string;
|
|
474
|
+
readonly deletionScheduled: (date: string) => string;
|
|
475
|
+
readonly keepAccount: string;
|
|
476
|
+
/** Why a change needs them to sign in again: their last sign-in isn't recent enough. */
|
|
477
|
+
readonly freshSignInNeeded: string;
|
|
478
|
+
/** What `useUsernameField()` says of the draft, by its `code` (AERO-2693). */
|
|
479
|
+
readonly usernameCodes: Readonly<Record<UsernameCode, (username: string) => string>>;
|
|
480
|
+
/** `<AccountPanel>` (AERO-2696): the trigger's label once signed in, with their first name when known. */
|
|
481
|
+
readonly yourProfile: (name: string | null) => string;
|
|
482
|
+
readonly close: string;
|
|
483
|
+
readonly back: string;
|
|
484
|
+
/** A way to sign in, on its button: "Continue with Google". */
|
|
485
|
+
readonly continueWith: (method: string) => string;
|
|
486
|
+
/** The wallet method with nothing connected. */
|
|
487
|
+
readonly continueWithWallet: string;
|
|
488
|
+
/** Under the connected wallet's button: what signing in with it takes. */
|
|
489
|
+
readonly walletSignInHint: string;
|
|
490
|
+
readonly useAnotherWallet: string;
|
|
491
|
+
readonly pickWallet: string;
|
|
492
|
+
/** Under a wallet in the picker. */
|
|
493
|
+
readonly walletDetected: string;
|
|
494
|
+
readonly noWalletHere: string;
|
|
495
|
+
/** Signing in on the brand's hosted page instead, where only it can. */
|
|
496
|
+
readonly useSignInPage: string;
|
|
497
|
+
readonly moreOptions: string;
|
|
498
|
+
readonly fewerOptions: string;
|
|
499
|
+
/** The mark on the way this browser last signed in. */
|
|
500
|
+
readonly lastUsedMethod: string;
|
|
501
|
+
/** Where a provider's sign-in can't run: another app's built-in browser. */
|
|
502
|
+
readonly openInBrowser: (method: string) => string;
|
|
503
|
+
/** A sign-in under way: a wallet's prompt, a popup, a redirect, a passkey. */
|
|
504
|
+
readonly approveIn: (walletApp: string | null) => string;
|
|
505
|
+
readonly finishInWindow: (method: string) => string;
|
|
506
|
+
readonly opening: (method: string) => string;
|
|
507
|
+
readonly usePasskeyNow: string;
|
|
508
|
+
readonly signingYouIn: string;
|
|
509
|
+
/** A sign-in that couldn't reach the app's server or Synq. */
|
|
510
|
+
readonly signInOffline: string;
|
|
511
|
+
readonly signInFailed: string;
|
|
512
|
+
readonly tryAgain: string;
|
|
513
|
+
readonly securedBy: string;
|
|
514
|
+
/** A first sign-in's greeting, with their first name when known. */
|
|
515
|
+
readonly youreIn: (name: string | null) => string;
|
|
516
|
+
readonly makeItYours: string;
|
|
517
|
+
/** A returning sign-in's greeting. */
|
|
518
|
+
readonly goodToSeeYou: (name: string | null) => string;
|
|
519
|
+
/** How they signed in: "Signed in with Google", "Signed in with 7xKX…3fQ". */
|
|
520
|
+
readonly signedInWith: (way: string) => string;
|
|
521
|
+
readonly viewProfile: string;
|
|
522
|
+
readonly edit: string;
|
|
523
|
+
readonly changePicture: string;
|
|
524
|
+
readonly yourPicture: string;
|
|
525
|
+
/** Beside the large avatar on the picture screen. */
|
|
526
|
+
readonly pictureHint: string;
|
|
527
|
+
/** The app's own default, drawn for them. */
|
|
528
|
+
readonly defaultPicture: string;
|
|
529
|
+
readonly defaultPictureHint: string;
|
|
530
|
+
readonly uploadPhoto: string;
|
|
531
|
+
readonly uploadAnotherPhoto: string;
|
|
532
|
+
readonly pictureTypes: string;
|
|
533
|
+
readonly uploadedPicture: string;
|
|
534
|
+
/** A linked account's picture: "Your Google picture". */
|
|
535
|
+
readonly pictureFrom: (provider: string) => string;
|
|
536
|
+
/** The mark on the picture showing now. */
|
|
537
|
+
readonly showing: string;
|
|
538
|
+
readonly accountSettings: string;
|
|
539
|
+
readonly signOutFailed: string;
|
|
540
|
+
readonly usernamePlaceholder: string;
|
|
541
|
+
readonly checking: string;
|
|
542
|
+
/** The connected wallet, when it isn't on their profile. */
|
|
543
|
+
readonly walletNotOnProfile: (address: string) => string;
|
|
544
|
+
readonly add: string;
|
|
545
|
+
readonly connected: string;
|
|
546
|
+
readonly signedInWithThis: string;
|
|
547
|
+
readonly addWallet: string;
|
|
548
|
+
/** Under a wallet in the add picker. */
|
|
549
|
+
readonly connectAndAdd: string;
|
|
550
|
+
readonly walletOptions: (name: string) => string;
|
|
551
|
+
readonly copyAddressShort: string;
|
|
552
|
+
readonly removeFromProfile: string;
|
|
553
|
+
readonly removeWalletQuestion: (name: string) => string;
|
|
554
|
+
readonly keep: string;
|
|
555
|
+
readonly confirmItsYou: string;
|
|
556
|
+
readonly onlyWayIn: string;
|
|
557
|
+
readonly walletInUse: string;
|
|
558
|
+
readonly moveHere: string;
|
|
559
|
+
readonly linked: string;
|
|
560
|
+
readonly link: string;
|
|
561
|
+
readonly notLinked: string;
|
|
562
|
+
/** The session ended while the panel was open, and not by its Sign out. */
|
|
563
|
+
readonly signedOutAgain: string;
|
|
564
|
+
/** Confirming it's them, they signed in as someone else, who is never let in. */
|
|
565
|
+
readonly notYourAccount: string;
|
|
566
|
+
/** A change that wants a recent sign-in, before "Confirm it's you". */
|
|
567
|
+
readonly confirmToGoOn: string;
|
|
196
568
|
}
|
|
197
569
|
/** The components' English words, which an app's own messages override one by one. */
|
|
198
570
|
export declare const DEFAULT_MESSAGES: SynqMessages;
|
|
199
571
|
//#endregion
|
|
200
|
-
//#region src/types.d.ts
|
|
201
|
-
/** A call's outcome: its data, or the `SynqError` it failed with (branch on `error.code`). */
|
|
202
|
-
type SynqResult<T> = {
|
|
203
|
-
readonly data: T;
|
|
204
|
-
readonly error: null;
|
|
205
|
-
} | {
|
|
206
|
-
readonly data: null;
|
|
207
|
-
readonly error: SynqError;
|
|
208
|
-
};
|
|
209
|
-
/** A signed-in person, from the ID token Synq issued at sign-in. */
|
|
210
|
-
interface SynqUser {
|
|
211
|
-
/** The user's id at the brand (`usr_…`). */
|
|
212
|
-
readonly sub: string;
|
|
213
|
-
readonly email?: string;
|
|
214
|
-
readonly email_verified?: boolean;
|
|
215
|
-
readonly name?: string;
|
|
216
|
-
readonly preferred_username?: string;
|
|
217
|
-
readonly picture?: string;
|
|
218
|
-
/** When they signed in, in seconds since the epoch. */
|
|
219
|
-
readonly auth_time?: number;
|
|
220
|
-
/** How they signed in: `pwd`, `otp`, `wallet`, `hwk`, `fed`... */
|
|
221
|
-
readonly amr?: readonly string[];
|
|
222
|
-
readonly [claim: string]: unknown;
|
|
223
|
-
}
|
|
224
|
-
/** Who is signed in, as the app's server tells the browser: `await synq.getSession()`, or the route mount's `session`. */
|
|
225
|
-
interface SynqSessionInfo {
|
|
226
|
-
readonly user: SynqUser | null;
|
|
227
|
-
/** When the session's main access token expires, in seconds since the epoch. */
|
|
228
|
-
readonly expiresAt: number | null;
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* What the brand keeps for the person (the account API's `metadata`).
|
|
232
|
-
* Augment it to type what the app reads:
|
|
233
|
-
*
|
|
234
|
-
* ```ts
|
|
235
|
-
* declare module '@synqauth/react' {
|
|
236
|
-
* interface UserMetadata {
|
|
237
|
-
* plan?: 'free' | 'pro'
|
|
238
|
-
* }
|
|
239
|
-
* }
|
|
240
|
-
* ```
|
|
241
|
-
*/
|
|
242
|
-
interface UserMetadata {
|
|
243
|
-
readonly [field: string]: unknown;
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* The ways a brand signs people in, as `synq_method` names them: the hosted
|
|
247
|
-
* page goes straight to one. A brand's own connection joins them the same way:
|
|
248
|
-
*
|
|
249
|
-
* ```ts
|
|
250
|
-
* declare module '@synqauth/react' {
|
|
251
|
-
* interface SignInMethods {
|
|
252
|
-
* okta: true
|
|
253
|
-
* }
|
|
254
|
-
* }
|
|
255
|
-
* ```
|
|
256
|
-
*/
|
|
257
|
-
interface SignInMethods {
|
|
258
|
-
readonly password: true;
|
|
259
|
-
readonly email: true;
|
|
260
|
-
readonly passkey: true;
|
|
261
|
-
readonly wallet: true;
|
|
262
|
-
readonly google: true;
|
|
263
|
-
readonly microsoft: true;
|
|
264
|
-
readonly discord: true;
|
|
265
|
-
}
|
|
266
|
-
/** One of the brand's sign-in methods. */
|
|
267
|
-
type SignInMethod = Extract<keyof SignInMethods, string>;
|
|
268
|
-
/** How to send the person to sign in. */
|
|
269
|
-
interface SignInOptions {
|
|
270
|
-
/** Where to come back to: a path on the app, the current page by default. */
|
|
271
|
-
readonly returnTo?: string;
|
|
272
|
-
/** Go straight to one sign-in method. */
|
|
273
|
-
readonly method?: SignInMethod;
|
|
274
|
-
/** Fills in their email address. */
|
|
275
|
-
readonly loginHint?: string;
|
|
276
|
-
readonly prompt?: 'login' | 'none' | 'consent' | 'select_account';
|
|
277
|
-
/** Ask them to sign in again when their last sign-in is older than this many seconds. */
|
|
278
|
-
readonly maxAge?: number;
|
|
279
|
-
/** Offer a new passkey once they've signed in again. */
|
|
280
|
-
readonly intent?: 'add-passkey';
|
|
281
|
-
}
|
|
282
|
-
/** The person's profile at the brand. */
|
|
283
|
-
type Profile = AccountComponents['schemas']['Profile'];
|
|
284
|
-
/** Changes to it: only the fields given change, and `null` clears one. */
|
|
285
|
-
type ProfileUpdate = AccountComponents['schemas']['ProfileUpdate'];
|
|
286
|
-
/** A Solana wallet the person signs in with. */
|
|
287
|
-
type Wallet = AccountComponents['schemas']['Wallet'];
|
|
288
|
-
/** A way the person signs in: their email address, a wallet, a Google account... */
|
|
289
|
-
type LinkedAccount = AccountComponents['schemas']['Identity'];
|
|
290
|
-
/** One of the person's sessions at the brand, on some device. */
|
|
291
|
-
type AccountSession = AccountComponents['schemas']['Session'];
|
|
292
|
-
/** One of the person's API keys for the brand's APIs (AERO-1693): never the key itself. */
|
|
293
|
-
type ApiKey = AccountComponents['schemas']['UserApiKey'];
|
|
294
|
-
/** A key just made: `key` is the key itself, in this answer only. */
|
|
295
|
-
type NewApiKey = AccountComponents['schemas']['NewUserApiKey'];
|
|
296
|
-
/** What making an API key takes: the API's identifier, a name, its scopes, an expiry if any. */
|
|
297
|
-
type ApiKeyInput = AccountComponents['schemas']['UserApiKeyCreate'];
|
|
298
|
-
/** One of the brand's APIs the person may make keys for, with the scopes it defines. */
|
|
299
|
-
type KeyableApi = AccountComponents['schemas']['KeyableApi'];
|
|
300
|
-
//#endregion
|
|
301
572
|
//#region src/mount.d.ts
|
|
302
573
|
/** Calls the app's route mount: `request('session')`, `request('account/v1/profile', { method: 'PATCH', ... })`. */
|
|
303
574
|
type SynqMountRequest = (path: string, init?: RequestInit) => Promise<Response>;
|
|
@@ -311,10 +582,90 @@ interface SynqClientPlugin<Id extends string = string, Actions = unknown> {
|
|
|
311
582
|
actions(request: SynqMountRequest): Actions;
|
|
312
583
|
}
|
|
313
584
|
//#endregion
|
|
585
|
+
//#region src/redirect.d.ts
|
|
586
|
+
/** What left the page: a sign-in, a link, or signing the person in again. */
|
|
587
|
+
type RedirectKind = 'sign-in' | 'link' | 'reauthenticate';
|
|
588
|
+
/** The outcome of a sign-in or link that left the page, once the app is back on it. */
|
|
589
|
+
interface RedirectResult {
|
|
590
|
+
/**
|
|
591
|
+
* What left the page: `sign-in` (`useAuth().signIn`), `link` (`useLink`,
|
|
592
|
+
* `useAuth().link`) or `reauthenticate` (`useAuth().reauthenticate`).
|
|
593
|
+
*/
|
|
594
|
+
readonly kind: RedirectKind;
|
|
595
|
+
/** The method it went for, if one was named. */
|
|
596
|
+
readonly method: SignInMethod | null;
|
|
597
|
+
/** What the app asked to keep (`keep`), as it gave it. */
|
|
598
|
+
readonly kept: unknown;
|
|
599
|
+
/** Why it didn't finish, as the app's callback said (`synq_error`), or null. */
|
|
600
|
+
readonly error: SynqError | null;
|
|
601
|
+
/** A link's: the ways in the person had before it. */
|
|
602
|
+
readonly before: readonly string[] | null;
|
|
603
|
+
}
|
|
604
|
+
//#endregion
|
|
314
605
|
//#region src/store.d.ts
|
|
315
606
|
/** `error` when the app couldn't be asked who is signed in, and nothing is known yet: the provider asks again, waiting longer each time. */
|
|
316
607
|
type SessionStatus = 'loading' | 'signed-in' | 'signed-out' | 'error';
|
|
317
608
|
//#endregion
|
|
609
|
+
//#region src/components/styling.d.ts
|
|
610
|
+
/** What every component takes for its look: Synq's classes, or `unstyled`. */
|
|
611
|
+
interface SynqStyleProps {
|
|
612
|
+
/** The same elements, roles and labels, with none of Synq's classes: the app styles them. */
|
|
613
|
+
readonly unstyled?: boolean;
|
|
614
|
+
/** Added to the component's outer element. */
|
|
615
|
+
readonly className?: string;
|
|
616
|
+
}
|
|
617
|
+
//#endregion
|
|
618
|
+
//#region src/components/Avatar.d.ts
|
|
619
|
+
/**
|
|
620
|
+
* Where a picture came from, as `sources` names it: `linked` is any linked
|
|
621
|
+
* account's. A token says `linked:<provider>` only with the
|
|
622
|
+
* `linked_accounts` scope, and `linked` without it; the profile always does.
|
|
623
|
+
*/
|
|
624
|
+
type AvatarSource = 'upload' | 'url' | 'linked' | `linked:${string}`;
|
|
625
|
+
/**
|
|
626
|
+
* What shows for someone with no picture to show: Synq's `aura` (the
|
|
627
|
+
* default) or `monogram`, or the app's own, from the person's seed: an
|
|
628
|
+
* image's URL, or an element. Nothing (null) goes on to the brand's default.
|
|
629
|
+
*/
|
|
630
|
+
type AvatarFallback = 'aura' | 'monogram' | ((seed: string, user: AvatarPerson) => ReactNode | string);
|
|
631
|
+
/** How an app draws avatars: once for the app (`SynqProvider avatar`), or per component. */
|
|
632
|
+
interface AvatarSettings {
|
|
633
|
+
/** What shows for someone with no picture to show: `aura` by default. */
|
|
634
|
+
readonly fallback?: AvatarFallback;
|
|
635
|
+
/**
|
|
636
|
+
* The pictures that show, by where they came from: all of them by
|
|
637
|
+
* default. `['upload']` shows only pictures people uploaded here, and the
|
|
638
|
+
* app's own art over their linked accounts' pictures.
|
|
639
|
+
*/
|
|
640
|
+
readonly sources?: readonly AvatarSource[];
|
|
641
|
+
}
|
|
642
|
+
/** What `useAvatar()` answers: what an avatar is drawn from (`avatarOf` in @synqauth/js). */
|
|
643
|
+
type UseAvatar = AvatarInfo;
|
|
644
|
+
/**
|
|
645
|
+
* What the avatar of `user` is drawn from: the signed-in person by default,
|
|
646
|
+
* with their profile's picture once the account API was read, so a picture
|
|
647
|
+
* they just chose shows at once. `user` is anyone as Synq names them: an ID
|
|
648
|
+
* token's claims, or the management API's user (`id`, `username`).
|
|
649
|
+
*/
|
|
650
|
+
export declare function useAvatar(user?: AvatarPerson | null): UseAvatar | null;
|
|
651
|
+
/** What `Avatar` takes: whose, how large, and how it falls back. */
|
|
652
|
+
interface AvatarProps extends SynqStyleProps, AvatarSettings {
|
|
653
|
+
/** Whose: the signed-in person by default, or anyone as Synq names them (`useAvatar`). */
|
|
654
|
+
readonly user?: AvatarPerson | null;
|
|
655
|
+
/**
|
|
656
|
+
* Its width and height in pixels: 32 by default. Styled, it sets
|
|
657
|
+
* `--synq-avatar-size`, which Synq's stylesheet sizes it by; your own CSS
|
|
658
|
+
* still wins.
|
|
659
|
+
*/
|
|
660
|
+
readonly size?: number;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* A person's avatar: their picture, or the app's default for them. Drawn
|
|
664
|
+
* for the eye alone (`alt=""`, `aria-hidden`): their name beside it says
|
|
665
|
+
* who it is. Nothing while there is nobody.
|
|
666
|
+
*/
|
|
667
|
+
export declare function Avatar({ user, size, fallback, sources, unstyled, className }: AvatarProps): ReactNode;
|
|
668
|
+
//#endregion
|
|
318
669
|
//#region src/provider.d.ts
|
|
319
670
|
/** What `SynqProvider` takes: the server's session, the route mount, the words and the plugins. */
|
|
320
671
|
interface SynqProviderProps {
|
|
@@ -339,13 +690,56 @@ interface SynqProviderProps {
|
|
|
339
690
|
readonly navigate?: (url: string) => void;
|
|
340
691
|
/** The components' words, in the app's language: any left out are English. */
|
|
341
692
|
readonly messages?: Partial<SynqMessages>;
|
|
693
|
+
/**
|
|
694
|
+
* How the app draws avatars (AERO-2704), once for every component: its
|
|
695
|
+
* own default for someone with no picture (`fallback`, from their seed),
|
|
696
|
+
* and which pictures show (`sources`). A component's `avatar` overrides it.
|
|
697
|
+
*/
|
|
698
|
+
readonly avatar?: AvatarSettings;
|
|
342
699
|
readonly children?: ReactNode;
|
|
343
700
|
}
|
|
344
701
|
/** Synq for the components under it. Its route mount and `fetch` are read once, when it mounts. */
|
|
345
|
-
export declare function SynqProvider({ initialSession, basePath, plugins, fetch: fetcher, navigate, messages, children }: SynqProviderProps): ReactNode;
|
|
702
|
+
export declare function SynqProvider({ initialSession, basePath, plugins, fetch: fetcher, navigate, messages, avatar, children }: SynqProviderProps): ReactNode;
|
|
346
703
|
/** A browser plugin's actions, typed by the plugin, which must be one of the provider's `plugins`. */
|
|
347
704
|
export declare function usePlugin<Actions>(plugin: SynqClientPlugin<string, Actions>): Actions;
|
|
348
705
|
//#endregion
|
|
706
|
+
//#region src/popup.d.ts
|
|
707
|
+
/** How a provider's sign-in or link opens: `auto` is a popup where one fits, a redirect elsewhere. */
|
|
708
|
+
type SignInDisplay = 'auto' | 'popup' | 'redirect';
|
|
709
|
+
//#endregion
|
|
710
|
+
//#region src/handoff.d.ts
|
|
711
|
+
/** How a sign-in or a link opens, and the app's own state to have back afterwards. */
|
|
712
|
+
interface HandoffOptions {
|
|
713
|
+
/**
|
|
714
|
+
* `redirect` leaves the page and comes back to `returnTo`; `popup` opens
|
|
715
|
+
* one over it, and the page carries on once the person finishes there;
|
|
716
|
+
* `auto` is a popup where one fits (a fine pointer, from 640px wide, a
|
|
717
|
+
* real browser), else a redirect. A popup the browser blocks becomes a
|
|
718
|
+
* redirect by itself.
|
|
719
|
+
*/
|
|
720
|
+
readonly display?: SignInDisplay;
|
|
721
|
+
/**
|
|
722
|
+
* Small state of the app's own (at most 4 KB of JSON), kept in this tab
|
|
723
|
+
* across a redirect and handed back by `useRedirectResult().kept`, or by
|
|
724
|
+
* the call's own answer after a popup: the screen the person was on, say.
|
|
725
|
+
*/
|
|
726
|
+
readonly keep?: unknown;
|
|
727
|
+
}
|
|
728
|
+
/** A sign-in that finished on this page, in a popup. */
|
|
729
|
+
interface SignInDone {
|
|
730
|
+
/** The method it went straight to, if one was named. */
|
|
731
|
+
readonly method: SignInMethod | null;
|
|
732
|
+
/** What the app asked to keep (`keep`), as it gave it. */
|
|
733
|
+
readonly kept: unknown;
|
|
734
|
+
}
|
|
735
|
+
/** What `useAuth().reauthenticate()` takes: the way to sign in again with, and how it opens. */
|
|
736
|
+
interface ReauthenticateOptions extends HandoffOptions {
|
|
737
|
+
/** The way to sign in again with (`google`, `x`…): the brand's page shows them all without it. */
|
|
738
|
+
readonly method?: SignInMethod;
|
|
739
|
+
/** Where a redirect comes back to: this page by default. */
|
|
740
|
+
readonly returnTo?: string;
|
|
741
|
+
}
|
|
742
|
+
//#endregion
|
|
349
743
|
//#region src/hooks.d.ts
|
|
350
744
|
/** What `useSession()` answers: who is signed in, and whether the app said yet. */
|
|
351
745
|
interface UseSession {
|
|
@@ -363,7 +757,7 @@ interface UseSession {
|
|
|
363
757
|
}
|
|
364
758
|
/** Who is signed in. It reads the session alone, and asks the account API nothing. */
|
|
365
759
|
export declare function useSession(): UseSession;
|
|
366
|
-
/** What the account hooks (`useWallets`, `useLinkedAccounts`, `useAccountSessions`) answer: the data, the error, and whether it loaded. */
|
|
760
|
+
/** What the account hooks (`useWallets`, `useLinkedAccounts`, `useAccountSessions`, `usePasskeys`) answer: the data, the error, and whether it loaded. */
|
|
367
761
|
interface UseAccountData<T> {
|
|
368
762
|
readonly data: T | null;
|
|
369
763
|
readonly error: SynqError | null;
|
|
@@ -382,6 +776,60 @@ export declare function useAccountSessions(): UseAccountData<readonly AccountSes
|
|
|
382
776
|
export declare function useApiKeys(): UseAccountData<readonly ApiKey[]>;
|
|
383
777
|
/** The brand's APIs that let the person make keys, with the scopes each defines. */
|
|
384
778
|
export declare function useKeyableApis(): UseAccountData<readonly KeyableApi[]>;
|
|
779
|
+
/** The person's passkeys. */
|
|
780
|
+
export declare function usePasskeys(): UseAccountData<readonly Passkey[]>;
|
|
781
|
+
/**
|
|
782
|
+
* The ways to sign in the person can add, in the brand's order (AERO-2080):
|
|
783
|
+
* each a `method` for `useAuth().link`, with its name. A passkey is listed
|
|
784
|
+
* only when offered; link('passkey') uses the hosted add-passkey intent.
|
|
785
|
+
*/
|
|
786
|
+
export declare function useLinkableMethods(): UseAccountData<readonly LinkableMethod[]>;
|
|
787
|
+
/** What `useSignInMethods()` answers: the app's methods, in the brand's order, and whether the brand shows "Last used". */
|
|
788
|
+
interface UseSignInMethods extends UseAccountData<readonly SignInMethodInfo[]> {
|
|
789
|
+
/** Whether the brand marks the way this browser last signed in: off where people share devices. */
|
|
790
|
+
readonly showLastUsed: boolean;
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* The ways the app's sign-in offers, in the brand's order (AERO-2690), for a
|
|
794
|
+
* sign-in panel of the app's own: each one's id (what `signIn({ method })`
|
|
795
|
+
* takes), kind, name and artwork, whether it finishes on the app's own
|
|
796
|
+
* screens (`in_place`, through `useSignIn()`) and whether it signs in at
|
|
797
|
+
* another site (`popup`). Read from the route mount's `sign-in/methods`
|
|
798
|
+
* once for every component, signed in or out; a method the brand turns off
|
|
799
|
+
* is gone within a minute.
|
|
800
|
+
*/
|
|
801
|
+
export declare function useSignInMethods(): UseSignInMethods;
|
|
802
|
+
/**
|
|
803
|
+
* The way this browser last signed in to the app, for a "Last used" mark on
|
|
804
|
+
* it (AERO-2691), or null: the method and, for a wallet, the wallet app's
|
|
805
|
+
* name, never an address or who it was. The app's server keeps it on the
|
|
806
|
+
* app's own host from its sign-in claims (`sign_in_claims` on the app), so
|
|
807
|
+
* it survives signing out and the issuer's cookies. Null where the brand
|
|
808
|
+
* turned "Last used" off, or no longer offers that method here, once
|
|
809
|
+
* `useSignInMethods()` says so.
|
|
810
|
+
*/
|
|
811
|
+
export declare function useLastUsedMethod(): LastUsedMethod | null;
|
|
812
|
+
/** What `useSignInEvent()` answers: the sign-in, what the app kept for it, and `consume` to say the page heard of it. */
|
|
813
|
+
type UseSignInEvent = SignInEvent & {
|
|
814
|
+
/**
|
|
815
|
+
* What the app asked to keep (`keep`) when it started this sign-in in a
|
|
816
|
+
* popup or by a redirect (AERO-2692), as it gave it: the screen to come
|
|
817
|
+
* back to, say. Undefined when it kept nothing.
|
|
818
|
+
*/
|
|
819
|
+
readonly kept: unknown;
|
|
820
|
+
/** The page heard of it: it's gone, here and on the app's server, so a reload doesn't tell it again. */
|
|
821
|
+
readonly consume: () => void;
|
|
822
|
+
};
|
|
823
|
+
/**
|
|
824
|
+
* The sign-in that just finished, once (AERO-2691): whether it made the
|
|
825
|
+
* account (`isNewUser`, for a first-profile screen or a welcome), how, with
|
|
826
|
+
* which wallet, and what the app kept for it (`kept`). It stays until
|
|
827
|
+
* `consume()`, or five minutes. Needs the app's sign-in claims on
|
|
828
|
+
* (`sign_in_claims`); null otherwise, and when there is none. Null in the
|
|
829
|
+
* server's render and the browser's first too: it is told just after, once
|
|
830
|
+
* the provider has read what a redirect kept for it.
|
|
831
|
+
*/
|
|
832
|
+
export declare function useSignInEvent(): UseSignInEvent | null;
|
|
385
833
|
/** What `useUser()` answers: the person's claims, profile and metadata, and `update` for the profile. */
|
|
386
834
|
interface UseUser {
|
|
387
835
|
readonly isLoaded: boolean;
|
|
@@ -396,37 +844,122 @@ interface UseUser {
|
|
|
396
844
|
readonly error: SynqError | null;
|
|
397
845
|
/** Changes their profile: only the fields given, `null` clearing one. */
|
|
398
846
|
readonly update: (changes: ProfileUpdate) => Promise<SynqResult<Profile>>;
|
|
847
|
+
/**
|
|
848
|
+
* Uploads a picture and makes it theirs (AERO-2700): a PNG, JPEG, WebP or
|
|
849
|
+
* GIF, which Synq keeps as a WebP square. A large one is made smaller in
|
|
850
|
+
* the browser first, to at most 1024 px, so a phone’s photo fits the 5 MiB
|
|
851
|
+
* Synq takes. It goes through the app's route mount
|
|
852
|
+
* (`<base>/account/picture`), whose server sends it on to Synq's storage.
|
|
853
|
+
* Offer it only where the profile's `picture_choices` is true.
|
|
854
|
+
*/
|
|
855
|
+
readonly uploadPicture: (picture: Blob) => Promise<SynqResult<Profile>>;
|
|
856
|
+
/**
|
|
857
|
+
* Makes a linked account's picture theirs, by its id (`useLinkedAccounts`,
|
|
858
|
+
* `has_picture`): Synq copies it into the brand's files.
|
|
859
|
+
*/
|
|
860
|
+
readonly setPictureFrom: (identity: string) => Promise<SynqResult<Profile>>;
|
|
861
|
+
/** Removes their picture: the app's default shows. */
|
|
862
|
+
readonly removePicture: () => Promise<SynqResult<Profile>>;
|
|
399
863
|
/** Reads the profile and metadata again. */
|
|
400
864
|
readonly reload: () => Promise<void>;
|
|
401
865
|
}
|
|
402
866
|
/** The signed-in person: their ID token's claims at once, then their profile and metadata. */
|
|
403
867
|
export declare function useUser(): UseUser;
|
|
404
|
-
/** What `useAuth()` answers: `signIn`, `signOut`, `link`, and the account's wallets, ways to sign in and
|
|
868
|
+
/** What `useAuth()` answers: `signIn`, `signOut`, `link`, and the account's wallets, ways to sign in, sessions, passkeys and deletion. */
|
|
405
869
|
interface UseAuth {
|
|
406
870
|
readonly isLoaded: boolean;
|
|
407
871
|
readonly isSignedIn: boolean;
|
|
408
872
|
readonly userId: string | null;
|
|
409
|
-
/**
|
|
410
|
-
|
|
873
|
+
/**
|
|
874
|
+
* Signs the person in: by default sends the browser to sign in, coming
|
|
875
|
+
* back to `returnTo` (this page by default), and answers `null` as the
|
|
876
|
+
* page leaves. With `display: 'popup'` (or `'auto'`, a popup where one
|
|
877
|
+
* fits) it opens one over the page, inside the tap, and answers once the
|
|
878
|
+
* session is the new one's, or the error it ended with (`cancelled` when
|
|
879
|
+
* the person closed it). A blocked popup becomes a redirect by itself.
|
|
880
|
+
*/
|
|
881
|
+
readonly signIn: (options?: SignInOptions & HandoffOptions) => Promise<SynqResult<SignInDone | null>>;
|
|
411
882
|
/** Where `signIn` sends the browser: the route mount's `sign-in`. */
|
|
412
883
|
readonly signInUrl: (options?: SignInOptions) => string;
|
|
413
|
-
/**
|
|
414
|
-
|
|
884
|
+
/**
|
|
885
|
+
* Ends the session in the app and at the brand, then goes where the brand
|
|
886
|
+
* sends the browser. With `stay` (AERO-2684), the app's server ends the
|
|
887
|
+
* brand's session itself and the page stays where it is: show the person
|
|
888
|
+
* they're signed out. A failure leaves them signed in, to try again.
|
|
889
|
+
*/
|
|
890
|
+
readonly signOut: (options?: SignOutOptions) => Promise<SynqResult<null>>;
|
|
415
891
|
/**
|
|
416
892
|
* Adds a way to sign in to the person's account: Synq asks them to sign in
|
|
417
|
-
* again
|
|
418
|
-
*
|
|
419
|
-
*
|
|
893
|
+
* again (unless they signed in within the brand's `link_reauth_window`),
|
|
894
|
+
* then for `method`, and the browser comes back to `returnTo` (this page
|
|
895
|
+
* by default), answering `null` as it leaves, or the problem when it can't
|
|
896
|
+
* start: the method isn't offered, or they have as many ways in as one
|
|
897
|
+
* may. With `display: 'popup'` or `'auto'` it runs in a popup and answers
|
|
898
|
+
* the way in that joined; `cancelled` when none did (closed, "Not now",
|
|
899
|
+
* or one they already had), and `account_switched` when they signed in to
|
|
900
|
+
* the account that has it instead. `useLink(method)` keeps its state for
|
|
901
|
+
* a button.
|
|
420
902
|
*/
|
|
421
903
|
readonly link: (method: SignInMethod, options?: {
|
|
422
904
|
returnTo?: string;
|
|
423
|
-
}) => Promise<SynqResult<null>>;
|
|
905
|
+
} & HandoffOptions) => Promise<SynqResult<LinkedAccount | null>>;
|
|
906
|
+
/**
|
|
907
|
+
* Signs the person signed in now in again, for a change that wants a
|
|
908
|
+
* recent sign-in (`fresh_sign_in_required`), through the brand's page:
|
|
909
|
+
* with `method` (`google`, `x`…), straight to it. In a popup where one fits
|
|
910
|
+
* (`display: 'auto'`, the default), answering once the session is the
|
|
911
|
+
* fresh one, so the change can be tried again at once; else by a
|
|
912
|
+
* redirect that comes back to `returnTo` (this page), answering `null` as
|
|
913
|
+
* the page leaves. Call it from a tap's own handler, before anything is
|
|
914
|
+
* awaited: a popup opened later may be blocked, and it runs as a redirect.
|
|
915
|
+
* Only the same person counts: anyone else who signs in there is signed
|
|
916
|
+
* out again at once, at the brand too, the session stays as it was, and
|
|
917
|
+
* it answers `other_account`. `cancelled` when they closed the popup;
|
|
918
|
+
* `not_signed_in` with nobody signed in, or once they were signed out
|
|
919
|
+
* before it finished. With a wallet on the profile,
|
|
920
|
+
* `useWalletSignIn().reauthenticate()` from `@synqauth/solana/react` does
|
|
921
|
+
* it with one signature and no page.
|
|
922
|
+
*/
|
|
923
|
+
readonly reauthenticate: (options?: ReauthenticateOptions) => Promise<SynqResult<SignInDone | null>>;
|
|
424
924
|
readonly wallets: {
|
|
425
925
|
readonly list: () => Promise<SynqResult<readonly Wallet[]>>;
|
|
426
926
|
/** Names a wallet; `null` takes its name away. */
|
|
427
927
|
readonly rename: (id: string, label: string | null) => Promise<SynqResult<Wallet>>;
|
|
428
928
|
/** Makes it their primary wallet, in place of the one that was. */
|
|
429
929
|
readonly setPrimary: (id: string) => Promise<SynqResult<Wallet>>;
|
|
930
|
+
/** Stops a wallet signing them in; the last way in can't go (`last_sign_in_method`). */
|
|
931
|
+
readonly remove: (id: string) => Promise<SynqResult<null>>;
|
|
932
|
+
/**
|
|
933
|
+
* The issuer and app the page asks for a wallet's sign-in request with
|
|
934
|
+
* (`POST <issuer>/siws/nonce`), from the route mount's `sign-in/wallet`:
|
|
935
|
+
* what `@synqauth/solana/react` signs with. Read once, then kept.
|
|
936
|
+
*/
|
|
937
|
+
readonly requestTarget: () => Promise<SynqResult<WalletRequestTarget>>;
|
|
938
|
+
/**
|
|
939
|
+
* Signs in with a wallet's signature over that request (`siws`, as
|
|
940
|
+
* `@synqauth/solana`'s `encodeSiws` writes it), in place: the route
|
|
941
|
+
* mount trades it for the session with no page (AERO-2681), and the
|
|
942
|
+
* session here follows. `reauthenticate` signs the person signed in now
|
|
943
|
+
* in again, for a route that wants a recent sign-in: Synq signs in only
|
|
944
|
+
* them, and refuses another account's wallet, or one nobody has, before
|
|
945
|
+
* anything changes (`other_account`). A signature that didn't
|
|
946
|
+
* count is `wallet_failed` or `wallet_expired` (ask for another
|
|
947
|
+
* request); what only the hosted page can do is `redirect_to_web`.
|
|
948
|
+
*/
|
|
949
|
+
readonly signIn: (siws: string, options?: {
|
|
950
|
+
reauthenticate?: boolean;
|
|
951
|
+
returnTo?: string;
|
|
952
|
+
}) => Promise<SynqResult<WalletSignedIn>>;
|
|
953
|
+
/**
|
|
954
|
+
* Adds the wallet that signed `siws` to their account (AERO-2683): one
|
|
955
|
+
* signature, no hosted page. It needs a recent sign-in
|
|
956
|
+
* (`fresh_sign_in_required`). A wallet another account has is
|
|
957
|
+
* `wallet_in_use`: `walletConflict(error)` from `@synqauth/js` says
|
|
958
|
+
* whether it can move here, and `move` moves it.
|
|
959
|
+
*/
|
|
960
|
+
readonly add: (siws: string) => Promise<SynqResult<Wallet>>;
|
|
961
|
+
/** Moves a wallet here with the `move_ticket` of a `wallet_in_use` conflict. */
|
|
962
|
+
readonly move: (ticket: string) => Promise<SynqResult<Wallet>>;
|
|
430
963
|
};
|
|
431
964
|
/** The ways they sign in. */
|
|
432
965
|
readonly accounts: {
|
|
@@ -451,12 +984,91 @@ interface UseAuth {
|
|
|
451
984
|
/** Revokes a key at once. */
|
|
452
985
|
readonly revoke: (id: string) => Promise<SynqResult<null>>;
|
|
453
986
|
};
|
|
987
|
+
readonly passkeys: {
|
|
988
|
+
readonly list: () => Promise<SynqResult<readonly Passkey[]>>;
|
|
989
|
+
/** Sends the browser to Synq, which asks them to sign in again and then makes a passkey, coming back to `returnTo` (this page by default). */
|
|
990
|
+
readonly add: (options?: {
|
|
991
|
+
returnTo?: string;
|
|
992
|
+
}) => void;
|
|
993
|
+
/** Removes a passkey; the last way in can't go (`last_sign_in_method`). */
|
|
994
|
+
readonly remove: (id: string) => Promise<SynqResult<null>>;
|
|
995
|
+
};
|
|
996
|
+
/** Deleting the account: after a grace period, which the profile's `deletion_scheduled_for` ends. */
|
|
997
|
+
readonly deletion: {
|
|
998
|
+
/** Asks for the account to be deleted. Someone who owns an org can't (`conflict`) until they hand it over. */
|
|
999
|
+
readonly schedule: () => Promise<SynqResult<Profile>>;
|
|
1000
|
+
/** Takes the request back while the grace period lasts. */
|
|
1001
|
+
readonly cancel: () => Promise<SynqResult<Profile>>;
|
|
1002
|
+
};
|
|
454
1003
|
/** Each browser plugin's actions, by its id (`usePlugin` types them). */
|
|
455
1004
|
readonly plugins: Readonly<Record<string, unknown>>;
|
|
456
1005
|
}
|
|
1006
|
+
/** Where the page asks for a wallet's sign-in request: the brand's issuer, as the app's client. */
|
|
1007
|
+
interface WalletRequestTarget {
|
|
1008
|
+
readonly issuer: string;
|
|
1009
|
+
readonly clientId: string;
|
|
1010
|
+
}
|
|
1011
|
+
/** A wallet's sign-in in place: who is signed in now, and where the app meant to go. */
|
|
1012
|
+
interface WalletSignedIn {
|
|
1013
|
+
readonly user: SynqUser | null;
|
|
1014
|
+
/** Where the sign-in was to land: the app decides whether to go there. */
|
|
1015
|
+
readonly returnTo: string;
|
|
1016
|
+
}
|
|
457
1017
|
/** Everything the signed-in person can do. */
|
|
458
1018
|
export declare function useAuth(): UseAuth;
|
|
459
1019
|
//#endregion
|
|
1020
|
+
//#region src/link.d.ts
|
|
1021
|
+
/** Where `useLink` is: nothing yet, under way, linked, or failed. */
|
|
1022
|
+
type LinkStatus = 'idle' | 'pending' | 'linked' | 'error';
|
|
1023
|
+
/** What `useLink(method)` answers. */
|
|
1024
|
+
interface UseLink {
|
|
1025
|
+
/**
|
|
1026
|
+
* Adds `method`'s way in: in a popup where one fits (`display: 'auto'`, the
|
|
1027
|
+
* default), else by a redirect that comes back to `returnTo` (this page).
|
|
1028
|
+
* Call it from the tap itself. Answers the way in that joined, `null` as
|
|
1029
|
+
* the page leaves for a redirect, or the error it ended with: `cancelled`
|
|
1030
|
+
* when the person closed the popup, went on without adding it or proved
|
|
1031
|
+
* one they already had, and `account_switched` when they signed in to the
|
|
1032
|
+
* account that has it instead.
|
|
1033
|
+
*/
|
|
1034
|
+
readonly link: (options?: {
|
|
1035
|
+
returnTo?: string;
|
|
1036
|
+
} & HandoffOptions) => Promise<SynqResult<LinkedAccount | null>>;
|
|
1037
|
+
/**
|
|
1038
|
+
* `linked` while the person has a way in of this kind, `pending` while one
|
|
1039
|
+
* is being added (a popup open, or a redirect on its way back), `error`
|
|
1040
|
+
* when the last try failed, else `idle`.
|
|
1041
|
+
*/
|
|
1042
|
+
readonly status: LinkStatus;
|
|
1043
|
+
/** Their way in of this kind: the one just added, else their newest. */
|
|
1044
|
+
readonly identity: LinkedAccount | null;
|
|
1045
|
+
/**
|
|
1046
|
+
* Why the last try failed; a closed popup is no failure. A redirect's
|
|
1047
|
+
* error shows until the next try, or until one of this kind joins.
|
|
1048
|
+
*/
|
|
1049
|
+
readonly problem: SynqError | null;
|
|
1050
|
+
/** Gives up on a popup still open, closing it where the browser lets the page. */
|
|
1051
|
+
readonly cancel: () => void;
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Linking one way in from a button of the app's own (AERO-2695): `link()`
|
|
1055
|
+
* from the tap, and the `status` and `identity` to show. A redirect's return
|
|
1056
|
+
* shows here too: the hook reads the way in that joined, or the error the
|
|
1057
|
+
* app's callback came back with.
|
|
1058
|
+
*/
|
|
1059
|
+
export declare function useLink(method: SignInMethod): UseLink;
|
|
1060
|
+
/** What `useRedirectResult()` answers: the result, and `consume()` to forget it once handled. */
|
|
1061
|
+
type UseRedirectResult = (RedirectResult & {
|
|
1062
|
+
readonly consume: () => void;
|
|
1063
|
+
}) | null;
|
|
1064
|
+
/**
|
|
1065
|
+
* A sign-in or link that left the page for a redirect (AERO-2692), once the
|
|
1066
|
+
* app is back: what it was, the state the app kept for it (`keep`), and the
|
|
1067
|
+
* error the app's callback came back with, if any. Null until there is one,
|
|
1068
|
+
* and after `consume()`. Who is signed in now is `useSession()`'s.
|
|
1069
|
+
*/
|
|
1070
|
+
export declare function useRedirectResult(): UseRedirectResult;
|
|
1071
|
+
//#endregion
|
|
460
1072
|
//#region src/components/SignedIn.d.ts
|
|
461
1073
|
/** Shows its children only while someone is signed in. It renders no element of its own. */
|
|
462
1074
|
export declare function SignedIn({ children }: {
|
|
@@ -469,15 +1081,6 @@ export declare function SignedOut({ children }: {
|
|
|
469
1081
|
readonly children?: ReactNode;
|
|
470
1082
|
}): ReactNode;
|
|
471
1083
|
//#endregion
|
|
472
|
-
//#region src/components/styling.d.ts
|
|
473
|
-
/** What every component takes for its look: Synq's classes, or `unstyled`. */
|
|
474
|
-
interface SynqStyleProps {
|
|
475
|
-
/** The same elements, roles and labels, with none of Synq's classes: the app styles them. */
|
|
476
|
-
readonly unstyled?: boolean;
|
|
477
|
-
/** Added to the component's outer element. */
|
|
478
|
-
readonly className?: string;
|
|
479
|
-
}
|
|
480
|
-
//#endregion
|
|
481
1084
|
//#region src/components/SignInButton.d.ts
|
|
482
1085
|
/** What `SignInButton` takes: the sign-in's options, its look and its words. */
|
|
483
1086
|
interface SignInButtonProps extends SignInOptions, SynqStyleProps {
|
|
@@ -538,33 +1141,49 @@ interface OneTimeCodeInputProps extends Omit<InputHTMLAttributes<HTMLInputElemen
|
|
|
538
1141
|
export declare function OneTimeCodeInput({ label, unstyled, className, ...input }: OneTimeCodeInputProps): ReactNode;
|
|
539
1142
|
//#endregion
|
|
540
1143
|
//#region src/components/UserButton.d.ts
|
|
541
|
-
/** What `UserButton` takes: where its account link goes, and its look. */
|
|
1144
|
+
/** What `UserButton` takes: where its account link goes, how it draws the avatar, and its look. */
|
|
542
1145
|
interface UserButtonProps extends SynqStyleProps {
|
|
543
1146
|
/** The app's page with `<AccountManager>`, linked as "Manage account". */
|
|
544
1147
|
readonly accountHref?: string;
|
|
1148
|
+
/** How its avatar falls back and which pictures show: the provider's `avatar` by default. */
|
|
1149
|
+
readonly avatar?: AvatarSettings;
|
|
545
1150
|
}
|
|
546
1151
|
/**
|
|
547
1152
|
* The signed-in person's picture and name, showing a panel to manage their
|
|
548
1153
|
* account or sign out: a disclosure (a button that shows and hides it), so
|
|
549
1154
|
* its link and button are reached with Tab as anywhere else. Escape or a
|
|
550
|
-
* click elsewhere hides it.
|
|
1155
|
+
* click elsewhere hides it. Its menu opens under the trigger and stays on
|
|
1156
|
+
* screen: on a narrow window it moves sideways to keep 8px clear of each edge
|
|
1157
|
+
* (AERO-2734). Nothing while nobody is signed in.
|
|
551
1158
|
*/
|
|
552
|
-
export declare function UserButton({ unstyled, className, accountHref }: UserButtonProps): ReactNode;
|
|
1159
|
+
export declare function UserButton({ unstyled, className, accountHref, avatar }: UserButtonProps): ReactNode;
|
|
553
1160
|
//#endregion
|
|
554
1161
|
//#region src/components/AccountManager.d.ts
|
|
555
|
-
/** One part of `AccountManager`: the profile, the ways to sign in, the sessions,
|
|
556
|
-
type AccountSection = 'profile' | 'accounts' | 'sessions' | 'apiKeys';
|
|
557
|
-
/** What `AccountManager` takes: which sections it shows, and its look. */
|
|
1162
|
+
/** One part of `AccountManager`: the profile, the ways to sign in, the passkeys, the sessions, the API keys, or deleting the account. */
|
|
1163
|
+
type AccountSection = 'profile' | 'accounts' | 'passkeys' | 'sessions' | 'apiKeys' | 'deletion';
|
|
1164
|
+
/** What `AccountManager` takes: which sections it shows, the ways to sign in it offers to add, and its look. */
|
|
558
1165
|
interface AccountManagerProps extends SynqStyleProps {
|
|
559
1166
|
/**
|
|
560
|
-
* The parts it shows, in this order: all
|
|
1167
|
+
* The parts it shows, in this order: all six by default. The API keys
|
|
561
1168
|
* show only where one of the brand's APIs lets people make keys, or the
|
|
562
1169
|
* person has some.
|
|
563
1170
|
*/
|
|
564
1171
|
readonly sections?: readonly AccountSection[];
|
|
1172
|
+
/**
|
|
1173
|
+
* Limits the ways to sign in it offers to add to these. By default it
|
|
1174
|
+
* offers every way the brand turns on for adding, as the account API lists
|
|
1175
|
+
* them (`useLinkableMethods`), and never one the brand doesn't. A way they
|
|
1176
|
+
* already have is left out, except a wallet or a passkey, of which they may
|
|
1177
|
+
* have several. A passkey is offered in the passkeys section when that
|
|
1178
|
+
* shows, else among the ways to add; either button makes one on Synq's
|
|
1179
|
+
* add-passkey page, and only where the brand offers passkeys.
|
|
1180
|
+
*/
|
|
1181
|
+
readonly linkMethods?: readonly SignInMethod[];
|
|
1182
|
+
/** How the profile's avatar falls back and which pictures show: the provider's `avatar` by default. */
|
|
1183
|
+
readonly avatar?: AvatarSettings;
|
|
565
1184
|
}
|
|
566
1185
|
/** Manage the signed-in person's account. Nothing while nobody is signed in. */
|
|
567
|
-
export declare function AccountManager({ unstyled, className, sections }: AccountManagerProps): ReactNode;
|
|
1186
|
+
export declare function AccountManager({ unstyled, className, sections, linkMethods, avatar }: AccountManagerProps): ReactNode;
|
|
568
1187
|
//#endregion
|
|
569
1188
|
//#region src/components/WalletManager.d.ts
|
|
570
1189
|
/** What `WalletManager` takes: its look. */
|
|
@@ -572,4 +1191,428 @@ type WalletManagerProps = SynqStyleProps;
|
|
|
572
1191
|
/** Manage the signed-in person's wallets. Nothing while nobody is signed in. */
|
|
573
1192
|
export declare function WalletManager({ unstyled, className }: WalletManagerProps): ReactNode;
|
|
574
1193
|
//#endregion
|
|
575
|
-
|
|
1194
|
+
//#region src/account-panel.d.ts
|
|
1195
|
+
/** What the panel shows: the ways to sign in, one under way, a first sign-in's onboarding, or the profile. */
|
|
1196
|
+
type AccountPanelView = 'sign-in' | 'progress' | 'onboarding' | 'profile';
|
|
1197
|
+
/** How the panel sits: a popover anchored under its trigger from 640px wide, a bottom sheet below. */
|
|
1198
|
+
type AccountPanelLayout = 'popover' | 'sheet';
|
|
1199
|
+
/** A sign-in the panel started and waits on. */
|
|
1200
|
+
interface AccountPanelPending {
|
|
1201
|
+
/** The method: `google`, `wallet`… */
|
|
1202
|
+
readonly method: string;
|
|
1203
|
+
/** Its name, as people know it: `Google`. */
|
|
1204
|
+
readonly name: string;
|
|
1205
|
+
/**
|
|
1206
|
+
* How it runs: in a `popup` over the page, a `redirect` that leaves it, or
|
|
1207
|
+
* `in-place` (a wallet's signature, a passkey's prompt) with no page at all.
|
|
1208
|
+
*/
|
|
1209
|
+
readonly display: 'popup' | 'redirect' | 'in-place';
|
|
1210
|
+
/** For a wallet's signature: the wallet app it waits on, when known. */
|
|
1211
|
+
readonly walletApp: string | null;
|
|
1212
|
+
}
|
|
1213
|
+
/** What `useAccountPanel()` takes. */
|
|
1214
|
+
interface UseAccountPanelOptions {
|
|
1215
|
+
/**
|
|
1216
|
+
* The query parameter that mirrors the panel being open
|
|
1217
|
+
* (`?<urlParam>=account`): `panel` by default; null mirrors nothing. With
|
|
1218
|
+
* it, Back closes the panel, a reload opens it again, and a provider's
|
|
1219
|
+
* redirect comes back into it.
|
|
1220
|
+
*/
|
|
1221
|
+
readonly urlParam?: string | null;
|
|
1222
|
+
/**
|
|
1223
|
+
* Small state of the app's own to have back after a sign-in that leaves
|
|
1224
|
+
* the page (at most 4 KB of JSON; `useRedirectResult().kept`): a value, or
|
|
1225
|
+
* a function the tap calls for it.
|
|
1226
|
+
*/
|
|
1227
|
+
readonly keep?: unknown;
|
|
1228
|
+
/** Called once the person signed out from the panel, which stays on the page: the app's toast. */
|
|
1229
|
+
readonly onSignedOut?: () => void;
|
|
1230
|
+
/**
|
|
1231
|
+
* Whether it moves the dialog as it opens and closes, with Synq's own
|
|
1232
|
+
* motion (WAAPI on `panelProps`' element): no by default, so a dialog of
|
|
1233
|
+
* the app's own moves as the app makes it. `<AccountPanel>` says yes.
|
|
1234
|
+
*/
|
|
1235
|
+
readonly animate?: boolean;
|
|
1236
|
+
}
|
|
1237
|
+
/** The props of the button that opens the panel. */
|
|
1238
|
+
interface AccountPanelTriggerProps {
|
|
1239
|
+
readonly ref: RefObject<HTMLButtonElement | null>;
|
|
1240
|
+
readonly type: 'button';
|
|
1241
|
+
readonly 'aria-haspopup': 'dialog';
|
|
1242
|
+
readonly 'aria-expanded': boolean;
|
|
1243
|
+
readonly 'aria-controls': string;
|
|
1244
|
+
readonly onClick: () => void;
|
|
1245
|
+
}
|
|
1246
|
+
/** The props of the panel itself: a dialog that keeps the focus inside. */
|
|
1247
|
+
interface AccountPanelDialogProps {
|
|
1248
|
+
readonly ref: RefObject<HTMLDivElement | null>;
|
|
1249
|
+
readonly id: string;
|
|
1250
|
+
readonly role: 'dialog';
|
|
1251
|
+
readonly 'aria-modal': true;
|
|
1252
|
+
readonly 'aria-labelledby': string;
|
|
1253
|
+
readonly tabIndex: -1;
|
|
1254
|
+
readonly 'data-layout': AccountPanelLayout;
|
|
1255
|
+
readonly 'data-view': AccountPanelView;
|
|
1256
|
+
/** Where a popover sits, as `--synq-panel-top`, `--synq-panel-right` and `--synq-panel-max-height`. */
|
|
1257
|
+
readonly style: CSSProperties;
|
|
1258
|
+
readonly onKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
|
|
1259
|
+
/**
|
|
1260
|
+
* Marks a press as inside the panel by React's tree, not the page's: a
|
|
1261
|
+
* popover, select or tooltip a card portals into `<body>` is still inside,
|
|
1262
|
+
* and pressing it leaves the panel open.
|
|
1263
|
+
*/
|
|
1264
|
+
readonly onPointerDownCapture: (event: PointerEvent<HTMLElement>) => void;
|
|
1265
|
+
/** A link inside closes the panel as it navigates, without going Back first. */
|
|
1266
|
+
readonly onClickCapture: (event: MouseEvent<HTMLElement>) => void;
|
|
1267
|
+
}
|
|
1268
|
+
/** The props of a sheet's grabber, which a drag down closes. */
|
|
1269
|
+
interface AccountPanelGrabberProps {
|
|
1270
|
+
readonly 'aria-hidden': true;
|
|
1271
|
+
readonly onPointerDown: (event: PointerEvent<HTMLElement>) => void;
|
|
1272
|
+
readonly onPointerMove: (event: PointerEvent<HTMLElement>) => void;
|
|
1273
|
+
readonly onPointerUp: () => void;
|
|
1274
|
+
readonly onPointerCancel: () => void;
|
|
1275
|
+
}
|
|
1276
|
+
/** What `useAccountPanel()` answers. */
|
|
1277
|
+
interface UseAccountPanel {
|
|
1278
|
+
readonly open: boolean;
|
|
1279
|
+
/** Opens or closes it; closing gives the focus back to the trigger and calls off a popup under way. */
|
|
1280
|
+
readonly setOpen: (open: boolean) => void;
|
|
1281
|
+
/**
|
|
1282
|
+
* Closes it. With `navigating`, before the page goes elsewhere (a
|
|
1283
|
+
* `router.push` of the app's): it takes `?panel=account` out of the
|
|
1284
|
+
* address in place instead of going Back, so the navigation lands where
|
|
1285
|
+
* it meant to. A link inside the panel does this by itself.
|
|
1286
|
+
*/
|
|
1287
|
+
readonly close: (options?: {
|
|
1288
|
+
readonly navigating?: boolean;
|
|
1289
|
+
}) => void;
|
|
1290
|
+
/** Whether to render the panel: open, or still closing. */
|
|
1291
|
+
readonly present: boolean;
|
|
1292
|
+
readonly view: AccountPanelView;
|
|
1293
|
+
readonly layout: AccountPanelLayout;
|
|
1294
|
+
/** The sign-in under way, started from the panel. */
|
|
1295
|
+
readonly pending: AccountPanelPending | null;
|
|
1296
|
+
/**
|
|
1297
|
+
* Why the last sign-in from the panel failed, in the page or by a redirect
|
|
1298
|
+
* that came back: a closed popup, a declined signature or a way back the
|
|
1299
|
+
* person took (`access_denied`) is none.
|
|
1300
|
+
*/
|
|
1301
|
+
readonly problem: SynqError | null;
|
|
1302
|
+
/** The method `problem` is for (`google`, `wallet`…), to show it there. */
|
|
1303
|
+
readonly problemMethod: string | null;
|
|
1304
|
+
/**
|
|
1305
|
+
* The session ended while the panel was open, and not by its own Sign
|
|
1306
|
+
* out (it expired, say): the panel is back on the ways in, and says so.
|
|
1307
|
+
*/
|
|
1308
|
+
readonly signedOut: boolean;
|
|
1309
|
+
/** Calls off the sign-in under way: closes its popup, and stops waiting on a wallet. */
|
|
1310
|
+
readonly cancel: () => void;
|
|
1311
|
+
/**
|
|
1312
|
+
* Signs in with `method` from a tap: a provider in a popup where one fits
|
|
1313
|
+
* (else a redirect that comes back into the panel), a wallet in place with
|
|
1314
|
+
* the wallet layer's signature (`walletApp` names one), anything else at
|
|
1315
|
+
* the hosted page. Call it from the tap itself, so a popup can open.
|
|
1316
|
+
*/
|
|
1317
|
+
readonly signIn: (method: string, options?: {
|
|
1318
|
+
readonly walletApp?: string;
|
|
1319
|
+
}) => Promise<void>;
|
|
1320
|
+
/**
|
|
1321
|
+
* The sign-in the panel is showing: a new account's (`isNewUser`, the
|
|
1322
|
+
* onboarding) or a returning person's (the greeting), until it closes.
|
|
1323
|
+
*/
|
|
1324
|
+
readonly event: SignInEvent | null;
|
|
1325
|
+
/** Shows the profile in place of a returning sign-in's greeting. */
|
|
1326
|
+
readonly showProfile: () => void;
|
|
1327
|
+
/** Signs out and stays on the page (`signOut({ stay: true })`), closing the panel and calling `onSignedOut`. */
|
|
1328
|
+
readonly signOut: () => Promise<SynqResult<null>>;
|
|
1329
|
+
/**
|
|
1330
|
+
* Keeps the panel open on a click outside while `busy`, as while a
|
|
1331
|
+
* wallet's prompt in the page waits: a card inside calls it through
|
|
1332
|
+
* `useAccountPanelSection()`.
|
|
1333
|
+
*/
|
|
1334
|
+
readonly hold: (busy: boolean) => () => void;
|
|
1335
|
+
/** The id of the panel's title, which labels the dialog. */
|
|
1336
|
+
readonly titleId: string;
|
|
1337
|
+
readonly triggerProps: AccountPanelTriggerProps;
|
|
1338
|
+
readonly panelProps: AccountPanelDialogProps;
|
|
1339
|
+
readonly grabberProps: AccountPanelGrabberProps;
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* The account panel's state and behavior, for a panel of the app's own:
|
|
1343
|
+
* spread `triggerProps` on its button and `panelProps` on its dialog.
|
|
1344
|
+
*/
|
|
1345
|
+
export declare function useAccountPanel(options?: UseAccountPanelOptions): UseAccountPanel;
|
|
1346
|
+
//#endregion
|
|
1347
|
+
//#region src/components/account-panel-sections.d.ts
|
|
1348
|
+
/** What a card of the app's own inside `<AccountPanel>` reads of it: `useAccountPanelSection()`. */
|
|
1349
|
+
interface AccountPanelSection {
|
|
1350
|
+
/** The onboarding of a first sign-in, which keeps to the essentials, rather than the profile. */
|
|
1351
|
+
readonly firstRun: boolean;
|
|
1352
|
+
readonly view: AccountPanelView;
|
|
1353
|
+
/**
|
|
1354
|
+
* Closes the panel. With `navigating`, before a `router.push` of the
|
|
1355
|
+
* card's: it goes from the address in place rather than Back, so the
|
|
1356
|
+
* navigation lands where it meant to. A link inside does this by itself.
|
|
1357
|
+
*/
|
|
1358
|
+
readonly close: (options?: {
|
|
1359
|
+
readonly navigating?: boolean;
|
|
1360
|
+
}) => void;
|
|
1361
|
+
/**
|
|
1362
|
+
* Keeps the panel open on a click outside while `busy` (a prompt of the
|
|
1363
|
+
* card's in the page): `useEffect(() => hold(busy), [hold, busy])`.
|
|
1364
|
+
*/
|
|
1365
|
+
readonly hold: (busy: boolean) => () => void;
|
|
1366
|
+
}
|
|
1367
|
+
/** The panel a card of the app's own is in: its view, and closing or holding it. */
|
|
1368
|
+
export declare function useAccountPanelSection(): AccountPanelSection;
|
|
1369
|
+
/** What `AccountPanel.Card` takes. */
|
|
1370
|
+
interface AccountPanelCardProps {
|
|
1371
|
+
/** Its heading, which names the card for screen readers too. */
|
|
1372
|
+
readonly title: ReactNode;
|
|
1373
|
+
/** Beside the heading: a count, say. */
|
|
1374
|
+
readonly badge?: ReactNode;
|
|
1375
|
+
readonly children?: ReactNode;
|
|
1376
|
+
}
|
|
1377
|
+
/** A card of the app's own, drawn as the panel's sections are: a heading, then what the app puts in it. */
|
|
1378
|
+
declare function Card({ title, badge, children }: AccountPanelCardProps): ReactNode;
|
|
1379
|
+
/** What `AccountPanel.Row` takes. */
|
|
1380
|
+
interface AccountPanelRowProps {
|
|
1381
|
+
/**
|
|
1382
|
+
* The provider the row stands for, when it's one: inside
|
|
1383
|
+
* `AccountPanel.Linked`, the profile then lists that provider's linked
|
|
1384
|
+
* account here alone, not again as a read-only row (an app's own
|
|
1385
|
+
* "Event reminders" row for Telegram, say).
|
|
1386
|
+
*/
|
|
1387
|
+
readonly provider?: SignInMethod;
|
|
1388
|
+
/** On its tile at the start: an icon, 20px. */
|
|
1389
|
+
readonly icon?: ReactNode;
|
|
1390
|
+
readonly title: ReactNode;
|
|
1391
|
+
/** The line under its title. */
|
|
1392
|
+
readonly line?: ReactNode;
|
|
1393
|
+
/** At its end: a button of the app's (a 44px target). */
|
|
1394
|
+
readonly action?: ReactNode;
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* A row of the app's own, drawn as a `LinkRow` is: an `<li>`, for inside
|
|
1398
|
+
* `AccountPanel.Linked` or a `<ul>` of the app's own card.
|
|
1399
|
+
*/
|
|
1400
|
+
declare function Row({ provider, icon, title, line, action }: AccountPanelRowProps): ReactNode;
|
|
1401
|
+
/** What `AccountPanel.Username` takes. */
|
|
1402
|
+
interface AccountPanelUsernameProps {
|
|
1403
|
+
/** The card's heading: "Username" by default. */
|
|
1404
|
+
readonly title?: ReactNode;
|
|
1405
|
+
/**
|
|
1406
|
+
* A line under the field while there's nothing to say about the name
|
|
1407
|
+
* typed: what the username is for, in the app's words ("Your name on
|
|
1408
|
+
* Acme Guild. Change it any time."). None by default.
|
|
1409
|
+
*/
|
|
1410
|
+
readonly description?: ReactNode;
|
|
1411
|
+
}
|
|
1412
|
+
/**
|
|
1413
|
+
* The username card of a first sign-in's onboarding: free names checked as
|
|
1414
|
+
* they type, three suggestions for a taken one, saved with Save or Enter.
|
|
1415
|
+
* In the profile, "Edit" beside their name changes it.
|
|
1416
|
+
*/
|
|
1417
|
+
declare function Username({ title, description }: AccountPanelUsernameProps): ReactNode;
|
|
1418
|
+
/** What `AccountPanel.Wallets` takes. */
|
|
1419
|
+
interface AccountPanelWalletsProps {
|
|
1420
|
+
/**
|
|
1421
|
+
* More to show under a wallet, from the app's own data (its rank, its
|
|
1422
|
+
* balance): `firstRun` is a first sign-in's onboarding, which keeps to
|
|
1423
|
+
* the essentials.
|
|
1424
|
+
*/
|
|
1425
|
+
readonly extra?: (wallet: Wallet, info: {
|
|
1426
|
+
readonly firstRun: boolean;
|
|
1427
|
+
}) => ReactNode;
|
|
1428
|
+
/** The card's heading: "Wallets" by default. */
|
|
1429
|
+
readonly title?: ReactNode;
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* The profile's wallets: which one is connected, which signed in, which is
|
|
1433
|
+
* primary; connecting one with no signature, adding one with one, and in
|
|
1434
|
+
* the profile, a menu to make one primary, rename, copy or remove it.
|
|
1435
|
+
* Through the wallet layer (`<SynqWalletProvider>`) where there is one,
|
|
1436
|
+
* else adding one goes through the hosted page.
|
|
1437
|
+
*/
|
|
1438
|
+
declare function Wallets({ extra, title }: AccountPanelWalletsProps): ReactNode;
|
|
1439
|
+
/** What `AccountPanel.Linked` takes. */
|
|
1440
|
+
interface AccountPanelLinkedProps {
|
|
1441
|
+
/** The card's heading: "Linked" by default. */
|
|
1442
|
+
readonly title?: ReactNode;
|
|
1443
|
+
/**
|
|
1444
|
+
* Its rows: `AccountPanel.LinkRow`s and the app's own, which render
|
|
1445
|
+
* inside a list, so each is an `<li>` (`AccountPanel.Row` is one). By
|
|
1446
|
+
* default, a LinkRow for each provider the brand offers the app.
|
|
1447
|
+
*/
|
|
1448
|
+
readonly children?: ReactNode;
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* The accounts linked to the profile: the rows the app puts in it, and in
|
|
1452
|
+
* the profile, each other linked account, read only.
|
|
1453
|
+
*/
|
|
1454
|
+
declare function Linked({ title, children }: AccountPanelLinkedProps): ReactNode;
|
|
1455
|
+
/** What `AccountPanel.LinkRow` takes. */
|
|
1456
|
+
interface AccountPanelLinkRowProps {
|
|
1457
|
+
/** The provider to link: `telegram`, `x`, `google`… */
|
|
1458
|
+
readonly provider: SignInMethod;
|
|
1459
|
+
/** The row's title: the provider's name by default. */
|
|
1460
|
+
readonly title?: ReactNode;
|
|
1461
|
+
/** The line under it while it isn't linked: "Not linked" by default. */
|
|
1462
|
+
readonly description?: ReactNode;
|
|
1463
|
+
/** What it says once linked, in place of the handle: an app's own status ("Alerts on"). */
|
|
1464
|
+
readonly linkedLine?: (account: LinkedAccount) => ReactNode;
|
|
1465
|
+
}
|
|
1466
|
+
/**
|
|
1467
|
+
* One provider to link: "Link", then "Finish in the X window" in a popup on
|
|
1468
|
+
* a laptop (or a redirect on a phone that comes back into the panel), then
|
|
1469
|
+
* their handle. Signing in again is skipped right after a sign-in.
|
|
1470
|
+
*/
|
|
1471
|
+
declare function LinkRow({ provider, title, description, linkedLine }: AccountPanelLinkRowProps): ReactNode;
|
|
1472
|
+
//#endregion
|
|
1473
|
+
//#region src/components/AccountPanel.d.ts
|
|
1474
|
+
/** What `AccountPanel` takes. */
|
|
1475
|
+
interface AccountPanelProps extends SynqStyleProps, Omit<UseAccountPanelOptions, 'animate'> {
|
|
1476
|
+
/**
|
|
1477
|
+
* The ways in that lead the panel, in this order, of those the brand
|
|
1478
|
+
* offers the app: its first four by default. The brand's others go under
|
|
1479
|
+
* "More options", in the brand's order; the one this browser last used is
|
|
1480
|
+
* lifted out of it.
|
|
1481
|
+
*/
|
|
1482
|
+
readonly methods?: readonly string[];
|
|
1483
|
+
/** Whether a sign-in plays the avatar's moment, the ring and embers: yes by default. */
|
|
1484
|
+
readonly moment?: boolean;
|
|
1485
|
+
/** How many embers rise in the moment: 6 by default. */
|
|
1486
|
+
readonly sparks?: number;
|
|
1487
|
+
/** A line under the sign-in title, in the app's words. */
|
|
1488
|
+
readonly description?: ReactNode;
|
|
1489
|
+
/** The app's page with `<AccountManager>`, linked as "Account settings" under the profile. */
|
|
1490
|
+
readonly accountHref?: string;
|
|
1491
|
+
/** How avatars fall back (the app's own default, from the person's seed) and which pictures show. */
|
|
1492
|
+
readonly avatar?: AvatarSettings;
|
|
1493
|
+
/**
|
|
1494
|
+
* Where the panel renders: `document.body` by default, so no ancestor's
|
|
1495
|
+
* transform, filter or overflow clips it; null renders it beside its
|
|
1496
|
+
* button. Out of the button's tree, it takes the theme variables set on
|
|
1497
|
+
* `.synq`, which it carries, or on `panelClassName`.
|
|
1498
|
+
*/
|
|
1499
|
+
readonly container?: Element | null;
|
|
1500
|
+
/**
|
|
1501
|
+
* Added to the panel's layer, the full-window element that holds the
|
|
1502
|
+
* dialog (and on a phone, its backdrop): where scoped theme variables go.
|
|
1503
|
+
* `className` is the button's wrapper's alone.
|
|
1504
|
+
*/
|
|
1505
|
+
readonly panelClassName?: string;
|
|
1506
|
+
/**
|
|
1507
|
+
* What the onboarding and the profile show, in this order: the panel's
|
|
1508
|
+
* sections and the app's own cards between them. Username, Wallets and
|
|
1509
|
+
* Linked by default.
|
|
1510
|
+
*/
|
|
1511
|
+
readonly children?: ReactNode;
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* The account button and panel: sign in, a first sign-in's onboarding, and
|
|
1515
|
+
* the profile, in one popover or sheet. Its sections are `AccountPanel.*`.
|
|
1516
|
+
*/
|
|
1517
|
+
export declare function AccountPanel({ methods, moment, sparks, description, accountHref, avatar, container, urlParam, keep, onSignedOut, unstyled, className, panelClassName, children }: AccountPanelProps): ReactNode;
|
|
1518
|
+
export declare namespace AccountPanel {
|
|
1519
|
+
var Username: typeof Username;
|
|
1520
|
+
var Wallets: typeof Wallets;
|
|
1521
|
+
var Linked: typeof Linked;
|
|
1522
|
+
var LinkRow: typeof LinkRow;
|
|
1523
|
+
var Card: typeof Card;
|
|
1524
|
+
var Row: typeof Row;
|
|
1525
|
+
}
|
|
1526
|
+
//#endregion
|
|
1527
|
+
//#region src/components/AvatarMoment.d.ts
|
|
1528
|
+
/** What `AvatarMoment` takes: the sign-in to mark, how large, and how many embers. */
|
|
1529
|
+
interface AvatarMomentProps extends SynqStyleProps, AvatarSettings {
|
|
1530
|
+
/**
|
|
1531
|
+
* The sign-in to mark (`useSignInEvent()`, or the panel's `event`): the
|
|
1532
|
+
* ring and embers play once for its `id`. Null shows the avatar alone.
|
|
1533
|
+
*/
|
|
1534
|
+
readonly event: {
|
|
1535
|
+
readonly id: string;
|
|
1536
|
+
} | null;
|
|
1537
|
+
/** Whose avatar: the signed-in person by default. */
|
|
1538
|
+
readonly user?: AvatarPerson | null;
|
|
1539
|
+
/** The avatar's width and height in pixels: 64 by default. */
|
|
1540
|
+
readonly size?: number;
|
|
1541
|
+
/** How many embers rise: 6 by default, 0 for the ring alone. */
|
|
1542
|
+
readonly sparks?: number;
|
|
1543
|
+
}
|
|
1544
|
+
/**
|
|
1545
|
+
* The person's avatar with the moment of a sign-in: a ring that sweeps
|
|
1546
|
+
* around it once and embers that rise off it, by `--synq-moment-1..3`.
|
|
1547
|
+
* Drawn for the eye alone; the greeting beside it says what happened.
|
|
1548
|
+
*/
|
|
1549
|
+
export declare function AvatarMoment({ event, user, size, sparks, fallback, sources, unstyled, className }: AvatarMomentProps): ReactNode;
|
|
1550
|
+
//#endregion
|
|
1551
|
+
//#region src/wallet-layer.d.ts
|
|
1552
|
+
/** A wallet app as people see it: its name, and its icon when the browser has it. */
|
|
1553
|
+
interface WalletAppInfo {
|
|
1554
|
+
readonly name: string;
|
|
1555
|
+
/** A data URL, as the wallet announced it; null when the browser hasn't it. */
|
|
1556
|
+
readonly icon: string | null;
|
|
1557
|
+
}
|
|
1558
|
+
/** What a wallet layer lends `<AccountPanel>`: see `WalletLayerProvider`. */
|
|
1559
|
+
interface WalletLayer {
|
|
1560
|
+
/** The account the app uses now, and its wallet app; null when none is connected. */
|
|
1561
|
+
readonly connected: {
|
|
1562
|
+
readonly address: string;
|
|
1563
|
+
readonly app: WalletAppInfo | null;
|
|
1564
|
+
} | null;
|
|
1565
|
+
/** The browser's wallets that can sign someone in, for a picker. */
|
|
1566
|
+
readonly wallets: readonly WalletAppInfo[];
|
|
1567
|
+
/**
|
|
1568
|
+
* Signs in with a wallet, in place: the connected one, or the wallet app
|
|
1569
|
+
* called `walletApp`. One signature; the wallet stays connected. A
|
|
1570
|
+
* declined signature is `wallet_rejected`, and what only the hosted page
|
|
1571
|
+
* can do is `redirect_to_web`.
|
|
1572
|
+
*/
|
|
1573
|
+
readonly signIn: (walletApp?: string) => Promise<SynqResult<unknown>>;
|
|
1574
|
+
/**
|
|
1575
|
+
* Adds a wallet to the signed-in profile with one signature: the
|
|
1576
|
+
* connected one, or the wallet app called `walletApp`, which connects it.
|
|
1577
|
+
* A wallet on another profile is `wallet_in_use`; `move()` moves it here
|
|
1578
|
+
* where the brand lets it.
|
|
1579
|
+
*/
|
|
1580
|
+
readonly add: (walletApp?: string) => Promise<SynqResult<Wallet>>;
|
|
1581
|
+
/** Moves the wallet of the last add's `wallet_in_use` here, where the brand lets it (`canMove`). */
|
|
1582
|
+
readonly move: () => Promise<SynqResult<Wallet>>;
|
|
1583
|
+
/** Whether the last add's conflict carries a ticket that moves the wallet here. */
|
|
1584
|
+
readonly canMove: boolean;
|
|
1585
|
+
/**
|
|
1586
|
+
* Connects one of the profile's wallets, signing nothing: at `address`,
|
|
1587
|
+
* in the wallet app called `walletApp` when the browser has it. Another
|
|
1588
|
+
* account selected in the wallet app is `account_mismatch`.
|
|
1589
|
+
*/
|
|
1590
|
+
readonly connect: (address: string, walletApp: string | null) => Promise<SynqResult<unknown>>;
|
|
1591
|
+
/** The address this session signed in with, when the layer knows it. */
|
|
1592
|
+
readonly signedInWith: string | null;
|
|
1593
|
+
/**
|
|
1594
|
+
* Confirms it's them for a change that wants a recent sign-in, with a
|
|
1595
|
+
* wallet on their profile: one signature, in place, no page.
|
|
1596
|
+
*/
|
|
1597
|
+
readonly reauthenticate: () => Promise<SynqResult<unknown>>;
|
|
1598
|
+
/**
|
|
1599
|
+
* Asks for the next signature's request now, and keeps it fresh until the
|
|
1600
|
+
* returned function is called, so a tap on a wallet goes straight to the
|
|
1601
|
+
* wallet (AERO-2679). The account panel calls it while it is open. A
|
|
1602
|
+
* layer without it asks after the tap.
|
|
1603
|
+
*/
|
|
1604
|
+
readonly prepare?: () => () => void;
|
|
1605
|
+
}
|
|
1606
|
+
/**
|
|
1607
|
+
* Lends a wallet layer to the components under it. `<SynqWalletProvider>`
|
|
1608
|
+
* from `@synqauth/solana/react` does this itself; a wallet layer of the
|
|
1609
|
+
* app's own (another chain's, say) passes its own `value`.
|
|
1610
|
+
*/
|
|
1611
|
+
export declare function WalletLayerProvider({ value, children }: {
|
|
1612
|
+
readonly value: WalletLayer | null;
|
|
1613
|
+
readonly children?: ReactNode;
|
|
1614
|
+
}): ReactNode;
|
|
1615
|
+
/** The wallet layer lent to this component (`WalletLayerProvider`), or null when there is none. */
|
|
1616
|
+
export declare function useWalletLayer(): WalletLayer | null;
|
|
1617
|
+
//#endregion
|
|
1618
|
+
export { type AccountManagerProps, Card as AccountPanelCard, type AccountPanelCardProps, type AccountPanelDialogProps, type AccountPanelGrabberProps, type AccountPanelLayout, LinkRow as AccountPanelLinkRow, type AccountPanelLinkRowProps, Linked as AccountPanelLinked, type AccountPanelLinkedProps, type AccountPanelPending, type AccountPanelProps, Row as AccountPanelRow, type AccountPanelRowProps, type AccountPanelSection, type AccountPanelTriggerProps, Username as AccountPanelUsername, type AccountPanelUsernameProps, type AccountPanelView, Wallets as AccountPanelWallets, type AccountPanelWalletsProps, type AccountSection, type AccountSession, type ApiKey, type ApiKeyInput, type AvatarFallback, type AvatarMomentProps, type AvatarProps, type AvatarSettings, type AvatarSource, type HandoffOptions, type KeyableApi, type LastUsedMethod, type LinkStatus, type LinkableMethod, type LinkedAccount, type NewApiKey, type OneTimeCodeInputProps, type Passkey, type Profile, type ProfileUpdate, type ReauthenticateOptions, type RedirectKind, type RedirectResult, type SessionStatus, type SignInButtonProps, type SignInDisplay, type SignInDone, type SignInEvent, type SignInFormProps, type SignInHandover, type SignInMethod, type SignInMethodInfo, type SignInMethods, type SignInOptions, type SignInPartProps, type SignInProblem, type SignInStep, type SignOutOptions, type SynqClientPlugin, type SynqMessages, type SynqMountRequest, type SynqProviderProps, type SynqResult, type SynqSessionInfo, type SynqStyleProps, type SynqUser, type UseAccountData, type UseAccountPanel, type UseAccountPanelOptions, type UseAuth, type UseAvatar, type UseLink, type UseRedirectResult, type UseSession, type UseSignIn, type UseSignInEvent, type UseSignInMethods, type UseSignInOptions, type UseUser, type UseUsernameField, type UserButtonProps, type UserMetadata, type UsernameCode, type UsernameStatus, type Wallet, type WalletAppInfo, type WalletLayer, type WalletManagerProps, type WalletRequestTarget, type WalletSignedIn };
|