@comapeo/core 2.1.0 → 2.3.0
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/blob-store/downloader.d.ts +43 -0
- package/dist/blob-store/downloader.d.ts.map +1 -0
- package/dist/blob-store/entries-stream.d.ts +13 -0
- package/dist/blob-store/entries-stream.d.ts.map +1 -0
- package/dist/blob-store/hyperdrive-index.d.ts +20 -0
- package/dist/blob-store/hyperdrive-index.d.ts.map +1 -0
- package/dist/blob-store/index.d.ts +29 -21
- package/dist/blob-store/index.d.ts.map +1 -1
- package/dist/blob-store/utils.d.ts +27 -0
- package/dist/blob-store/utils.d.ts.map +1 -0
- package/dist/core-manager/index.d.ts +1 -1
- package/dist/core-manager/index.d.ts.map +1 -1
- package/dist/core-ownership.d.ts.map +1 -1
- package/dist/datastore/index.d.ts +1 -1
- package/dist/datastore/index.d.ts.map +1 -1
- package/dist/datatype/index.d.ts +5 -1
- package/dist/discovery/local-discovery.d.ts.map +1 -1
- package/dist/errors.d.ts +6 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/fastify-plugins/blobs.d.ts.map +1 -1
- package/dist/fastify-plugins/maps.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/error.d.ts +14 -0
- package/dist/lib/error.d.ts.map +1 -1
- package/dist/mapeo-manager.d.ts.map +1 -1
- package/dist/mapeo-project.d.ts +17 -17
- package/dist/mapeo-project.d.ts.map +1 -1
- package/dist/member-api.d.ts +4 -0
- package/dist/member-api.d.ts.map +1 -1
- package/dist/roles.d.ts.map +1 -1
- package/dist/schema/project.d.ts +2 -2
- package/dist/sync/core-sync-state.d.ts +20 -15
- package/dist/sync/core-sync-state.d.ts.map +1 -1
- package/dist/sync/namespace-sync-state.d.ts +13 -1
- package/dist/sync/namespace-sync-state.d.ts.map +1 -1
- package/dist/sync/peer-sync-controller.d.ts +1 -1
- package/dist/sync/sync-api.d.ts +22 -3
- package/dist/sync/sync-api.d.ts.map +1 -1
- package/dist/sync/sync-state.d.ts +12 -0
- package/dist/sync/sync-state.d.ts.map +1 -1
- package/dist/translation-api.d.ts +2 -2
- package/dist/translation-api.d.ts.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -3
- package/src/blob-store/downloader.js +130 -0
- package/src/blob-store/entries-stream.js +81 -0
- package/src/blob-store/hyperdrive-index.js +122 -0
- package/src/blob-store/index.js +56 -115
- package/src/blob-store/utils.js +54 -0
- package/src/core-manager/index.js +2 -1
- package/src/core-ownership.js +2 -4
- package/src/datastore/index.js +4 -3
- package/src/datatype/index.d.ts +5 -1
- package/src/datatype/index.js +22 -9
- package/src/discovery/local-discovery.js +2 -1
- package/src/errors.js +11 -2
- package/src/fastify-plugins/blobs.js +16 -1
- package/src/fastify-plugins/maps.js +2 -1
- package/src/lib/error.js +24 -0
- package/src/mapeo-manager.js +6 -3
- package/src/mapeo-project.js +89 -19
- package/src/member-api.js +68 -26
- package/src/roles.js +38 -32
- package/src/sync/core-sync-state.js +39 -23
- package/src/sync/namespace-sync-state.js +22 -0
- package/src/sync/sync-api.js +30 -4
- package/src/sync/sync-state.js +18 -0
- package/src/translation-api.js +5 -9
- package/src/types.ts +8 -0
- package/dist/blob-store/live-download.d.ts +0 -107
- package/dist/blob-store/live-download.d.ts.map +0 -1
- package/src/blob-store/live-download.js +0 -373
package/dist/schema/project.d.ts
CHANGED
|
@@ -118,7 +118,7 @@ export const translationTable: import("drizzle-orm/sqlite-core").SQLiteTableWith
|
|
|
118
118
|
tableName: "translation";
|
|
119
119
|
dataType: "string";
|
|
120
120
|
columnType: "SQLiteText";
|
|
121
|
-
data: "
|
|
121
|
+
data: "track" | "role" | "projectSettings" | "preset" | "observation" | "field" | "deviceInfo" | "UNRECOGNIZED" | "type_unspecified";
|
|
122
122
|
driverParam: string;
|
|
123
123
|
notNull: true;
|
|
124
124
|
hasDefault: false;
|
|
@@ -2009,7 +2009,7 @@ export const coresTable: import("drizzle-orm/sqlite-core").SQLiteTableWithColumn
|
|
|
2009
2009
|
tableName: "cores";
|
|
2010
2010
|
dataType: "string";
|
|
2011
2011
|
columnType: "SQLiteText";
|
|
2012
|
-
data: "
|
|
2012
|
+
data: "auth" | "config" | "data" | "blobIndex" | "blob";
|
|
2013
2013
|
driverParam: string;
|
|
2014
2014
|
notNull: true;
|
|
2015
2015
|
hasDefault: false;
|
|
@@ -112,12 +112,16 @@ export class CoreSyncState {
|
|
|
112
112
|
* blocks/ranges that are added here
|
|
113
113
|
*
|
|
114
114
|
* @param {PeerId} peerId
|
|
115
|
-
* @param {
|
|
115
|
+
* @param {number} start
|
|
116
|
+
* @param {number} length
|
|
117
|
+
* @returns {void}
|
|
118
|
+
*/
|
|
119
|
+
addWantRange(peerId: PeerId, start: number, length: number): void;
|
|
120
|
+
/**
|
|
121
|
+
* @param {PeerId} peerId
|
|
122
|
+
* @returns {void}
|
|
116
123
|
*/
|
|
117
|
-
|
|
118
|
-
start: number;
|
|
119
|
-
length: number;
|
|
120
|
-
}>): void;
|
|
124
|
+
clearWantRanges(peerId: PeerId): void;
|
|
121
125
|
/**
|
|
122
126
|
* @param {PeerId} peerId
|
|
123
127
|
*/
|
|
@@ -138,9 +142,6 @@ export class CoreSyncState {
|
|
|
138
142
|
* Only exported for testing
|
|
139
143
|
*/
|
|
140
144
|
export class PeerState {
|
|
141
|
-
constructor({ wantAll }?: {
|
|
142
|
-
wantAll?: boolean | undefined;
|
|
143
|
-
});
|
|
144
145
|
/** @type {PeerNamespaceState['status']} */
|
|
145
146
|
status: PeerNamespaceState["status"];
|
|
146
147
|
get preHavesBitfield(): RemoteBitfield;
|
|
@@ -154,18 +155,22 @@ export class PeerState {
|
|
|
154
155
|
*/
|
|
155
156
|
setHavesBitfield(bitfield: HypercoreRemoteBitfield): void;
|
|
156
157
|
/**
|
|
157
|
-
*
|
|
158
|
+
* Add a range of blocks that a peer wants. This is not part of the Hypercore
|
|
158
159
|
* protocol, so we need our own extension messages that a peer can use to
|
|
159
160
|
* inform us which blocks they are interested in. For most cores peers always
|
|
160
|
-
* want all blocks, but for blob cores
|
|
161
|
+
* want all blocks, but for blob cores peers may only want preview or
|
|
161
162
|
* thumbnail versions of media
|
|
162
163
|
*
|
|
163
|
-
* @param {
|
|
164
|
+
* @param {number} start
|
|
165
|
+
* @param {number} length
|
|
166
|
+
* @returns {void}
|
|
167
|
+
*/
|
|
168
|
+
addWantRange(start: number, length: number): void;
|
|
169
|
+
/**
|
|
170
|
+
* Set the range of blocks that this peer wants to the empty set. In other
|
|
171
|
+
* words, this peer wants nothing from this core.
|
|
164
172
|
*/
|
|
165
|
-
|
|
166
|
-
start: number;
|
|
167
|
-
length: number;
|
|
168
|
-
}): void;
|
|
173
|
+
clearWantRanges(): void;
|
|
169
174
|
/**
|
|
170
175
|
* Returns whether the peer has the block at `index`. If a pre-have bitfield
|
|
171
176
|
* has been passed, this is used if no connected peer bitfield is available.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core-sync-state.d.ts","sourceRoot":"","sources":["../../src/sync/core-sync-state.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"core-sync-state.d.ts","sourceRoot":"","sources":["../../src/sync/core-sync-state.js"],"names":[],"mappings":"AAwYA;;;;;;;GAOG;AACH,uCALW,aAAa;;;;EA6DvB;AAED;;;;GAIG;AACH,8BAFW,MAAM,UAMhB;AA9cD,uFAAuF;AAEvF;;GAEG;AACH;;GAEG;AACH;;;;;;;GAOG;AACH;;;;;GAKG;AACH;;;;;;GAMG;AACH;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH;IAaE;;;;;;OAMG;IACH,kEALG;QAAyB,QAAQ,EAAzB,MAAM,IAAI;QACgE,mBAAmB,EAA7F,GAAG,CAAC,MAAM,EAAE,OAAO,2BAA2B,EAAE,kBAAkB,CAAC;QACnD,SAAS,EAAzB,SAAS;QACK,MAAM;KAAC,EAY/B;IAEU,YAAM,YAAY,CAAA;IAY7B;;;;;;OAMG;IACH,iBAFW,OAAO,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,QAiC/C;IAED;;;;;;;;OAQG;IACH,uBAJW,MAAM,SACN,MAAM,YACN,WAAW,QAsBrB;IAED;;;;;;;;;OASG;IACH,qBALW,MAAM,SACN,MAAM,UACN,MAAM,GACJ,IAAI,CAMhB;IAED;;;OAGG;IACH,wBAHW,MAAM,GACJ,IAAI,CAMhB;IAED;;OAEG;IACH,gBAFW,MAAM,QAMhB;IAED;;OAEG;IACH,uBAFW,MAAM,QAOhB;;CAkEF;AAED;;;;;;;;GAQG;AACH;IAUE,2CAA2C;IAC3C,QADW,kBAAkB,CAAC,QAAQ,CAAC,CACrB;IAClB,uCAEC;IACD;;;OAGG;IACH,sBAHW,MAAM,YACN,WAAW,WAIrB;IACD;;OAEG;IACH,2BAFW,uBAAuB,QAIjC;IACD;;;;;;;;;;OAUG;IACH,oBAJW,MAAM,UACN,MAAM,GACJ,IAAI,CAKhB;IACD;;;OAGG;IACH,wBAEC;IACD;;;;;OAKG;IACH,YAFW,MAAM,WAIhB;IACD;;;;;;OAMG;IACH,gBAJW,MAAM,GACJ,MAAM,CAOlB;IACD;;;;OAIG;IACH,YAFW,MAAM,WAIhB;IACD;;;;;;OAMG;IACH,gBAJW,MAAM,GACJ,MAAM,CAQlB;;CACF;uBA9XY,cAAc;qBAGd,MAAM;;;;;YAIL,MAAM,GAAG,SAAS;gBAClB,SAAS;kBACT,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC;yBACtB,GAAG,CAAC,MAAM,EAAE,OAAO,2BAA2B,EAAE,kBAAkB,CAAC;eACnE,SAAS;;;;;;UAIT,MAAM;;;;UACN,MAAM;;;;YACN,MAAM;;;;;;UAIN,MAAM;;;;UACN,MAAM;;;;YACN,MAAM;YACN,SAAS,GAAG,UAAU,GAAG,SAAS;;;;;;gBAIlC,MAAM;;;;gBACN,cAAc;;;;kBACd,GAAG,MAAgB,IAAN,MAAM,GAAG,kBAAkB,GAAE;;+BAjCe,aAAa;uBAD7D,cAAc;2BAD9B,oCAAoC;6CAE4B,aAAa"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @template {Namespace} [TNamespace=Namespace]
|
|
7
7
|
*/
|
|
8
|
-
export class NamespaceSyncState<TNamespace extends Namespace = "
|
|
8
|
+
export class NamespaceSyncState<TNamespace extends Namespace = "auth" | "config" | "data" | "blobIndex" | "blob"> {
|
|
9
9
|
/**
|
|
10
10
|
* @param {object} opts
|
|
11
11
|
* @param {TNamespace} opts.namespace
|
|
@@ -32,6 +32,18 @@ export class NamespaceSyncState<TNamespace extends Namespace = "blob" | "auth" |
|
|
|
32
32
|
* @param {string} peerId
|
|
33
33
|
*/
|
|
34
34
|
disconnectPeer(peerId: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* @param {string} peerId
|
|
37
|
+
* @param {number} start
|
|
38
|
+
* @param {number} length
|
|
39
|
+
* @returns {void}
|
|
40
|
+
*/
|
|
41
|
+
addWantRange(peerId: string, start: number, length: number): void;
|
|
42
|
+
/**
|
|
43
|
+
* @param {string} peerId
|
|
44
|
+
* @returns {void}
|
|
45
|
+
*/
|
|
46
|
+
clearWantRanges(peerId: string): void;
|
|
35
47
|
#private;
|
|
36
48
|
}
|
|
37
49
|
export type SyncState = Omit<import("./core-sync-state.js").DerivedState, "coreLength"> & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"namespace-sync-state.d.ts","sourceRoot":"","sources":["../../src/sync/namespace-sync-state.js"],"names":[],"mappings":"AAGA,+CAA+C;AAE/C;;GAEG;AAEH;;GAEG;AACH,gCAF0B,UAAU,SAAvB,SAAW;IAatB;;;;;;;OAOG;IACH,gFANG;QAAyB,SAAS,EAA1B,UAAU;QAC2C,WAAW,EAAhE,OAAO,0BAA0B,EAAE,WAAW;QAC7B,QAAQ,EAAzB,MAAM,IAAI;QACgE,mBAAmB,EAA7F,GAAG,CAAC,MAAM,EAAE,OAAO,2BAA2B,EAAE,kBAAkB,CAAC;QACrD,MAAM;KAAC,EAiC/B;IAED,4BAEC;IAED,2BAA2B;IAC3B,YADc,SAAS,CA4BtB;IAED;;OAEG;IACH,gBAFW,MAAM,QAMhB;IAED;;OAEG;IACH,uBAFW,MAAM,QAMhB;;
|
|
1
|
+
{"version":3,"file":"namespace-sync-state.d.ts","sourceRoot":"","sources":["../../src/sync/namespace-sync-state.js"],"names":[],"mappings":"AAGA,+CAA+C;AAE/C;;GAEG;AAEH;;GAEG;AACH,gCAF0B,UAAU,SAAvB,SAAW;IAatB;;;;;;;OAOG;IACH,gFANG;QAAyB,SAAS,EAA1B,UAAU;QAC2C,WAAW,EAAhE,OAAO,0BAA0B,EAAE,WAAW;QAC7B,QAAQ,EAAzB,MAAM,IAAI;QACgE,mBAAmB,EAA7F,GAAG,CAAC,MAAM,EAAE,OAAO,2BAA2B,EAAE,kBAAkB,CAAC;QACrD,MAAM;KAAC,EAiC/B;IAED,4BAEC;IAED,2BAA2B;IAC3B,YADc,SAAS,CA4BtB;IAED;;OAEG;IACH,gBAFW,MAAM,QAMhB;IAED;;OAEG;IACH,uBAFW,MAAM,QAMhB;IAwBD;;;;;OAKG;IACH,qBALW,MAAM,SACN,MAAM,UACN,MAAM,GACJ,IAAI,CAMhB;IAED;;;OAGG;IACH,wBAHW,MAAM,GACJ,IAAI,CAMhB;;CAqBF;wBA7KY,IAAI,CAAC,OAAO,sBAAsB,EAAE,YAAY,EAAE,YAAY,CAAC,GAAG;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;+BAH1F,aAAa;uBAHrB,cAAc"}
|
|
@@ -24,7 +24,7 @@ export class PeerSyncController {
|
|
|
24
24
|
});
|
|
25
25
|
get peerKey(): Buffer;
|
|
26
26
|
get peerId(): string;
|
|
27
|
-
get syncCapability(): Record<"
|
|
27
|
+
get syncCapability(): Record<"auth" | "config" | "data" | "blobIndex" | "blob", SyncCapability>;
|
|
28
28
|
/** @param {SyncEnabledState} syncEnabledState */
|
|
29
29
|
setSyncEnabledState(syncEnabledState: SyncEnabledState): void;
|
|
30
30
|
/**
|
package/dist/sync/sync-api.d.ts
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
/** @import * as http from 'node:http' */
|
|
3
3
|
/** @import { CoreOwnership } from '../core-ownership.js' */
|
|
4
4
|
/** @import { OpenedNoiseStream } from '../lib/noise-secret-stream-helpers.js' */
|
|
5
|
-
/** @import { ReplicationStream } from '../types.js' */
|
|
5
|
+
/** @import { BlobFilter, ReplicationStream } from '../types.js' */
|
|
6
6
|
export const kHandleDiscoveryKey: unique symbol;
|
|
7
7
|
export const kSyncState: unique symbol;
|
|
8
8
|
export const kRequestFullStop: unique symbol;
|
|
9
9
|
export const kRescindFullStopRequest: unique symbol;
|
|
10
10
|
export const kWaitForInitialSyncWithPeer: unique symbol;
|
|
11
11
|
export const kSetBlobDownloadFilter: unique symbol;
|
|
12
|
+
export const kAddBlobWantRange: unique symbol;
|
|
13
|
+
export const kClearBlobWantRanges: unique symbol;
|
|
12
14
|
/**
|
|
13
15
|
* @typedef {'initial' | 'full'} SyncType
|
|
14
16
|
*/
|
|
@@ -49,7 +51,7 @@ export class SyncApi extends TypedEmitter<SyncEvents> {
|
|
|
49
51
|
* @param {import('../roles.js').Roles} opts.roles
|
|
50
52
|
* @param {() => Promise<Iterable<string>>} opts.getServerWebsocketUrls
|
|
51
53
|
* @param {() => ReplicationStream} opts.getReplicationStream
|
|
52
|
-
* @param {
|
|
54
|
+
* @param {null | BlobFilter} opts.blobDownloadFilter
|
|
53
55
|
* @param {number} [opts.throttleMs]
|
|
54
56
|
* @param {Logger} [opts.logger]
|
|
55
57
|
*/
|
|
@@ -59,7 +61,7 @@ export class SyncApi extends TypedEmitter<SyncEvents> {
|
|
|
59
61
|
roles: import("../roles.js").Roles;
|
|
60
62
|
getServerWebsocketUrls: () => Promise<Iterable<string>>;
|
|
61
63
|
getReplicationStream: () => ReplicationStream;
|
|
62
|
-
blobDownloadFilter:
|
|
64
|
+
blobDownloadFilter: null | BlobFilter;
|
|
63
65
|
throttleMs?: number | undefined;
|
|
64
66
|
logger?: Logger | undefined;
|
|
65
67
|
});
|
|
@@ -108,6 +110,22 @@ export class SyncApi extends TypedEmitter<SyncEvents> {
|
|
|
108
110
|
waitForSync(type: SyncType): Promise<void>;
|
|
109
111
|
/** @param {import('../types.js').BlobFilter | null} blobDownloadFilter */
|
|
110
112
|
[kSetBlobDownloadFilter](blobDownloadFilter: import("../types.js").BlobFilter | null): void;
|
|
113
|
+
/**
|
|
114
|
+
* Add some blob blocks this peer wants.
|
|
115
|
+
*
|
|
116
|
+
* @param {string} peerId
|
|
117
|
+
* @param {number} start
|
|
118
|
+
* @param {number} length
|
|
119
|
+
* @returns {void}
|
|
120
|
+
*/
|
|
121
|
+
[kAddBlobWantRange](peerId: string, start: number, length: number): void;
|
|
122
|
+
/**
|
|
123
|
+
* Clear the blob blocks this peer wants.
|
|
124
|
+
*
|
|
125
|
+
* @param {string} peerId
|
|
126
|
+
* @returns {void}
|
|
127
|
+
*/
|
|
128
|
+
[kClearBlobWantRanges](peerId: string): void;
|
|
111
129
|
[kHandleDiscoveryKey](discoveryKey: Buffer, protomux: import("protomux")<import("@hyperswarm/secret-stream")>): void;
|
|
112
130
|
/**
|
|
113
131
|
* Request a graceful stop to all sync.
|
|
@@ -180,5 +198,6 @@ import { TypedEmitter } from 'tiny-typed-emitter';
|
|
|
180
198
|
import { SyncState } from './sync-state.js';
|
|
181
199
|
import type { CoreOwnership } from '../core-ownership.js';
|
|
182
200
|
import type { ReplicationStream } from '../types.js';
|
|
201
|
+
import type { BlobFilter } from '../types.js';
|
|
183
202
|
import { Logger } from '../logger.js';
|
|
184
203
|
//# sourceMappingURL=sync-api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-api.d.ts","sourceRoot":"","sources":["../../src/sync/sync-api.js"],"names":[],"mappings":"AAcA,2EAA2E;AAC3E,yCAAyC;AACzC,4DAA4D;AAC5D,iFAAiF;AACjF,
|
|
1
|
+
{"version":3,"file":"sync-api.d.ts","sourceRoot":"","sources":["../../src/sync/sync-api.js"],"names":[],"mappings":"AAcA,2EAA2E;AAC3E,yCAAyC;AACzC,4DAA4D;AAC5D,iFAAiF;AACjF,mEAAmE;AAEnE,gDAAiE;AACjE,uCAA8C;AAC9C,6CAAoD;AACpD,oDAA2D;AAC3D,wDAEC;AACD,mDAAmE;AACnE,8CAA8D;AAC9D,iDAAoE;AAEpE;;GAEG;AAEH;;GAEG;AAEH;;;;;;GAMG;AAEH;;;;;GAKG;AAEH;;;;;GAKG;AAEH;;;GAGG;AAEH;;GAEG;AACH;IA6BE;;;;;;;;;;OAUG;IACH,0IATG;QAA6D,WAAW,EAAhE,OAAO,0BAA0B,EAAE,WAAW;QAC1B,aAAa,EAAjC,aAAa;QACqB,KAAK,EAAvC,OAAO,aAAa,EAAE,KAAK;QACW,sBAAsB,EAA5D,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACD,oBAAoB,EAAlD,MAAM,iBAAiB;QACC,kBAAkB,EAA1C,IAAI,GAAG,UAAU;QACH,UAAU;QACV,MAAM;KAAC,EAiD/B;IA6DD;;;OAGG;IACH,YAFa,KAAK,CAIjB;IAqHD;;OAEG;IACH,kBAFa,IAAI,CAsDhB;IAED;;OAEG;IACH,qBAFa,IAAI,CAQhB;IAED;;;;;;;;;;OAUG;IACH;;yBAOC;IAED;;;;OAIG;IACH,aAGC;IAkBD;;;OAGG;IACH,kDAHW,IAAI,GAAG,MAAM,GACX,IAAI,CAOhB;IAED;;;OAGG;IACH,kBAHW,QAAQ,GACN,OAAO,CAAC,IAAI,CAAC,CAazB;IAlUD,0EAA0E;IAC1E,6CADY,OAAO,aAAa,EAAE,UAAU,GAAG,IAAI,QAOlD;IAED;;;;;;;OAOG;IACH,4BALW,MAAM,SACN,MAAM,UACN,MAAM,GACJ,IAAI,CAIhB;IAED;;;;;OAKG;IACH,+BAHW,MAAM,GACJ,IAAI,CAIhB;oFA0Da,2BACf;IAgMC;;OAEG;IACH,2BAGC;IAED;;OAEG;IACH,kCAGC;IA8BD;;;;OAIG;IACH,wCAJW,MAAM,eACN,WAAW,GACT,OAAO,CAAC,IAAI,CAAC,CA6BzB;IApYC,wBAKE;;CAihBL;uBApnBY,SAAS,GAAG,MAAM;+BAIlB,MAAM,GAAG,SAAS,GAAG,KAAK;;;;;mBAMzB,OAAO;;;;UACP,MAAM;;;;YACN,MAAM;;;;;;;;;aAMN,mCAAmC;;;;UACnC,mCAAmC;;;;;;aAKnC;QAAE,aAAa,EAAE,OAAO,CAAA;KAAE;;;;UAC1B;QAAE,aAAa,EAAE,OAAO,CAAA;KAAE;;;;2BAC1B,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC;;;kBAKrC,CAAC,SAAS,EAAE,KAAK,KAAK,IAAI;;6BA/DX,oBAAoB;0BAEvB,iBAAiB;mCAcR,sBAAsB;uCAEN,aAAa;gCAAb,aAAa;uBAdzC,cAAc"}
|
|
@@ -38,6 +38,18 @@ export class SyncState extends TypedEmitter<{
|
|
|
38
38
|
* @returns {State}
|
|
39
39
|
*/
|
|
40
40
|
getState(): State;
|
|
41
|
+
/**
|
|
42
|
+
* @param {string} peerId
|
|
43
|
+
* @param {number} start
|
|
44
|
+
* @param {number} length
|
|
45
|
+
* @returns {void}
|
|
46
|
+
*/
|
|
47
|
+
addBlobWantRange(peerId: string, start: number, length: number): void;
|
|
48
|
+
/**
|
|
49
|
+
* @param {string} peerId
|
|
50
|
+
* @returns {void}
|
|
51
|
+
*/
|
|
52
|
+
clearBlobWantRanges(peerId: string): void;
|
|
41
53
|
#private;
|
|
42
54
|
}
|
|
43
55
|
export type State = Record<Namespace, import("./namespace-sync-state.js").SyncState>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-state.d.ts","sourceRoot":"","sources":["../../src/sync/sync-state.js"],"names":[],"mappings":"AAKA,+CAA+C;AAE/C;;;;;GAKG;AAEH;;;GAGG;AACH;WAFmC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;;IAIvD;;;;;;;OAOG;IACH,sEALG;QAA6D,WAAW,EAAhE,OAAO,0BAA0B,EAAE,WAAW;QAC4B,mBAAmB,EAA7F,GAAG,CAAC,MAAM,EAAE,OAAO,2BAA2B,EAAE,kBAAkB,CAAC;QACrD,UAAU;QACa,MAAM;KAAC,EActD;IAED;;OAEG;IACH,gBAFW,MAAM,QAMhB;IAED;;OAEG;IACH,uBAFW,MAAM,QAMhB;IAED;;OAEG;IACH,YAFa,KAAK,CAOjB;;CAKF;
|
|
1
|
+
{"version":3,"file":"sync-state.d.ts","sourceRoot":"","sources":["../../src/sync/sync-state.js"],"names":[],"mappings":"AAKA,+CAA+C;AAE/C;;;;;GAKG;AAEH;;;GAGG;AACH;WAFmC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;;IAIvD;;;;;;;OAOG;IACH,sEALG;QAA6D,WAAW,EAAhE,OAAO,0BAA0B,EAAE,WAAW;QAC4B,mBAAmB,EAA7F,GAAG,CAAC,MAAM,EAAE,OAAO,2BAA2B,EAAE,kBAAkB,CAAC;QACrD,UAAU;QACa,MAAM;KAAC,EActD;IAED;;OAEG;IACH,gBAFW,MAAM,QAMhB;IAED;;OAEG;IACH,uBAFW,MAAM,QAMhB;IAED;;OAEG;IACH,YAFa,KAAK,CAOjB;IAED;;;;;OAKG;IACH,yBALW,MAAM,SACN,MAAM,UACN,MAAM,GACJ,IAAI,CAIhB;IAED;;;OAGG;IACH,4BAHW,MAAM,GACJ,IAAI,CAIhB;;CAKF;oBAnFY,MAAM,CAClB,SAAY,EACZ,OAAU,2BAA2B,EAAE,SAAS,CAC7C;6BAXyB,oBAAoB;+BAKlB,aAAa"}
|
|
@@ -58,7 +58,7 @@ export default class TranslationApi {
|
|
|
58
58
|
* @param {TranslationValue} doc
|
|
59
59
|
*/
|
|
60
60
|
index(doc: TranslationValue): void;
|
|
61
|
-
get dataType(): import("./datatype/index.js").DataType<import("./datastore/index.js").DataStore<"config", "translation" | "
|
|
61
|
+
get dataType(): import("./datatype/index.js").DataType<import("./datastore/index.js").DataStore<"config", "translation" | "projectSettings" | "preset" | "icon" | "field" | "deviceInfo">, import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
62
62
|
name: "translation";
|
|
63
63
|
schema: undefined;
|
|
64
64
|
columns: {
|
|
@@ -178,7 +178,7 @@ export default class TranslationApi {
|
|
|
178
178
|
tableName: "translation";
|
|
179
179
|
dataType: "string";
|
|
180
180
|
columnType: "SQLiteText";
|
|
181
|
-
data: "
|
|
181
|
+
data: "track" | "role" | "projectSettings" | "preset" | "observation" | "field" | "deviceInfo" | "UNRECOGNIZED" | "type_unspecified";
|
|
182
182
|
driverParam: string;
|
|
183
183
|
notNull: true;
|
|
184
184
|
hasDefault: false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translation-api.d.ts","sourceRoot":"","sources":["../src/translation-api.js"],"names":[],"mappings":"AAKA,uEAAuE;AACvE,+CAA+C;AAE/C,iEAEC;AACD;IAQE;;;;;;;;;OASG;IACH,0BARG;QAMS,QAAQ,EANT,OAAO,qBAAqB,EAAE,QAAQ,CAChD,OAAW,sBAAsB,EAAE,SAAS,CAAC,QAAQ,CAAC,EACtD,cAAkB,qBAAqB,EAAE,gBAAgB,EACzD,aAAiB,EACjB,WAAe,EACf,gBAAoB,CACjB;KACH,EAWA;IAED,+BAA+B;IAC/B,SADc,OAAO,CAAC,IAAI,CAAC,CAG1B;IAED;;OAEG;IACH,WAFW,gBAAgB;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"translation-api.d.ts","sourceRoot":"","sources":["../src/translation-api.js"],"names":[],"mappings":"AAKA,uEAAuE;AACvE,+CAA+C;AAE/C,iEAEC;AACD;IAQE;;;;;;;;;OASG;IACH,0BARG;QAMS,QAAQ,EANT,OAAO,qBAAqB,EAAE,QAAQ,CAChD,OAAW,sBAAsB,EAAE,SAAS,CAAC,QAAQ,CAAC,EACtD,cAAkB,qBAAqB,EAAE,gBAAgB,EACzD,aAAiB,EACjB,WAAe,EACf,gBAAoB,CACjB;KACH,EAWA;IAED,+BAA+B;IAC/B,SADc,OAAO,CAAC,IAAI,CAAC,CAG1B;IAED;;OAEG;IACH,WAFW,gBAAgB;;;;;;;;;;;;;;;;;;;;OAW1B;IAED,kGAAkG;IAElG;;;;;OAKG;IACH,WALW,YACR,IAAI,CAAC,gBAAgB,EAAC,YAAY,GAAG,SAAS,GAAG,QAAQ,CAAC,EAC5D,aAAe,GAAG,YAAY,CAAC,GAAG;QAAC,MAAM;;;UAA6B;KAAC,GAC3D,OAAO,CAAC,OAAO,iBAAiB,EAAE,WAAW,EAAE,CAAC,CAqC5D;IAED;;OAEG;IACH,WAFW,gBAAgB,QAkB1B;IAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAEC;IALD,mHAEC;;CAIF;sCAhIkD,iBAAiB;iCACnC,WAAW;iCADO,iBAAiB"}
|
package/dist/types.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ import { Duplex } from 'streamx';
|
|
|
8
8
|
import RandomAccessStorage from 'random-access-storage';
|
|
9
9
|
import { DefaultListener, ListenerSignature } from 'tiny-typed-emitter';
|
|
10
10
|
import type { NAMESPACES } from './constants.js';
|
|
11
|
+
import type { Readable } from 'stream';
|
|
12
|
+
import type { HyperdriveEntry } from 'hyperdrive';
|
|
11
13
|
export type Namespace = (typeof NAMESPACES)[number];
|
|
12
14
|
type SupportedBlobVariants = typeof SUPPORTED_BLOB_VARIANTS;
|
|
13
15
|
export type BlobType = keyof SupportedBlobVariants;
|
|
@@ -112,5 +114,10 @@ export type DefaultEmitterEvents<L extends ListenerSignature<L> = DefaultListene
|
|
|
112
114
|
newListener: (event: keyof L, listener: L[keyof L]) => void;
|
|
113
115
|
removeListener: (event: keyof L, listener: L[keyof L]) => void;
|
|
114
116
|
};
|
|
117
|
+
export type BlobStoreEntriesStream = Readable & {
|
|
118
|
+
[Symbol.asyncIterator](): AsyncIterableIterator<HyperdriveEntry & {
|
|
119
|
+
driveId: string;
|
|
120
|
+
}>;
|
|
121
|
+
};
|
|
115
122
|
export {};
|
|
116
123
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,iBAAiB,EACjB,WAAW,EACZ,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC3E,OAAO,KAAK,cAAc,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAA;AACpC,OAAO,KAAK,WAAW,MAAM,2BAA2B,CAAA;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,mBAAmB,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@comapeo/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Offline p2p mapping library",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -108,6 +108,7 @@
|
|
|
108
108
|
"homepage": "https://github.com/digidem/comapeo-core#readme",
|
|
109
109
|
"devDependencies": {
|
|
110
110
|
"@bufbuild/buf": "^1.26.1",
|
|
111
|
+
"@comapeo/cloud": "^0.1.0",
|
|
111
112
|
"@comapeo/core2.0.1": "npm:@comapeo/core@2.0.1",
|
|
112
113
|
"@mapeo/default-config": "5.0.0",
|
|
113
114
|
"@mapeo/mock-data": "^2.1.1",
|
|
@@ -133,6 +134,7 @@
|
|
|
133
134
|
"cpy-cli": "^5.0.0",
|
|
134
135
|
"drizzle-kit": "^0.20.14",
|
|
135
136
|
"eslint": "^8.57.0",
|
|
137
|
+
"execa": "^9.5.1",
|
|
136
138
|
"husky": "^8.0.0",
|
|
137
139
|
"iterpal": "^0.4.0",
|
|
138
140
|
"lint-staged": "^14.0.1",
|
|
@@ -140,6 +142,7 @@
|
|
|
140
142
|
"math-random-seed": "^2.0.0",
|
|
141
143
|
"nanobench": "^3.0.0",
|
|
142
144
|
"npm-run-all": "^4.1.5",
|
|
145
|
+
"p-props": "^6.0.0",
|
|
143
146
|
"prettier": "^2.8.8",
|
|
144
147
|
"random-access-file": "^4.0.7",
|
|
145
148
|
"random-access-memory": "^6.2.1",
|
|
@@ -155,7 +158,7 @@
|
|
|
155
158
|
},
|
|
156
159
|
"dependencies": {
|
|
157
160
|
"@comapeo/fallback-smp": "^1.0.0",
|
|
158
|
-
"@comapeo/schema": "1.
|
|
161
|
+
"@comapeo/schema": "1.3.0",
|
|
159
162
|
"@digidem/types": "^2.3.0",
|
|
160
163
|
"@fastify/error": "^3.4.1",
|
|
161
164
|
"@fastify/type-provider-typebox": "^4.1.0",
|
|
@@ -163,6 +166,7 @@
|
|
|
163
166
|
"@mapeo/crypto": "1.0.0-alpha.10",
|
|
164
167
|
"@mapeo/sqlite-indexer": "1.0.0-alpha.9",
|
|
165
168
|
"@sinclair/typebox": "^0.29.6",
|
|
169
|
+
"@sindresorhus/merge-streams": "^4.0.0",
|
|
166
170
|
"b4a": "^1.6.3",
|
|
167
171
|
"bcp-47": "^2.1.0",
|
|
168
172
|
"better-sqlite3": "^8.7.0",
|
|
@@ -198,8 +202,9 @@
|
|
|
198
202
|
"sub-encoder": "^2.1.1",
|
|
199
203
|
"throttle-debounce": "^5.0.0",
|
|
200
204
|
"tiny-typed-emitter": "^2.1.0",
|
|
201
|
-
"type-fest": "^4.
|
|
205
|
+
"type-fest": "^4.30.0",
|
|
202
206
|
"undici": "^6.13.0",
|
|
207
|
+
"unix-path-resolve": "^1.0.2",
|
|
203
208
|
"varint": "^6.0.0",
|
|
204
209
|
"ws": "^8.18.0",
|
|
205
210
|
"yauzl-promise": "^4.0.0"
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { TypedEmitter } from 'tiny-typed-emitter'
|
|
2
|
+
import { createEntriesStream } from './entries-stream.js'
|
|
3
|
+
import { filePathMatchesFilter } from './utils.js'
|
|
4
|
+
|
|
5
|
+
/** @import { BlobFilter } from '../types.js' */
|
|
6
|
+
/** @import { THyperdriveIndex } from './hyperdrive-index.js' */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Like hyperdrive.download() but 'live', and for multiple drives.
|
|
10
|
+
*
|
|
11
|
+
* Will emit an 'error' event for any unexpected errors. A consumer must attach
|
|
12
|
+
* an error listener to avoid uncaught errors. Sources of errors include:
|
|
13
|
+
*
|
|
14
|
+
* - If the entries stream emits an error
|
|
15
|
+
* - If a drive referenced in an entry is not found
|
|
16
|
+
* - If core.has() throws (e.g. if hypercore is closed)
|
|
17
|
+
* - If core.download().done() throws, which should not happen according to
|
|
18
|
+
* current hypercore code.
|
|
19
|
+
* - If the entries stream ends unexpectedly (it should be live and not end)
|
|
20
|
+
*
|
|
21
|
+
* NB: unlike hyperdrive.download(), this will also download deleted and
|
|
22
|
+
* previous versions of blobs - we don't currently support editing or deleting
|
|
23
|
+
* of blobs, so this should not be an issue, and if we do in the future,
|
|
24
|
+
* downloading deleted and previous versions may be desirable behavior anyway
|
|
25
|
+
*
|
|
26
|
+
* @extends {TypedEmitter<{ error: (error: Error) => void }>}
|
|
27
|
+
*/
|
|
28
|
+
export class Downloader extends TypedEmitter {
|
|
29
|
+
/** @type {THyperdriveIndex} */
|
|
30
|
+
#driveIndex
|
|
31
|
+
/** @type {Set<{ done(): Promise<void>, destroy(): void }>} */
|
|
32
|
+
#queuedDownloads = new Set()
|
|
33
|
+
#entriesStream
|
|
34
|
+
#processEntriesPromise
|
|
35
|
+
#ac = new AbortController()
|
|
36
|
+
#shouldDownloadFile
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {THyperdriveIndex} driveIndex
|
|
40
|
+
* @param {object} [options]
|
|
41
|
+
* @param {BlobFilter | null} [options.filter] Filter blobs of specific types and/or sizes to download
|
|
42
|
+
*/
|
|
43
|
+
constructor(driveIndex, { filter } = {}) {
|
|
44
|
+
super()
|
|
45
|
+
this.#driveIndex = driveIndex
|
|
46
|
+
|
|
47
|
+
this.#shouldDownloadFile = filter
|
|
48
|
+
? filePathMatchesFilter.bind(null, filter)
|
|
49
|
+
: () => true
|
|
50
|
+
|
|
51
|
+
this.#entriesStream = createEntriesStream(driveIndex, { live: true })
|
|
52
|
+
this.#entriesStream.once('error', this.#handleError)
|
|
53
|
+
|
|
54
|
+
this.#ac.signal.addEventListener('abort', this.#handleAbort, { once: true })
|
|
55
|
+
|
|
56
|
+
this.#processEntriesPromise = this.#processEntries()
|
|
57
|
+
this.#processEntriesPromise.catch(this.#handleError)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Start processing entries from the entries stream - if an entry matches the
|
|
62
|
+
* filter, and we don't already have it, queue it for download. If the
|
|
63
|
+
* Downloader is live, this method will never resolve, otherwise it will
|
|
64
|
+
* resolve when all the entries have been processed and downloaded.
|
|
65
|
+
*/
|
|
66
|
+
async #processEntries() {
|
|
67
|
+
for await (const entry of this.#entriesStream) {
|
|
68
|
+
this.#ac.signal.throwIfAborted()
|
|
69
|
+
const {
|
|
70
|
+
driveId,
|
|
71
|
+
key: filePath,
|
|
72
|
+
value: { blob },
|
|
73
|
+
} = entry
|
|
74
|
+
if (!this.#shouldDownloadFile(filePath)) continue
|
|
75
|
+
const drive = this.#driveIndex.get(driveId)
|
|
76
|
+
// ERROR HANDLING: this is unexpected and should not happen
|
|
77
|
+
if (!drive) throw new Error('Drive not found: ' + driveId)
|
|
78
|
+
const blobs = await drive.getBlobs()
|
|
79
|
+
this.#ac.signal.throwIfAborted()
|
|
80
|
+
await this.#processEntry(blobs.core, blob)
|
|
81
|
+
this.#ac.signal.throwIfAborted()
|
|
82
|
+
}
|
|
83
|
+
throw new Error('Entries stream ended unexpectedly')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Update state and queue missing entries for download
|
|
88
|
+
*
|
|
89
|
+
* @param {import('hypercore')} blobsCore
|
|
90
|
+
* @param {{ blockOffset: number, blockLength: number, byteLength: number }} blob
|
|
91
|
+
*/
|
|
92
|
+
async #processEntry(blobsCore, { blockOffset: start, blockLength: length }) {
|
|
93
|
+
const end = start + length
|
|
94
|
+
const have = await blobsCore.has(start, end)
|
|
95
|
+
this.#ac.signal.throwIfAborted()
|
|
96
|
+
if (have) return
|
|
97
|
+
const download = blobsCore.download({ start, end })
|
|
98
|
+
this.#queuedDownloads.add(download)
|
|
99
|
+
download
|
|
100
|
+
.done()
|
|
101
|
+
// According to the code, this should never throw.
|
|
102
|
+
.catch(this.#handleError)
|
|
103
|
+
.finally(() => {
|
|
104
|
+
this.#queuedDownloads.delete(download)
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Cancel the downloads and clean up resources.
|
|
110
|
+
*/
|
|
111
|
+
destroy() {
|
|
112
|
+
this.#ac.abort()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** @param {Error} error */
|
|
116
|
+
#handleError = (error) => {
|
|
117
|
+
if (this.#ac.signal.aborted) return
|
|
118
|
+
this.emit('error', error)
|
|
119
|
+
this.#ac.abort(error)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
#handleAbort = () => {
|
|
123
|
+
for (const download of this.#queuedDownloads) download.destroy()
|
|
124
|
+
this.#ac.signal.removeEventListener('abort', this.#handleAbort)
|
|
125
|
+
this.#entriesStream.removeListener('error', this.#ac.abort)
|
|
126
|
+
// queuedDownloads is likely to be empty here anyway, but clear just in case.
|
|
127
|
+
this.#queuedDownloads.clear()
|
|
128
|
+
this.#entriesStream.destroy()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import SubEncoder from 'sub-encoder'
|
|
2
|
+
import mergeStreams from '@sindresorhus/merge-streams'
|
|
3
|
+
import { Transform, pipeline } from 'node:stream'
|
|
4
|
+
import { noop } from '../utils.js'
|
|
5
|
+
|
|
6
|
+
/** @import Hyperdrive from 'hyperdrive' */
|
|
7
|
+
/** @import { BlobStoreEntriesStream } from '../types.js' */
|
|
8
|
+
/** @import { THyperdriveIndex } from './hyperdrive-index.js' */
|
|
9
|
+
|
|
10
|
+
const keyEncoding = new SubEncoder('files', 'utf-8')
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param {THyperdriveIndex} driveIndex
|
|
15
|
+
* @param {object} opts
|
|
16
|
+
* @param {boolean} [opts.live=false]
|
|
17
|
+
* @returns {BlobStoreEntriesStream}
|
|
18
|
+
*/
|
|
19
|
+
export function createEntriesStream(driveIndex, { live = false } = {}) {
|
|
20
|
+
const mergedEntriesStreams = mergeStreams(
|
|
21
|
+
[...driveIndex].map((drive) => getHistoryStream(drive.db, { live }))
|
|
22
|
+
)
|
|
23
|
+
driveIndex.on('add-drive', addDrive)
|
|
24
|
+
// Close is always emitted, so we can use it to remove the listener
|
|
25
|
+
mergedEntriesStreams.once('close', () =>
|
|
26
|
+
driveIndex.off('add-drive', addDrive)
|
|
27
|
+
)
|
|
28
|
+
return mergedEntriesStreams
|
|
29
|
+
|
|
30
|
+
/** @param {Hyperdrive} drive */
|
|
31
|
+
function addDrive(drive) {
|
|
32
|
+
mergedEntriesStreams.add(getHistoryStream(drive.db, { live }))
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* @param {import('hyperbee')} bee
|
|
39
|
+
* @param {object} opts
|
|
40
|
+
* @param {boolean} opts.live
|
|
41
|
+
*/
|
|
42
|
+
function getHistoryStream(bee, { live }) {
|
|
43
|
+
// This will also include old versions of files, but it is the only way to
|
|
44
|
+
// get a live stream from a Hyperbee, however we currently do not support
|
|
45
|
+
// edits of blobs, so this should not be an issue, and the consequence is
|
|
46
|
+
// that old versions are downloaded too, which is acceptable.
|
|
47
|
+
const historyStream = bee.createHistoryStream({
|
|
48
|
+
live,
|
|
49
|
+
// `keyEncoding` is necessary because hyperdrive stores file index data
|
|
50
|
+
// under the `files` sub-encoding key
|
|
51
|
+
keyEncoding,
|
|
52
|
+
})
|
|
53
|
+
return pipeline(historyStream, new AddDriveIds(bee.core), noop)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class AddDriveIds extends Transform {
|
|
57
|
+
#core
|
|
58
|
+
#cachedDriveId
|
|
59
|
+
|
|
60
|
+
/** @param {import('hypercore')} core */
|
|
61
|
+
constructor(core) {
|
|
62
|
+
super({ objectMode: true })
|
|
63
|
+
this.#core = core
|
|
64
|
+
this.#cachedDriveId = core.discoveryKey?.toString('hex')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** @type {Transform['_transform']} */
|
|
68
|
+
_transform(entry, _, callback) {
|
|
69
|
+
// Minimal performance optimization to only call toString() once.
|
|
70
|
+
// core.discoveryKey will always be defined by the time it starts
|
|
71
|
+
// streaming, but could be null when the instance is first created.
|
|
72
|
+
let driveId
|
|
73
|
+
if (this.#cachedDriveId) {
|
|
74
|
+
driveId = this.#cachedDriveId
|
|
75
|
+
} else {
|
|
76
|
+
driveId = this.#core.discoveryKey?.toString('hex')
|
|
77
|
+
this.#cachedDriveId = driveId
|
|
78
|
+
}
|
|
79
|
+
callback(null, { ...entry, driveId })
|
|
80
|
+
}
|
|
81
|
+
}
|