@oxyhq/core 10.1.2 → 10.1.3

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.
@@ -26,6 +26,7 @@
26
26
  * builds the hand-off URL; device-first convergence syncs the session back.
27
27
  */
28
28
  import { logger } from '../utils/loggerUtils.js';
29
+ import { extractErrorStatus } from '../utils/errorUtils.js';
29
30
  import { CENTRAL_IDP_APEX } from '../utils/authWebUrl.js';
30
31
  import { generateOAuthState, generatePkcePair, normalizeOAuthRedirectUri, persistOAuthHandshake, } from '../utils/oauthPkce.js';
31
32
  import { projectSwitchableAccounts, switchableAccountIds, } from './accountProjection.js';
@@ -241,10 +242,20 @@ export class AccountDialogController {
241
242
  graph = await this.oxyServices.listAccounts();
242
243
  }
243
244
  catch (error) {
244
- // A graph-load failure is non-fatal: device rows still render. Surface the
245
- // message but keep going with whatever graph we already had.
246
- this.error = errorMessage(error);
247
- logger.warn('[AccountDialogController] listAccounts failed', { component: 'AccountDialogController' }, error);
245
+ // A 401 here is the EXPECTED signed-out edge, not a failure: the bearer was
246
+ // stale/revoked, so `HttpService` already cleared it and emitted
247
+ // `onTokensChanged(null)`, which drops the graph via `reconcileAuth`. Log at
248
+ // debug and leave the dialog error-free — a signed-out device with zero
249
+ // accounts is a normal state, not a warning. Any other error (network, 5xx,
250
+ // malformed) IS unexpected: surface it and warn while keeping the prior graph
251
+ // so device rows still render.
252
+ if (extractErrorStatus(error) === 401) {
253
+ logger.debug('[AccountDialogController] listAccounts unauthorized (signed out)', { component: 'AccountDialogController' }, error);
254
+ }
255
+ else {
256
+ this.error = errorMessage(error);
257
+ logger.warn('[AccountDialogController] listAccounts failed', { component: 'AccountDialogController' }, error);
258
+ }
248
259
  }
249
260
  if (seq !== this.refreshSeq)
250
261
  return; // superseded by a newer refresh
@@ -284,9 +295,16 @@ export class AccountDialogController {
284
295
  profiles = await this.oxyServices.getUsersByIds(ids);
285
296
  }
286
297
  catch (error) {
287
- // `getUsersByIds` already swallows per-chunk failures and returns `[]`;
288
- // this guards the unexpected total failure. Non-fatal keep prior map.
289
- logger.warn('[AccountDialogController] getUsersByIds failed', { component: 'AccountDialogController' }, error);
298
+ // A 401 is the EXPECTED signed-out edge (stale/cleared bearer) — log at debug.
299
+ // `getUsersByIds` already swallows per-chunk failures and returns `[]`, so any
300
+ // OTHER error here is an unexpected total failure worth a warn. Either way keep
301
+ // the prior profile map.
302
+ if (extractErrorStatus(error) === 401) {
303
+ logger.debug('[AccountDialogController] getUsersByIds unauthorized (signed out)', { component: 'AccountDialogController' }, error);
304
+ }
305
+ else {
306
+ logger.warn('[AccountDialogController] getUsersByIds failed', { component: 'AccountDialogController' }, error);
307
+ }
290
308
  return;
291
309
  }
292
310
  if (seq !== this.refreshSeq)