@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.
Files changed (186) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/HttpService.js +6 -3
  3. package/dist/cjs/OxyServices.base.js +7 -102
  4. package/dist/cjs/boot/coldBootV2.js +350 -0
  5. package/dist/cjs/boot/deviceBootReturn.js +152 -0
  6. package/dist/cjs/crypto/keyManager.js +95 -0
  7. package/dist/cjs/i18n/locales/en-US.json +13 -1
  8. package/dist/cjs/i18n/locales/es-ES.json +13 -1
  9. package/dist/cjs/i18n/locales/locales/en-US.json +13 -1
  10. package/dist/cjs/i18n/locales/locales/es-ES.json +13 -1
  11. package/dist/cjs/index.js +47 -43
  12. package/dist/cjs/mixins/OxyServices.accounts.js +6 -13
  13. package/dist/cjs/mixins/OxyServices.auth.js +66 -201
  14. package/dist/cjs/mixins/OxyServices.authorizedApps.js +38 -0
  15. package/dist/cjs/mixins/OxyServices.deviceBoot.js +119 -0
  16. package/dist/cjs/mixins/index.js +13 -17
  17. package/dist/cjs/session/SessionClient.js +44 -2
  18. package/dist/cjs/session/authStateStore.js +284 -0
  19. package/dist/cjs/session/createSessionClient.js +8 -2
  20. package/dist/cjs/session/refresh.js +264 -0
  21. package/dist/cjs/utils/accountUtils.js +1 -55
  22. package/dist/cjs/utils/authWebUrl.js +6 -15
  23. package/dist/cjs/utils/fapiAutoDetect.js +16 -64
  24. package/dist/cjs/utils/platform.js +19 -0
  25. package/dist/cjs/utils/ssoBounce.js +15 -340
  26. package/dist/cjs/utils/validationUtils.js +57 -0
  27. package/dist/esm/.tsbuildinfo +1 -1
  28. package/dist/esm/HttpService.js +6 -3
  29. package/dist/esm/OxyServices.base.js +7 -102
  30. package/dist/esm/boot/coldBootV2.js +344 -0
  31. package/dist/esm/boot/deviceBootReturn.js +146 -0
  32. package/dist/esm/crypto/keyManager.js +95 -0
  33. package/dist/esm/i18n/locales/en-US.json +13 -1
  34. package/dist/esm/i18n/locales/es-ES.json +13 -1
  35. package/dist/esm/i18n/locales/locales/en-US.json +13 -1
  36. package/dist/esm/i18n/locales/locales/es-ES.json +13 -1
  37. package/dist/esm/index.js +28 -18
  38. package/dist/esm/mixins/OxyServices.accounts.js +6 -13
  39. package/dist/esm/mixins/OxyServices.auth.js +66 -201
  40. package/dist/esm/mixins/OxyServices.authorizedApps.js +35 -0
  41. package/dist/esm/mixins/OxyServices.deviceBoot.js +116 -0
  42. package/dist/esm/mixins/index.js +13 -17
  43. package/dist/esm/session/SessionClient.js +44 -2
  44. package/dist/esm/session/authStateStore.js +278 -0
  45. package/dist/esm/session/createSessionClient.js +8 -2
  46. package/dist/esm/session/refresh.js +257 -0
  47. package/dist/esm/utils/accountUtils.js +0 -53
  48. package/dist/esm/utils/authWebUrl.js +6 -14
  49. package/dist/esm/utils/fapiAutoDetect.js +16 -63
  50. package/dist/esm/utils/platform.js +18 -0
  51. package/dist/esm/utils/ssoBounce.js +14 -324
  52. package/dist/esm/utils/validationUtils.js +56 -0
  53. package/dist/types/.tsbuildinfo +1 -1
  54. package/dist/types/HttpService.d.ts +13 -0
  55. package/dist/types/OxyServices.base.d.ts +0 -52
  56. package/dist/types/OxyServices.d.ts +0 -25
  57. package/dist/types/boot/coldBootV2.d.ts +76 -0
  58. package/dist/types/boot/deviceBootReturn.d.ts +83 -0
  59. package/dist/types/crypto/keyManager.d.ts +21 -0
  60. package/dist/types/index.d.ts +16 -21
  61. package/dist/types/mixins/OxyServices.accounts.d.ts +0 -2
  62. package/dist/types/mixins/OxyServices.analytics.d.ts +0 -2
  63. package/dist/types/mixins/OxyServices.appData.d.ts +0 -2
  64. package/dist/types/mixins/OxyServices.assets.d.ts +0 -2
  65. package/dist/types/mixins/OxyServices.auth.d.ts +35 -77
  66. package/dist/types/mixins/{OxyServices.redirect.d.ts → OxyServices.authorizedApps.d.ts} +35 -33
  67. package/dist/types/mixins/OxyServices.civic.d.ts +0 -2
  68. package/dist/types/mixins/OxyServices.connectedApps.d.ts +0 -2
  69. package/dist/types/mixins/OxyServices.contacts.d.ts +0 -2
  70. package/dist/types/mixins/OxyServices.deviceBoot.d.ts +110 -0
  71. package/dist/types/mixins/OxyServices.devices.d.ts +0 -2
  72. package/dist/types/mixins/OxyServices.features.d.ts +0 -2
  73. package/dist/types/mixins/OxyServices.identity.d.ts +0 -2
  74. package/dist/types/mixins/OxyServices.language.d.ts +0 -2
  75. package/dist/types/mixins/OxyServices.links.d.ts +0 -2
  76. package/dist/types/mixins/OxyServices.location.d.ts +0 -2
  77. package/dist/types/mixins/OxyServices.nodes.d.ts +0 -2
  78. package/dist/types/mixins/OxyServices.payment.d.ts +0 -2
  79. package/dist/types/mixins/OxyServices.privacy.d.ts +0 -2
  80. package/dist/types/mixins/OxyServices.reputation.d.ts +0 -2
  81. package/dist/types/mixins/OxyServices.security.d.ts +0 -2
  82. package/dist/types/mixins/OxyServices.topics.d.ts +0 -2
  83. package/dist/types/mixins/OxyServices.user.d.ts +0 -2
  84. package/dist/types/mixins/OxyServices.utility.d.ts +0 -2
  85. package/dist/types/mixins/index.d.ts +6 -9
  86. package/dist/types/models/interfaces.d.ts +0 -67
  87. package/dist/types/session/SessionClient.d.ts +38 -1
  88. package/dist/types/session/authStateStore.d.ts +119 -0
  89. package/dist/types/session/createSessionClient.d.ts +8 -1
  90. package/dist/types/session/refresh.d.ts +93 -0
  91. package/dist/types/utils/accountUtils.d.ts +0 -14
  92. package/dist/types/utils/authWebUrl.d.ts +6 -12
  93. package/dist/types/utils/fapiAutoDetect.d.ts +15 -38
  94. package/dist/types/utils/platform.d.ts +14 -0
  95. package/dist/types/utils/ssoBounce.d.ts +14 -262
  96. package/dist/types/utils/validationUtils.d.ts +15 -0
  97. package/package.json +2 -2
  98. package/src/HttpService.ts +19 -3
  99. package/src/OxyServices.base.ts +7 -112
  100. package/src/OxyServices.ts +0 -38
  101. package/src/boot/__tests__/coldBootV2.test.ts +317 -0
  102. package/src/boot/__tests__/deviceBootReturn.test.ts +158 -0
  103. package/src/boot/coldBootV2.ts +426 -0
  104. package/src/boot/deviceBootReturn.ts +195 -0
  105. package/src/crypto/__tests__/sharedDeviceToken.test.ts +24 -0
  106. package/src/crypto/keyManager.ts +101 -0
  107. package/src/i18n/locales/en-US.json +13 -1
  108. package/src/i18n/locales/es-ES.json +13 -1
  109. package/src/index.ts +78 -64
  110. package/src/mixins/OxyServices.accounts.ts +6 -13
  111. package/src/mixins/OxyServices.auth.ts +78 -253
  112. package/src/mixins/OxyServices.authorizedApps.ts +75 -0
  113. package/src/mixins/OxyServices.deviceBoot.ts +146 -0
  114. package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +107 -0
  115. package/src/mixins/__tests__/accounts.test.ts +17 -44
  116. package/src/mixins/__tests__/authorizedApps.test.ts +63 -0
  117. package/src/mixins/__tests__/passwordSignIn.test.ts +91 -0
  118. package/src/mixins/index.ts +16 -22
  119. package/src/models/interfaces.ts +0 -79
  120. package/src/session/SessionClient.ts +69 -3
  121. package/src/session/__tests__/SessionClient.additive.test.ts +92 -0
  122. package/src/session/__tests__/SessionClient.rest.test.ts +25 -0
  123. package/src/session/__tests__/SessionClient.socketFactory.test.ts +79 -0
  124. package/src/session/__tests__/SessionClient.state.test.ts +18 -5
  125. package/src/session/__tests__/authStateStore.test.ts +209 -0
  126. package/src/session/__tests__/refresh.test.ts +256 -0
  127. package/src/session/authStateStore.ts +335 -0
  128. package/src/session/createSessionClient.ts +9 -1
  129. package/src/session/refresh.ts +334 -0
  130. package/src/utils/__tests__/authWebUrl.test.ts +5 -29
  131. package/src/utils/__tests__/fapiAutoDetect.test.ts +5 -126
  132. package/src/utils/__tests__/validationUtils.test.ts +30 -0
  133. package/src/utils/accountUtils.ts +0 -62
  134. package/src/utils/authWebUrl.ts +6 -15
  135. package/src/utils/fapiAutoDetect.ts +16 -60
  136. package/src/utils/platform.ts +21 -0
  137. package/src/utils/ssoBounce.ts +14 -371
  138. package/src/utils/validationUtils.ts +62 -0
  139. package/dist/cjs/AuthManager.js +0 -1110
  140. package/dist/cjs/AuthManagerTypes.js +0 -13
  141. package/dist/cjs/CrossDomainAuth.js +0 -206
  142. package/dist/cjs/mixins/OxyServices.fedcm.js +0 -823
  143. package/dist/cjs/mixins/OxyServices.redirect.js +0 -95
  144. package/dist/cjs/mixins/OxyServices.silent.js +0 -204
  145. package/dist/cjs/mixins/OxyServices.sso.js +0 -208
  146. package/dist/cjs/utils/ssoEstablish.js +0 -110
  147. package/dist/cjs/utils/ssoReturn.js +0 -267
  148. package/dist/esm/AuthManager.js +0 -1105
  149. package/dist/esm/AuthManagerTypes.js +0 -12
  150. package/dist/esm/CrossDomainAuth.js +0 -201
  151. package/dist/esm/mixins/OxyServices.fedcm.js +0 -821
  152. package/dist/esm/mixins/OxyServices.redirect.js +0 -92
  153. package/dist/esm/mixins/OxyServices.silent.js +0 -202
  154. package/dist/esm/mixins/OxyServices.sso.js +0 -204
  155. package/dist/esm/utils/ssoEstablish.js +0 -107
  156. package/dist/esm/utils/ssoReturn.js +0 -263
  157. package/dist/types/AuthManager.d.ts +0 -380
  158. package/dist/types/AuthManagerTypes.d.ts +0 -81
  159. package/dist/types/CrossDomainAuth.d.ts +0 -164
  160. package/dist/types/mixins/OxyServices.fedcm.d.ts +0 -331
  161. package/dist/types/mixins/OxyServices.silent.d.ts +0 -132
  162. package/dist/types/mixins/OxyServices.sso.d.ts +0 -138
  163. package/dist/types/utils/ssoEstablish.d.ts +0 -85
  164. package/dist/types/utils/ssoReturn.d.ts +0 -146
  165. package/src/AuthManager.ts +0 -1269
  166. package/src/AuthManagerTypes.ts +0 -86
  167. package/src/CrossDomainAuth.ts +0 -243
  168. package/src/__tests__/authManager.cookiePath.test.ts +0 -390
  169. package/src/__tests__/authManager.security.test.ts +0 -377
  170. package/src/__tests__/crossDomainAuth.test.ts +0 -116
  171. package/src/__tests__/establishDeviceRefreshSlot.test.ts +0 -221
  172. package/src/mixins/OxyServices.fedcm.ts +0 -1026
  173. package/src/mixins/OxyServices.redirect.ts +0 -122
  174. package/src/mixins/OxyServices.silent.ts +0 -272
  175. package/src/mixins/OxyServices.sso.ts +0 -261
  176. package/src/mixins/__tests__/constructorAuthWebUrl.test.ts +0 -85
  177. package/src/mixins/__tests__/fedcm.test.ts +0 -667
  178. package/src/mixins/__tests__/sessionBaseUrl.test.ts +0 -61
  179. package/src/mixins/__tests__/silent.test.ts +0 -102
  180. package/src/mixins/__tests__/sso.test.ts +0 -228
  181. package/src/utils/__tests__/consumeSsoReturn.test.ts +0 -816
  182. package/src/utils/__tests__/ssoBounce.test.ts +0 -219
  183. package/src/utils/__tests__/ssoEstablish.test.ts +0 -204
  184. package/src/utils/__tests__/ssoReturn.test.ts +0 -251
  185. package/src/utils/ssoEstablish.ts +0 -174
  186. 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
  *
@@ -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 { AuthManager, createAuthManager } from './AuthManager';
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, mergeAccountsFromRefreshAll, getAccountColor, } from './utils/accountUtils';
81
+ export { buildAccountsArray, createQuickAccount, getAccountDisplayName, getAccountFallbackHandle, formatPublicKeyHandle, getAccountColor, } from './utils/accountUtils';
90
82
  export type { QuickAccount, DisplayNameUserShape } from './utils/accountUtils';
91
- export { autoDetectAuthWebUrl, registrableApex } from './utils/fapiAutoDetect';
92
- export { CENTRAL_AUTH_URL, CENTRAL_IDP_APEX, resolveCentralAuthUrl } from './utils/authWebUrl';
93
- export { parseSsoReturnFragment, consumeSsoReturn } from './utils/ssoReturn';
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, RefreshAllResponse, RefreshCookieResponse } from '../models/interfaces';
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?: {