@oxyhq/core 5.1.1 → 5.2.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 (56) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/AuthManager.js +27 -5
  3. package/dist/cjs/OxyServices.base.js +71 -0
  4. package/dist/cjs/index.js +3 -1
  5. package/dist/cjs/mixins/OxyServices.accounts.js +10 -25
  6. package/dist/cjs/mixins/OxyServices.assets.js +76 -0
  7. package/dist/cjs/utils/ssoBounce.js +59 -0
  8. package/dist/esm/.tsbuildinfo +1 -1
  9. package/dist/esm/AuthManager.js +27 -5
  10. package/dist/esm/OxyServices.base.js +71 -0
  11. package/dist/esm/index.js +1 -1
  12. package/dist/esm/mixins/OxyServices.accounts.js +10 -25
  13. package/dist/esm/mixins/OxyServices.assets.js +76 -0
  14. package/dist/esm/utils/ssoBounce.js +57 -0
  15. package/dist/types/.tsbuildinfo +1 -1
  16. package/dist/types/OxyServices.base.d.ts +38 -0
  17. package/dist/types/index.d.ts +2 -2
  18. package/dist/types/mixins/OxyServices.accounts.d.ts +1 -0
  19. package/dist/types/mixins/OxyServices.analytics.d.ts +1 -0
  20. package/dist/types/mixins/OxyServices.appData.d.ts +1 -0
  21. package/dist/types/mixins/OxyServices.assets.d.ts +36 -1
  22. package/dist/types/mixins/OxyServices.auth.d.ts +1 -0
  23. package/dist/types/mixins/OxyServices.civic.d.ts +1 -0
  24. package/dist/types/mixins/OxyServices.connectedApps.d.ts +1 -0
  25. package/dist/types/mixins/OxyServices.contacts.d.ts +1 -0
  26. package/dist/types/mixins/OxyServices.devices.d.ts +1 -0
  27. package/dist/types/mixins/OxyServices.features.d.ts +1 -0
  28. package/dist/types/mixins/OxyServices.fedcm.d.ts +1 -0
  29. package/dist/types/mixins/OxyServices.identity.d.ts +1 -0
  30. package/dist/types/mixins/OxyServices.language.d.ts +1 -0
  31. package/dist/types/mixins/OxyServices.links.d.ts +1 -0
  32. package/dist/types/mixins/OxyServices.location.d.ts +1 -0
  33. package/dist/types/mixins/OxyServices.nodes.d.ts +1 -0
  34. package/dist/types/mixins/OxyServices.payment.d.ts +1 -0
  35. package/dist/types/mixins/OxyServices.privacy.d.ts +1 -0
  36. package/dist/types/mixins/OxyServices.redirect.d.ts +1 -0
  37. package/dist/types/mixins/OxyServices.reputation.d.ts +1 -0
  38. package/dist/types/mixins/OxyServices.security.d.ts +1 -0
  39. package/dist/types/mixins/OxyServices.silent.d.ts +1 -0
  40. package/dist/types/mixins/OxyServices.sso.d.ts +1 -0
  41. package/dist/types/mixins/OxyServices.topics.d.ts +1 -0
  42. package/dist/types/mixins/OxyServices.user.d.ts +1 -0
  43. package/dist/types/mixins/OxyServices.utility.d.ts +1 -0
  44. package/dist/types/models/interfaces.d.ts +23 -0
  45. package/dist/types/utils/ssoBounce.d.ts +47 -0
  46. package/package.json +1 -1
  47. package/src/AuthManager.ts +29 -5
  48. package/src/OxyServices.base.ts +79 -0
  49. package/src/__tests__/establishDeviceRefreshSlot.test.ts +221 -0
  50. package/src/index.ts +3 -0
  51. package/src/mixins/OxyServices.accounts.ts +10 -33
  52. package/src/mixins/OxyServices.assets.ts +92 -1
  53. package/src/mixins/__tests__/OxyServices.serviceAssetMetadataBySha.test.ts +135 -0
  54. package/src/models/interfaces.ts +24 -0
  55. package/src/utils/__tests__/ssoBounce.test.ts +41 -0
  56. package/src/utils/ssoBounce.ts +61 -0
@@ -69,6 +69,7 @@ const NO_SESSION_KEY_PREFIX = 'oxy_sso_no_session:';
69
69
  const ATTEMPTED_KEY_PREFIX = 'oxy_sso_attempted:';
70
70
  const CALLBACK_BOOTSTRAP_KEY_PREFIX = 'oxy_sso_callback_bootstrap:';
71
71
  const PRIOR_SESSION_KEY_PREFIX = 'oxy_sso_prior_session:';
72
+ const SIGNED_OUT_KEY_PREFIX = 'oxy_signed_out:';
72
73
 
73
74
  /** Per-origin CSRF state key (matched on return to defeat fragment forgery). */
74
75
  export function ssoStateKey(origin: string): string {
@@ -125,6 +126,37 @@ export function ssoPriorSessionKey(origin: string): string {
125
126
  return `${PRIOR_SESSION_KEY_PREFIX}${origin}`;
126
127
  }
127
128
 
129
+ /**
130
+ * Per-origin DURABLE "the user DELIBERATELY signed out on this device/origin"
131
+ * flag.
132
+ *
133
+ * Like {@link ssoPriorSessionKey} this lives in DURABLE storage (web
134
+ * `localStorage`; services uses its own `storageKeyPrefix`-scoped key), NOT the
135
+ * per-tab `sessionStorage` the loop-breaker keys use — it must survive a reload.
136
+ *
137
+ * It exists purely to suppress AUTOMATIC silent restore after a deliberate
138
+ * sign-out: a still-live IdP session (the central `fedcm_session` / the FedCM
139
+ * credential association) would otherwise let `fedcm-silent` / the per-apex
140
+ * `/auth/silent` iframe re-mint a session on the very next cold boot, so a user
141
+ * who pressed "Sign out" gets silently signed back in on reload. With this flag
142
+ * set, those silent cold-boot steps are skipped while the Gmail-style
143
+ * returning-account fast-path is otherwise preserved.
144
+ *
145
+ * Lifecycle (mirrors the existing gate machinery — set on a definitive event,
146
+ * cleared on its inverse):
147
+ * - SET on EXPLICIT full sign-out (alongside clearing the prior-session hint
148
+ * and the SSO bounce state).
149
+ * - CLEARED on ANY deliberate sign-in (password, FedCM, account switch, device
150
+ * claim) so a real sign-in fully re-enables silent restore — there is no
151
+ * "stuck signed out" state.
152
+ *
153
+ * NOTE: this gates only AUTOMATIC/silent restore. An INTERACTIVE sign-in always
154
+ * clears it first, so the user can always sign back in.
155
+ */
156
+ export function ssoSignedOutKey(origin: string): string {
157
+ return `${SIGNED_OUT_KEY_PREFIX}${origin}`;
158
+ }
159
+
128
160
  /**
129
161
  * Per-origin marker written by the pre-hydration callback bootstrap.
130
162
  *
@@ -267,6 +299,35 @@ export function guardActive(
267
299
  return now - ts < SSO_GUARD_TTL_MS;
268
300
  }
269
301
 
302
+ /**
303
+ * Whether AUTOMATIC silent restore is SUPPRESSED for this origin because the
304
+ * user deliberately signed out (the durable {@link ssoSignedOutKey} flag).
305
+ *
306
+ * When `true`, the silent cold-boot steps that can re-mint a session from a
307
+ * still-live IdP session WITHOUT user intent — `fedcm-silent` and the per-apex
308
+ * `/auth/silent` iframe — MUST be skipped, so a user who pressed "Sign out" is
309
+ * not silently signed back in on the next reload. Interactive sign-in clears the
310
+ * flag, so this never blocks a deliberate re-sign-in.
311
+ *
312
+ * Defensive: a `getItem` that throws (locked/disabled storage) is treated as NOT
313
+ * suppressed, so the gate fails toward the normal restore behaviour rather than
314
+ * wedging the user out.
315
+ *
316
+ * @param storage - The DURABLE storage to read (web `localStorage`; injected for
317
+ * testability).
318
+ * @param origin - The page origin whose signed-out flag to evaluate.
319
+ */
320
+ export function silentRestoreSuppressed(
321
+ storage: Pick<Storage, 'getItem'>,
322
+ origin: string,
323
+ ): boolean {
324
+ try {
325
+ return storage.getItem(ssoSignedOutKey(origin)) === '1';
326
+ } catch {
327
+ return false;
328
+ }
329
+ }
330
+
270
331
  /**
271
332
  * Inputs to the smart {@link allowSsoBounce} gate.
272
333
  */