@muhkoo/connect 0.15.0-alpha.3 → 0.15.0-alpha.4
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 +1552 -226
- package/dist/browser/index.js.map +1 -1
- package/dist/connect.d.ts +414 -23
- package/dist/server/index.js +1552 -226
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/connect.d.ts
CHANGED
|
@@ -4100,14 +4100,36 @@ interface OfflineStore {
|
|
|
4100
4100
|
* Replays are idempotent by construction (kv/db are LWW-by-key, messages dedupe
|
|
4101
4101
|
* by `clientId`, file PUTs are content-addressed), so re-running a partially
|
|
4102
4102
|
* drained queue is safe.
|
|
4103
|
+
*
|
|
4104
|
+
* Every tab of an origin shares the queue. Given a `tryLock`, a drain runs
|
|
4105
|
+
* only while holding `muhkoo:offline-drain:<commitment>`, so two tabs coming
|
|
4106
|
+
* back online replay it once between them, not once each.
|
|
4103
4107
|
*/
|
|
4104
4108
|
|
|
4105
4109
|
type Replayer = (entry: QueueEntry) => Promise<void>;
|
|
4110
|
+
/**
|
|
4111
|
+
* Run `fn` holding lock `name` if no one else holds it: true once it has
|
|
4112
|
+
* run, false - without running it - when another holder has it. Web Locks'
|
|
4113
|
+
* `ifAvailable` in a browser tab; see `core/crossTab.ts`.
|
|
4114
|
+
*/
|
|
4115
|
+
type TryLock = (name: string, fn: () => Promise<void>) => Promise<boolean>;
|
|
4116
|
+
interface OutboundQueueOptions {
|
|
4117
|
+
/**
|
|
4118
|
+
* The lock that keeps two tabs from draining at once. Every tab of an
|
|
4119
|
+
* origin shares one IndexedDB queue, and each replayed all of it when it
|
|
4120
|
+
* came back online: two tabs, every queued write twice. Absent (Node,
|
|
4121
|
+
* tests), every drain runs, as before.
|
|
4122
|
+
*/
|
|
4123
|
+
tryLock?: TryLock;
|
|
4124
|
+
/** Whose drain lock to take: the signed-in user's. With no one signed in, the drain runs unlocked. */
|
|
4125
|
+
commitment?: () => string | null;
|
|
4126
|
+
}
|
|
4106
4127
|
declare class OutboundQueue {
|
|
4107
4128
|
private readonly store;
|
|
4129
|
+
private readonly opts;
|
|
4108
4130
|
private readonly replayers;
|
|
4109
4131
|
private draining;
|
|
4110
|
-
constructor(store: OfflineStore);
|
|
4132
|
+
constructor(store: OfflineStore, opts?: OutboundQueueOptions);
|
|
4111
4133
|
/** A domain registers how to replay its mutations. */
|
|
4112
4134
|
register(domain: QueueEntry["domain"], replayer: Replayer): void;
|
|
4113
4135
|
/** Record a mutation for later replay; resolves with its assigned seq. */
|
|
@@ -4120,6 +4142,13 @@ declare class OutboundQueue {
|
|
|
4120
4142
|
* remaining entries for the next attempt.
|
|
4121
4143
|
*/
|
|
4122
4144
|
drain(): Promise<void>;
|
|
4145
|
+
/**
|
|
4146
|
+
* One drain, holding the device-wide drain lock where there is one. A
|
|
4147
|
+
* tab that finds another tab holding it leaves the queue to that one,
|
|
4148
|
+
* which is replaying it already and removes each entry as it lands - so
|
|
4149
|
+
* a drain after it finds only what it left.
|
|
4150
|
+
*/
|
|
4151
|
+
private drainOnce;
|
|
4123
4152
|
private runDrain;
|
|
4124
4153
|
}
|
|
4125
4154
|
|
|
@@ -4249,6 +4278,12 @@ interface OfflineManagerDeps {
|
|
|
4249
4278
|
session: SessionState;
|
|
4250
4279
|
/** Whether offline support is active (browser) vs a no-op (Node/Workers). */
|
|
4251
4280
|
enabled: boolean;
|
|
4281
|
+
/**
|
|
4282
|
+
* The drain lock the tabs of this origin share - Web Locks in a browser
|
|
4283
|
+
* tab. Absent, every tab drains the shared queue itself, as before. See
|
|
4284
|
+
* `OutboundQueue`.
|
|
4285
|
+
*/
|
|
4286
|
+
locks?: TryLock;
|
|
4252
4287
|
}
|
|
4253
4288
|
declare class OfflineManager {
|
|
4254
4289
|
/** True in browsers with IndexedDB; false when running over a NoopStore. */
|
|
@@ -6757,6 +6792,114 @@ declare class VfsLimitError extends Error {
|
|
|
6757
6792
|
constructor(limit: VfsLimitError["limit"], max: number, path: string, at: string, doing?: string);
|
|
6758
6793
|
}
|
|
6759
6794
|
|
|
6795
|
+
/**
|
|
6796
|
+
* How `client.vfs` orders writes of one directory record between the tabs of
|
|
6797
|
+
* an app on one device. Internal: nothing re-exports this module, and it is
|
|
6798
|
+
* not public API.
|
|
6799
|
+
*
|
|
6800
|
+
* The personal space keeps whichever write of a key arrives last, so two tabs
|
|
6801
|
+
* that each edit a copy of a folder and write it lose one tab's edit. A
|
|
6802
|
+
* coordinator gives every namespace on the device one lock per record, held
|
|
6803
|
+
* from the decision to write until the write has landed or failed, and a
|
|
6804
|
+
* count of each record's writes, which a writer stores before it lets go of
|
|
6805
|
+
* the lock and the next holder reads to tell whether its copy is current.
|
|
6806
|
+
* It also tells the others which record was written, as a hint: that can
|
|
6807
|
+
* reach them after the next holder has decided, or never. And it gives
|
|
6808
|
+
* each file or folder being moved or deleted a lock, which a move or delete
|
|
6809
|
+
* of it elsewhere takes only if it is free, and refuses otherwise (see
|
|
6810
|
+
* `holdMoving`). `Client` builds one
|
|
6811
|
+
* from Web Locks and a BroadcastChannel in a browser tab (see
|
|
6812
|
+
* `core/crossTab.ts`); without one, writes are ordered within one namespace
|
|
6813
|
+
* only, as they always were.
|
|
6814
|
+
*/
|
|
6815
|
+
interface VfsCoordinator {
|
|
6816
|
+
/**
|
|
6817
|
+
* Run `fn` holding the device-wide lock for record `id`, and settle as it
|
|
6818
|
+
* does. Where the runtime refuses the lock to this document, as it then
|
|
6819
|
+
* does to every tab of the app, `fn` runs without it.
|
|
6820
|
+
*/
|
|
6821
|
+
lock<T>(id: string, fn: () => Promise<T>): Promise<T>;
|
|
6822
|
+
/** Tell every other namespace that this one has just written record `id`. Called while holding its lock. */
|
|
6823
|
+
announce(id: string): void;
|
|
6824
|
+
/**
|
|
6825
|
+
* Call `handler` with the id of each record another namespace announces -
|
|
6826
|
+
* or with null when announcements may have been missed, because this one
|
|
6827
|
+
* has only just started hearing them, or now hears them for someone else,
|
|
6828
|
+
* so that every record held must be taken as written elsewhere. Returns a
|
|
6829
|
+
* function that stops it.
|
|
6830
|
+
*/
|
|
6831
|
+
onAnnounce(handler: (id: string | null) => void): () => void;
|
|
6832
|
+
/**
|
|
6833
|
+
* Make sure announcements for whoever is signed in now are being heard.
|
|
6834
|
+
* Cheap; called before every read of a record from the store, so that
|
|
6835
|
+
* nothing is read before this namespace can hear of a later write of it.
|
|
6836
|
+
*/
|
|
6837
|
+
listen(): void;
|
|
6838
|
+
/**
|
|
6839
|
+
* How often each record in `ids` has been written by any namespace on
|
|
6840
|
+
* the device, for whoever is signed in: one counter each, in order, read
|
|
6841
|
+
* at one moment from storage every tab of the app shares (IndexedDB, in
|
|
6842
|
+
* a browser). Null where it cannot be told: the storage cannot be read,
|
|
6843
|
+
* or does not answer within a few seconds, or a write of the record has
|
|
6844
|
+
* begun and not been counted (see `begin`). Never rejects.
|
|
6845
|
+
*
|
|
6846
|
+
* A copy of a record fetched after its counter was read holds every
|
|
6847
|
+
* write the counter counts. Read again once its holder has taken a lock
|
|
6848
|
+
* that another tab held while it wrote the record - the record's own, or
|
|
6849
|
+
* a move lock - a counter that has not moved says no other tab has
|
|
6850
|
+
* written it since: unlike an announcement, a count is stored before
|
|
6851
|
+
* the writer lets go of its locks. See `VfsNamespace.sendLocked`.
|
|
6852
|
+
*/
|
|
6853
|
+
counters(ids: readonly string[]): Promise<Array<string | null>>;
|
|
6854
|
+
/**
|
|
6855
|
+
* Called holding record `id`'s lock, before deciding whether a copy of it
|
|
6856
|
+
* is current: its counter as the last tab to write it left it - one whose
|
|
6857
|
+
* write began and was never counted, which no copy holds, included. And
|
|
6858
|
+
* from then, stored with it, a mark that a write of it has begun, which
|
|
6859
|
+
* `counters` reports as null until `bump`: a tab that goes, or cannot
|
|
6860
|
+
* count its write, in between leaves every tab reading the record again.
|
|
6861
|
+
* Null when the storage could not be read and marked within a few
|
|
6862
|
+
* seconds. Never rejects.
|
|
6863
|
+
*/
|
|
6864
|
+
begin(id: string): Promise<string | null>;
|
|
6865
|
+
/**
|
|
6866
|
+
* Called holding record `id`'s lock, after `begin`, once the write has
|
|
6867
|
+
* landed or failed, or nothing was written after all: count it, and
|
|
6868
|
+
* resolve to the record's new counter once that is stored - so before
|
|
6869
|
+
* the lock is let go of. Null when it could not be stored within a few
|
|
6870
|
+
* seconds. Never rejects.
|
|
6871
|
+
*/
|
|
6872
|
+
bump(id: string): Promise<string | null>;
|
|
6873
|
+
/**
|
|
6874
|
+
* Hold the lock that says entry `id` - a file or a folder, by its id in
|
|
6875
|
+
* the tree - is being moved or deleted on this device, if no one holds
|
|
6876
|
+
* it. Never waits: resolves to null when another holder has it, in this
|
|
6877
|
+
* tab or another, and otherwise to the function that lets go of it. A
|
|
6878
|
+
* tab that dies lets go of everything it held. With no one signed in it
|
|
6879
|
+
* holds nothing, and resolves to a function that does nothing; so too
|
|
6880
|
+
* where the runtime refuses the lock to this document, as it then does
|
|
6881
|
+
* to every tab of the app.
|
|
6882
|
+
*
|
|
6883
|
+
* `shared` holds a folder's lock as a place on the way to where a move
|
|
6884
|
+
* is putting something. Any number of shared holders hold it at once,
|
|
6885
|
+
* in any tab; a holder that is not shared cannot have it while they do,
|
|
6886
|
+
* nor they while it does.
|
|
6887
|
+
*
|
|
6888
|
+
* A move marks its entry before it puts it in its second place, and a
|
|
6889
|
+
* mark cannot tell a move still writing from one that was interrupted.
|
|
6890
|
+
* Another tab took the first for the second: it finished the move too,
|
|
6891
|
+
* naming the entry in two places, or let go of what the move was about
|
|
6892
|
+
* to put somewhere else. So a move holds this from before it marks until
|
|
6893
|
+
* it has taken the entry from where it was, a delete holds it for all it
|
|
6894
|
+
* is deleting, and either refuses when it cannot have it. A move also
|
|
6895
|
+
* holds the folder it is moving into, and every folder above that one,
|
|
6896
|
+
* shared, for as long: a move into a folder that another tab was
|
|
6897
|
+
* deleting put what it moved in a record the delete then purged. See
|
|
6898
|
+
* `VfsNamespace.rename` and `VfsNamespace.delete`.
|
|
6899
|
+
*/
|
|
6900
|
+
holdMoving(id: string, shared?: boolean): Promise<(() => void) | null>;
|
|
6901
|
+
}
|
|
6902
|
+
|
|
6760
6903
|
/**
|
|
6761
6904
|
* `client.vfs` — a real filesystem over Muhkoo primitives.
|
|
6762
6905
|
*
|
|
@@ -6769,21 +6912,25 @@ declare class VfsLimitError extends Error {
|
|
|
6769
6912
|
*
|
|
6770
6913
|
* Every mutation is a read-modify-write of exactly ONE directory record, so a
|
|
6771
6914
|
* write cannot leave the tree half-updated: either the parent names the new
|
|
6772
|
-
* child or it does not.
|
|
6773
|
-
*
|
|
6774
|
-
*
|
|
6775
|
-
*
|
|
6776
|
-
*
|
|
6777
|
-
*
|
|
6778
|
-
*
|
|
6915
|
+
* child or it does not. A VFS write sends no HLC and the personal space has
|
|
6916
|
+
* no compare-and-swap: of two writes of one key it keeps whichever arrives
|
|
6917
|
+
* last.
|
|
6918
|
+
*
|
|
6919
|
+
* Within ONE namespace, writes of a record are sent one at a time, in the
|
|
6920
|
+
* order they were made - edits made while one is in flight go out together
|
|
6921
|
+
* in the next (see `queue`) - and a read that has to fetch a record waits for
|
|
6922
|
+
* its write in flight (see `writing`). Every edit of a record is made to one
|
|
6923
|
+
* in-memory copy of it, and that copy is what is written (see `mutate`).
|
|
6924
|
+
*
|
|
6925
|
+
* Between the tabs of an app on one device, a coordinator (`VfsCoordinator`;
|
|
6926
|
+
* `Client` wires one in a browser tab) gives each record one lock, and a tab
|
|
6927
|
+
* reads a record another tab has written again before its next write of it
|
|
6928
|
+
* (see `sendLocked`). Between devices - or a browser and the CLI - two writes
|
|
6929
|
+
* of the same directory are still last-writer-wins, and the other edit is
|
|
6930
|
+
* lost: that takes a compare-and-swap at the server. Orphaned records (a
|
|
6931
|
+
* directory whose parent entry lost the race) are unreachable rather than
|
|
6932
|
+
* corrupting - they cost storage until a sweep, the trade this shape makes in
|
|
6779
6933
|
* exchange for single-record writes.
|
|
6780
|
-
*
|
|
6781
|
-
* Within ONE tab, writes of a record are queued and sent one at a time, in the
|
|
6782
|
-
* order they were made, and a read that has to fetch a record waits for its
|
|
6783
|
-
* write in flight (see `writing`). Every edit of a record is made to one
|
|
6784
|
-
* in-memory copy of it, and that copy is what is written (see `mutate`). All
|
|
6785
|
-
* of this is per namespace instance only; nothing orders writes across tabs
|
|
6786
|
-
* or devices - that would take a compare-and-swap at the server.
|
|
6787
6934
|
*/
|
|
6788
6935
|
|
|
6789
6936
|
/**
|
|
@@ -6849,6 +6996,13 @@ interface VfsNamespaceDeps {
|
|
|
6849
6996
|
entries?: number;
|
|
6850
6997
|
pathChars?: number;
|
|
6851
6998
|
};
|
|
6999
|
+
/**
|
|
7000
|
+
* Orders writes of a record with the other tabs of this app on the
|
|
7001
|
+
* device. `Client` passes one in a browser tab; without it - Node, a
|
|
7002
|
+
* test, a runtime with no Web Locks - writes are ordered within this
|
|
7003
|
+
* namespace only. See `VfsCoordinator`.
|
|
7004
|
+
*/
|
|
7005
|
+
coordinator?: VfsCoordinator;
|
|
6852
7006
|
}
|
|
6853
7007
|
declare class VfsNamespace {
|
|
6854
7008
|
private readonly deps;
|
|
@@ -6892,6 +7046,81 @@ declare class VfsNamespace {
|
|
|
6892
7046
|
* `openDirById`.
|
|
6893
7047
|
*/
|
|
6894
7048
|
private readonly writing;
|
|
7049
|
+
/**
|
|
7050
|
+
* Every entry this namespace is moving right now, by id.
|
|
7051
|
+
*
|
|
7052
|
+
* A move between two directories marks the entry before it puts it in
|
|
7053
|
+
* the second (see `rename`), and a mark is all a later operation can
|
|
7054
|
+
* see. It cannot tell a move still writing from one that was
|
|
7055
|
+
* interrupted, and was taken for the second: a delete that began after
|
|
7056
|
+
* a move had marked a folder looked for the folder's other half, found
|
|
7057
|
+
* none yet, and purged it while the move was putting it in its new
|
|
7058
|
+
* place; a second move of a file finished the "interrupted" move and
|
|
7059
|
+
* left it named in two places. So a move holds its entry here until it
|
|
7060
|
+
* has taken it from where it was, and `rename` and `delete` refuse an
|
|
7061
|
+
* entry that is here - or, for a delete, a folder holding one. A delete
|
|
7062
|
+
* holds what it deletes the same way: see `deleting`.
|
|
7063
|
+
*
|
|
7064
|
+
* This set is one namespace's. With a coordinator, a move also holds
|
|
7065
|
+
* the entry's move lock for every tab on the device, for as long as the
|
|
7066
|
+
* entry is here: see `VfsCoordinator.holdMoving`.
|
|
7067
|
+
*/
|
|
7068
|
+
private readonly inMotion;
|
|
7069
|
+
/**
|
|
7070
|
+
* What each delete under way in this namespace is deleting, by entry id,
|
|
7071
|
+
* one set per delete: its target from the moment it has found the target
|
|
7072
|
+
* not in `inMotion`, and everything it read below the target once it has
|
|
7073
|
+
* read it. Each delete lets go of its own set when it is done.
|
|
7074
|
+
*
|
|
7075
|
+
* A delete waits after it has read what it will let go of: on more
|
|
7076
|
+
* reads, and on a read of the whole tree for the other half of a move.
|
|
7077
|
+
* A move of any of it that started meanwhile could put it in its new
|
|
7078
|
+
* place, fail to take it from the old, and end, all before the delete's
|
|
7079
|
+
* detach. Ended, it was no longer in `inMotion`; and an entry that was
|
|
7080
|
+
* marked already showed no change. So the delete let go of what the
|
|
7081
|
+
* move had just named somewhere else. Now `rename` refuses an entry that
|
|
7082
|
+
* is here, or one on a way from the root that passes through a folder
|
|
7083
|
+
* that is: everything below a delete's target, read yet or not.
|
|
7084
|
+
*/
|
|
7085
|
+
private readonly deleting;
|
|
7086
|
+
/**
|
|
7087
|
+
* The write of each record that has not gone out yet, by id: the one
|
|
7088
|
+
* the next edit of that record joins. See `queue`.
|
|
7089
|
+
*/
|
|
7090
|
+
private readonly waiting;
|
|
7091
|
+
/**
|
|
7092
|
+
* Announcements heard from other tabs, counted. `heardAt` is the count
|
|
7093
|
+
* at the last one for each record, `missedAt` the count when some may
|
|
7094
|
+
* have been missed. A copy read after both holds every write announced:
|
|
7095
|
+
* see `current`.
|
|
7096
|
+
*/
|
|
7097
|
+
private hearing;
|
|
7098
|
+
private missedAt;
|
|
7099
|
+
private readonly heardAt;
|
|
7100
|
+
/**
|
|
7101
|
+
* Each record a write of which this namespace marked as begun and could
|
|
7102
|
+
* not count, and has said so, until one is counted. And whether it has
|
|
7103
|
+
* said that a write it could not mark or count may be lost, which it
|
|
7104
|
+
* says only once. See `notCounted`.
|
|
7105
|
+
*/
|
|
7106
|
+
private readonly uncounted;
|
|
7107
|
+
private lossWarned;
|
|
7108
|
+
/**
|
|
7109
|
+
* The copy of each record this namespace is writing under the record's
|
|
7110
|
+
* lock, by id, from when it has decided what to write until it has
|
|
7111
|
+
* counted the write, or failed to. Its counter reads as unknown
|
|
7112
|
+
* meanwhile, as this write has begun and is not counted yet, but the
|
|
7113
|
+
* copy holds every write of the record another tab has counted, and no
|
|
7114
|
+
* other tab can make one until this one lets go of the lock. See
|
|
7115
|
+
* `dropStale`.
|
|
7116
|
+
*/
|
|
7117
|
+
private readonly locked;
|
|
7118
|
+
/**
|
|
7119
|
+
* Each directory a `createDir` here has named whose write has not landed
|
|
7120
|
+
* yet, by entry id: a promise that settles - and never rejects - once
|
|
7121
|
+
* that write has landed or failed. See `mkdir`.
|
|
7122
|
+
*/
|
|
7123
|
+
private readonly naming;
|
|
6895
7124
|
private readonly historyLimit;
|
|
6896
7125
|
private readonly maxEntries;
|
|
6897
7126
|
private readonly maxPathChars;
|
|
@@ -7113,11 +7342,12 @@ declare class VfsNamespace {
|
|
|
7113
7342
|
* Delete metadata records no longer reachable from the root.
|
|
7114
7343
|
*
|
|
7115
7344
|
* These accumulate because every write touches exactly one record: if two
|
|
7116
|
-
*
|
|
7117
|
-
* whichever put arrives last (a
|
|
7118
|
-
* applies puts of one key in arrival
|
|
7119
|
-
* parent entry lost the race. The
|
|
7120
|
-
*
|
|
7345
|
+
* devices edit the same directory - or two tabs, where there is no
|
|
7346
|
+
* coordinator - the personal space keeps whichever put arrives last (a
|
|
7347
|
+
* VFS write sends no HLC, and the space applies puts of one key in arrival
|
|
7348
|
+
* order), which can leave a child whose parent entry lost the race. The
|
|
7349
|
+
* per-record queue and the coordinator order writes within one device
|
|
7350
|
+
* only. Unreachable is harmless —
|
|
7121
7351
|
* it is invisible and undecryptable-by-nobody — but it costs storage, so
|
|
7122
7352
|
* this reclaims it.
|
|
7123
7353
|
*
|
|
@@ -7157,6 +7387,15 @@ declare class VfsNamespace {
|
|
|
7157
7387
|
* the error names whichever asked first.
|
|
7158
7388
|
*/
|
|
7159
7389
|
private openDirById;
|
|
7390
|
+
/**
|
|
7391
|
+
* Fetch record `id` from the store and open it. Whatever another tab
|
|
7392
|
+
* announced before the fetch began is in what it returns (see
|
|
7393
|
+
* `current`), and so is every write its counter counts: read here, or
|
|
7394
|
+
* given as `counter` (see `OpenDir.counter`).
|
|
7395
|
+
*/
|
|
7396
|
+
private fetchRecord;
|
|
7397
|
+
/** Record `id`'s write counter now: see `OpenDir.counter`. */
|
|
7398
|
+
private counterOf;
|
|
7160
7399
|
/**
|
|
7161
7400
|
* Turn a decrypted record into an OpenDir, or throw.
|
|
7162
7401
|
*
|
|
@@ -7179,8 +7418,18 @@ declare class VfsNamespace {
|
|
|
7179
7418
|
*
|
|
7180
7419
|
* So `edit` must take what it writes from the record it is given, not
|
|
7181
7420
|
* from anything read off `dir` before an await - and re-check whatever it
|
|
7182
|
-
* relies on from then, throwing if another write changed it
|
|
7183
|
-
* false writes nothing after all.
|
|
7421
|
+
* relies on from then, throwing if another write changed it, before it
|
|
7422
|
+
* changes anything. Returning false writes nothing after all.
|
|
7423
|
+
*
|
|
7424
|
+
* The write that carries the edit may carry others, made while an
|
|
7425
|
+
* earlier write of the record was in flight (see `queue`): it lands, or
|
|
7426
|
+
* fails, for all of them at once.
|
|
7427
|
+
*
|
|
7428
|
+
* With a coordinator, the edit may be made a second time, to the record
|
|
7429
|
+
* as another tab left it, and refused then (see `replay`): an edit must
|
|
7430
|
+
* check everything before it changes anything, and whatever it sets
|
|
7431
|
+
* outside `node` and `record` must be safe to set again, since each run
|
|
7432
|
+
* overwrites the last.
|
|
7184
7433
|
*/
|
|
7185
7434
|
private mutate;
|
|
7186
7435
|
/**
|
|
@@ -7206,6 +7455,112 @@ declare class VfsNamespace {
|
|
|
7206
7455
|
private reopen;
|
|
7207
7456
|
/** Make `dir` the cached copy of its record - unless the cache has been cleared since it was read. */
|
|
7208
7457
|
private adopt;
|
|
7458
|
+
/** After an edit of `copy`: its time, and any entry it cannot read that the edit replaced. */
|
|
7459
|
+
private touch;
|
|
7460
|
+
/**
|
|
7461
|
+
* The write that will carry the edit just made to `copy`.
|
|
7462
|
+
*
|
|
7463
|
+
* Writes of a record go out one at a time, each once the one before it
|
|
7464
|
+
* has landed or failed (see `writing`), and each seals the record as it
|
|
7465
|
+
* stands when it goes out. So a write still waiting carries every edit
|
|
7466
|
+
* made while it waits, and an edit made then joins it instead of
|
|
7467
|
+
* queueing a write of its own: a burst of edits of one directory while a
|
|
7468
|
+
* write of it is in flight costs two writes, not one per edit. Each is a
|
|
7469
|
+
* billed write; a 20-file upload into one folder cost twenty.
|
|
7470
|
+
*/
|
|
7471
|
+
private queue;
|
|
7472
|
+
/**
|
|
7473
|
+
* Send `batch`: from here on, an edit of its record goes in the next
|
|
7474
|
+
* write. With a coordinator, holding the lock every tab of the device
|
|
7475
|
+
* takes to write this record - see `sendLocked`.
|
|
7476
|
+
*/
|
|
7477
|
+
private send;
|
|
7478
|
+
/** Stop `batch` taking more edits, as it is sealed. */
|
|
7479
|
+
private close;
|
|
7480
|
+
/**
|
|
7481
|
+
* Send `batch` while no other tab can write its record.
|
|
7482
|
+
*
|
|
7483
|
+
* If another tab wrote the record since this copy was read, the copy is
|
|
7484
|
+
* out of date, and writing it would undo that tab's write. So it is read
|
|
7485
|
+
* again, here, under the lock, and every edit the batch carries is made
|
|
7486
|
+
* again to what was read (see `replay`). A copy no other tab has written
|
|
7487
|
+
* over is sent as it is: one tab on its own costs no extra request.
|
|
7488
|
+
*
|
|
7489
|
+
* Which it is, the record's write counter says (see
|
|
7490
|
+
* `VfsCoordinator.counters`). Read once the lock is granted, it counts
|
|
7491
|
+
* every write of the record another tab made, because each counts its
|
|
7492
|
+
* write, and waits for the count to be stored, before it lets go of the
|
|
7493
|
+
* lock. If it has moved since the copy was read, or cannot be told, the
|
|
7494
|
+
* copy is read again. Whether this tab has heard of another tab's write
|
|
7495
|
+
* does not decide it: an announcement can reach this tab after the
|
|
7496
|
+
* lock does, or never. One it has heard of can only add a read.
|
|
7497
|
+
*
|
|
7498
|
+
* The write is counted once it has landed or failed - one that failed
|
|
7499
|
+
* may have landed even so - and the other tabs are then told of it,
|
|
7500
|
+
* all before the lock is let go of.
|
|
7501
|
+
*/
|
|
7502
|
+
private sendLocked;
|
|
7503
|
+
/**
|
|
7504
|
+
* Say that a write of `copy`'s record could not be counted.
|
|
7505
|
+
*
|
|
7506
|
+
* `marked`: `VfsCoordinator.begin` stored its mark, which stays until a
|
|
7507
|
+
* count can be stored, so every tab reads the record again before it
|
|
7508
|
+
* writes it. Said once for each record, until a write of it is counted.
|
|
7509
|
+
*
|
|
7510
|
+
* Not marked, a tab whose IndexedDB works may take its copy for current
|
|
7511
|
+
* and write it over this write. Said once for this namespace, whatever
|
|
7512
|
+
* the record: where IndexedDB cannot be used at all, no write of any
|
|
7513
|
+
* folder is counted, and a warning for each said nothing new. And only
|
|
7514
|
+
* where another tab can count its writes can one be lost, which the
|
|
7515
|
+
* warning says: where no tab can, every tab reads each folder again.
|
|
7516
|
+
*/
|
|
7517
|
+
private notCounted;
|
|
7518
|
+
/**
|
|
7519
|
+
* Make every edit in `batch` again, in order, to `fresh` - the record as
|
|
7520
|
+
* another tab left it - and make that the copy. An edit that no longer
|
|
7521
|
+
* applies throws, as it would have the first time, and is left out; its
|
|
7522
|
+
* caller gets what it threw. Every edit checks before it changes
|
|
7523
|
+
* anything (see `mutate`), so one that throws has changed nothing. True
|
|
7524
|
+
* when what is left changes the record, and so needs writing.
|
|
7525
|
+
*/
|
|
7526
|
+
private replay;
|
|
7527
|
+
/**
|
|
7528
|
+
* Another tab wrote record `id` - or, null, this namespace may have
|
|
7529
|
+
* missed some announcements. What the cache holds is read again when
|
|
7530
|
+
* next asked for, as a change frame from the personal space would have
|
|
7531
|
+
* it, and a copy read before then is read again before the next write
|
|
7532
|
+
* of its record (see `current`). A hint, not a guarantee: an
|
|
7533
|
+
* announcement can reach this tab after the next lock does, or never.
|
|
7534
|
+
* What decides whether a copy may be written over, or relied on under a
|
|
7535
|
+
* move's or a delete's locks, is the record's counter: see `sendLocked`
|
|
7536
|
+
* and `dropStale`.
|
|
7537
|
+
*/
|
|
7538
|
+
private heard;
|
|
7539
|
+
/**
|
|
7540
|
+
* Does `copy` hold every write of its record another tab has announced
|
|
7541
|
+
* that this one has heard of? See `heard`. Only ever a reason to read it
|
|
7542
|
+
* again, never to take it for current: see `sendLocked`.
|
|
7543
|
+
*/
|
|
7544
|
+
private current;
|
|
7545
|
+
/**
|
|
7546
|
+
* Drop from the cache every copy of a record in `ids` that may not hold
|
|
7547
|
+
* every write of it another tab has made: its counter has moved since
|
|
7548
|
+
* the copy was read, or cannot be told, or the copy is still being read.
|
|
7549
|
+
* Returns every id whose copy here is not known to be current - those,
|
|
7550
|
+
* and those not cached - so that the next read of each fetches it again,
|
|
7551
|
+
* once any write of it in flight here has landed or failed. Not a copy
|
|
7552
|
+
* this tab is writing under its lock (see `locked`): its counter reads
|
|
7553
|
+
* as unknown only because that write is not counted yet, and dropped,
|
|
7554
|
+
* the next read would wait for the write.
|
|
7555
|
+
*
|
|
7556
|
+
* The counters are read in one go, after the caller has taken the locks
|
|
7557
|
+
* it relies on: another tab counts each write of a record before it lets
|
|
7558
|
+
* go of the locks it held while writing it, the record's own and any
|
|
7559
|
+
* move lock, so what it wrote before letting go of one of them is
|
|
7560
|
+
* counted by then. Its announcements may not have reached this tab yet,
|
|
7561
|
+
* or ever. See `sendLocked`.
|
|
7562
|
+
*/
|
|
7563
|
+
private dropStale;
|
|
7209
7564
|
/**
|
|
7210
7565
|
* Seal a directory record as it stands NOW and put it in the store.
|
|
7211
7566
|
*
|
|
@@ -7230,8 +7585,44 @@ declare class VfsNamespace {
|
|
|
7230
7585
|
*
|
|
7231
7586
|
* `moving` says whether anything in it is marked as half of an
|
|
7232
7587
|
* interrupted move, which is what makes a delete look for the other half.
|
|
7588
|
+
*
|
|
7589
|
+
* `ids` is every entry id in it, and `shape` what each record named when
|
|
7590
|
+
* it was read: see `currentSubtree`.
|
|
7233
7591
|
*/
|
|
7234
7592
|
private subtree;
|
|
7593
|
+
/**
|
|
7594
|
+
* The records a recursive delete read, as they are now - or null when
|
|
7595
|
+
* one has changed since in a way that purging it would get wrong.
|
|
7596
|
+
*
|
|
7597
|
+
* The delete decided what to let go of, and whether to look for the
|
|
7598
|
+
* other half of a move, from what it read; then it waited, on reads and
|
|
7599
|
+
* on the write of its parent. A record that is no longer named by the
|
|
7600
|
+
* record it was read in has been moved out, and is not this delete's to
|
|
7601
|
+
* purge; an entry marked since it was read is being moved, and is about
|
|
7602
|
+
* to be named somewhere the delete never looked. Purging either purged
|
|
7603
|
+
* the folder a move had just put somewhere else. Anything else - a file
|
|
7604
|
+
* saved into one of them, or moved out - is purged as it now stands,
|
|
7605
|
+
* which is why the copies to purge are what this returns.
|
|
7606
|
+
*
|
|
7607
|
+
* Synchronous, for an edit. A record whose copy is not to hand counts as
|
|
7608
|
+
* changed.
|
|
7609
|
+
*
|
|
7610
|
+
* `held`, with a coordinator, is every entry whose move lock the delete
|
|
7611
|
+
* holds. An entry named since the records were read - saved or moved in
|
|
7612
|
+
* - is not among them, so nothing stops another tab moving it out while
|
|
7613
|
+
* the delete writes the parent, and purging it then let go of what that
|
|
7614
|
+
* move had put somewhere else. So with `held`, that counts as changed
|
|
7615
|
+
* too, and the delete is tried again from the start.
|
|
7616
|
+
*/
|
|
7617
|
+
private currentSubtree;
|
|
7618
|
+
/**
|
|
7619
|
+
* Hold the move lock of every entry in `ids` - see
|
|
7620
|
+
* `VfsCoordinator.holdMoving` - or of none: null when another holder has
|
|
7621
|
+
* any of them, and then nothing is held. Otherwise the function that
|
|
7622
|
+
* lets go of them all. Asked for all at once: none of them waits.
|
|
7623
|
+
* `shared` holds them as the folders a move goes into.
|
|
7624
|
+
*/
|
|
7625
|
+
private holdAll;
|
|
7235
7626
|
/**
|
|
7236
7627
|
* Delete these records and let go of every file in them. The second half
|
|
7237
7628
|
* of a recursive delete, run only once the subtree is detached. Cannot
|
|
@@ -9102,7 +9493,7 @@ declare function getId(row: {
|
|
|
9102
9493
|
* expect (and isn't serving a stale cached bundle). Keep this in sync with
|
|
9103
9494
|
* `package.json` `version`.
|
|
9104
9495
|
*/
|
|
9105
|
-
declare const VERSION = "0.15.0-alpha.
|
|
9496
|
+
declare const VERSION = "0.15.0-alpha.4";
|
|
9106
9497
|
|
|
9107
9498
|
/**
|
|
9108
9499
|
* The SDK's process-global logger.
|