@muhkoo/connect 0.10.13-alpha.0 → 0.11.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.
package/dist/connect.d.ts CHANGED
@@ -1897,7 +1897,7 @@ interface AuthSuccess {
1897
1897
  /** A vault factor record (M1.0 + M2 gated types). Wrap/iv are base64 AES-GCM; absent for phrase. */
1898
1898
  interface VaultFactor {
1899
1899
  id: string;
1900
- type: "password" | "passkey" | "phrase-marker" | "email" | "google";
1900
+ type: "password" | "passkey" | "phrase-marker" | "email" | "google" | "device";
1901
1901
  wrap?: string;
1902
1902
  iv?: string;
1903
1903
  params?: Record<string, unknown>;
@@ -2009,7 +2009,9 @@ declare class AuthClient {
2009
2009
  /** Passkeys are per-origin: naming the caller's host returns THAT origin's
2010
2010
  * passkey instead of whichever was enrolled first (which WebAuthn would
2011
2011
  * refuse). Ignored for other factor types. */
2012
- rpId?: string): Promise<{
2012
+ rpId?: string,
2013
+ /** Device factors are selected by id — a user may have many machines. */
2014
+ factorId?: string): Promise<{
2013
2015
  factor: VaultFactor | null;
2014
2016
  }>;
2015
2017
  /**
@@ -2833,12 +2835,22 @@ declare class HostedAuth {
2833
2835
  /**
2834
2836
  * The account's paired devices. Session-authed.
2835
2837
  *
2836
- * UI copy note (spec §10.6): removing a device signs it out and forces a full
2837
- * re-approval, but it **does not take back the encryption key the device
2838
- * already holds**. Say so — users will assume otherwise.
2838
+ * UI copy note (spec §10.6): removing a device forces a full re-approval next
2839
+ * time, but be careful what you promise. It does NOT sign the device out —
2840
+ * the server returns `session_revoked: false`, and that session runs until it
2841
+ * expires — and it cannot take back the master seed the device already holds.
2842
+ * Users assume "remove" means "locked out immediately"; it does not.
2839
2843
  */
2840
2844
  listPairedDevices(): Promise<PairedDevice[]>;
2841
- /** Remove a paired device and revoke its session. Session-authed. */
2845
+ /**
2846
+ * Un-pair a device. Session-authed.
2847
+ *
2848
+ * It stops being a "known" device, so pairing it again needs full approval
2849
+ * with a fresh factor. It does NOT end that device's current session — the
2850
+ * server reports `session_revoked: false` — and it cannot take back the
2851
+ * master seed the device already holds. Do not write UI copy promising an
2852
+ * immediate sign-out; users will assume it and be wrong.
2853
+ */
2842
2854
  revokePairedDevice(id: string): Promise<void>;
2843
2855
  /**
2844
2856
  * The whole tail of an approved pairing: unseal → derive → **verify** →
@@ -2956,10 +2968,6 @@ interface ZkAuthDeps {
2956
2968
  circuits: CircuitUrls;
2957
2969
  session: SessionState;
2958
2970
  }
2959
- /**
2960
- * ZK identity auth. One instance per {@link Client}; reads/writes the shared
2961
- * {@link SessionState}.
2962
- */
2963
2971
  declare class ZkAuth {
2964
2972
  private readonly deps;
2965
2973
  constructor(deps: ZkAuthDeps);
@@ -3174,6 +3182,63 @@ declare class ZkAuth {
3174
3182
  * passwordless (passkey) login, both of which recover the same seed.
3175
3183
  */
3176
3184
  get seedBase64(): string | null;
3185
+ /**
3186
+ * Pair this machine, so it can unlock the account later without a password.
3187
+ *
3188
+ * Generates a random 32-byte key, wraps the master seed under it, and stores
3189
+ * only the CIPHERTEXT in the vault as a `device` factor. The key is returned
3190
+ * for the caller to persist locally and is never sent anywhere.
3191
+ *
3192
+ * The split is the point: the seed itself never lands on disk, and the
3193
+ * server holds a blob it cannot open. Revoking the factor
3194
+ * ({@link revokeDevice}) makes the local key inert immediately — which a
3195
+ * stored master seed can never be, because nothing can reach out and
3196
+ * un-store it.
3197
+ *
3198
+ * Returns the factor id and the key, both base64. Losing the key just means
3199
+ * re-pairing; leaking it is equivalent to leaking the seed for as long as
3200
+ * the factor exists, so store it with the tightest permissions available.
3201
+ */
3202
+ enrollDevice(label: string): Promise<{
3203
+ factorId: string;
3204
+ deviceKey: string;
3205
+ }>;
3206
+ /**
3207
+ * Unlock using a key stored by {@link enrollDevice}.
3208
+ *
3209
+ * Fetches the wrapped seed and opens it locally. Establishes the encryption
3210
+ * identity only — pair it with a session for calls that need one.
3211
+ *
3212
+ * Throws distinguishably: a REVOKED factor is gone from the vault and says
3213
+ * so, where a wrong key fails to decrypt. A machine that has had its access
3214
+ * withdrawn should be able to tell you that, not just "decryption failed".
3215
+ */
3216
+ unlockWithDevice(username: string, factorId: string, deviceKey: string): Promise<void>;
3217
+ /** Paired machines, newest first. Metadata only — never the ciphertext. */
3218
+ listDevices(): Promise<Array<{
3219
+ id: string;
3220
+ label?: string;
3221
+ createdAt?: number;
3222
+ }>>;
3223
+ /** Withdraw a machine's access. Its stored key stops working immediately. */
3224
+ revokeDevice(factorId: string): Promise<boolean>;
3225
+ /**
3226
+ * Restore an unlocked identity from a seed you already hold.
3227
+ *
3228
+ * The inverse of {@link seedBase64}, for hosts that persist the seed
3229
+ * themselves rather than re-deriving it from a password: a CLI holding it in
3230
+ * a 0600 file, a server-side tool, a test. Without this the seed is a
3231
+ * one-way export and anything outside a browser has to run a full ZK login —
3232
+ * circuits download and proof — on every single invocation.
3233
+ *
3234
+ * Establishes the ENCRYPTION identity only. It does not authenticate: pair
3235
+ * it with a session token (`sessionStore`) for calls that need one.
3236
+ *
3237
+ * Treat a persisted seed as the master credential it is. It is not scoped
3238
+ * and cannot be revoked server-side the way a session token can — rotating
3239
+ * it means moving the identity.
3240
+ */
3241
+ unlockWithSeed(seedBase64: string): void;
3177
3242
  /** Poseidon commitment for an identity — the value the server stores. */
3178
3243
  private commitmentFor;
3179
3244
  /**
@@ -3756,6 +3821,8 @@ interface StorageChangeEvent<T = unknown> {
3756
3821
  }
3757
3822
  declare class KvNamespace {
3758
3823
  private readonly deps;
3824
+ /** One personal-space socket, shared by every subscriber. */
3825
+ private feed;
3759
3826
  private cipher;
3760
3827
  private cipherIdentity;
3761
3828
  constructor(deps: KvNamespaceDeps);
@@ -3779,6 +3846,20 @@ declare class KvNamespace {
3779
3846
  * Requires a `WebSocket` global (browsers; Node 22+ or a `ws` shim).
3780
3847
  */
3781
3848
  on<T = unknown>(event: "change", handler: (e: StorageChangeEvent<T>) => void): () => void;
3849
+ /**
3850
+ * Subscribe to the personal space's raw change feed.
3851
+ *
3852
+ * Every key this user owns crosses this socket, not only `client.kv`
3853
+ * collections — the VFS keeps its directory records here too. Consumers get
3854
+ * the frame untouched: no decryption, no offline-cache merge, because the
3855
+ * value's meaning depends on which subsystem wrote it.
3856
+ *
3857
+ * The transport is SHARED and reference-counted. `WSTransport` namespaces
3858
+ * its events by `id`, so two transports with the same id would cross wires
3859
+ * on the shared event bus — and a second socket to the same Durable Object
3860
+ * would be pure waste besides.
3861
+ */
3862
+ onRaw(handler: (frame: unknown) => void): () => void;
3782
3863
  private dispatchChange;
3783
3864
  /** Decode a stored value: decrypt envelopes, pass plaintext through. */
3784
3865
  private decode;
@@ -4905,9 +4986,20 @@ declare class SpaceNamespace {
4905
4986
  * Create a new space: generate its keypair (public key = id), register
4906
4987
  * metadata, mint the initial group key, and connect. Returns the open Space.
4907
4988
  */
4989
+ /**
4990
+ * Create a space.
4991
+ *
4992
+ * `messaging: false` registers the space and stops there — no group-key
4993
+ * bootstrap and no WebSocket. Use it for a space that only ever holds
4994
+ * FILES: each chunk carries its own key inside its manifest, so the group
4995
+ * keyring buys nothing, and opening a socket makes the write path depend on
4996
+ * a live connection. That dependency is wrong for a CLI, and it is what made
4997
+ * the first VFS write hang forever instead of failing.
4998
+ */
4908
4999
  createSpace(opts?: {
4909
5000
  historyPolicy?: HistoryPolicy;
4910
5001
  private?: boolean;
5002
+ messaging?: boolean;
4911
5003
  }): Promise<Space>;
4912
5004
  /** Join an existing space by id (its public key). Resolves once a key arrives. */
4913
5005
  joinSpace(spaceId: string, opts?: {
@@ -5369,6 +5461,318 @@ declare class AccessTokensNamespace {
5369
5461
  private path;
5370
5462
  }
5371
5463
 
5464
+ /**
5465
+ * Wire types for the VFS metadata layer.
5466
+ *
5467
+ * ## What is stored where
5468
+ *
5469
+ * The filesystem is a graph of **directory records**, one per directory, each
5470
+ * held under a personal-space KV key and encrypted client-side. A record lists
5471
+ * only its immediate children — so listing a directory is one fetch, and you
5472
+ * only ever pay for the subtrees you actually open.
5473
+ *
5474
+ * File CONTENT is not here. Bytes are written with `client.storage.writeFile`
5475
+ * exactly as any other file — into a real Space, with a real gated manifest —
5476
+ * and the entry keeps the returned `FileManifest` as its handle.
5477
+ * `client.storage.readByManifest(manifest)` then reconstructs the bytes from
5478
+ * the content-addressed shard store with no space membership or directory
5479
+ * lookup needed, which is what makes a file shareable by handing over the
5480
+ * handle alone.
5481
+ *
5482
+ * This supersedes the flat personal mirror `writeFile` already maintains
5483
+ * (`{spaceId, manifest}` keyed by manifest id): the same metadata, in the same
5484
+ * personal space, arranged as a tree you can actually navigate.
5485
+ *
5486
+ * ## Why directories have stable random ids, not content hashes
5487
+ *
5488
+ * A git-style tree keys each directory by the hash of its contents, so writing
5489
+ * one file rewrites every ancestor up to the root. Here a directory's id is
5490
+ * random and permanent, so a file write touches exactly ONE record — its
5491
+ * parent — and renaming or moving a directory edits only the parent entry
5492
+ * while the whole subtree underneath stays byte-identical and untouched.
5493
+ *
5494
+ * ## Why a directory's key lives in its parent
5495
+ *
5496
+ * Only the root key is derived from the master seed. Every other directory has
5497
+ * a random key stored in its parent's entry, which chains capabilities
5498
+ * downward: handing someone `{id, key}` for `/apps/my-app` lets them walk that
5499
+ * subtree and nothing else, because no key can be derived upward. That is the
5500
+ * seam group-sharing hangs off later without re-encrypting the filesystem.
5501
+ */
5502
+
5503
+ /** What `stat` and `list` hand back — a path-addressed view of an entry. */
5504
+ interface VfsStat {
5505
+ path: string;
5506
+ name: string;
5507
+ kind: "file" | "dir";
5508
+ size: number;
5509
+ mtime: number;
5510
+ versions: number;
5511
+ }
5512
+ /** The personal-space blob store the VFS persists through. */
5513
+ interface VfsStore {
5514
+ get(key: string): Promise<unknown | null>;
5515
+ put(key: string, value: unknown): Promise<void>;
5516
+ delete(key: string): Promise<void>;
5517
+ /** Every key in the store — the personal space is shared, so this is NOT VFS-only. */
5518
+ list(): Promise<string[]>;
5519
+ }
5520
+
5521
+ /**
5522
+ * `client.vfs` — a real filesystem over Muhkoo primitives.
5523
+ *
5524
+ * Metadata is a graph of encrypted directory records in the user's personal
5525
+ * space; file content is chunked, encrypted and stored in the global
5526
+ * content-addressed shard store, referenced by manifest. See `types.ts` for
5527
+ * why directories carry stable random ids and why each key lives in its parent.
5528
+ *
5529
+ * ## Consistency
5530
+ *
5531
+ * Every mutation is a read-modify-write of exactly ONE directory record, so a
5532
+ * write cannot leave the tree half-updated: either the parent names the new
5533
+ * child or it does not. Two tabs writing different directories never conflict;
5534
+ * two tabs writing the SAME directory resolve last-writer-wins at the personal
5535
+ * space, which carries an HLC per key. Orphaned records (a directory whose
5536
+ * parent entry lost the race) are unreachable rather than corrupting — they
5537
+ * cost storage until a future sweep, which is the trade this shape makes in
5538
+ * exchange for single-record writes.
5539
+ */
5540
+
5541
+ /**
5542
+ * The slice of content storage the VFS needs.
5543
+ *
5544
+ * Narrow on purpose: the VFS knows how to name and arrange things, not how to
5545
+ * shard them. The adapter in `Client` resolves the content space and calls
5546
+ * `client.storage.writeFile` unchanged — the file still lands in a real Space
5547
+ * with a real gated manifest, and the VFS just keeps the handle somewhere
5548
+ * better than a flat mirror.
5549
+ */
5550
+ interface VfsContentStore {
5551
+ write(data: Uint8Array | Blob, meta: {
5552
+ name: string;
5553
+ type: string;
5554
+ }): Promise<{
5555
+ manifest: FileManifest;
5556
+ size: number;
5557
+ }>;
5558
+ read(manifest: FileManifest): Promise<Uint8Array>;
5559
+ /**
5560
+ * Drop a reference to a manifest's shards.
5561
+ *
5562
+ * Shards are content-addressed and reference-counted, so deleting a file is
5563
+ * not enough to reclaim the bytes — without this, every version ever
5564
+ * written stays on disk and billed forever. Best-effort: a failure here
5565
+ * leaks storage but must not block the delete.
5566
+ */
5567
+ release(manifest: FileManifest): Promise<void>;
5568
+ /**
5569
+ * Take an ADDITIONAL reference to shards that already exist.
5570
+ *
5571
+ * Needed when a manifest gains a second owner without new bytes being
5572
+ * written — copying a file. Without it the copy holds a handle to shards
5573
+ * with a refcount of one, and deleting the original frees the bytes out
5574
+ * from under it.
5575
+ */
5576
+ retain(manifest: FileManifest): Promise<void>;
5577
+ }
5578
+ interface VfsNamespaceDeps {
5579
+ store: VfsStore;
5580
+ /**
5581
+ * Subscribe to the personal space's raw change feed, if the runtime has one.
5582
+ * Optional so the VFS works headlessly (a CLI, a test) with no socket.
5583
+ */
5584
+ subscribe?: (handler: (frame: unknown) => void) => () => void;
5585
+ content: VfsContentStore;
5586
+ /** The in-memory master seed, or null when locked. Read per call — it can change. */
5587
+ seed: () => Uint8Array | null;
5588
+ /** Versions retained per file. */
5589
+ historyLimit?: number;
5590
+ }
5591
+ declare class VfsNamespace {
5592
+ private readonly deps;
5593
+ private rootKey;
5594
+ /**
5595
+ * Decrypted directory records, by id.
5596
+ *
5597
+ * The file tree re-lists constantly while typing, and every miss is a
5598
+ * network round trip plus a decrypt. Invalidated precisely on write rather
5599
+ * than by TTL — a stale directory listing shows files that are not there.
5600
+ */
5601
+ private cache;
5602
+ private readonly historyLimit;
5603
+ constructor(deps: VfsNamespaceDeps);
5604
+ /**
5605
+ * The working directory relative paths resolve against.
5606
+ *
5607
+ * Kept here rather than left to each caller so that a CLI, a script and the
5608
+ * SDK all agree on what "here" means — the alternative is every consumer
5609
+ * re-implementing `cd`, and disagreeing about `..`.
5610
+ */
5611
+ private _cwd;
5612
+ /** The current working directory. Always absolute. */
5613
+ get cwd(): string;
5614
+ /**
5615
+ * Change the working directory.
5616
+ *
5617
+ * Verifies the target is a real directory, so a typo fails here — where the
5618
+ * message can name the path — rather than turning every later relative path
5619
+ * into a confusing "does not exist".
5620
+ */
5621
+ cd(path: string): Promise<string>;
5622
+ /** Resolve a path against the working directory. Absolute paths pass through. */
5623
+ resolve(path: string): string;
5624
+ /** True when the master seed is held, so the root key can be derived. */
5625
+ get unlocked(): boolean;
5626
+ /**
5627
+ * Drop every cached record.
5628
+ *
5629
+ * Call after signing in as someone else — the cache is keyed by directory
5630
+ * id with no notion of whose filesystem it came from, and serving one
5631
+ * identity's directories to another would be the worst possible bug here.
5632
+ */
5633
+ clearCache(): void;
5634
+ /**
5635
+ * Call `handler` when this filesystem changes somewhere else — another tab,
5636
+ * another machine, the CLI.
5637
+ *
5638
+ * Deliberately a NOTIFICATION, not a diff: the frame names a record id, and
5639
+ * a record id is not a path (paths are resolved by walking, and the walk is
5640
+ * what the change may have invalidated). So the cache is dropped and the
5641
+ * caller re-reads whatever it is actually showing. Trying to translate a
5642
+ * record id back into a path would mean maintaining a reverse index that
5643
+ * could itself go stale.
5644
+ *
5645
+ * Returns an unsubscribe function. A runtime with no socket (a CLI) gets a
5646
+ * no-op rather than an error — watching is an optimisation, never required
5647
+ * for correctness.
5648
+ */
5649
+ watch(handler: () => void): () => void;
5650
+ exists(path: string): Promise<boolean>;
5651
+ stat(path: string): Promise<VfsStat>;
5652
+ /** Immediate children of a directory. One record fetch. */
5653
+ list(path?: string): Promise<VfsStat[]>;
5654
+ /**
5655
+ * Every file path under a prefix, depth-first.
5656
+ *
5657
+ * Deliberately separate from `list`: this walks the whole subtree, which is
5658
+ * one fetch per directory. Fine for a project, wrong as a default.
5659
+ */
5660
+ walk(path?: string): Promise<string[]>;
5661
+ readFile(path: string): Promise<Uint8Array>;
5662
+ readText(path: string): Promise<string>;
5663
+ /**
5664
+ * Create a directory. `recursive` creates missing parents and tolerates an
5665
+ * existing target, matching `mkdir -p`.
5666
+ */
5667
+ mkdir(path: string, opts?: {
5668
+ recursive?: boolean;
5669
+ }): Promise<void>;
5670
+ /**
5671
+ * Write a file, creating parent directories as needed.
5672
+ *
5673
+ * The previous version is pushed onto the file's history record before the
5674
+ * directory entry is replaced, so an interrupted write can lose the new
5675
+ * version but never the old one.
5676
+ */
5677
+ writeFile(path: string, data: Uint8Array | string | Blob, opts?: {
5678
+ type?: string;
5679
+ }): Promise<VfsStat>;
5680
+ /** Delete a file, or a directory when `recursive`. */
5681
+ delete(path: string, opts?: {
5682
+ recursive?: boolean;
5683
+ }): Promise<void>;
5684
+ /**
5685
+ * Move or rename. Works across directories, which is the same operation:
5686
+ * detach the entry from one parent and attach it to another.
5687
+ *
5688
+ * A directory move is O(1) regardless of how much is inside it — the
5689
+ * subtree records are not touched at all, because nothing in them records
5690
+ * its own path.
5691
+ */
5692
+ rename(from: string, to: string): Promise<void>;
5693
+ /**
5694
+ * Copy a file or a directory tree.
5695
+ *
5696
+ * Copying a FILE moves no bytes: content is immutable and content-addressed,
5697
+ * so the new entry simply points at the same manifest. A 200 MB asset
5698
+ * duplicates in one small metadata write, and the shard store already holds
5699
+ * exactly one copy of it.
5700
+ *
5701
+ * The copy gets a NEW file id, so it does not inherit or share history —
5702
+ * two paths sharing an id would mean saving one silently pushed a version
5703
+ * onto the other.
5704
+ */
5705
+ copy(from: string, to: string): Promise<VfsStat>;
5706
+ /**
5707
+ * Paths matching a glob, relative to the whole filesystem.
5708
+ *
5709
+ * Matching happens on the client over a walk of the tree, so the cost is one
5710
+ * record fetch per directory — cheap for a project, and worth knowing before
5711
+ * pointing it at the root of a large filesystem. Use `walk` when the prefix
5712
+ * already narrows it.
5713
+ */
5714
+ glob(pattern: string, opts?: {
5715
+ from?: string;
5716
+ }): Promise<string[]>;
5717
+ /**
5718
+ * Delete metadata records no longer reachable from the root.
5719
+ *
5720
+ * These accumulate because every write touches exactly one record: if two
5721
+ * tabs edit the same directory, last-writer-wins at the personal space can
5722
+ * leave a child whose parent entry lost the race. Unreachable is harmless —
5723
+ * it is invisible and undecryptable-by-nobody — but it costs storage, so
5724
+ * this reclaims it.
5725
+ *
5726
+ * Deliberately explicit, never automatic: a sweep racing another tab's
5727
+ * in-flight write could delete a record that is about to be referenced.
5728
+ * Run it when the filesystem is idle.
5729
+ */
5730
+ sweep(opts?: {
5731
+ force?: boolean;
5732
+ }): Promise<{
5733
+ removed: string[];
5734
+ }>;
5735
+ /** Prior versions of a file, newest first. One record fetch. */
5736
+ history(path: string): Promise<Array<{
5737
+ size: number;
5738
+ mtime: number;
5739
+ }>>;
5740
+ /**
5741
+ * Restore a prior version, where 0 is the most recent one.
5742
+ *
5743
+ * The current version is pushed onto history first, so restoring is itself
5744
+ * undoable rather than a one-way door.
5745
+ */
5746
+ restore(path: string, index?: number): Promise<VfsStat>;
5747
+ private expectFile;
5748
+ /** Resolve a path to its entry, or null. Root has no entry of its own. */
5749
+ private find;
5750
+ private root;
5751
+ /** Open a directory by path, creating nothing. Throws if it is missing. */
5752
+ private openDir;
5753
+ private openDirOrNull;
5754
+ private openDirById;
5755
+ /** Apply an edit to a directory record and persist it. */
5756
+ private mutate;
5757
+ private createDir;
5758
+ /** Recursively remove a subtree's records. Best-effort: unreachable ≠ fatal. */
5759
+ private purge;
5760
+ /**
5761
+ * Deep-copy an entry. Files reuse their manifest (no bytes move); each
5762
+ * directory gets a fresh id and key, so the copy is independent of the
5763
+ * original — writing into one must never appear in the other.
5764
+ */
5765
+ private cloneEntry;
5766
+ /**
5767
+ * Let go of a file's bytes: the current manifest and every retained
5768
+ * version, then the history record itself.
5769
+ */
5770
+ private releaseFile;
5771
+ private readHistory;
5772
+ /** Push `entry` onto its history record. Returns the new version count. */
5773
+ private pushHistory;
5774
+ }
5775
+
5372
5776
  /** The hosted Muhkoo Accelerator — the default {@link ClientOptions.baseUrl}. */
5373
5777
  declare const DEFAULT_BASE_URL = "https://api.muhkoo.dev";
5374
5778
  /** The hosted auth SPA — the default {@link ClientOptions.authBaseUrl}. */
@@ -5466,6 +5870,8 @@ declare class Client {
5466
5870
  readonly db: DbNamespace;
5467
5871
  /** File storage — `client.storage.writeFile(...)`, etc. */
5468
5872
  readonly storage: StorageNamespace;
5873
+ /** Filesystem over the personal space: directories, versions, real paths. */
5874
+ readonly vfs: VfsNamespace;
5469
5875
  /** Realtime messaging — `client.message.subscribe(...)`, etc. */
5470
5876
  readonly message: MessageNamespace;
5471
5877
  /** Fan-out group spaces — `client.space.createSpace(...)`, etc. */
@@ -5705,6 +6111,23 @@ declare function defaultRpId(): string;
5705
6111
  * sign-in (and offer to enroll a passkey for this origin) instead.
5706
6112
  */
5707
6113
  declare function rpIdUsableForOrigin(rpId: string | undefined | null, host?: string): boolean;
6114
+ /**
6115
+ * Would {@link AuthNamespace.loginWithPasskey} accept a factor recorded with
6116
+ * this `rpId`, from `host`?
6117
+ *
6118
+ * This is deliberately NOT the same as {@link rpIdUsableForOrigin}. That answers
6119
+ * a raw WebAuthn question and is `false` for a missing rpId. But a factor with
6120
+ * NO recorded rpId predates per-origin enrolment, and `loginWithPasskey`
6121
+ * resolves it as `params.rpId ?? host` — so it IS usable, from anywhere.
6122
+ *
6123
+ * Callers deciding "should I even try a passkey here?" must use this one.
6124
+ * Reaching for `rpIdUsableForOrigin` instead silently excludes every legacy
6125
+ * passkey holder, which has locked real users out of production twice.
6126
+ *
6127
+ * The `?? host` fallback applies to nullish only, matching `loginWithPasskey`:
6128
+ * an empty-string rpId stays unusable rather than resolving to the host.
6129
+ */
6130
+ declare function passkeyUsableFromOrigin(rpId: string | undefined | null, host?: string): boolean;
5708
6131
  /** Thrown when the account's passkey belongs to a different origin. Callers
5709
6132
  * should treat this as "no passkey here" and fall back to another factor. */
5710
6133
  declare class PasskeyOriginError extends Error {
@@ -6632,5 +7055,5 @@ declare class KeyringClient implements KeyringTransport {
6632
7055
  fetchMetadata(): Promise<SpaceMetadata | null>;
6633
7056
  }
6634
7057
 
6635
- 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 };
7058
+ 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 };
6636
7059
  export type { ACL, ACLEntry, AccessTokenInfo, AccessTokensNamespaceDeps, AgentConfig, AgentCreateInput, AgentDbToolMode, AgentProvisioned, AgentScopeOpts, AgentSkill, AgentToolsConfig, AgentTrigger, AgentTriggerType, AgentUpdateInput, AgentsNamespaceDeps, AttachedPeerNetwork, AuthClientOptions, AuthKeyPair, AuthSuccess, AuthToken, AuthType, AuthUser, BlockStore, Bn128WasmInstance, BroadcastChannelEvent, BroadcastChannelOptions, CachedSpaceMessage, ChannelLike, ChunkKeyMaterial, ChunkManifest, CipherFrame, CipherMessage, CipherMessageHeader, CircuitBufferConfig, CircuitUrls, ClientOptions, ConnectivityOptions, ConnectivityState, CreateAccessTokenInput, CreatedAccessToken, DbQueryPage, DehydratedKeypair, DehydratedKeys, DeviceBlobStore, DeviceKeyVault, DevicePairingErrorReason, DevicePairingKeypair, DevicePairingPoll, DevicePairingRequest, DevicePairingSession, DoubleRatchetCipherDeps, ECDHCurve, EncodeResult, EngineHandle, EngineHost, EphemeralEvent, EpochKeyProvider, FileManifest, FileNamespaceDeps, FileStat, FileStorageOptions, FunctionCaps, FunctionConfig, FunctionDeployInput, FunctionInvokeOptions, FunctionScopeOpts, FunctionTrigger, FunctionTriggerType, FunctionTriggers, FunctionUpdateInput, FunctionsNamespaceDeps, Groth16Proof, Hasher, HlcParts, HlcState, HostedAuthDeps, HttpClientOptions, IncomingFrame, KeyExchangeFrame, KeyPair, Keypair, KeyringClientDeps, KeyringTransport, KvEntry, KvNamespaceDeps, LoginOptions, LwwMap, LwwRegister, MessageBody, MessageDeletedEvent, MessageEntry, MessageEvent, MessageHeaders, MessageNamespaceDeps, MessageOp, MessageOptions, MessageSubscription, MuhkooAgentMeta, MuhkooAgentToolsConfig, MuhkooAppDescriptor, MuhkooDBAccess, MuhkooDBMeta, MuhkooFunctionMeta, MuhkooKeystoreBridge, MuhkooMessageEvent, MuhkooSpaceMeta, OAuthProvider, OfflineEntry, OfflineManagerDeps, OfflineStore, OutSink, PacketCipher, PacketHeaders, PacketOptions, PairedDevice, Participant, PasskeyEnrollment, PeerBlockSource, PeerExchangeOptions, PeerId, PeerNetworkOptions, PeerTransport, Permission, PermissionCheckRequest, PermissionCheckResult, PersistedDeviceIdentity, PersonalSpaceClientOptions, Pkce, PublicKeyJWK, QueueEntry, RatchetState, ReceiveResult, RegisterParams, Replayer, Role, SpaceDeps as RoomDeps, SpaceFileMetadata as RoomFileMetadata, Scope, SealedHandoff, SealedHeaders, Session, SessionOptions, SessionStore, SetOptions, ShardByteCache, ShardClientOptions, SharedSpaceClientOptions, SignalEnvelope, SignalKind, SignalingSpace, SnapshotNamespaceDeps, SnarkProof, SpaceChannelLike, SpaceCursor, SpaceDeps, SpaceFileMetadata, SpaceKeyCache, SpaceKeyringDeps, SpaceMessageEvent, SpaceNamespaceDeps, SpaceOfflineAdapter, StartDevicePairingOptions, StorageChangeEvent, StoreName, StoredSession, Subscription, UserIdentity, VaultFactor, VerificationKey, WSMessage, WSMessageType, WSTransportOptions, WaitForDevicePairingOptions, WebRtcTransportOptions, WrappedPayload, WriteFileInput, WriteFileOptions, WriteToShardsInput, ZkAuthDeps, ZkAuthenticateRequest, ZkChallengeResponse, ZkCompiled, ZkIdentity, ZkRegisterRequest, ZkRegisterResponse };