@oxyhq/core 5.4.3 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/HttpService.js +6 -3
- package/dist/cjs/OxyServices.base.js +7 -102
- package/dist/cjs/boot/coldBootV2.js +350 -0
- package/dist/cjs/boot/deviceBootReturn.js +152 -0
- package/dist/cjs/crypto/keyManager.js +95 -0
- package/dist/cjs/i18n/locales/en-US.json +13 -1
- package/dist/cjs/i18n/locales/es-ES.json +13 -1
- package/dist/cjs/i18n/locales/locales/en-US.json +13 -1
- package/dist/cjs/i18n/locales/locales/es-ES.json +13 -1
- package/dist/cjs/index.js +47 -43
- package/dist/cjs/mixins/OxyServices.accounts.js +6 -13
- package/dist/cjs/mixins/OxyServices.auth.js +66 -201
- package/dist/cjs/mixins/OxyServices.authorizedApps.js +38 -0
- package/dist/cjs/mixins/OxyServices.deviceBoot.js +119 -0
- package/dist/cjs/mixins/index.js +13 -17
- package/dist/cjs/session/SessionClient.js +44 -2
- package/dist/cjs/session/authStateStore.js +284 -0
- package/dist/cjs/session/createSessionClient.js +8 -2
- package/dist/cjs/session/refresh.js +264 -0
- package/dist/cjs/utils/accountUtils.js +1 -55
- package/dist/cjs/utils/authWebUrl.js +6 -15
- package/dist/cjs/utils/fapiAutoDetect.js +16 -64
- package/dist/cjs/utils/platform.js +19 -0
- package/dist/cjs/utils/ssoBounce.js +15 -340
- package/dist/cjs/utils/validationUtils.js +57 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/HttpService.js +6 -3
- package/dist/esm/OxyServices.base.js +7 -102
- package/dist/esm/boot/coldBootV2.js +344 -0
- package/dist/esm/boot/deviceBootReturn.js +146 -0
- package/dist/esm/crypto/keyManager.js +95 -0
- package/dist/esm/i18n/locales/en-US.json +13 -1
- package/dist/esm/i18n/locales/es-ES.json +13 -1
- package/dist/esm/i18n/locales/locales/en-US.json +13 -1
- package/dist/esm/i18n/locales/locales/es-ES.json +13 -1
- package/dist/esm/index.js +28 -18
- package/dist/esm/mixins/OxyServices.accounts.js +6 -13
- package/dist/esm/mixins/OxyServices.auth.js +66 -201
- package/dist/esm/mixins/OxyServices.authorizedApps.js +35 -0
- package/dist/esm/mixins/OxyServices.deviceBoot.js +116 -0
- package/dist/esm/mixins/index.js +13 -17
- package/dist/esm/session/SessionClient.js +44 -2
- package/dist/esm/session/authStateStore.js +278 -0
- package/dist/esm/session/createSessionClient.js +8 -2
- package/dist/esm/session/refresh.js +257 -0
- package/dist/esm/utils/accountUtils.js +0 -53
- package/dist/esm/utils/authWebUrl.js +6 -14
- package/dist/esm/utils/fapiAutoDetect.js +16 -63
- package/dist/esm/utils/platform.js +18 -0
- package/dist/esm/utils/ssoBounce.js +14 -324
- package/dist/esm/utils/validationUtils.js +56 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/HttpService.d.ts +13 -0
- package/dist/types/OxyServices.base.d.ts +0 -52
- package/dist/types/OxyServices.d.ts +0 -25
- package/dist/types/boot/coldBootV2.d.ts +76 -0
- package/dist/types/boot/deviceBootReturn.d.ts +83 -0
- package/dist/types/crypto/keyManager.d.ts +21 -0
- package/dist/types/index.d.ts +16 -21
- package/dist/types/mixins/OxyServices.accounts.d.ts +0 -2
- package/dist/types/mixins/OxyServices.analytics.d.ts +0 -2
- package/dist/types/mixins/OxyServices.appData.d.ts +0 -2
- package/dist/types/mixins/OxyServices.assets.d.ts +0 -2
- package/dist/types/mixins/OxyServices.auth.d.ts +35 -77
- package/dist/types/mixins/{OxyServices.redirect.d.ts → OxyServices.authorizedApps.d.ts} +35 -33
- package/dist/types/mixins/OxyServices.civic.d.ts +0 -2
- package/dist/types/mixins/OxyServices.connectedApps.d.ts +0 -2
- package/dist/types/mixins/OxyServices.contacts.d.ts +0 -2
- package/dist/types/mixins/OxyServices.deviceBoot.d.ts +110 -0
- package/dist/types/mixins/OxyServices.devices.d.ts +0 -2
- package/dist/types/mixins/OxyServices.features.d.ts +0 -2
- package/dist/types/mixins/OxyServices.identity.d.ts +0 -2
- package/dist/types/mixins/OxyServices.language.d.ts +0 -2
- package/dist/types/mixins/OxyServices.links.d.ts +0 -2
- package/dist/types/mixins/OxyServices.location.d.ts +0 -2
- package/dist/types/mixins/OxyServices.nodes.d.ts +0 -2
- package/dist/types/mixins/OxyServices.payment.d.ts +0 -2
- package/dist/types/mixins/OxyServices.privacy.d.ts +0 -2
- package/dist/types/mixins/OxyServices.reputation.d.ts +0 -2
- package/dist/types/mixins/OxyServices.security.d.ts +0 -2
- package/dist/types/mixins/OxyServices.topics.d.ts +0 -2
- package/dist/types/mixins/OxyServices.user.d.ts +0 -2
- package/dist/types/mixins/OxyServices.utility.d.ts +0 -2
- package/dist/types/mixins/index.d.ts +6 -9
- package/dist/types/models/interfaces.d.ts +0 -67
- package/dist/types/session/SessionClient.d.ts +38 -1
- package/dist/types/session/authStateStore.d.ts +119 -0
- package/dist/types/session/createSessionClient.d.ts +8 -1
- package/dist/types/session/refresh.d.ts +93 -0
- package/dist/types/utils/accountUtils.d.ts +0 -14
- package/dist/types/utils/authWebUrl.d.ts +6 -12
- package/dist/types/utils/fapiAutoDetect.d.ts +15 -38
- package/dist/types/utils/platform.d.ts +14 -0
- package/dist/types/utils/ssoBounce.d.ts +14 -262
- package/dist/types/utils/validationUtils.d.ts +15 -0
- package/package.json +2 -2
- package/src/HttpService.ts +19 -3
- package/src/OxyServices.base.ts +7 -112
- package/src/OxyServices.ts +0 -38
- package/src/boot/__tests__/coldBootV2.test.ts +317 -0
- package/src/boot/__tests__/deviceBootReturn.test.ts +158 -0
- package/src/boot/coldBootV2.ts +426 -0
- package/src/boot/deviceBootReturn.ts +195 -0
- package/src/crypto/__tests__/sharedDeviceToken.test.ts +24 -0
- package/src/crypto/keyManager.ts +101 -0
- package/src/i18n/locales/en-US.json +13 -1
- package/src/i18n/locales/es-ES.json +13 -1
- package/src/index.ts +78 -64
- package/src/mixins/OxyServices.accounts.ts +6 -13
- package/src/mixins/OxyServices.auth.ts +78 -253
- package/src/mixins/OxyServices.authorizedApps.ts +75 -0
- package/src/mixins/OxyServices.deviceBoot.ts +146 -0
- package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +107 -0
- package/src/mixins/__tests__/accounts.test.ts +17 -44
- package/src/mixins/__tests__/authorizedApps.test.ts +63 -0
- package/src/mixins/__tests__/passwordSignIn.test.ts +91 -0
- package/src/mixins/index.ts +16 -22
- package/src/models/interfaces.ts +0 -79
- package/src/session/SessionClient.ts +69 -3
- package/src/session/__tests__/SessionClient.additive.test.ts +92 -0
- package/src/session/__tests__/SessionClient.rest.test.ts +25 -0
- package/src/session/__tests__/SessionClient.socketFactory.test.ts +79 -0
- package/src/session/__tests__/SessionClient.state.test.ts +18 -5
- package/src/session/__tests__/authStateStore.test.ts +209 -0
- package/src/session/__tests__/refresh.test.ts +256 -0
- package/src/session/authStateStore.ts +335 -0
- package/src/session/createSessionClient.ts +9 -1
- package/src/session/refresh.ts +334 -0
- package/src/utils/__tests__/authWebUrl.test.ts +5 -29
- package/src/utils/__tests__/fapiAutoDetect.test.ts +5 -126
- package/src/utils/__tests__/validationUtils.test.ts +30 -0
- package/src/utils/accountUtils.ts +0 -62
- package/src/utils/authWebUrl.ts +6 -15
- package/src/utils/fapiAutoDetect.ts +16 -60
- package/src/utils/platform.ts +21 -0
- package/src/utils/ssoBounce.ts +14 -371
- package/src/utils/validationUtils.ts +62 -0
- package/dist/cjs/AuthManager.js +0 -1110
- package/dist/cjs/AuthManagerTypes.js +0 -13
- package/dist/cjs/CrossDomainAuth.js +0 -206
- package/dist/cjs/mixins/OxyServices.fedcm.js +0 -823
- package/dist/cjs/mixins/OxyServices.redirect.js +0 -95
- package/dist/cjs/mixins/OxyServices.silent.js +0 -204
- package/dist/cjs/mixins/OxyServices.sso.js +0 -208
- package/dist/cjs/utils/ssoEstablish.js +0 -110
- package/dist/cjs/utils/ssoReturn.js +0 -267
- package/dist/esm/AuthManager.js +0 -1105
- package/dist/esm/AuthManagerTypes.js +0 -12
- package/dist/esm/CrossDomainAuth.js +0 -201
- package/dist/esm/mixins/OxyServices.fedcm.js +0 -821
- package/dist/esm/mixins/OxyServices.redirect.js +0 -92
- package/dist/esm/mixins/OxyServices.silent.js +0 -202
- package/dist/esm/mixins/OxyServices.sso.js +0 -204
- package/dist/esm/utils/ssoEstablish.js +0 -107
- package/dist/esm/utils/ssoReturn.js +0 -263
- package/dist/types/AuthManager.d.ts +0 -380
- package/dist/types/AuthManagerTypes.d.ts +0 -81
- package/dist/types/CrossDomainAuth.d.ts +0 -164
- package/dist/types/mixins/OxyServices.fedcm.d.ts +0 -331
- package/dist/types/mixins/OxyServices.silent.d.ts +0 -132
- package/dist/types/mixins/OxyServices.sso.d.ts +0 -138
- package/dist/types/utils/ssoEstablish.d.ts +0 -85
- package/dist/types/utils/ssoReturn.d.ts +0 -146
- package/src/AuthManager.ts +0 -1269
- package/src/AuthManagerTypes.ts +0 -86
- package/src/CrossDomainAuth.ts +0 -243
- package/src/__tests__/authManager.cookiePath.test.ts +0 -390
- package/src/__tests__/authManager.security.test.ts +0 -377
- package/src/__tests__/crossDomainAuth.test.ts +0 -116
- package/src/__tests__/establishDeviceRefreshSlot.test.ts +0 -221
- package/src/mixins/OxyServices.fedcm.ts +0 -1026
- package/src/mixins/OxyServices.redirect.ts +0 -122
- package/src/mixins/OxyServices.silent.ts +0 -272
- package/src/mixins/OxyServices.sso.ts +0 -261
- package/src/mixins/__tests__/constructorAuthWebUrl.test.ts +0 -85
- package/src/mixins/__tests__/fedcm.test.ts +0 -667
- package/src/mixins/__tests__/sessionBaseUrl.test.ts +0 -61
- package/src/mixins/__tests__/silent.test.ts +0 -102
- package/src/mixins/__tests__/sso.test.ts +0 -228
- package/src/utils/__tests__/consumeSsoReturn.test.ts +0 -816
- package/src/utils/__tests__/ssoBounce.test.ts +0 -219
- package/src/utils/__tests__/ssoEstablish.test.ts +0 -204
- package/src/utils/__tests__/ssoReturn.test.ts +0 -251
- package/src/utils/ssoEstablish.ts +0 -174
- package/src/utils/ssoReturn.ts +0 -372
|
@@ -26,6 +26,19 @@ export interface RequestOptions {
|
|
|
26
26
|
signal?: AbortSignal;
|
|
27
27
|
headers?: Record<string, string>;
|
|
28
28
|
responseType?: 'blob';
|
|
29
|
+
/**
|
|
30
|
+
* Skip BOTH the bearer auth header (and its near-expiry preflight refresh)
|
|
31
|
+
* AND the 401-driven auto-refresh/retry for this request.
|
|
32
|
+
*
|
|
33
|
+
* Required for the body-authenticated refresh endpoint (`POST
|
|
34
|
+
* /auth/refresh-token`): it does not need a bearer, and — critically — it is
|
|
35
|
+
* itself invoked from inside the registered `AuthRefreshHandler`. If it went
|
|
36
|
+
* through the normal preflight, `getAuthHeader` would call
|
|
37
|
+
* `refreshAccessToken` while the handler-owning `tokenRefreshPromise` is
|
|
38
|
+
* still in flight and await ITSELF (deadlock). Skipping auth makes the
|
|
39
|
+
* refresh call fully independent of the current (near-expired) bearer.
|
|
40
|
+
*/
|
|
41
|
+
skipAuth?: boolean;
|
|
29
42
|
}
|
|
30
43
|
interface RequestConfig extends RequestOptions {
|
|
31
44
|
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
@@ -25,20 +25,6 @@ export declare class OxyServicesBase {
|
|
|
25
25
|
* Get the configured Oxy API base URL
|
|
26
26
|
*/
|
|
27
27
|
getBaseURL(): string;
|
|
28
|
-
/**
|
|
29
|
-
* Get the base URL the SDK's first-party session/refresh calls should target.
|
|
30
|
-
*
|
|
31
|
-
* Returns the configured `sessionBaseUrl` when provided, otherwise falls back
|
|
32
|
-
* to the API `baseURL` (`getBaseURL()`). Per the 2026 session architecture
|
|
33
|
-
* (docs/SESSION-ARCHITECTURE.md), non-`oxy.so` apps point this at their own
|
|
34
|
-
* same-site backend (e.g. `https://api.mention.earth`) whose session bridge
|
|
35
|
-
* forwards the user's refresh credential to `api.oxy.so`; `*.oxy.so` apps
|
|
36
|
-
* leave it unset so it resolves to `https://api.oxy.so` and nothing changes.
|
|
37
|
-
*
|
|
38
|
-
* This is additive: it only exposes configuration for `@oxyhq/services` to
|
|
39
|
-
* consume in a later phase. No refresh/auth logic in core reads it yet.
|
|
40
|
-
*/
|
|
41
|
-
getSessionBaseUrl(): string;
|
|
42
28
|
/**
|
|
43
29
|
* Get the HTTP service instance
|
|
44
30
|
* Useful for advanced use cases where direct access to the HTTP service is needed
|
|
@@ -142,44 +128,6 @@ export declare class OxyServicesBase {
|
|
|
142
128
|
* Get the raw access token (for constructing anchor URLs when needed)
|
|
143
129
|
*/
|
|
144
130
|
getAccessToken(): string | null;
|
|
145
|
-
/**
|
|
146
|
-
* Register the CURRENTLY-ACTIVE session in the device's first-party
|
|
147
|
-
* multi-account refresh-cookie set by calling `POST /auth/session`.
|
|
148
|
-
*
|
|
149
|
-
* This is the single, shared primitive every web primary-session commit and the
|
|
150
|
-
* account switch use to plant their `oxy_rt_<authuser>` slot. It MUST be a
|
|
151
|
-
* dedicated call to `/auth/session` rather than relying on whichever endpoint
|
|
152
|
-
* established the session: that endpoint is frequently OUTSIDE the cookie's
|
|
153
|
-
* `Path=/auth` scope (`/accounts/:id/switch`) or is a cross-origin/credential-
|
|
154
|
-
* less restore (`/sso/exchange`, the IdP `/auth/silent` postMessage) that cannot
|
|
155
|
-
* set an `api.oxy.so` cookie at all. `/auth/session` runs where the device's
|
|
156
|
-
* existing slots ARE visible, so the server resolves this user's slot (reusing an
|
|
157
|
-
* existing one or allocating a new one) without clobbering a sibling account,
|
|
158
|
-
* mints a fresh access token bound to the same session, and returns the resolved
|
|
159
|
-
* `authuser`.
|
|
160
|
-
*
|
|
161
|
-
* Behaviour:
|
|
162
|
-
* - Requires a planted bearer (the caller must have already installed the
|
|
163
|
-
* session's access token); `/auth/session` derives the session from it.
|
|
164
|
-
* - On success re-plants the rotated access token (so the active token matches
|
|
165
|
-
* the freshly-rotated cookie) and returns the device `authuser` slot.
|
|
166
|
-
* - WEB-ONLY: on native there are no first-party refresh cookies → returns
|
|
167
|
-
* `null`.
|
|
168
|
-
* - FIRST-PARTY-ONLY: the cookie is host-only on the API host with
|
|
169
|
-
* `SameSite=Lax`, so it only sticks when the page is SAME-SITE (same
|
|
170
|
-
* registrable apex) as the API. On a cross-apex RP (`mention.earth` calling
|
|
171
|
-
* `api.oxy.so`) the browser rejects the `Set-Cookie` as a third-party cookie,
|
|
172
|
-
* so a returned slot would be a phantom never enumerated by `refresh-all`.
|
|
173
|
-
* Those RPs durably restore via the per-apex `/auth/silent` iframe + `/sso`
|
|
174
|
-
* bounce, NOT this device set → returns `null` without calling the API.
|
|
175
|
-
* - BEST-EFFORT: a failure (e.g. transient network) never throws — the session
|
|
176
|
-
* stays active in-memory; only its reload durability via the device set is at
|
|
177
|
-
* risk. The caller treats `null` as "not registered in the device set".
|
|
178
|
-
*
|
|
179
|
-
* @returns The resolved device `authuser` slot, or `null` on native / cross-apex
|
|
180
|
-
* / failure.
|
|
181
|
-
*/
|
|
182
|
-
establishDeviceRefreshSlot(): Promise<number | null>;
|
|
183
131
|
/**
|
|
184
132
|
* Decode the current access token and return its `exp` claim in SECONDS since
|
|
185
133
|
* the Unix epoch (the raw JWT `exp` unit), or `null` when there is no token,
|
|
@@ -58,10 +58,6 @@
|
|
|
58
58
|
*/
|
|
59
59
|
import { type LinkedHttpClient, type OxyConfig } from './OxyServices.base';
|
|
60
60
|
import { OxyAuthenticationError, OxyAuthenticationTimeoutError } from './OxyServices.errors';
|
|
61
|
-
import type { SessionLoginResponse } from './models/session';
|
|
62
|
-
import type { FedCMAuthOptions, FedCMConfig } from './mixins/OxyServices.fedcm';
|
|
63
|
-
import type { SilentAuthOptions } from './mixins/OxyServices.silent';
|
|
64
|
-
import type { RedirectAuthOptions } from './mixins/OxyServices.redirect';
|
|
65
61
|
import { composeOxyServices } from './mixins';
|
|
66
62
|
/**
|
|
67
63
|
* OxyServices - Unified client library for interacting with the Oxy API
|
|
@@ -100,31 +96,10 @@ import { composeOxyServices } from './mixins';
|
|
|
100
96
|
*/
|
|
101
97
|
declare const OxyServicesComposed: import("./mixins").ComposedOxyServicesConstructor;
|
|
102
98
|
export declare class OxyServices extends OxyServicesComposed {
|
|
103
|
-
/**
|
|
104
|
-
* FedCM credential-request timeouts (ms). The runtime values are defined on
|
|
105
|
-
* the FedCM mixin and inherited here via `extends`; these `declare` members
|
|
106
|
-
* surface their types to TypeScript without re-emitting (or duplicating) the
|
|
107
|
-
* literals, so consumers/tests can reference `OxyServices.FEDCM_SILENT_TIMEOUT`
|
|
108
|
-
* with full typing.
|
|
109
|
-
*/
|
|
110
|
-
static readonly FEDCM_TIMEOUT: number;
|
|
111
|
-
static readonly FEDCM_SILENT_TIMEOUT: number;
|
|
112
99
|
constructor(config: OxyConfig);
|
|
113
100
|
}
|
|
114
101
|
export interface OxyServices extends InstanceType<ReturnType<typeof composeOxyServices>> {
|
|
115
102
|
createLinkedClient(config: OxyConfig): LinkedHttpClient;
|
|
116
|
-
isFedCMSupported(): boolean;
|
|
117
|
-
signInWithFedCM(options?: FedCMAuthOptions): Promise<SessionLoginResponse>;
|
|
118
|
-
silentSignInWithFedCM(): Promise<SessionLoginResponse | null>;
|
|
119
|
-
revokeFedCMCredential(): Promise<void>;
|
|
120
|
-
getFedCMConfig(): FedCMConfig;
|
|
121
|
-
resolveAuthUrl(): string;
|
|
122
|
-
silentSignIn(options?: SilentAuthOptions): Promise<SessionLoginResponse | null>;
|
|
123
|
-
waitForIframeAuth(iframe: HTMLIFrameElement, timeout: number, expectedOrigin: string): Promise<SessionLoginResponse | null>;
|
|
124
|
-
signInWithRedirect(options?: RedirectAuthOptions): void;
|
|
125
|
-
signUpWithRedirect(options?: RedirectAuthOptions): void;
|
|
126
|
-
exchangeSsoCode(code: string, state?: string): Promise<SessionLoginResponse>;
|
|
127
|
-
generateSsoState(): string;
|
|
128
103
|
auth(options?: {
|
|
129
104
|
debug?: boolean;
|
|
130
105
|
onError?: (error: unknown) => unknown;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type ColdBootOutcome } from '../utils/coldBoot';
|
|
2
|
+
import type { OxyServices } from '../OxyServices';
|
|
3
|
+
import type { AuthStateStore } from '../session/authStateStore';
|
|
4
|
+
import { type DeviceBootSession } from './deviceBootReturn';
|
|
5
|
+
/**
|
|
6
|
+
* localStorage flag marking that the cross-apex bootstrap navigation has fired
|
|
7
|
+
* once for this origin. Persistent (not session) so the visible redirect
|
|
8
|
+
* happens AT MOST ONCE EVER per browser+origin — a signed-out user is never
|
|
9
|
+
* bounced again; they sign in explicitly.
|
|
10
|
+
*/
|
|
11
|
+
export declare const BOOT_ATTEMPTED_KEY = "oxy.boot.attempted";
|
|
12
|
+
/** Why a cold boot ended without a session. */
|
|
13
|
+
export type SignedOutReason = 'no_session' | 'new_device' | 'state-mismatch' | 'error';
|
|
14
|
+
/**
|
|
15
|
+
* The DOM/storage seam. All access is injected so the boot is unit-testable
|
|
16
|
+
* under the jest `node` environment; {@link createBrowserColdBootDom} provides
|
|
17
|
+
* the guarded real-globals implementation used in production.
|
|
18
|
+
*/
|
|
19
|
+
export interface ColdBootDom {
|
|
20
|
+
getHash(): string;
|
|
21
|
+
stripFragment(): void;
|
|
22
|
+
getSessionItem(key: string): string | null;
|
|
23
|
+
setSessionItem(key: string, value: string): void;
|
|
24
|
+
removeSessionItem(key: string): void;
|
|
25
|
+
getLocalItem(key: string): string | null;
|
|
26
|
+
setLocalItem(key: string, value: string): void;
|
|
27
|
+
getLocationHostname(): string | null;
|
|
28
|
+
/** Current href WITHOUT its hash fragment (the bootstrap `return_to`). */
|
|
29
|
+
getReturnToHref(): string | null;
|
|
30
|
+
navigate(url: string): void;
|
|
31
|
+
/** A fresh high-entropy CSRF state token. */
|
|
32
|
+
randomState(): string;
|
|
33
|
+
}
|
|
34
|
+
export interface RunSessionColdBootOptions {
|
|
35
|
+
oxy: OxyServices;
|
|
36
|
+
store: AuthStateStore;
|
|
37
|
+
/** Platform hints; default derived from `@oxyhq/core`'s platform detection. */
|
|
38
|
+
platform?: {
|
|
39
|
+
isWeb?: boolean;
|
|
40
|
+
isNative?: boolean;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* The RP return URL for the cross-apex hop. Defaults to the current href
|
|
44
|
+
* (sans fragment) via the DOM seam.
|
|
45
|
+
*/
|
|
46
|
+
returnTo?: string;
|
|
47
|
+
/** Invoked with the winning session (token already planted). */
|
|
48
|
+
onSession?: (session: DeviceBootSession & {
|
|
49
|
+
via: string;
|
|
50
|
+
}) => void | Promise<void>;
|
|
51
|
+
/** Invoked when the boot ended signed out (not while navigating away). */
|
|
52
|
+
onSignedOut?: (reason: SignedOutReason) => void | Promise<void>;
|
|
53
|
+
onStepError?: (id: string, error: unknown) => void;
|
|
54
|
+
/** DOM/storage seam; defaults to the guarded browser implementation. */
|
|
55
|
+
dom?: ColdBootDom;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The guarded real-globals {@link ColdBootDom}. Every accessor tolerates a
|
|
59
|
+
* missing/throwing global (SSR, sandboxed iframe) by returning a neutral value
|
|
60
|
+
* or no-op, so the boot degrades to signed-out rather than crashing.
|
|
61
|
+
*/
|
|
62
|
+
export declare function createBrowserColdBootDom(): ColdBootDom;
|
|
63
|
+
/**
|
|
64
|
+
* True when both hosts are same-site / same-apex. For a normal multi-label host
|
|
65
|
+
* pair, that means sharing a registrable domain. For an IP literal or a
|
|
66
|
+
* single-label host (no registrable domain), same-apex requires the two hosts
|
|
67
|
+
* to be EXACTLY equal — never grouped by a spurious trailing-label match.
|
|
68
|
+
*/
|
|
69
|
+
export declare function isSameApex(pageHost: string, apiHost: string): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Run the device-first cold boot. Resolves to the `runColdBoot` outcome and, as
|
|
72
|
+
* a side effect, invokes `onSession` (winning session, token already planted)
|
|
73
|
+
* or `onSignedOut` (no session — unless the boot is navigating away for the
|
|
74
|
+
* cross-apex hop, in which case neither fires).
|
|
75
|
+
*/
|
|
76
|
+
export declare function runSessionColdBoot(opts: RunSessionColdBootOptions): Promise<ColdBootOutcome<DeviceBootSession>>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Device-boot return-fragment consumption (web cross-apex hop).
|
|
3
|
+
*
|
|
4
|
+
* After the top-level `GET /auth/device/bootstrap` hop, the API 303s back to the
|
|
5
|
+
* RP with a `#oxy_boot=<base64url(JSON)>` fragment. This module parses and
|
|
6
|
+
* consumes it: it strips the fragment from the URL FIRST (so the opaque
|
|
7
|
+
* deviceToken / code never linger in history or a `Referer`), verifies the
|
|
8
|
+
* echoed CSRF `state` against the value the initiator stashed in
|
|
9
|
+
* `sessionStorage`, persists the deviceToken, and — when a session resolved —
|
|
10
|
+
* exchanges the single-use `code` for a token bundle.
|
|
11
|
+
*
|
|
12
|
+
* Pure/injectable: all DOM access (hash, `history.replaceState`,
|
|
13
|
+
* `sessionStorage`) is passed in as callbacks so the logic is unit-testable
|
|
14
|
+
* under the jest `node` environment and reusable by `coldBootV2`.
|
|
15
|
+
*
|
|
16
|
+
* ESM-safe (no `require()`).
|
|
17
|
+
*/
|
|
18
|
+
import { type AuthTokenBundle, type DeviceBootFragment, type DeviceBootReason } from '@oxyhq/contracts';
|
|
19
|
+
import type { AuthStateStore } from '../session/authStateStore';
|
|
20
|
+
/** The `#oxy_boot=` fragment parameter name the API appends on the return hop. */
|
|
21
|
+
export declare const BOOT_FRAGMENT_PARAM = "oxy_boot";
|
|
22
|
+
/**
|
|
23
|
+
* `sessionStorage` key under which the bootstrap-hop initiator stashes the
|
|
24
|
+
* 128-bit CSRF `state` before navigating, and which the return step reads back
|
|
25
|
+
* (single-use).
|
|
26
|
+
*/
|
|
27
|
+
export declare const BOOT_STATE_SESSION_KEY = "oxy.boot.state";
|
|
28
|
+
/** True when a location hash carries the `oxy_boot` return fragment. */
|
|
29
|
+
export declare function hashHasBootFragment(hash: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Extract + decode + validate the `oxy_boot` fragment from a location hash.
|
|
32
|
+
* Returns the parsed {@link DeviceBootFragment}, or `null` when the parameter
|
|
33
|
+
* is absent, not valid base64url, not JSON, or fails the contract schema.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseDeviceBootFragment(hash: string): DeviceBootFragment | null;
|
|
36
|
+
/** The winning session shape a cold-boot step reports. */
|
|
37
|
+
export interface DeviceBootSession {
|
|
38
|
+
sessionId: string;
|
|
39
|
+
userId: string;
|
|
40
|
+
accessToken: string;
|
|
41
|
+
}
|
|
42
|
+
/** Outcome of {@link consumeDeviceBootReturn}. */
|
|
43
|
+
export type DeviceBootReturnOutcome = {
|
|
44
|
+
kind: 'none';
|
|
45
|
+
} | {
|
|
46
|
+
kind: 'state-mismatch';
|
|
47
|
+
} | {
|
|
48
|
+
kind: 'session';
|
|
49
|
+
session: DeviceBootSession;
|
|
50
|
+
} | {
|
|
51
|
+
kind: 'no-session';
|
|
52
|
+
reason: DeviceBootReason;
|
|
53
|
+
};
|
|
54
|
+
export interface ConsumeDeviceBootReturnDeps {
|
|
55
|
+
/** The current location hash (e.g. `window.location.hash`). */
|
|
56
|
+
hash: string;
|
|
57
|
+
/** Strip the fragment from the URL (e.g. `history.replaceState`). */
|
|
58
|
+
stripFragment: () => void;
|
|
59
|
+
/** Read the expected CSRF state (e.g. `sessionStorage.getItem(BOOT_STATE_SESSION_KEY)`). */
|
|
60
|
+
readExpectedState: () => string | null;
|
|
61
|
+
/** Clear the expected CSRF state (single-use). */
|
|
62
|
+
clearExpectedState: () => void;
|
|
63
|
+
store: AuthStateStore;
|
|
64
|
+
/** Exchange the single-use boot code for a token bundle (`oxy.exchangeBootCode`). */
|
|
65
|
+
exchangeBootCode: (code: string) => Promise<AuthTokenBundle>;
|
|
66
|
+
/** Plant the freshly-minted access token on the owner client (`oxy.setTokens`). */
|
|
67
|
+
plantAccessToken: (accessToken: string) => void;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Consume the device-boot return fragment.
|
|
71
|
+
*
|
|
72
|
+
* Order is load-bearing:
|
|
73
|
+
* 1. If no fragment is present, return `none` (no URL mutation).
|
|
74
|
+
* 2. STRIP the fragment from the URL immediately — before validation or any
|
|
75
|
+
* network — so the deviceToken/code never persist in history/referrer.
|
|
76
|
+
* 3. Verify the echoed `state` against the stashed (single-use) value; a
|
|
77
|
+
* mismatch returns `state-mismatch` without persisting or exchanging.
|
|
78
|
+
* 4. Persist the deviceToken (survives sign-out).
|
|
79
|
+
* 5. If a session resolved (`reason:'session'` + `code`), exchange the code,
|
|
80
|
+
* persist the rotated session, plant the token, and return `session`.
|
|
81
|
+
* Otherwise return `no-session` with the reason.
|
|
82
|
+
*/
|
|
83
|
+
export declare function consumeDeviceBootReturn(deps: ConsumeDeviceBootReturnDeps): Promise<DeviceBootReturnOutcome>;
|
|
@@ -157,6 +157,27 @@ export declare class KeyManager {
|
|
|
157
157
|
* @returns True if migration was successful, false if no local identity exists
|
|
158
158
|
*/
|
|
159
159
|
static migrateToSharedIdentity(): Promise<boolean>;
|
|
160
|
+
/**
|
|
161
|
+
* Store the opaque device-attribution token in the SHARED keychain so every
|
|
162
|
+
* Oxy app on this device reads the SAME token and therefore resolves to one
|
|
163
|
+
* server-side DeviceSession.
|
|
164
|
+
*
|
|
165
|
+
* Mirrors the shared-session storage options exactly (iOS keychain access
|
|
166
|
+
* group `group.so.oxy.shared`; Android shared secure store). Native-only —
|
|
167
|
+
* a no-op on web (the shared keychain does not exist there; web persists its
|
|
168
|
+
* deviceToken in the per-origin {@link AuthStateStore} instead).
|
|
169
|
+
*/
|
|
170
|
+
static setSharedDeviceToken(deviceToken: string): Promise<void>;
|
|
171
|
+
/**
|
|
172
|
+
* Read the shared device-attribution token, or `null` when none is set (or
|
|
173
|
+
* on web). Mirrors {@link getSharedSession}'s keychain-access-group read.
|
|
174
|
+
*/
|
|
175
|
+
static getSharedDeviceToken(): Promise<string | null>;
|
|
176
|
+
/**
|
|
177
|
+
* Delete the shared device-attribution token (device signout-all). Best-effort:
|
|
178
|
+
* a keychain failure is logged, not thrown, so it cannot block a sign-out.
|
|
179
|
+
*/
|
|
180
|
+
static clearSharedDeviceToken(): Promise<void>;
|
|
160
181
|
/**
|
|
161
182
|
* Atomically persist a key pair to secure storage with verification + backup.
|
|
162
183
|
*
|
package/dist/types/index.d.ts
CHANGED
|
@@ -21,14 +21,7 @@ export { OxyServices, OxyAuthenticationError, OxyAuthenticationTimeoutError } fr
|
|
|
21
21
|
export { OXY_CLOUD_URL, oxyClient } from './OxyServices';
|
|
22
22
|
export type { LinkedHttpClient } from './OxyServices.base';
|
|
23
23
|
export type { AuthRefreshReason, AuthRefreshHandler } from './HttpService';
|
|
24
|
-
export {
|
|
25
|
-
export type { StorageAdapter, AuthStateChangeCallback, AuthMethod, AuthManagerConfig, } from './AuthManager';
|
|
26
|
-
export type { AuthManagerAccount, RestoreFromCookiesResult, RestoreFromCookiesOptions, SwitchAuthuserResult, } from './AuthManagerTypes';
|
|
27
|
-
export { CrossDomainAuth, createCrossDomainAuth } from './CrossDomainAuth';
|
|
28
|
-
export type { CrossDomainAuthOptions } from './CrossDomainAuth';
|
|
29
|
-
export type { FedCMAuthOptions, FedCMConfig, AuthorizedApp } from './mixins/OxyServices.fedcm';
|
|
30
|
-
export type { SilentAuthOptions } from './mixins/OxyServices.silent';
|
|
31
|
-
export type { RedirectAuthOptions } from './mixins/OxyServices.redirect';
|
|
24
|
+
export type { AuthorizedApp } from './mixins/OxyServices.authorizedApps';
|
|
32
25
|
export { ServiceCredentialMismatchError } from './mixins/OxyServices.auth';
|
|
33
26
|
export type { ServiceTokenResponse } from './mixins/OxyServices.auth';
|
|
34
27
|
export type { CommonsSignInHandle, CommonsSignInStatus, CommonsApprovalInfo, CommonsSignInActionResult, } from './mixins/OxyServices.auth';
|
|
@@ -53,7 +46,6 @@ export { SessionSyncRequiredError, AuthenticationFailedError, ensureValidToken,
|
|
|
53
46
|
export type { HandleApiErrorOptions } from './utils/authHelpers';
|
|
54
47
|
export { mergeSessions, normalizeAndSortSessions, sessionsArraysEqual, } from './utils/sessionUtils';
|
|
55
48
|
export type { ClientSession, StorageKeys, MinimalUserData, SessionLoginResponse, } from './models/session';
|
|
56
|
-
export type { RefreshAllResponse, RefreshAllAccount, RefreshAllAccountUser, RefreshCookieResponse, } from './models/interfaces';
|
|
57
49
|
export { KeyManager, IdentityAlreadyExistsError, IdentityPersistError, } from './crypto/keyManager';
|
|
58
50
|
export type { KeyPair } from './crypto/keyManager';
|
|
59
51
|
export { SignatureService } from './crypto/signatureService';
|
|
@@ -68,7 +60,7 @@ export { TopicType, TopicSource } from './models/Topic';
|
|
|
68
60
|
export type { TopicData, TopicTranslation } from './models/Topic';
|
|
69
61
|
export { SUPPORTED_LANGUAGES, getLanguageMetadata, getLanguageName, getNativeLanguageName, normalizeLanguageCode, isRTLLocale, } from './utils/languageUtils';
|
|
70
62
|
export type { LanguageMetadata } from './utils/languageUtils';
|
|
71
|
-
export { getPlatformOS, setPlatformOS, isWeb, isNative, isIOS, isAndroid, } from './utils/platform';
|
|
63
|
+
export { getPlatformOS, setPlatformOS, isWeb, isNative, isIOS, isAndroid, isWebBrowser, } from './utils/platform';
|
|
72
64
|
export type { PlatformOS } from './utils/platform';
|
|
73
65
|
export { darkenColor, lightenColor, hexToRgb, rgbToHex, withOpacity, isLightColor, getContrastTextColor, } from './shared/utils/colorUtils';
|
|
74
66
|
export { normalizeTheme, normalizeColorScheme, getOppositeTheme, systemPrefersDarkMode, getSystemColorScheme, } from './shared/utils/themeUtils';
|
|
@@ -82,28 +74,31 @@ export { buildSearchParams, buildUrl, buildPaginationParams, safeJsonParse, } fr
|
|
|
82
74
|
export type { PaginationParams, ApiResponse, ErrorResponse, } from './utils/apiUtils';
|
|
83
75
|
export { ErrorCodes, createApiError, handleHttpError, validateRequiredFields, } from './utils/errorUtils';
|
|
84
76
|
export { retryAsync } from './utils/asyncUtils';
|
|
85
|
-
export { EMAIL_REGEX, USERNAME_REGEX, PASSWORD_REGEX, isValidEmail, isValidUsername, isValidPassword, isRequiredString, isRequiredNumber, isRequiredBoolean, isValidArray, isValidObject, isValidUUID, isValidURL, isValidDate, isValidFileSize, isValidFileType, sanitizeString, sanitizeHTML, isValidObjectId, validateAndSanitizeUserInput, } from './utils/validationUtils';
|
|
77
|
+
export { EMAIL_REGEX, USERNAME_REGEX, PASSWORD_REGEX, isValidEmail, isValidUsername, isValidPassword, isValidDisplayName, isRequiredString, isRequiredNumber, isRequiredBoolean, isValidArray, isValidObject, isValidUUID, isValidURL, isValidDate, isValidFileSize, isValidFileType, sanitizeString, sanitizeHTML, isValidObjectId, validateAndSanitizeUserInput, } from './utils/validationUtils';
|
|
86
78
|
export { logger, LogLevel, logAuth, logApi, logSession, logUser, logDevice, logPayment, logPerformance, } from './utils/loggerUtils';
|
|
87
79
|
export type { LogContext } from './utils/loggerUtils';
|
|
88
80
|
export { updateAvatarVisibility } from './utils/avatarUtils';
|
|
89
|
-
export { buildAccountsArray, createQuickAccount, getAccountDisplayName, getAccountFallbackHandle, formatPublicKeyHandle,
|
|
81
|
+
export { buildAccountsArray, createQuickAccount, getAccountDisplayName, getAccountFallbackHandle, formatPublicKeyHandle, getAccountColor, } from './utils/accountUtils';
|
|
90
82
|
export type { QuickAccount, DisplayNameUserShape } from './utils/accountUtils';
|
|
91
|
-
export {
|
|
92
|
-
export { CENTRAL_AUTH_URL, CENTRAL_IDP_APEX
|
|
93
|
-
export {
|
|
94
|
-
export type { SsoReturnKind, SsoReturnResult, ConsumeSsoReturnDeps } from './utils/ssoReturn';
|
|
95
|
-
export { generateSsoState } from './mixins/OxyServices.sso';
|
|
96
|
-
export { establishIdpSessionAfterClaim } from './utils/ssoEstablish';
|
|
97
|
-
export type { SsoEstablishClient, EstablishAfterClaimDeps } from './utils/ssoEstablish';
|
|
98
|
-
export { SSO_CALLBACK_PATH, SSO_GUARD_TTL_MS, ssoStateKey, ssoGuardKey, ssoDestKey, ssoNoSessionKey, ssoAttemptedKey, ssoPriorSessionKey, ssoSignedOutKey, ssoCallbackBootstrapKey, ssoNavigate, getSsoCallbackBootstrapScript, buildSsoBounceUrl, isCentralIdPOrigin, guardActive, silentRestoreSuppressed, allowSsoBounce, } from './utils/ssoBounce';
|
|
99
|
-
export type { SsoBounceGate } from './utils/ssoBounce';
|
|
83
|
+
export { registrableApex } from './utils/fapiAutoDetect';
|
|
84
|
+
export { CENTRAL_AUTH_URL, CENTRAL_IDP_APEX } from './utils/authWebUrl';
|
|
85
|
+
export { SSO_CALLBACK_PATH } from './utils/ssoBounce';
|
|
100
86
|
export { runColdBoot } from './utils/coldBoot';
|
|
101
87
|
export type { ColdBootStep, ColdBootStepResult, ColdBootSession, ColdBootSkip, ColdBootOutcome, RunColdBootOptions, } from './utils/coldBoot';
|
|
102
88
|
export { SessionClient } from './session/SessionClient';
|
|
103
89
|
export type { TokenTransport, SessionClientHost, SessionClientOptions } from './session/SessionClient';
|
|
90
|
+
export type { SocketIOFactory, MinimalSocket } from './session/socketLoader';
|
|
104
91
|
export { createSessionClientHost } from './session/sessionClientHost';
|
|
105
92
|
export { createSessionClient } from './session/createSessionClient';
|
|
106
93
|
export { deviceStateToClientSessions, activeSessionIdOf, activeUserOf, accountIdsOf, } from './session/projectSessionState';
|
|
94
|
+
export { createWebAuthStateStore, createNativeAuthStateStore, createMemoryAuthStateStore, AUTH_STATE_STORAGE_KEY, DEVICE_TOKEN_STORAGE_KEY, } from './session/authStateStore';
|
|
95
|
+
export type { PersistedAuthState, AuthStateStore, NativeKeyValueStorage, } from './session/authStateStore';
|
|
96
|
+
export { refreshPersistedSession, createAuthRefreshHandler, installAuthRefreshHandler, startTokenRefreshScheduler, TOKEN_REFRESH_LEAD_MS, } from './session/refresh';
|
|
97
|
+
export type { RefreshDeps, TokenRefreshSchedulerHandle } from './session/refresh';
|
|
98
|
+
export { runSessionColdBoot, createBrowserColdBootDom, isSameApex, BOOT_ATTEMPTED_KEY, } from './boot/coldBootV2';
|
|
99
|
+
export type { RunSessionColdBootOptions, ColdBootDom, SignedOutReason, } from './boot/coldBootV2';
|
|
100
|
+
export { consumeDeviceBootReturn, parseDeviceBootFragment, hashHasBootFragment, BOOT_FRAGMENT_PARAM, BOOT_STATE_SESSION_KEY, } from './boot/deviceBootReturn';
|
|
101
|
+
export type { DeviceBootSession, DeviceBootReturnOutcome, ConsumeDeviceBootReturnDeps, } from './boot/deviceBootReturn';
|
|
107
102
|
export { packageInfo } from './constants/version';
|
|
108
103
|
import { OxyServices } from './OxyServices';
|
|
109
104
|
export default OxyServices;
|
|
@@ -655,7 +655,6 @@ export declare function OxyServicesAccountsMixin<T extends typeof OxyServicesBas
|
|
|
655
655
|
__resetTokensForTests(): void;
|
|
656
656
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
657
657
|
getBaseURL(): string;
|
|
658
|
-
getSessionBaseUrl(): string;
|
|
659
658
|
getClient(): import("../HttpService").HttpService;
|
|
660
659
|
createLinkedClient(config: import("../OxyServices.base").OxyConfig): import("..").LinkedHttpClient;
|
|
661
660
|
getMetrics(): {
|
|
@@ -684,7 +683,6 @@ export declare function OxyServicesAccountsMixin<T extends typeof OxyServicesBas
|
|
|
684
683
|
getCurrentUserId(): string | null;
|
|
685
684
|
hasValidToken(): boolean;
|
|
686
685
|
getAccessToken(): string | null;
|
|
687
|
-
establishDeviceRefreshSlot(): Promise<number | null>;
|
|
688
686
|
getAccessTokenExpiry(): number | null;
|
|
689
687
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
690
688
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
@@ -25,7 +25,6 @@ export declare function OxyServicesAnalyticsMixin<T extends typeof OxyServicesBa
|
|
|
25
25
|
__resetTokensForTests(): void;
|
|
26
26
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
27
27
|
getBaseURL(): string;
|
|
28
|
-
getSessionBaseUrl(): string;
|
|
29
28
|
getClient(): import("../HttpService").HttpService;
|
|
30
29
|
createLinkedClient(config: import("../OxyServices.base").OxyConfig): import("..").LinkedHttpClient;
|
|
31
30
|
getMetrics(): {
|
|
@@ -54,7 +53,6 @@ export declare function OxyServicesAnalyticsMixin<T extends typeof OxyServicesBa
|
|
|
54
53
|
getCurrentUserId(): string | null;
|
|
55
54
|
hasValidToken(): boolean;
|
|
56
55
|
getAccessToken(): string | null;
|
|
57
|
-
establishDeviceRefreshSlot(): Promise<number | null>;
|
|
58
56
|
getAccessTokenExpiry(): number | null;
|
|
59
57
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
60
58
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
@@ -61,7 +61,6 @@ export declare function OxyServicesAppDataMixin<T extends typeof OxyServicesBase
|
|
|
61
61
|
__resetTokensForTests(): void;
|
|
62
62
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
63
63
|
getBaseURL(): string;
|
|
64
|
-
getSessionBaseUrl(): string;
|
|
65
64
|
getClient(): import("../HttpService").HttpService;
|
|
66
65
|
createLinkedClient(config: import("../OxyServices.base").OxyConfig): import("..").LinkedHttpClient;
|
|
67
66
|
getMetrics(): {
|
|
@@ -90,7 +89,6 @@ export declare function OxyServicesAppDataMixin<T extends typeof OxyServicesBase
|
|
|
90
89
|
getCurrentUserId(): string | null;
|
|
91
90
|
hasValidToken(): boolean;
|
|
92
91
|
getAccessToken(): string | null;
|
|
93
|
-
establishDeviceRefreshSlot(): Promise<number | null>;
|
|
94
92
|
getAccessTokenExpiry(): number | null;
|
|
95
93
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
96
94
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
@@ -180,7 +180,6 @@ export declare function OxyServicesAssetsMixin<T extends typeof OxyServicesBase>
|
|
|
180
180
|
__resetTokensForTests(): void;
|
|
181
181
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
182
182
|
getBaseURL(): string;
|
|
183
|
-
getSessionBaseUrl(): string;
|
|
184
183
|
getClient(): import("../HttpService").HttpService;
|
|
185
184
|
createLinkedClient(config: import("../OxyServices.base").OxyConfig): import("..").LinkedHttpClient;
|
|
186
185
|
getMetrics(): {
|
|
@@ -209,7 +208,6 @@ export declare function OxyServicesAssetsMixin<T extends typeof OxyServicesBase>
|
|
|
209
208
|
getCurrentUserId(): string | null;
|
|
210
209
|
hasValidToken(): boolean;
|
|
211
210
|
getAccessToken(): string | null;
|
|
212
|
-
establishDeviceRefreshSlot(): Promise<number | null>;
|
|
213
211
|
getAccessTokenExpiry(): number | null;
|
|
214
212
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
215
213
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Supports password-based login (email/username) and public key challenge-response.
|
|
5
5
|
*/
|
|
6
|
-
import type { User
|
|
6
|
+
import type { User } from '../models/interfaces';
|
|
7
|
+
import type { LoginResult, LoginSessionResult } from '@oxyhq/contracts';
|
|
7
8
|
import type { SessionLoginResponse } from '../models/session';
|
|
8
9
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
9
10
|
import type { PublicApplication } from './OxyServices.connectedApps';
|
|
@@ -11,25 +12,6 @@ export interface ChallengeResponse {
|
|
|
11
12
|
challenge: string;
|
|
12
13
|
expiresAt: string;
|
|
13
14
|
}
|
|
14
|
-
/**
|
|
15
|
-
* Options for {@link refreshAllSessions}.
|
|
16
|
-
*/
|
|
17
|
-
export interface RefreshAllOptions {
|
|
18
|
-
/**
|
|
19
|
-
* Abort the `POST /auth/refresh-all` request after this many milliseconds and
|
|
20
|
-
* resolve as "no signed-in accounts" (`{ accounts: [] }`) rather than hanging.
|
|
21
|
-
*
|
|
22
|
-
* Why: on a cross-domain RP (e.g. `mention.earth`) the `Domain=oxy.so` refresh
|
|
23
|
-
* cookie never reaches `api.<apex>`, so this request can stall behind a slow
|
|
24
|
-
* or unreachable endpoint with no useful answer coming back. As one step of
|
|
25
|
-
* the ordered cold-boot sequence, a stalled refresh is dead latency in front
|
|
26
|
-
* of the steps that actually hold the answer. A bounded abort lets cold boot
|
|
27
|
-
* fall through quickly. Omit (or pass `0`/negative) to wait indefinitely.
|
|
28
|
-
* The abort is treated identically to a 401 — the
|
|
29
|
-
* "not signed in on this device" path — never an error.
|
|
30
|
-
*/
|
|
31
|
-
timeout?: number;
|
|
32
|
-
}
|
|
33
15
|
export interface RegistrationRequest {
|
|
34
16
|
publicKey: string;
|
|
35
17
|
username: string;
|
|
@@ -419,61 +401,6 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
419
401
|
* @param authorizeCode - The public code being denied.
|
|
420
402
|
*/
|
|
421
403
|
denyCommonsSignIn(authorizeCode: string): Promise<CommonsSignInActionResult>;
|
|
422
|
-
/**
|
|
423
|
-
* Refresh every device-local refresh-cookie slot in a single round trip
|
|
424
|
-
* (Google-style multi-account rebuild).
|
|
425
|
-
*
|
|
426
|
-
* Calls `POST {sessionBaseUrl}/auth/refresh-all` with `credentials: 'include'`
|
|
427
|
-
* and NO bearer. The browser attaches every indexed `oxy_rt_${authuser}`
|
|
428
|
-
* cookie it has; the server rotates each in parallel and returns one entry
|
|
429
|
-
* per VALID account.
|
|
430
|
-
*
|
|
431
|
-
* Failure handling:
|
|
432
|
-
* - 401 → no signed-in accounts on this device → returns `{ accounts: [] }`
|
|
433
|
-
* (NOT an error; this is the cold-boot "not signed in" path).
|
|
434
|
-
* - 404 → endpoint not deployed → returns `{ accounts: [] }`.
|
|
435
|
-
* - Any other non-2xx → throws via `handleError`.
|
|
436
|
-
*
|
|
437
|
-
* The refresh cookie itself never enters JS — only the rotated access
|
|
438
|
-
* tokens do. Each access token still needs to be planted via
|
|
439
|
-
* `setTokens(...)` (or per-account in-memory storage) at the consumer.
|
|
440
|
-
*/
|
|
441
|
-
refreshAllSessions(options?: RefreshAllOptions): Promise<RefreshAllResponse>;
|
|
442
|
-
/**
|
|
443
|
-
* Rotate a single refresh-cookie slot and return the fresh access token.
|
|
444
|
-
*
|
|
445
|
-
* When `authuser` is provided, the server rotates ONLY that slot
|
|
446
|
-
* (`oxy_rt_${authuser}`) — sibling accounts on the same device stay
|
|
447
|
-
* untouched. When omitted, the server picks the lowest indexed slot present.
|
|
448
|
-
* The refresh cookie itself never enters JS.
|
|
449
|
-
*
|
|
450
|
-
* Returns `null` on 401 (no cookie / expired / reused) so the caller can
|
|
451
|
-
* fall through cleanly to the unauthenticated path.
|
|
452
|
-
*/
|
|
453
|
-
refreshTokenViaCookie(opts?: {
|
|
454
|
-
authuser?: number;
|
|
455
|
-
}): Promise<RefreshCookieResponse | null>;
|
|
456
|
-
/**
|
|
457
|
-
* Sign out a single device-local account by its authuser slot index.
|
|
458
|
-
*
|
|
459
|
-
* Revokes that slot's refresh-token family and deactivates its session;
|
|
460
|
-
* sibling indexed slots stay signed in. The browser-side `oxy_rt_${n}`
|
|
461
|
-
* cookie is cleared by the server's `Set-Cookie` response header.
|
|
462
|
-
*/
|
|
463
|
-
logoutSessionByAuthuser(authuser: number): Promise<void>;
|
|
464
|
-
/**
|
|
465
|
-
* Sign out EVERY device-local account on this device by clearing every
|
|
466
|
-
* presented refresh-cookie slot at once. Revokes every family + clears
|
|
467
|
-
* every slot. Always succeeds (idempotent on unknown/garbage tokens).
|
|
468
|
-
*/
|
|
469
|
-
logoutAllSessionsViaCookie(): Promise<void>;
|
|
470
|
-
/**
|
|
471
|
-
* Internal: raw `POST /auth/refresh[?authuser=N]` call returning the
|
|
472
|
-
* minted access token. Returns `null` on 401 / non-2xx.
|
|
473
|
-
*
|
|
474
|
-
* @internal
|
|
475
|
-
*/
|
|
476
|
-
_refreshCookieRaw(authuser?: number): Promise<RefreshCookieResponse | null>;
|
|
477
404
|
/**
|
|
478
405
|
* Internal: decode (without verifying) the `sessionId` claim from a
|
|
479
406
|
* server-signed access token. The server already verified the signature;
|
|
@@ -534,13 +461,45 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
534
461
|
* Convenience helper for email sign-in
|
|
535
462
|
*/
|
|
536
463
|
signInWithEmail(email: string, password: string, deviceName?: string, deviceFingerprint?: any): Promise<SessionLoginResponse>;
|
|
464
|
+
/**
|
|
465
|
+
* Device-first password sign-in. Unlike the legacy {@link signIn} (which
|
|
466
|
+
* assumes a one-step session and is kept intact for existing callers until
|
|
467
|
+
* the F4 cutover), this returns the FULL `POST /auth/login` contract — the
|
|
468
|
+
* discriminated {@link LoginResult}: either a 2FA challenge
|
|
469
|
+
* (`{ twoFactorRequired, loginToken }`) to complete via
|
|
470
|
+
* {@link completeTwoFactorSignIn}, or a session arm.
|
|
471
|
+
*
|
|
472
|
+
* `options.deviceToken` attributes the new session to the caller's existing
|
|
473
|
+
* device set (so an in-app login from a cross-apex, cookie-less web app
|
|
474
|
+
* still joins the same DeviceSession). On the session arm, a returned access
|
|
475
|
+
* token is planted immediately (mirroring {@link verifyChallenge}), so the
|
|
476
|
+
* caller has an authenticated client without a second round-trip.
|
|
477
|
+
*/
|
|
478
|
+
passwordSignIn(identifier: string, password: string, options?: {
|
|
479
|
+
deviceToken?: string;
|
|
480
|
+
deviceName?: string;
|
|
481
|
+
deviceFingerprint?: string;
|
|
482
|
+
}): Promise<LoginResult>;
|
|
483
|
+
/**
|
|
484
|
+
* Complete a 2FA-gated sign-in started by {@link passwordSignIn}. Presents
|
|
485
|
+
* the short-lived `loginToken` with either a TOTP `token` or a `backupCode`
|
|
486
|
+
* to `POST /security/2fa/verify-login`, which must resolve to the session
|
|
487
|
+
* arm of {@link LoginResult} (a second 2FA challenge here is a protocol
|
|
488
|
+
* error). A returned access token is planted immediately.
|
|
489
|
+
*/
|
|
490
|
+
completeTwoFactorSignIn(params: {
|
|
491
|
+
loginToken: string;
|
|
492
|
+
token?: string;
|
|
493
|
+
backupCode?: string;
|
|
494
|
+
deviceToken?: string;
|
|
495
|
+
deviceName?: string;
|
|
496
|
+
}): Promise<LoginSessionResult>;
|
|
537
497
|
httpService: import("../HttpService").HttpService;
|
|
538
498
|
cloudURL: string;
|
|
539
499
|
config: import("../OxyServices.base").OxyConfig;
|
|
540
500
|
__resetTokensForTests(): void;
|
|
541
501
|
makeRequest<T_1>(method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE", url: string, data?: any, options?: import("../HttpService").RequestOptions): Promise<T_1>;
|
|
542
502
|
getBaseURL(): string;
|
|
543
|
-
getSessionBaseUrl(): string;
|
|
544
503
|
getClient(): import("../HttpService").HttpService;
|
|
545
504
|
createLinkedClient(config: import("../OxyServices.base").OxyConfig): import("..").LinkedHttpClient;
|
|
546
505
|
getMetrics(): {
|
|
@@ -569,7 +528,6 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
569
528
|
getCurrentUserId(): string | null;
|
|
570
529
|
hasValidToken(): boolean;
|
|
571
530
|
getAccessToken(): string | null;
|
|
572
|
-
establishDeviceRefreshSlot(): Promise<number | null>;
|
|
573
531
|
getAccessTokenExpiry(): number | null;
|
|
574
532
|
waitForAuth(timeoutMs?: number): Promise<boolean>;
|
|
575
533
|
withAuthRetry<T_1>(operation: () => Promise<T_1>, operationName: string, options?: {
|