@automerge/automerge-repo
Advanced tools
Comparing version 2.0.0-alpha.13 to 2.0.0-alpha.14
@@ -10,3 +10,3 @@ import { EventEmitter } from "eventemitter3"; | ||
import { DocSyncMetrics } from "./synchronizer/Synchronizer.js"; | ||
import type { AnyDocumentId, DocumentId, PeerId } from "./types.js"; | ||
import type { AnyDocumentId, AutomergeUrl, DocumentId, PeerId } from "./types.js"; | ||
/** A Repo is a collection of documents with networking, syncing, and storage capabilities. */ | ||
@@ -37,3 +37,3 @@ /** The `Repo` is the main entry point of this library | ||
peerMetadataByPeerId: Record<PeerId, PeerMetadata>; | ||
constructor({ storage, network, peerId, sharePolicy, isEphemeral, enableRemoteHeadsGossiping, }?: RepoConfig); | ||
constructor({ storage, network, peerId, sharePolicy, isEphemeral, enableRemoteHeadsGossiping, denylist, }?: RepoConfig); | ||
/** Returns all the handles we have cached. */ | ||
@@ -131,2 +131,8 @@ get handles(): Record<DocumentId, DocHandle<any>>; | ||
enableRemoteHeadsGossiping?: boolean; | ||
/** | ||
* A list of automerge URLs which should never be loaded regardless of what | ||
* messages are received or what the share policy is. This is useful to avoid | ||
* loading documents that are known to be too resource intensive. | ||
*/ | ||
denylist?: AutomergeUrl[]; | ||
} | ||
@@ -163,3 +169,6 @@ /** A function that determines whether we should share a document with a peer | ||
numChanges: number; | ||
} | { | ||
type: "doc-denied"; | ||
documentId: DocumentId; | ||
}; | ||
//# sourceMappingURL=Repo.d.ts.map |
@@ -43,3 +43,3 @@ import { next as Automerge } from "@automerge/automerge/slim"; | ||
#remoteHeadsGossipingEnabled = false; | ||
constructor({ storage, network = [], peerId = randomPeerId(), sharePolicy, isEphemeral = storage === undefined, enableRemoteHeadsGossiping = false, } = {}) { | ||
constructor({ storage, network = [], peerId = randomPeerId(), sharePolicy, isEphemeral = storage === undefined, enableRemoteHeadsGossiping = false, denylist = [], } = {}) { | ||
super(); | ||
@@ -60,3 +60,3 @@ this.#remoteHeadsGossipingEnabled = enableRemoteHeadsGossiping; | ||
// The synchronizer uses the network subsystem to keep documents in sync with peers. | ||
this.synchronizer = new CollectionSynchronizer(this); | ||
this.synchronizer = new CollectionSynchronizer(this, denylist); | ||
// When the synchronizer emits messages, send them to peers | ||
@@ -63,0 +63,0 @@ this.synchronizer.on("message", message => { |
import { Repo } from "../Repo.js"; | ||
import { DocMessage } from "../network/messages.js"; | ||
import { DocumentId, PeerId } from "../types.js"; | ||
import { AutomergeUrl, DocumentId, PeerId } from "../types.js"; | ||
import { DocSynchronizer } from "./DocSynchronizer.js"; | ||
@@ -13,3 +13,3 @@ import { Synchronizer } from "./Synchronizer.js"; | ||
docSynchronizers: Record<DocumentId, DocSynchronizer>; | ||
constructor(repo: Repo); | ||
constructor(repo: Repo, denylist?: AutomergeUrl[]); | ||
/** | ||
@@ -16,0 +16,0 @@ * When we receive a sync message for a document we haven't got in memory, we |
import debug from "debug"; | ||
import { stringifyAutomergeUrl } from "../AutomergeUrl.js"; | ||
import { parseAutomergeUrl, stringifyAutomergeUrl } from "../AutomergeUrl.js"; | ||
import { DocSynchronizer } from "./DocSynchronizer.js"; | ||
@@ -16,5 +16,7 @@ import { Synchronizer } from "./Synchronizer.js"; | ||
#docSetUp = {}; | ||
constructor(repo) { | ||
#denylist; | ||
constructor(repo, denylist = []) { | ||
super(); | ||
this.repo = repo; | ||
this.#denylist = denylist.map(url => parseAutomergeUrl(url).documentId); | ||
} | ||
@@ -72,2 +74,14 @@ /** Returns a synchronizer for the given document, creating one if it doesn't already exist. */ | ||
} | ||
if (this.#denylist.includes(documentId)) { | ||
this.emit("metrics", { | ||
type: "doc-denied", | ||
documentId, | ||
}); | ||
this.emit("message", { | ||
type: "doc-unavailable", | ||
documentId, | ||
targetId: message.senderId, | ||
}); | ||
return; | ||
} | ||
this.#docSetUp[documentId] = true; | ||
@@ -74,0 +88,0 @@ const docSynchronizer = this.#fetchDocSynchronizer(documentId); |
@@ -26,3 +26,6 @@ import { EventEmitter } from "eventemitter3"; | ||
numChanges: number; | ||
} | { | ||
type: "doc-denied"; | ||
documentId: DocumentId; | ||
}; | ||
//# sourceMappingURL=Synchronizer.d.ts.map |
{ | ||
"name": "@automerge/automerge-repo", | ||
"version": "2.0.0-alpha.13", | ||
"version": "2.0.0-alpha.14", | ||
"description": "A repository object to manage a collection of automerge documents", | ||
@@ -63,3 +63,3 @@ "repository": "https://github.com/automerge/automerge-repo/tree/master/packages/automerge-repo", | ||
}, | ||
"gitHead": "f4504b4e6441d938df54f77adf0d629f26ff9a7c" | ||
"gitHead": "3048251989fc0cdbf605f534e48750f0c681004a" | ||
} |
@@ -34,3 +34,8 @@ import { next as Automerge } from "@automerge/automerge/slim" | ||
} from "./synchronizer/Synchronizer.js" | ||
import type { AnyDocumentId, DocumentId, PeerId } from "./types.js" | ||
import type { | ||
AnyDocumentId, | ||
AutomergeUrl, | ||
DocumentId, | ||
PeerId, | ||
} from "./types.js" | ||
@@ -84,2 +89,3 @@ function randomPeerId() { | ||
enableRemoteHeadsGossiping = false, | ||
denylist = [], | ||
}: RepoConfig = {}) { | ||
@@ -104,3 +110,3 @@ super() | ||
// The synchronizer uses the network subsystem to keep documents in sync with peers. | ||
this.synchronizer = new CollectionSynchronizer(this) | ||
this.synchronizer = new CollectionSynchronizer(this, denylist) | ||
@@ -633,2 +639,9 @@ // When the synchronizer emits messages, send them to peers | ||
enableRemoteHeadsGossiping?: boolean | ||
/** | ||
* A list of automerge URLs which should never be loaded regardless of what | ||
* messages are received or what the share policy is. This is useful to avoid | ||
* loading documents that are known to be too resource intensive. | ||
*/ | ||
denylist?: AutomergeUrl[] | ||
} | ||
@@ -677,1 +690,5 @@ | ||
} | ||
| { | ||
type: "doc-denied" | ||
documentId: DocumentId | ||
} |
import debug from "debug" | ||
import { DocHandle } from "../DocHandle.js" | ||
import { stringifyAutomergeUrl } from "../AutomergeUrl.js" | ||
import { parseAutomergeUrl, stringifyAutomergeUrl } from "../AutomergeUrl.js" | ||
import { Repo } from "../Repo.js" | ||
import { DocMessage } from "../network/messages.js" | ||
import { DocumentId, PeerId } from "../types.js" | ||
import { AutomergeUrl, DocumentId, PeerId } from "../types.js" | ||
import { DocSynchronizer } from "./DocSynchronizer.js" | ||
@@ -24,4 +24,7 @@ import { Synchronizer } from "./Synchronizer.js" | ||
constructor(private repo: Repo) { | ||
#denylist: DocumentId[] | ||
constructor(private repo: Repo, denylist: AutomergeUrl[] = []) { | ||
super() | ||
this.#denylist = denylist.map(url => parseAutomergeUrl(url).documentId) | ||
} | ||
@@ -95,2 +98,15 @@ | ||
if (this.#denylist.includes(documentId)) { | ||
this.emit("metrics", { | ||
type: "doc-denied", | ||
documentId, | ||
}) | ||
this.emit("message", { | ||
type: "doc-unavailable", | ||
documentId, | ||
targetId: message.senderId, | ||
}) | ||
return | ||
} | ||
this.#docSetUp[documentId] = true | ||
@@ -97,0 +113,0 @@ |
@@ -28,8 +28,13 @@ import { EventEmitter } from "eventemitter3" | ||
export type DocSyncMetrics = { | ||
type: "receive-sync-message" | ||
documentId: DocumentId | ||
durationMillis: number | ||
numOps: number | ||
numChanges: number | ||
} | ||
export type DocSyncMetrics = | ||
| { | ||
type: "receive-sync-message" | ||
documentId: DocumentId | ||
durationMillis: number | ||
numOps: number | ||
numChanges: number | ||
} | ||
| { | ||
type: "doc-denied" | ||
documentId: DocumentId | ||
} |
@@ -1489,2 +1489,40 @@ import { next as A } from "@automerge/automerge" | ||
}) | ||
describe("the denylist", () => { | ||
it("should immediately return an unavailable message in response to a request for a denylisted document", async () => { | ||
const storage = new DummyStorageAdapter() | ||
// first create the document in storage | ||
const dummyRepo = new Repo({ network: [], storage }) | ||
const doc = dummyRepo.create({ foo: "bar" }) | ||
await dummyRepo.flush() | ||
// Check that the document actually is in storage | ||
let docId = doc.documentId | ||
assert(storage.keys().some((k: string) => k.includes(docId))) | ||
const channel = new MessageChannel() | ||
const { port1: clientToServer, port2: serverToClient } = channel | ||
const server = new Repo({ | ||
network: [new MessageChannelNetworkAdapter(serverToClient)], | ||
storage, | ||
denylist: [doc.url], | ||
}) | ||
const client = new Repo({ | ||
network: [new MessageChannelNetworkAdapter(clientToServer)], | ||
}) | ||
await Promise.all([ | ||
eventPromise(server.networkSubsystem, "peer"), | ||
eventPromise(client.networkSubsystem, "peer"), | ||
]) | ||
const clientDoc = client.find(doc.url) | ||
await pause(100) | ||
assert.strictEqual(clientDoc.docSync(), undefined) | ||
const openDocs = Object.keys(server.metrics().documents).length | ||
assert.deepEqual(openDocs, 0) | ||
}) | ||
}) | ||
}) | ||
@@ -1491,0 +1529,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
471356
10947