@oxyhq/core 12.8.0 → 12.9.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 (38) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/boot/sessionColdBoot.js +16 -3
  3. package/dist/cjs/crypto/identityMarker.js +255 -0
  4. package/dist/cjs/crypto/keyManager.js +844 -106
  5. package/dist/cjs/index.js +8 -4
  6. package/dist/cjs/mixins/OxyServices.auth.js +21 -6
  7. package/dist/cjs/mixins/OxyServices.deviceBoot.js +9 -1
  8. package/dist/esm/.tsbuildinfo +1 -1
  9. package/dist/esm/boot/sessionColdBoot.js +16 -3
  10. package/dist/esm/crypto/identityMarker.js +248 -0
  11. package/dist/esm/crypto/keyManager.js +843 -106
  12. package/dist/esm/index.js +2 -1
  13. package/dist/esm/mixins/OxyServices.auth.js +21 -6
  14. package/dist/esm/mixins/OxyServices.deviceBoot.js +9 -1
  15. package/dist/types/.tsbuildinfo +1 -1
  16. package/dist/types/boot/sessionColdBoot.d.ts +25 -0
  17. package/dist/types/crypto/identityMarker.d.ts +94 -0
  18. package/dist/types/crypto/keyManager.d.ts +212 -3
  19. package/dist/types/index.d.ts +4 -2
  20. package/dist/types/mixins/OxyServices.auth.d.ts +27 -2
  21. package/dist/types/mixins/OxyServices.deviceBoot.d.ts +8 -0
  22. package/package.json +1 -1
  23. package/src/boot/__tests__/sessionColdBoot.test.ts +113 -0
  24. package/src/boot/sessionColdBoot.ts +42 -3
  25. package/src/crypto/__tests__/identityMocks.ts +125 -0
  26. package/src/crypto/__tests__/keyManager.atomicity.test.ts +79 -94
  27. package/src/crypto/__tests__/keyManager.cacheSafety.test.ts +175 -0
  28. package/src/crypto/__tests__/keyManager.identityStatus.test.ts +217 -0
  29. package/src/crypto/__tests__/keyManager.recoveryLadder.test.ts +179 -0
  30. package/src/crypto/__tests__/keyManager.storageMigration.test.ts +227 -0
  31. package/src/crypto/__tests__/keyManager.test.ts +77 -87
  32. package/src/crypto/identityMarker.ts +291 -0
  33. package/src/crypto/keyManager.ts +1026 -105
  34. package/src/index.ts +7 -1
  35. package/src/mixins/OxyServices.auth.ts +31 -7
  36. package/src/mixins/OxyServices.deviceBoot.ts +9 -1
  37. package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +4 -2
  38. package/src/mixins/__tests__/commonsSignIn.test.ts +84 -1
package/dist/esm/index.js CHANGED
@@ -62,7 +62,8 @@ export { mergeSessions, normalizeAndSortSessions, sessionsArraysEqual, } from '.
62
62
  // ---------------------------------------------------------------------------
63
63
  // Crypto / identity
64
64
  // ---------------------------------------------------------------------------
65
- export { KeyManager, IdentityAlreadyExistsError, IdentityPersistError, } from './crypto/keyManager.js';
65
+ export { KeyManager, IdentityAlreadyExistsError, IdentityPersistError, IdentityUnavailableError, } from './crypto/keyManager.js';
66
+ export { readIdentityMarker, updateIdentityMarker, } from './crypto/identityMarker.js';
66
67
  export { SignatureService } from './crypto/signatureService.js';
67
68
  export { RecoveryPhraseService } from './crypto/recoveryPhrase.js';
68
69
  // Low-level crypto primitives (b3 Phase 0 — encrypted backup + device transfer)
@@ -293,12 +293,16 @@ export function OxyServicesAuthMixin(Base) {
293
293
  * The client must sign this challenge with their private key
294
294
  *
295
295
  * @param publicKey - The user's public key
296
+ * @param requestOptions - Optional per-call transport overrides (`retry`,
297
+ * `timeout`). Interactive callers omit it (defaults keep retries); the
298
+ * cold-boot `shared-key-signin` step passes `{ retry: false }` so a slow
299
+ * network cannot multiply boot latency via the inner retry loop.
296
300
  */
297
- async requestChallenge(publicKey) {
301
+ async requestChallenge(publicKey, requestOptions) {
298
302
  try {
299
303
  return await this.makeRequest('POST', '/auth/challenge', {
300
304
  publicKey,
301
- }, { cache: false });
305
+ }, { cache: false, ...requestOptions });
302
306
  }
303
307
  catch (error) {
304
308
  throw this.handleError(error);
@@ -313,8 +317,12 @@ export function OxyServicesAuthMixin(Base) {
313
317
  * @param timestamp - Timestamp when the signature was created
314
318
  * @param deviceName - Optional device name
315
319
  * @param deviceFingerprint - Optional device fingerprint
320
+ * @param requestOptions - Optional per-call transport overrides (`retry`,
321
+ * `timeout`). Interactive callers omit it (defaults keep retries); the
322
+ * cold-boot `shared-key-signin` step passes `{ retry: false }` so a slow
323
+ * network cannot multiply boot latency via the inner retry loop.
316
324
  */
317
- async verifyChallenge(publicKey, challenge, signature, timestamp, deviceName, deviceFingerprint) {
325
+ async verifyChallenge(publicKey, challenge, signature, timestamp, deviceName, deviceFingerprint, requestOptions) {
318
326
  try {
319
327
  const res = await this.makeRequest('POST', '/auth/verify', {
320
328
  publicKey,
@@ -323,7 +331,7 @@ export function OxyServicesAuthMixin(Base) {
323
331
  timestamp,
324
332
  deviceName,
325
333
  deviceFingerprint,
326
- }, { cache: false });
334
+ }, { cache: false, ...requestOptions });
327
335
  // Plant the freshly-minted tokens, mirroring `claimSessionByToken`.
328
336
  // `/auth/verify` returns the first access token (and refresh token) in
329
337
  // its body, so installing it here means callers get an authenticated
@@ -461,6 +469,13 @@ export function OxyServicesAuthMixin(Base) {
461
469
  *
462
470
  * The cold-boot wiring that CALLS this lives in `OxyContext`
463
471
  * (`@oxyhq/services`); this method just performs the exchange.
472
+ *
473
+ * @param opts.requestOptions - Optional per-call transport overrides
474
+ * (`retry`, `timeout`) forwarded to BOTH the `requestChallenge` and
475
+ * `verifyChallenge` round-trips. Interactive flows omit it (defaults keep
476
+ * retries); the cold-boot `shared-key-signin` step passes `{ retry: false }`
477
+ * so this network step cannot multiply boot latency via the inner retry
478
+ * loop. The token-refresh scheduler / 401 lane still retry later.
464
479
  */
465
480
  async signInWithSharedIdentity(opts = {}) {
466
481
  try {
@@ -474,10 +489,10 @@ export function OxyServicesAuthMixin(Base) {
474
489
  if (!sharedPublicKey) {
475
490
  return null;
476
491
  }
477
- const { challenge } = await this.requestChallenge(sharedPublicKey);
492
+ const { challenge } = await this.requestChallenge(sharedPublicKey, opts.requestOptions);
478
493
  const signed = await SignatureService.signChallengeWithSharedKey(challenge);
479
494
  // `signed.challenge` carries the SIGNATURE (mirrors `signChallenge`).
480
- return await this.verifyChallenge(signed.publicKey, challenge, signed.challenge, signed.timestamp, opts.deviceName, opts.deviceFingerprint);
495
+ return await this.verifyChallenge(signed.publicKey, challenge, signed.challenge, signed.timestamp, opts.deviceName, opts.deviceFingerprint, opts.requestOptions);
481
496
  }
482
497
  catch (error) {
483
498
  throw this.handleError(error);
@@ -29,11 +29,19 @@ export function OxyServicesDeviceBootMixin(Base) {
29
29
  * `no_active_session`) to decide whether to drop the secret and fall back or
30
30
  * resolve signed-out.
31
31
  *
32
+ * `retry: false`: the mint is a single logical attempt. The proactive
33
+ * token-refresh scheduler and the reactive 401 lane already own backoff and
34
+ * re-arm, so `HttpService`'s inner retry loop here would only multiply the
35
+ * mint's latency on a slow/black-hole network (3 retries × 5s timeout ≈ 20s
36
+ * per lane) with no correctness benefit — it is the dominant term in the cold
37
+ * boot's worst-case time-to-route. A transient failure surfaces once and the
38
+ * scheduler/401 path retries it later.
39
+ *
32
40
  * @throws if the response does not match {@link deviceTokenMintResponseSchema}.
33
41
  */
34
42
  async mintFromDeviceSecret(deviceId, deviceSecret) {
35
43
  try {
36
- const res = await this.makeRequest('POST', '/session/device/token', { deviceId, deviceSecret }, { cache: false, skipAuth: true });
44
+ const res = await this.makeRequest('POST', '/session/device/token', { deviceId, deviceSecret }, { cache: false, skipAuth: true, retry: false });
37
45
  const parsed = safeParseContract(deviceTokenMintResponseSchema, res);
38
46
  if (!parsed) {
39
47
  throw new Error('session/device/token returned an unexpected response shape');