@oxy.so/core 4.5.0-oxy-one.1 → 4.6.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 (283) 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 +16 -3
  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/models/interfaces.d.ts +9 -1
  163. package/dist/types/server/index.d.ts +6 -6
  164. package/dist/types/server/workloadIdentity.client.d.ts +5 -1
  165. package/dist/types/server/workloadIdentity.d.ts +26 -0
  166. package/dist/types/session/accountDelegationAccess.d.ts +1 -1
  167. package/dist/types/session/index.d.ts +1 -1
  168. package/dist/types/utils/userIdentity.d.ts +1 -1
  169. package/dist/types/utils/validationUtils.d.ts +4 -5
  170. package/package.json +3 -4
  171. package/src/HttpService.ts +183 -53
  172. package/src/OxyServices.errors.ts +7 -3
  173. package/src/OxyServices.ts +6 -2
  174. package/src/api/accounts.ts +96 -28
  175. package/src/api/agency.ts +24 -9
  176. package/src/api/appData.ts +12 -2
  177. package/src/api/apps.ts +81 -31
  178. package/src/api/assets.ts +113 -43
  179. package/src/api/auth.ts +145 -77
  180. package/src/api/billing.ts +112 -65
  181. package/src/api/civic.ts +61 -19
  182. package/src/api/contacts.ts +4 -1
  183. package/src/api/devices.ts +54 -21
  184. package/src/api/follows.ts +88 -31
  185. package/src/api/identity.ts +101 -33
  186. package/src/api/linkedAccounts.ts +26 -8
  187. package/src/api/nodes.ts +18 -6
  188. package/src/api/notifications.ts +26 -6
  189. package/src/api/privacy.ts +42 -8
  190. package/src/api/reputation.ts +18 -7
  191. package/src/api/session.ts +23 -5
  192. package/src/api/store.ts +81 -31
  193. package/src/api/topics.ts +18 -6
  194. package/src/api/users.ts +98 -35
  195. package/src/boot/sessionColdBoot.ts +60 -19
  196. package/src/civic/payloads.ts +1 -4
  197. package/src/client/context.ts +6 -1
  198. package/src/constants/version.ts +7 -6
  199. package/src/crypto/aead.ts +1 -5
  200. package/src/crypto/ecdh.ts +1 -4
  201. package/src/crypto/identityDerivations.ts +5 -1
  202. package/src/crypto/identityMarker.ts +3 -1
  203. package/src/crypto/identityProof.ts +6 -1
  204. package/src/crypto/index.ts +11 -11
  205. package/src/crypto/internal.ts +6 -1
  206. package/src/crypto/keyManager.ts +348 -98
  207. package/src/crypto/recoveryPhrase.ts +14 -9
  208. package/src/crypto/registrationPow.ts +1 -1
  209. package/src/crypto/signatureService.ts +14 -6
  210. package/src/i18n/accountCategoryLabels.ts +1 -4
  211. package/src/i18n/accountRoleLabels.ts +1 -4
  212. package/src/i18n/index.ts +25 -7
  213. package/src/i18n/locales/ar-SA.ts +375 -366
  214. package/src/i18n/locales/ca-ES.ts +382 -366
  215. package/src/i18n/locales/de-DE.ts +387 -366
  216. package/src/i18n/locales/en-US.ts +2034 -1994
  217. package/src/i18n/locales/es-ES.ts +2043 -1994
  218. package/src/i18n/locales/fr-FR.ts +387 -366
  219. package/src/i18n/locales/it-IT.ts +380 -366
  220. package/src/i18n/locales/ja-JP.ts +380 -366
  221. package/src/i18n/locales/ko-KR.ts +377 -366
  222. package/src/i18n/locales/pt-PT.ts +383 -366
  223. package/src/i18n/locales/zh-CN.ts +373 -366
  224. package/src/i18n/trustTierLabels.ts +1 -4
  225. package/src/index.ts +371 -349
  226. package/src/inference/OxyInferenceClient.ts +784 -780
  227. package/src/models/interfaces.ts +39 -27
  228. package/src/server/OxyServer.ts +227 -68
  229. package/src/server/agentAccount.ts +8 -2
  230. package/src/server/aliaMachineCredential.ts +57 -16
  231. package/src/server/auth.ts +9 -5
  232. package/src/server/capabilityTicket.ts +30 -21
  233. package/src/server/index.ts +29 -6
  234. package/src/server/liveCapabilityTicket.ts +31 -9
  235. package/src/server/middleware.ts +212 -121
  236. package/src/server/namespaces.ts +247 -94
  237. package/src/server/rateLimit.ts +2 -4
  238. package/src/server/requesterAssertion.ts +93 -54
  239. package/src/server/serviceTokenLifetime.ts +9 -4
  240. package/src/server/traffic.ts +117 -23
  241. package/src/server/trafficNodeHttp.ts +61 -14
  242. package/src/server/userInvalidation.ts +1 -4
  243. package/src/server/workloadIdentity.client.ts +12 -1
  244. package/src/server/workloadIdentity.ts +52 -5
  245. package/src/session/SessionClient.ts +170 -49
  246. package/src/session/accountDelegationAccess.ts +24 -31
  247. package/src/session/accountDialogController.ts +59 -14
  248. package/src/session/accountSwitchTargets.ts +10 -15
  249. package/src/session/authStateStore.ts +121 -81
  250. package/src/session/deviceDirectory.ts +1 -3
  251. package/src/session/identityPin.ts +10 -11
  252. package/src/session/identitySession.ts +3 -1
  253. package/src/session/index.ts +87 -82
  254. package/src/session/refresh.ts +138 -44
  255. package/src/session/sessionClientHost.ts +1 -3
  256. package/src/session/sharedDeviceCredential.ts +35 -14
  257. package/src/session/socketLoader.ts +9 -2
  258. package/src/shared/utils/errorUtils.ts +5 -2
  259. package/src/shared/utils/networkUtils.ts +5 -8
  260. package/src/shared/utils/themeUtils.ts +2 -6
  261. package/src/types/buffer.d.ts +66 -21
  262. package/src/types/expo-secure-store.d.ts +5 -1
  263. package/src/utils/accountCacheSweep.ts +4 -5
  264. package/src/utils/accountUtils.ts +107 -108
  265. package/src/utils/apiUtils.ts +3 -3
  266. package/src/utils/asyncUtils.ts +2 -2
  267. package/src/utils/authHelpers.ts +10 -5
  268. package/src/utils/avatarUtils.ts +11 -6
  269. package/src/utils/cache.ts +9 -10
  270. package/src/utils/cacheKey.ts +5 -1
  271. package/src/utils/coldBoot.ts +1 -3
  272. package/src/utils/commonsDelivery.ts +1 -4
  273. package/src/utils/deviceManager.ts +15 -14
  274. package/src/utils/errorUtils.ts +68 -86
  275. package/src/utils/languageUtils.ts +407 -58
  276. package/src/utils/oauthPkce.ts +1 -4
  277. package/src/utils/platform.ts +0 -1
  278. package/src/utils/profileLinks.ts +2 -5
  279. package/src/utils/requestUtils.ts +18 -14
  280. package/src/utils/sessionUtils.ts +34 -33
  281. package/src/utils/userHandle.ts +3 -1
  282. package/src/utils/userIdentity.ts +1 -1
  283. package/src/utils/validationUtils.ts +11 -9
@@ -31,30 +31,53 @@ export interface OxyAliaMachineRequest extends Request {
31
31
  }
32
32
 
33
33
  function id(value: unknown): value is string {
34
- return typeof value === 'string' && value.length > 0 && value.length <= 128 && value.trim() === value;
34
+ return (
35
+ typeof value === 'string' && value.length > 0 && value.length <= 128 && value.trim() === value
36
+ );
35
37
  }
36
38
 
37
39
  /** Strict response boundary: extra user/tier fields cannot smuggle authority. */
38
40
  export function isOxyAliaMachinePrincipal(value: unknown): value is OxyAliaMachinePrincipal {
39
41
  if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
40
42
  const p = value as Record<string, unknown>;
41
- const keys = ['kind', 'audience', 'applicationId', 'credentialId', 'ownerAccountId', 'environment', 'scopes'];
42
- return Object.keys(p).length === keys.length && keys.every(key => Object.prototype.hasOwnProperty.call(p, key))
43
- && p.kind === 'machine' && p.audience === OXY_ALIA_RESOURCE_APPLICATION_ID
44
- && id(p.applicationId) && id(p.credentialId) && id(p.ownerAccountId)
45
- && typeof p.environment === 'string' && ['production', 'staging', 'development'].includes(p.environment)
46
- && Array.isArray(p.scopes) && p.scopes.length === 2
47
- && OXY_ALIA_MACHINE_SCOPES.every(scope => (p.scopes as unknown[]).includes(scope));
43
+ const keys = [
44
+ 'kind',
45
+ 'audience',
46
+ 'applicationId',
47
+ 'credentialId',
48
+ 'ownerAccountId',
49
+ 'environment',
50
+ 'scopes',
51
+ ];
52
+ return (
53
+ Object.keys(p).length === keys.length &&
54
+ keys.every((key) => Object.prototype.hasOwnProperty.call(p, key)) &&
55
+ p.kind === 'machine' &&
56
+ p.audience === OXY_ALIA_RESOURCE_APPLICATION_ID &&
57
+ id(p.applicationId) &&
58
+ id(p.credentialId) &&
59
+ id(p.ownerAccountId) &&
60
+ typeof p.environment === 'string' &&
61
+ ['production', 'staging', 'development'].includes(p.environment) &&
62
+ Array.isArray(p.scopes) &&
63
+ p.scopes.length === 2 &&
64
+ OXY_ALIA_MACHINE_SCOPES.every((scope) => (p.scopes as unknown[]).includes(scope))
65
+ );
48
66
  }
49
67
 
50
68
  // Keep the forwarding credential out of enumerable request/principal objects,
51
69
  // logs, response serialization and persistent SDK/session state. No cache.
52
- const forwardingCredentials = new WeakMap<Request, { principal: OxyAliaMachinePrincipal; bearer: string }>();
70
+ const forwardingCredentials = new WeakMap<
71
+ Request,
72
+ { principal: OxyAliaMachinePrincipal; bearer: string }
73
+ >();
53
74
 
54
75
  /** Only for the request-scoped Oxy inference client; never for a user API. */
55
76
  export function getOxyAliaMachineCredentialBearer(req: Request): string | null {
56
77
  const bound = forwardingCredentials.get(req);
57
- return bound && (req as OxyAliaMachineRequest).machineCredential === bound.principal ? bound.bearer : null;
78
+ return bound && (req as OxyAliaMachineRequest).machineCredential === bound.principal
79
+ ? bound.bearer
80
+ : null;
58
81
  }
59
82
 
60
83
  /** Opt into Alia's app-only chat lane on its two chat routes, never globally. */
@@ -69,20 +92,38 @@ export function createOxyAliaMachineCredentialAuth(
69
92
  res.status(401).json({ error: 'MACHINE_CREDENTIAL_INVALID' });
70
93
  return;
71
94
  }
72
- const existing = req as Request & { user?: unknown; userId?: unknown; serviceApp?: unknown; oxyRequester?: unknown };
73
- if (existing.user || existing.userId || existing.serviceApp || existing.oxyRequester
74
- || (req as OxyAliaMachineRequest).machineCredential
75
- || req.headers['x-oxy-user-id'] !== undefined || req.headers['x-oxy-requester-assertion'] !== undefined) {
95
+ const existing = req as Request & {
96
+ user?: unknown;
97
+ userId?: unknown;
98
+ serviceApp?: unknown;
99
+ oxyRequester?: unknown;
100
+ };
101
+ if (
102
+ existing.user ||
103
+ existing.userId ||
104
+ existing.serviceApp ||
105
+ existing.oxyRequester ||
106
+ (req as OxyAliaMachineRequest).machineCredential ||
107
+ req.headers['x-oxy-user-id'] !== undefined ||
108
+ req.headers['x-oxy-requester-assertion'] !== undefined
109
+ ) {
76
110
  res.status(403).json({ error: 'MACHINE_USER_DELEGATION_UNSUPPORTED' });
77
111
  return;
78
112
  }
79
113
  try {
80
114
  const answer = await server.apps.introspectAliaMachineCredential(token);
81
- if (!answer.active || !isOxyAliaMachinePrincipal(answer.principal) || answer.principal.environment !== options.environment) {
115
+ if (
116
+ !answer.active ||
117
+ !isOxyAliaMachinePrincipal(answer.principal) ||
118
+ answer.principal.environment !== options.environment
119
+ ) {
82
120
  res.status(401).json({ error: 'MACHINE_CREDENTIAL_INVALID' });
83
121
  return;
84
122
  }
85
- const principal = Object.freeze({ ...answer.principal, scopes: Object.freeze(['alia:chat', 'inference:invoke'] as const) });
123
+ const principal = Object.freeze({
124
+ ...answer.principal,
125
+ scopes: Object.freeze(['alia:chat', 'inference:invoke'] as const),
126
+ });
86
127
  (req as OxyAliaMachineRequest).machineCredential = principal;
87
128
  forwardingCredentials.set(req, { principal, bearer: token });
88
129
  next();
@@ -2,7 +2,10 @@ import type { NextFunction, Request, RequestHandler, Response } from 'express';
2
2
  import type { AuthMiddlewareOptions, OxyAuthRefusal, OxyMiddleware } from './middleware';
3
3
  import type { AccountActorChain } from '@oxy.so/contracts';
4
4
  import { logger } from '../logger';
5
- import { OXY_SERVICE_ENVIRONMENTS, type OxyServiceEnvironment } from '../utils/oxyServiceEnvironment';
5
+ import {
6
+ OXY_SERVICE_ENVIRONMENTS,
7
+ type OxyServiceEnvironment,
8
+ } from '../utils/oxyServiceEnvironment';
6
9
 
7
10
  export { OXY_SERVICE_ENVIRONMENTS };
8
11
  export type { OxyServiceEnvironment, OxyAuthRefusal };
@@ -96,9 +99,7 @@ function ensureUser(req: OxyAuthRequest, userId: string): OxyRequestUser {
96
99
  export function getOxyUserId(req: Request): string | null {
97
100
  const authReq = req as OxyAuthRequest;
98
101
  return (
99
- normalizeId(authReq.userId) ??
100
- normalizeId(authReq.user?.id) ??
101
- normalizeId(authReq.user?._id)
102
+ normalizeId(authReq.userId) ?? normalizeId(authReq.user?.id) ?? normalizeId(authReq.user?._id)
102
103
  );
103
104
  }
104
105
 
@@ -297,7 +298,10 @@ export function createOptionalOxyAuth(
297
298
  oxy: OxyAuthHost,
298
299
  options: OxyAuthMiddlewareOptions = {},
299
300
  ): RequestHandler {
300
- const resolveSession = oxy.middleware.auth({ ...options.auth, optional: true }) as unknown as RequestHandler;
301
+ const resolveSession = oxy.middleware.auth({
302
+ ...options.auth,
303
+ optional: true,
304
+ }) as unknown as RequestHandler;
301
305
 
302
306
  return (req, res, next) => {
303
307
  if (getOxyUserId(req)) {
@@ -1,9 +1,4 @@
1
- import {
2
- randomUUID,
3
- sign as signBytes,
4
- verify as verifyBytes,
5
- type KeyObject,
6
- } from 'node:crypto';
1
+ import { randomUUID, sign as signBytes, verify as verifyBytes, type KeyObject } from 'node:crypto';
7
2
  import {
8
3
  capabilityTicketClaimsSchema,
9
4
  type CapabilityTicketClaims,
@@ -79,7 +74,10 @@ export function issueCapabilityTicket(
79
74
  ): string {
80
75
  const ttlSeconds = options.ttlSeconds ?? 60;
81
76
  if (!Number.isInteger(ttlSeconds) || ttlSeconds < 1 || ttlSeconds > DEFAULT_MAX_TTL_SECONDS) {
82
- throw new CapabilityTicketError('ttl_exceeded', `Capability ticket TTL must be between 1 and ${DEFAULT_MAX_TTL_SECONDS} seconds`);
77
+ throw new CapabilityTicketError(
78
+ 'ttl_exceeded',
79
+ `Capability ticket TTL must be between 1 and ${DEFAULT_MAX_TTL_SECONDS} seconds`,
80
+ );
83
81
  }
84
82
 
85
83
  const issuedAt = Math.floor((options.now ?? new Date()).getTime() / 1_000);
@@ -91,7 +89,10 @@ export function issueCapabilityTicket(
91
89
  jti: options.jti ?? randomUUID(),
92
90
  });
93
91
  if (options.privateKey.asymmetricKeyType !== 'ed25519') {
94
- throw new CapabilityTicketError('invalid_claims', 'Capability tickets require an Ed25519 private key');
92
+ throw new CapabilityTicketError(
93
+ 'invalid_claims',
94
+ 'Capability tickets require an Ed25519 private key',
95
+ );
95
96
  }
96
97
  const header = { alg: ALGORITHM, typ: TOKEN_TYPE, kid: options.keyId } as const;
97
98
  const signingInput = `${base64UrlEncode(JSON.stringify(header))}.${base64UrlEncode(JSON.stringify(payload))}`;
@@ -117,11 +118,11 @@ export function verifyCapabilityTicket(
117
118
  }
118
119
  const headerRecord = header as Record<string, unknown>;
119
120
  if (
120
- Object.keys(headerRecord).length !== 3
121
- || headerRecord.alg !== ALGORITHM
122
- || headerRecord.typ !== TOKEN_TYPE
123
- || typeof headerRecord.kid !== 'string'
124
- || headerRecord.kid.length === 0
121
+ Object.keys(headerRecord).length !== 3 ||
122
+ headerRecord.alg !== ALGORITHM ||
123
+ headerRecord.typ !== TOKEN_TYPE ||
124
+ typeof headerRecord.kid !== 'string' ||
125
+ headerRecord.kid.length === 0
125
126
  ) {
126
127
  throw new CapabilityTicketError('malformed', 'Capability ticket header is not supported');
127
128
  }
@@ -135,12 +136,14 @@ export function verifyCapabilityTicket(
135
136
  } catch {
136
137
  throw new CapabilityTicketError('malformed', 'Capability ticket signature is malformed');
137
138
  }
138
- if (!verifyBytes(
139
- null,
140
- Buffer.from(`${encodedHeader}.${encodedPayload}`),
141
- publicKey,
142
- providedSignature,
143
- )) {
139
+ if (
140
+ !verifyBytes(
141
+ null,
142
+ Buffer.from(`${encodedHeader}.${encodedPayload}`),
143
+ publicKey,
144
+ providedSignature,
145
+ )
146
+ ) {
144
147
  throw new CapabilityTicketError('invalid_signature', 'Capability ticket signature is invalid');
145
148
  }
146
149
 
@@ -158,10 +161,16 @@ export function verifyCapabilityTicket(
158
161
  throw new CapabilityTicketError('expired', 'Capability ticket has expired');
159
162
  }
160
163
  if (claims.exp - claims.iat > (options.maximumTtlSeconds ?? DEFAULT_MAX_TTL_SECONDS)) {
161
- throw new CapabilityTicketError('ttl_exceeded', 'Capability ticket lifetime exceeds the accepted maximum');
164
+ throw new CapabilityTicketError(
165
+ 'ttl_exceeded',
166
+ 'Capability ticket lifetime exceeds the accepted maximum',
167
+ );
162
168
  }
163
169
  if (claims.aud !== options.audience) {
164
- throw new CapabilityTicketError('wrong_audience', 'Capability ticket audience does not match this app');
170
+ throw new CapabilityTicketError(
171
+ 'wrong_audience',
172
+ 'Capability ticket audience does not match this app',
173
+ );
165
174
  }
166
175
  if (options.issuer && claims.iss !== options.issuer) {
167
176
  throw new CapabilityTicketError('wrong_issuer', 'Capability ticket issuer is not trusted');
@@ -17,7 +17,11 @@
17
17
 
18
18
  // The backend client: OxyServices plus the service-token lane, middleware,
19
19
  // account events and the service-only namespace methods.
20
- export { OxyServer, ServiceCredentialMismatchError, ANONYMOUS_SERVICE_TOKEN_RETRY_MS } from './OxyServer';
20
+ export {
21
+ OxyServer,
22
+ ServiceCredentialMismatchError,
23
+ ANONYMOUS_SERVICE_TOKEN_RETRY_MS,
24
+ } from './OxyServer';
21
25
  export type { OxyServerConfig, ServiceTokenResponse } from './OxyServer';
22
26
  export {
23
27
  ServerAppsApi,
@@ -200,7 +204,11 @@ export type {
200
204
  // The identity-key enumeration itself is platform-neutral (`src/utils/`) so the
201
205
  // client namespaces and this Node-only subscriber sweep the SAME list — a second
202
206
  // copy is what let `updateAccount` and `updateProfile` drift apart.
203
- export { evictOxyIdentityCache, oxyUserByIdCacheKey, OXY_IDENTITY_CACHE_PREFIXES } from '../utils/identityCacheSweep';
207
+ export {
208
+ evictOxyIdentityCache,
209
+ oxyUserByIdCacheKey,
210
+ OXY_IDENTITY_CACHE_PREFIXES,
211
+ } from '../utils/identityCacheSweep';
204
212
  export type { OxyIdentityCacheEvictor } from '../utils/identityCacheSweep';
205
213
 
206
214
  // Registrable-apex (eTLD+1) derivation via the Public Suffix List — the SINGLE
@@ -208,7 +216,11 @@ export type { OxyIdentityCacheEvictor } from '../utils/identityCacheSweep';
208
216
  // Pure host handling (no browser deps), so it is safe on the server subpath and
209
217
  // lets `@oxy.so/api` derive `auth.<apex>` without duplicating PSL logic.
210
218
  export { registrableApex } from '../utils/registrableApex';
211
- export { isLoopbackOrigin, isOfficialWebOrigin, isAllowedDeviceJoinOrigin } from '../utils/officialOrigins';
219
+ export {
220
+ isLoopbackOrigin,
221
+ isOfficialWebOrigin,
222
+ isAllowedDeviceJoinOrigin,
223
+ } from '../utils/officialOrigins';
212
224
 
213
225
  export { createEcosystemTraffic } from './traffic';
214
226
  export type { EcosystemTrafficOptions } from './traffic';
@@ -221,9 +233,20 @@ export { observeNodeHttp, withoutNodeHttpObservation } from './trafficNodeHttp';
221
233
  * exported from this subpath rather than the root barrel because it reaches the
222
234
  * container credentials endpoint.
223
235
  */
224
- export { canAttestWorkloadIdentity, requestWorkloadServiceToken } from './workloadIdentity';
225
- export type { WorkloadServiceToken, WorkloadServiceTokenOptions } from './workloadIdentity';
236
+ export {
237
+ attestWorkloadIdentity,
238
+ canAttestWorkloadIdentity,
239
+ requestWorkloadServiceToken,
240
+ } from './workloadIdentity';
241
+ export type {
242
+ WorkloadAttestation,
243
+ WorkloadServiceToken,
244
+ WorkloadServiceTokenOptions,
245
+ } from './workloadIdentity';
226
246
 
227
- export { OXY_SERVICE_TOKEN_MAX_LIFETIME_SECONDS, hasBoundedServiceTokenLifetime } from './serviceTokenLifetime';
247
+ export {
248
+ OXY_SERVICE_TOKEN_MAX_LIFETIME_SECONDS,
249
+ hasBoundedServiceTokenLifetime,
250
+ } from './serviceTokenLifetime';
228
251
  export { signInAgentAccount } from './agentAccount';
229
252
  export type { AgentAccountSigner } from './agentAccount';
@@ -1,41 +1,63 @@
1
- import { canonicalCapabilityJson, capabilityTicketClaimsSchema, type CapabilityTicketClaims } from '@oxy.so/contracts';
2
- import { verifyCapabilityTicket, type CapabilityTicketVerificationOptions } from './capabilityTicket';
1
+ import {
2
+ canonicalCapabilityJson,
3
+ capabilityTicketClaimsSchema,
4
+ type CapabilityTicketClaims,
5
+ } from '@oxy.so/contracts';
6
+ import {
7
+ verifyCapabilityTicket,
8
+ type CapabilityTicketVerificationOptions,
9
+ } from './capabilityTicket';
3
10
  import type { CapabilityTicketIntrospection } from './namespaces';
4
11
 
5
12
  export interface LiveCapabilityTicketVerifierOptions extends CapabilityTicketVerificationOptions {
6
13
  issuer: string;
7
- introspect: (ticket: string, options: { signal: AbortSignal }) => Promise<CapabilityTicketIntrospection>;
14
+ introspect: (
15
+ ticket: string,
16
+ options: { signal: AbortSignal },
17
+ ) => Promise<CapabilityTicketIntrospection>;
8
18
  /** Network bound only; does not establish an authority freshness policy. */
9
19
  timeoutMs?: number;
10
20
  }
11
21
 
12
22
  /** Local signature + live receiving-service introspection; no cache or retry. */
13
23
  export function createLiveCapabilityTicketVerifier(options: LiveCapabilityTicketVerifierOptions) {
14
- if (typeof options.issuer !== 'string' || options.issuer.trim() === '') throw new Error('A trusted Capability issuer is required');
24
+ if (typeof options.issuer !== 'string' || options.issuer.trim() === '')
25
+ throw new Error('A trusted Capability issuer is required');
15
26
  const timeoutMs = options.timeoutMs ?? 5000;
16
27
  if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 60000) {
17
28
  throw new Error('Capability introspection timeout must be between 1 and 60000ms');
18
29
  }
19
- return async (ticket: string, input: { signal?: AbortSignal } = {}): Promise<CapabilityTicketClaims> => {
30
+ return async (
31
+ ticket: string,
32
+ input: { signal?: AbortSignal } = {},
33
+ ): Promise<CapabilityTicketClaims> => {
20
34
  input.signal?.throwIfAborted();
21
35
  const signed = verifyCapabilityTicket(ticket, options);
22
36
  if (!signed.catalog) throw new Error('Internal MCP requires a signed catalogue binding');
23
37
  const controller = new AbortController();
24
38
  const abort = () => controller.abort(input.signal?.reason);
25
39
  input.signal?.addEventListener('abort', abort, { once: true });
26
- const timer = setTimeout(() => controller.abort(new Error('Capability introspection timed out')), timeoutMs);
40
+ const timer = setTimeout(
41
+ () => controller.abort(new Error('Capability introspection timed out')),
42
+ timeoutMs,
43
+ );
27
44
  let rejectAbort: (() => void) | undefined;
28
45
  try {
29
46
  const interrupted = new Promise<never>((_resolve, reject) => {
30
- rejectAbort = () => reject(controller.signal.reason ?? new Error('Capability introspection aborted'));
47
+ rejectAbort = () =>
48
+ reject(controller.signal.reason ?? new Error('Capability introspection aborted'));
31
49
  controller.signal.addEventListener('abort', rejectAbort, { once: true });
32
50
  if (controller.signal.aborted) rejectAbort();
33
51
  });
34
- const result = await Promise.race([options.introspect(ticket, { signal: controller.signal }), interrupted]);
52
+ const result = await Promise.race([
53
+ options.introspect(ticket, { signal: controller.signal }),
54
+ interrupted,
55
+ ]);
35
56
  controller.signal.throwIfAborted();
36
57
  if (result.active !== true) throw new Error('Capability ticket is inactive');
37
58
  const live = capabilityTicketClaimsSchema.parse(result.claims);
38
- if (canonicalCapabilityJson(live) !== canonicalCapabilityJson(signed)) throw new Error('Capability introspection claims mismatch');
59
+ if (canonicalCapabilityJson(live) !== canonicalCapabilityJson(signed))
60
+ throw new Error('Capability introspection claims mismatch');
39
61
  // An authority response delayed past expiry cannot extend the signed grant.
40
62
  return verifyCapabilityTicket(ticket, options);
41
63
  } finally {