@muhkoo/connect 0.10.13-alpha.0 → 0.10.14-alpha.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.
@@ -5325,7 +5325,7 @@ function base64UrlDecode(s) {
5325
5325
  * expect (and isn't serving a stale cached bundle). Keep this in sync with
5326
5326
  * `package.json` `version`.
5327
5327
  */
5328
- const VERSION = "0.10.13-alpha.0";
5328
+ const VERSION = "0.10.14-alpha.0";
5329
5329
 
5330
5330
  /**
5331
5331
  * `HttpClient` — the one place the unified {@link Client} talks to the
@@ -5861,6 +5861,30 @@ function rpIdUsableForOrigin(rpId, host) {
5861
5861
  return false;
5862
5862
  return h === rpId || h.endsWith(`.${rpId}`);
5863
5863
  }
5864
+ /**
5865
+ * Would {@link AuthNamespace.loginWithPasskey} accept a factor recorded with
5866
+ * this `rpId`, from `host`?
5867
+ *
5868
+ * This is deliberately NOT the same as {@link rpIdUsableForOrigin}. That answers
5869
+ * a raw WebAuthn question and is `false` for a missing rpId. But a factor with
5870
+ * NO recorded rpId predates per-origin enrolment, and `loginWithPasskey`
5871
+ * resolves it as `params.rpId ?? host` — so it IS usable, from anywhere.
5872
+ *
5873
+ * Callers deciding "should I even try a passkey here?" must use this one.
5874
+ * Reaching for `rpIdUsableForOrigin` instead silently excludes every legacy
5875
+ * passkey holder, which has locked real users out of production twice.
5876
+ *
5877
+ * The `?? host` fallback applies to nullish only, matching `loginWithPasskey`:
5878
+ * an empty-string rpId stays unusable rather than resolving to the host.
5879
+ */
5880
+ function passkeyUsableFromOrigin(rpId, host) {
5881
+ const h = host ?? defaultRpId();
5882
+ if (!h)
5883
+ return false;
5884
+ if (rpId == null)
5885
+ return true;
5886
+ return rpIdUsableForOrigin(rpId, h);
5887
+ }
5864
5888
  /** Thrown when the account's passkey belongs to a different origin. Callers
5865
5889
  * should treat this as "no passkey here" and fall back to another factor. */
5866
5890
  class PasskeyOriginError extends Error {
@@ -6812,9 +6836,11 @@ class HostedAuth {
6812
6836
  /**
6813
6837
  * The account's paired devices. Session-authed.
6814
6838
  *
6815
- * UI copy note (spec §10.6): removing a device signs it out and forces a full
6816
- * re-approval, but it **does not take back the encryption key the device
6817
- * already holds**. Say so — users will assume otherwise.
6839
+ * UI copy note (spec §10.6): removing a device forces a full re-approval next
6840
+ * time, but be careful what you promise. It does NOT sign the device out —
6841
+ * the server returns `session_revoked: false`, and that session runs until it
6842
+ * expires — and it cannot take back the master seed the device already holds.
6843
+ * Users assume "remove" means "locked out immediately"; it does not.
6818
6844
  */
6819
6845
  async listPairedDevices() {
6820
6846
  const res = await this.deviceApi("GET", "/api/auth/devices", undefined, true);
@@ -6832,7 +6858,15 @@ class HostedAuth {
6832
6858
  };
6833
6859
  });
6834
6860
  }
6835
- /** Remove a paired device and revoke its session. Session-authed. */
6861
+ /**
6862
+ * Un-pair a device. Session-authed.
6863
+ *
6864
+ * It stops being a "known" device, so pairing it again needs full approval
6865
+ * with a fresh factor. It does NOT end that device's current session — the
6866
+ * server reports `session_revoked: false` — and it cannot take back the
6867
+ * master seed the device already holds. Do not write UI copy promising an
6868
+ * immediate sign-out; users will assume it and be wrong.
6869
+ */
6836
6870
  async revokePairedDevice(id) {
6837
6871
  if (!id)
6838
6872
  throw new DevicePairingError("error", { message: "revokePairedDevice: `id` is required." });
@@ -7405,7 +7439,34 @@ class ZkAuth {
7405
7439
  return { user, unlocked: true };
7406
7440
  try {
7407
7441
  const factors = await this.listFactors();
7408
- if (factors.some((f) => f.type === "passkey")) {
7442
+ // Only auto-attempt when a passkey is usable from THIS origin.
7443
+ //
7444
+ // Passkeys are per-origin, and an account's passkey may belong to a
7445
+ // different host entirely (hosted-auth enrolment records
7446
+ // `auth.muhkoo.dev`, so a user who added a passkey there is
7447
+ // mismatched on every app host). Attempting anyway means
7448
+ // `loginWithPasskey` does an unauthenticated vault read for a
7449
+ // passkey this origin doesn't have. Today that returns a decoy with
7450
+ // no `prfSalt`, so it fails the guard before touching WebAuthn — the
7451
+ // silence is incidental. Once the decoy is reshaped to be
7452
+ // indistinguishable (it must carry `prfSalt` to stop being an
7453
+ // account-enumeration oracle) that same call would sail through and
7454
+ // fire a modal `navigator.credentials.get()` at page load, on every
7455
+ // boot, for a credential that does not exist. `resume()` is awaited
7456
+ // inside every app's readiness gate, so that dialog lands on the
7457
+ // splash screen before the user has asked for anything.
7458
+ //
7459
+ // `listFactors` is session-authenticated and returns real records,
7460
+ // so decoys never appear here — this reads true rpIds.
7461
+ //
7462
+ // `passkeyUsableFromOrigin`, NOT `rpIdUsableForOrigin`: a factor
7463
+ // with no recorded rpId predates per-origin enrolment and is still
7464
+ // usable (`loginWithPasskey` resolves it as `params.rpId ?? host`).
7465
+ // The raw predicate is false for undefined, so using it here would
7466
+ // skip exactly those users — the regression that locked legacy
7467
+ // passkey holders out of production twice.
7468
+ const host = defaultRpId();
7469
+ if (factors.some((f) => f.type === "passkey" && passkeyUsableFromOrigin(f.rpId, host))) {
7409
7470
  await this.loginWithPasskey(user.username);
7410
7471
  }
7411
7472
  }
@@ -13400,5 +13461,5 @@ var bundledLoader = /*#__PURE__*/Object.freeze({
13400
13461
  default: loadRsWasm
13401
13462
  });
13402
13463
 
13403
- export { ACCESS_TOKEN_SCOPES, AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AccessTokensNamespace, AgentsNamespace, AuthClient, AuthNamespace, AuthPublicInput, Authenticator, BlockEngine, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, Client, ConnectivityManager, DEFAULT_AUTH_BASE_URL, DEFAULT_BASE_URL, DEFAULT_FN_HOST_SUFFIX, DEVICE_IDENTITY_STORAGE_KEY, DEVICE_KEY_DB_NAME, DbCache, DevicePairingError, DeviceStoreUnavailableError, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, FunctionsNamespace, HLC, HashKnowledge, HostedAuth, HttpClient, HttpError, IndexedDbStore, KEEPER_MEMBER_ID, KeyStore, KeyringClient, KvCache, KvNamespace, LocalEngineHost, LocalStorageSessionStore, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, MuhkooAgent, MuhkooDB, MuhkooFunction, MuhkooSpace, NoopStore, OfflineLockedError, OfflineManager, OutboundQueue, P2P_SUBJECT, PAIRING_CODE_ALPHABET, PAIRING_CODE_LENGTH, PBKDF2_DEFAULT_ITERATIONS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PasskeyOriginError, PeerExchange, PeerNetwork, PersonalSpaceClient, Poseidon, PreimagePoK, ReauthRequiredError, ReedSolomonCodec, Space as Room, SerializeMessage, SessionState, ShardCache, ShardClient, SharedSpaceClient, SnapshotNamespace, Space, SpaceCache, SpaceKeyring, SpaceNamespace, SpacePacketCipher, SpaceSignaler, StorageNamespace, SyncEngine, VaultUnavailableError, WSTransport, WebRtcTransport, WorkerEngineHost, ZERO_HLC, ZkAuth, buildCommitment, canonicalUserCode, clearDeviceIdentity, compareHlc, compilePrograms, configureDeviceStore, createPasskeyWithPrf, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultRpId, defaultSessionStore, deleteBeatsWrite, deleteRegister, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, deriveIdentityFromSeed, deriveMasterSeedFromPassword, deviceFingerprint, deviceIdentityIsEphemeral, deviceIdentityKey, ejectAgentPrompt, ejectAgentTools, emptyMap, emptyRegister, encodeToHex, encryptAesGcm, evaluatePasskeyPrf, exportPublicKeyBase64, exportPublicKeyHex, formatUserCode, generateAuthProof, generateDevicePairingKeypair, generatePkce, getMuhkooAppDescriptor, getSubtle, hasDeviceIdentity, initBn128Wasm, initRsWasm, initializeCircuits, isNewer, isOfflineCapable, isP2pCapable, isProvisional, loadDeviceIdentity, manifestToStat, materializeRow, mergeMap, mergeMessage, mergeRegister, messageKey, pack, padHandle, pairingVerificationCode, passkeyPrfCapable, passkeySupported, persistDeviceIdentity, poseidonHash, protocol, provisionalHandle, quickVerify, randomBytes, randomState, rpIdUsableForOrigin, sealSeed, sealSeedToDevice, shardHash, signMessage, stableStringify, toField, tombstoneRow, unpack, unsealSeed, unsealSeedFromDevice, unwrapWithPassphrase, verify, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase, writeBeatsTombstone, writeColumns, writeRegister };
13464
+ export { ACCESS_TOKEN_SCOPES, AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AccessTokensNamespace, AgentsNamespace, AuthClient, AuthNamespace, AuthPublicInput, Authenticator, BlockEngine, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, Client, ConnectivityManager, DEFAULT_AUTH_BASE_URL, DEFAULT_BASE_URL, DEFAULT_FN_HOST_SUFFIX, DEVICE_IDENTITY_STORAGE_KEY, DEVICE_KEY_DB_NAME, DbCache, DevicePairingError, DeviceStoreUnavailableError, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, FunctionsNamespace, HLC, HashKnowledge, HostedAuth, HttpClient, HttpError, IndexedDbStore, KEEPER_MEMBER_ID, KeyStore, KeyringClient, KvCache, KvNamespace, LocalEngineHost, LocalStorageSessionStore, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, MuhkooAgent, MuhkooDB, MuhkooFunction, MuhkooSpace, NoopStore, OfflineLockedError, OfflineManager, OutboundQueue, P2P_SUBJECT, PAIRING_CODE_ALPHABET, PAIRING_CODE_LENGTH, PBKDF2_DEFAULT_ITERATIONS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PasskeyOriginError, PeerExchange, PeerNetwork, PersonalSpaceClient, Poseidon, PreimagePoK, ReauthRequiredError, ReedSolomonCodec, Space as Room, SerializeMessage, SessionState, ShardCache, ShardClient, SharedSpaceClient, SnapshotNamespace, Space, SpaceCache, SpaceKeyring, SpaceNamespace, SpacePacketCipher, SpaceSignaler, StorageNamespace, SyncEngine, VaultUnavailableError, WSTransport, WebRtcTransport, WorkerEngineHost, ZERO_HLC, ZkAuth, buildCommitment, canonicalUserCode, clearDeviceIdentity, compareHlc, compilePrograms, configureDeviceStore, createPasskeyWithPrf, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultRpId, defaultSessionStore, deleteBeatsWrite, deleteRegister, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, deriveIdentityFromSeed, deriveMasterSeedFromPassword, deviceFingerprint, deviceIdentityIsEphemeral, deviceIdentityKey, ejectAgentPrompt, ejectAgentTools, emptyMap, emptyRegister, encodeToHex, encryptAesGcm, evaluatePasskeyPrf, exportPublicKeyBase64, exportPublicKeyHex, formatUserCode, generateAuthProof, generateDevicePairingKeypair, generatePkce, getMuhkooAppDescriptor, getSubtle, hasDeviceIdentity, initBn128Wasm, initRsWasm, initializeCircuits, isNewer, isOfflineCapable, isP2pCapable, isProvisional, loadDeviceIdentity, manifestToStat, materializeRow, mergeMap, mergeMessage, mergeRegister, messageKey, pack, padHandle, pairingVerificationCode, passkeyPrfCapable, passkeySupported, passkeyUsableFromOrigin, persistDeviceIdentity, poseidonHash, protocol, provisionalHandle, quickVerify, randomBytes, randomState, rpIdUsableForOrigin, sealSeed, sealSeedToDevice, shardHash, signMessage, stableStringify, toField, tombstoneRow, unpack, unsealSeed, unsealSeedFromDevice, unwrapWithPassphrase, verify, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase, writeBeatsTombstone, writeColumns, writeRegister };
13404
13465
  //# sourceMappingURL=index.js.map