@oxyhq/core 3.16.1 → 3.17.1

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 (45) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/HttpService.js +8 -1
  3. package/dist/cjs/OxyServices.base.js +25 -0
  4. package/dist/cjs/mixins/OxyServices.links.js +6 -2
  5. package/dist/esm/.tsbuildinfo +1 -1
  6. package/dist/esm/HttpService.js +8 -1
  7. package/dist/esm/OxyServices.base.js +25 -0
  8. package/dist/esm/mixins/OxyServices.links.js +6 -2
  9. package/dist/types/.tsbuildinfo +1 -1
  10. package/dist/types/OxyServices.base.d.ts +11 -0
  11. package/dist/types/index.d.ts +1 -0
  12. package/dist/types/mixins/OxyServices.analytics.d.ts +1 -0
  13. package/dist/types/mixins/OxyServices.appData.d.ts +1 -0
  14. package/dist/types/mixins/OxyServices.applications.d.ts +1 -0
  15. package/dist/types/mixins/OxyServices.assets.d.ts +1 -0
  16. package/dist/types/mixins/OxyServices.auth.d.ts +1 -0
  17. package/dist/types/mixins/OxyServices.civic.d.ts +1 -0
  18. package/dist/types/mixins/OxyServices.contacts.d.ts +1 -0
  19. package/dist/types/mixins/OxyServices.devices.d.ts +1 -0
  20. package/dist/types/mixins/OxyServices.features.d.ts +1 -0
  21. package/dist/types/mixins/OxyServices.fedcm.d.ts +1 -0
  22. package/dist/types/mixins/OxyServices.identity.d.ts +1 -0
  23. package/dist/types/mixins/OxyServices.language.d.ts +1 -0
  24. package/dist/types/mixins/OxyServices.links.d.ts +6 -1
  25. package/dist/types/mixins/OxyServices.location.d.ts +1 -0
  26. package/dist/types/mixins/OxyServices.managedAccounts.d.ts +1 -0
  27. package/dist/types/mixins/OxyServices.nodes.d.ts +1 -0
  28. package/dist/types/mixins/OxyServices.payment.d.ts +1 -0
  29. package/dist/types/mixins/OxyServices.privacy.d.ts +1 -0
  30. package/dist/types/mixins/OxyServices.redirect.d.ts +1 -0
  31. package/dist/types/mixins/OxyServices.reputation.d.ts +1 -0
  32. package/dist/types/mixins/OxyServices.security.d.ts +1 -0
  33. package/dist/types/mixins/OxyServices.silent.d.ts +1 -0
  34. package/dist/types/mixins/OxyServices.sso.d.ts +1 -0
  35. package/dist/types/mixins/OxyServices.topics.d.ts +1 -0
  36. package/dist/types/mixins/OxyServices.user.d.ts +1 -0
  37. package/dist/types/mixins/OxyServices.utility.d.ts +1 -0
  38. package/dist/types/mixins/OxyServices.workspaces.d.ts +1 -0
  39. package/package.json +1 -1
  40. package/src/HttpService.ts +8 -1
  41. package/src/OxyServices.base.ts +25 -0
  42. package/src/__tests__/inSessionRefresh.test.ts +193 -0
  43. package/src/index.ts +4 -0
  44. package/src/mixins/OxyServices.links.ts +8 -4
  45. package/src/mixins/__tests__/OxyServices.links.test.ts +8 -8
@@ -369,7 +369,14 @@ class HttpService {
369
369
  if (response.status === 401 && !config._isAuthRetry) {
370
370
  const refreshed = await this.refreshAccessToken('response-401');
371
371
  if (refreshed) {
372
- return this.request({ ...config, _isAuthRetry: true, retry: false });
372
+ // `deduplicate: false` is REQUIRED on the retry (mirrors the 403
373
+ // CSRF retry below). This re-issue runs while the ORIGINAL request
374
+ // is still in-flight under its dedupe key; the refreshed token is
375
+ // for the SAME user, so the identity-scoped key is UNCHANGED — a
376
+ // deduplicated retry would resolve to the still-pending original
377
+ // and await itself (deadlock). Opting the retry out of dedupe makes
378
+ // it a fresh request.
379
+ return this.request({ ...config, _isAuthRetry: true, retry: false, deduplicate: false });
373
380
  }
374
381
  // Refresh failed or no token — clear tokens and stale CSRF
375
382
  this.tokenStore.clearTokens();
@@ -253,6 +253,31 @@ class OxyServicesBase {
253
253
  getAccessToken() {
254
254
  return this.httpService.getAccessToken();
255
255
  }
256
+ /**
257
+ * Decode the current access token and return its `exp` claim in SECONDS since
258
+ * the Unix epoch (the raw JWT `exp` unit), or `null` when there is no token,
259
+ * the token is opaque/undecodable, or it carries no numeric `exp`.
260
+ *
261
+ * Exposed so `@oxyhq/services` can schedule a PROACTIVE in-session refresh a
262
+ * fixed lead before expiry without re-importing a JWT decoder (and without
263
+ * duplicating the `jwt-decode` dependency in the RN bundle). HttpService keeps
264
+ * the per-request preflight refresh; this powers the idle/background timer.
265
+ */
266
+ getAccessTokenExpiry() {
267
+ const token = this.httpService.getAccessToken();
268
+ if (!token) {
269
+ return null;
270
+ }
271
+ try {
272
+ const decoded = (0, jwt_decode_1.jwtDecode)(token);
273
+ return typeof decoded.exp === 'number' ? decoded.exp : null;
274
+ }
275
+ catch {
276
+ // A malformed / non-JWT token has no usable expiry — fall back to the
277
+ // reactive 401 refresh path instead of a scheduled one.
278
+ return null;
279
+ }
280
+ }
256
281
  /**
257
282
  * Set the acting-as identity for managed accounts.
258
283
  *
@@ -38,11 +38,15 @@ function OxyServicesLinksMixin(Base) {
38
38
  * Resolve multiple link previews via `POST /links/previews` (body `{ urls }`).
39
39
  *
40
40
  * Inputs are de-duplicated and split into chunks of {@link LINK_PREVIEWS_CHUNK_SIZE}
41
- * (the server-side cap). Chunks run concurrently and their `data` maps are
41
+ * (the server-side cap). Chunks run concurrently and their result maps are
42
42
  * merged into a single result keyed by the REQUESTED url (the exact string
43
43
  * passed in `urls`) — matching the batch contract — so a caller can always
44
44
  * look its own input back up.
45
45
  *
46
+ * `makeRequest` unwraps the API's top-level `{ data }` envelope (same as
47
+ * `getUsersByIds`'s `makeServiceRequest<User[]>`), so each chunk response is
48
+ * already the `Record<url, LinkPreview>` map — merge it directly.
49
+ *
46
50
  * An empty / whitespace-only input resolves immediately with `{}` and
47
51
  * performs no network call. A failure in any chunk surfaces (via
48
52
  * `handleError`) rather than being swallowed.
@@ -58,7 +62,7 @@ function OxyServicesLinksMixin(Base) {
58
62
  }
59
63
  try {
60
64
  const responses = await Promise.all(chunks.map((chunk) => this.makeRequest('POST', '/links/previews', { urls: chunk }, { cache: false })));
61
- return responses.reduce((merged, response) => Object.assign(merged, response?.data ?? {}), {});
65
+ return responses.reduce((merged, response) => Object.assign(merged, response ?? {}), {});
62
66
  }
63
67
  catch (error) {
64
68
  throw this.handleError(error);