@automerge/automerge-repo 2.4.0-alpha.0 → 2.4.0-alpha.2
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/AutomergeUrl.d.ts.map +1 -1
- package/dist/AutomergeUrl.js +1 -5
- package/dist/Repo.d.ts +22 -2
- package/dist/Repo.d.ts.map +1 -1
- package/dist/Repo.js +50 -10
- package/package.json +2 -2
- package/src/AutomergeUrl.ts +1 -5
- package/src/Repo.ts +66 -9
- package/test/AutomergeUrl.test.ts +10 -5
- package/test/Repo.test.ts +45 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AutomergeUrl.d.ts","sourceRoot":"","sources":["../src/AutomergeUrl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,QAAQ,EACT,MAAM,YAAY,CAAA;AASnB,OAAO,KAAK,EAAE,KAAK,IAAI,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAExE,eAAO,MAAM,SAAS,eAAe,CAAA;AAErC,UAAU,kBAAkB;IAC1B,2BAA2B;IAC3B,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,8BAA8B;IAC9B,UAAU,EAAE,UAAU,CAAA;IACtB,mDAAmD;IACnD,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,sGAAsG;AACtG,eAAO,MAAM,iBAAiB,GAAI,KAAK,YAAY,KAAG,kBAsBrD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAChC,KAAK,UAAU,GAAG,UAAU,GAAG,gBAAgB,KAC9C,YAgCF,CAAA;AAED,gEAAgE;AAChE,eAAO,MAAM,eAAe,GAAI,KAAK,YAAY,KAAG,MAAM,EAAE,GAAG,SAG9D,CAAA;AAED,eAAO,MAAM,2BAA2B,GAAI,IAAI,aAAa,6BAO9C,CAAA;AAEf;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,KAAK,OAAO,KAAG,GAAG,IAAI,YAsBzD,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,KAAK,OAAO,KAAG,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"AutomergeUrl.d.ts","sourceRoot":"","sources":["../src/AutomergeUrl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,QAAQ,EACT,MAAM,YAAY,CAAA;AASnB,OAAO,KAAK,EAAE,KAAK,IAAI,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAExE,eAAO,MAAM,SAAS,eAAe,CAAA;AAErC,UAAU,kBAAkB;IAC1B,2BAA2B;IAC3B,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,8BAA8B;IAC9B,UAAU,EAAE,UAAU,CAAA;IACtB,mDAAmD;IACnD,KAAK,CAAC,EAAE,QAAQ,CAAA;IAChB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,sGAAsG;AACtG,eAAO,MAAM,iBAAiB,GAAI,KAAK,YAAY,KAAG,kBAsBrD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAChC,KAAK,UAAU,GAAG,UAAU,GAAG,gBAAgB,KAC9C,YAgCF,CAAA;AAED,gEAAgE;AAChE,eAAO,MAAM,eAAe,GAAI,KAAK,YAAY,KAAG,MAAM,EAAE,GAAG,SAG9D,CAAA;AAED,eAAO,MAAM,2BAA2B,GAAI,IAAI,aAAa,6BAO9C,CAAA;AAEf;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,KAAK,OAAO,KAAG,GAAG,IAAI,YAsBzD,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,KAAK,OAAO,KAAG,GAAG,IAAI,UAKvD,CAAA;AAED,eAAO,MAAM,WAAW,GAAI,KAAK,OAAO,KAAG,GAAG,IAAI,gBACH,CAAA;AAE/C;;GAEG;AACH,eAAO,MAAM,oBAAoB,QAAO,YAGvC,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,OAAO,UAAU,KACjB,gBAAgB,GAAG,SAAS,CAAA;AAE/D,eAAO,MAAM,kBAAkB,GAAI,OAAO,gBAAgB,KAC7B,UAAU,CAAA;AAEvC,eAAO,MAAM,WAAW,GAAI,OAAO,cAAc,KAAG,QACsB,CAAA;AAE1E,eAAO,MAAM,WAAW,GAAI,OAAO,QAAQ,KAAG,cACgC,CAAA;AAE9E,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,6BAI1C,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,GAAI,IAAI,aAAa,eAqBtD,CAAA;AAID,KAAK,UAAU,GAAG;IAChB,UAAU,EAAE,UAAU,GAAG,gBAAgB,CAAA;IACzC,KAAK,CAAC,EAAE,QAAQ,CAAA;CACjB,CAAA"}
|
package/dist/AutomergeUrl.js
CHANGED
|
@@ -103,11 +103,7 @@ export const isValidDocumentId = (str) => {
|
|
|
103
103
|
return false;
|
|
104
104
|
// try to decode from base58
|
|
105
105
|
const binaryDocumentID = documentIdToBinary(str);
|
|
106
|
-
|
|
107
|
-
return false; // invalid base58check encoding
|
|
108
|
-
// confirm that the document ID is a valid UUID
|
|
109
|
-
const documentId = Uuid.stringify(binaryDocumentID);
|
|
110
|
-
return Uuid.validate(documentId);
|
|
106
|
+
return binaryDocumentID !== undefined;
|
|
111
107
|
};
|
|
112
108
|
export const isValidUuid = (str) => typeof str === "string" && Uuid.validate(str);
|
|
113
109
|
/**
|
package/dist/Repo.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Heads } from "@automerge/automerge/slim";
|
|
1
2
|
import { EventEmitter } from "eventemitter3";
|
|
2
3
|
import { DocHandle } from "./DocHandle.js";
|
|
3
4
|
import { NetworkAdapterInterface, type PeerMetadata } from "./network/NetworkAdapterInterface.js";
|
|
@@ -39,7 +40,7 @@ export declare class Repo extends EventEmitter<RepoEvents> {
|
|
|
39
40
|
/** maps peer id to to persistence information (storageId, isEphemeral), access by collection synchronizer */
|
|
40
41
|
/** @hidden */
|
|
41
42
|
peerMetadataByPeerId: Record<PeerId, PeerMetadata>;
|
|
42
|
-
constructor({ storage, network, peerId, sharePolicy, shareConfig, isEphemeral, enableRemoteHeadsGossiping, denylist, saveDebounceRate, }?: RepoConfig);
|
|
43
|
+
constructor({ storage, network, peerId, sharePolicy, shareConfig, isEphemeral, enableRemoteHeadsGossiping, denylist, saveDebounceRate, idFactory, }?: RepoConfig);
|
|
43
44
|
/** Returns all the handles we have cached. */
|
|
44
45
|
get handles(): Record<DocumentId, DocHandle<any>>;
|
|
45
46
|
/** Returns a list of all connected peer ids */
|
|
@@ -60,6 +61,18 @@ export declare class Repo extends EventEmitter<RepoEvents> {
|
|
|
60
61
|
* system. we emit a `document` event to advertise interest in the document.
|
|
61
62
|
*/
|
|
62
63
|
create<T>(initialValue?: T): DocHandle<T>;
|
|
64
|
+
/**
|
|
65
|
+
* Creates a new document and returns a handle to it. The initial value of the
|
|
66
|
+
* document is an empty object `{}` unless an initial value is provided. The
|
|
67
|
+
* main difference between this and Repo.create is that if an `idGenerator`
|
|
68
|
+
* was provided at repo construction, that idGenerator will be used to
|
|
69
|
+
* generate the document ID of the document returned by this method.
|
|
70
|
+
*
|
|
71
|
+
* This is a hidden, experimental API which is subject to change or removal without notice.
|
|
72
|
+
* @hidden
|
|
73
|
+
* @experimental
|
|
74
|
+
*/
|
|
75
|
+
create2<T>(initialValue?: T): Promise<DocHandle<T>>;
|
|
63
76
|
/** Create a new DocHandle by cloning the history of an existing DocHandle.
|
|
64
77
|
*
|
|
65
78
|
* @param clonedHandle - The handle to clone
|
|
@@ -149,13 +162,16 @@ export interface RepoConfig {
|
|
|
149
162
|
/**
|
|
150
163
|
* Normal peers typically share generously with everyone (meaning we sync all our documents with
|
|
151
164
|
* all peers). A server only syncs documents that a peer explicitly requests by ID.
|
|
152
|
-
* @deprecated Use `shareConfig` instead
|
|
153
165
|
*/
|
|
154
166
|
sharePolicy?: SharePolicy;
|
|
155
167
|
/**
|
|
156
168
|
* Whether to share documents with other peers. By default we announce new
|
|
157
169
|
* documents to everyone and allow everyone access to documents, see the
|
|
158
170
|
* documentation for {@link ShareConfig} to override this
|
|
171
|
+
*
|
|
172
|
+
* Note that this is currently an experimental API and will very likely change
|
|
173
|
+
* without a major release.
|
|
174
|
+
* @experimental
|
|
159
175
|
*/
|
|
160
176
|
shareConfig?: ShareConfig;
|
|
161
177
|
/**
|
|
@@ -172,6 +188,10 @@ export interface RepoConfig {
|
|
|
172
188
|
* The debounce rate in milliseconds for saving documents. Defaults to 100ms.
|
|
173
189
|
*/
|
|
174
190
|
saveDebounceRate?: number;
|
|
191
|
+
/**
|
|
192
|
+
* @hidden
|
|
193
|
+
*/
|
|
194
|
+
idFactory?: (initialHeads: Heads) => Promise<Uint8Array>;
|
|
175
195
|
}
|
|
176
196
|
/** A function that determines whether we should share a document with a peer
|
|
177
197
|
*
|
package/dist/Repo.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"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"}
|
package/dist/Repo.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { next as Automerge } from "@automerge/automerge/slim";
|
|
2
2
|
import debug from "debug";
|
|
3
3
|
import { EventEmitter } from "eventemitter3";
|
|
4
|
-
import { encodeHeads, generateAutomergeUrl, interpretAsDocumentId, isValidAutomergeUrl, parseAutomergeUrl, } from "./AutomergeUrl.js";
|
|
4
|
+
import { binaryToDocumentId, encodeHeads, generateAutomergeUrl, interpretAsDocumentId, isValidAutomergeUrl, parseAutomergeUrl, } from "./AutomergeUrl.js";
|
|
5
5
|
import { DELETED, DocHandle, READY, UNAVAILABLE, UNLOADED, } from "./DocHandle.js";
|
|
6
6
|
import { RemoteHeadsSubscriptions } from "./RemoteHeadsSubscriptions.js";
|
|
7
7
|
import { headsAreSame } from "./helpers/headsAreSame.js";
|
|
@@ -45,10 +45,12 @@ export class Repo extends EventEmitter {
|
|
|
45
45
|
#remoteHeadsGossipingEnabled = false;
|
|
46
46
|
#progressCache = {};
|
|
47
47
|
#saveFns = {};
|
|
48
|
-
|
|
48
|
+
#idFactory;
|
|
49
|
+
constructor({ storage, network = [], peerId = randomPeerId(), sharePolicy, shareConfig, isEphemeral = storage === undefined, enableRemoteHeadsGossiping = false, denylist = [], saveDebounceRate = 100, idFactory, } = {}) {
|
|
49
50
|
super();
|
|
50
51
|
this.#remoteHeadsGossipingEnabled = enableRemoteHeadsGossiping;
|
|
51
52
|
this.#log = debug(`automerge-repo:repo`);
|
|
53
|
+
this.#idFactory = idFactory || null;
|
|
52
54
|
// Handle legacy sharePolicy
|
|
53
55
|
if (sharePolicy != null && shareConfig != null) {
|
|
54
56
|
throw new Error("cannot provide both sharePolicy and shareConfig at once");
|
|
@@ -300,6 +302,13 @@ export class Repo extends EventEmitter {
|
|
|
300
302
|
* system. we emit a `document` event to advertise interest in the document.
|
|
301
303
|
*/
|
|
302
304
|
create(initialValue) {
|
|
305
|
+
let initialDoc;
|
|
306
|
+
if (initialValue) {
|
|
307
|
+
initialDoc = Automerge.from(initialValue);
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
initialDoc = Automerge.emptyChange(Automerge.init());
|
|
311
|
+
}
|
|
303
312
|
// Generate a new UUID and store it in the buffer
|
|
304
313
|
const { documentId } = parseAutomergeUrl(generateAutomergeUrl());
|
|
305
314
|
const handle = this.#getHandle({
|
|
@@ -307,14 +316,45 @@ export class Repo extends EventEmitter {
|
|
|
307
316
|
});
|
|
308
317
|
this.#registerHandleWithSubsystems(handle);
|
|
309
318
|
handle.update(() => {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
319
|
+
return initialDoc;
|
|
320
|
+
});
|
|
321
|
+
handle.doneLoading();
|
|
322
|
+
return handle;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Creates a new document and returns a handle to it. The initial value of the
|
|
326
|
+
* document is an empty object `{}` unless an initial value is provided. The
|
|
327
|
+
* main difference between this and Repo.create is that if an `idGenerator`
|
|
328
|
+
* was provided at repo construction, that idGenerator will be used to
|
|
329
|
+
* generate the document ID of the document returned by this method.
|
|
330
|
+
*
|
|
331
|
+
* This is a hidden, experimental API which is subject to change or removal without notice.
|
|
332
|
+
* @hidden
|
|
333
|
+
* @experimental
|
|
334
|
+
*/
|
|
335
|
+
async create2(initialValue) {
|
|
336
|
+
// Note that the reason this method is hidden and experimental is because it is async,
|
|
337
|
+
// and it is async because we want to be able to call the #idGenerator, which is async.
|
|
338
|
+
// This is all really in service of wiring up keyhive and we probably need to find a
|
|
339
|
+
// nicer way to achieve this.
|
|
340
|
+
let initialDoc;
|
|
341
|
+
if (initialValue) {
|
|
342
|
+
initialDoc = Automerge.from(initialValue);
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
initialDoc = Automerge.emptyChange(Automerge.init());
|
|
346
|
+
}
|
|
347
|
+
let { documentId } = parseAutomergeUrl(generateAutomergeUrl());
|
|
348
|
+
if (this.#idFactory) {
|
|
349
|
+
const rawDocId = await this.#idFactory(Automerge.getHeads(initialDoc));
|
|
350
|
+
documentId = binaryToDocumentId(rawDocId);
|
|
351
|
+
}
|
|
352
|
+
const handle = this.#getHandle({
|
|
353
|
+
documentId,
|
|
354
|
+
});
|
|
355
|
+
this.#registerHandleWithSubsystems(handle);
|
|
356
|
+
handle.update(() => {
|
|
357
|
+
return initialDoc;
|
|
318
358
|
});
|
|
319
359
|
handle.doneLoading();
|
|
320
360
|
return handle;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automerge/automerge-repo",
|
|
3
|
-
"version": "2.4.0-alpha.
|
|
3
|
+
"version": "2.4.0-alpha.2",
|
|
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>",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"access": "public"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "f963f3a1a36292ac0ea417c1c17d180fd8e78ac5"
|
|
63
63
|
}
|
package/src/AutomergeUrl.ts
CHANGED
|
@@ -141,11 +141,7 @@ export const isValidDocumentId = (str: unknown): str is DocumentId => {
|
|
|
141
141
|
if (typeof str !== "string") return false
|
|
142
142
|
// try to decode from base58
|
|
143
143
|
const binaryDocumentID = documentIdToBinary(str as DocumentId)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
// confirm that the document ID is a valid UUID
|
|
147
|
-
const documentId = Uuid.stringify(binaryDocumentID)
|
|
148
|
-
return Uuid.validate(documentId)
|
|
144
|
+
return binaryDocumentID !== undefined
|
|
149
145
|
}
|
|
150
146
|
|
|
151
147
|
export const isValidUuid = (str: unknown): str is LegacyDocumentId =>
|
package/src/Repo.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { next as Automerge } from "@automerge/automerge/slim"
|
|
1
|
+
import { next as Automerge, Heads } from "@automerge/automerge/slim"
|
|
2
2
|
import debug from "debug"
|
|
3
3
|
import { EventEmitter } from "eventemitter3"
|
|
4
4
|
import {
|
|
5
|
+
binaryToDocumentId,
|
|
5
6
|
encodeHeads,
|
|
6
7
|
generateAutomergeUrl,
|
|
7
8
|
interpretAsDocumentId,
|
|
@@ -36,6 +37,7 @@ import {
|
|
|
36
37
|
import type {
|
|
37
38
|
AnyDocumentId,
|
|
38
39
|
AutomergeUrl,
|
|
40
|
+
BinaryDocumentId,
|
|
39
41
|
DocumentId,
|
|
40
42
|
PeerId,
|
|
41
43
|
} from "./types.js"
|
|
@@ -101,6 +103,7 @@ export class Repo extends EventEmitter<RepoEvents> {
|
|
|
101
103
|
DocumentId,
|
|
102
104
|
(payload: DocHandleEncodedChangePayload<any>) => void
|
|
103
105
|
> = {}
|
|
106
|
+
#idFactory: ((initialHeads: Heads) => Promise<Uint8Array>) | null
|
|
104
107
|
|
|
105
108
|
constructor({
|
|
106
109
|
storage,
|
|
@@ -112,11 +115,13 @@ export class Repo extends EventEmitter<RepoEvents> {
|
|
|
112
115
|
enableRemoteHeadsGossiping = false,
|
|
113
116
|
denylist = [],
|
|
114
117
|
saveDebounceRate = 100,
|
|
118
|
+
idFactory,
|
|
115
119
|
}: RepoConfig = {}) {
|
|
116
120
|
super()
|
|
117
121
|
this.#remoteHeadsGossipingEnabled = enableRemoteHeadsGossiping
|
|
118
122
|
this.#log = debug(`automerge-repo:repo`)
|
|
119
123
|
|
|
124
|
+
this.#idFactory = idFactory || null
|
|
120
125
|
// Handle legacy sharePolicy
|
|
121
126
|
if (sharePolicy != null && shareConfig != null) {
|
|
122
127
|
throw new Error("cannot provide both sharePolicy and shareConfig at once")
|
|
@@ -446,6 +451,13 @@ export class Repo extends EventEmitter<RepoEvents> {
|
|
|
446
451
|
* system. we emit a `document` event to advertise interest in the document.
|
|
447
452
|
*/
|
|
448
453
|
create<T>(initialValue?: T): DocHandle<T> {
|
|
454
|
+
let initialDoc: Automerge.Doc<T>
|
|
455
|
+
if (initialValue) {
|
|
456
|
+
initialDoc = Automerge.from(initialValue)
|
|
457
|
+
} else {
|
|
458
|
+
initialDoc = Automerge.emptyChange(Automerge.init())
|
|
459
|
+
}
|
|
460
|
+
|
|
449
461
|
// Generate a new UUID and store it in the buffer
|
|
450
462
|
const { documentId } = parseAutomergeUrl(generateAutomergeUrl())
|
|
451
463
|
const handle = this.#getHandle<T>({
|
|
@@ -455,19 +467,54 @@ export class Repo extends EventEmitter<RepoEvents> {
|
|
|
455
467
|
this.#registerHandleWithSubsystems(handle)
|
|
456
468
|
|
|
457
469
|
handle.update(() => {
|
|
458
|
-
|
|
459
|
-
if (initialValue) {
|
|
460
|
-
nextDoc = Automerge.from(initialValue)
|
|
461
|
-
} else {
|
|
462
|
-
nextDoc = Automerge.emptyChange(Automerge.init())
|
|
463
|
-
}
|
|
464
|
-
return nextDoc
|
|
470
|
+
return initialDoc
|
|
465
471
|
})
|
|
466
472
|
|
|
467
473
|
handle.doneLoading()
|
|
468
474
|
return handle
|
|
469
475
|
}
|
|
470
476
|
|
|
477
|
+
/**
|
|
478
|
+
* Creates a new document and returns a handle to it. The initial value of the
|
|
479
|
+
* document is an empty object `{}` unless an initial value is provided. The
|
|
480
|
+
* main difference between this and Repo.create is that if an `idGenerator`
|
|
481
|
+
* was provided at repo construction, that idGenerator will be used to
|
|
482
|
+
* generate the document ID of the document returned by this method.
|
|
483
|
+
*
|
|
484
|
+
* This is a hidden, experimental API which is subject to change or removal without notice.
|
|
485
|
+
* @hidden
|
|
486
|
+
* @experimental
|
|
487
|
+
*/
|
|
488
|
+
async create2<T>(initialValue?: T): Promise<DocHandle<T>> {
|
|
489
|
+
// Note that the reason this method is hidden and experimental is because it is async,
|
|
490
|
+
// and it is async because we want to be able to call the #idGenerator, which is async.
|
|
491
|
+
// This is all really in service of wiring up keyhive and we probably need to find a
|
|
492
|
+
// nicer way to achieve this.
|
|
493
|
+
let initialDoc: Automerge.Doc<T>
|
|
494
|
+
if (initialValue) {
|
|
495
|
+
initialDoc = Automerge.from(initialValue)
|
|
496
|
+
} else {
|
|
497
|
+
initialDoc = Automerge.emptyChange(Automerge.init())
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
let { documentId } = parseAutomergeUrl(generateAutomergeUrl())
|
|
501
|
+
if (this.#idFactory) {
|
|
502
|
+
const rawDocId = await this.#idFactory(Automerge.getHeads(initialDoc))
|
|
503
|
+
documentId = binaryToDocumentId(rawDocId as BinaryDocumentId)
|
|
504
|
+
}
|
|
505
|
+
const handle = this.#getHandle<T>({
|
|
506
|
+
documentId,
|
|
507
|
+
}) as DocHandle<T>
|
|
508
|
+
|
|
509
|
+
this.#registerHandleWithSubsystems(handle)
|
|
510
|
+
|
|
511
|
+
handle.update(() => {
|
|
512
|
+
return initialDoc
|
|
513
|
+
})
|
|
514
|
+
|
|
515
|
+
handle.doneLoading()
|
|
516
|
+
return handle
|
|
517
|
+
}
|
|
471
518
|
/** Create a new DocHandle by cloning the history of an existing DocHandle.
|
|
472
519
|
*
|
|
473
520
|
* @param clonedHandle - The handle to clone
|
|
@@ -937,7 +984,6 @@ export interface RepoConfig {
|
|
|
937
984
|
/**
|
|
938
985
|
* Normal peers typically share generously with everyone (meaning we sync all our documents with
|
|
939
986
|
* all peers). A server only syncs documents that a peer explicitly requests by ID.
|
|
940
|
-
* @deprecated Use `shareConfig` instead
|
|
941
987
|
*/
|
|
942
988
|
sharePolicy?: SharePolicy
|
|
943
989
|
|
|
@@ -945,6 +991,10 @@ export interface RepoConfig {
|
|
|
945
991
|
* Whether to share documents with other peers. By default we announce new
|
|
946
992
|
* documents to everyone and allow everyone access to documents, see the
|
|
947
993
|
* documentation for {@link ShareConfig} to override this
|
|
994
|
+
*
|
|
995
|
+
* Note that this is currently an experimental API and will very likely change
|
|
996
|
+
* without a major release.
|
|
997
|
+
* @experimental
|
|
948
998
|
*/
|
|
949
999
|
shareConfig?: ShareConfig
|
|
950
1000
|
|
|
@@ -964,6 +1014,13 @@ export interface RepoConfig {
|
|
|
964
1014
|
* The debounce rate in milliseconds for saving documents. Defaults to 100ms.
|
|
965
1015
|
*/
|
|
966
1016
|
saveDebounceRate?: number
|
|
1017
|
+
|
|
1018
|
+
// This is hidden for now because it's an experimental API, mostly here in order
|
|
1019
|
+
// for keyhive to be able to control the ID generation
|
|
1020
|
+
/**
|
|
1021
|
+
* @hidden
|
|
1022
|
+
*/
|
|
1023
|
+
idFactory?: (initialHeads: Heads) => Promise<Uint8Array>
|
|
967
1024
|
}
|
|
968
1025
|
|
|
969
1026
|
/** A function that determines whether we should share a document with a peer
|
|
@@ -2,6 +2,7 @@ import assert from "assert"
|
|
|
2
2
|
import bs58check from "bs58check"
|
|
3
3
|
import { describe, it } from "vitest"
|
|
4
4
|
import {
|
|
5
|
+
binaryToDocumentId,
|
|
5
6
|
generateAutomergeUrl,
|
|
6
7
|
getHeadsFromUrl,
|
|
7
8
|
isValidAutomergeUrl,
|
|
@@ -14,6 +15,7 @@ import type {
|
|
|
14
15
|
BinaryDocumentId,
|
|
15
16
|
DocumentId,
|
|
16
17
|
} from "../src/types.js"
|
|
18
|
+
import { interpretAsDocumentId } from "../src/AutomergeUrl.js"
|
|
17
19
|
|
|
18
20
|
const goodUrl = "automerge:4NMNnkMhL8jXrdJ9jamS58PAVdXu" as AutomergeUrl
|
|
19
21
|
const badChecksumUrl = "automerge:badbadbad" as AutomergeUrl
|
|
@@ -94,15 +96,18 @@ describe("AutomergeUrl", () => {
|
|
|
94
96
|
assert(isValidAutomergeUrl(url) === false)
|
|
95
97
|
})
|
|
96
98
|
|
|
97
|
-
it("should return false for a documentId that is not a valid UUID ", () => {
|
|
98
|
-
const url = stringifyAutomergeUrl({ documentId: badUuidDocumentId })
|
|
99
|
-
assert(isValidAutomergeUrl(url) === false)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
99
|
it("should return false for a documentId that is just some random type", () => {
|
|
103
100
|
assert(isValidAutomergeUrl({ foo: "bar" } as unknown) === false)
|
|
104
101
|
})
|
|
105
102
|
})
|
|
103
|
+
|
|
104
|
+
it("should allow arbitrary uint8array ids", () => {
|
|
105
|
+
const raw = new Uint8Array("custom-id".split("").map(c => c.charCodeAt(0)))
|
|
106
|
+
const documentId = binaryToDocumentId(raw as BinaryDocumentId)
|
|
107
|
+
const url = stringifyAutomergeUrl({ documentId })
|
|
108
|
+
const interpreted = interpretAsDocumentId(url)
|
|
109
|
+
assert.deepStrictEqual(interpreted, documentId)
|
|
110
|
+
})
|
|
106
111
|
})
|
|
107
112
|
|
|
108
113
|
describe("AutomergeUrl with heads", () => {
|
package/test/Repo.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { next as A } from "@automerge/automerge"
|
|
1
|
+
import { next as A, Heads } from "@automerge/automerge"
|
|
2
2
|
import { MessageChannelNetworkAdapter } from "../../automerge-repo-network-messagechannel/src/index.js"
|
|
3
3
|
import assert from "assert"
|
|
4
4
|
import * as Uuid from "uuid"
|
|
@@ -2027,6 +2027,50 @@ describe("Repo.find() abort behavior", () => {
|
|
|
2027
2027
|
controller.abort()
|
|
2028
2028
|
expect(handle.url).toBe(url)
|
|
2029
2029
|
})
|
|
2030
|
+
|
|
2031
|
+
describe("creating a document with a custom ID factory", () => {
|
|
2032
|
+
it("creates a document with the custom ID", async () => {
|
|
2033
|
+
const id = new Uint8Array("custom-id".split("").map(c => c.charCodeAt(0)))
|
|
2034
|
+
const repo = new Repo({
|
|
2035
|
+
idFactory: () => id,
|
|
2036
|
+
})
|
|
2037
|
+
const handle = await repo.create2()
|
|
2038
|
+
expect(handle.documentId).toBe("9HUp4wuzRMx9MRvN4x")
|
|
2039
|
+
})
|
|
2040
|
+
|
|
2041
|
+
it("passes the heads of the document to the callback", async () => {
|
|
2042
|
+
const id = new Uint8Array("custom-id".split("").map(c => c.charCodeAt(0)))
|
|
2043
|
+
let calledHeads: Heads | null = null
|
|
2044
|
+
const repo = new Repo({
|
|
2045
|
+
idFactory: (heads: Heads) => {
|
|
2046
|
+
calledHeads = heads
|
|
2047
|
+
return id
|
|
2048
|
+
},
|
|
2049
|
+
})
|
|
2050
|
+
const handle = await repo.create2()
|
|
2051
|
+
const actualHeads = A.getHeads(handle.doc())
|
|
2052
|
+
assert.deepStrictEqual(actualHeads, calledHeads)
|
|
2053
|
+
})
|
|
2054
|
+
|
|
2055
|
+
it("allows syncing documents with a custom ID", async () => {
|
|
2056
|
+
const [aliceToBob, bobToAlice] = DummyNetworkAdapter.createConnectedPair()
|
|
2057
|
+
const alice = new Repo({
|
|
2058
|
+
peerId: "alice" as PeerId,
|
|
2059
|
+
idFactory: () =>
|
|
2060
|
+
new Uint8Array("custom-id".split("").map(c => c.charCodeAt(0))),
|
|
2061
|
+
network: [aliceToBob],
|
|
2062
|
+
})
|
|
2063
|
+
const bob = new Repo({ peerId: "bob" as PeerId, network: [bobToAlice] })
|
|
2064
|
+
aliceToBob.peerCandidate("bob" as PeerId)
|
|
2065
|
+
bobToAlice.peerCandidate("alice" as PeerId)
|
|
2066
|
+
|
|
2067
|
+
await pause(50)
|
|
2068
|
+
|
|
2069
|
+
const handle = await alice.create2({ foo: "bar" })
|
|
2070
|
+
const bobHandle = await bob.find(handle.url)
|
|
2071
|
+
assert.deepStrictEqual(bobHandle.doc(), { foo: "bar" })
|
|
2072
|
+
})
|
|
2073
|
+
})
|
|
2030
2074
|
})
|
|
2031
2075
|
|
|
2032
2076
|
const warn = console.warn
|