@oxy.so/core 4.5.0-oxy-one.1 → 4.5.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 (282) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/HttpService.js +63 -19
  3. package/dist/cjs/api/accounts.js +10 -3
  4. package/dist/cjs/api/agency.js +3 -1
  5. package/dist/cjs/api/apps.js +15 -4
  6. package/dist/cjs/api/assets.js +39 -11
  7. package/dist/cjs/api/auth.js +28 -8
  8. package/dist/cjs/api/billing.js +24 -7
  9. package/dist/cjs/api/civic.js +14 -4
  10. package/dist/cjs/api/follows.js +9 -2
  11. package/dist/cjs/api/identity.js +31 -9
  12. package/dist/cjs/api/nodes.js +3 -1
  13. package/dist/cjs/api/privacy.js +8 -2
  14. package/dist/cjs/api/session.js +15 -4
  15. package/dist/cjs/api/store.js +15 -5
  16. package/dist/cjs/api/topics.js +10 -3
  17. package/dist/cjs/api/users.js +16 -4
  18. package/dist/cjs/boot/sessionColdBoot.js +40 -13
  19. package/dist/cjs/constants/version.js +6 -6
  20. package/dist/cjs/crypto/identityMarker.js +3 -1
  21. package/dist/cjs/crypto/identityProof.js +6 -1
  22. package/dist/cjs/crypto/keyManager.js +87 -32
  23. package/dist/cjs/crypto/recoveryPhrase.js +2 -2
  24. package/dist/cjs/crypto/signatureService.js +3 -4
  25. package/dist/cjs/i18n/index.js +16 -3
  26. package/dist/cjs/i18n/locales/ar-SA.js +366 -366
  27. package/dist/cjs/i18n/locales/ca-ES.js +366 -366
  28. package/dist/cjs/i18n/locales/de-DE.js +366 -366
  29. package/dist/cjs/i18n/locales/en-US.js +1994 -1994
  30. package/dist/cjs/i18n/locales/es-ES.js +1994 -1994
  31. package/dist/cjs/i18n/locales/fr-FR.js +366 -366
  32. package/dist/cjs/i18n/locales/it-IT.js +366 -366
  33. package/dist/cjs/i18n/locales/ja-JP.js +366 -366
  34. package/dist/cjs/i18n/locales/ko-KR.js +366 -366
  35. package/dist/cjs/i18n/locales/pt-PT.js +366 -366
  36. package/dist/cjs/i18n/locales/zh-CN.js +366 -366
  37. package/dist/cjs/inference/OxyInferenceClient.js +12 -18
  38. package/dist/cjs/models/interfaces.js +11 -11
  39. package/dist/cjs/server/OxyServer.js +86 -28
  40. package/dist/cjs/server/agentAccount.js +6 -2
  41. package/dist/cjs/server/aliaMachineCredential.js +39 -14
  42. package/dist/cjs/server/auth.js +5 -4
  43. package/dist/cjs/server/capabilityTicket.js +5 -5
  44. package/dist/cjs/server/index.js +2 -1
  45. package/dist/cjs/server/liveCapabilityTicket.js +4 -1
  46. package/dist/cjs/server/middleware.js +61 -42
  47. package/dist/cjs/server/namespaces.js +28 -7
  48. package/dist/cjs/server/requesterAssertion.js +36 -30
  49. package/dist/cjs/server/serviceTokenLifetime.js +7 -4
  50. package/dist/cjs/server/traffic.js +53 -14
  51. package/dist/cjs/server/trafficNodeHttp.js +33 -8
  52. package/dist/cjs/server/workloadIdentity.client.js +4 -0
  53. package/dist/cjs/server/workloadIdentity.js +28 -1
  54. package/dist/cjs/session/SessionClient.js +54 -17
  55. package/dist/cjs/session/accountDelegationAccess.js +4 -6
  56. package/dist/cjs/session/accountDialogController.js +1 -1
  57. package/dist/cjs/session/authStateStore.js +18 -9
  58. package/dist/cjs/session/identityPin.js +6 -2
  59. package/dist/cjs/session/refresh.js +81 -23
  60. package/dist/cjs/session/sharedDeviceCredential.js +28 -15
  61. package/dist/cjs/shared/utils/errorUtils.js +1 -1
  62. package/dist/cjs/shared/utils/networkUtils.js +1 -1
  63. package/dist/cjs/shared/utils/themeUtils.js +1 -1
  64. package/dist/cjs/utils/accountCacheSweep.js +3 -1
  65. package/dist/cjs/utils/accountUtils.js +1 -3
  66. package/dist/cjs/utils/asyncUtils.js +1 -1
  67. package/dist/cjs/utils/authHelpers.js +2 -1
  68. package/dist/cjs/utils/avatarUtils.js +4 -2
  69. package/dist/cjs/utils/cache.js +1 -1
  70. package/dist/cjs/utils/cacheKey.js +3 -1
  71. package/dist/cjs/utils/deviceManager.js +4 -4
  72. package/dist/cjs/utils/errorUtils.js +6 -4
  73. package/dist/cjs/utils/languageUtils.js +404 -57
  74. package/dist/cjs/utils/profileLinks.js +1 -3
  75. package/dist/cjs/utils/requestUtils.js +7 -1
  76. package/dist/cjs/utils/userIdentity.js +1 -1
  77. package/dist/cjs/utils/validationUtils.js +5 -6
  78. package/dist/esm/HttpService.js +64 -20
  79. package/dist/esm/api/accounts.js +11 -4
  80. package/dist/esm/api/agency.js +3 -1
  81. package/dist/esm/api/apps.js +15 -4
  82. package/dist/esm/api/assets.js +39 -11
  83. package/dist/esm/api/auth.js +28 -8
  84. package/dist/esm/api/billing.js +25 -8
  85. package/dist/esm/api/civic.js +14 -4
  86. package/dist/esm/api/follows.js +9 -2
  87. package/dist/esm/api/identity.js +31 -9
  88. package/dist/esm/api/nodes.js +3 -1
  89. package/dist/esm/api/privacy.js +8 -2
  90. package/dist/esm/api/session.js +15 -4
  91. package/dist/esm/api/store.js +15 -5
  92. package/dist/esm/api/topics.js +10 -3
  93. package/dist/esm/api/users.js +16 -4
  94. package/dist/esm/boot/sessionColdBoot.js +41 -14
  95. package/dist/esm/constants/version.js +6 -6
  96. package/dist/esm/crypto/identityMarker.js +3 -1
  97. package/dist/esm/crypto/identityProof.js +6 -1
  98. package/dist/esm/crypto/internal.js +1 -1
  99. package/dist/esm/crypto/keyManager.js +87 -32
  100. package/dist/esm/crypto/recoveryPhrase.js +2 -2
  101. package/dist/esm/crypto/signatureService.js +3 -4
  102. package/dist/esm/i18n/index.js +16 -3
  103. package/dist/esm/i18n/locales/ar-SA.js +366 -366
  104. package/dist/esm/i18n/locales/ca-ES.js +366 -366
  105. package/dist/esm/i18n/locales/de-DE.js +366 -366
  106. package/dist/esm/i18n/locales/en-US.js +1994 -1994
  107. package/dist/esm/i18n/locales/es-ES.js +1994 -1994
  108. package/dist/esm/i18n/locales/fr-FR.js +366 -366
  109. package/dist/esm/i18n/locales/it-IT.js +366 -366
  110. package/dist/esm/i18n/locales/ja-JP.js +366 -366
  111. package/dist/esm/i18n/locales/ko-KR.js +366 -366
  112. package/dist/esm/i18n/locales/pt-PT.js +366 -366
  113. package/dist/esm/i18n/locales/zh-CN.js +366 -366
  114. package/dist/esm/index.js +1 -1
  115. package/dist/esm/inference/OxyInferenceClient.js +13 -19
  116. package/dist/esm/models/interfaces.js +11 -11
  117. package/dist/esm/server/OxyServer.js +87 -29
  118. package/dist/esm/server/agentAccount.js +6 -2
  119. package/dist/esm/server/aliaMachineCredential.js +39 -14
  120. package/dist/esm/server/auth.js +6 -5
  121. package/dist/esm/server/capabilityTicket.js +6 -6
  122. package/dist/esm/server/index.js +5 -5
  123. package/dist/esm/server/liveCapabilityTicket.js +6 -3
  124. package/dist/esm/server/middleware.js +62 -43
  125. package/dist/esm/server/namespaces.js +31 -10
  126. package/dist/esm/server/requesterAssertion.js +36 -30
  127. package/dist/esm/server/serviceTokenLifetime.js +7 -4
  128. package/dist/esm/server/traffic.js +55 -16
  129. package/dist/esm/server/trafficNodeHttp.js +34 -9
  130. package/dist/esm/server/userInvalidation.js +1 -1
  131. package/dist/esm/server/workloadIdentity.client.js +3 -0
  132. package/dist/esm/server/workloadIdentity.js +27 -1
  133. package/dist/esm/session/SessionClient.js +54 -17
  134. package/dist/esm/session/accountDelegationAccess.js +5 -7
  135. package/dist/esm/session/accountDialogController.js +1 -1
  136. package/dist/esm/session/authStateStore.js +18 -9
  137. package/dist/esm/session/identityPin.js +6 -2
  138. package/dist/esm/session/refresh.js +82 -24
  139. package/dist/esm/session/sharedDeviceCredential.js +28 -15
  140. package/dist/esm/shared/utils/errorUtils.js +1 -1
  141. package/dist/esm/shared/utils/networkUtils.js +1 -1
  142. package/dist/esm/shared/utils/themeUtils.js +1 -1
  143. package/dist/esm/utils/accountCacheSweep.js +3 -1
  144. package/dist/esm/utils/accountUtils.js +1 -3
  145. package/dist/esm/utils/asyncUtils.js +1 -1
  146. package/dist/esm/utils/authHelpers.js +2 -1
  147. package/dist/esm/utils/avatarUtils.js +4 -2
  148. package/dist/esm/utils/cache.js +1 -1
  149. package/dist/esm/utils/cacheKey.js +3 -1
  150. package/dist/esm/utils/deviceManager.js +4 -4
  151. package/dist/esm/utils/errorUtils.js +6 -4
  152. package/dist/esm/utils/languageUtils.js +404 -57
  153. package/dist/esm/utils/profileLinks.js +1 -3
  154. package/dist/esm/utils/requestUtils.js +7 -1
  155. package/dist/esm/utils/userIdentity.js +1 -1
  156. package/dist/esm/utils/validationUtils.js +5 -6
  157. package/dist/types/HttpService.d.ts +1 -1
  158. package/dist/types/api/accounts.d.ts +1 -1
  159. package/dist/types/api/apps.d.ts +4 -4
  160. package/dist/types/crypto/internal.d.ts +1 -1
  161. package/dist/types/index.d.ts +4 -4
  162. package/dist/types/server/index.d.ts +6 -6
  163. package/dist/types/server/workloadIdentity.client.d.ts +5 -1
  164. package/dist/types/server/workloadIdentity.d.ts +26 -0
  165. package/dist/types/session/accountDelegationAccess.d.ts +1 -1
  166. package/dist/types/session/index.d.ts +1 -1
  167. package/dist/types/utils/userIdentity.d.ts +1 -1
  168. package/dist/types/utils/validationUtils.d.ts +4 -5
  169. package/package.json +2 -3
  170. package/src/HttpService.ts +183 -53
  171. package/src/OxyServices.errors.ts +7 -3
  172. package/src/OxyServices.ts +6 -2
  173. package/src/api/accounts.ts +76 -26
  174. package/src/api/agency.ts +24 -9
  175. package/src/api/appData.ts +12 -2
  176. package/src/api/apps.ts +81 -31
  177. package/src/api/assets.ts +113 -43
  178. package/src/api/auth.ts +145 -77
  179. package/src/api/billing.ts +112 -65
  180. package/src/api/civic.ts +61 -19
  181. package/src/api/contacts.ts +4 -1
  182. package/src/api/devices.ts +54 -21
  183. package/src/api/follows.ts +88 -31
  184. package/src/api/identity.ts +101 -33
  185. package/src/api/linkedAccounts.ts +26 -8
  186. package/src/api/nodes.ts +18 -6
  187. package/src/api/notifications.ts +26 -6
  188. package/src/api/privacy.ts +42 -8
  189. package/src/api/reputation.ts +18 -7
  190. package/src/api/session.ts +23 -5
  191. package/src/api/store.ts +81 -31
  192. package/src/api/topics.ts +18 -6
  193. package/src/api/users.ts +98 -35
  194. package/src/boot/sessionColdBoot.ts +60 -19
  195. package/src/civic/payloads.ts +1 -4
  196. package/src/client/context.ts +6 -1
  197. package/src/constants/version.ts +7 -6
  198. package/src/crypto/aead.ts +1 -5
  199. package/src/crypto/ecdh.ts +1 -4
  200. package/src/crypto/identityDerivations.ts +5 -1
  201. package/src/crypto/identityMarker.ts +3 -1
  202. package/src/crypto/identityProof.ts +6 -1
  203. package/src/crypto/index.ts +11 -11
  204. package/src/crypto/internal.ts +6 -1
  205. package/src/crypto/keyManager.ts +348 -98
  206. package/src/crypto/recoveryPhrase.ts +14 -9
  207. package/src/crypto/registrationPow.ts +1 -1
  208. package/src/crypto/signatureService.ts +14 -6
  209. package/src/i18n/accountCategoryLabels.ts +1 -4
  210. package/src/i18n/accountRoleLabels.ts +1 -4
  211. package/src/i18n/index.ts +25 -7
  212. package/src/i18n/locales/ar-SA.ts +375 -366
  213. package/src/i18n/locales/ca-ES.ts +382 -366
  214. package/src/i18n/locales/de-DE.ts +387 -366
  215. package/src/i18n/locales/en-US.ts +2034 -1994
  216. package/src/i18n/locales/es-ES.ts +2043 -1994
  217. package/src/i18n/locales/fr-FR.ts +387 -366
  218. package/src/i18n/locales/it-IT.ts +380 -366
  219. package/src/i18n/locales/ja-JP.ts +380 -366
  220. package/src/i18n/locales/ko-KR.ts +377 -366
  221. package/src/i18n/locales/pt-PT.ts +383 -366
  222. package/src/i18n/locales/zh-CN.ts +373 -366
  223. package/src/i18n/trustTierLabels.ts +1 -4
  224. package/src/index.ts +371 -349
  225. package/src/inference/OxyInferenceClient.ts +784 -780
  226. package/src/models/interfaces.ts +30 -27
  227. package/src/server/OxyServer.ts +227 -68
  228. package/src/server/agentAccount.ts +8 -2
  229. package/src/server/aliaMachineCredential.ts +57 -16
  230. package/src/server/auth.ts +9 -5
  231. package/src/server/capabilityTicket.ts +30 -21
  232. package/src/server/index.ts +29 -6
  233. package/src/server/liveCapabilityTicket.ts +31 -9
  234. package/src/server/middleware.ts +212 -121
  235. package/src/server/namespaces.ts +247 -94
  236. package/src/server/rateLimit.ts +2 -4
  237. package/src/server/requesterAssertion.ts +93 -54
  238. package/src/server/serviceTokenLifetime.ts +9 -4
  239. package/src/server/traffic.ts +117 -23
  240. package/src/server/trafficNodeHttp.ts +61 -14
  241. package/src/server/userInvalidation.ts +1 -4
  242. package/src/server/workloadIdentity.client.ts +12 -1
  243. package/src/server/workloadIdentity.ts +52 -5
  244. package/src/session/SessionClient.ts +170 -49
  245. package/src/session/accountDelegationAccess.ts +24 -31
  246. package/src/session/accountDialogController.ts +59 -14
  247. package/src/session/accountSwitchTargets.ts +10 -15
  248. package/src/session/authStateStore.ts +121 -81
  249. package/src/session/deviceDirectory.ts +1 -3
  250. package/src/session/identityPin.ts +10 -11
  251. package/src/session/identitySession.ts +3 -1
  252. package/src/session/index.ts +87 -82
  253. package/src/session/refresh.ts +138 -44
  254. package/src/session/sessionClientHost.ts +1 -3
  255. package/src/session/sharedDeviceCredential.ts +35 -14
  256. package/src/session/socketLoader.ts +9 -2
  257. package/src/shared/utils/errorUtils.ts +5 -2
  258. package/src/shared/utils/networkUtils.ts +5 -8
  259. package/src/shared/utils/themeUtils.ts +2 -6
  260. package/src/types/buffer.d.ts +66 -21
  261. package/src/types/expo-secure-store.d.ts +5 -1
  262. package/src/utils/accountCacheSweep.ts +4 -5
  263. package/src/utils/accountUtils.ts +107 -108
  264. package/src/utils/apiUtils.ts +3 -3
  265. package/src/utils/asyncUtils.ts +2 -2
  266. package/src/utils/authHelpers.ts +10 -5
  267. package/src/utils/avatarUtils.ts +11 -6
  268. package/src/utils/cache.ts +9 -10
  269. package/src/utils/cacheKey.ts +5 -1
  270. package/src/utils/coldBoot.ts +1 -3
  271. package/src/utils/commonsDelivery.ts +1 -4
  272. package/src/utils/deviceManager.ts +15 -14
  273. package/src/utils/errorUtils.ts +68 -86
  274. package/src/utils/languageUtils.ts +407 -58
  275. package/src/utils/oauthPkce.ts +1 -4
  276. package/src/utils/platform.ts +0 -1
  277. package/src/utils/profileLinks.ts +2 -5
  278. package/src/utils/requestUtils.ts +18 -14
  279. package/src/utils/sessionUtils.ts +34 -33
  280. package/src/utils/userHandle.ts +3 -1
  281. package/src/utils/userIdentity.ts +1 -1
  282. package/src/utils/validationUtils.ts +11 -9
@@ -2,9 +2,11 @@ import http from 'node:http';
2
2
  import https from 'node:https';
3
3
  import { AsyncLocalStorage } from 'node:async_hooks';
4
4
  import { syncBuiltinESMExports } from 'node:module';
5
- import { normalizeInfrastructureRegion, trafficType } from '@oxy.so/telemetry/collector';
5
+ import { normalizeInfrastructureRegion, trafficType, } from '@oxy.so/telemetry/collector';
6
6
  const suppressed = new AsyncLocalStorage();
7
- export function withoutNodeHttpObservation(callback) { return suppressed.run(true, callback); }
7
+ export function withoutNodeHttpObservation(callback) {
8
+ return suppressed.run(true, callback);
9
+ }
8
10
  /** Node and Bun share the HTTP facade; Bun does not emit Node's HTTP diagnostic channels. */
9
11
  export function observeNodeHttp(collector, service, region, resolveEndpoint) {
10
12
  const seen = new WeakSet();
@@ -22,11 +24,23 @@ export function observeNodeHttp(collector, service, region, resolveEndpoint) {
22
24
  const peer = resolveEndpoint(url);
23
25
  if (peer && !request.headersSent)
24
26
  request.setHeader('X-Oxy-Source-Region', region);
25
- const flow = { service, region, activityType: trafficType(url.pathname), scope: peer ? 'internal' : 'external', direction: 'outbound', sourceRegion: region, sourceService: service, targetService: peer?.service };
27
+ const flow = {
28
+ service,
29
+ region,
30
+ activityType: trafficType(url.pathname),
31
+ scope: peer ? 'internal' : 'external',
32
+ direction: 'outbound',
33
+ sourceRegion: region,
34
+ sourceService: service,
35
+ targetService: peer?.service,
36
+ };
26
37
  const emit = request.emit;
27
38
  let recorded = false;
28
- const restore = () => { if (request.emit === observedEmit)
29
- request.emit = emit; restoreRequests.delete(restore); };
39
+ const restore = () => {
40
+ if (request.emit === observedEmit)
41
+ request.emit = emit;
42
+ restoreRequests.delete(restore);
43
+ };
30
44
  // Intercept notifications without adding an 'error' listener: observation
31
45
  // must not turn an unhandled application error into a swallowed error.
32
46
  const observedEmit = function (event, ...args) {
@@ -34,16 +48,27 @@ export function observeNodeHttp(collector, service, region, resolveEndpoint) {
34
48
  if (!recorded && event === 'response') {
35
49
  recorded = true;
36
50
  const response = args[0];
37
- const targetRegion = peer ? normalizeInfrastructureRegion(response.headers['x-oxy-region']) : undefined;
51
+ const targetRegion = peer
52
+ ? normalizeInfrastructureRegion(response.headers['x-oxy-region'])
53
+ : undefined;
38
54
  collector.record({ ...flow, targetRegion });
39
- collector.record({ ...flow, direction: 'inbound', sourceRegion: targetRegion, targetRegion: region, sourceService: peer?.service, targetService: service });
55
+ collector.record({
56
+ ...flow,
57
+ direction: 'inbound',
58
+ sourceRegion: targetRegion,
59
+ targetRegion: region,
60
+ sourceService: peer?.service,
61
+ targetService: service,
62
+ });
40
63
  }
41
64
  else if (!recorded && (event === 'error' || event === 'close')) {
42
65
  recorded = true;
43
66
  collector.record(flow);
44
67
  }
45
68
  }
46
- catch { /* A metrics failure cannot change a request's behavior. */ }
69
+ catch {
70
+ /* A metrics failure cannot change a request's behavior. */
71
+ }
47
72
  if (event === 'close')
48
73
  restore();
49
74
  return emit.call(this, event, ...args);
@@ -60,7 +85,7 @@ export function observeNodeHttp(collector, service, region, resolveEndpoint) {
60
85
  return request;
61
86
  }
62
87
  };
63
- const patches = [http, https].map(module => {
88
+ const patches = [http, https].map((module) => {
64
89
  const request = module.request;
65
90
  const get = module.get;
66
91
  const wrappedRequest = ((...args) => safelyObserve(request.apply(module, args)));
@@ -51,7 +51,7 @@
51
51
  * Node-only; exported solely from `@oxy.so/core/server`.
52
52
  */
53
53
  import { OXY_USER_INVALIDATION_CHANNEL, isPublishedOxyUserChangeReason, oxyUserInvalidationEventSchema, } from '@oxy.so/contracts';
54
- import { evictOxyIdentityCache, } from '../utils/identityCacheSweep.js';
54
+ import { evictOxyIdentityCache } from '../utils/identityCacheSweep.js';
55
55
  /**
56
56
  * Broadcast that an Oxy user's record changed.
57
57
  *
@@ -5,3 +5,6 @@ export function canAttestWorkloadIdentity() {
5
5
  export async function requestWorkloadServiceToken(_options) {
6
6
  throw new Error('Workload identity is only available on a Node host');
7
7
  }
8
+ export async function attestWorkloadIdentity(_options) {
9
+ throw new Error('Workload identity is only available on a Node host');
10
+ }
@@ -81,7 +81,10 @@ function sha256Hex(value) {
81
81
  * does not cover can be swapped by whoever captured the attestation.
82
82
  */
83
83
  function signGetCallerIdentity(credentials, nonce, now) {
84
- const amzDate = now.toISOString().replace(/[-:]/g, '').replace(/\.\d{3}/, '');
84
+ const amzDate = now
85
+ .toISOString()
86
+ .replace(/[-:]/g, '')
87
+ .replace(/\.\d{3}/, '');
85
88
  const dateStamp = amzDate.slice(0, 8);
86
89
  const headers = {
87
90
  host: STS_HOST,
@@ -116,6 +119,29 @@ async function awsContainerAttestation(fetchImpl, nonce) {
116
119
  const credentials = await containerCredentials(fetchImpl);
117
120
  return { headers: signGetCallerIdentity(credentials, nonce, new Date()) };
118
121
  }
122
+ /**
123
+ * Signs this process's identity proof over a nonce the CALLER chose, and sends
124
+ * it nowhere.
125
+ *
126
+ * {@link requestWorkloadServiceToken} is the ordinary consumer: Oxy issues the
127
+ * nonce and replays the proof. This exists for the one host that is its own
128
+ * verifier — Oxy's API acting as an application it hosts (Inbox) needs to learn
129
+ * which role it runs as, and the honest way to learn that is the way it learns
130
+ * anyone else's: sign `GetCallerIdentity` and let STS say whose signature it is.
131
+ * Reading a role name out of configuration would be the process's own word for
132
+ * what it is, which is what ADR 0026 refuses from every other caller.
133
+ *
134
+ * The same signer, so the two can never disagree about the shape the verifier
135
+ * accepts. Throws exactly as the token path does when there is no identity here.
136
+ */
137
+ export async function attestWorkloadIdentity(options) {
138
+ if (!options.nonce)
139
+ throw new Error('A workload attestation needs a nonce to sign.');
140
+ return {
141
+ provider: 'aws-iam',
142
+ attestation: await awsContainerAttestation(options.fetch ?? fetch, options.nonce),
143
+ };
144
+ }
119
145
  /**
120
146
  * Exchanges this process's identity for an Oxy service token.
121
147
  *
@@ -249,7 +249,8 @@ export class SessionClient {
249
249
  // otherwise, so a mismatch always resolves to "mint".
250
250
  const needsMintBeforeNotify = transport != null &&
251
251
  next.accounts.length > 0 &&
252
- (activeAccountId === null || computeIdentityTag(this.host.getAccessToken()) !== activeAccountId);
252
+ (activeAccountId === null ||
253
+ computeIdentityTag(this.host.getAccessToken()) !== activeAccountId);
253
254
  const publish = () => {
254
255
  if (generation !== this.lifecycleGeneration || this.state !== next)
255
256
  return;
@@ -291,13 +292,20 @@ export class SessionClient {
291
292
  // Warm cold boot may fetch authoritative empty state before it ever had a
292
293
  // local projection. Its authenticated holder is history too. Decoding only
293
294
  // identifies local history; authority remains the validated REST response.
294
- const warmHolderEnded = previousState === null && origin === 'request' &&
295
- typeof bearerAccount === 'string' && bearerAccount.length > 0 &&
295
+ const warmHolderEnded = previousState === null &&
296
+ origin === 'request' &&
297
+ typeof bearerAccount === 'string' &&
298
+ bearerAccount.length > 0 &&
296
299
  this.host.getDeviceCredential()?.deviceId === next.deviceId;
297
- if (((previousState?.deviceId === next.deviceId && previousState.accounts.length > 0) || warmHolderEnded) &&
298
- next.accounts.length === 0 && pinnedAccountId === null && this.options.onFullExplicitSignOut) {
300
+ if (((previousState?.deviceId === next.deviceId && previousState.accounts.length > 0) ||
301
+ warmHolderEnded) &&
302
+ next.accounts.length === 0 &&
303
+ pinnedAccountId === null &&
304
+ this.options.onFullExplicitSignOut) {
299
305
  try {
300
- void this.persistFullSignOut().then(finishApply).catch((error) => {
306
+ void this.persistFullSignOut()
307
+ .then(finishApply)
308
+ .catch((error) => {
301
309
  logger.error('[SessionClient] failed to persist received full sign-out', error);
302
310
  finishApply();
303
311
  });
@@ -309,7 +317,10 @@ export class SessionClient {
309
317
  return true;
310
318
  }
311
319
  if (needsMintBeforeNotify) {
312
- void transport.ensureActiveToken(next).then(finishApply).catch((error) => {
320
+ void transport
321
+ .ensureActiveToken(next)
322
+ .then(finishApply)
323
+ .catch((error) => {
313
324
  if (generation !== this.lifecycleGeneration)
314
325
  return;
315
326
  logger.warn('[SessionClient] ensureActiveToken failed — reverting session state', { component: 'SessionClient' }, error);
@@ -345,10 +356,19 @@ export class SessionClient {
345
356
  const issues = parsed.success
346
357
  ? []
347
358
  : parsed.error.issues.map((issue) => issue.code === 'invalid_type'
348
- ? { path: issue.path.join('.'), code: issue.code, expected: issue.expected, received: issue.received }
359
+ ? {
360
+ path: issue.path.join('.'),
361
+ code: issue.code,
362
+ expected: issue.expected,
363
+ received: issue.received,
364
+ }
349
365
  : { path: issue.path.join('.'), code: issue.code });
350
366
  const keys = raw && typeof raw === 'object' ? Object.keys(raw) : [];
351
- logger.warn('[SessionClient] discarded invalid session sync', { component: 'SessionClient', issues, keys });
367
+ logger.warn('[SessionClient] discarded invalid session sync', {
368
+ component: 'SessionClient',
369
+ issues,
370
+ keys,
371
+ });
352
372
  return;
353
373
  }
354
374
  this.commitSync(sync);
@@ -431,7 +451,9 @@ export class SessionClient {
431
451
  }
432
452
  /** `GET /session/device/directory` → {@link applyDirectory}. No notify. */
433
453
  async fetchDirectory() {
434
- const res = await this.requestDevice('GET', '/session/device/directory', undefined, { cache: false });
454
+ const res = await this.requestDevice('GET', '/session/device/directory', undefined, {
455
+ cache: false,
456
+ });
435
457
  return this.applyDirectory(res);
436
458
  }
437
459
  /**
@@ -540,7 +562,9 @@ export class SessionClient {
540
562
  }
541
563
  }
542
564
  async bootstrap() {
543
- const res = await this.requestDevice('GET', '/session/device/state', undefined, { cache: false });
565
+ const res = await this.requestDevice('GET', '/session/device/state', undefined, {
566
+ cache: false,
567
+ });
544
568
  await this.applySync(res);
545
569
  }
546
570
  /**
@@ -626,7 +650,9 @@ export class SessionClient {
626
650
  * {@link signOutPrincipal} for the two that can tell those apart.
627
651
  */
628
652
  async signOut(target) {
629
- const res = await this.requestDevice('POST', '/session/device/signout', target, { cache: false });
653
+ const res = await this.requestDevice('POST', '/session/device/signout', target, {
654
+ cache: false,
655
+ });
630
656
  await this.applySync(res);
631
657
  this.postCommitPing();
632
658
  if (this.state?.accounts.length === 0)
@@ -669,14 +695,19 @@ export class SessionClient {
669
695
  * applied this revision.
670
696
  */
671
697
  async removeFromDevice(target) {
672
- const res = await this.requestDevice('POST', '/session/device/signout', target, { cache: false });
698
+ const res = await this.requestDevice('POST', '/session/device/signout', target, {
699
+ cache: false,
700
+ });
673
701
  const removal = safeParseContract(deviceDirectorySyncSchema, res);
674
702
  if (!removal) {
675
703
  logger.warn('[SessionClient] discarded invalid device removal response');
676
704
  return;
677
705
  }
678
706
  const directoryApplied = this.applyDirectory(removal.directory);
679
- const stateApplied = this.commitSync({ state: removal.state, activeToken: removal.activeToken });
707
+ const stateApplied = this.commitSync({
708
+ state: removal.state,
709
+ activeToken: removal.activeToken,
710
+ });
680
711
  if (this.fullSignOutPersistence?.state === this.state)
681
712
  await this.fullSignOutPersistence.pending;
682
713
  // `commitSync` publishes whenever the flat state moved. When only the
@@ -690,7 +721,9 @@ export class SessionClient {
690
721
  await this.persistFullSignOut();
691
722
  }
692
723
  async addCurrentAccount() {
693
- const res = await this.requestDevice('POST', '/session/device/add', undefined, { cache: false });
724
+ const res = await this.requestDevice('POST', '/session/device/add', undefined, {
725
+ cache: false,
726
+ });
694
727
  await this.applySync(res);
695
728
  this.postCommitPing();
696
729
  }
@@ -784,7 +817,9 @@ export class SessionClient {
784
817
  // if THAT yields nothing — only when no factory was injected.
785
818
  const io = this.options.socketFactory ?? (await getSocketIO());
786
819
  if (!io) {
787
- logger.warn('[SessionClient] no socket.io-client; running REST-only (no realtime sync)', { component: 'SessionClient' });
820
+ logger.warn('[SessionClient] no socket.io-client; running REST-only (no realtime sync)', {
821
+ component: 'SessionClient',
822
+ });
788
823
  return;
789
824
  }
790
825
  if (!this.started)
@@ -869,7 +904,9 @@ export class SessionClient {
869
904
  onSessionAccountsChanged(payload) {
870
905
  const event = safeParseContract(sessionAccountsChangedEventSchema, payload);
871
906
  if (!event) {
872
- logger.warn('[SessionClient] discarded invalid session_accounts_changed', { component: 'SessionClient' });
907
+ logger.warn('[SessionClient] discarded invalid session_accounts_changed', {
908
+ component: 'SessionClient',
909
+ });
873
910
  return;
874
911
  }
875
912
  // The socket is in `user:<activeUserId>` for the planted bearer, so this should
@@ -13,7 +13,7 @@
13
13
  * (or the structural subset below), so the SDK and every agent runtime read the
14
14
  * API's already-resolved relationship and effective permissions identically.
15
15
  */
16
- import { isDelegatedActAsEligibleKind } from "@oxy.so/contracts";
16
+ import { isDelegatedActAsEligibleKind } from '@oxy.so/contracts';
17
17
  /**
18
18
  * Resolve standing and delegated act-as authority from one account-graph node.
19
19
  *
@@ -28,18 +28,16 @@ import { isDelegatedActAsEligibleKind } from "@oxy.so/contracts";
28
28
  */
29
29
  export function resolveAccountDelegationAccess(node) {
30
30
  const membership = node.callerMembership;
31
- const activeMembership = membership?.status === "active";
32
- const hasStanding = node.relationship === "self" ||
33
- node.relationship === "owner" ||
34
- activeMembership;
31
+ const activeMembership = membership?.status === 'active';
32
+ const hasStanding = node.relationship === 'self' || node.relationship === 'owner' || activeMembership;
35
33
  if (!hasStanding || !isDelegatedActAsEligibleKind(node.kind)) {
36
34
  return { hasStanding, canActAs: false };
37
35
  }
38
36
  if (membership !== null && membership !== undefined) {
39
37
  return {
40
38
  hasStanding,
41
- canActAs: activeMembership && membership.permissions.includes("account:act_as"),
39
+ canActAs: activeMembership && membership.permissions.includes('account:act_as'),
42
40
  };
43
41
  }
44
- return { hasStanding, canActAs: node.relationship === "owner" };
42
+ return { hasStanding, canActAs: node.relationship === 'owner' };
45
43
  }
@@ -980,7 +980,7 @@ export class AccountDialogController {
980
980
  // OAuth-bound sessions mint no sessionId on approval — they finalize
981
981
  // into an authorization code. The account dialog only starts device
982
982
  // sign-in today; stop rather than poll until expiry.
983
- this.failSignIn('unsupported-flow', 'This sign-in flow cannot be completed here. Use the app\'s OAuth sign-in instead.');
983
+ this.failSignIn('unsupported-flow', "This sign-in flow cannot be completed here. Use the app's OAuth sign-in instead.");
984
984
  return;
985
985
  }
986
986
  if (status.authorized && status.sessionId) {
@@ -20,9 +20,12 @@ import { logger } from '../logger/index.js';
20
20
  export function matchesAuthState(actual, expected) {
21
21
  if (!actual || !expected)
22
22
  return actual === expected;
23
- return actual.deviceId === expected.deviceId && actual.deviceSecret === expected.deviceSecret &&
24
- actual.sessionId === expected.sessionId && actual.userId === expected.userId &&
25
- actual.accessToken === expected.accessToken && actual.expiresAt === expected.expiresAt;
23
+ return (actual.deviceId === expected.deviceId &&
24
+ actual.deviceSecret === expected.deviceSecret &&
25
+ actual.sessionId === expected.sessionId &&
26
+ actual.userId === expected.userId &&
27
+ actual.accessToken === expected.accessToken &&
28
+ actual.expiresAt === expected.expiresAt);
26
29
  }
27
30
  /**
28
31
  * Versioned DURABLE storage key. Holds ONLY the small, re-mint-critical fields
@@ -350,7 +353,8 @@ export function createNativeAuthStateStore(storage) {
350
353
  if (sessionMirror !== undefined)
351
354
  return sessionMirror;
352
355
  const [durable, warm] = await Promise.all([
353
- storage.getItem(AUTH_STATE_STORAGE_KEY), storage.getItem(AUTH_STATE_TOKEN_STORAGE_KEY),
356
+ storage.getItem(AUTH_STATE_STORAGE_KEY),
357
+ storage.getItem(AUTH_STATE_TOKEN_STORAGE_KEY),
354
358
  ]);
355
359
  return composeState(durable, warm);
356
360
  };
@@ -409,7 +413,8 @@ export function createNativeAuthStateStore(storage) {
409
413
  if (current === undefined) {
410
414
  try {
411
415
  const [durable, warm] = await Promise.all([
412
- storage.getItem(AUTH_STATE_STORAGE_KEY), storage.getItem(AUTH_STATE_TOKEN_STORAGE_KEY),
416
+ storage.getItem(AUTH_STATE_STORAGE_KEY),
417
+ storage.getItem(AUTH_STATE_TOKEN_STORAGE_KEY),
413
418
  ]);
414
419
  current = composeState(durable, warm);
415
420
  }
@@ -419,10 +424,14 @@ export function createNativeAuthStateStore(storage) {
419
424
  }
420
425
  }
421
426
  const expected = guard.expectedState;
422
- if (!guard.isCurrent() || !current ||
423
- current.deviceId !== expected.deviceId || current.deviceSecret !== expected.deviceSecret ||
424
- current.sessionId !== expected.sessionId || current.userId !== expected.userId ||
425
- current.accessToken !== expected.accessToken || current.expiresAt !== expected.expiresAt)
427
+ if (!guard.isCurrent() ||
428
+ !current ||
429
+ current.deviceId !== expected.deviceId ||
430
+ current.deviceSecret !== expected.deviceSecret ||
431
+ current.sessionId !== expected.sessionId ||
432
+ current.userId !== expected.userId ||
433
+ current.accessToken !== expected.accessToken ||
434
+ current.expiresAt !== expected.expiresAt)
426
435
  return false;
427
436
  }
428
437
  suppressedMirror = suppressed;
@@ -167,7 +167,9 @@ export function createWebIdentityPinStore() {
167
167
  save: async (pin) => {
168
168
  const json = serialize(pin);
169
169
  if (!json) {
170
- logger.error('[identityPin] refusing to persist a malformed identity pin', undefined, { component: 'identityPin' });
170
+ logger.error('[identityPin] refusing to persist a malformed identity pin', undefined, {
171
+ component: 'identityPin',
172
+ });
171
173
  return false;
172
174
  }
173
175
  sessionMirror = { publicKey: pin.publicKey.toLowerCase(), accountId: pin.accountId };
@@ -217,7 +219,9 @@ export function createNativeIdentityPinStore(storage) {
217
219
  save: async (pin) => {
218
220
  const json = serialize(pin);
219
221
  if (!json) {
220
- logger.error('[identityPin] refusing to persist a malformed identity pin', undefined, { component: 'identityPin' });
222
+ logger.error('[identityPin] refusing to persist a malformed identity pin', undefined, {
223
+ component: 'identityPin',
224
+ });
221
225
  return false;
222
226
  }
223
227
  sessionMirror = { publicKey: pin.publicKey.toLowerCase(), accountId: pin.accountId };
@@ -1,5 +1,5 @@
1
1
  import { matchesAuthState } from './authStateStore.js';
2
- import { establishIdentitySession, resolveIdentityPin } from './identitySession.js';
2
+ import { establishIdentitySession, resolveIdentityPin, } from './identitySession.js';
3
3
  import { isNative } from '../utils/platform.js';
4
4
  import { extractErrorStatus } from '../utils/errorUtils.js';
5
5
  import { logger } from '../logger/index.js';
@@ -127,9 +127,12 @@ export async function refreshDeviceSecretArm(deps) {
127
127
  // push. Its exact live holder's authoritative empty-device rejection
128
128
  // must suppress automatic key recovery on this and future boots.
129
129
  // A late rejection for a replaced session/local epoch is not current.
130
- if (pin === null && store.setAutomaticIdentitySignInSuppressed && (!invalidSecret || (persisted.sessionId && persisted.userId))) {
130
+ if (pin === null &&
131
+ store.setAutomaticIdentitySignInSuppressed &&
132
+ (!invalidSecret || (persisted.sessionId && persisted.userId))) {
131
133
  const current = await store.load();
132
- if (!isCurrent() || oxy.http.getSessionEpoch() !== epoch ||
134
+ if (!isCurrent() ||
135
+ oxy.http.getSessionEpoch() !== epoch ||
133
136
  current?.deviceId !== persisted.deviceId ||
134
137
  current.deviceSecret !== persisted.deviceSecret ||
135
138
  current.sessionId !== persisted.sessionId ||
@@ -137,7 +140,8 @@ export async function refreshDeviceSecretArm(deps) {
137
140
  current.accessToken !== persisted.accessToken)
138
141
  return { status: 'session-ended' };
139
142
  if (!(await store.setAutomaticIdentitySignInSuppressed(true, {
140
- expectedState: persisted, isCurrent: () => isCurrent() && oxy.http.getSessionEpoch() === epoch,
143
+ expectedState: persisted,
144
+ isCurrent: () => isCurrent() && oxy.http.getSessionEpoch() === epoch,
141
145
  })))
142
146
  return { status: 'session-ended' };
143
147
  }
@@ -185,7 +189,10 @@ export async function refreshDeviceSecretArm(deps) {
185
189
  // Persist nextDeviceSecret (read-back-verified) BEFORE planting the token.
186
190
  // A failed durable persist must NOT plant.
187
191
  const persistedOk = store.saveIfCurrent
188
- ? await store.saveIfCurrent(next, { expectedState: persisted, isCurrent: () => isCurrent() && oxy.http.getSessionEpoch() === epoch })
192
+ ? await store.saveIfCurrent(next, {
193
+ expectedState: persisted,
194
+ isCurrent: () => isCurrent() && oxy.http.getSessionEpoch() === epoch,
195
+ })
189
196
  : await store.save(next);
190
197
  if (!persistedOk) {
191
198
  return { status: 'persist-failed' };
@@ -244,22 +251,39 @@ export async function refreshSharedDeviceArm(deps) {
244
251
  }
245
252
  return { status: 'transient' };
246
253
  }
247
- const bound = mint.state.accounts.find(account => account.accountId === mint.state.activeAccountId);
248
- if (!bound || mint.state.deviceId !== credential.deviceId || !mint.accessToken || !mint.nextDeviceSecret)
254
+ const bound = mint.state.accounts.find((account) => account.accountId === mint.state.activeAccountId);
255
+ if (!bound ||
256
+ mint.state.deviceId !== credential.deviceId ||
257
+ !mint.accessToken ||
258
+ !mint.nextDeviceSecret)
249
259
  return { status: 'transient' };
250
- if (!isCurrent() || oxy.http.getSessionEpoch() !== epoch || !matchesAuthState(await store.load(), before))
260
+ if (!isCurrent() ||
261
+ oxy.http.getSessionEpoch() !== epoch ||
262
+ !matchesAuthState(await store.load(), before))
251
263
  return { status: 'session-ended' };
252
264
  const next = {
253
- deviceId: mint.state.deviceId, deviceSecret: mint.nextDeviceSecret,
254
- sessionId: bound.sessionId, userId: bound.accountId,
255
- accessToken: mint.accessToken, expiresAt: mint.expiresAt,
265
+ deviceId: mint.state.deviceId,
266
+ deviceSecret: mint.nextDeviceSecret,
267
+ sessionId: bound.sessionId,
268
+ userId: bound.accountId,
269
+ accessToken: mint.accessToken,
270
+ expiresAt: mint.expiresAt,
256
271
  };
257
- if (!(await store.saveIfCurrent(next, { expectedState: before, isCurrent: () => isCurrent() && oxy.http.getSessionEpoch() === epoch })))
272
+ if (!(await store.saveIfCurrent(next, {
273
+ expectedState: before,
274
+ isCurrent: () => isCurrent() && oxy.http.getSessionEpoch() === epoch,
275
+ })))
258
276
  return { status: 'persist-failed' };
259
277
  if (!isCurrent() || oxy.http.getSessionEpoch() !== epoch)
260
278
  return { status: 'session-ended' };
261
279
  oxy.session.setAccessToken(mint.accessToken);
262
- return { status: 'ok', token: mint.accessToken, sessionId: bound.sessionId, userId: bound.accountId, state: mint.state };
280
+ return {
281
+ status: 'ok',
282
+ token: mint.accessToken,
283
+ sessionId: bound.sessionId,
284
+ userId: bound.accountId,
285
+ state: mint.state,
286
+ };
263
287
  });
264
288
  }
265
289
  /**
@@ -293,7 +317,10 @@ export async function refreshPersistedSession(deps) {
293
317
  return null;
294
318
  const identity = deps.identity ?? null;
295
319
  // The shared identity is never an identity-bound client's recovery path.
296
- const allowCommonsIdentityFallback = identity ? false : (deps.allowCommonsIdentityFallback ?? isNative()) && !(await store.isAutomaticIdentitySignInSuppressed?.());
320
+ const allowCommonsIdentityFallback = identity
321
+ ? false
322
+ : (deps.allowCommonsIdentityFallback ?? isNative()) &&
323
+ !(await store.isAutomaticIdentitySignInSuppressed?.());
297
324
  const epoch = oxy.http.getSessionEpoch();
298
325
  // Resolved per call: a re-established identity session can move the pin, and a
299
326
  // replaced/removed local key clears it (in which case arm 1 must NOT mint —
@@ -309,7 +336,10 @@ export async function refreshPersistedSession(deps) {
309
336
  case 'session-ended':
310
337
  return null;
311
338
  case 'transient':
312
- logger.debug('Persisted deviceSecret mint failed (transient) — keeping store', { component: 'refresh', method: 'refreshPersistedSession' });
339
+ logger.debug('Persisted deviceSecret mint failed (transient) — keeping store', {
340
+ component: 'refresh',
341
+ method: 'refreshPersistedSession',
342
+ });
313
343
  return null;
314
344
  case 'persist-failed':
315
345
  // The server rotated the secret but it did not durably persist. Do NOT fall
@@ -321,13 +351,21 @@ export async function refreshPersistedSession(deps) {
321
351
  case 'invalid-secret':
322
352
  case 'no-session': {
323
353
  if (!identity && deps.sharedDeviceCredential) {
324
- const joined = await refreshSharedDeviceArm({ oxy, store, shared: deps.sharedDeviceCredential, rejectedLocalHolder: true, isCurrent: deps.isCurrent });
354
+ const joined = await refreshSharedDeviceArm({
355
+ oxy,
356
+ store,
357
+ shared: deps.sharedDeviceCredential,
358
+ rejectedLocalHolder: true,
359
+ isCurrent: deps.isCurrent,
360
+ });
325
361
  if (joined.status === 'ok')
326
362
  return joined.token;
327
363
  if (joined.status === 'session-ended' || joined.status === 'persist-failed')
328
364
  return null;
329
365
  }
330
- if (!identity && arm1.status === 'invalid-secret' && await store.isAutomaticIdentitySignInSuppressed?.())
366
+ if (!identity &&
367
+ arm1.status === 'invalid-secret' &&
368
+ (await store.isAutomaticIdentitySignInSuppressed?.()))
331
369
  return null;
332
370
  if (arm1.status === 'no-session' && !identity) {
333
371
  if (store.setAutomaticIdentitySignInSuppressed)
@@ -337,7 +375,12 @@ export async function refreshPersistedSession(deps) {
337
375
  // to turn this signed-out verdict into a new account session.
338
376
  const persisted = await store.load();
339
377
  if (persisted?.deviceId && persisted.deviceSecret) {
340
- await store.save({ sessionId: '', userId: '', deviceId: persisted.deviceId, deviceSecret: persisted.deviceSecret });
378
+ await store.save({
379
+ sessionId: '',
380
+ userId: '',
381
+ deviceId: persisted.deviceId,
382
+ deviceSecret: persisted.deviceSecret,
383
+ });
341
384
  }
342
385
  return null;
343
386
  }
@@ -364,10 +407,17 @@ export async function refreshPersistedSession(deps) {
364
407
  break;
365
408
  case 'no-secret':
366
409
  if (!identity && deps.sharedDeviceCredential) {
367
- const joined = await refreshSharedDeviceArm({ oxy, store, shared: deps.sharedDeviceCredential, isCurrent: deps.isCurrent });
410
+ const joined = await refreshSharedDeviceArm({
411
+ oxy,
412
+ store,
413
+ shared: deps.sharedDeviceCredential,
414
+ isCurrent: deps.isCurrent,
415
+ });
368
416
  if (joined.status === 'ok')
369
417
  return joined.token;
370
- if (joined.status === 'session-ended' || joined.status === 'persist-failed' || joined.status === 'transient')
418
+ if (joined.status === 'session-ended' ||
419
+ joined.status === 'persist-failed' ||
420
+ joined.status === 'transient')
371
421
  return null;
372
422
  }
373
423
  break;
@@ -377,14 +427,19 @@ export async function refreshPersistedSession(deps) {
377
427
  }
378
428
  // Never after a sign-out: the shared identity is a KEY, not a session, and
379
429
  // proving it here would sign the user straight back in.
380
- if (allowCommonsIdentityFallback && (deps.isCurrent?.() ?? true) && !oxy.http.hasSessionEnded() && !(await store.isAutomaticIdentitySignInSuppressed?.())) {
430
+ if (allowCommonsIdentityFallback &&
431
+ (deps.isCurrent?.() ?? true) &&
432
+ !oxy.http.hasSessionEnded() &&
433
+ !(await store.isAutomaticIdentitySignInSuppressed?.())) {
381
434
  try {
382
435
  // Planted here, not by the sign-in: a sign-out that lands while the
383
436
  // challenge round-trips must win, or the identity proof signs the user
384
437
  // straight back in.
385
438
  const session = await oxy.auth.signInWithCommonsIdentity({ plantTokens: false });
386
439
  if (session?.accessToken) {
387
- if (!(deps.isCurrent?.() ?? true) || oxy.http.getSessionEpoch() !== epoch || await store.isAutomaticIdentitySignInSuppressed?.()) {
440
+ if (!(deps.isCurrent?.() ?? true) ||
441
+ oxy.http.getSessionEpoch() !== epoch ||
442
+ (await store.isAutomaticIdentitySignInSuppressed?.())) {
388
443
  return null;
389
444
  }
390
445
  // Repopulate the fast device-secret lane from the identity re-mint.
@@ -398,7 +453,9 @@ export async function refreshPersistedSession(deps) {
398
453
  expiresAt: session.expiresAt,
399
454
  });
400
455
  }
401
- if (!(deps.isCurrent?.() ?? true) || oxy.http.getSessionEpoch() !== epoch || await store.isAutomaticIdentitySignInSuppressed?.()) {
456
+ if (!(deps.isCurrent?.() ?? true) ||
457
+ oxy.http.getSessionEpoch() !== epoch ||
458
+ (await store.isAutomaticIdentitySignInSuppressed?.())) {
402
459
  return null;
403
460
  }
404
461
  oxy.session.setAccessToken(session.accessToken);
@@ -519,7 +576,8 @@ export function startTokenRefreshScheduler(oxy) {
519
576
  scheduleFromExpiry();
520
577
  return;
521
578
  }
522
- void oxy.http.refreshAccessToken('preflight')
579
+ void oxy.http
580
+ .refreshAccessToken('preflight')
523
581
  .then((token) => Boolean(token))
524
582
  .catch(() => false)
525
583
  .then((ok) => {