@muhkoo/connect 0.13.1-alpha.0 → 0.14.0-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.
@@ -5327,7 +5327,7 @@ function base64UrlDecode(s) {
5327
5327
  * expect (and isn't serving a stale cached bundle). Keep this in sync with
5328
5328
  * `package.json` `version`.
5329
5329
  */
5330
- const VERSION = "0.13.1-alpha.0";
5330
+ const VERSION = "0.13.2-alpha.0";
5331
5331
 
5332
5332
  /**
5333
5333
  * `HttpClient` — the one place the unified {@link Client} talks to the
@@ -6456,13 +6456,21 @@ class HostedAuth {
6456
6456
  const { codeVerifier, codeChallenge } = await generatePkce();
6457
6457
  const state = randomState();
6458
6458
  this.store({ codeVerifier, state, appId: opts.appId, redirectUri: opts.redirectUri });
6459
- const url = `${this.deps.authBaseUrl}/authorize?` + new URLSearchParams({
6459
+ const params = {
6460
6460
  app_id: opts.appId,
6461
6461
  redirect_uri: opts.redirectUri,
6462
6462
  state,
6463
6463
  code_challenge: codeChallenge,
6464
6464
  code_challenge_method: "S256",
6465
- }).toString();
6465
+ };
6466
+ // `prompt=login` forces the credential screen even when the browser is
6467
+ // remembered. Without it, an app's own "sign out" would be undone on the
6468
+ // very next sign-in click: single sign-on means the hosted page still
6469
+ // knows you, so the app must be able to say "ask anyway". Named after the
6470
+ // OIDC parameter that solves the same problem.
6471
+ if (opts.prompt)
6472
+ params.prompt = opts.prompt;
6473
+ const url = `${this.deps.authBaseUrl}/authorize?` + new URLSearchParams(params).toString();
6466
6474
  if (opts.redirect !== false)
6467
6475
  this.location().assign(url);
6468
6476
  return url;
@@ -7260,6 +7268,25 @@ class VaultUnavailableError extends Error {
7260
7268
  this.cause = cause;
7261
7269
  }
7262
7270
  }
7271
+ /**
7272
+ * A stored device pairing that the account has since revoked.
7273
+ *
7274
+ * Typed rather than a bare Error because the right response is specific and the
7275
+ * wrong one is harmful: the caller must DISCARD its stored key and fall back to
7276
+ * a password. Retrying is futile (the factor is gone from the vault), and
7277
+ * silently re-pairing would undo the revocation that a user performed
7278
+ * deliberately — the whole point of a revocable pairing is that withdrawing it
7279
+ * stays withdrawn.
7280
+ *
7281
+ * Distinct from a wrong key, which fails to decrypt rather than failing to
7282
+ * resolve. A machine whose access was withdrawn should be able to say so.
7283
+ */
7284
+ class DeviceRevokedError extends Error {
7285
+ constructor() {
7286
+ super("This device is no longer paired — its access was revoked. Sign in again to re-pair.");
7287
+ this.name = "DeviceRevokedError";
7288
+ }
7289
+ }
7263
7290
  /**
7264
7291
  * ZK identity auth. One instance per {@link Client}; reads/writes the shared
7265
7292
  * {@link SessionState}.
@@ -7870,15 +7897,46 @@ class ZkAuth {
7870
7897
  * withdrawn should be able to tell you that, not just "decryption failed".
7871
7898
  */
7872
7899
  async unlockWithDevice(username, factorId, deviceKey) {
7900
+ const seed = await this.openDeviceFactor(username, factorId, deviceKey);
7901
+ this.deps.session.setSeed(seed);
7902
+ }
7903
+ /**
7904
+ * Sign in using a key stored by {@link enrollDevice} — session AND seed.
7905
+ *
7906
+ * {@link unlockWithDevice} recovers only the encryption identity, which suits
7907
+ * a CLI that already holds a session token on disk. A browser generally does
7908
+ * not: its session expires while the device pairing is still perfectly valid,
7909
+ * and at that point it holds the means to decrypt everything but no way to
7910
+ * make an authenticated call. So this derives the ZK identity from the
7911
+ * recovered seed and proves it, exactly as {@link recoverWithPhrase} does —
7912
+ * the seed has always been sufficient to authenticate, and withholding that
7913
+ * here just meant re-typing a password to prove something already known.
7914
+ *
7915
+ * This is what makes single sign-on possible without any credential at rest:
7916
+ * the seed is never stored, only a key that opens a server-held blob, and
7917
+ * revoking the factor ({@link revokeDevice}) severs it immediately.
7918
+ *
7919
+ * Throws distinguishably on a revoked pairing, so a caller can clear its
7920
+ * stored key and fall back to a password rather than retrying forever.
7921
+ */
7922
+ async loginWithDevice(username, factorId, deviceKey, opts = {}) {
7923
+ const seed = await this.openDeviceFactor(username, factorId, deviceKey);
7924
+ const identity = await deriveIdentityFromSeed(seed);
7925
+ const user = await this.proveAndStore(username, identity, opts);
7926
+ this.deps.session.setSeed(seed);
7927
+ return user;
7928
+ }
7929
+ /** Fetch and open a `device` factor. Shared by the unlock and login paths so
7930
+ * the two can never disagree about what a revoked pairing looks like. */
7931
+ async openDeviceFactor(username, factorId, deviceKey) {
7873
7932
  const { factor } = await this.deps.auth.vaultRead(username, "device", undefined, undefined, factorId);
7874
7933
  if (!factor) {
7875
- throw new Error("This device is no longer paired — its access was revoked. Sign in again to re-pair.");
7934
+ throw new DeviceRevokedError();
7876
7935
  }
7877
7936
  if (!factor.wrap || !factor.iv)
7878
7937
  throw new Error("The stored device factor is incomplete; re-pair this device.");
7879
7938
  const key = await wrapKeyFromBytes(fromBase64$1(deviceKey), DEVICE_WRAP_INFO);
7880
- const seed = await unwrapSeed({ iv: factor.iv, ct: factor.wrap }, key);
7881
- this.deps.session.setSeed(seed);
7939
+ return unwrapSeed({ iv: factor.iv, ct: factor.wrap }, key);
7882
7940
  }
7883
7941
  /** Paired machines, newest first. Metadata only — never the ciphertext. */
7884
7942
  async listDevices() {
@@ -15654,5 +15712,5 @@ var bundledLoader = /*#__PURE__*/Object.freeze({
15654
15712
  default: loadRsWasm
15655
15713
  });
15656
15714
 
15657
- export { ACCESS_TOKEN_SCOPES, AES_GCM_IV_BYTES$1 as 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_BRANCH, 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, ROOT_ID, ReauthRequiredError, ReedSolomonCodec, Repo, Space as Room, SerializeMessage, SessionState, ShardCache, ShardClient, SharedSpaceClient, SnapshotNamespace, Space, SpaceCache, SpaceKeyring, SpaceNamespace, SpacePacketCipher, SpaceSignaler, StorageNamespace, SyncEngine, VFS_ROOT_INFO, VaultUnavailableError, VcsError, VcsNamespace, VfsConflictError, VfsLockedError, VfsNamespace, VfsNotFoundError, 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, dirKey, ejectAgentPrompt, ejectAgentTools, emptyMap, emptyRegister, encodeToHex, encryptAesGcm, evaluatePasskeyPrf, exportPublicKeyBase64, exportPublicKeyHex, formatUserCode, generateAuthProof, generateDevicePairingKeypair, generatePkce, getMuhkooAppDescriptor, getSubtle, hasDeviceIdentity, headKey, historyKey, initBn128Wasm, initRsWasm, initializeCircuits, isNewer, isOfflineCapable, isP2pCapable, isProvisional, loadDeviceIdentity, manifestToStat, materializeRow, merge3, merge3Text, mergeKey, mergeMap, mergeMessage, mergeRegister, messageKey, objectKey, pack, padHandle, pairingVerificationCode, passkeyPrfCapable, passkeySupported, passkeyUsableFromOrigin, persistDeviceIdentity, poseidonHash, protocol, provisionalHandle, quickVerify, randomBytes, randomState, refKey, refsIndexKey, rpIdUsableForOrigin, sealSeed, sealSeedToDevice, shardHash, signMessage, stableStringify, toField, tombstoneRow, unpack, unsealSeed, unsealSeedFromDevice, unwrapWithPassphrase, verify, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase, writeBeatsTombstone, writeColumns, writeRegister };
15715
+ export { ACCESS_TOKEN_SCOPES, AES_GCM_IV_BYTES$1 as 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_BRANCH, DEFAULT_FN_HOST_SUFFIX, DEVICE_IDENTITY_STORAGE_KEY, DEVICE_KEY_DB_NAME, DbCache, DevicePairingError, DeviceRevokedError, 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, ROOT_ID, ReauthRequiredError, ReedSolomonCodec, Repo, Space as Room, SerializeMessage, SessionState, ShardCache, ShardClient, SharedSpaceClient, SnapshotNamespace, Space, SpaceCache, SpaceKeyring, SpaceNamespace, SpacePacketCipher, SpaceSignaler, StorageNamespace, SyncEngine, VFS_ROOT_INFO, VaultUnavailableError, VcsError, VcsNamespace, VfsConflictError, VfsLockedError, VfsNamespace, VfsNotFoundError, 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, dirKey, ejectAgentPrompt, ejectAgentTools, emptyMap, emptyRegister, encodeToHex, encryptAesGcm, evaluatePasskeyPrf, exportPublicKeyBase64, exportPublicKeyHex, formatUserCode, generateAuthProof, generateDevicePairingKeypair, generatePkce, getMuhkooAppDescriptor, getSubtle, hasDeviceIdentity, headKey, historyKey, initBn128Wasm, initRsWasm, initializeCircuits, isNewer, isOfflineCapable, isP2pCapable, isProvisional, loadDeviceIdentity, manifestToStat, materializeRow, merge3, merge3Text, mergeKey, mergeMap, mergeMessage, mergeRegister, messageKey, objectKey, pack, padHandle, pairingVerificationCode, passkeyPrfCapable, passkeySupported, passkeyUsableFromOrigin, persistDeviceIdentity, poseidonHash, protocol, provisionalHandle, quickVerify, randomBytes, randomState, refKey, refsIndexKey, rpIdUsableForOrigin, sealSeed, sealSeedToDevice, shardHash, signMessage, stableStringify, toField, tombstoneRow, unpack, unsealSeed, unsealSeedFromDevice, unwrapWithPassphrase, verify, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase, writeBeatsTombstone, writeColumns, writeRegister };
15658
15716
  //# sourceMappingURL=index.js.map