@dxos/echo-pipeline 0.3.11-main.a8d7a97 → 0.3.11-main.afa73e0

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.
@@ -1481,7 +1481,7 @@ var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipelin
1481
1481
  var MESSAGES_PER_SNAPSHOT = 10;
1482
1482
  var AUTOMATIC_SNAPSHOT_DEBOUNCE_INTERVAL = 5e3;
1483
1483
  var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL = 5e3;
1484
- var DataPipeline = class DataPipeline2 {
1484
+ var DataPipeline = class {
1485
1485
  constructor(_params) {
1486
1486
  this._params = _params;
1487
1487
  this._ctx = new Context4();
@@ -1955,7 +1955,7 @@ var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeli
1955
1955
  var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL2 = 500;
1956
1956
  var CONTROL_PIPELINE_SNAPSHOT_DELAY = 1e4;
1957
1957
  var USE_SNAPSHOTS = true;
1958
- var ControlPipeline = class ControlPipeline2 {
1958
+ var ControlPipeline = class {
1959
1959
  constructor({ spaceKey, genesisFeed, feedProvider, metadataStore }) {
1960
1960
  this._ctx = new Context5();
1961
1961
  this._lastTimeframeSaveTime = Date.now();
@@ -2201,7 +2201,7 @@ function _ts_decorate6(decorators, target, key, desc) {
2201
2201
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2202
2202
  }
2203
2203
  var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/space.ts";
2204
- var Space = class Space2 {
2204
+ var Space = class {
2205
2205
  constructor(params) {
2206
2206
  this._addFeedLock = new Lock();
2207
2207
  this.onCredentialProcessed = new Callback2();
@@ -2585,7 +2585,7 @@ var SpaceProtocolSession = class {
2585
2585
  this.replicator = new ReplicatorExtension().setOptions({
2586
2586
  upload: true
2587
2587
  });
2588
- this._authStatus = AuthStatus.INITIAL;
2588
+ this._authStatus = "INITIAL";
2589
2589
  this._wireParams = wireParams;
2590
2590
  this._swarmIdentity = swarmIdentity;
2591
2591
  this._onSessionAuth = onSessionAuth;
@@ -2614,11 +2614,11 @@ var SpaceProtocolSession = class {
2614
2614
  S: this,
2615
2615
  C: (f, a) => f(...a)
2616
2616
  });
2617
- this._authStatus = AuthStatus.SUCCESS;
2617
+ this._authStatus = "SUCCESS";
2618
2618
  this._onSessionAuth?.(this._teleport);
2619
2619
  },
2620
2620
  onAuthFailure: () => {
2621
- this._authStatus = AuthStatus.FAILURE;
2621
+ this._authStatus = "FAILURE";
2622
2622
  this._onAuthFailure?.(this._teleport);
2623
2623
  }
2624
2624
  }));
@@ -2663,7 +2663,7 @@ function _ts_decorate8(decorators, target, key, desc) {
2663
2663
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2664
2664
  }
2665
2665
  var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/space-manager.ts";
2666
- var SpaceManager = class SpaceManager2 {
2666
+ var SpaceManager = class {
2667
2667
  constructor({ feedStore, networkManager, modelFactory, metadataStore, snapshotStore, blobStore }) {
2668
2668
  this._spaces = new ComplexMap6(PublicKey7.hash);
2669
2669
  this._instanceId = PublicKey7.random().toHex();
@@ -2685,7 +2685,7 @@ var SpaceManager = class SpaceManager2 {
2685
2685
  ...this._spaces.values()
2686
2686
  ].map((space) => space.close()));
2687
2687
  }
2688
- async constructSpace({ metadata, swarmIdentity, onNetworkConnection, onAuthFailure, memberKey }) {
2688
+ async constructSpace({ metadata, swarmIdentity, onAuthorizedConnection, onAuthFailure, memberKey }) {
2689
2689
  log12.trace("dxos.echo.space-manager.construct-space", trace4.begin({
2690
2690
  id: this._instanceId
2691
2691
  }), {
@@ -2708,7 +2708,7 @@ var SpaceManager = class SpaceManager2 {
2708
2708
  topic: spaceKey,
2709
2709
  swarmIdentity,
2710
2710
  networkManager: this._networkManager,
2711
- onSessionAuth: onNetworkConnection,
2711
+ onSessionAuth: onAuthorizedConnection,
2712
2712
  onAuthFailure,
2713
2713
  blobStore: this._blobStore
2714
2714
  });
@@ -2746,26 +2746,96 @@ SpaceManager = _ts_decorate8([
2746
2746
  ], SpaceManager);
2747
2747
 
2748
2748
  // packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
2749
+ import { Trigger as Trigger2 } from "@dxos/async";
2749
2750
  import { Repo, NetworkAdapter, StorageAdapter, cbor } from "@dxos/automerge/automerge-repo";
2751
+ import { IndexedDBStorageAdapter } from "@dxos/automerge/automerge-repo-storage-indexeddb";
2750
2752
  import { Stream as Stream2 } from "@dxos/codec-protobuf";
2751
2753
  import { invariant as invariant10 } from "@dxos/invariant";
2754
+ import { PublicKey as PublicKey8 } from "@dxos/keys";
2752
2755
  import { log as log13 } from "@dxos/log";
2756
+ import { StorageType } from "@dxos/random-access-storage";
2753
2757
  import { AutomergeReplicator } from "@dxos/teleport-extension-automerge-replicator";
2754
- import { arrayToBuffer as arrayToBuffer2, bufferToArray } from "@dxos/util";
2758
+ import { ComplexMap as ComplexMap7, ComplexSet, arrayToBuffer as arrayToBuffer2, bufferToArray, defaultMap } from "@dxos/util";
2755
2759
  var __dxlog_file14 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
2756
2760
  var AutomergeHost = class {
2757
2761
  constructor(storageDirectory) {
2762
+ /**
2763
+ * spaceKey -> deviceKey[]
2764
+ */
2765
+ this._authorizedDevices = new ComplexMap7(PublicKey8.hash);
2758
2766
  this._meshNetwork = new MeshNetworkAdapter();
2759
2767
  this._clientNetwork = new LocalHostNetworkAdapter();
2760
- this._storage = new AutomergeStorageAdapter(storageDirectory);
2768
+ this._storage = storageDirectory.type === StorageType.IDB ? new IndexedDBStorageAdapter(storageDirectory.path, "data") : new AutomergeStorageAdapter(storageDirectory);
2761
2769
  this._repo = new Repo({
2770
+ peerId: `host-${PublicKey8.random().toHex()}`,
2762
2771
  network: [
2763
2772
  this._clientNetwork,
2764
2773
  this._meshNetwork
2765
2774
  ],
2766
2775
  storage: this._storage,
2767
2776
  // TODO(dmaretskyi): Share based on HALO permissions and space affinity.
2768
- sharePolicy: async (peerId, documentId) => true
2777
+ // Hosts, running in the worker, don't share documents unless requested by other peers.
2778
+ sharePolicy: async (peerId, documentId) => {
2779
+ if (peerId.startsWith("client-")) {
2780
+ return true;
2781
+ }
2782
+ if (!documentId) {
2783
+ return false;
2784
+ }
2785
+ const doc = this._repo.handles[documentId]?.docSync();
2786
+ if (!doc) {
2787
+ log13("doc not found for share policy check", {
2788
+ peerId,
2789
+ documentId
2790
+ }, {
2791
+ F: __dxlog_file14,
2792
+ L: 65,
2793
+ S: this,
2794
+ C: (f, a) => f(...a)
2795
+ });
2796
+ return false;
2797
+ }
2798
+ try {
2799
+ const spaceKey = PublicKey8.from(doc.experimental_spaceKey);
2800
+ const authorizedDevices = this._authorizedDevices.get(spaceKey);
2801
+ const deviceKeyHex = this.repo.peerMetadataByPeerId[peerId]?.dxos_deviceKey;
2802
+ if (!deviceKeyHex) {
2803
+ log13.warn("device key not found for share policy check", {
2804
+ peerId,
2805
+ documentId
2806
+ }, {
2807
+ F: __dxlog_file14,
2808
+ L: 76,
2809
+ S: this,
2810
+ C: (f, a) => f(...a)
2811
+ });
2812
+ return false;
2813
+ }
2814
+ const deviceKey = PublicKey8.from(deviceKeyHex);
2815
+ const isAuthorized = authorizedDevices?.has(deviceKey) ?? false;
2816
+ log13.info("share policy check", {
2817
+ peerId,
2818
+ documentId,
2819
+ deviceKey,
2820
+ spaceKey,
2821
+ isAuthorized
2822
+ }, {
2823
+ F: __dxlog_file14,
2824
+ L: 82,
2825
+ S: this,
2826
+ C: (f, a) => f(...a)
2827
+ });
2828
+ return isAuthorized;
2829
+ } catch (err) {
2830
+ log13.catch(err, void 0, {
2831
+ F: __dxlog_file14,
2832
+ L: 85,
2833
+ S: this,
2834
+ C: (f, a) => f(...a)
2835
+ });
2836
+ return false;
2837
+ }
2838
+ }
2769
2839
  });
2770
2840
  this._clientNetwork.ready();
2771
2841
  this._meshNetwork.ready();
@@ -2774,6 +2844,7 @@ var AutomergeHost = class {
2774
2844
  return this._repo;
2775
2845
  }
2776
2846
  async close() {
2847
+ this._storage instanceof AutomergeStorageAdapter && await this._storage.close();
2777
2848
  await this._clientNetwork.close();
2778
2849
  }
2779
2850
  //
@@ -2785,7 +2856,7 @@ var AutomergeHost = class {
2785
2856
  sendSyncMessage(request) {
2786
2857
  return this._clientNetwork.sendSyncMessage(request);
2787
2858
  }
2788
- getHostInfo() {
2859
+ async getHostInfo() {
2789
2860
  return this._clientNetwork.getHostInfo();
2790
2861
  }
2791
2862
  //
@@ -2794,11 +2865,15 @@ var AutomergeHost = class {
2794
2865
  createExtension() {
2795
2866
  return this._meshNetwork.createExtension();
2796
2867
  }
2868
+ authorizeDevice(spaceKey, deviceKey) {
2869
+ defaultMap(this._authorizedDevices, spaceKey, () => new ComplexSet(PublicKey8.hash)).add(deviceKey);
2870
+ }
2797
2871
  };
2798
2872
  var LocalHostNetworkAdapter = class extends NetworkAdapter {
2799
2873
  constructor() {
2800
2874
  super(...arguments);
2801
2875
  this._peers = /* @__PURE__ */ new Map();
2876
+ this._connected = new Trigger2();
2802
2877
  }
2803
2878
  /**
2804
2879
  * Emits `ready` event. That signals to `Repo` that it can start using the adapter.
@@ -2810,12 +2885,13 @@ var LocalHostNetworkAdapter = class extends NetworkAdapter {
2810
2885
  }
2811
2886
  connect(peerId) {
2812
2887
  this.peerId = peerId;
2888
+ this._connected.wake();
2813
2889
  }
2814
2890
  send(message) {
2815
2891
  const peer = this._peers.get(message.targetId);
2816
2892
  invariant10(peer, "Peer not found.", {
2817
2893
  F: __dxlog_file14,
2818
- L: 108,
2894
+ L: 165,
2819
2895
  S: this,
2820
2896
  A: [
2821
2897
  "peer",
@@ -2835,7 +2911,7 @@ var LocalHostNetworkAdapter = class extends NetworkAdapter {
2835
2911
  return new Stream2(({ next, close }) => {
2836
2912
  invariant10(!this._peers.has(peerId), "Peer already connected.", {
2837
2913
  F: __dxlog_file14,
2838
- L: 126,
2914
+ L: 183,
2839
2915
  S: this,
2840
2916
  A: [
2841
2917
  "!this._peers.has(peerId)",
@@ -2857,19 +2933,35 @@ var LocalHostNetworkAdapter = class extends NetworkAdapter {
2857
2933
  });
2858
2934
  }
2859
2935
  });
2860
- this.emit("peer-candidate", {
2861
- peerId
2862
- });
2936
+ this._connected.wait({
2937
+ timeout: 1e3
2938
+ }).then(() => {
2939
+ this.emit("peer-candidate", {
2940
+ peerMetadata: {},
2941
+ peerId
2942
+ });
2943
+ }).catch((err) => log13.catch(err, void 0, {
2944
+ F: __dxlog_file14,
2945
+ L: 208,
2946
+ S: this,
2947
+ C: (f, a) => f(...a)
2948
+ }));
2863
2949
  });
2864
2950
  }
2865
2951
  async sendSyncMessage({ id, syncMessage }) {
2952
+ await this._connected.wait({
2953
+ timeout: 1e3
2954
+ });
2866
2955
  const message = cbor.decode(syncMessage);
2867
2956
  this.emit("message", message);
2868
2957
  }
2869
- getHostInfo() {
2958
+ async getHostInfo() {
2959
+ await this._connected.wait({
2960
+ timeout: 1e3
2961
+ });
2870
2962
  invariant10(this.peerId, "Peer id not set.", {
2871
2963
  F: __dxlog_file14,
2872
- L: 155,
2964
+ L: 220,
2873
2965
  S: this,
2874
2966
  A: [
2875
2967
  "this.peerId",
@@ -2905,7 +2997,7 @@ var MeshNetworkAdapter = class extends NetworkAdapter {
2905
2997
  const extension = this._extensions.get(receiverId);
2906
2998
  invariant10(extension, "Extension not found.", {
2907
2999
  F: __dxlog_file14,
2908
- L: 190,
3000
+ L: 255,
2909
3001
  S: this,
2910
3002
  A: [
2911
3003
  "extension",
@@ -2916,7 +3008,7 @@ var MeshNetworkAdapter = class extends NetworkAdapter {
2916
3008
  payload: cbor.encode(message)
2917
3009
  }).catch((err) => log13.catch(err, void 0, {
2918
3010
  F: __dxlog_file14,
2919
- L: 191,
3011
+ L: 256,
2920
3012
  S: this,
2921
3013
  C: (f, a) => f(...a)
2922
3014
  }));
@@ -2926,7 +3018,7 @@ var MeshNetworkAdapter = class extends NetworkAdapter {
2926
3018
  createExtension() {
2927
3019
  invariant10(this.peerId, "Peer id not set.", {
2928
3020
  F: __dxlog_file14,
2929
- L: 199,
3021
+ L: 264,
2930
3022
  S: this,
2931
3023
  A: [
2932
3024
  "this.peerId",
@@ -2937,13 +3029,17 @@ var MeshNetworkAdapter = class extends NetworkAdapter {
2937
3029
  const extension = new AutomergeReplicator({
2938
3030
  peerId: this.peerId
2939
3031
  }, {
2940
- onStartReplication: async (info) => {
3032
+ onStartReplication: async (info, remotePeerId) => {
2941
3033
  if (this._extensions.has(info.id)) {
2942
3034
  return;
2943
3035
  }
2944
3036
  peerInfo = info;
2945
3037
  this._extensions.set(info.id, extension);
2946
3038
  this.emit("peer-candidate", {
3039
+ // TODO(mykola): Hack, stop abusing `peerMetadata` field.
3040
+ peerMetadata: {
3041
+ dxos_deviceKey: remotePeerId.toHex()
3042
+ },
2947
3043
  peerId: info.id
2948
3044
  });
2949
3045
  },
@@ -2952,9 +3048,13 @@ var MeshNetworkAdapter = class extends NetworkAdapter {
2952
3048
  this.emit("message", message);
2953
3049
  },
2954
3050
  onClose: async () => {
2955
- peerInfo && this.emit("peer-disconnected", {
3051
+ if (!peerInfo) {
3052
+ return;
3053
+ }
3054
+ this.emit("peer-disconnected", {
2956
3055
  peerId: peerInfo.id
2957
3056
  });
3057
+ this._extensions.delete(peerInfo.id);
2958
3058
  }
2959
3059
  });
2960
3060
  return extension;
@@ -2964,8 +3064,12 @@ var AutomergeStorageAdapter = class extends StorageAdapter {
2964
3064
  constructor(_directory) {
2965
3065
  super();
2966
3066
  this._directory = _directory;
3067
+ this._state = "opened";
2967
3068
  }
2968
3069
  async load(key) {
3070
+ if (this._state !== "opened") {
3071
+ return void 0;
3072
+ }
2969
3073
  const filename = this._getFilename(key);
2970
3074
  const file = this._directory.getOrCreateFile(filename);
2971
3075
  const { size } = await file.stat();
@@ -2976,6 +3080,9 @@ var AutomergeStorageAdapter = class extends StorageAdapter {
2976
3080
  return bufferToArray(buffer);
2977
3081
  }
2978
3082
  async save(key, data) {
3083
+ if (this._state !== "opened") {
3084
+ return void 0;
3085
+ }
2979
3086
  const filename = this._getFilename(key);
2980
3087
  const file = this._directory.getOrCreateFile(filename);
2981
3088
  await file.write(0, arrayToBuffer2(data));
@@ -2983,11 +3090,17 @@ var AutomergeStorageAdapter = class extends StorageAdapter {
2983
3090
  await file.flush?.();
2984
3091
  }
2985
3092
  async remove(key) {
3093
+ if (this._state !== "opened") {
3094
+ return void 0;
3095
+ }
2986
3096
  const filename = this._getFilename(key);
2987
3097
  const file = this._directory.getOrCreateFile(filename);
2988
- await file.truncate?.(0);
3098
+ await file.destroy();
2989
3099
  }
2990
3100
  async loadRange(keyPrefix) {
3101
+ if (this._state !== "opened") {
3102
+ return [];
3103
+ }
2991
3104
  const filename = this._getFilename(keyPrefix);
2992
3105
  const entries = await this._directory.list();
2993
3106
  return Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
@@ -3001,13 +3114,19 @@ var AutomergeStorageAdapter = class extends StorageAdapter {
3001
3114
  }));
3002
3115
  }
3003
3116
  async removeRange(keyPrefix) {
3117
+ if (this._state !== "opened") {
3118
+ return void 0;
3119
+ }
3004
3120
  const filename = this._getFilename(keyPrefix);
3005
3121
  const entries = await this._directory.list();
3006
3122
  await Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
3007
- const file = this._directory.getOrCreateFile(filename);
3008
- await file.truncate?.(0);
3123
+ const file = this._directory.getOrCreateFile(entry);
3124
+ await file.destroy();
3009
3125
  }));
3010
3126
  }
3127
+ async close() {
3128
+ this._state = "closed";
3129
+ }
3011
3130
  _getFilename(key) {
3012
3131
  return key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-");
3013
3132
  }
@@ -3041,7 +3160,6 @@ export {
3041
3160
  AuthStatus,
3042
3161
  SpaceProtocolSession,
3043
3162
  SpaceManager,
3044
- AutomergeHost,
3045
- AutomergeStorageAdapter
3163
+ AutomergeHost
3046
3164
  };
3047
- //# sourceMappingURL=chunk-EM4RCBYQ.mjs.map
3165
+ //# sourceMappingURL=chunk-AUYVKEFF.mjs.map