js-bao-wss-client 2.1.0-alpha.8 → 2.1.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 +59 -49
- package/dist/JsBaoClient.d.ts +161 -11
- package/dist/JsBaoClient.js +355 -8
- package/dist/api/cronTriggersApi.d.ts +24 -13
- package/dist/api/cronTriggersApi.js +11 -11
- package/dist/api/documentsApi.d.ts +17 -3
- package/dist/api/documentsApi.js +40 -4
- package/dist/browser.umd.js +836 -55
- package/dist/errors.d.ts +1 -1
- package/dist/internal/authController.d.ts +86 -5
- package/dist/internal/authController.js +94 -11
- package/dist/internal/documentManager.d.ts +64 -0
- package/dist/internal/documentManager.js +140 -1
- package/dist/internal/webSocketManager.d.ts +17 -0
- package/dist/internal/webSocketManager.js +114 -10
- package/dist/internal/y-indexeddb/src/y-indexeddb.d.ts +3 -0
- package/dist/internal/y-indexeddb/src/y-indexeddb.js +76 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -921,10 +921,17 @@ const all = await client.documents.list({ includeRoot: true });
|
|
|
921
921
|
|
|
922
922
|
## OAuth Authentication
|
|
923
923
|
|
|
924
|
+
Google registers a separate OAuth client per platform, so the server publishes a
|
|
925
|
+
client MAP keyed by client type (`web`, `ios`, `android`, `desktop`,
|
|
926
|
+
`chrome-extension`). A browser reads the `web` entry; there is no single
|
|
927
|
+
"is Google available" flag, because one could only ever be right for one
|
|
928
|
+
platform.
|
|
929
|
+
|
|
924
930
|
```typescript
|
|
925
|
-
// Check if
|
|
926
|
-
|
|
927
|
-
|
|
931
|
+
// Check if Google sign-in is available for THIS (browser) client: the provider
|
|
932
|
+
// is enabled and the web entry is usable.
|
|
933
|
+
const googleAvailable = await client.checkOAuthAvailable();
|
|
934
|
+
if (googleAvailable) {
|
|
928
935
|
// Start OAuth flow (redirects to Google)
|
|
929
936
|
await client.startOAuthFlow();
|
|
930
937
|
}
|
|
@@ -975,18 +982,45 @@ if (client.isAuthenticated()) {
|
|
|
975
982
|
client.setToken("new-jwt-token");
|
|
976
983
|
```
|
|
977
984
|
|
|
978
|
-
##
|
|
985
|
+
## Email Sign-In
|
|
979
986
|
|
|
980
|
-
|
|
987
|
+
One request sends ONE email carrying a 6-digit code and — when the redirect
|
|
988
|
+
target is on the app's `[auth].emailRedirectUris` allow-list — a sign-in link.
|
|
989
|
+
The user finishes with whichever suits them, and consuming either one retires
|
|
990
|
+
both: one email signs a user in once. Email sign-in must be enabled for the app
|
|
991
|
+
(`[auth].emailSignInEnabled`, on by default).
|
|
981
992
|
|
|
982
|
-
### Request
|
|
993
|
+
### Request the email
|
|
983
994
|
|
|
984
995
|
```typescript
|
|
985
|
-
//
|
|
986
|
-
|
|
996
|
+
// `redirectUri` defaults to the client's oauthRedirectUri. With no target at
|
|
997
|
+
// all the email carries the code alone, from the same template. A target that
|
|
998
|
+
// IS sent must match the app's non-empty allow-list, or the request is
|
|
999
|
+
// rejected 400 `Invalid redirect URI` — it never degrades to code-only.
|
|
1000
|
+
await client.emailSignInRequest("user@example.com", {
|
|
1001
|
+
redirectUri: "https://app.example.com/auth/callback",
|
|
1002
|
+
});
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
Both credentials expire together, 15 minutes after the request. Rate limits
|
|
1006
|
+
apply (5 requests per email per hour, 20 per IP per hour).
|
|
1007
|
+
|
|
1008
|
+
`magicLinkRequest` and `otpRequest` still work and are **deprecated**: both are
|
|
1009
|
+
aliases of the same issuance path and send the same email.
|
|
1010
|
+
|
|
1011
|
+
### Finish with the code
|
|
1012
|
+
|
|
1013
|
+
```typescript
|
|
1014
|
+
const { user, isNewUser } = await client.otpVerify("user@example.com", "123456");
|
|
1015
|
+
console.log("Logged in as:", user.email);
|
|
1016
|
+
|
|
1017
|
+
// isNewUser is true if this is the user's first sign-in (account was just created)
|
|
1018
|
+
if (isNewUser) {
|
|
1019
|
+
// Show onboarding flow for new users
|
|
1020
|
+
}
|
|
987
1021
|
```
|
|
988
1022
|
|
|
989
|
-
###
|
|
1023
|
+
### Finish with the link
|
|
990
1024
|
|
|
991
1025
|
```typescript
|
|
992
1026
|
// In your callback page (e.g., /oauth/callback)
|
|
@@ -998,7 +1032,6 @@ if (magicToken) {
|
|
|
998
1032
|
const { user, promptAddPasskey, isNewUser } = await client.magicLinkVerify(magicToken);
|
|
999
1033
|
console.log("Logged in as:", user.email);
|
|
1000
1034
|
|
|
1001
|
-
// isNewUser is true if this is the user's first sign-in (account was just created)
|
|
1002
1035
|
if (isNewUser) {
|
|
1003
1036
|
// Show onboarding flow for new users
|
|
1004
1037
|
}
|
|
@@ -1010,56 +1043,32 @@ if (magicToken) {
|
|
|
1010
1043
|
}
|
|
1011
1044
|
```
|
|
1012
1045
|
|
|
1013
|
-
## OTP (Email Code) Authentication
|
|
1014
|
-
|
|
1015
|
-
The client supports passwordless authentication via one-time 6-digit codes sent by email. OTP authentication must be enabled in the admin console for your app.
|
|
1016
|
-
|
|
1017
|
-
### Request OTP Code
|
|
1018
|
-
|
|
1019
|
-
```typescript
|
|
1020
|
-
// Send a 6-digit code to the user's email
|
|
1021
|
-
await client.otpRequest("user@example.com");
|
|
1022
|
-
```
|
|
1023
|
-
|
|
1024
|
-
The code is valid for 10 minutes. Rate limits apply (5 codes per email per hour, 20 per IP per hour).
|
|
1025
|
-
|
|
1026
|
-
### Verify OTP Code
|
|
1027
|
-
|
|
1028
|
-
```typescript
|
|
1029
|
-
// Verify the code and complete authentication
|
|
1030
|
-
const { user, isNewUser } = await client.otpVerify("user@example.com", "123456");
|
|
1031
|
-
console.log("Logged in as:", user.email);
|
|
1032
|
-
|
|
1033
|
-
// isNewUser is true if this is the user's first sign-in (account was just created)
|
|
1034
|
-
if (isNewUser) {
|
|
1035
|
-
// Show onboarding flow for new users
|
|
1036
|
-
}
|
|
1037
|
-
```
|
|
1038
|
-
|
|
1039
1046
|
### Error Handling
|
|
1040
1047
|
|
|
1041
1048
|
```typescript
|
|
1042
1049
|
try {
|
|
1043
1050
|
await client.otpVerify("user@example.com", "123456");
|
|
1044
1051
|
} catch (error) {
|
|
1045
|
-
if (error.code === "
|
|
1046
|
-
// OTP auth not enabled for this app
|
|
1047
|
-
} else if (error.code === "RATE_LIMITED") {
|
|
1052
|
+
if (error.code === "RATE_LIMITED") {
|
|
1048
1053
|
// Too many attempts, try again later
|
|
1049
1054
|
} else if (error.code === "OTP_MAX_ATTEMPTS") {
|
|
1050
|
-
// Maximum verification attempts exceeded, request a new
|
|
1055
|
+
// Maximum verification attempts exceeded, request a new email
|
|
1051
1056
|
} else if (error.code === "INVALID_TOKEN") {
|
|
1052
1057
|
// Invalid or expired code
|
|
1053
1058
|
}
|
|
1054
1059
|
}
|
|
1055
1060
|
```
|
|
1056
1061
|
|
|
1062
|
+
When email sign-in is disabled the request endpoints answer a plain 400 with
|
|
1063
|
+
`"Email sign-in is not enabled for this app"` and no error code — gate the UI
|
|
1064
|
+
on `getAuthConfig()`'s `emailSignInEnabled` instead.
|
|
1065
|
+
|
|
1057
1066
|
## Passkey Authentication
|
|
1058
1067
|
|
|
1059
1068
|
The client supports WebAuthn/passkey authentication for passwordless sign-in. Passkeys must be enabled in the admin console for your app.
|
|
1060
1069
|
|
|
1061
|
-
Note: Passkeys can only be added to existing accounts (created via OAuth or
|
|
1062
|
-
1. User creates account via OAuth or
|
|
1070
|
+
Note: Passkeys can only be added to existing accounts (created via OAuth or email sign-in). To use passkey authentication:
|
|
1071
|
+
1. User creates account via OAuth or email sign-in
|
|
1063
1072
|
2. User adds a passkey to their account
|
|
1064
1073
|
3. User can then sign in with the passkey on future visits
|
|
1065
1074
|
|
|
@@ -1073,14 +1082,15 @@ const config = await client.getAuthConfig();
|
|
|
1073
1082
|
if (config.hasPasskey) {
|
|
1074
1083
|
console.log("Passkeys are available");
|
|
1075
1084
|
}
|
|
1076
|
-
if (config.
|
|
1077
|
-
console.log("
|
|
1078
|
-
}
|
|
1079
|
-
if (config.otpEnabled) {
|
|
1080
|
-
console.log("OTP (email code) sign-in is available");
|
|
1085
|
+
if (config.emailSignInEnabled) {
|
|
1086
|
+
console.log("Email sign-in is available");
|
|
1081
1087
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1088
|
+
// Per-platform Google configuration. `usable` is the server's shape verdict for
|
|
1089
|
+
// one entry — a client id, at least one redirect URI, and a client secret
|
|
1090
|
+
// exactly when that client type takes one. Availability is that AND the
|
|
1091
|
+
// provider switch, which is what `checkOAuthAvailable()` computes.
|
|
1092
|
+
if (config.googleOAuthEnabled && config.googleClients.clients.web?.usable) {
|
|
1093
|
+
console.log("Google OAuth is available in the browser");
|
|
1084
1094
|
}
|
|
1085
1095
|
```
|
|
1086
1096
|
|
package/dist/JsBaoClient.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { type SubscribeOptions } from "./internal/databaseSubscriptions";
|
|
|
8
8
|
import { type StorageConfig, type YjsPersistenceFactory } from "./internal/storage/index.js";
|
|
9
9
|
import { BlobManager } from "./internal/blobManager";
|
|
10
10
|
import { type AnalyticsEventInput } from "./internal/analyticsQueue";
|
|
11
|
+
import { type GoogleClientsConfig } from "./internal/authController";
|
|
11
12
|
import { type RequestOptions } from "./internal/httpClient";
|
|
12
13
|
import { type DocumentPermission as DocumentAccessLevel, type LocalDocumentEntry, type LocalMetadataEntry, type DocumentDebugSnapshot } from "./internal/documentManager";
|
|
13
14
|
import { DocumentsAPI, DocumentContext, type DocumentInfo, type ResolveAliasParams, type CreateDocumentOptions } from "./api/documentsApi";
|
|
@@ -32,8 +33,8 @@ import { InvitationsAPI } from "./api/invitationsApi";
|
|
|
32
33
|
import { NotificationsAPI } from "./api/notificationsApi";
|
|
33
34
|
export { JsBaoError, isJsBaoError, LockTimeoutError, JsBaoApiError, isJsBaoApiError, JsBaoNetworkError, isJsBaoNetworkError, } from "./errors";
|
|
34
35
|
export type { JsBaoErrorCode } from "./errors";
|
|
35
|
-
export { AuthError, AUTH_CODES } from "./internal/authController";
|
|
36
|
-
export type { AuthCode } from "./internal/authController";
|
|
36
|
+
export { AuthError, AUTH_CODES, googleWebClientAvailable, } from "./internal/authController";
|
|
37
|
+
export type { AuthCode, GoogleClientConfig, GoogleClientsConfig, } from "./internal/authController";
|
|
37
38
|
export type { DocumentInfo, DocumentPermissionEntry, DocumentInvitation, DocumentInvitationResponse, DocumentAccessResult, DocumentGroupPermissionEntry, DocumentAliasInfo, DocumentAliasScope, PermissionUpdateResult, DirectPermissionGrant, DeferredPermissionGrant, PendingInvitationEntry, PendingGroupInvitationEntry, LinkAccessResult, } from "./api/documentsApi";
|
|
38
39
|
export type { UserProfile, SharedDocument, SharedDocumentListResult, SharedDocumentsOptions, OwnedDocumentsOptions, } from "./api/meApi";
|
|
39
40
|
export type { SessionInfo } from "./api/sessionApi";
|
|
@@ -69,7 +70,7 @@ export type { GroupTypeConfigsAPI } from "./api/groupTypeConfigsApi";
|
|
|
69
70
|
export type { CollectionTypeConfigsAPI } from "./api/collectionTypeConfigsApi";
|
|
70
71
|
export type { DatabaseTypeConfigsAPI } from "./api/databaseTypeConfigsApi";
|
|
71
72
|
export type { CronTriggersAPI } from "./api/cronTriggersApi";
|
|
72
|
-
export type { CronTriggerInfo, CreateCronTriggerParams, UpdateCronTriggerParams, CronTriggerListResult, } from "./api/cronTriggersApi";
|
|
73
|
+
export type { CronTriggerInfo, CreateCronTriggerParams, UpdateCronTriggerParams, CronTriggerListResult, ObjectStatus, } from "./api/cronTriggersApi";
|
|
73
74
|
export type { CreateDocumentOptions, CreateOfflineOptions, CreateWithAliasOptions, GetOrCreateWithAliasOptions, DeleteDocumentOptions, DocumentAccessRequest, DocumentAccessRequestResponse, DocumentListOptions, DocumentListPage, EvictAllDocumentsOptions, EvictDocumentOptions, GrantGroupPermissionParams, ResolveAliasParams, SetAliasParams, UpdateDocumentData, } from "./api/documentsApi";
|
|
74
75
|
export type { CreateDatabaseParams, UpdateDatabaseParams } from "./api/databasesApi";
|
|
75
76
|
export type { CreateCollectionParams, UpdateCollectionParams, GrantCollectionGroupPermissionParams, ListCollectionsOptions, } from "./api/collectionsApi";
|
|
@@ -325,7 +326,10 @@ export interface PromptsAPI {
|
|
|
325
326
|
* refusal rejects with a `JsBaoApiError` whose `status` is `403` and whose
|
|
326
327
|
* `code` is `"PROMPT_ACCESS_DENIED"` — including when the prompt has no rule
|
|
327
328
|
* stored at all, which denies every caller who is not an app admin or owner.
|
|
328
|
-
* A prompt that is
|
|
329
|
+
* A prompt that is not in service rejects with a `400` whose `code` is
|
|
330
|
+
* `"PROMPT_NOT_EXECUTABLE"`. Availability is a single server-owned `status`:
|
|
331
|
+
* only an `active` prompt executes here, and `primitive prompts enable`
|
|
332
|
+
* puts an inactive one back in service.
|
|
329
333
|
*/
|
|
330
334
|
execute<V extends object = Record<string, unknown>, R = unknown>(promptKey: string, options: ExecutePromptOptions<V>): Promise<ExecutePromptResult<R>>;
|
|
331
335
|
}
|
|
@@ -384,6 +388,16 @@ export interface JsBaoClientOptions {
|
|
|
384
388
|
};
|
|
385
389
|
sync?: {
|
|
386
390
|
outboundDebounceMs?: number;
|
|
391
|
+
/**
|
|
392
|
+
* How long a handshake may take before the client gives up on it and lets
|
|
393
|
+
* the reconnect logic retry, in milliseconds. Defaults to 10000, and is
|
|
394
|
+
* also settable through `CLIENT_SYNC_HANDSHAKE_TIMEOUT_MS`.
|
|
395
|
+
*
|
|
396
|
+
* The budget covers both halves: opening the WebSocket (an endpoint that
|
|
397
|
+
* accepts the connection but never answers the upgrade is abandoned here,
|
|
398
|
+
* rather than holding the connect open forever) and the sync handshake
|
|
399
|
+
* that follows it.
|
|
400
|
+
*/
|
|
387
401
|
handshakeTimeoutMs?: number;
|
|
388
402
|
};
|
|
389
403
|
commitRetryBackoff?: {
|
|
@@ -1884,6 +1898,96 @@ export declare class JsBaoClient extends Observable<any> {
|
|
|
1884
1898
|
background?: boolean;
|
|
1885
1899
|
shouldRetain?: (docId: string) => boolean;
|
|
1886
1900
|
}): Promise<void>;
|
|
1901
|
+
/**
|
|
1902
|
+
* Documents per page for the whole-scope walk. The server caps `limit` at
|
|
1903
|
+
* 100 (`parseListLimitParam`), so asking for more buys nothing.
|
|
1904
|
+
*/
|
|
1905
|
+
private static readonly SCOPE_RECONCILE_PAGE_SIZE;
|
|
1906
|
+
/**
|
|
1907
|
+
* How many pages the walk follows before giving up. 100 pages × 100 rows
|
|
1908
|
+
* bounds it at 10k documents; a scope larger than that (or a server handing
|
|
1909
|
+
* back an endless cursor) is simply not reconciled, which is the safe
|
|
1910
|
+
* direction — nothing is deleted.
|
|
1911
|
+
*/
|
|
1912
|
+
private static readonly SCOPE_RECONCILE_MAX_PAGES;
|
|
1913
|
+
/**
|
|
1914
|
+
* Shortest gap between two whole-scope reconciliations. A walk costs one
|
|
1915
|
+
* request per 100 documents, so a client that reconnects through a flaky
|
|
1916
|
+
* network must not pay for it on every socket.
|
|
1917
|
+
*/
|
|
1918
|
+
private scopeReconcileMinIntervalMs;
|
|
1919
|
+
/** The walk currently running, so concurrent connects share one. */
|
|
1920
|
+
private scopeReconcileInFlight;
|
|
1921
|
+
/** When the last walk finished, completed or not. */
|
|
1922
|
+
private scopeReconcileLastRunAt;
|
|
1923
|
+
/**
|
|
1924
|
+
* Bumped whenever the signed-in user changes. Both the staleness window and
|
|
1925
|
+
* a walk in flight are about one user's scope, and say nothing about the
|
|
1926
|
+
* next user's.
|
|
1927
|
+
*/
|
|
1928
|
+
private scopeReconcileGeneration;
|
|
1929
|
+
/**
|
|
1930
|
+
* Reconcile the local metadata cache against the user's whole document
|
|
1931
|
+
* scope, evicting the documents the server no longer has (#2852).
|
|
1932
|
+
*
|
|
1933
|
+
* Eviction used to happen only inside `documents.list()`, whose response is
|
|
1934
|
+
* reconciled `authoritative: true`. Both clients steer developers off that
|
|
1935
|
+
* method (#628) and onto `me.ownedDocuments` / `me.sharedDocuments`, which
|
|
1936
|
+
* are strict subsets of the cached scope and so stay merge-only — correct
|
|
1937
|
+
* for a subset, but it left an app that never calls the deprecated method
|
|
1938
|
+
* with no eviction path at all: metadata rows and multi-megabyte `yjs_docs`
|
|
1939
|
+
* snapshots of deleted documents accumulated for as long as it kept
|
|
1940
|
+
* launching.
|
|
1941
|
+
*
|
|
1942
|
+
* So this runs on its own schedule — once per connect, and at most once per
|
|
1943
|
+
* `scopeReconcileMinIntervalMs` — rather than as a side effect of a listing
|
|
1944
|
+
* call, which would put a full scope walk behind every list.
|
|
1945
|
+
*
|
|
1946
|
+
* The walk is what makes the result trustworthy. An unpaged `GET /documents`
|
|
1947
|
+
* returns a bare array silently truncated at dynamo-bao's 100-row
|
|
1948
|
+
* `defaultQueryLimit`, so a truncated listing and a complete one are the same
|
|
1949
|
+
* bytes; reading one as the whole scope would delete real local data for
|
|
1950
|
+
* anyone with more than 100 documents. The paged form returns
|
|
1951
|
+
* `{ items, hasMore, nextCursor }`, which is followed here to exhaustion, and
|
|
1952
|
+
* only the union of a completed walk evicts. Anything short of that — a
|
|
1953
|
+
* failed request, a server that ignores `limit` and answers with a bare
|
|
1954
|
+
* array, a page that claims more rows with no cursor to ask for them, a
|
|
1955
|
+
* cursor that stops advancing, the page cap — evicts nothing. Nor does a
|
|
1956
|
+
* completed walk whose union is empty: the request asks `includeRoot=true`,
|
|
1957
|
+
* so zero rows is an anomalous answer rather than a user with no documents
|
|
1958
|
+
* (#2859).
|
|
1959
|
+
*/
|
|
1960
|
+
private reconcileDocumentScope;
|
|
1961
|
+
/**
|
|
1962
|
+
* The hand-off from an unpaged `documents.list()` to the scope walk (#2919).
|
|
1963
|
+
*
|
|
1964
|
+
* `documentsApi` used to reconcile the caller's own listing response
|
|
1965
|
+
* `authoritative: true` whenever the request was not paged. But the unpaged
|
|
1966
|
+
* `GET /documents` is a bare array the server silently truncated at
|
|
1967
|
+
* dynamo-bao's 100-row `defaultQueryLimit`, so a truncated listing and a
|
|
1968
|
+
* complete one are the same bytes: reading one as the server's whole view of
|
|
1969
|
+
* the scope deleted the metadata row — and the cached CRDT state, unflushed
|
|
1970
|
+
* offline edits included — of every cached document past the truncation
|
|
1971
|
+
* point. So the response now merges only, and the eviction decision is left
|
|
1972
|
+
* to `reconcileDocumentScope`, whose paged walk is the only read that can
|
|
1973
|
+
* say where the scope ends. Mirrors the swift-client's
|
|
1974
|
+
* `reconcileByWalkingScope(seenIds:)` (#2827 / PR #2841).
|
|
1975
|
+
*
|
|
1976
|
+
* `seenIds` is what the caller's response already accounted for. When no
|
|
1977
|
+
* cached document is missing from it, an authoritative pass would have
|
|
1978
|
+
* nothing to delete and the walk is skipped — an app whose documents fit in
|
|
1979
|
+
* one response issues no extra request. The root is exempt from that
|
|
1980
|
+
* question: the listing filters it out of its own response, so it is always
|
|
1981
|
+
* "missing", and treating it as a truncation would put a scope walk behind
|
|
1982
|
+
* every listing.
|
|
1983
|
+
*
|
|
1984
|
+
* The walk is NOT forced. Above the truncation threshold every unpaged
|
|
1985
|
+
* listing looks truncated, so forcing would make each `documents.list()` pay
|
|
1986
|
+
* a full N/100-request walk; it shares the connect-time walk's staleness
|
|
1987
|
+
* window instead.
|
|
1988
|
+
*/
|
|
1989
|
+
private _reconcileScopeAfterListing;
|
|
1990
|
+
private _runScopeReconcile;
|
|
1887
1991
|
/** Update local metadata cache with server document data.
|
|
1888
1992
|
* @param items - Array of server document records to merge into the local cache
|
|
1889
1993
|
* @param options - Controls how the merge is performed
|
|
@@ -2615,12 +2719,49 @@ export declare class JsBaoClient extends Observable<any> {
|
|
|
2615
2719
|
name: string;
|
|
2616
2720
|
mode: "public" | "invite-only" | "domain";
|
|
2617
2721
|
waitlistEnabled: boolean;
|
|
2618
|
-
|
|
2722
|
+
/**
|
|
2723
|
+
* Whether THIS (browser) client can start Google sign-in: the provider is
|
|
2724
|
+
* enabled and the `web` entry is usable. A single server-side flag could
|
|
2725
|
+
* not tell a web-configured app from a native-configured one, so this is
|
|
2726
|
+
* computed per platform from the client map.
|
|
2727
|
+
*/
|
|
2728
|
+
googleAvailable: boolean;
|
|
2619
2729
|
hasPasskey: boolean;
|
|
2730
|
+
/**
|
|
2731
|
+
* Is email sign-in available? ONE flag: one request sends one email
|
|
2732
|
+
* carrying both credentials.
|
|
2733
|
+
*/
|
|
2734
|
+
emailSignInEnabled: boolean;
|
|
2735
|
+
/** @deprecated Always equal to `emailSignInEnabled`. */
|
|
2620
2736
|
magicLinkEnabled: boolean;
|
|
2621
2737
|
}>;
|
|
2738
|
+
/**
|
|
2739
|
+
* Request one sign-in email. It carries a 6-digit code and — when a redirect
|
|
2740
|
+
* target is available AND the app allow-lists it — a sign-in link, so the
|
|
2741
|
+
* user can finish on the device they started on or on whichever device has
|
|
2742
|
+
* their mail. Nothing selects a method up front.
|
|
2743
|
+
*
|
|
2744
|
+
* Finish with `otpVerify(email, code)` for the code, or `magicLinkVerify(token)`
|
|
2745
|
+
* for the link. Consuming either one retires both: one email, one session.
|
|
2746
|
+
*
|
|
2747
|
+
* @param email - The email address to sign in
|
|
2748
|
+
* @param options - Optional configuration
|
|
2749
|
+
* @param options.redirectUri - Where the link should land. Defaults to the
|
|
2750
|
+
* client's `oauthRedirectUri`. With neither, the email carries the code
|
|
2751
|
+
* alone rather than failing.
|
|
2752
|
+
* @group Authentication
|
|
2753
|
+
*/
|
|
2754
|
+
emailSignInRequest(email: string, options?: {
|
|
2755
|
+
redirectUri?: string;
|
|
2756
|
+
}): Promise<{
|
|
2757
|
+
success: boolean;
|
|
2758
|
+
}>;
|
|
2622
2759
|
/**
|
|
2623
2760
|
* Request a magic link email for passwordless authentication.
|
|
2761
|
+
*
|
|
2762
|
+
* @deprecated Use {@link emailSignInRequest}. This is an alias of it — the
|
|
2763
|
+
* server issues through the same path and sends the same email, which now
|
|
2764
|
+
* also carries a 6-digit code.
|
|
2624
2765
|
* @param email - The email address to send the magic link to
|
|
2625
2766
|
* @param options - Optional configuration
|
|
2626
2767
|
* @param options.redirectUri - Override the default OAuth redirect URI for the magic link callback
|
|
@@ -2654,6 +2795,9 @@ export declare class JsBaoClient extends Observable<any> {
|
|
|
2654
2795
|
/**
|
|
2655
2796
|
* Request a one-time password (OTP) code to be sent to the specified email.
|
|
2656
2797
|
* The code can be verified using `otpVerify()`.
|
|
2798
|
+
*
|
|
2799
|
+
* @deprecated Use {@link emailSignInRequest}. This is an alias of it that
|
|
2800
|
+
* carries no redirect target, so the email it sends is code-only.
|
|
2657
2801
|
* @param email - The email address to send the OTP code to
|
|
2658
2802
|
* @group Authentication
|
|
2659
2803
|
*/
|
|
@@ -2781,17 +2925,21 @@ export declare class JsBaoClient extends Observable<any> {
|
|
|
2781
2925
|
mode: string;
|
|
2782
2926
|
waitlistEnabled: boolean;
|
|
2783
2927
|
googleOAuthEnabled: boolean;
|
|
2784
|
-
|
|
2785
|
-
hasOAuth: boolean;
|
|
2786
|
-
redirectUris: string[] | null;
|
|
2928
|
+
googleClients: GoogleClientsConfig;
|
|
2787
2929
|
passkeyEnabled: boolean;
|
|
2788
|
-
passkeyRpId: string | null;
|
|
2789
|
-
passkeyRpName: string | null;
|
|
2790
2930
|
passkeyRpConfig: Record<string, {
|
|
2791
2931
|
name: string;
|
|
2792
2932
|
}> | null;
|
|
2793
2933
|
hasPasskey: boolean;
|
|
2934
|
+
/**
|
|
2935
|
+
* Is email sign-in available at all (#2884)? ONE flag — one request sends
|
|
2936
|
+
* one email carrying both credentials, so there is no per-method
|
|
2937
|
+
* availability to report.
|
|
2938
|
+
*/
|
|
2939
|
+
emailSignInEnabled: boolean;
|
|
2940
|
+
/** @deprecated (#2884) Always equal to `emailSignInEnabled`. */
|
|
2794
2941
|
magicLinkEnabled: boolean;
|
|
2942
|
+
/** @deprecated (#2884) Always equal to `emailSignInEnabled`. */
|
|
2795
2943
|
otpEnabled: boolean;
|
|
2796
2944
|
hasApple: boolean;
|
|
2797
2945
|
appleSignInEnabled: boolean;
|
|
@@ -2975,7 +3123,9 @@ export declare class JsBaoClient extends Observable<any> {
|
|
|
2975
3123
|
ttlMs?: number;
|
|
2976
3124
|
preserveOnSignOut?: boolean;
|
|
2977
3125
|
}): void;
|
|
2978
|
-
/** Create a new document
|
|
3126
|
+
/** Create a new document. Writable locally immediately, with the server
|
|
3127
|
+
* commit racing in the background — unless `options.localOnly` is set, in
|
|
3128
|
+
* which case the document never syncs.
|
|
2979
3129
|
* @param options - Document creation options
|
|
2980
3130
|
* @group Documents */
|
|
2981
3131
|
createDocument(options: CreateDocumentOptions): Promise<{
|