@muhkoo/connect 0.10.14-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/browser/index.js +1217 -78
- package/dist/browser/index.js.map +1 -1
- package/dist/connect.d.ts +402 -6
- package/dist/server/index.js +1217 -78
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
/**
|
|
@@ -2966,10 +2968,6 @@ interface ZkAuthDeps {
|
|
|
2966
2968
|
circuits: CircuitUrls;
|
|
2967
2969
|
session: SessionState;
|
|
2968
2970
|
}
|
|
2969
|
-
/**
|
|
2970
|
-
* ZK identity auth. One instance per {@link Client}; reads/writes the shared
|
|
2971
|
-
* {@link SessionState}.
|
|
2972
|
-
*/
|
|
2973
2971
|
declare class ZkAuth {
|
|
2974
2972
|
private readonly deps;
|
|
2975
2973
|
constructor(deps: ZkAuthDeps);
|
|
@@ -3184,6 +3182,63 @@ declare class ZkAuth {
|
|
|
3184
3182
|
* passwordless (passkey) login, both of which recover the same seed.
|
|
3185
3183
|
*/
|
|
3186
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;
|
|
3187
3242
|
/** Poseidon commitment for an identity — the value the server stores. */
|
|
3188
3243
|
private commitmentFor;
|
|
3189
3244
|
/**
|
|
@@ -3766,6 +3821,8 @@ interface StorageChangeEvent<T = unknown> {
|
|
|
3766
3821
|
}
|
|
3767
3822
|
declare class KvNamespace {
|
|
3768
3823
|
private readonly deps;
|
|
3824
|
+
/** One personal-space socket, shared by every subscriber. */
|
|
3825
|
+
private feed;
|
|
3769
3826
|
private cipher;
|
|
3770
3827
|
private cipherIdentity;
|
|
3771
3828
|
constructor(deps: KvNamespaceDeps);
|
|
@@ -3789,6 +3846,20 @@ declare class KvNamespace {
|
|
|
3789
3846
|
* Requires a `WebSocket` global (browsers; Node 22+ or a `ws` shim).
|
|
3790
3847
|
*/
|
|
3791
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;
|
|
3792
3863
|
private dispatchChange;
|
|
3793
3864
|
/** Decode a stored value: decrypt envelopes, pass plaintext through. */
|
|
3794
3865
|
private decode;
|
|
@@ -4915,9 +4986,20 @@ declare class SpaceNamespace {
|
|
|
4915
4986
|
* Create a new space: generate its keypair (public key = id), register
|
|
4916
4987
|
* metadata, mint the initial group key, and connect. Returns the open Space.
|
|
4917
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
|
+
*/
|
|
4918
4999
|
createSpace(opts?: {
|
|
4919
5000
|
historyPolicy?: HistoryPolicy;
|
|
4920
5001
|
private?: boolean;
|
|
5002
|
+
messaging?: boolean;
|
|
4921
5003
|
}): Promise<Space>;
|
|
4922
5004
|
/** Join an existing space by id (its public key). Resolves once a key arrives. */
|
|
4923
5005
|
joinSpace(spaceId: string, opts?: {
|
|
@@ -5379,6 +5461,318 @@ declare class AccessTokensNamespace {
|
|
|
5379
5461
|
private path;
|
|
5380
5462
|
}
|
|
5381
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
|
+
|
|
5382
5776
|
/** The hosted Muhkoo Accelerator — the default {@link ClientOptions.baseUrl}. */
|
|
5383
5777
|
declare const DEFAULT_BASE_URL = "https://api.muhkoo.dev";
|
|
5384
5778
|
/** The hosted auth SPA — the default {@link ClientOptions.authBaseUrl}. */
|
|
@@ -5476,6 +5870,8 @@ declare class Client {
|
|
|
5476
5870
|
readonly db: DbNamespace;
|
|
5477
5871
|
/** File storage — `client.storage.writeFile(...)`, etc. */
|
|
5478
5872
|
readonly storage: StorageNamespace;
|
|
5873
|
+
/** Filesystem over the personal space: directories, versions, real paths. */
|
|
5874
|
+
readonly vfs: VfsNamespace;
|
|
5479
5875
|
/** Realtime messaging — `client.message.subscribe(...)`, etc. */
|
|
5480
5876
|
readonly message: MessageNamespace;
|
|
5481
5877
|
/** Fan-out group spaces — `client.space.createSpace(...)`, etc. */
|