@automerge/automerge-repo 1.1.0-alpha.1 → 1.1.0-alpha.3

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
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter } from "eventemitter3";
2
2
  import { DocHandle } from "./DocHandle.js";
3
- import { NetworkAdapter } from "./network/NetworkAdapter.js";
3
+ import { NetworkAdapter, type PeerMetadata } from "./network/NetworkAdapter.js";
4
4
  import { NetworkSubsystem } from "./network/NetworkSubsystem.js";
5
5
  import { StorageAdapter } from "./storage/StorageAdapter.js";
6
6
  import { StorageSubsystem } from "./storage/StorageSubsystem.js";
@@ -26,9 +26,9 @@ export declare class Repo extends EventEmitter<RepoEvents> {
26
26
  /** By default, we share generously with all peers. */
27
27
  /** @hidden */
28
28
  sharePolicy: SharePolicy;
29
- /** maps peer id to to persistance information (storageId, isEphemeral), access by collection synchronizer */
29
+ /** maps peer id to to persistence information (storageId, isEphemeral), access by collection synchronizer */
30
30
  /** @hidden */
31
- persistanceInfoByPeerId: Record<PeerId, PersistanceInfo>;
31
+ peerMetadataByPeerId: Record<PeerId, PeerMetadata>;
32
32
  constructor({ storage, network, peerId, sharePolicy, isEphemeral, }: RepoConfig);
33
33
  /** Returns all the handles we have cached. */
34
34
  get handles(): Record<DocumentId, DocHandle<any>>;
@@ -69,10 +69,6 @@ export declare class Repo extends EventEmitter<RepoEvents> {
69
69
  subscribeToRemotes: (remotes: StorageId[]) => void;
70
70
  storageId: () => Promise<StorageId | undefined>;
71
71
  }
72
- interface PersistanceInfo {
73
- storageId: StorageId;
74
- isEphemeral: boolean;
75
- }
76
72
  export interface RepoConfig {
77
73
  /** Our unique identifier */
78
74
  peerId?: PeerId;
@@ -113,5 +109,4 @@ export interface DocumentPayload {
113
109
  export interface DeleteDocumentPayload {
114
110
  documentId: DocumentId;
115
111
  }
116
- export {};
117
112
  //# 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,EAAE,SAAS,EAAiC,MAAM,gBAAgB,CAAA;AAEzE,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAEhE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAEnE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAI9C,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;IAMtB,sDAAsD;IACtD,cAAc;IACd,WAAW,EAAE,WAAW,CAAmB;IAE3C,8GAA8G;IAC9G,cAAc;IACd,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAK;gBAI3C,EACV,OAAO,EACP,OAAO,EACP,MAAM,EACN,WAAW,EACX,WAAmC,GACpC,EAAE,UAAU;IAuQb,8CAA8C;IAC9C,IAAI,OAAO,uCAEV;IAED,+CAA+C;IAC/C,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;IAED;;;;OAIG;IACH,MAAM,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;IA0BzB;;;;;;;;;;;;;;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;IAqBf,MAAM;IACJ,oDAAoD;IACpD,EAAE,EAAE,aAAa;IAWnB,kBAAkB,YAAa,SAAS,EAAE,UAGzC;IAED,SAAS,QAAa,QAAQ,SAAS,GAAG,SAAS,CAAC,CAMnD;CACF;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,cAAc,CAAA;IAExB,oDAAoD;IACpD,OAAO,EAAE,cAAc,EAAE,CAAA;IAEzB;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,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;CAC7D;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAA;IACtB,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,UAAU,CAAA;CACvB"}
package/dist/Repo.js CHANGED
@@ -31,9 +31,9 @@ export class Repo extends EventEmitter {
31
31
  /** By default, we share generously with all peers. */
32
32
  /** @hidden */
33
33
  sharePolicy = async () => true;
34
- /** maps peer id to to persistance information (storageId, isEphemeral), access by collection synchronizer */
34
+ /** maps peer id to to persistence information (storageId, isEphemeral), access by collection synchronizer */
35
35
  /** @hidden */
36
- persistanceInfoByPeerId = {};
36
+ peerMetadataByPeerId = {};
37
37
  #remoteHeadsSubscriptions = new RemoteHeadsSubscriptions();
38
38
  constructor({ storage, network, peerId, sharePolicy, isEphemeral = storage === undefined, }) {
39
39
  super();
@@ -107,16 +107,17 @@ export class Repo extends EventEmitter {
107
107
  this.storageSubsystem = storageSubsystem;
108
108
  // NETWORK
109
109
  // The network subsystem deals with sending and receiving messages to and from peers.
110
- const networkSubsystem = new NetworkSubsystem(network, peerId, storageSubsystem?.id() ?? Promise.resolve(undefined), isEphemeral);
110
+ const myPeerMetadata = new Promise(async (resolve, reject) => resolve({
111
+ storageId: await storageSubsystem?.id(),
112
+ isEphemeral,
113
+ }));
114
+ const networkSubsystem = new NetworkSubsystem(network, peerId, myPeerMetadata);
111
115
  this.networkSubsystem = networkSubsystem;
112
116
  // When we get a new peer, register it with the synchronizer
113
- networkSubsystem.on("peer", async ({ peerId, storageId, isEphemeral }) => {
117
+ networkSubsystem.on("peer", async ({ peerId, peerMetadata }) => {
114
118
  this.#log("peer connected", { peerId });
115
- if (storageId) {
116
- this.persistanceInfoByPeerId[peerId] = {
117
- storageId,
118
- isEphemeral,
119
- };
119
+ if (peerMetadata) {
120
+ this.peerMetadataByPeerId[peerId] = { ...peerMetadata };
120
121
  }
121
122
  this.sharePolicy(peerId)
122
123
  .then(shouldShare => {
@@ -141,11 +142,10 @@ export class Repo extends EventEmitter {
141
142
  this.#synchronizer.on("sync-state", message => {
142
143
  this.#saveSyncState(message);
143
144
  const handle = this.#handleCache[message.documentId];
144
- const info = this.persistanceInfoByPeerId[message.peerId];
145
- if (!info) {
145
+ const { storageId } = this.peerMetadataByPeerId[message.peerId] || {};
146
+ if (!storageId) {
146
147
  return;
147
148
  }
148
- const { storageId } = info;
149
149
  const heads = handle.getRemoteHeads(storageId);
150
150
  const haveHeadsChanged = message.syncState.theirHeads &&
151
151
  (!heads || !headsAreSame(heads, message.syncState.theirHeads));
@@ -208,11 +208,10 @@ export class Repo extends EventEmitter {
208
208
  if (!this.storageSubsystem) {
209
209
  return;
210
210
  }
211
- const persistanceInfo = this.persistanceInfoByPeerId[message.peerId];
212
- if (!persistanceInfo || persistanceInfo.isEphemeral) {
211
+ const { storageId, isEphemeral } = this.peerMetadataByPeerId[message.peerId] || {};
212
+ if (!storageId || isEphemeral) {
213
213
  return;
214
214
  }
215
- const { storageId } = persistanceInfo;
216
215
  let handler = this.#throttledSaveSyncStateHandlers[storageId];
217
216
  if (!handler) {
218
217
  handler = this.#throttledSaveSyncStateHandlers[storageId] = throttle(({ documentId, syncState }) => {
package/dist/index.d.ts CHANGED
@@ -35,7 +35,7 @@ export { StorageAdapter } from "./storage/StorageAdapter.js";
35
35
  export * as cbor from "./helpers/cbor.js";
36
36
  export type { DocHandleChangePayload, DocHandleDeletePayload, DocHandleEncodedChangePayload, DocHandleEphemeralMessagePayload, DocHandleRemoteHeadsPayload, DocHandleEvents, DocHandleOptions, DocHandleOutboundEphemeralMessagePayload, HandleState, } from "./DocHandle.js";
37
37
  export type { DeleteDocumentPayload, DocumentPayload, RepoConfig, RepoEvents, SharePolicy, } from "./Repo.js";
38
- export type { NetworkAdapterEvents, OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, } from "./network/NetworkAdapter.js";
38
+ export type { NetworkAdapterEvents, OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, PeerMetadata, } from "./network/NetworkAdapter.js";
39
39
  export type { DocumentUnavailableMessage, EphemeralMessage, Message, RepoMessage, RequestMessage, SyncMessage, } from "./network/messages.js";
40
40
  export type { Chunk, ChunkInfo, ChunkType, StorageKey, StorageId, } from "./storage/types.js";
41
41
  export * from "./types.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAE5D,eAAe;AACf,OAAO,KAAK,IAAI,MAAM,mBAAmB,CAAA;AAIzC,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,6BAA6B,EAC7B,gCAAgC,EAChC,2BAA2B,EAC3B,eAAe,EACf,gBAAgB,EAChB,wCAAwC,EACxC,WAAW,GACZ,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EACV,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,WAAW,CAAA;AAElB,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,6BAA6B,CAAA;AAEpC,YAAY,EACV,0BAA0B,EAC1B,gBAAgB,EAChB,OAAO,EACP,WAAW,EACX,cAAc,EACd,WAAW,GACZ,MAAM,uBAAuB,CAAA;AAE9B,YAAY,EACV,KAAK,EACL,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,GACV,MAAM,oBAAoB,CAAA;AAE3B,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAE5D,eAAe;AACf,OAAO,KAAK,IAAI,MAAM,mBAAmB,CAAA;AAIzC,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,6BAA6B,EAC7B,gCAAgC,EAChC,2BAA2B,EAC3B,eAAe,EACf,gBAAgB,EAChB,wCAAwC,EACxC,WAAW,GACZ,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EACV,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,WAAW,CAAA;AAElB,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,uBAAuB,EACvB,YAAY,GACb,MAAM,6BAA6B,CAAA;AAEpC,YAAY,EACV,0BAA0B,EAC1B,gBAAgB,EAChB,OAAO,EACP,WAAW,EACX,cAAc,EACd,WAAW,GACZ,MAAM,uBAAuB,CAAA;AAE9B,YAAY,EACV,KAAK,EACL,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,GACV,MAAM,oBAAoB,CAAA;AAE3B,cAAc,YAAY,CAAA"}
@@ -2,6 +2,16 @@ import { EventEmitter } from "eventemitter3";
2
2
  import { PeerId } from "../types.js";
3
3
  import { Message } from "./messages.js";
4
4
  import { StorageId } from "../storage/types.js";
5
+ /**
6
+ * Describes a peer intent to the system
7
+ * storageId: the key for syncState to decide what the other peer already has
8
+ * isEphemeral: to decide if we bother recording this peer's sync state
9
+ *
10
+ */
11
+ export interface PeerMetadata {
12
+ storageId?: StorageId;
13
+ isEphemeral?: boolean;
14
+ }
5
15
  /** An interface representing some way to connect to other peers
6
16
  *
7
17
  * @remarks
@@ -11,15 +21,13 @@ import { StorageId } from "../storage/types.js";
11
21
  */
12
22
  export declare abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> {
13
23
  peerId?: PeerId;
14
- storageId?: StorageId;
15
- isEphemeral: boolean;
24
+ peerMetadata?: PeerMetadata;
16
25
  /** Called by the {@link Repo} to start the connection process
17
26
  *
18
27
  * @argument peerId - the peerId of this repo
19
- * @argument storageId - the storage id of the peer
20
- * @argument isEphemeral - weather or not the other end should persist our sync state
28
+ * @argument peerMetadata - how this adapter should present itself to other peers
21
29
  */
22
- abstract connect(peerId: PeerId, storageId: StorageId | undefined, isEphemeral: boolean): void;
30
+ abstract connect(peerId: PeerId, peerMetadata?: PeerMetadata): void;
23
31
  /** Called by the {@link Repo} to send a message to a peer
24
32
  *
25
33
  * @argument message - the message to send
@@ -45,8 +53,7 @@ export interface OpenPayload {
45
53
  }
46
54
  export interface PeerCandidatePayload {
47
55
  peerId: PeerId;
48
- storageId?: StorageId;
49
- isEphemeral: boolean;
56
+ peerMetadata: PeerMetadata;
50
57
  }
51
58
  export interface PeerDisconnectedPayload {
52
59
  peerId: PeerId;
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkAdapter.d.ts","sourceRoot":"","sources":["../../src/network/NetworkAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C;;;;;;GAMG;AACH,8BAAsB,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,UAAO;IAElB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,WAAW,EAAE,OAAO,GACnB,IAAI;IAEP;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAErC,gEAAgE;IAChE,QAAQ,CAAC,UAAU,IAAI,IAAI;CAC5B;AAID,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IAErC,yCAAyC;IACzC,KAAK,EAAE,MAAM,IAAI,CAAA;IAEjB,+DAA+D;IAC/D,gBAAgB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAEzD,2EAA2E;IAC3E,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAE/D,sEAAsE;IACtE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,cAAc,CAAA;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;CACf"}
1
+ {"version":3,"file":"NetworkAdapter.d.ts","sourceRoot":"","sources":["../../src/network/NetworkAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED;;;;;;GAMG;AACH,8BAAsB,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,YAAY,CAAA;IAE3B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI;IAEnE;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAErC,gEAAgE;IAChE,QAAQ,CAAC,UAAU,IAAI,IAAI;CAC5B;AAID,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IAErC,yCAAyC;IACzC,KAAK,EAAE,MAAM,IAAI,CAAA;IAEjB,+DAA+D;IAC/D,gBAAgB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAEzD,2EAA2E;IAC3E,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAE/D,sEAAsE;IACtE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,cAAc,CAAA;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,YAAY,CAAA;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;CACf"}
@@ -8,6 +8,5 @@ import { EventEmitter } from "eventemitter3";
8
8
  */
9
9
  export class NetworkAdapter extends EventEmitter {
10
10
  peerId; // hmmm, maybe not
11
- storageId;
12
- isEphemeral = true;
11
+ peerMetadata;
13
12
  }
@@ -1,15 +1,12 @@
1
1
  import { EventEmitter } from "eventemitter3";
2
2
  import { PeerId } from "../types.js";
3
- import { NetworkAdapter, PeerDisconnectedPayload } from "./NetworkAdapter.js";
3
+ import type { NetworkAdapter, PeerDisconnectedPayload, PeerMetadata } from "./NetworkAdapter.js";
4
4
  import { MessageContents, RepoMessage } from "./messages.js";
5
- import { StorageId } from "../storage/types.js";
6
5
  export declare class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
7
6
  #private;
8
7
  peerId: PeerId;
9
- private storageId;
10
- private isEphemeral;
11
- constructor(adapters: NetworkAdapter[], peerId: PeerId, storageId: Promise<StorageId | undefined>, // todo: we shouldn't pass a promise here
12
- isEphemeral: boolean);
8
+ private peerMetadata;
9
+ constructor(adapters: NetworkAdapter[], peerId: PeerId, peerMetadata: Promise<PeerMetadata>);
13
10
  addNetworkAdapter(networkAdapter: NetworkAdapter): void;
14
11
  send(message: MessageContents): void;
15
12
  isReady: () => boolean;
@@ -23,7 +20,6 @@ export interface NetworkSubsystemEvents {
23
20
  }
24
21
  export interface PeerPayload {
25
22
  peerId: PeerId;
26
- storageId?: StorageId;
27
- isEphemeral: boolean;
23
+ peerMetadata: PeerMetadata;
28
24
  }
29
25
  //# sourceMappingURL=NetworkSubsystem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkSubsystem.d.ts","sourceRoot":"","sources":["../../src/network/NetworkSubsystem.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAa,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7E,OAAO,EAEL,eAAe,EACf,WAAW,EAGZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAO/C,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;;IAY/D,MAAM;IACb,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,WAAW;gBAHnB,QAAQ,EAAE,cAAc,EAAE,EACnB,MAAM,QAAiB,EACtB,SAAS,EAAE,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,EAAE,yCAAyC;IACpF,WAAW,EAAE,OAAO;IAO9B,iBAAiB,CAAC,cAAc,EAAE,cAAc;IA2EhD,IAAI,CAAC,OAAO,EAAE,eAAe;IAsC7B,OAAO,gBAEN;IAED,SAAS,sBAUR;CACF;AAQD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IACpC,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAC/D,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IACvC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,EAAE,OAAO,CAAA;CACrB"}
1
+ {"version":3,"file":"NetworkSubsystem.d.ts","sourceRoot":"","sources":["../../src/network/NetworkSubsystem.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAa,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EACV,cAAc,EACd,uBAAuB,EACvB,YAAY,EACb,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAEL,eAAe,EACf,WAAW,EAGZ,MAAM,eAAe,CAAA;AAQtB,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;;IAY/D,MAAM;IACb,OAAO,CAAC,YAAY;gBAFpB,QAAQ,EAAE,cAAc,EAAE,EACnB,MAAM,QAAiB,EACtB,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC;IAO7C,iBAAiB,CAAC,cAAc,EAAE,cAAc;IAuEhD,IAAI,CAAC,OAAO,EAAE,eAAe;IAsC7B,OAAO,gBAEN;IAED,SAAS,sBAUR;CACF;AAQD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IACpC,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAC/D,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IACvC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,YAAY,CAAA;CAC3B"}
@@ -4,8 +4,7 @@ import { isEphemeralMessage, isValidRepoMessage, } from "./messages.js";
4
4
  const getEphemeralMessageSource = (message) => `${message.senderId}:${message.sessionId}`;
5
5
  export class NetworkSubsystem extends EventEmitter {
6
6
  peerId;
7
- storageId;
8
- isEphemeral;
7
+ peerMetadata;
9
8
  #log;
10
9
  #adaptersByPeer = {};
11
10
  #count = 0;
@@ -13,12 +12,10 @@ export class NetworkSubsystem extends EventEmitter {
13
12
  #ephemeralSessionCounts = {};
14
13
  #readyAdapterCount = 0;
15
14
  #adapters = [];
16
- constructor(adapters, peerId = randomPeerId(), storageId, // todo: we shouldn't pass a promise here
17
- isEphemeral) {
15
+ constructor(adapters, peerId = randomPeerId(), peerMetadata) {
18
16
  super();
19
17
  this.peerId = peerId;
20
- this.storageId = storageId;
21
- this.isEphemeral = isEphemeral;
18
+ this.peerMetadata = peerMetadata;
22
19
  this.#log = debug(`automerge-repo:network:${this.peerId}`);
23
20
  adapters.forEach(a => this.addNetworkAdapter(a));
24
21
  }
@@ -31,14 +28,14 @@ export class NetworkSubsystem extends EventEmitter {
31
28
  this.emit("ready");
32
29
  }
33
30
  });
34
- networkAdapter.on("peer-candidate", ({ peerId, storageId, isEphemeral }) => {
31
+ networkAdapter.on("peer-candidate", ({ peerId, peerMetadata }) => {
35
32
  this.#log(`peer candidate: ${peerId} `);
36
33
  // TODO: This is where authentication would happen
37
34
  if (!this.#adaptersByPeer[peerId]) {
38
35
  // TODO: handle losing a server here
39
36
  this.#adaptersByPeer[peerId] = networkAdapter;
40
37
  }
41
- this.emit("peer", { peerId, storageId, isEphemeral });
38
+ this.emit("peer", { peerId, peerMetadata });
42
39
  });
43
40
  networkAdapter.on("peer-disconnected", ({ peerId }) => {
44
41
  this.#log(`peer disconnected: ${peerId} `);
@@ -70,8 +67,8 @@ export class NetworkSubsystem extends EventEmitter {
70
67
  }
71
68
  });
72
69
  });
73
- this.storageId.then(storageId => {
74
- networkAdapter.connect(this.peerId, storageId, this.isEphemeral);
70
+ this.peerMetadata.then(peerMetadata => {
71
+ networkAdapter.connect(this.peerId, peerMetadata);
75
72
  });
76
73
  }
77
74
  send(message) {
@@ -1 +1 @@
1
- {"version":3,"file":"StorageSubsystem.d.ts","sourceRoot":"","sources":["../../src/storage/StorageSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAI9C,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAyB,SAAS,EAAE,MAAM,YAAY,CAAA;AAK7D;;;GAGG;AACH,qBAAa,gBAAgB;;gBAef,cAAc,EAAE,cAAc;IAIpC,EAAE,IAAI,OAAO,CAAC,SAAS,CAAC;IA2B9B,kCAAkC;IAC5B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAKlC,gCAAgC;IAC1B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM;IAEX,sCAAsC;IACtC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC;IAKhB,oCAAoC;IAC9B,MAAM;IACV,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,2FAA2F;IAC3F,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC;IAOhB;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAmClE;;;;;;OAMG;IACG,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAazE;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,UAAU;IAkEhC,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC;IAM7B,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,CAAC,CAAC,SAAS,GACrB,OAAO,CAAC,IAAI,CAAC;CAyCjB"}
1
+ {"version":3,"file":"StorageSubsystem.d.ts","sourceRoot":"","sources":["../../src/storage/StorageSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAI9C,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAyB,SAAS,EAAE,MAAM,YAAY,CAAA;AAK7D;;;GAGG;AACH,qBAAa,gBAAgB;;gBAef,cAAc,EAAE,cAAc;IAIpC,EAAE,IAAI,OAAO,CAAC,SAAS,CAAC;IA2B9B,kCAAkC;IAC5B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAKlC,gCAAgC;IAC1B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM;IAEX,sCAAsC;IACtC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC;IAKhB,oCAAoC;IAC9B,MAAM;IACV,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,2FAA2F;IAC3F,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC;IAOhB;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAmClE;;;;;;OAMG;IACG,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAazE;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,UAAU;IAkEhC,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC;IAM7B,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,CAAC,CAAC,SAAS,GACrB,OAAO,CAAC,IAAI,CAAC;CA8CjB"}
@@ -217,6 +217,11 @@ export class StorageSubsystem {
217
217
  incrementalSize += chunk.size;
218
218
  }
219
219
  }
220
- return incrementalSize >= snapshotSize;
220
+ // if the file is currently small, don't worry, just compact
221
+ // this might seem a bit arbitrary (1k is arbitrary) but is designed to ensure compaction
222
+ // for documents with only a single large change on top of an empty (or nearly empty) document
223
+ // for example: imported NPM modules, images, etc.
224
+ // if we have even more incrementals (so far) than the snapshot, compact
225
+ return snapshotSize < 1024 || incrementalSize >= snapshotSize;
221
226
  }
222
227
  }
@@ -1 +1 @@
1
- {"version":3,"file":"keyHash.d.ts","sourceRoot":"","sources":["../../src/storage/keyHash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAI9C,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,UAIzC;AACD,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,GAAG,MAAM,CAIhD"}
1
+ {"version":3,"file":"keyHash.d.ts","sourceRoot":"","sources":["../../src/storage/keyHash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAI9C,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,UAIzC;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,GAAG,MAAM,CAIhD"}
@@ -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;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIhD,4FAA4F;AAC5F,qBAAa,sBAAuB,SAAQ,YAAY;;IAU1C,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IAmD9B;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,UAAU;IAyBxC;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,UAAU;IAYlC,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;CACF"}
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;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIhD,4FAA4F;AAC5F,qBAAa,sBAAuB,SAAQ,YAAY;;IAU1C,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IAoD9B;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,UAAU;IAyBxC;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,UAAU;IAYlC,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;CACF"}
@@ -32,11 +32,11 @@ export class CollectionSynchronizer extends Synchronizer {
32
32
  if (!this.repo.storageSubsystem) {
33
33
  return;
34
34
  }
35
- const persistanceInfo = this.repo.persistanceInfoByPeerId[peerId];
36
- if (!persistanceInfo || persistanceInfo.isEphemeral) {
35
+ const { storageId, isEphemeral } = this.repo.peerMetadataByPeerId[peerId] || {};
36
+ if (!storageId || isEphemeral) {
37
37
  return;
38
38
  }
39
- return this.repo.storageSubsystem.loadSyncState(handle.documentId, persistanceInfo.storageId);
39
+ return this.repo.storageSubsystem.loadSyncState(handle.documentId, storageId);
40
40
  },
41
41
  });
42
42
  docSynchronizer.on("message", event => this.emit("message", event));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automerge/automerge-repo",
3
- "version": "1.1.0-alpha.1",
3
+ "version": "1.1.0-alpha.3",
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>",
@@ -13,7 +13,6 @@
13
13
  "test:coverage": "c8 --reporter=lcov --reporter=html --reporter=text yarn test",
14
14
  "test": "vitest",
15
15
  "test:watch": "npm-watch test",
16
- "test:log": "cross-env DEBUG='automerge-repo:*' yarn test",
17
16
  "fuzz": "ts-node --esm --experimentalSpecifierResolution=node fuzz/fuzz.ts"
18
17
  },
19
18
  "browser": {
@@ -23,7 +22,7 @@
23
22
  "http-server": "^14.1.0"
24
23
  },
25
24
  "dependencies": {
26
- "@automerge/automerge": "^2.1.8-alpha.1",
25
+ "@automerge/automerge": "^2.1.8-alpha.2",
27
26
  "bs58check": "^3.0.1",
28
27
  "cbor-x": "^1.3.0",
29
28
  "debug": "^4.3.4",
@@ -55,5 +54,5 @@
55
54
  "publishConfig": {
56
55
  "access": "public"
57
56
  },
58
- "gitHead": "11805d698f860bd6ffb3ca028d3b57e718690b5a"
57
+ "gitHead": "0d76620579403005a01d4205ee15fd08a85d445c"
59
58
  }
package/src/Repo.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  } from "./AutomergeUrl.js"
9
9
  import { DocHandle, DocHandleEncodedChangePayload } from "./DocHandle.js"
10
10
  import { throttle } from "./helpers/throttle.js"
11
- import { NetworkAdapter } from "./network/NetworkAdapter.js"
11
+ import { NetworkAdapter, type PeerMetadata } from "./network/NetworkAdapter.js"
12
12
  import { NetworkSubsystem } from "./network/NetworkSubsystem.js"
13
13
  import { StorageAdapter } from "./storage/StorageAdapter.js"
14
14
  import { StorageSubsystem } from "./storage/StorageSubsystem.js"
@@ -47,9 +47,9 @@ export class Repo extends EventEmitter<RepoEvents> {
47
47
  /** @hidden */
48
48
  sharePolicy: SharePolicy = async () => true
49
49
 
50
- /** maps peer id to to persistance information (storageId, isEphemeral), access by collection synchronizer */
50
+ /** maps peer id to to persistence information (storageId, isEphemeral), access by collection synchronizer */
51
51
  /** @hidden */
52
- persistanceInfoByPeerId: Record<PeerId, PersistanceInfo> = {}
52
+ peerMetadataByPeerId: Record<PeerId, PeerMetadata> = {}
53
53
 
54
54
  #remoteHeadsSubscriptions = new RemoteHeadsSubscriptions()
55
55
 
@@ -147,23 +147,28 @@ export class Repo extends EventEmitter<RepoEvents> {
147
147
 
148
148
  // NETWORK
149
149
  // The network subsystem deals with sending and receiving messages to and from peers.
150
+
151
+ const myPeerMetadata: Promise<PeerMetadata> = new Promise(
152
+ async (resolve, reject) =>
153
+ resolve({
154
+ storageId: await storageSubsystem?.id(),
155
+ isEphemeral,
156
+ } as PeerMetadata)
157
+ )
158
+
150
159
  const networkSubsystem = new NetworkSubsystem(
151
160
  network,
152
161
  peerId,
153
- storageSubsystem?.id() ?? Promise.resolve(undefined),
154
- isEphemeral
162
+ myPeerMetadata
155
163
  )
156
164
  this.networkSubsystem = networkSubsystem
157
165
 
158
166
  // When we get a new peer, register it with the synchronizer
159
- networkSubsystem.on("peer", async ({ peerId, storageId, isEphemeral }) => {
167
+ networkSubsystem.on("peer", async ({ peerId, peerMetadata }) => {
160
168
  this.#log("peer connected", { peerId })
161
169
 
162
- if (storageId) {
163
- this.persistanceInfoByPeerId[peerId] = {
164
- storageId,
165
- isEphemeral,
166
- }
170
+ if (peerMetadata) {
171
+ this.peerMetadataByPeerId[peerId] = { ...peerMetadata }
167
172
  }
168
173
 
169
174
  this.sharePolicy(peerId)
@@ -195,12 +200,11 @@ export class Repo extends EventEmitter<RepoEvents> {
195
200
 
196
201
  const handle = this.#handleCache[message.documentId]
197
202
 
198
- const info = this.persistanceInfoByPeerId[message.peerId]
199
- if (!info) {
203
+ const { storageId } = this.peerMetadataByPeerId[message.peerId] || {}
204
+ if (!storageId) {
200
205
  return
201
206
  }
202
207
 
203
- const { storageId } = info
204
208
  const heads = handle.getRemoteHeads(storageId)
205
209
  const haveHeadsChanged =
206
210
  message.syncState.theirHeads &&
@@ -280,14 +284,13 @@ export class Repo extends EventEmitter<RepoEvents> {
280
284
  return
281
285
  }
282
286
 
283
- const persistanceInfo = this.persistanceInfoByPeerId[message.peerId]
287
+ const { storageId, isEphemeral } =
288
+ this.peerMetadataByPeerId[message.peerId] || {}
284
289
 
285
- if (!persistanceInfo || persistanceInfo.isEphemeral) {
290
+ if (!storageId || isEphemeral) {
286
291
  return
287
292
  }
288
293
 
289
- const { storageId } = persistanceInfo
290
-
291
294
  let handler = this.#throttledSaveSyncStateHandlers[storageId]
292
295
  if (!handler) {
293
296
  handler = this.#throttledSaveSyncStateHandlers[storageId] = throttle(
@@ -453,11 +456,6 @@ export class Repo extends EventEmitter<RepoEvents> {
453
456
  }
454
457
  }
455
458
 
456
- interface PersistanceInfo {
457
- storageId: StorageId
458
- isEphemeral: boolean
459
- }
460
-
461
459
  export interface RepoConfig {
462
460
  /** Our unique identifier */
463
461
  peerId?: PeerId
package/src/index.ts CHANGED
@@ -67,6 +67,7 @@ export type {
67
67
  OpenPayload,
68
68
  PeerCandidatePayload,
69
69
  PeerDisconnectedPayload,
70
+ PeerMetadata,
70
71
  } from "./network/NetworkAdapter.js"
71
72
 
72
73
  export type {
@@ -3,6 +3,17 @@ import { PeerId } from "../types.js"
3
3
  import { Message } from "./messages.js"
4
4
  import { StorageId } from "../storage/types.js"
5
5
 
6
+ /**
7
+ * Describes a peer intent to the system
8
+ * storageId: the key for syncState to decide what the other peer already has
9
+ * isEphemeral: to decide if we bother recording this peer's sync state
10
+ *
11
+ */
12
+ export interface PeerMetadata {
13
+ storageId?: StorageId
14
+ isEphemeral?: boolean
15
+ }
16
+
6
17
  /** An interface representing some way to connect to other peers
7
18
  *
8
19
  * @remarks
@@ -12,20 +23,14 @@ import { StorageId } from "../storage/types.js"
12
23
  */
13
24
  export abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> {
14
25
  peerId?: PeerId // hmmm, maybe not
15
- storageId?: StorageId
16
- isEphemeral = true
26
+ peerMetadata?: PeerMetadata
17
27
 
18
28
  /** Called by the {@link Repo} to start the connection process
19
29
  *
20
30
  * @argument peerId - the peerId of this repo
21
- * @argument storageId - the storage id of the peer
22
- * @argument isEphemeral - weather or not the other end should persist our sync state
31
+ * @argument peerMetadata - how this adapter should present itself to other peers
23
32
  */
24
- abstract connect(
25
- peerId: PeerId,
26
- storageId: StorageId | undefined,
27
- isEphemeral: boolean
28
- ): void
33
+ abstract connect(peerId: PeerId, peerMetadata?: PeerMetadata): void
29
34
 
30
35
  /** Called by the {@link Repo} to send a message to a peer
31
36
  *
@@ -62,8 +67,7 @@ export interface OpenPayload {
62
67
 
63
68
  export interface PeerCandidatePayload {
64
69
  peerId: PeerId
65
- storageId?: StorageId
66
- isEphemeral: boolean
70
+ peerMetadata: PeerMetadata
67
71
  }
68
72
 
69
73
  export interface PeerDisconnectedPayload {
@@ -1,7 +1,11 @@
1
1
  import debug from "debug"
2
2
  import { EventEmitter } from "eventemitter3"
3
3
  import { PeerId, SessionId } from "../types.js"
4
- import { NetworkAdapter, PeerDisconnectedPayload } from "./NetworkAdapter.js"
4
+ import type {
5
+ NetworkAdapter,
6
+ PeerDisconnectedPayload,
7
+ PeerMetadata,
8
+ } from "./NetworkAdapter.js"
5
9
  import {
6
10
  EphemeralMessage,
7
11
  MessageContents,
@@ -29,8 +33,7 @@ export class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
29
33
  constructor(
30
34
  adapters: NetworkAdapter[],
31
35
  public peerId = randomPeerId(),
32
- private storageId: Promise<StorageId | undefined>, // todo: we shouldn't pass a promise here
33
- private isEphemeral: boolean
36
+ private peerMetadata: Promise<PeerMetadata>
34
37
  ) {
35
38
  super()
36
39
  this.#log = debug(`automerge-repo:network:${this.peerId}`)
@@ -52,21 +55,17 @@ export class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
52
55
  }
53
56
  })
54
57
 
55
- networkAdapter.on(
56
- "peer-candidate",
57
- ({ peerId, storageId, isEphemeral }) => {
58
- this.#log(`peer candidate: ${peerId} `)
58
+ networkAdapter.on("peer-candidate", ({ peerId, peerMetadata }) => {
59
+ this.#log(`peer candidate: ${peerId} `)
60
+ // TODO: This is where authentication would happen
59
61
 
60
- // TODO: This is where authentication would happen
61
-
62
- if (!this.#adaptersByPeer[peerId]) {
63
- // TODO: handle losing a server here
64
- this.#adaptersByPeer[peerId] = networkAdapter
65
- }
66
-
67
- this.emit("peer", { peerId, storageId, isEphemeral })
62
+ if (!this.#adaptersByPeer[peerId]) {
63
+ // TODO: handle losing a server here
64
+ this.#adaptersByPeer[peerId] = networkAdapter
68
65
  }
69
- )
66
+
67
+ this.emit("peer", { peerId, peerMetadata })
68
+ })
70
69
 
71
70
  networkAdapter.on("peer-disconnected", ({ peerId }) => {
72
71
  this.#log(`peer disconnected: ${peerId} `)
@@ -107,8 +106,8 @@ export class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
107
106
  })
108
107
  })
109
108
 
110
- this.storageId.then(storageId => {
111
- networkAdapter.connect(this.peerId, storageId, this.isEphemeral)
109
+ this.peerMetadata.then(peerMetadata => {
110
+ networkAdapter.connect(this.peerId, peerMetadata)
112
111
  })
113
112
  }
114
113
 
@@ -182,6 +181,5 @@ export interface NetworkSubsystemEvents {
182
181
 
183
182
  export interface PeerPayload {
184
183
  peerId: PeerId
185
- storageId?: StorageId
186
- isEphemeral: boolean
184
+ peerMetadata: PeerMetadata
187
185
  }
@@ -279,6 +279,11 @@ export class StorageSubsystem {
279
279
  incrementalSize += chunk.size
280
280
  }
281
281
  }
282
- return incrementalSize >= snapshotSize
282
+ // if the file is currently small, don't worry, just compact
283
+ // this might seem a bit arbitrary (1k is arbitrary) but is designed to ensure compaction
284
+ // for documents with only a single large change on top of an empty (or nearly empty) document
285
+ // for example: imported NPM modules, images, etc.
286
+ // if we have even more incrementals (so far) than the snapshot, compact
287
+ return snapshotSize < 1024 || incrementalSize >= snapshotSize
283
288
  }
284
289
  }
@@ -7,11 +7,13 @@ export function keyHash(binary: Uint8Array) {
7
7
  const hash = sha256.hash(binary)
8
8
  return bufferToHexString(hash)
9
9
  }
10
+
10
11
  export function headsHash(heads: A.Heads): string {
11
12
  const encoder = new TextEncoder()
12
13
  const headsbinary = mergeArrays(heads.map((h: string) => encoder.encode(h)))
13
14
  return keyHash(headsbinary)
14
15
  }
16
+
15
17
  function bufferToHexString(data: Uint8Array) {
16
18
  return Array.from(data, byte => byte.toString(16).padStart(2, "0")).join("")
17
19
  }
@@ -42,14 +42,15 @@ export class CollectionSynchronizer extends Synchronizer {
42
42
  return
43
43
  }
44
44
 
45
- const persistanceInfo = this.repo.persistanceInfoByPeerId[peerId]
46
- if (!persistanceInfo || persistanceInfo.isEphemeral) {
45
+ const { storageId, isEphemeral } =
46
+ this.repo.peerMetadataByPeerId[peerId] || {}
47
+ if (!storageId || isEphemeral) {
47
48
  return
48
49
  }
49
50
 
50
51
  return this.repo.storageSubsystem.loadSyncState(
51
52
  handle.documentId,
52
- persistanceInfo.storageId
53
+ storageId
53
54
  )
54
55
  },
55
56
  })