@automerge/automerge-repo 2.0.0-alpha.13 → 2.0.0-alpha.14

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/Repo.d.ts CHANGED
@@ -7,7 +7,7 @@ import { StorageSubsystem } from "./storage/StorageSubsystem.js";
7
7
  import { StorageId } from "./storage/types.js";
8
8
  import { CollectionSynchronizer } from "./synchronizer/CollectionSynchronizer.js";
9
9
  import { DocSyncMetrics } from "./synchronizer/Synchronizer.js";
10
- import type { AnyDocumentId, DocumentId, PeerId } from "./types.js";
10
+ import type { AnyDocumentId, AutomergeUrl, DocumentId, PeerId } from "./types.js";
11
11
  /** A Repo is a collection of documents with networking, syncing, and storage capabilities. */
12
12
  /** The `Repo` is the main entry point of this library
13
13
  *
@@ -33,7 +33,7 @@ export declare class Repo extends EventEmitter<RepoEvents> {
33
33
  /** maps peer id to to persistence information (storageId, isEphemeral), access by collection synchronizer */
34
34
  /** @hidden */
35
35
  peerMetadataByPeerId: Record<PeerId, PeerMetadata>;
36
- constructor({ storage, network, peerId, sharePolicy, isEphemeral, enableRemoteHeadsGossiping, }?: RepoConfig);
36
+ constructor({ storage, network, peerId, sharePolicy, isEphemeral, enableRemoteHeadsGossiping, denylist, }?: RepoConfig);
37
37
  /** Returns all the handles we have cached. */
38
38
  get handles(): Record<DocumentId, DocHandle<any>>;
39
39
  /** Returns a list of all connected peer ids */
@@ -126,6 +126,12 @@ export interface RepoConfig {
126
126
  * Whether to enable the experimental remote heads gossiping feature
127
127
  */
128
128
  enableRemoteHeadsGossiping?: boolean;
129
+ /**
130
+ * A list of automerge URLs which should never be loaded regardless of what
131
+ * messages are received or what the share policy is. This is useful to avoid
132
+ * loading documents that are known to be too resource intensive.
133
+ */
134
+ denylist?: AutomergeUrl[];
129
135
  }
130
136
  /** A function that determines whether we should share a document with a peer
131
137
  *
@@ -157,5 +163,8 @@ export type DocMetrics = DocSyncMetrics | {
157
163
  durationMillis: number;
158
164
  numOps: number;
159
165
  numChanges: number;
166
+ } | {
167
+ type: "doc-denied";
168
+ documentId: DocumentId;
160
169
  };
161
170
  //# sourceMappingURL=Repo.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAM5C,OAAO,EAEL,SAAS,EAKV,MAAM,gBAAgB,CAAA;AAIvB,OAAO,EACL,uBAAuB,EACvB,KAAK,YAAY,EAClB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAEhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAA;AACjF,OAAO,EACL,cAAc,EAEf,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,MAAM,EACP,MAAM,YAAY,CAAA;AAMnB,8FAA8F;AAC9F;;;;;;GAMG;AACH,qBAAa,IAAK,SAAQ,YAAY,CAAC,UAAU,CAAC;;IAGhD,cAAc;IACd,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,cAAc;IACd,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IAEnC,mDAAmD;IACnD,cAAc;IACd,gBAAgB,SAAM;IAItB,cAAc;IACd,YAAY,EAAE,sBAAsB,CAAA;IAEpC,sDAAsD;IACtD,cAAc;IACd,WAAW,EAAE,WAAW,CAAmB;IAE3C,8GAA8G;IAC9G,cAAc;IACd,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAK;gBAK3C,EACV,OAAO,EACP,OAAY,EACZ,MAAuB,EACvB,WAAW,EACX,WAAmC,EACnC,0BAAkC,EAClC,QAAa,GACd,GAAE,UAAe;IAgQlB,8CAA8C;IAC9C,IAAI,OAAO,uCAEV;IAED,+CAA+C;IAC/C,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;IAED,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIzD;;;;OAIG;IACH,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IAuBzC;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,CAAC,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;IAuBnC;;;OAGG;IACH,IAAI,CAAC,CAAC;IACJ,sDAAsD;IACtD,EAAE,EAAE,aAAa,GAChB,SAAS,CAAC,CAAC,CAAC;IA+Cf,MAAM;IACJ,oDAAoD;IACpD,EAAE,EAAE,aAAa;IAWnB;;;;;;OAMG;IACG,MAAM,CAAC,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAShE;;;OAGG;IACH,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU;IAY5B,kBAAkB,YAAa,SAAS,EAAE,UASzC;IAED,SAAS,QAAa,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAMnD;IAED;;;;;OAKG;IACG,KAAK,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBpD;;;;;OAKG;IACG,eAAe,CAAC,UAAU,EAAE,UAAU;IA2B5C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOzB,OAAO,IAAI;QAAE,SAAS,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAA;KAAE;CAGjD;AAED,MAAM,WAAW,UAAU;IACzB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;8DAC0D;IAC1D,WAAW,CAAC,EAAE,OAAO,CAAA;IAErB,gDAAgD;IAChD,OAAO,CAAC,EAAE,uBAAuB,CAAA;IAEjC,iEAAiE;IACjE,OAAO,CAAC,EAAE,uBAAuB,EAAE,CAAA;IAEnC;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;IAEzB;;OAEG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAA;IAEpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAA;CAC1B;AAED;;;;;;;KAOK;AACL,MAAM,MAAM,WAAW,GAAG,CACxB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,UAAU,KACpB,OAAO,CAAC,OAAO,CAAC,CAAA;AAGrB,MAAM,WAAW,UAAU;IACzB,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAA;IACxC,6BAA6B;IAC7B,iBAAiB,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,IAAI,CAAA;IACvD,4FAA4F;IAC5F,sBAAsB,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,IAAI,CAAA;IAC5D,aAAa,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,CAAA;CACzC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAA;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,UAAU,CAAA;CACvB;AAED,MAAM,MAAM,UAAU,GAClB,cAAc,GACd;IACE,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,EAAE,UAAU,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB,GACD;IACE,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA"}
package/dist/Repo.js CHANGED
@@ -40,7 +40,7 @@ export class Repo extends EventEmitter {
40
40
  peerMetadataByPeerId = {};
41
41
  #remoteHeadsSubscriptions = new RemoteHeadsSubscriptions();
42
42
  #remoteHeadsGossipingEnabled = false;
43
- constructor({ storage, network = [], peerId = randomPeerId(), sharePolicy, isEphemeral = storage === undefined, enableRemoteHeadsGossiping = false, } = {}) {
43
+ constructor({ storage, network = [], peerId = randomPeerId(), sharePolicy, isEphemeral = storage === undefined, enableRemoteHeadsGossiping = false, denylist = [], } = {}) {
44
44
  super();
45
45
  this.#remoteHeadsGossipingEnabled = enableRemoteHeadsGossiping;
46
46
  this.#log = debug(`automerge-repo:repo`);
@@ -56,7 +56,7 @@ export class Repo extends EventEmitter {
56
56
  });
57
57
  // SYNCHRONIZER
58
58
  // The synchronizer uses the network subsystem to keep documents in sync with peers.
59
- this.synchronizer = new CollectionSynchronizer(this);
59
+ this.synchronizer = new CollectionSynchronizer(this, denylist);
60
60
  // When the synchronizer emits messages, send them to peers
61
61
  this.synchronizer.on("message", message => {
62
62
  this.#log(`sending ${message.type} message to ${message.targetId}`);
@@ -1,6 +1,6 @@
1
1
  import { Repo } from "../Repo.js";
2
2
  import { DocMessage } from "../network/messages.js";
3
- import { DocumentId, PeerId } from "../types.js";
3
+ import { AutomergeUrl, DocumentId, PeerId } from "../types.js";
4
4
  import { DocSynchronizer } from "./DocSynchronizer.js";
5
5
  import { Synchronizer } from "./Synchronizer.js";
6
6
  /** A CollectionSynchronizer is responsible for synchronizing a DocCollection with peers. */
@@ -10,7 +10,7 @@ export declare class CollectionSynchronizer extends Synchronizer {
10
10
  /** A map of documentIds to their synchronizers */
11
11
  /** @hidden */
12
12
  docSynchronizers: Record<DocumentId, DocSynchronizer>;
13
- constructor(repo: Repo);
13
+ constructor(repo: Repo, denylist?: AutomergeUrl[]);
14
14
  /**
15
15
  * When we receive a sync message for a document we haven't got in memory, we
16
16
  * register it with the repo and start synchronizing
@@ -1 +1 @@
1
- {"version":3,"file":"CollectionSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/CollectionSynchronizer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIhD,4FAA4F;AAC5F,qBAAa,sBAAuB,SAAQ,YAAY;;IAW1C,OAAO,CAAC,IAAI;IAPxB,kDAAkD;IAClD,cAAc;IACd,gBAAgB,EAAE,MAAM,CAAC,UAAU,EAAE,eAAe,CAAC,CAAK;gBAKtC,IAAI,EAAE,IAAI;IAsD9B;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,UAAU;IAyBxC;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,UAAU;IAalC,cAAc,CAAC,UAAU,EAAE,UAAU;IAIrC,2DAA2D;IAC3D,OAAO,CAAC,MAAM,EAAE,MAAM;IAgBtB,uDAAuD;IACvD,UAAU,CAAC,MAAM,EAAE,MAAM;IASzB,+CAA+C;IAC/C,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;IAED,OAAO,IAAI;QACT,CAAC,GAAG,EAAE,MAAM,GAAG;YACb,KAAK,EAAE,MAAM,EAAE,CAAA;YACf,IAAI,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAC;gBAAC,UAAU,EAAE,MAAM,CAAA;aAAE,CAAA;SAC7C,CAAA;KACF;CASF"}
1
+ {"version":3,"file":"CollectionSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/CollectionSynchronizer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIhD,4FAA4F;AAC5F,qBAAa,sBAAuB,SAAQ,YAAY;;IAa1C,OAAO,CAAC,IAAI;IATxB,kDAAkD;IAClD,cAAc;IACd,gBAAgB,EAAE,MAAM,CAAC,UAAU,EAAE,eAAe,CAAC,CAAK;gBAOtC,IAAI,EAAE,IAAI,EAAE,QAAQ,GAAE,YAAY,EAAO;IAuD7D;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,UAAU;IAsCxC;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,UAAU;IAalC,cAAc,CAAC,UAAU,EAAE,UAAU;IAIrC,2DAA2D;IAC3D,OAAO,CAAC,MAAM,EAAE,MAAM;IAgBtB,uDAAuD;IACvD,UAAU,CAAC,MAAM,EAAE,MAAM;IASzB,+CAA+C;IAC/C,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;IAED,OAAO,IAAI;QACT,CAAC,GAAG,EAAE,MAAM,GAAG;YACb,KAAK,EAAE,MAAM,EAAE,CAAA;YACf,IAAI,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAC;gBAAC,UAAU,EAAE,MAAM,CAAA;aAAE,CAAA;SAC7C,CAAA;KACF;CASF"}
@@ -1,5 +1,5 @@
1
1
  import debug from "debug";
2
- import { stringifyAutomergeUrl } from "../AutomergeUrl.js";
2
+ import { parseAutomergeUrl, stringifyAutomergeUrl } from "../AutomergeUrl.js";
3
3
  import { DocSynchronizer } from "./DocSynchronizer.js";
4
4
  import { Synchronizer } from "./Synchronizer.js";
5
5
  const log = debug("automerge-repo:collectionsync");
@@ -13,9 +13,11 @@ export class CollectionSynchronizer extends Synchronizer {
13
13
  docSynchronizers = {};
14
14
  /** Used to determine if the document is know to the Collection and a synchronizer exists or is being set up */
15
15
  #docSetUp = {};
16
- constructor(repo) {
16
+ #denylist;
17
+ constructor(repo, denylist = []) {
17
18
  super();
18
19
  this.repo = repo;
20
+ this.#denylist = denylist.map(url => parseAutomergeUrl(url).documentId);
19
21
  }
20
22
  /** Returns a synchronizer for the given document, creating one if it doesn't already exist. */
21
23
  #fetchDocSynchronizer(documentId) {
@@ -68,6 +70,18 @@ export class CollectionSynchronizer extends Synchronizer {
68
70
  if (!documentId) {
69
71
  throw new Error("received a message with an invalid documentId");
70
72
  }
73
+ if (this.#denylist.includes(documentId)) {
74
+ this.emit("metrics", {
75
+ type: "doc-denied",
76
+ documentId,
77
+ });
78
+ this.emit("message", {
79
+ type: "doc-unavailable",
80
+ documentId,
81
+ targetId: message.senderId,
82
+ });
83
+ return;
84
+ }
71
85
  this.#docSetUp[documentId] = true;
72
86
  const docSynchronizer = this.#fetchDocSynchronizer(documentId);
73
87
  docSynchronizer.receiveMessage(message);
@@ -23,5 +23,8 @@ export type DocSyncMetrics = {
23
23
  durationMillis: number;
24
24
  numOps: number;
25
25
  numChanges: number;
26
+ } | {
27
+ type: "doc-denied";
28
+ documentId: DocumentId;
26
29
  };
27
30
  //# sourceMappingURL=Synchronizer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Synchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/Synchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EACL,eAAe,EACf,cAAc,EACd,WAAW,EACZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEhD,8BAAsB,YAAa,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IACzE,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;CACpD;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;IAC3C,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAA;IACjD,UAAU,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAA;IACzC,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAA;CACvC;AAED,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;CACrB;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,sBAAsB,CAAA;IAC5B,UAAU,EAAE,UAAU,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA"}
1
+ {"version":3,"file":"Synchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/Synchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EACL,eAAe,EACf,cAAc,EACd,WAAW,EACZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEhD,8BAAsB,YAAa,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IACzE,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;CACpD;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;IAC3C,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAA;IACjD,UAAU,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAA;IACzC,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAA;CACvC;AAED,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;CACrB;AAED,MAAM,MAAM,cAAc,GACtB;IACE,IAAI,EAAE,sBAAsB,CAAA;IAC5B,UAAU,EAAE,UAAU,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB,GACD;IACE,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automerge/automerge-repo",
3
- "version": "2.0.0-alpha.13",
3
+ "version": "2.0.0-alpha.14",
4
4
  "description": "A repository object to manage a collection of automerge documents",
5
5
  "repository": "https://github.com/automerge/automerge-repo/tree/master/packages/automerge-repo",
6
6
  "author": "Peter van Hardenberg <pvh@pvh.ca>",
@@ -60,5 +60,5 @@
60
60
  "publishConfig": {
61
61
  "access": "public"
62
62
  },
63
- "gitHead": "f4504b4e6441d938df54f77adf0d629f26ff9a7c"
63
+ "gitHead": "3048251989fc0cdbf605f534e48750f0c681004a"
64
64
  }
package/src/Repo.ts CHANGED
@@ -31,7 +31,12 @@ import {
31
31
  DocSyncMetrics,
32
32
  SyncStatePayload,
33
33
  } from "./synchronizer/Synchronizer.js"
34
- import type { AnyDocumentId, DocumentId, PeerId } from "./types.js"
34
+ import type {
35
+ AnyDocumentId,
36
+ AutomergeUrl,
37
+ DocumentId,
38
+ PeerId,
39
+ } from "./types.js"
35
40
 
36
41
  function randomPeerId() {
37
42
  return ("peer-" + Math.random().toString(36).slice(4)) as PeerId
@@ -80,6 +85,7 @@ export class Repo extends EventEmitter<RepoEvents> {
80
85
  sharePolicy,
81
86
  isEphemeral = storage === undefined,
82
87
  enableRemoteHeadsGossiping = false,
88
+ denylist = [],
83
89
  }: RepoConfig = {}) {
84
90
  super()
85
91
  this.#remoteHeadsGossipingEnabled = enableRemoteHeadsGossiping
@@ -99,7 +105,7 @@ export class Repo extends EventEmitter<RepoEvents> {
99
105
 
100
106
  // SYNCHRONIZER
101
107
  // The synchronizer uses the network subsystem to keep documents in sync with peers.
102
- this.synchronizer = new CollectionSynchronizer(this)
108
+ this.synchronizer = new CollectionSynchronizer(this, denylist)
103
109
 
104
110
  // When the synchronizer emits messages, send them to peers
105
111
  this.synchronizer.on("message", message => {
@@ -627,6 +633,13 @@ export interface RepoConfig {
627
633
  * Whether to enable the experimental remote heads gossiping feature
628
634
  */
629
635
  enableRemoteHeadsGossiping?: boolean
636
+
637
+ /**
638
+ * A list of automerge URLs which should never be loaded regardless of what
639
+ * messages are received or what the share policy is. This is useful to avoid
640
+ * loading documents that are known to be too resource intensive.
641
+ */
642
+ denylist?: AutomergeUrl[]
630
643
  }
631
644
 
632
645
  /** A function that determines whether we should share a document with a peer
@@ -670,3 +683,7 @@ export type DocMetrics =
670
683
  numOps: number
671
684
  numChanges: number
672
685
  }
686
+ | {
687
+ type: "doc-denied"
688
+ documentId: DocumentId
689
+ }
@@ -1,9 +1,9 @@
1
1
  import debug from "debug"
2
2
  import { DocHandle } from "../DocHandle.js"
3
- import { stringifyAutomergeUrl } from "../AutomergeUrl.js"
3
+ import { parseAutomergeUrl, stringifyAutomergeUrl } from "../AutomergeUrl.js"
4
4
  import { Repo } from "../Repo.js"
5
5
  import { DocMessage } from "../network/messages.js"
6
- import { DocumentId, PeerId } from "../types.js"
6
+ import { AutomergeUrl, DocumentId, PeerId } from "../types.js"
7
7
  import { DocSynchronizer } from "./DocSynchronizer.js"
8
8
  import { Synchronizer } from "./Synchronizer.js"
9
9
 
@@ -21,8 +21,11 @@ export class CollectionSynchronizer extends Synchronizer {
21
21
  /** Used to determine if the document is know to the Collection and a synchronizer exists or is being set up */
22
22
  #docSetUp: Record<DocumentId, boolean> = {}
23
23
 
24
- constructor(private repo: Repo) {
24
+ #denylist: DocumentId[]
25
+
26
+ constructor(private repo: Repo, denylist: AutomergeUrl[] = []) {
25
27
  super()
28
+ this.#denylist = denylist.map(url => parseAutomergeUrl(url).documentId)
26
29
  }
27
30
 
28
31
  /** Returns a synchronizer for the given document, creating one if it doesn't already exist. */
@@ -91,6 +94,19 @@ export class CollectionSynchronizer extends Synchronizer {
91
94
  throw new Error("received a message with an invalid documentId")
92
95
  }
93
96
 
97
+ if (this.#denylist.includes(documentId)) {
98
+ this.emit("metrics", {
99
+ type: "doc-denied",
100
+ documentId,
101
+ })
102
+ this.emit("message", {
103
+ type: "doc-unavailable",
104
+ documentId,
105
+ targetId: message.senderId,
106
+ })
107
+ return
108
+ }
109
+
94
110
  this.#docSetUp[documentId] = true
95
111
 
96
112
  const docSynchronizer = this.#fetchDocSynchronizer(documentId)
@@ -25,10 +25,15 @@ export interface SyncStatePayload {
25
25
  syncState: SyncState
26
26
  }
27
27
 
28
- export type DocSyncMetrics = {
29
- type: "receive-sync-message"
30
- documentId: DocumentId
31
- durationMillis: number
32
- numOps: number
33
- numChanges: number
34
- }
28
+ export type DocSyncMetrics =
29
+ | {
30
+ type: "receive-sync-message"
31
+ documentId: DocumentId
32
+ durationMillis: number
33
+ numOps: number
34
+ numChanges: number
35
+ }
36
+ | {
37
+ type: "doc-denied"
38
+ documentId: DocumentId
39
+ }
package/test/Repo.test.ts CHANGED
@@ -1486,6 +1486,44 @@ describe("Repo", () => {
1486
1486
  teardown()
1487
1487
  })
1488
1488
  })
1489
+
1490
+ describe("the denylist", () => {
1491
+ it("should immediately return an unavailable message in response to a request for a denylisted document", async () => {
1492
+ const storage = new DummyStorageAdapter()
1493
+
1494
+ // first create the document in storage
1495
+ const dummyRepo = new Repo({ network: [], storage })
1496
+ const doc = dummyRepo.create({ foo: "bar" })
1497
+ await dummyRepo.flush()
1498
+
1499
+ // Check that the document actually is in storage
1500
+ let docId = doc.documentId
1501
+ assert(storage.keys().some((k: string) => k.includes(docId)))
1502
+
1503
+ const channel = new MessageChannel()
1504
+ const { port1: clientToServer, port2: serverToClient } = channel
1505
+ const server = new Repo({
1506
+ network: [new MessageChannelNetworkAdapter(serverToClient)],
1507
+ storage,
1508
+ denylist: [doc.url],
1509
+ })
1510
+ const client = new Repo({
1511
+ network: [new MessageChannelNetworkAdapter(clientToServer)],
1512
+ })
1513
+
1514
+ await Promise.all([
1515
+ eventPromise(server.networkSubsystem, "peer"),
1516
+ eventPromise(client.networkSubsystem, "peer"),
1517
+ ])
1518
+
1519
+ const clientDoc = client.find(doc.url)
1520
+ await pause(100)
1521
+ assert.strictEqual(clientDoc.docSync(), undefined)
1522
+
1523
+ const openDocs = Object.keys(server.metrics().documents).length
1524
+ assert.deepEqual(openDocs, 0)
1525
+ })
1526
+ })
1489
1527
  })
1490
1528
 
1491
1529
  const warn = console.warn