diff --git a/packages/automerge-repo/src/DocHandle.ts b/packages/automerge-repo/src/DocHandle.ts index 64db33b62..4b2a3c2dd 100644 --- a/packages/automerge-repo/src/DocHandle.ts +++ b/packages/automerge-repo/src/DocHandle.ts @@ -99,16 +99,9 @@ export class DocHandle extends EventEmitter> { on: { REQUEST: "requesting", DOC_READY: "ready", - AWAIT_NETWORK: "awaitingNetwork", }, after: { [delay]: "unavailable" }, }, - awaitingNetwork: { - on: { - DOC_READY: "ready", - NETWORK_READY: "requesting" - }, - }, requesting: { on: { DOC_UNAVAILABLE: "unavailable", @@ -429,17 +422,6 @@ export class DocHandle extends EventEmitter> { if (this.#state === "loading") this.#machine.send({ type: REQUEST }) } - /** @hidden */ - awaitNetwork() { - if (this.#state === "loading") this.#machine.send({ type: AWAIT_NETWORK }) - } - - /** @hidden */ - networkReady() { - if (this.#state === "awaitingNetwork") - this.#machine.send({ type: NETWORK_READY }) - } - /** Called by the repo when the document is deleted. */ delete() { this.#machine.send({ type: DELETE }) @@ -554,8 +536,6 @@ export const HandleState = { IDLE: "idle", /** We are waiting for storage to finish loading */ LOADING: "loading", - /** We are waiting for the network to be come ready */ - AWAITING_NETWORK: "awaitingNetwork", /** We are waiting for someone in the network to respond to a sync request */ REQUESTING: "requesting", /** The document is available */ @@ -567,15 +547,8 @@ export const HandleState = { } as const export type HandleState = (typeof HandleState)[keyof typeof HandleState] -export const { - IDLE, - LOADING, - AWAITING_NETWORK, - REQUESTING, - READY, - DELETED, - UNAVAILABLE, -} = HandleState +export const { IDLE, LOADING, REQUESTING, READY, DELETED, UNAVAILABLE } = + HandleState // context @@ -598,14 +571,10 @@ type DocHandleEvent = | { type: typeof TIMEOUT } | { type: typeof DELETE } | { type: typeof DOC_UNAVAILABLE } - | { type: typeof AWAIT_NETWORK } - | { type: typeof NETWORK_READY } const FIND = "FIND" const REQUEST = "REQUEST" const DOC_READY = "DOC_READY" -const AWAIT_NETWORK = "AWAIT_NETWORK" -const NETWORK_READY = "NETWORK_READY" const UPDATE = "UPDATE" const DELETE = "DELETE" const TIMEOUT = "TIMEOUT" diff --git a/packages/automerge-repo/src/Repo.ts b/packages/automerge-repo/src/Repo.ts index 8b561083c..e80d53e16 100644 --- a/packages/automerge-repo/src/Repo.ts +++ b/packages/automerge-repo/src/Repo.ts @@ -24,7 +24,7 @@ import { SyncStatePayload } from "./synchronizer/Synchronizer.js" import type { AnyDocumentId, DocumentId, PeerId } from "./types.js" function randomPeerId() { - return "peer-" + Math.random().toString(36).slice(4) as PeerId + return ("peer-" + Math.random().toString(36).slice(4)) as PeerId } /** A Repo is a collection of documents with networking, syncing, and storage capabilities. */ @@ -88,9 +88,7 @@ export class Repo extends EventEmitter { }: DocHandleEncodedChangePayload) => { void storageSubsystem.saveDoc(handle.documentId, doc) } - handle.on("heads-changed", - throttle(saveFn, this.saveDebounceRate) - ) + handle.on("heads-changed", throttle(saveFn, this.saveDebounceRate)) } handle.on("unavailable", () => { @@ -100,18 +98,6 @@ export class Repo extends EventEmitter { }) }) - if (!this.networkSubsystem.isReady()) { - handle.awaitNetwork() - this.networkSubsystem - .whenReady() - .then(() => { - handle.networkReady() - }) - .catch(err => { - this.#log("error waiting for network", { err }) - }) - } - // Register the document with the synchronizer. This advertises our interest in the document. this.#synchronizer.addDocument(handle.documentId) }) @@ -316,7 +302,7 @@ export class Repo extends EventEmitter { /** Returns an existing handle if we have it; creates one otherwise. */ #getHandle({ - documentId + documentId, }: { /** The documentId of the handle to look up or create */ documentId: DocumentId /** If we know we're creating a new document, specify this so we can have access to it immediately */ @@ -354,7 +340,7 @@ export class Repo extends EventEmitter { // Generate a new UUID and store it in the buffer const { documentId } = parseAutomergeUrl(generateAutomergeUrl()) const handle = this.#getHandle({ - documentId + documentId, }) as DocHandle this.emit("document", { handle }) @@ -365,10 +351,10 @@ export class Repo extends EventEmitter { nextDoc = Automerge.from(initialValue) } else { nextDoc = Automerge.emptyChange(Automerge.init()) - } + } return nextDoc }) - + handle.doneLoading() return handle } @@ -438,7 +424,7 @@ export class Repo extends EventEmitter { const handle = this.#getHandle({ documentId, }) as DocHandle - + // Try to load from disk if (this.storageSubsystem) { void this.storageSubsystem.loadDoc(handle.documentId).then(loadedDoc => { @@ -447,15 +433,21 @@ export class Repo extends EventEmitter { handle.update(() => loadedDoc as Automerge.Doc) handle.doneLoading() } else { - handle.request() + this.networkSubsystem + .whenReady() + .then(() => { + handle.request() + }) + .catch(err => { + this.#log("error waiting for network", { err }) + }) + this.emit("document", { handle }) } }) - } else { handle.request() + this.emit("document", { handle }) } - - this.emit("document", { handle }) return handle } diff --git a/packages/automerge-repo/src/network/NetworkSubsystem.ts b/packages/automerge-repo/src/network/NetworkSubsystem.ts index 81f729487..b4ab1a5c7 100644 --- a/packages/automerge-repo/src/network/NetworkSubsystem.ts +++ b/packages/automerge-repo/src/network/NetworkSubsystem.ts @@ -157,7 +157,10 @@ export class NetworkSubsystem extends EventEmitter { } isReady = () => { - return this.#readyAdapterCount === this.#adapters.length + return ( + this.#adapters.length === 0 || + this.#readyAdapterCount === this.#adapters.length + ) } whenReady = async () => { diff --git a/packages/automerge-repo/src/synchronizer/CollectionSynchronizer.ts b/packages/automerge-repo/src/synchronizer/CollectionSynchronizer.ts index ddfb4820f..b6183b998 100644 --- a/packages/automerge-repo/src/synchronizer/CollectionSynchronizer.ts +++ b/packages/automerge-repo/src/synchronizer/CollectionSynchronizer.ts @@ -79,8 +79,7 @@ export class CollectionSynchronizer extends Synchronizer { */ async receiveMessage(message: DocMessage) { log( - `onSyncMessage: ${message.senderId}, ${message.documentId}, ${ - "data" in message ? message.data.byteLength + "bytes" : "" + `onSyncMessage: ${message.senderId}, ${message.documentId}, ${"data" in message ? message.data.byteLength + "bytes" : "" }` ) diff --git a/packages/automerge-repo/test/Repo.test.ts b/packages/automerge-repo/test/Repo.test.ts index 89386ef46..d848241bb 100644 --- a/packages/automerge-repo/test/Repo.test.ts +++ b/packages/automerge-repo/test/Repo.test.ts @@ -198,8 +198,11 @@ describe("Repo", () => { it("doesn't find a document that doesn't exist", async () => { const { repo } = setup() const handle = repo.find(generateAutomergeUrl()) - assert.equal(handle.isReady(), false) + await handle.whenReady(["ready", "unavailable"]) + + assert.equal(handle.isReady(), false) + assert.equal(handle.state, "unavailable") const doc = await handle.doc() assert.equal(doc, undefined) }) @@ -221,6 +224,7 @@ describe("Repo", () => { handle.on("unavailable", () => { wasUnavailable = true }) + await pause(50) assert.equal(wasUnavailable, false) @@ -400,6 +404,8 @@ describe("Repo", () => { d.count = 1 }) + await repo.flush() + for (let i = 0; i < 3; i++) { const repo2 = new Repo({ storage,