@oxyhq/services 18.0.0 → 19.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 (51) hide show
  1. package/lib/commonjs/ui/context/OxyContext.js +52 -83
  2. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  3. package/lib/commonjs/ui/context/hooks/useAuthOperations.js +15 -18
  4. package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
  5. package/lib/commonjs/ui/session/authStore.js +12 -50
  6. package/lib/commonjs/ui/session/authStore.js.map +1 -1
  7. package/lib/commonjs/ui/session/createSessionClient.js +6 -11
  8. package/lib/commonjs/ui/session/createSessionClient.js.map +1 -1
  9. package/lib/commonjs/ui/session/tokenTransport.js +3 -4
  10. package/lib/commonjs/ui/session/tokenTransport.js.map +1 -1
  11. package/lib/module/ui/context/OxyContext.js +52 -83
  12. package/lib/module/ui/context/OxyContext.js.map +1 -1
  13. package/lib/module/ui/context/hooks/useAuthOperations.js +15 -18
  14. package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
  15. package/lib/module/ui/session/authStore.js +13 -51
  16. package/lib/module/ui/session/authStore.js.map +1 -1
  17. package/lib/module/ui/session/createSessionClient.js +6 -11
  18. package/lib/module/ui/session/createSessionClient.js.map +1 -1
  19. package/lib/module/ui/session/tokenTransport.js +3 -4
  20. package/lib/module/ui/session/tokenTransport.js.map +1 -1
  21. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts +15 -6
  22. package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
  23. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts +4 -5
  24. package/lib/typescript/commonjs/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  25. package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  26. package/lib/typescript/commonjs/ui/session/authStore.d.ts +11 -15
  27. package/lib/typescript/commonjs/ui/session/authStore.d.ts.map +1 -1
  28. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts +6 -10
  29. package/lib/typescript/commonjs/ui/session/createSessionClient.d.ts.map +1 -1
  30. package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts +3 -4
  31. package/lib/typescript/commonjs/ui/session/tokenTransport.d.ts.map +1 -1
  32. package/lib/typescript/module/ui/context/OxyContext.d.ts +15 -6
  33. package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
  34. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts +4 -5
  35. package/lib/typescript/module/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
  36. package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
  37. package/lib/typescript/module/ui/session/authStore.d.ts +11 -15
  38. package/lib/typescript/module/ui/session/authStore.d.ts.map +1 -1
  39. package/lib/typescript/module/ui/session/createSessionClient.d.ts +6 -10
  40. package/lib/typescript/module/ui/session/createSessionClient.d.ts.map +1 -1
  41. package/lib/typescript/module/ui/session/tokenTransport.d.ts +3 -4
  42. package/lib/typescript/module/ui/session/tokenTransport.d.ts.map +1 -1
  43. package/package.json +4 -4
  44. package/src/ui/context/OxyContext.tsx +61 -92
  45. package/src/ui/context/__tests__/OxyContext.coldBoot.test.tsx +13 -12
  46. package/src/ui/context/hooks/useAuthOperations.ts +18 -20
  47. package/src/ui/session/__tests__/createSessionClient.test.ts +3 -1
  48. package/src/ui/session/__tests__/tokenTransport.test.ts +6 -5
  49. package/src/ui/session/authStore.ts +12 -55
  50. package/src/ui/session/createSessionClient.ts +5 -10
  51. package/src/ui/session/tokenTransport.ts +3 -4
@@ -2,6 +2,7 @@ import type React from 'react';
2
2
  import { type ReactNode } from 'react';
3
3
  import { OxyServices } from '@oxyhq/core';
4
4
  import type { User, ApiError, SessionLoginResponse, AccountNode, CreateAccountInput, ClientSession, AccountDialogController, AccountDialogView } from '@oxyhq/core';
5
+ import type { SecurityAlert } from '@oxyhq/contracts';
5
6
  import type { UseFollowHook } from '../hooks/useFollow.types.js';
6
7
  import { useLanguageManagement } from '../hooks/useLanguageManagement.js';
7
8
  import type { RouteName } from '../navigation/routes.js';
@@ -40,7 +41,7 @@ export interface OxyContextState {
40
41
  *
41
42
  * Commits a successful session into context state through the SAME path the
42
43
  * QR device-flow and cold boot use (so `isAuthenticated` / `user` update and
43
- * the rotating refresh family is persisted). Returns a discriminated result
44
+ * the zero-cookie device credential is persisted). Returns a discriminated result
44
45
  * so the caller can branch on the two-factor-required case — which creates NO
45
46
  * session; the caller completes the 2FA challenge with the returned
46
47
  * `loginToken` via {@link OxyContextState.completeTwoFactorSignIn}.
@@ -52,18 +53,22 @@ export interface OxyContextState {
52
53
  /**
53
54
  * Complete a 2FA-gated password sign-in started by {@link signInWithPassword}.
54
55
  * Presents the short-lived `loginToken` with a TOTP `token` or a `backupCode`;
55
- * on success the session is committed exactly like a one-step sign-in.
56
+ * on success the session is committed exactly like a one-step sign-in. Returns
57
+ * any `securityAlert` the server attached so the caller can show the same
58
+ * "New sign-in detected" acknowledgement as the one-step path.
56
59
  */
57
60
  completeTwoFactorSignIn: (params: {
58
61
  loginToken: string;
59
62
  token?: string;
60
63
  backupCode?: string;
61
64
  deviceName?: string;
62
- }) => Promise<void>;
65
+ }) => Promise<{
66
+ securityAlert?: SecurityAlert;
67
+ }>;
63
68
  /**
64
69
  * Commit a session obtained out-of-band (the "Sign in with Oxy" QR device
65
- * flow). Plants tokens, persists the rotating refresh family, registers the
66
- * account into the device set, and hydrates the full user profile.
70
+ * flow). Plants tokens, persists the zero-cookie device credential, registers
71
+ * the account into the device set, and hydrates the full user profile.
67
72
  */
68
73
  handleWebSession: (session: SessionLoginResponse) => Promise<void>;
69
74
  logout: (targetSessionId?: string) => Promise<void>;
@@ -134,7 +139,10 @@ export interface OxyContextState {
134
139
  * Result of {@link OxyContextState.signInWithPassword}.
135
140
  *
136
141
  * `'ok'` — the password was accepted and the session committed (so
137
- * `isAuthenticated` / `user` are updated and the refresh family persisted).
142
+ * `isAuthenticated` / `user` are updated and the device credential persisted).
143
+ * `securityAlert` is present when the server flagged this sign-in as anomalous
144
+ * (new device / location) — the caller shows a "New sign-in detected"
145
+ * acknowledgement before proceeding; the session is already committed.
138
146
  *
139
147
  * `'2fa_required'` — the account has two-factor auth enabled, so NO session was
140
148
  * created. Complete the challenge with the returned short-lived `loginToken`
@@ -142,6 +150,7 @@ export interface OxyContextState {
142
150
  */
143
151
  export type PasswordSignInResult = {
144
152
  status: 'ok';
153
+ securityAlert?: SecurityAlert;
145
154
  } | {
146
155
  status: '2fa_required';
147
156
  loginToken: string;
@@ -1 +1 @@
1
- {"version":3,"file":"OxyContext.d.ts","sourceRoot":"","sources":["../../../../../src/ui/context/OxyContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAE,WAAW,EAAa,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EACV,IAAI,EACJ,QAAQ,EACR,oBAAoB,EACpB,WAAW,EACX,kBAAkB,EAClB,aAAa,EAGb,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAerB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA0B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAgC,CAAC;AAKvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAsB,CAAC;AAgBtD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mBAAmB,EAAE,OAAO,CAAC;IAC7B;;;;;;;;;OASG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,uBAAuB,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,UAAU,CAAC,CAAC;IAC9E,mBAAmB,EAAE,MAAM,CAAC;IAC5B,yBAAyB,EAAE,MAAM,CAAC;IAGlC,WAAW,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAG3C,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAElE;;;;;;;;;OASG;IACH,kBAAkB,EAAE,CAClB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,KACvD,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAEnC;;;;OAIG;IACH,uBAAuB,EAAE,CAAC,MAAM,EAAE;QAChC,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpB;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAGnE,MAAM,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,iBAAiB,EAAE,MAAM,OAAO,CAC9B,KAAK,CAAC;QACJ,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CACH,CAAC;IACF,uBAAuB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,mBAAmB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;;;OAQG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,eAAe,CAAC,EAAE,CAAC,cAAc,EAAE,SAAS,GAAG;QAAE,MAAM,EAAE,SAAS,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/G,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAK7B,sFAAsF;IACtF,uBAAuB,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACxD,iEAAiE;IACjE,mBAAmB,EAAE,OAAO,CAAC;IAC7B;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,IAAI,CAAC,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,gFAAgF;IAChF,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAS/B,0GAA0G;IAC1G,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB;;;;;;;;;;OAUG;IACH,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,aAAa,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CACnE;AAID;;;;;;;;;GASG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,MAAM,EAAE,IAAI,CAAA;CAAE,GAChB;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,SAAS,CAAC;IACpB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;CACrC;AA4FD,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA49BzD,CAAC;AAEF,eAAO,MAAM,kBAAkB,mCAAc,CAAC;AA8D9C,eAAO,MAAM,MAAM,QAAO,eAMzB,CAAC"}
1
+ {"version":3,"file":"OxyContext.d.ts","sourceRoot":"","sources":["../../../../../src/ui/context/OxyContext.tsx"],"names":[],"mappings":"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"}
@@ -9,10 +9,9 @@ export interface UseAuthOperationsOptions {
9
9
  /**
10
10
  * The device-first persisted auth-state store. On EXPLICIT full sign-out the
11
11
  * session blob is cleared (`store.clear()`) so a reload's cold boot finds no
12
- * refresh family to restore; on sign-in a returned rotating refresh token is
13
- * persisted so the next boot warm-restores without a redirect. The long-lived
14
- * device token SURVIVES sign-out (the device is unchanged), so it is never
15
- * cleared here.
12
+ * device credential to restore; on sign-in the returned zero-cookie device
13
+ * credential (`deviceId` + `deviceSecret`) is persisted so the next boot
14
+ * warm-restores without a redirect.
16
15
  */
17
16
  store: AuthStateStore;
18
17
  activeSessionId: string | null;
@@ -51,7 +50,7 @@ export interface UseAuthOperationsResult {
51
50
  logoutAll: () => Promise<void>;
52
51
  }
53
52
  /**
54
- * Clear the persisted refresh-token family on an explicit full sign-out.
53
+ * Clear the persisted device credential on an explicit full sign-out.
55
54
  * Best-effort and non-blocking: sign-out must never fail because a storage
56
55
  * write threw. Exported so `OxyContext`'s zero-account branch (a REMOTE full
57
56
  * sign-out pushed over the socket) runs the EXACT same cleanup as the local
@@ -1 +1 @@
1
- {"version":3,"file":"useAuthOperations.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/context/hooks/useAuthOperations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,aAAa,CAAC;AAIvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC;;;;;;;OAOG;IACH,KAAK,EAAE,cAAc,CAAC;IACtB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,cAAc,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IACnF,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,0JAA0J;IAC1J,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD;;;;;OAKG;IACH,aAAa,EAAE,aAAa,CAAC;IAC7B,+MAA+M;IAC/M,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,uBAAuB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC;IAClD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACrD;AAED,MAAM,WAAW,uBAAuB;IACtC,uCAAuC;IACvC,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,kCAAkC;IAClC,MAAM,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,+BAA+B;IAC/B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC;AAMD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,EACrB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,GAClD,IAAI,CAIN;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,wRAmB/B,wBAAwB,KAAG,uBAsR7B,CAAC"}
1
+ {"version":3,"file":"useAuthOperations.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/context/hooks/useAuthOperations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,aAAa,CAAC;AAIvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC;;;;;;OAMG;IACH,KAAK,EAAE,cAAc,CAAC;IACtB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,cAAc,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IACnF,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,0JAA0J;IAC1J,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD;;;;;OAKG;IACH,aAAa,EAAE,aAAa,CAAC;IAC7B,+MAA+M;IAC/M,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,uBAAuB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC;IAClD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACrD;AAED,MAAM,WAAW,uBAAuB;IACtC,uCAAuC;IACvC,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,kCAAkC;IAClC,MAAM,EAAE,CAAC,eAAe,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,+BAA+B;IAC/B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC;AAMD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,EACrB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,GAClD,IAAI,CAIN;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,wRAmB/B,wBAAwB,KAAG,uBAqR7B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useAccountMutations.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/hooks/mutations/useAccountMutations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useAccountMutations.d.ts","sourceRoot":"","sources":["../../../../../../src/ui/hooks/mutations/useAccountMutations.ts"],"names":[],"mappings":"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"}
@@ -1,18 +1,16 @@
1
1
  /**
2
2
  * Platform `AuthStateStore` for `@oxyhq/services`.
3
3
  *
4
- * The device-first session model persists the rotating refresh-token family
5
- * head per origin (web) / per device (native). `@oxyhq/core` owns the store
6
- * shape + logic (`createWebAuthStateStore` / `createNativeAuthStateStore`); this
7
- * module only supplies the platform storage seam and wires the native device
8
- * token to the SHARED keychain so every native Oxy app joins one DeviceSession:
4
+ * The zero-cookie device model persists the durable device credential
5
+ * (`deviceId` + `deviceSecret`) per origin (web) / per device (native), and the
6
+ * SDK re-mints the access token from that credential on cold boot. `@oxyhq/core`
7
+ * owns the store shape + logic (`createWebAuthStateStore` /
8
+ * `createNativeAuthStateStore`); this module only supplies the platform storage
9
+ * seam:
9
10
  *
10
11
  * - web → `createWebAuthStateStore()` (localStorage, in-memory fallback).
11
- * - native → `createNativeAuthStateStore(secureKV)` for the SESSION blob
12
- * (refresh token) over `expo-secure-store` (AsyncStorage fallback), with the
13
- * long-lived DEVICE token delegated to `KeyManager`'s shared keychain
14
- * (`group.so.oxy.shared`) instead of per-app storage — so an in-app login on
15
- * any native Oxy app attributes to the SAME server-side DeviceSession.
12
+ * - native → `createNativeAuthStateStore(secureKV)` for the SESSION blob over
13
+ * `expo-secure-store` (AsyncStorage fallback).
16
14
  *
17
15
  * `expo-secure-store` is loaded via a runtime-computed dynamic import (the same
18
16
  * optional-native-module pattern `OxyProvider` uses for netinfo / keyboard
@@ -23,11 +21,9 @@ import { type AuthStateStore } from '@oxyhq/core';
23
21
  /**
24
22
  * Build the platform {@link AuthStateStore} for this runtime.
25
23
  *
26
- * Native additionally routes the device token through the shared keychain so
27
- * every native Oxy app shares one server-side DeviceSession; the session blob
28
- * (refresh token) stays per-app in SecureStore. Best-effort keychain access —
29
- * a locked/failed shared-keychain read degrades to "no device token" rather
30
- * than throwing out of cold boot / refresh.
24
+ * Native persists the SESSION blob (`deviceId` + `deviceSecret` + cached access
25
+ * token) per-app in SecureStore; the SDK re-mints the access token from the
26
+ * device credential on the next cold boot.
31
27
  */
32
28
  export declare function createPlatformAuthStateStore(): AuthStateStore;
33
29
  //# sourceMappingURL=authStore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"authStore.d.ts","sourceRoot":"","sources":["../../../../../src/ui/session/authStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAIL,KAAK,cAAc,EAGpB,MAAM,aAAa,CAAC;AAmFrB;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,IAAI,cAAc,CA2C7D"}
1
+ {"version":3,"file":"authStore.d.ts","sourceRoot":"","sources":["../../../../../src/ui/session/authStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAGL,KAAK,cAAc,EAEpB,MAAM,aAAa,CAAC;AAmFrB;;;;;;GAMG;AACH,wBAAgB,4BAA4B,IAAI,cAAc,CAM7D"}
@@ -1,4 +1,4 @@
1
- import { SessionClient, createSessionClientHost, type AuthStateStore, type OxyServices, type SessionClientOptions } from '@oxyhq/core';
1
+ import { SessionClient, createSessionClientHost, type AuthStateStore, type OxyServices } from '@oxyhq/core';
2
2
  /**
3
3
  * Wire a `SessionClient` for `@oxyhq/services`.
4
4
  *
@@ -11,22 +11,18 @@ import { SessionClient, createSessionClientHost, type AuthStateStore, type OxySe
11
11
  * core's lazy dynamic import of a bare specifier — bundler-fragile in
12
12
  * Metro/Expo-web against the published core dist.
13
13
  * - the device-first {@link createTokenTransport}, which mints a fallback token
14
- * by rotating the persisted refresh family (`store`).
14
+ * from the persisted device credential (`store` → `deviceId` + `deviceSecret`).
15
15
  *
16
16
  * `onUnauthenticated` fires when an applied device state has zero accounts (a
17
17
  * device signout-all): the provider clears the persisted store + local state so
18
18
  * a reload does not try to restore a dead session. The host is returned
19
19
  * alongside the client so the caller can call `host.setCurrentAccountId(...)`
20
20
  * as the active account changes.
21
+ *
22
+ * The realtime socket is bearer-only: a signed-out tab cannot join any device
23
+ * room, so there is no signed-out socket wiring.
21
24
  */
22
- export declare function createSessionClient(oxyServices: OxyServices, store: AuthStateStore, onUnauthenticated?: () => void,
23
- /**
24
- * Optional signed-out realtime wiring: `signedOutSocketAuth` (open the socket
25
- * while signed out — web returns `true` to ride the `oxy_device` cookie,
26
- * native returns the shared device token) and `onSessionAppeared` (self-acquire
27
- * when a sibling signs in on this device).
28
- */
29
- extra?: Pick<SessionClientOptions, 'signedOutSocketAuth' | 'onSessionAppeared'>): {
25
+ export declare function createSessionClient(oxyServices: OxyServices, store: AuthStateStore, onUnauthenticated?: () => void): {
30
26
  client: SessionClient;
31
27
  host: ReturnType<typeof createSessionClientHost>;
32
28
  };
@@ -1 +1 @@
1
- {"version":3,"file":"createSessionClient.d.ts","sourceRoot":"","sources":["../../../../../src/ui/session/createSessionClient.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,oBAAoB,EAC1B,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,cAAc,EACrB,iBAAiB,CAAC,EAAE,MAAM,IAAI;AAC9B;;;;;GAKG;AACH,KAAK,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,qBAAqB,GAAG,mBAAmB,CAAC,GAC9E;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;CAClD,CAKA"}
1
+ {"version":3,"file":"createSessionClient.d.ts","sourceRoot":"","sources":["../../../../../src/ui/session/createSessionClient.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,uBAAuB,EACvB,KAAK,cAAc,EACnB,KAAK,WAAW,EACjB,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,cAAc,EACrB,iBAAiB,CAAC,EAAE,MAAM,IAAI,GAC7B;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;CAClD,CAKA"}
@@ -5,10 +5,9 @@ import { type AuthStateStore, type OxyServices, type TokenTransport } from '@oxy
5
5
  * `ensureActiveToken` is the fallback the client uses when a `session_state`
6
6
  * push arrived WITHOUT an embedded `activeToken` and the app currently holds no
7
7
  * bearer. It mints one through the ONE unified refresh path
8
- * (`refreshPersistedSession`): rotate the persisted refresh-token family
9
- * (`POST /auth/refresh-token`) and, on native, fall back to the shared-keychain
10
- * re-mint. There is no FedCM/silent-iframe arm anymore — the per-origin
11
- * persisted refresh token is the durable web credential.
8
+ * (`refreshPersistedSession`), which presents the persisted zero-cookie device
9
+ * credential (`deviceId` + `deviceSecret`) at `POST /session/device/token`. The
10
+ * persisted device credential is the sole durable restore credential.
12
11
  *
13
12
  * Concurrent pushes coalesce onto one in-flight mint. A failure is logged and
14
13
  * swallowed: this method must never throw out (it runs inside the socket state
@@ -1 +1 @@
1
- {"version":3,"file":"tokenTransport.d.ts","sourceRoot":"","sources":["../../../../../src/ui/session/tokenTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,cAAc,GACpB,cAAc,CAsChB"}
1
+ {"version":3,"file":"tokenTransport.d.ts","sourceRoot":"","sources":["../../../../../src/ui/session/tokenTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,cAAc,EACpB,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,cAAc,GACpB,cAAc,CAsChB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/services",
3
- "version": "18.0.0",
3
+ "version": "19.0.0",
4
4
  "description": "OxyHQ Expo/React Native SDK — UI components, screens, and native features",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -106,10 +106,10 @@
106
106
  }
107
107
  },
108
108
  "dependencies": {
109
- "@oxyhq/contracts": "0.11.0"
109
+ "@oxyhq/contracts": "0.13.0"
110
110
  },
111
111
  "devDependencies": {
112
- "@oxyhq/core": "8.0.0",
112
+ "@oxyhq/core": "9.0.0",
113
113
  "nativewind": "5.0.0-preview.3",
114
114
  "react-native-css": "^3.0.0",
115
115
  "@react-native-async-storage/async-storage": "^2.0.0",
@@ -153,7 +153,7 @@
153
153
  "peerDependencies": {
154
154
  "@expo/vector-icons": "^15.0.3",
155
155
  "@oxyhq/bloom": ">=0.16.0",
156
- "@oxyhq/core": "^8.0.0",
156
+ "@oxyhq/core": "^9.0.0",
157
157
  "@react-native-async-storage/async-storage": "^2.0.0",
158
158
  "@react-native-community/netinfo": "^11.4.1",
159
159
  "@tanstack/query-async-storage-persister": "^5.101",
@@ -31,6 +31,7 @@ import {
31
31
  createAccountDialogController,
32
32
  logger as loggerUtil,
33
33
  } from '@oxyhq/core';
34
+ import type { SecurityAlert } from '@oxyhq/contracts';
34
35
  import {
35
36
  registerAccountDialogControls,
36
37
  notifyAccountDialogVisibility,
@@ -99,7 +100,7 @@ export interface OxyContextState {
99
100
  *
100
101
  * Commits a successful session into context state through the SAME path the
101
102
  * QR device-flow and cold boot use (so `isAuthenticated` / `user` update and
102
- * the rotating refresh family is persisted). Returns a discriminated result
103
+ * the zero-cookie device credential is persisted). Returns a discriminated result
103
104
  * so the caller can branch on the two-factor-required case — which creates NO
104
105
  * session; the caller completes the 2FA challenge with the returned
105
106
  * `loginToken` via {@link OxyContextState.completeTwoFactorSignIn}.
@@ -113,19 +114,21 @@ export interface OxyContextState {
113
114
  /**
114
115
  * Complete a 2FA-gated password sign-in started by {@link signInWithPassword}.
115
116
  * Presents the short-lived `loginToken` with a TOTP `token` or a `backupCode`;
116
- * on success the session is committed exactly like a one-step sign-in.
117
+ * on success the session is committed exactly like a one-step sign-in. Returns
118
+ * any `securityAlert` the server attached so the caller can show the same
119
+ * "New sign-in detected" acknowledgement as the one-step path.
117
120
  */
118
121
  completeTwoFactorSignIn: (params: {
119
122
  loginToken: string;
120
123
  token?: string;
121
124
  backupCode?: string;
122
125
  deviceName?: string;
123
- }) => Promise<void>;
126
+ }) => Promise<{ securityAlert?: SecurityAlert }>;
124
127
 
125
128
  /**
126
129
  * Commit a session obtained out-of-band (the "Sign in with Oxy" QR device
127
- * flow). Plants tokens, persists the rotating refresh family, registers the
128
- * account into the device set, and hydrates the full user profile.
130
+ * flow). Plants tokens, persists the zero-cookie device credential, registers
131
+ * the account into the device set, and hydrates the full user profile.
129
132
  */
130
133
  handleWebSession: (session: SessionLoginResponse) => Promise<void>;
131
134
 
@@ -212,14 +215,17 @@ const OxyContext = createContext<OxyContextState | null>(null);
212
215
  * Result of {@link OxyContextState.signInWithPassword}.
213
216
  *
214
217
  * `'ok'` — the password was accepted and the session committed (so
215
- * `isAuthenticated` / `user` are updated and the refresh family persisted).
218
+ * `isAuthenticated` / `user` are updated and the device credential persisted).
219
+ * `securityAlert` is present when the server flagged this sign-in as anomalous
220
+ * (new device / location) — the caller shows a "New sign-in detected"
221
+ * acknowledgement before proceeding; the session is already committed.
216
222
  *
217
223
  * `'2fa_required'` — the account has two-factor auth enabled, so NO session was
218
224
  * created. Complete the challenge with the returned short-lived `loginToken`
219
225
  * via {@link OxyContextState.completeTwoFactorSignIn}.
220
226
  */
221
227
  export type PasswordSignInResult =
222
- | { status: 'ok' }
228
+ | { status: 'ok'; securityAlert?: SecurityAlert }
223
229
  | { status: '2fa_required'; loginToken: string };
224
230
 
225
231
  export interface OxyContextProviderProps {
@@ -272,14 +278,16 @@ const DEFAULT_SESSION_VALIDITY_MS = 7 * 24 * 60 * 60 * 1000;
272
278
  */
273
279
  const SESSION_HANDOFF_DEADLINE = 6000;
274
280
 
275
- /** The internal commit input — a session plus the device-first extras that are
276
- * not on the public `SessionLoginResponse` (a rotating refresh token, a device
277
- * token). All extras optional so `SessionLoginResponse` is assignable. */
281
+ /** The internal commit input — a session plus the zero-cookie device credential
282
+ * (`deviceId` + `deviceSecret`) that is not on the public `SessionLoginResponse`.
283
+ * All extras optional so `SessionLoginResponse` is assignable. */
278
284
  interface CommitInput {
279
285
  sessionId: string;
280
286
  accessToken?: string;
281
- refreshToken?: string;
282
287
  deviceId?: string;
288
+ /** Rotating device secret (zero-cookie transport); persisted with `deviceId`
289
+ * so the cold boot can mint via `POST /session/device/token`. */
290
+ deviceSecret?: string;
283
291
  expiresAt?: string;
284
292
  userId?: string;
285
293
  /** Minimal user carried by the sign-in response; a best-effort fallback used
@@ -368,9 +376,9 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
368
376
  }
369
377
  const oxyServices = oxyServicesRef.current;
370
378
 
371
- // The device-first persisted auth-state store (per-origin refresh family on
372
- // web; SecureStore session blob + shared-keychain device token on native).
373
- // Built ONCE per provider mount.
379
+ // The device-first persisted auth-state store (per-origin zero-cookie device
380
+ // credential on web; SecureStore session blob on native). Built ONCE per
381
+ // provider mount.
374
382
  const authStoreRef = useRef<AuthStateStore | null>(null);
375
383
  if (!authStoreRef.current) {
376
384
  authStoreRef.current = createPlatformAuthStateStore();
@@ -545,19 +553,13 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
545
553
  const markAuthResolvedRef = useRef(markAuthResolved);
546
554
  markAuthResolvedRef.current = markAuthResolved;
547
555
 
548
- // Re-boot indirection: the SessionClient is built in the ref initializer below
549
- // (before `runColdBoot` is defined), but its `onSessionAppeared` must re-run the
550
- // cold boot to self-acquire when a sibling signs in on this device. A ref bridges
551
- // the ordering; it is assigned right after `runColdBoot` is declared.
552
- const runColdBootRef = useRef<(() => Promise<void>) | null>(null);
553
-
554
556
  // Server-authoritative device session client. Built ONCE per `oxyServices`
555
- // instance. `onUnauthenticated` (a device signout-all pushed over the socket,
556
- // or bootstrapped as zero-account) clears the persisted store + local state so
557
- // a reload does not try to restore a session the device no longer has.
558
- // `signedOutSocketAuth` + `onSessionAppeared` power the signed-out sync channel:
559
- // an idle tab joins its `device:<id>` room (web via the `oxy_device` cookie,
560
- // native via the shared device token) and self-acquires on a sibling sign-in.
557
+ // instance. `onUnauthenticated` (a device signout-all pushed over the
558
+ // bearer-authenticated socket, or bootstrapped as zero-account) clears the
559
+ // persisted store + local state so a reload does not try to restore a session
560
+ // the device no longer has. The realtime socket is bearer-only now: a
561
+ // signed-out tab cannot join any device room, so there is no signed-out sync
562
+ // wiring here.
561
563
  const sessionClientPairRef = useRef<ReturnType<typeof createSessionClient> | null>(null);
562
564
  if (!sessionClientPairRef.current) {
563
565
  sessionClientPairRef.current = createSessionClient(
@@ -569,22 +571,6 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
569
571
  logger('Failed to clear local state on remote sign-out', clearError);
570
572
  });
571
573
  },
572
- {
573
- signedOutSocketAuth: async () => {
574
- // Web (`*.oxy.so`): the first-party `oxy_device` cookie rides the
575
- // same-site handshake automatically — just connect.
576
- if (isWebBrowser()) return true;
577
- // Native (no cookie jar): present the shared device token if we have one.
578
- try {
579
- return (await authStore.loadDeviceToken()) ?? false;
580
- } catch {
581
- return false;
582
- }
583
- },
584
- onSessionAppeared: () => {
585
- void runColdBootRef.current?.();
586
- },
587
- },
588
574
  );
589
575
  }
590
576
  const { client: sessionClient, host: sessionClientHost } = sessionClientPairRef.current;
@@ -678,7 +664,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
678
664
  }
679
665
  }
680
666
  await clearSessionState();
681
- // Explicit FULL wipe: also drop the persisted refresh family so a reload
667
+ // Explicit FULL wipe: also drop the persisted device credential so a reload
682
668
  // finds nothing to restore.
683
669
  await authStore.clear();
684
670
  useAccountStore.getState().reset();
@@ -736,10 +722,10 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
736
722
  }, [logger, oxyServices]);
737
723
 
738
724
  // Unified in-session refresh (SDK-owned; every RP inherits it). Installs the
739
- // ONE core refresh handler (rotate the persisted refresh family; native falls
740
- // back to the shared keychain) plus the proactive scheduler that refreshes
741
- // ~60s before expiry and on tab-focus. Replaces the deleted services-local
742
- // `inSessionTokenRefresh` module.
725
+ // ONE core refresh handler (re-mint from the persisted zero-cookie device
726
+ // credential via `POST /session/device/token`) plus the proactive scheduler
727
+ // that refreshes ~60s before expiry and on tab-focus. Replaces the deleted
728
+ // services-local `inSessionTokenRefresh` module.
743
729
  useEffect(() => {
744
730
  const dispose = installAuthRefreshHandler({ oxy: oxyServices, store: authStore });
745
731
  const scheduler = startTokenRefreshScheduler(oxyServices);
@@ -751,27 +737,27 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
751
737
 
752
738
  // ── Session commit funnel ────────────────────────────────────────────────
753
739
  // The single place a session becomes committed: plant tokens, persist the
754
- // rotating refresh family, register the account into the server-authoritative
755
- // device set, and hydrate the full user. Used by the QR device flow
756
- // (`handleWebSession`), password sign-in, 2FA completion, and the cold boot.
740
+ // zero-cookie device credential (`deviceId` + `deviceSecret`), register the
741
+ // account into the server-authoritative device set, and hydrate the full user.
742
+ // Used by the QR device flow (`handleWebSession`), password sign-in, 2FA
743
+ // completion, and the cold boot.
757
744
  const commitSession = useCallback(
758
745
  async (input: CommitInput, options: { activate: boolean }): Promise<void> => {
759
746
  if (input.accessToken) {
760
747
  oxyServices.setTokens(input.accessToken);
761
748
  }
762
749
 
763
- // Persist the durable blob when a rotating refresh token is present
764
- // (trusted-lane sign-ins). The cold boot has usually persisted already;
765
- // this is idempotent. A missing refresh token means the session survives
766
- // reload via the device cookie (web) / shared keychain (native) instead.
767
- if (input.refreshToken && input.userId) {
750
+ // Persist the durable blob when the zero-cookie device credential
751
+ // (`deviceId` + `deviceSecret`) is present. The cold boot has usually
752
+ // persisted already; this is idempotent. Without the credential there is
753
+ // nothing durable to persist and the session lives only for this runtime.
754
+ if (input.deviceId && input.deviceSecret && input.userId) {
768
755
  try {
769
- const deviceToken = (await authStore.loadDeviceToken()) ?? undefined;
770
756
  const next: PersistedAuthState = {
771
757
  sessionId: input.sessionId,
772
- refreshToken: input.refreshToken,
773
758
  userId: input.userId,
774
- ...(deviceToken ? { deviceToken } : {}),
759
+ deviceId: input.deviceId,
760
+ deviceSecret: input.deviceSecret,
775
761
  ...(input.accessToken ? { accessToken: input.accessToken } : {}),
776
762
  ...(input.expiresAt ? { expiresAt: input.expiresAt } : {}),
777
763
  };
@@ -859,9 +845,9 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
859
845
  {
860
846
  sessionId: session.sessionId,
861
847
  accessToken: session.accessToken,
862
- // deviceFlow threads a rotating refresh token on the runtime object
848
+ // deviceFlow threads the rotating deviceSecret on the runtime object
863
849
  // even though `SessionLoginResponse` does not type it.
864
- refreshToken: (session as { refreshToken?: string }).refreshToken,
850
+ deviceSecret: (session as { deviceSecret?: string }).deviceSecret,
865
851
  deviceId: session.deviceId,
866
852
  expiresAt: session.expiresAt,
867
853
  userId: session.user.id,
@@ -935,9 +921,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
935
921
  password: string,
936
922
  opts?: { deviceName?: string; deviceFingerprint?: string },
937
923
  ): Promise<PasswordSignInResult> => {
938
- const deviceToken = (await authStore.loadDeviceToken()) ?? undefined;
939
924
  const result = await oxyServices.passwordSignIn(identifier, password, {
940
- deviceToken,
941
925
  deviceName: opts?.deviceName,
942
926
  deviceFingerprint: opts?.deviceFingerprint,
943
927
  });
@@ -949,7 +933,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
949
933
  {
950
934
  sessionId: result.sessionId,
951
935
  accessToken: result.accessToken,
952
- refreshToken: result.refreshToken,
936
+ deviceSecret: result.deviceSecret,
953
937
  deviceId: result.deviceId,
954
938
  expiresAt: result.expiresAt,
955
939
  userId: result.user.id,
@@ -957,9 +941,9 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
957
941
  },
958
942
  { activate: true },
959
943
  );
960
- return { status: 'ok' };
944
+ return { status: 'ok', ...(result.securityAlert ? { securityAlert: result.securityAlert } : {}) };
961
945
  },
962
- [oxyServices, authStore, commitSession],
946
+ [oxyServices, commitSession],
963
947
  );
964
948
 
965
949
  const completeTwoFactorSignIn = useCallback(
@@ -968,20 +952,18 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
968
952
  token?: string;
969
953
  backupCode?: string;
970
954
  deviceName?: string;
971
- }): Promise<void> => {
972
- const deviceToken = (await authStore.loadDeviceToken()) ?? undefined;
955
+ }): Promise<{ securityAlert?: SecurityAlert }> => {
973
956
  const result = await oxyServices.completeTwoFactorSignIn({
974
957
  loginToken: params.loginToken,
975
958
  token: params.token,
976
959
  backupCode: params.backupCode,
977
- deviceToken,
978
960
  deviceName: params.deviceName,
979
961
  });
980
962
  await commitSession(
981
963
  {
982
964
  sessionId: result.sessionId,
983
965
  accessToken: result.accessToken,
984
- refreshToken: result.refreshToken,
966
+ deviceSecret: result.deviceSecret,
985
967
  deviceId: result.deviceId,
986
968
  expiresAt: result.expiresAt,
987
969
  userId: result.user.id,
@@ -989,8 +971,9 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
989
971
  },
990
972
  { activate: true },
991
973
  );
974
+ return { securityAlert: result.securityAlert };
992
975
  },
993
- [oxyServices, authStore, commitSession],
976
+ [oxyServices, commitSession],
994
977
  );
995
978
 
996
979
  // ── Cold boot ────────────────────────────────────────────────────────────
@@ -1031,19 +1014,9 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
1031
1014
  markAuthResolvedRef.current();
1032
1015
  },
1033
1016
  onSignedOut: () => {
1017
+ // The realtime socket is bearer-only: a signed-out tab cannot join any
1018
+ // device room, so there is no signed-out socket to start here.
1034
1019
  markAuthResolvedRef.current();
1035
- // Open the signed-out realtime channel so this idle tab joins its
1036
- // `device:<id>` room (web `oxy_device` cookie / native device token)
1037
- // and self-acquires when a sibling signs in. Idempotent, best-effort.
1038
- void sessionClient.start().catch((startError) => {
1039
- if (__DEV__) {
1040
- loggerUtil.debug(
1041
- 'signed-out socket start failed (non-fatal)',
1042
- { component: 'OxyContext', method: 'runColdBoot' },
1043
- startError as unknown,
1044
- );
1045
- }
1046
- });
1047
1020
  },
1048
1021
  onStepError: (id, error) => {
1049
1022
  if (__DEV__) {
@@ -1067,20 +1040,16 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
1067
1040
  // Backstop: resolve on every exit path so the gate can never hang.
1068
1041
  markAuthResolvedRef.current();
1069
1042
  }
1070
- }, [oxyServices, authStore, sessionClient]);
1071
- // Bridge for `onSessionAppeared` (SessionClient) → re-run the cold boot to
1072
- // self-acquire when a sibling signs in on this device while this tab is idle.
1073
- runColdBootRef.current = runColdBoot;
1043
+ }, [oxyServices, authStore]);
1074
1044
 
1075
1045
  useEffect(() => {
1076
1046
  if (initialized) {
1077
1047
  return;
1078
1048
  }
1079
1049
  // IdP mode (`coldBoot={false}`): this provider is NOT the ecosystem session
1080
- // authority, so it never runs the device-first restore and never opens the
1081
- // signed-out device-state socket (`runColdBoot` `onSignedOut` is the sole
1082
- // place that socket starts). Resolve auth immediately as signed out so there
1083
- // is no boot spinner; a deliberate sign-in still commits a normal session.
1050
+ // authority, so it never runs the device-first restore. Resolve auth
1051
+ // immediately as signed out so there is no boot spinner; a deliberate sign-in
1052
+ // still commits a normal session.
1084
1053
  if (!coldBoot) {
1085
1054
  setInitialized(true);
1086
1055
  markAuthResolved();
@@ -1204,7 +1173,7 @@ export const OxyProvider: React.FC<OxyContextProviderProps> = ({
1204
1173
  {
1205
1174
  sessionId: result.sessionId,
1206
1175
  accessToken: result.accessToken,
1207
- refreshToken: (result as { refreshToken?: string }).refreshToken,
1176
+ deviceSecret: (result as { deviceSecret?: string }).deviceSecret,
1208
1177
  deviceId: result.deviceId,
1209
1178
  expiresAt: result.expiresAt,
1210
1179
  userId: result.user.id,
@@ -1367,7 +1336,7 @@ const LOADING_STATE: OxyContextState = {
1367
1336
  getPublicKey: () => Promise.resolve(null),
1368
1337
  signIn: () => rejectMissingProvider<User>(),
1369
1338
  signInWithPassword: () => rejectMissingProvider<PasswordSignInResult>(),
1370
- completeTwoFactorSignIn: () => rejectMissingProvider<void>(),
1339
+ completeTwoFactorSignIn: () => rejectMissingProvider<{ securityAlert?: SecurityAlert }>(),
1371
1340
  handleWebSession: () => rejectMissingProvider<void>(),
1372
1341
  logout: () => rejectMissingProvider<void>(),
1373
1342
  logoutAll: () => rejectMissingProvider<void>(),