@dxos/teleport-extension-replicator 0.1.56-next.a63ce79 → 0.1.56

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.
@@ -20,7 +20,7 @@ function _ts_decorate(decorators, target, key, desc) {
20
20
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21
21
  return c > 3 && r && Object.defineProperty(target, key, r), r;
22
22
  }
23
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts";
23
+ var __dxlog_file = "/mnt/ramdisk/work/packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts";
24
24
  var ReplicatorExtension = class {
25
25
  constructor() {
26
26
  this._ctx = new Context({
@@ -323,7 +323,8 @@ var ReplicatorExtension = class {
323
323
  upload: info.upload,
324
324
  download: info.download,
325
325
  noise: false,
326
- encrypted: false
326
+ encrypted: false,
327
+ maxRequests: 1024
327
328
  });
328
329
  replicationStream.on("error", (err) => {
329
330
  if (err?.message === "Writable stream closed prematurely" || err?.message === "Cannot call write after a stream was destroyed") {
@@ -334,7 +335,7 @@ var ReplicatorExtension = class {
334
335
  info
335
336
  }, {
336
337
  F: __dxlog_file,
337
- L: 240,
338
+ L: 251,
338
339
  S: this,
339
340
  C: (f, a) => f(...a)
340
341
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/replicator-extension.ts"],
4
- "sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nimport type { ProtocolStream } from 'hypercore-protocol';\nimport { Duplex } from 'node:stream';\n\nimport { asyncTimeout, DeferredTask, synchronized } from '@dxos/async';\nimport { Context } from '@dxos/context';\nimport { failUndefined } from '@dxos/debug';\nimport { FeedWrapper } from '@dxos/feed-store';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { log, logInfo } from '@dxos/log';\nimport { schema, RpcClosedError } from '@dxos/protocols';\nimport { FeedInfo, ReplicatorService } from '@dxos/protocols/proto/dxos/mesh/teleport/replicator';\nimport { createProtoRpcPeer, ProtoRpcPeer } from '@dxos/rpc';\nimport { ExtensionContext, TeleportExtension } from '@dxos/teleport';\nimport { ComplexMap } from '@dxos/util';\n\nexport type ReplicationOptions = {\n upload: boolean;\n};\n\n/**\n * Manages replication between a set of feeds for a single teleport session.\n */\nexport class ReplicatorExtension implements TeleportExtension {\n private readonly _ctx = new Context({\n onError: (err) => {\n log.catch(err);\n this._extensionContext?.close(err);\n },\n });\n\n private readonly _feeds = new ComplexMap<PublicKey, FeedWrapper<any>>(PublicKey.hash);\n private readonly _streams = new ComplexMap<PublicKey, ActiveStream>(PublicKey.hash);\n\n private _rpc?: ProtoRpcPeer<ServiceBundle>;\n private _extensionContext?: ExtensionContext;\n\n private _options: ReplicationOptions = {\n upload: false,\n };\n\n private readonly _updateTask = new DeferredTask(this._ctx, async () => {\n try {\n if (this._extensionContext!.initiator === false) {\n await this._rpc!.rpc.ReplicatorService.updateFeeds({\n feeds: Array.from(this._feeds.values()).map((feed) => ({\n feedKey: feed.key,\n download: true,\n upload: this._options.upload,\n })),\n });\n } else if (this._extensionContext!.initiator === true) {\n await this._reevaluateFeeds();\n }\n } catch (err) {\n if (err instanceof RpcClosedError) {\n return; // Some RPC requests might be pending while closing.\n }\n throw err;\n }\n });\n\n @logInfo\n private get extensionInfo() {\n return {\n initiator: this._extensionContext?.initiator,\n localPeerId: this._extensionContext?.localPeerId,\n remotePeerId: this._extensionContext?.remotePeerId,\n feeds: Array.from(this._feeds.keys()),\n };\n }\n\n setOptions(options: ReplicationOptions): this {\n this._options = options;\n log('setOptions', { options });\n if (this._extensionContext) {\n this._updateTask.schedule();\n }\n return this;\n }\n\n addFeed(feed: FeedWrapper<any>) {\n this._feeds.set(feed.key, feed);\n log('addFeed', { feedKey: feed.key });\n if (this._extensionContext) {\n this._updateTask.schedule();\n }\n }\n\n async onOpen(context: ExtensionContext) {\n this._extensionContext = context;\n log('open');\n\n this._rpc = createProtoRpcPeer<ServiceBundle, ServiceBundle>({\n requested: {\n ReplicatorService: schema.getService('dxos.mesh.teleport.replicator.ReplicatorService'),\n },\n exposed: {\n ReplicatorService: schema.getService('dxos.mesh.teleport.replicator.ReplicatorService'),\n },\n handlers: {\n ReplicatorService: {\n updateFeeds: async ({ feeds }) => {\n log('received feed info', { feeds });\n invariant(this._extensionContext!.initiator === true, 'Invalid call');\n this._updateTask.schedule();\n },\n startReplication: async ({ info }) => {\n log('starting replication...', { info });\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n const streamTag = await this._acceptReplication(info);\n return {\n streamTag,\n };\n },\n stopReplication: async ({ info }) => {\n log('stopping replication...', { info });\n // TODO(dmaretskyi): Make sure any peer can stop replication.\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n await this._stopReplication(info.feedKey);\n },\n },\n },\n port: await context.createPort('rpc', {\n contentType: 'application/x-protobuf; messageType=\"dxos.rpc.Message\"',\n }),\n });\n await this._rpc.open();\n\n this._updateTask.schedule();\n }\n\n async onClose(err?: Error | undefined) {\n log('close', { err });\n await this._ctx.dispose();\n await this._rpc?.close();\n for (const feedKey of this._streams.keys()) {\n await this._stopReplication(feedKey);\n }\n }\n\n @synchronized\n private async _reevaluateFeeds() {\n log('_reevaluateFeeds');\n for (const feedKey of this._feeds.keys()) {\n if (this._ctx.disposed) {\n return;\n }\n if (this._streams.has(feedKey) && this._options.upload !== this._streams.get(feedKey)?.info.upload) {\n try {\n await asyncTimeout(this._stopReplication(feedKey), 1000);\n } catch (err) {\n log.catch(err);\n }\n }\n\n if (this._ctx.disposed) {\n return;\n }\n if (!this._streams.has(feedKey)) {\n await this._initiateReplication({\n feedKey,\n download: true,\n upload: this._options.upload,\n });\n }\n }\n }\n\n /**\n * Try to initiate feed replication.\n */\n private async _initiateReplication(feedInfo: FeedInfo) {\n log('initiating replication', { feedInfo });\n invariant(this._extensionContext!.initiator === true, 'Invalid call');\n invariant(!this._streams.has(feedInfo.feedKey), `Replication already in progress for feed: ${feedInfo.feedKey}`);\n const { streamTag } = await this._rpc!.rpc.ReplicatorService.startReplication({ info: feedInfo });\n if (!streamTag) {\n return;\n }\n\n await this._replicateFeed(feedInfo, streamTag);\n }\n\n /**\n * Respond to a remote request to replicate a feed.\n * @returns A stream tag for the replication stream or `undefined` if we don't want to replicate.\n */\n @synchronized\n private async _acceptReplication(feedInfo: FeedInfo): Promise<string | undefined> {\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n if (!this._feeds.has(feedInfo.feedKey) || this._streams.has(feedInfo.feedKey)) {\n return undefined; // We don't have the feed or we are already replicating it.\n }\n\n const tag = `feed-${feedInfo.feedKey.toHex()}-${PublicKey.random().toHex().slice(0, 8)}`; // Generate a unique tag for the stream.\n await this._replicateFeed(feedInfo, tag);\n return tag;\n }\n\n private async _replicateFeed(info: FeedInfo, streamTag: string) {\n log('replicate', { info, streamTag });\n invariant(!this._streams.has(info.feedKey), `Replication already in progress for feed: ${info.feedKey}`);\n\n const feed = this._feeds.get(info.feedKey) ?? failUndefined();\n const networkStream = await this._extensionContext!.createStream(streamTag, {\n contentType: 'application/x-hypercore',\n });\n const replicationStream = feed.replicate(true, {\n live: true,\n upload: info.upload,\n download: info.download,\n noise: false,\n encrypted: false,\n });\n\n // left for testing\n // feed.on('download', (index: number, data: any) => {\n // log('download', {\n // key: info.feedKey,\n // index\n // });\n // });\n\n replicationStream.on('error', (err) => {\n if (\n err?.message === 'Writable stream closed prematurely' ||\n err?.message === 'Cannot call write after a stream was destroyed'\n ) {\n return;\n }\n\n log.warn('replication stream error', { err, info });\n });\n\n this._streams.set(info.feedKey, {\n streamTag,\n networkStream,\n replicationStream,\n info,\n });\n\n networkStream.pipe(replicationStream as any).pipe(networkStream);\n }\n\n private async _stopReplication(feedKey: PublicKey) {\n const stream = this._streams.get(feedKey);\n if (!stream) {\n return;\n }\n\n stream.networkStream.destroy();\n this._streams.delete(feedKey);\n }\n}\n\ntype ServiceBundle = {\n ReplicatorService: ReplicatorService;\n};\n\ntype ActiveStream = {\n streamTag: string;\n networkStream: Duplex;\n replicationStream: ProtocolStream;\n info: FeedInfo;\n};\n"],
5
- "mappings": "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",
6
- "names": ["asyncTimeout", "DeferredTask", "synchronized", "Context", "failUndefined", "invariant", "PublicKey", "log", "logInfo", "schema", "RpcClosedError", "createProtoRpcPeer", "ComplexMap", "ReplicatorExtension", "_ctx", "onError", "err", "catch", "_extensionContext", "close", "_feeds", "hash", "_streams", "_options", "upload", "_updateTask", "initiator", "_rpc", "rpc", "ReplicatorService", "updateFeeds", "feeds", "Array", "from", "values", "map", "feed", "feedKey", "key", "download", "_reevaluateFeeds", "extensionInfo", "localPeerId", "remotePeerId", "keys", "setOptions", "options", "schedule", "addFeed", "set", "onOpen", "context", "requested", "getService", "exposed", "handlers", "startReplication", "info", "streamTag", "_acceptReplication", "stopReplication", "_stopReplication", "port", "createPort", "contentType", "open", "onClose", "dispose", "disposed", "has", "get", "_initiateReplication", "feedInfo", "_replicateFeed", "undefined", "tag", "toHex", "random", "slice", "networkStream", "createStream", "replicationStream", "replicate", "live", "noise", "encrypted", "on", "message", "warn", "pipe", "stream", "destroy", "delete"]
4
+ "sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nimport type { ProtocolStream } from 'hypercore-protocol';\nimport { Duplex } from 'node:stream';\n\nimport { asyncTimeout, DeferredTask, synchronized } from '@dxos/async';\nimport { Context } from '@dxos/context';\nimport { failUndefined } from '@dxos/debug';\nimport { FeedWrapper } from '@dxos/feed-store';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { log, logInfo } from '@dxos/log';\nimport { schema, RpcClosedError } from '@dxos/protocols';\nimport { FeedInfo, ReplicatorService } from '@dxos/protocols/proto/dxos/mesh/teleport/replicator';\nimport { createProtoRpcPeer, ProtoRpcPeer } from '@dxos/rpc';\nimport { ExtensionContext, TeleportExtension } from '@dxos/teleport';\nimport { ComplexMap } from '@dxos/util';\n\nexport type ReplicationOptions = {\n upload: boolean;\n};\n\n/**\n * Manages replication between a set of feeds for a single teleport session.\n */\nexport class ReplicatorExtension implements TeleportExtension {\n private readonly _ctx = new Context({\n onError: (err) => {\n log.catch(err);\n this._extensionContext?.close(err);\n },\n });\n\n private readonly _feeds = new ComplexMap<PublicKey, FeedWrapper<any>>(PublicKey.hash);\n private readonly _streams = new ComplexMap<PublicKey, ActiveStream>(PublicKey.hash);\n\n private _rpc?: ProtoRpcPeer<ServiceBundle>;\n private _extensionContext?: ExtensionContext;\n\n private _options: ReplicationOptions = {\n upload: false,\n };\n\n private readonly _updateTask = new DeferredTask(this._ctx, async () => {\n try {\n if (this._extensionContext!.initiator === false) {\n await this._rpc!.rpc.ReplicatorService.updateFeeds({\n feeds: Array.from(this._feeds.values()).map((feed) => ({\n feedKey: feed.key,\n download: true,\n upload: this._options.upload,\n })),\n });\n } else if (this._extensionContext!.initiator === true) {\n await this._reevaluateFeeds();\n }\n } catch (err) {\n if (err instanceof RpcClosedError) {\n return; // Some RPC requests might be pending while closing.\n }\n throw err;\n }\n });\n\n @logInfo\n private get extensionInfo() {\n return {\n initiator: this._extensionContext?.initiator,\n localPeerId: this._extensionContext?.localPeerId,\n remotePeerId: this._extensionContext?.remotePeerId,\n feeds: Array.from(this._feeds.keys()),\n };\n }\n\n setOptions(options: ReplicationOptions): this {\n this._options = options;\n log('setOptions', { options });\n if (this._extensionContext) {\n this._updateTask.schedule();\n }\n return this;\n }\n\n addFeed(feed: FeedWrapper<any>) {\n this._feeds.set(feed.key, feed);\n log('addFeed', { feedKey: feed.key });\n if (this._extensionContext) {\n this._updateTask.schedule();\n }\n }\n\n async onOpen(context: ExtensionContext) {\n this._extensionContext = context;\n log('open');\n\n this._rpc = createProtoRpcPeer<ServiceBundle, ServiceBundle>({\n requested: {\n ReplicatorService: schema.getService('dxos.mesh.teleport.replicator.ReplicatorService'),\n },\n exposed: {\n ReplicatorService: schema.getService('dxos.mesh.teleport.replicator.ReplicatorService'),\n },\n handlers: {\n ReplicatorService: {\n updateFeeds: async ({ feeds }) => {\n log('received feed info', { feeds });\n invariant(this._extensionContext!.initiator === true, 'Invalid call');\n this._updateTask.schedule();\n },\n startReplication: async ({ info }) => {\n log('starting replication...', { info });\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n const streamTag = await this._acceptReplication(info);\n return {\n streamTag,\n };\n },\n stopReplication: async ({ info }) => {\n log('stopping replication...', { info });\n // TODO(dmaretskyi): Make sure any peer can stop replication.\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n await this._stopReplication(info.feedKey);\n },\n },\n },\n port: await context.createPort('rpc', {\n contentType: 'application/x-protobuf; messageType=\"dxos.rpc.Message\"',\n }),\n });\n await this._rpc.open();\n\n this._updateTask.schedule();\n }\n\n async onClose(err?: Error | undefined) {\n log('close', { err });\n await this._ctx.dispose();\n await this._rpc?.close();\n for (const feedKey of this._streams.keys()) {\n await this._stopReplication(feedKey);\n }\n }\n\n @synchronized\n private async _reevaluateFeeds() {\n log('_reevaluateFeeds');\n for (const feedKey of this._feeds.keys()) {\n if (this._ctx.disposed) {\n return;\n }\n if (this._streams.has(feedKey) && this._options.upload !== this._streams.get(feedKey)?.info.upload) {\n try {\n await asyncTimeout(this._stopReplication(feedKey), 1000);\n } catch (err) {\n log.catch(err);\n }\n }\n\n if (this._ctx.disposed) {\n return;\n }\n if (!this._streams.has(feedKey)) {\n await this._initiateReplication({\n feedKey,\n download: true,\n upload: this._options.upload,\n });\n }\n }\n }\n\n /**\n * Try to initiate feed replication.\n */\n private async _initiateReplication(feedInfo: FeedInfo) {\n log('initiating replication', { feedInfo });\n invariant(this._extensionContext!.initiator === true, 'Invalid call');\n invariant(!this._streams.has(feedInfo.feedKey), `Replication already in progress for feed: ${feedInfo.feedKey}`);\n const { streamTag } = await this._rpc!.rpc.ReplicatorService.startReplication({ info: feedInfo });\n if (!streamTag) {\n return;\n }\n\n await this._replicateFeed(feedInfo, streamTag);\n }\n\n /**\n * Respond to a remote request to replicate a feed.\n * @returns A stream tag for the replication stream or `undefined` if we don't want to replicate.\n */\n @synchronized\n private async _acceptReplication(feedInfo: FeedInfo): Promise<string | undefined> {\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n if (!this._feeds.has(feedInfo.feedKey) || this._streams.has(feedInfo.feedKey)) {\n return undefined; // We don't have the feed or we are already replicating it.\n }\n\n const tag = `feed-${feedInfo.feedKey.toHex()}-${PublicKey.random().toHex().slice(0, 8)}`; // Generate a unique tag for the stream.\n await this._replicateFeed(feedInfo, tag);\n return tag;\n }\n\n private async _replicateFeed(info: FeedInfo, streamTag: string) {\n log('replicate', { info, streamTag });\n invariant(!this._streams.has(info.feedKey), `Replication already in progress for feed: ${info.feedKey}`);\n\n const feed = this._feeds.get(info.feedKey) ?? failUndefined();\n const networkStream = await this._extensionContext!.createStream(streamTag, {\n contentType: 'application/x-hypercore',\n });\n\n // https://github.com/holepunchto/hypercore/tree/v9.12.0#var-stream--feedreplicateisinitiator-options\n const replicationStream = feed.replicate(true, {\n live: true,\n upload: info.upload,\n download: info.download,\n noise: false,\n encrypted: false,\n maxRequests: 1024,\n });\n\n // Left for testing.\n // const debug = true;\n // if (debug) {\n // feed.on('sync', () => {\n // log.info('sync', { key: feed.key, length: feed.length });\n // });\n // feed.on('download', (index: number, data: any) => {\n // log.info('download', {\n // key: feed.key,\n // index,\n // length: feed.length,\n // data: data.length,\n // });\n // });\n // }\n\n replicationStream.on('error', (err) => {\n if (\n err?.message === 'Writable stream closed prematurely' ||\n err?.message === 'Cannot call write after a stream was destroyed'\n ) {\n return;\n }\n\n log.warn('replication stream error', { err, info });\n });\n\n this._streams.set(info.feedKey, {\n streamTag,\n networkStream,\n replicationStream,\n info,\n });\n\n networkStream.pipe(replicationStream as any).pipe(networkStream);\n }\n\n private async _stopReplication(feedKey: PublicKey) {\n const stream = this._streams.get(feedKey);\n if (!stream) {\n return;\n }\n\n stream.networkStream.destroy();\n this._streams.delete(feedKey);\n }\n}\n\ntype ServiceBundle = {\n ReplicatorService: ReplicatorService;\n};\n\ntype ActiveStream = {\n streamTag: string;\n networkStream: Duplex;\n replicationStream: ProtocolStream;\n info: FeedInfo;\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["asyncTimeout", "DeferredTask", "synchronized", "Context", "failUndefined", "invariant", "PublicKey", "log", "logInfo", "schema", "RpcClosedError", "createProtoRpcPeer", "ComplexMap", "ReplicatorExtension", "_ctx", "onError", "err", "catch", "_extensionContext", "close", "_feeds", "hash", "_streams", "_options", "upload", "_updateTask", "initiator", "_rpc", "rpc", "ReplicatorService", "updateFeeds", "feeds", "Array", "from", "values", "map", "feed", "feedKey", "key", "download", "_reevaluateFeeds", "extensionInfo", "localPeerId", "remotePeerId", "keys", "setOptions", "options", "schedule", "addFeed", "set", "onOpen", "context", "requested", "getService", "exposed", "handlers", "startReplication", "info", "streamTag", "_acceptReplication", "stopReplication", "_stopReplication", "port", "createPort", "contentType", "open", "onClose", "dispose", "disposed", "has", "get", "_initiateReplication", "feedInfo", "_replicateFeed", "undefined", "tag", "toHex", "random", "slice", "networkStream", "createStream", "replicationStream", "replicate", "live", "noise", "encrypted", "maxRequests", "on", "message", "warn", "pipe", "stream", "destroy", "delete"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts":{"bytes":33894,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/teleport-extension-replicator/src/index.ts":{"bytes":520,"imports":[{"path":"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts","kind":"import-statement","original":"./replicator-extension"}],"format":"esm"}},"outputs":{"packages/core/mesh/teleport-extension-replicator/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":14638},"packages/core/mesh/teleport-extension-replicator/dist/lib/browser/index.mjs":{"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["ReplicatorExtension"],"entryPoint":"packages/core/mesh/teleport-extension-replicator/src/index.ts","inputs":{"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts":{"bytesInOutput":10545},"packages/core/mesh/teleport-extension-replicator/src/index.ts":{"bytesInOutput":0}},"bytes":10728}}}
1
+ {"inputs":{"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts":{"bytes":35013,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/teleport-extension-replicator/src/index.ts":{"bytes":510,"imports":[{"path":"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts","kind":"import-statement","original":"./replicator-extension"}],"format":"esm"}},"outputs":{"packages/core/mesh/teleport-extension-replicator/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":15060},"packages/core/mesh/teleport-extension-replicator/dist/lib/browser/index.mjs":{"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["ReplicatorExtension"],"entryPoint":"packages/core/mesh/teleport-extension-replicator/src/index.ts","inputs":{"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts":{"bytesInOutput":10560},"packages/core/mesh/teleport-extension-replicator/src/index.ts":{"bytesInOutput":0}},"bytes":10743}}}
@@ -44,7 +44,7 @@ function _ts_decorate(decorators, target, key, desc) {
44
44
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
45
45
  return c > 3 && r && Object.defineProperty(target, key, r), r;
46
46
  }
47
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts";
47
+ var __dxlog_file = "/mnt/ramdisk/work/packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts";
48
48
  var ReplicatorExtension = class {
49
49
  constructor() {
50
50
  this._ctx = new import_context.Context({
@@ -347,7 +347,8 @@ var ReplicatorExtension = class {
347
347
  upload: info.upload,
348
348
  download: info.download,
349
349
  noise: false,
350
- encrypted: false
350
+ encrypted: false,
351
+ maxRequests: 1024
351
352
  });
352
353
  replicationStream.on("error", (err) => {
353
354
  if (err?.message === "Writable stream closed prematurely" || err?.message === "Cannot call write after a stream was destroyed") {
@@ -358,7 +359,7 @@ var ReplicatorExtension = class {
358
359
  info
359
360
  }, {
360
361
  F: __dxlog_file,
361
- L: 240,
362
+ L: 251,
362
363
  S: this,
363
364
  C: (f, a) => f(...a)
364
365
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/index.ts", "../../../src/replicator-extension.ts"],
4
- "sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nexport * from './replicator-extension';\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport type { ProtocolStream } from 'hypercore-protocol';\nimport { Duplex } from 'node:stream';\n\nimport { asyncTimeout, DeferredTask, synchronized } from '@dxos/async';\nimport { Context } from '@dxos/context';\nimport { failUndefined } from '@dxos/debug';\nimport { FeedWrapper } from '@dxos/feed-store';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { log, logInfo } from '@dxos/log';\nimport { schema, RpcClosedError } from '@dxos/protocols';\nimport { FeedInfo, ReplicatorService } from '@dxos/protocols/proto/dxos/mesh/teleport/replicator';\nimport { createProtoRpcPeer, ProtoRpcPeer } from '@dxos/rpc';\nimport { ExtensionContext, TeleportExtension } from '@dxos/teleport';\nimport { ComplexMap } from '@dxos/util';\n\nexport type ReplicationOptions = {\n upload: boolean;\n};\n\n/**\n * Manages replication between a set of feeds for a single teleport session.\n */\nexport class ReplicatorExtension implements TeleportExtension {\n private readonly _ctx = new Context({\n onError: (err) => {\n log.catch(err);\n this._extensionContext?.close(err);\n },\n });\n\n private readonly _feeds = new ComplexMap<PublicKey, FeedWrapper<any>>(PublicKey.hash);\n private readonly _streams = new ComplexMap<PublicKey, ActiveStream>(PublicKey.hash);\n\n private _rpc?: ProtoRpcPeer<ServiceBundle>;\n private _extensionContext?: ExtensionContext;\n\n private _options: ReplicationOptions = {\n upload: false,\n };\n\n private readonly _updateTask = new DeferredTask(this._ctx, async () => {\n try {\n if (this._extensionContext!.initiator === false) {\n await this._rpc!.rpc.ReplicatorService.updateFeeds({\n feeds: Array.from(this._feeds.values()).map((feed) => ({\n feedKey: feed.key,\n download: true,\n upload: this._options.upload,\n })),\n });\n } else if (this._extensionContext!.initiator === true) {\n await this._reevaluateFeeds();\n }\n } catch (err) {\n if (err instanceof RpcClosedError) {\n return; // Some RPC requests might be pending while closing.\n }\n throw err;\n }\n });\n\n @logInfo\n private get extensionInfo() {\n return {\n initiator: this._extensionContext?.initiator,\n localPeerId: this._extensionContext?.localPeerId,\n remotePeerId: this._extensionContext?.remotePeerId,\n feeds: Array.from(this._feeds.keys()),\n };\n }\n\n setOptions(options: ReplicationOptions): this {\n this._options = options;\n log('setOptions', { options });\n if (this._extensionContext) {\n this._updateTask.schedule();\n }\n return this;\n }\n\n addFeed(feed: FeedWrapper<any>) {\n this._feeds.set(feed.key, feed);\n log('addFeed', { feedKey: feed.key });\n if (this._extensionContext) {\n this._updateTask.schedule();\n }\n }\n\n async onOpen(context: ExtensionContext) {\n this._extensionContext = context;\n log('open');\n\n this._rpc = createProtoRpcPeer<ServiceBundle, ServiceBundle>({\n requested: {\n ReplicatorService: schema.getService('dxos.mesh.teleport.replicator.ReplicatorService'),\n },\n exposed: {\n ReplicatorService: schema.getService('dxos.mesh.teleport.replicator.ReplicatorService'),\n },\n handlers: {\n ReplicatorService: {\n updateFeeds: async ({ feeds }) => {\n log('received feed info', { feeds });\n invariant(this._extensionContext!.initiator === true, 'Invalid call');\n this._updateTask.schedule();\n },\n startReplication: async ({ info }) => {\n log('starting replication...', { info });\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n const streamTag = await this._acceptReplication(info);\n return {\n streamTag,\n };\n },\n stopReplication: async ({ info }) => {\n log('stopping replication...', { info });\n // TODO(dmaretskyi): Make sure any peer can stop replication.\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n await this._stopReplication(info.feedKey);\n },\n },\n },\n port: await context.createPort('rpc', {\n contentType: 'application/x-protobuf; messageType=\"dxos.rpc.Message\"',\n }),\n });\n await this._rpc.open();\n\n this._updateTask.schedule();\n }\n\n async onClose(err?: Error | undefined) {\n log('close', { err });\n await this._ctx.dispose();\n await this._rpc?.close();\n for (const feedKey of this._streams.keys()) {\n await this._stopReplication(feedKey);\n }\n }\n\n @synchronized\n private async _reevaluateFeeds() {\n log('_reevaluateFeeds');\n for (const feedKey of this._feeds.keys()) {\n if (this._ctx.disposed) {\n return;\n }\n if (this._streams.has(feedKey) && this._options.upload !== this._streams.get(feedKey)?.info.upload) {\n try {\n await asyncTimeout(this._stopReplication(feedKey), 1000);\n } catch (err) {\n log.catch(err);\n }\n }\n\n if (this._ctx.disposed) {\n return;\n }\n if (!this._streams.has(feedKey)) {\n await this._initiateReplication({\n feedKey,\n download: true,\n upload: this._options.upload,\n });\n }\n }\n }\n\n /**\n * Try to initiate feed replication.\n */\n private async _initiateReplication(feedInfo: FeedInfo) {\n log('initiating replication', { feedInfo });\n invariant(this._extensionContext!.initiator === true, 'Invalid call');\n invariant(!this._streams.has(feedInfo.feedKey), `Replication already in progress for feed: ${feedInfo.feedKey}`);\n const { streamTag } = await this._rpc!.rpc.ReplicatorService.startReplication({ info: feedInfo });\n if (!streamTag) {\n return;\n }\n\n await this._replicateFeed(feedInfo, streamTag);\n }\n\n /**\n * Respond to a remote request to replicate a feed.\n * @returns A stream tag for the replication stream or `undefined` if we don't want to replicate.\n */\n @synchronized\n private async _acceptReplication(feedInfo: FeedInfo): Promise<string | undefined> {\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n if (!this._feeds.has(feedInfo.feedKey) || this._streams.has(feedInfo.feedKey)) {\n return undefined; // We don't have the feed or we are already replicating it.\n }\n\n const tag = `feed-${feedInfo.feedKey.toHex()}-${PublicKey.random().toHex().slice(0, 8)}`; // Generate a unique tag for the stream.\n await this._replicateFeed(feedInfo, tag);\n return tag;\n }\n\n private async _replicateFeed(info: FeedInfo, streamTag: string) {\n log('replicate', { info, streamTag });\n invariant(!this._streams.has(info.feedKey), `Replication already in progress for feed: ${info.feedKey}`);\n\n const feed = this._feeds.get(info.feedKey) ?? failUndefined();\n const networkStream = await this._extensionContext!.createStream(streamTag, {\n contentType: 'application/x-hypercore',\n });\n const replicationStream = feed.replicate(true, {\n live: true,\n upload: info.upload,\n download: info.download,\n noise: false,\n encrypted: false,\n });\n\n // left for testing\n // feed.on('download', (index: number, data: any) => {\n // log('download', {\n // key: info.feedKey,\n // index\n // });\n // });\n\n replicationStream.on('error', (err) => {\n if (\n err?.message === 'Writable stream closed prematurely' ||\n err?.message === 'Cannot call write after a stream was destroyed'\n ) {\n return;\n }\n\n log.warn('replication stream error', { err, info });\n });\n\n this._streams.set(info.feedKey, {\n streamTag,\n networkStream,\n replicationStream,\n info,\n });\n\n networkStream.pipe(replicationStream as any).pipe(networkStream);\n }\n\n private async _stopReplication(feedKey: PublicKey) {\n const stream = this._streams.get(feedKey);\n if (!stream) {\n return;\n }\n\n stream.networkStream.destroy();\n this._streams.delete(feedKey);\n }\n}\n\ntype ServiceBundle = {\n ReplicatorService: ReplicatorService;\n};\n\ntype ActiveStream = {\n streamTag: string;\n networkStream: Duplex;\n replicationStream: ProtocolStream;\n info: FeedInfo;\n};\n"],
5
- "mappings": "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",
6
- "names": ["ReplicatorExtension", "_ctx", "Context", "onError", "err", "log", "catch", "_extensionContext", "close", "_feeds", "ComplexMap", "PublicKey", "hash", "_streams", "_options", "upload", "_updateTask", "DeferredTask", "initiator", "_rpc", "rpc", "ReplicatorService", "updateFeeds", "feeds", "Array", "from", "values", "map", "feed", "feedKey", "key", "download", "_reevaluateFeeds", "RpcClosedError", "extensionInfo", "localPeerId", "remotePeerId", "keys", "setOptions", "options", "schedule", "addFeed", "set", "onOpen", "context", "createProtoRpcPeer", "requested", "schema", "getService", "exposed", "handlers", "invariant", "startReplication", "info", "streamTag", "_acceptReplication", "stopReplication", "_stopReplication", "port", "createPort", "contentType", "open", "onClose", "dispose", "disposed", "has", "get", "asyncTimeout", "_initiateReplication", "feedInfo", "_replicateFeed", "undefined", "tag", "toHex", "random", "slice", "failUndefined", "networkStream", "createStream", "replicationStream", "replicate", "live", "noise", "encrypted", "on", "message", "warn", "pipe", "stream", "destroy", "delete", "logInfo", "synchronized"]
4
+ "sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nexport * from './replicator-extension';\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport type { ProtocolStream } from 'hypercore-protocol';\nimport { Duplex } from 'node:stream';\n\nimport { asyncTimeout, DeferredTask, synchronized } from '@dxos/async';\nimport { Context } from '@dxos/context';\nimport { failUndefined } from '@dxos/debug';\nimport { FeedWrapper } from '@dxos/feed-store';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { log, logInfo } from '@dxos/log';\nimport { schema, RpcClosedError } from '@dxos/protocols';\nimport { FeedInfo, ReplicatorService } from '@dxos/protocols/proto/dxos/mesh/teleport/replicator';\nimport { createProtoRpcPeer, ProtoRpcPeer } from '@dxos/rpc';\nimport { ExtensionContext, TeleportExtension } from '@dxos/teleport';\nimport { ComplexMap } from '@dxos/util';\n\nexport type ReplicationOptions = {\n upload: boolean;\n};\n\n/**\n * Manages replication between a set of feeds for a single teleport session.\n */\nexport class ReplicatorExtension implements TeleportExtension {\n private readonly _ctx = new Context({\n onError: (err) => {\n log.catch(err);\n this._extensionContext?.close(err);\n },\n });\n\n private readonly _feeds = new ComplexMap<PublicKey, FeedWrapper<any>>(PublicKey.hash);\n private readonly _streams = new ComplexMap<PublicKey, ActiveStream>(PublicKey.hash);\n\n private _rpc?: ProtoRpcPeer<ServiceBundle>;\n private _extensionContext?: ExtensionContext;\n\n private _options: ReplicationOptions = {\n upload: false,\n };\n\n private readonly _updateTask = new DeferredTask(this._ctx, async () => {\n try {\n if (this._extensionContext!.initiator === false) {\n await this._rpc!.rpc.ReplicatorService.updateFeeds({\n feeds: Array.from(this._feeds.values()).map((feed) => ({\n feedKey: feed.key,\n download: true,\n upload: this._options.upload,\n })),\n });\n } else if (this._extensionContext!.initiator === true) {\n await this._reevaluateFeeds();\n }\n } catch (err) {\n if (err instanceof RpcClosedError) {\n return; // Some RPC requests might be pending while closing.\n }\n throw err;\n }\n });\n\n @logInfo\n private get extensionInfo() {\n return {\n initiator: this._extensionContext?.initiator,\n localPeerId: this._extensionContext?.localPeerId,\n remotePeerId: this._extensionContext?.remotePeerId,\n feeds: Array.from(this._feeds.keys()),\n };\n }\n\n setOptions(options: ReplicationOptions): this {\n this._options = options;\n log('setOptions', { options });\n if (this._extensionContext) {\n this._updateTask.schedule();\n }\n return this;\n }\n\n addFeed(feed: FeedWrapper<any>) {\n this._feeds.set(feed.key, feed);\n log('addFeed', { feedKey: feed.key });\n if (this._extensionContext) {\n this._updateTask.schedule();\n }\n }\n\n async onOpen(context: ExtensionContext) {\n this._extensionContext = context;\n log('open');\n\n this._rpc = createProtoRpcPeer<ServiceBundle, ServiceBundle>({\n requested: {\n ReplicatorService: schema.getService('dxos.mesh.teleport.replicator.ReplicatorService'),\n },\n exposed: {\n ReplicatorService: schema.getService('dxos.mesh.teleport.replicator.ReplicatorService'),\n },\n handlers: {\n ReplicatorService: {\n updateFeeds: async ({ feeds }) => {\n log('received feed info', { feeds });\n invariant(this._extensionContext!.initiator === true, 'Invalid call');\n this._updateTask.schedule();\n },\n startReplication: async ({ info }) => {\n log('starting replication...', { info });\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n const streamTag = await this._acceptReplication(info);\n return {\n streamTag,\n };\n },\n stopReplication: async ({ info }) => {\n log('stopping replication...', { info });\n // TODO(dmaretskyi): Make sure any peer can stop replication.\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n await this._stopReplication(info.feedKey);\n },\n },\n },\n port: await context.createPort('rpc', {\n contentType: 'application/x-protobuf; messageType=\"dxos.rpc.Message\"',\n }),\n });\n await this._rpc.open();\n\n this._updateTask.schedule();\n }\n\n async onClose(err?: Error | undefined) {\n log('close', { err });\n await this._ctx.dispose();\n await this._rpc?.close();\n for (const feedKey of this._streams.keys()) {\n await this._stopReplication(feedKey);\n }\n }\n\n @synchronized\n private async _reevaluateFeeds() {\n log('_reevaluateFeeds');\n for (const feedKey of this._feeds.keys()) {\n if (this._ctx.disposed) {\n return;\n }\n if (this._streams.has(feedKey) && this._options.upload !== this._streams.get(feedKey)?.info.upload) {\n try {\n await asyncTimeout(this._stopReplication(feedKey), 1000);\n } catch (err) {\n log.catch(err);\n }\n }\n\n if (this._ctx.disposed) {\n return;\n }\n if (!this._streams.has(feedKey)) {\n await this._initiateReplication({\n feedKey,\n download: true,\n upload: this._options.upload,\n });\n }\n }\n }\n\n /**\n * Try to initiate feed replication.\n */\n private async _initiateReplication(feedInfo: FeedInfo) {\n log('initiating replication', { feedInfo });\n invariant(this._extensionContext!.initiator === true, 'Invalid call');\n invariant(!this._streams.has(feedInfo.feedKey), `Replication already in progress for feed: ${feedInfo.feedKey}`);\n const { streamTag } = await this._rpc!.rpc.ReplicatorService.startReplication({ info: feedInfo });\n if (!streamTag) {\n return;\n }\n\n await this._replicateFeed(feedInfo, streamTag);\n }\n\n /**\n * Respond to a remote request to replicate a feed.\n * @returns A stream tag for the replication stream or `undefined` if we don't want to replicate.\n */\n @synchronized\n private async _acceptReplication(feedInfo: FeedInfo): Promise<string | undefined> {\n invariant(this._extensionContext!.initiator === false, 'Invalid call');\n\n if (!this._feeds.has(feedInfo.feedKey) || this._streams.has(feedInfo.feedKey)) {\n return undefined; // We don't have the feed or we are already replicating it.\n }\n\n const tag = `feed-${feedInfo.feedKey.toHex()}-${PublicKey.random().toHex().slice(0, 8)}`; // Generate a unique tag for the stream.\n await this._replicateFeed(feedInfo, tag);\n return tag;\n }\n\n private async _replicateFeed(info: FeedInfo, streamTag: string) {\n log('replicate', { info, streamTag });\n invariant(!this._streams.has(info.feedKey), `Replication already in progress for feed: ${info.feedKey}`);\n\n const feed = this._feeds.get(info.feedKey) ?? failUndefined();\n const networkStream = await this._extensionContext!.createStream(streamTag, {\n contentType: 'application/x-hypercore',\n });\n\n // https://github.com/holepunchto/hypercore/tree/v9.12.0#var-stream--feedreplicateisinitiator-options\n const replicationStream = feed.replicate(true, {\n live: true,\n upload: info.upload,\n download: info.download,\n noise: false,\n encrypted: false,\n maxRequests: 1024,\n });\n\n // Left for testing.\n // const debug = true;\n // if (debug) {\n // feed.on('sync', () => {\n // log.info('sync', { key: feed.key, length: feed.length });\n // });\n // feed.on('download', (index: number, data: any) => {\n // log.info('download', {\n // key: feed.key,\n // index,\n // length: feed.length,\n // data: data.length,\n // });\n // });\n // }\n\n replicationStream.on('error', (err) => {\n if (\n err?.message === 'Writable stream closed prematurely' ||\n err?.message === 'Cannot call write after a stream was destroyed'\n ) {\n return;\n }\n\n log.warn('replication stream error', { err, info });\n });\n\n this._streams.set(info.feedKey, {\n streamTag,\n networkStream,\n replicationStream,\n info,\n });\n\n networkStream.pipe(replicationStream as any).pipe(networkStream);\n }\n\n private async _stopReplication(feedKey: PublicKey) {\n const stream = this._streams.get(feedKey);\n if (!stream) {\n return;\n }\n\n stream.networkStream.destroy();\n this._streams.delete(feedKey);\n }\n}\n\ntype ServiceBundle = {\n ReplicatorService: ReplicatorService;\n};\n\ntype ActiveStream = {\n streamTag: string;\n networkStream: Duplex;\n replicationStream: ProtocolStream;\n info: FeedInfo;\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["ReplicatorExtension", "_ctx", "Context", "onError", "err", "log", "catch", "_extensionContext", "close", "_feeds", "ComplexMap", "PublicKey", "hash", "_streams", "_options", "upload", "_updateTask", "DeferredTask", "initiator", "_rpc", "rpc", "ReplicatorService", "updateFeeds", "feeds", "Array", "from", "values", "map", "feed", "feedKey", "key", "download", "_reevaluateFeeds", "RpcClosedError", "extensionInfo", "localPeerId", "remotePeerId", "keys", "setOptions", "options", "schedule", "addFeed", "set", "onOpen", "context", "createProtoRpcPeer", "requested", "schema", "getService", "exposed", "handlers", "invariant", "startReplication", "info", "streamTag", "_acceptReplication", "stopReplication", "_stopReplication", "port", "createPort", "contentType", "open", "onClose", "dispose", "disposed", "has", "get", "asyncTimeout", "_initiateReplication", "feedInfo", "_replicateFeed", "undefined", "tag", "toHex", "random", "slice", "failUndefined", "networkStream", "createStream", "replicationStream", "replicate", "live", "noise", "encrypted", "maxRequests", "on", "message", "warn", "pipe", "stream", "destroy", "delete", "logInfo", "synchronized"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts":{"bytes":33894,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/teleport-extension-replicator/src/index.ts":{"bytes":520,"imports":[{"path":"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts","kind":"import-statement","original":"./replicator-extension"}],"format":"esm"}},"outputs":{"packages/core/mesh/teleport-extension-replicator/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":14739},"packages/core/mesh/teleport-extension-replicator/dist/lib/node/index.cjs":{"imports":[{"path":"@dxos/async","kind":"require-call","external":true},{"path":"@dxos/context","kind":"require-call","external":true},{"path":"@dxos/debug","kind":"require-call","external":true},{"path":"@dxos/invariant","kind":"require-call","external":true},{"path":"@dxos/keys","kind":"require-call","external":true},{"path":"@dxos/log","kind":"require-call","external":true},{"path":"@dxos/protocols","kind":"require-call","external":true},{"path":"@dxos/rpc","kind":"require-call","external":true},{"path":"@dxos/util","kind":"require-call","external":true}],"exports":[],"entryPoint":"packages/core/mesh/teleport-extension-replicator/src/index.ts","inputs":{"packages/core/mesh/teleport-extension-replicator/src/index.ts":{"bytesInOutput":143},"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts":{"bytesInOutput":11083}},"bytes":12320}}}
1
+ {"inputs":{"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts":{"bytes":35013,"imports":[{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/debug","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@dxos/protocols","kind":"import-statement","external":true},{"path":"@dxos/rpc","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"packages/core/mesh/teleport-extension-replicator/src/index.ts":{"bytes":510,"imports":[{"path":"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts","kind":"import-statement","original":"./replicator-extension"}],"format":"esm"}},"outputs":{"packages/core/mesh/teleport-extension-replicator/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":15161},"packages/core/mesh/teleport-extension-replicator/dist/lib/node/index.cjs":{"imports":[{"path":"@dxos/async","kind":"require-call","external":true},{"path":"@dxos/context","kind":"require-call","external":true},{"path":"@dxos/debug","kind":"require-call","external":true},{"path":"@dxos/invariant","kind":"require-call","external":true},{"path":"@dxos/keys","kind":"require-call","external":true},{"path":"@dxos/log","kind":"require-call","external":true},{"path":"@dxos/protocols","kind":"require-call","external":true},{"path":"@dxos/rpc","kind":"require-call","external":true},{"path":"@dxos/util","kind":"require-call","external":true}],"exports":[],"entryPoint":"packages/core/mesh/teleport-extension-replicator/src/index.ts","inputs":{"packages/core/mesh/teleport-extension-replicator/src/index.ts":{"bytesInOutput":143},"packages/core/mesh/teleport-extension-replicator/src/replicator-extension.ts":{"bytesInOutput":11098}},"bytes":12335}}}
@@ -1 +1 @@
1
- {"version":3,"file":"replicator-extension.d.ts","sourceRoot":"","sources":["../../../src/replicator-extension.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAO/C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGrE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF;;GAEG;AACH,qBAAa,mBAAoB,YAAW,iBAAiB;IAC3D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAKlB;IAEH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+D;IACtF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2D;IAEpF,OAAO,CAAC,IAAI,CAAC,CAA8B;IAC3C,OAAO,CAAC,iBAAiB,CAAC,CAAmB;IAE7C,OAAO,CAAC,QAAQ,CAEd;IAEF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAmBzB;IAGH,OAAO,KAAK,aAAa,GAOxB;IAED,UAAU,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAS7C,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC;IAQxB,MAAM,CAAC,OAAO,EAAE,gBAAgB;IA6ChC,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS;YAUvB,gBAAgB;IA2B9B;;OAEG;YACW,oBAAoB;IAYlC;;;OAGG;YAEW,kBAAkB;YAYlB,cAAc;YA6Cd,gBAAgB;CAS/B"}
1
+ {"version":3,"file":"replicator-extension.d.ts","sourceRoot":"","sources":["../../../src/replicator-extension.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAO/C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGrE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF;;GAEG;AACH,qBAAa,mBAAoB,YAAW,iBAAiB;IAC3D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAKlB;IAEH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+D;IACtF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2D;IAEpF,OAAO,CAAC,IAAI,CAAC,CAA8B;IAC3C,OAAO,CAAC,iBAAiB,CAAC,CAAmB;IAE7C,OAAO,CAAC,QAAQ,CAEd;IAEF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAmBzB;IAGH,OAAO,KAAK,aAAa,GAOxB;IAED,UAAU,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAS7C,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,GAAG,CAAC;IAQxB,MAAM,CAAC,OAAO,EAAE,gBAAgB;IA6ChC,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS;YAUvB,gBAAgB;IA2B9B;;OAEG;YACW,oBAAoB;IAYlC;;;OAGG;YAEW,kBAAkB;YAYlB,cAAc;YAwDd,gBAAgB;CAS/B"}
@@ -1,4 +1,4 @@
1
- import { FeedStore } from '@dxos/feed-store';
1
+ import { FeedOptions, FeedStore } from '@dxos/feed-store';
2
2
  import { Keyring } from '@dxos/keyring';
3
3
  import { PublicKey } from '@dxos/keys';
4
4
  import { Teleport } from '@dxos/teleport';
@@ -11,7 +11,7 @@ export declare class TestAgent {
11
11
  keyring: Keyring;
12
12
  feedStore: FeedStore<{}>;
13
13
  createWriteFeed(numBlocks?: number): Promise<import("@dxos/feed-store").FeedWrapper<{}>>;
14
- createReadFeed(key: PublicKey): Promise<import("@dxos/feed-store").FeedWrapper<{}>>;
14
+ createReadFeed(key: PublicKey, opts?: FeedOptions): Promise<import("@dxos/feed-store").FeedWrapper<{}>>;
15
15
  }
16
16
  /**
17
17
  * Simulates two peers connected via P2P network.
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../src/testing.ts"],"names":[],"mappings":"AAMA,OAAO,EAAe,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAI1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,qBAAa,WAAW;IACtB,WAAW,IAAI,SAAS;CAGzB;AAGD,qBAAa,SAAS;IACb,OAAO,gDAA4C;IACnD,OAAO,UAAwD;IAC/D,SAAS,gBAEb;IAEG,eAAe,CAAC,SAAS,SAAI;IAUnC,cAAc,CAAC,GAAG,EAAE,SAAS;CAG9B;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;EAuB5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;EAUhC,CAAC"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../../src/testing.ts"],"names":[],"mappings":"AAMA,OAAO,EAAe,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAI1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,qBAAa,WAAW;IACtB,WAAW,IAAI,SAAS;CAGzB;AAGD,qBAAa,SAAS;IACb,OAAO,gDAA4C;IACnD,OAAO,UAAwD;IAC/D,SAAS,gBAEb;IAEG,eAAe,CAAC,SAAS,SAAI;IAUnC,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,WAAW;CAGlD;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;EAuB5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;EAUhC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/teleport-extension-replicator",
3
- "version": "0.1.56-next.a63ce79",
3
+ "version": "0.1.56",
4
4
  "description": "Replicator extension for teleport.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -16,25 +16,25 @@
16
16
  "src"
17
17
  ],
18
18
  "dependencies": {
19
- "@dxos/async": "0.1.56-next.a63ce79",
20
- "@dxos/context": "0.1.56-next.a63ce79",
21
- "@dxos/debug": "0.1.56-next.a63ce79",
22
- "@dxos/feed-store": "0.1.56-next.a63ce79",
23
- "@dxos/invariant": "0.1.56-next.a63ce79",
24
- "@dxos/keys": "0.1.56-next.a63ce79",
25
- "@dxos/log": "0.1.56-next.a63ce79",
26
- "@dxos/node-std": "0.1.56-next.a63ce79",
27
- "@dxos/protocols": "0.1.56-next.a63ce79",
28
- "@dxos/rpc": "0.1.56-next.a63ce79",
29
- "@dxos/teleport": "0.1.56-next.a63ce79",
30
- "@dxos/util": "0.1.56-next.a63ce79"
19
+ "@dxos/async": "0.1.56",
20
+ "@dxos/context": "0.1.56",
21
+ "@dxos/debug": "0.1.56",
22
+ "@dxos/feed-store": "0.1.56",
23
+ "@dxos/invariant": "0.1.56",
24
+ "@dxos/keys": "0.1.56",
25
+ "@dxos/log": "0.1.56",
26
+ "@dxos/node-std": "0.1.56",
27
+ "@dxos/protocols": "0.1.56",
28
+ "@dxos/rpc": "0.1.56",
29
+ "@dxos/teleport": "0.1.56",
30
+ "@dxos/util": "0.1.56"
31
31
  },
32
32
  "devDependencies": {
33
33
  "add": "^2.0.6",
34
34
  "fast-check": "~3.3.0",
35
35
  "typescript": "^5.0.4",
36
- "@dxos/keyring": "0.1.56-next.a63ce79",
37
- "@dxos/random-access-storage": "0.1.56-next.a63ce79"
36
+ "@dxos/keyring": "0.1.56",
37
+ "@dxos/random-access-storage": "0.1.56"
38
38
  },
39
39
  "publishConfig": {
40
40
  "access": "public"
@@ -6,6 +6,7 @@ import expect from 'expect';
6
6
 
7
7
  import { Event, sleep } from '@dxos/async';
8
8
  import { describe, test } from '@dxos/test';
9
+ import { range } from '@dxos/util';
9
10
 
10
11
  import { createReplicatorPair, TestBuilder } from './testing';
11
12
 
@@ -103,6 +104,33 @@ describe('ReplicatorExtension', () => {
103
104
  await Event.wrap(feed1B, 'download').waitForCondition(() => feed1B.length === 10);
104
105
  });
105
106
 
107
+ test('sparse replication', async () => {
108
+ const builder = new TestBuilder();
109
+ const agent1 = builder.createAgent();
110
+ const agent2 = builder.createAgent();
111
+
112
+ const { replicator1, replicator2 } = await createReplicatorPair();
113
+
114
+ replicator1.setOptions({ upload: true });
115
+ replicator2.setOptions({ upload: true });
116
+
117
+ const feed1 = await agent1.createWriteFeed(10);
118
+ const feed2 = await agent2.createReadFeed(feed1.key, { sparse: true });
119
+
120
+ replicator1.addFeed(feed1);
121
+ replicator2.addFeed(feed2);
122
+
123
+ void feed2.download({ start: 10, linear: true });
124
+
125
+ await sleep(50);
126
+
127
+ expect(range(10).every((idx) => feed2.has(idx))).toEqual(false);
128
+
129
+ void feed2.download({ start: 0, linear: true });
130
+
131
+ await Event.wrap(feed2, 'download').waitForCondition(() => range(10).every((idx) => feed2.has(idx)));
132
+ });
133
+
106
134
  // TODO: not working yet.
107
135
  // eslint-disable-next-line mocha/no-skipped-tests
108
136
  test.skip('enabling upload mid replication', async () => {
@@ -213,21 +213,32 @@ export class ReplicatorExtension implements TeleportExtension {
213
213
  const networkStream = await this._extensionContext!.createStream(streamTag, {
214
214
  contentType: 'application/x-hypercore',
215
215
  });
216
+
217
+ // https://github.com/holepunchto/hypercore/tree/v9.12.0#var-stream--feedreplicateisinitiator-options
216
218
  const replicationStream = feed.replicate(true, {
217
219
  live: true,
218
220
  upload: info.upload,
219
221
  download: info.download,
220
222
  noise: false,
221
223
  encrypted: false,
224
+ maxRequests: 1024,
222
225
  });
223
226
 
224
- // left for testing
225
- // feed.on('download', (index: number, data: any) => {
226
- // log('download', {
227
- // key: info.feedKey,
228
- // index
227
+ // Left for testing.
228
+ // const debug = true;
229
+ // if (debug) {
230
+ // feed.on('sync', () => {
231
+ // log.info('sync', { key: feed.key, length: feed.length });
232
+ // });
233
+ // feed.on('download', (index: number, data: any) => {
234
+ // log.info('download', {
235
+ // key: feed.key,
236
+ // index,
237
+ // length: feed.length,
238
+ // data: data.length,
239
+ // });
229
240
  // });
230
- // });
241
+ // }
231
242
 
232
243
  replicationStream.on('error', (err) => {
233
244
  if (
@@ -209,8 +209,8 @@ describe('stress-tests', () => {
209
209
 
210
210
  await fc.assert(
211
211
  fc.asyncProperty(fc.commands(allCommands, { maxCommands: 100 }), async (cmds) => {
212
- console.log('\n=====');
213
- console.log([...cmds].map((c) => c.toString()).join('\n'));
212
+ // console.log('\n=====');
213
+ // console.log([...cmds].map((c) => c.toString()).join('\n'));
214
214
 
215
215
  const system = await factory(keyring)();
216
216
  try {
package/src/testing.ts CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { pipeline } from 'stream';
6
6
 
7
- import { FeedFactory, FeedStore } from '@dxos/feed-store';
7
+ import { FeedFactory, FeedOptions, FeedStore } from '@dxos/feed-store';
8
8
  import { Keyring } from '@dxos/keyring';
9
9
  import { PublicKey } from '@dxos/keys';
10
10
  import { log } from '@dxos/log';
@@ -39,8 +39,8 @@ export class TestAgent {
39
39
  return feed;
40
40
  }
41
41
 
42
- createReadFeed(key: PublicKey) {
43
- return this.feedStore.openFeed(key);
42
+ createReadFeed(key: PublicKey, opts?: FeedOptions) {
43
+ return this.feedStore.openFeed(key, opts);
44
44
  }
45
45
  }
46
46