@dxos/echo-pipeline 0.3.11-main.cc2fe2c → 0.3.11-main.ccc0ca3

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.
@@ -2685,7 +2685,7 @@ var SpaceManager = class {
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 {
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,28 +2746,108 @@ 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";
2750
2751
  import { IndexedDBStorageAdapter } from "@dxos/automerge/automerge-repo-storage-indexeddb";
2751
2752
  import { Stream as Stream2 } from "@dxos/codec-protobuf";
2752
2753
  import { invariant as invariant10 } from "@dxos/invariant";
2754
+ import { PublicKey as PublicKey8 } from "@dxos/keys";
2753
2755
  import { log as log13 } from "@dxos/log";
2754
2756
  import { StorageType } from "@dxos/random-access-storage";
2755
2757
  import { AutomergeReplicator } from "@dxos/teleport-extension-automerge-replicator";
2756
- import { arrayToBuffer as arrayToBuffer2, bufferToArray } from "@dxos/util";
2758
+ import { ComplexMap as ComplexMap7, ComplexSet, arrayToBuffer as arrayToBuffer2, bufferToArray, defaultMap } from "@dxos/util";
2757
2759
  var __dxlog_file14 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
2758
2760
  var AutomergeHost = class {
2759
2761
  constructor(storageDirectory) {
2762
+ /**
2763
+ * spaceKey -> deviceKey[]
2764
+ */
2765
+ this._authorizedDevices = new ComplexMap7(PublicKey8.hash);
2760
2766
  this._meshNetwork = new MeshNetworkAdapter();
2761
2767
  this._clientNetwork = new LocalHostNetworkAdapter();
2762
2768
  this._storage = storageDirectory.type === StorageType.IDB ? new IndexedDBStorageAdapter(storageDirectory.path, "data") : new AutomergeStorageAdapter(storageDirectory);
2763
2769
  this._repo = new Repo({
2770
+ peerId: `host-${PublicKey8.random().toHex()}`,
2764
2771
  network: [
2765
2772
  this._clientNetwork,
2766
2773
  this._meshNetwork
2767
2774
  ],
2768
2775
  storage: this._storage,
2769
2776
  // TODO(dmaretskyi): Share based on HALO permissions and space affinity.
2770
- 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
+ if (!doc.experimental_spaceKey) {
2800
+ log13.warn("space key not found for share policy check", {
2801
+ peerId,
2802
+ documentId
2803
+ }, {
2804
+ F: __dxlog_file14,
2805
+ L: 71,
2806
+ S: this,
2807
+ C: (f, a) => f(...a)
2808
+ });
2809
+ return false;
2810
+ }
2811
+ const spaceKey = PublicKey8.from(doc.experimental_spaceKey);
2812
+ const authorizedDevices = this._authorizedDevices.get(spaceKey);
2813
+ const deviceKeyHex = this.repo.peerMetadataByPeerId[peerId]?.dxos_deviceKey;
2814
+ if (!deviceKeyHex) {
2815
+ log13.warn("device key not found for share policy check", {
2816
+ peerId,
2817
+ documentId
2818
+ }, {
2819
+ F: __dxlog_file14,
2820
+ L: 81,
2821
+ S: this,
2822
+ C: (f, a) => f(...a)
2823
+ });
2824
+ return false;
2825
+ }
2826
+ const deviceKey = PublicKey8.from(deviceKeyHex);
2827
+ const isAuthorized = authorizedDevices?.has(deviceKey) ?? false;
2828
+ log13.info("share policy check", {
2829
+ peerId,
2830
+ documentId,
2831
+ deviceKey,
2832
+ spaceKey,
2833
+ isAuthorized
2834
+ }, {
2835
+ F: __dxlog_file14,
2836
+ L: 87,
2837
+ S: this,
2838
+ C: (f, a) => f(...a)
2839
+ });
2840
+ return isAuthorized;
2841
+ } catch (err) {
2842
+ log13.catch(err, void 0, {
2843
+ F: __dxlog_file14,
2844
+ L: 90,
2845
+ S: this,
2846
+ C: (f, a) => f(...a)
2847
+ });
2848
+ return false;
2849
+ }
2850
+ }
2771
2851
  });
2772
2852
  this._clientNetwork.ready();
2773
2853
  this._meshNetwork.ready();
@@ -2776,6 +2856,7 @@ var AutomergeHost = class {
2776
2856
  return this._repo;
2777
2857
  }
2778
2858
  async close() {
2859
+ this._storage instanceof AutomergeStorageAdapter && await this._storage.close();
2779
2860
  await this._clientNetwork.close();
2780
2861
  }
2781
2862
  //
@@ -2787,7 +2868,7 @@ var AutomergeHost = class {
2787
2868
  sendSyncMessage(request) {
2788
2869
  return this._clientNetwork.sendSyncMessage(request);
2789
2870
  }
2790
- getHostInfo() {
2871
+ async getHostInfo() {
2791
2872
  return this._clientNetwork.getHostInfo();
2792
2873
  }
2793
2874
  //
@@ -2796,11 +2877,15 @@ var AutomergeHost = class {
2796
2877
  createExtension() {
2797
2878
  return this._meshNetwork.createExtension();
2798
2879
  }
2880
+ authorizeDevice(spaceKey, deviceKey) {
2881
+ defaultMap(this._authorizedDevices, spaceKey, () => new ComplexSet(PublicKey8.hash)).add(deviceKey);
2882
+ }
2799
2883
  };
2800
2884
  var LocalHostNetworkAdapter = class extends NetworkAdapter {
2801
2885
  constructor() {
2802
2886
  super(...arguments);
2803
2887
  this._peers = /* @__PURE__ */ new Map();
2888
+ this._connected = new Trigger2();
2804
2889
  }
2805
2890
  /**
2806
2891
  * Emits `ready` event. That signals to `Repo` that it can start using the adapter.
@@ -2812,12 +2897,13 @@ var LocalHostNetworkAdapter = class extends NetworkAdapter {
2812
2897
  }
2813
2898
  connect(peerId) {
2814
2899
  this.peerId = peerId;
2900
+ this._connected.wake();
2815
2901
  }
2816
2902
  send(message) {
2817
2903
  const peer = this._peers.get(message.targetId);
2818
2904
  invariant10(peer, "Peer not found.", {
2819
2905
  F: __dxlog_file14,
2820
- L: 114,
2906
+ L: 170,
2821
2907
  S: this,
2822
2908
  A: [
2823
2909
  "peer",
@@ -2837,7 +2923,7 @@ var LocalHostNetworkAdapter = class extends NetworkAdapter {
2837
2923
  return new Stream2(({ next, close }) => {
2838
2924
  invariant10(!this._peers.has(peerId), "Peer already connected.", {
2839
2925
  F: __dxlog_file14,
2840
- L: 132,
2926
+ L: 188,
2841
2927
  S: this,
2842
2928
  A: [
2843
2929
  "!this._peers.has(peerId)",
@@ -2859,19 +2945,35 @@ var LocalHostNetworkAdapter = class extends NetworkAdapter {
2859
2945
  });
2860
2946
  }
2861
2947
  });
2862
- this.emit("peer-candidate", {
2863
- peerId
2864
- });
2948
+ this._connected.wait({
2949
+ timeout: 1e3
2950
+ }).then(() => {
2951
+ this.emit("peer-candidate", {
2952
+ peerMetadata: {},
2953
+ peerId
2954
+ });
2955
+ }).catch((err) => log13.catch(err, void 0, {
2956
+ F: __dxlog_file14,
2957
+ L: 213,
2958
+ S: this,
2959
+ C: (f, a) => f(...a)
2960
+ }));
2865
2961
  });
2866
2962
  }
2867
2963
  async sendSyncMessage({ id, syncMessage }) {
2964
+ await this._connected.wait({
2965
+ timeout: 1e3
2966
+ });
2868
2967
  const message = cbor.decode(syncMessage);
2869
2968
  this.emit("message", message);
2870
2969
  }
2871
- getHostInfo() {
2970
+ async getHostInfo() {
2971
+ await this._connected.wait({
2972
+ timeout: 1e3
2973
+ });
2872
2974
  invariant10(this.peerId, "Peer id not set.", {
2873
2975
  F: __dxlog_file14,
2874
- L: 161,
2976
+ L: 225,
2875
2977
  S: this,
2876
2978
  A: [
2877
2979
  "this.peerId",
@@ -2907,7 +3009,7 @@ var MeshNetworkAdapter = class extends NetworkAdapter {
2907
3009
  const extension = this._extensions.get(receiverId);
2908
3010
  invariant10(extension, "Extension not found.", {
2909
3011
  F: __dxlog_file14,
2910
- L: 196,
3012
+ L: 260,
2911
3013
  S: this,
2912
3014
  A: [
2913
3015
  "extension",
@@ -2918,7 +3020,7 @@ var MeshNetworkAdapter = class extends NetworkAdapter {
2918
3020
  payload: cbor.encode(message)
2919
3021
  }).catch((err) => log13.catch(err, void 0, {
2920
3022
  F: __dxlog_file14,
2921
- L: 197,
3023
+ L: 261,
2922
3024
  S: this,
2923
3025
  C: (f, a) => f(...a)
2924
3026
  }));
@@ -2928,7 +3030,7 @@ var MeshNetworkAdapter = class extends NetworkAdapter {
2928
3030
  createExtension() {
2929
3031
  invariant10(this.peerId, "Peer id not set.", {
2930
3032
  F: __dxlog_file14,
2931
- L: 205,
3033
+ L: 269,
2932
3034
  S: this,
2933
3035
  A: [
2934
3036
  "this.peerId",
@@ -2939,13 +3041,17 @@ var MeshNetworkAdapter = class extends NetworkAdapter {
2939
3041
  const extension = new AutomergeReplicator({
2940
3042
  peerId: this.peerId
2941
3043
  }, {
2942
- onStartReplication: async (info) => {
3044
+ onStartReplication: async (info, remotePeerId) => {
2943
3045
  if (this._extensions.has(info.id)) {
2944
3046
  return;
2945
3047
  }
2946
3048
  peerInfo = info;
2947
3049
  this._extensions.set(info.id, extension);
2948
3050
  this.emit("peer-candidate", {
3051
+ // TODO(mykola): Hack, stop abusing `peerMetadata` field.
3052
+ peerMetadata: {
3053
+ dxos_deviceKey: remotePeerId.toHex()
3054
+ },
2949
3055
  peerId: info.id
2950
3056
  });
2951
3057
  },
@@ -2970,8 +3076,12 @@ var AutomergeStorageAdapter = class extends StorageAdapter {
2970
3076
  constructor(_directory) {
2971
3077
  super();
2972
3078
  this._directory = _directory;
3079
+ this._state = "opened";
2973
3080
  }
2974
3081
  async load(key) {
3082
+ if (this._state !== "opened") {
3083
+ return void 0;
3084
+ }
2975
3085
  const filename = this._getFilename(key);
2976
3086
  const file = this._directory.getOrCreateFile(filename);
2977
3087
  const { size } = await file.stat();
@@ -2982,6 +3092,9 @@ var AutomergeStorageAdapter = class extends StorageAdapter {
2982
3092
  return bufferToArray(buffer);
2983
3093
  }
2984
3094
  async save(key, data) {
3095
+ if (this._state !== "opened") {
3096
+ return void 0;
3097
+ }
2985
3098
  const filename = this._getFilename(key);
2986
3099
  const file = this._directory.getOrCreateFile(filename);
2987
3100
  await file.write(0, arrayToBuffer2(data));
@@ -2989,11 +3102,17 @@ var AutomergeStorageAdapter = class extends StorageAdapter {
2989
3102
  await file.flush?.();
2990
3103
  }
2991
3104
  async remove(key) {
3105
+ if (this._state !== "opened") {
3106
+ return void 0;
3107
+ }
2992
3108
  const filename = this._getFilename(key);
2993
3109
  const file = this._directory.getOrCreateFile(filename);
2994
3110
  await file.destroy();
2995
3111
  }
2996
3112
  async loadRange(keyPrefix) {
3113
+ if (this._state !== "opened") {
3114
+ return [];
3115
+ }
2997
3116
  const filename = this._getFilename(keyPrefix);
2998
3117
  const entries = await this._directory.list();
2999
3118
  return Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
@@ -3007,6 +3126,9 @@ var AutomergeStorageAdapter = class extends StorageAdapter {
3007
3126
  }));
3008
3127
  }
3009
3128
  async removeRange(keyPrefix) {
3129
+ if (this._state !== "opened") {
3130
+ return void 0;
3131
+ }
3010
3132
  const filename = this._getFilename(keyPrefix);
3011
3133
  const entries = await this._directory.list();
3012
3134
  await Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
@@ -3014,6 +3136,9 @@ var AutomergeStorageAdapter = class extends StorageAdapter {
3014
3136
  await file.destroy();
3015
3137
  }));
3016
3138
  }
3139
+ async close() {
3140
+ this._state = "closed";
3141
+ }
3017
3142
  _getFilename(key) {
3018
3143
  return key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-");
3019
3144
  }
@@ -3049,4 +3174,4 @@ export {
3049
3174
  SpaceManager,
3050
3175
  AutomergeHost
3051
3176
  };
3052
- //# sourceMappingURL=chunk-MPBRK5OV.mjs.map
3177
+ //# sourceMappingURL=chunk-PB5T4DLC.mjs.map