@dxos/echo-pipeline 0.3.11-main.00a28cb → 0.3.11-main.0999ea0

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.
@@ -26,12 +26,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  mod
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
- var chunk_PZONK23P_exports = {};
30
- __export(chunk_PZONK23P_exports, {
29
+ var chunk_WGNVVL2H_exports = {};
30
+ __export(chunk_WGNVVL2H_exports, {
31
31
  AuthExtension: () => AuthExtension,
32
32
  AuthStatus: () => AuthStatus,
33
33
  AutomergeHost: () => AutomergeHost,
34
- AutomergeStorageAdapter: () => AutomergeStorageAdapter,
35
34
  DataPipeline: () => DataPipeline,
36
35
  DataServiceHost: () => DataServiceHost,
37
36
  DataServiceImpl: () => DataServiceImpl,
@@ -55,7 +54,7 @@ __export(chunk_PZONK23P_exports, {
55
54
  startAfter: () => startAfter,
56
55
  valueEncoding: () => valueEncoding
57
56
  });
58
- module.exports = __toCommonJS(chunk_PZONK23P_exports);
57
+ module.exports = __toCommonJS(chunk_WGNVVL2H_exports);
59
58
  var import_hypercore = require("@dxos/hypercore");
60
59
  var import_protocols = require("@dxos/protocols");
61
60
  var import_invariant = require("@dxos/invariant");
@@ -148,10 +147,12 @@ var import_keys7 = require("@dxos/keys");
148
147
  var import_log12 = require("@dxos/log");
149
148
  var import_protocols7 = require("@dxos/protocols");
150
149
  var import_util9 = require("@dxos/util");
150
+ var import_async10 = require("@dxos/async");
151
151
  var import_automerge_repo = require("@dxos/automerge/automerge-repo");
152
152
  var import_automerge_repo_storage_indexeddb = require("@dxos/automerge/automerge-repo-storage-indexeddb");
153
153
  var import_codec_protobuf2 = require("@dxos/codec-protobuf");
154
154
  var import_invariant10 = require("@dxos/invariant");
155
+ var import_keys8 = require("@dxos/keys");
155
156
  var import_log13 = require("@dxos/log");
156
157
  var import_random_access_storage = require("@dxos/random-access-storage");
157
158
  var import_teleport_extension_automerge_replicator = require("@dxos/teleport-extension-automerge-replicator");
@@ -2701,7 +2702,7 @@ var SpaceManager = class {
2701
2702
  ...this._spaces.values()
2702
2703
  ].map((space) => space.close()));
2703
2704
  }
2704
- async constructSpace({ metadata, swarmIdentity, onNetworkConnection, onAuthFailure, memberKey }) {
2705
+ async constructSpace({ metadata, swarmIdentity, onAuthorizedConnection, onAuthFailure, memberKey }) {
2705
2706
  import_log12.log.trace("dxos.echo.space-manager.construct-space", import_protocols7.trace.begin({
2706
2707
  id: this._instanceId
2707
2708
  }), {
@@ -2724,7 +2725,7 @@ var SpaceManager = class {
2724
2725
  topic: spaceKey,
2725
2726
  swarmIdentity,
2726
2727
  networkManager: this._networkManager,
2727
- onSessionAuth: onNetworkConnection,
2728
+ onSessionAuth: onAuthorizedConnection,
2728
2729
  onAuthFailure,
2729
2730
  blobStore: this._blobStore
2730
2731
  });
@@ -2763,17 +2764,92 @@ SpaceManager = _ts_decorate8([
2763
2764
  var __dxlog_file14 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
2764
2765
  var AutomergeHost = class {
2765
2766
  constructor(storageDirectory) {
2767
+ this._authorizedDevices = new import_util10.ComplexMap(import_keys8.PublicKey.hash);
2766
2768
  this._meshNetwork = new MeshNetworkAdapter();
2767
2769
  this._clientNetwork = new LocalHostNetworkAdapter();
2768
2770
  this._storage = storageDirectory.type === import_random_access_storage.StorageType.IDB ? new import_automerge_repo_storage_indexeddb.IndexedDBStorageAdapter(storageDirectory.path, "data") : new AutomergeStorageAdapter(storageDirectory);
2769
2771
  this._repo = new import_automerge_repo.Repo({
2772
+ peerId: `host-${import_keys8.PublicKey.random().toHex()}`,
2770
2773
  network: [
2771
2774
  this._clientNetwork,
2772
2775
  this._meshNetwork
2773
2776
  ],
2774
2777
  storage: this._storage,
2775
2778
  // TODO(dmaretskyi): Share based on HALO permissions and space affinity.
2776
- sharePolicy: async (peerId, documentId) => true
2779
+ // Hosts, running in the worker, don't share documents unless requested by other peers.
2780
+ sharePolicy: async (peerId, documentId) => {
2781
+ if (peerId.startsWith("client-")) {
2782
+ return true;
2783
+ }
2784
+ if (!documentId) {
2785
+ return false;
2786
+ }
2787
+ const doc = this._repo.handles[documentId]?.docSync();
2788
+ if (!doc) {
2789
+ (0, import_log13.log)("doc not found for share policy check", {
2790
+ peerId,
2791
+ documentId
2792
+ }, {
2793
+ F: __dxlog_file14,
2794
+ L: 65,
2795
+ S: this,
2796
+ C: (f, a) => f(...a)
2797
+ });
2798
+ return false;
2799
+ }
2800
+ try {
2801
+ if (!doc.experimental_spaceKey) {
2802
+ import_log13.log.warn("space key not found for share policy check", {
2803
+ peerId,
2804
+ documentId
2805
+ }, {
2806
+ F: __dxlog_file14,
2807
+ L: 71,
2808
+ S: this,
2809
+ C: (f, a) => f(...a)
2810
+ });
2811
+ return false;
2812
+ }
2813
+ const spaceKey = import_keys8.PublicKey.from(doc.experimental_spaceKey);
2814
+ const authorizedDevices = this._authorizedDevices.get(spaceKey);
2815
+ const deviceKeyHex = this.repo.peerMetadataByPeerId[peerId]?.dxos_deviceKey;
2816
+ if (!deviceKeyHex) {
2817
+ import_log13.log.warn("device key not found for share policy check", {
2818
+ peerId,
2819
+ documentId
2820
+ }, {
2821
+ F: __dxlog_file14,
2822
+ L: 81,
2823
+ S: this,
2824
+ C: (f, a) => f(...a)
2825
+ });
2826
+ return false;
2827
+ }
2828
+ const deviceKey = import_keys8.PublicKey.from(deviceKeyHex);
2829
+ const isAuthorized = authorizedDevices?.has(deviceKey) ?? false;
2830
+ import_log13.log.info("share policy check", {
2831
+ peerId,
2832
+ documentId,
2833
+ deviceKey,
2834
+ spaceKey,
2835
+ isAuthorized
2836
+ }, {
2837
+ F: __dxlog_file14,
2838
+ L: 87,
2839
+ S: this,
2840
+ C: (f, a) => f(...a)
2841
+ });
2842
+ return isAuthorized;
2843
+ } catch (err) {
2844
+ import_log13.log.catch(err, void 0, {
2845
+ F: __dxlog_file14,
2846
+ L: 90,
2847
+ S: this,
2848
+ C: (f, a) => f(...a)
2849
+ });
2850
+ return false;
2851
+ }
2852
+ }
2777
2853
  });
2778
2854
  this._clientNetwork.ready();
2779
2855
  this._meshNetwork.ready();
@@ -2782,6 +2858,7 @@ var AutomergeHost = class {
2782
2858
  return this._repo;
2783
2859
  }
2784
2860
  async close() {
2861
+ this._storage instanceof AutomergeStorageAdapter && await this._storage.close();
2785
2862
  await this._clientNetwork.close();
2786
2863
  }
2787
2864
  //
@@ -2793,7 +2870,7 @@ var AutomergeHost = class {
2793
2870
  sendSyncMessage(request) {
2794
2871
  return this._clientNetwork.sendSyncMessage(request);
2795
2872
  }
2796
- getHostInfo() {
2873
+ async getHostInfo() {
2797
2874
  return this._clientNetwork.getHostInfo();
2798
2875
  }
2799
2876
  //
@@ -2802,11 +2879,15 @@ var AutomergeHost = class {
2802
2879
  createExtension() {
2803
2880
  return this._meshNetwork.createExtension();
2804
2881
  }
2882
+ authorizeDevice(spaceKey, deviceKey) {
2883
+ (0, import_util10.defaultMap)(this._authorizedDevices, spaceKey, () => new import_util10.ComplexSet(import_keys8.PublicKey.hash)).add(deviceKey);
2884
+ }
2805
2885
  };
2806
2886
  var LocalHostNetworkAdapter = class extends import_automerge_repo.NetworkAdapter {
2807
2887
  constructor() {
2808
2888
  super(...arguments);
2809
2889
  this._peers = /* @__PURE__ */ new Map();
2890
+ this._connected = new import_async10.Trigger();
2810
2891
  }
2811
2892
  /**
2812
2893
  * Emits `ready` event. That signals to `Repo` that it can start using the adapter.
@@ -2818,12 +2899,13 @@ var LocalHostNetworkAdapter = class extends import_automerge_repo.NetworkAdapter
2818
2899
  }
2819
2900
  connect(peerId) {
2820
2901
  this.peerId = peerId;
2902
+ this._connected.wake();
2821
2903
  }
2822
2904
  send(message) {
2823
2905
  const peer = this._peers.get(message.targetId);
2824
2906
  (0, import_invariant10.invariant)(peer, "Peer not found.", {
2825
2907
  F: __dxlog_file14,
2826
- L: 114,
2908
+ L: 170,
2827
2909
  S: this,
2828
2910
  A: [
2829
2911
  "peer",
@@ -2843,7 +2925,7 @@ var LocalHostNetworkAdapter = class extends import_automerge_repo.NetworkAdapter
2843
2925
  return new import_codec_protobuf2.Stream(({ next, close }) => {
2844
2926
  (0, import_invariant10.invariant)(!this._peers.has(peerId), "Peer already connected.", {
2845
2927
  F: __dxlog_file14,
2846
- L: 132,
2928
+ L: 188,
2847
2929
  S: this,
2848
2930
  A: [
2849
2931
  "!this._peers.has(peerId)",
@@ -2865,19 +2947,35 @@ var LocalHostNetworkAdapter = class extends import_automerge_repo.NetworkAdapter
2865
2947
  });
2866
2948
  }
2867
2949
  });
2868
- this.emit("peer-candidate", {
2869
- peerId
2870
- });
2950
+ this._connected.wait({
2951
+ timeout: 1e3
2952
+ }).then(() => {
2953
+ this.emit("peer-candidate", {
2954
+ peerMetadata: {},
2955
+ peerId
2956
+ });
2957
+ }).catch((err) => import_log13.log.catch(err, void 0, {
2958
+ F: __dxlog_file14,
2959
+ L: 213,
2960
+ S: this,
2961
+ C: (f, a) => f(...a)
2962
+ }));
2871
2963
  });
2872
2964
  }
2873
2965
  async sendSyncMessage({ id, syncMessage }) {
2966
+ await this._connected.wait({
2967
+ timeout: 1e3
2968
+ });
2874
2969
  const message = import_automerge_repo.cbor.decode(syncMessage);
2875
2970
  this.emit("message", message);
2876
2971
  }
2877
- getHostInfo() {
2972
+ async getHostInfo() {
2973
+ await this._connected.wait({
2974
+ timeout: 1e3
2975
+ });
2878
2976
  (0, import_invariant10.invariant)(this.peerId, "Peer id not set.", {
2879
2977
  F: __dxlog_file14,
2880
- L: 161,
2978
+ L: 225,
2881
2979
  S: this,
2882
2980
  A: [
2883
2981
  "this.peerId",
@@ -2913,7 +3011,7 @@ var MeshNetworkAdapter = class extends import_automerge_repo.NetworkAdapter {
2913
3011
  const extension = this._extensions.get(receiverId);
2914
3012
  (0, import_invariant10.invariant)(extension, "Extension not found.", {
2915
3013
  F: __dxlog_file14,
2916
- L: 196,
3014
+ L: 260,
2917
3015
  S: this,
2918
3016
  A: [
2919
3017
  "extension",
@@ -2924,7 +3022,7 @@ var MeshNetworkAdapter = class extends import_automerge_repo.NetworkAdapter {
2924
3022
  payload: import_automerge_repo.cbor.encode(message)
2925
3023
  }).catch((err) => import_log13.log.catch(err, void 0, {
2926
3024
  F: __dxlog_file14,
2927
- L: 197,
3025
+ L: 261,
2928
3026
  S: this,
2929
3027
  C: (f, a) => f(...a)
2930
3028
  }));
@@ -2934,7 +3032,7 @@ var MeshNetworkAdapter = class extends import_automerge_repo.NetworkAdapter {
2934
3032
  createExtension() {
2935
3033
  (0, import_invariant10.invariant)(this.peerId, "Peer id not set.", {
2936
3034
  F: __dxlog_file14,
2937
- L: 205,
3035
+ L: 269,
2938
3036
  S: this,
2939
3037
  A: [
2940
3038
  "this.peerId",
@@ -2945,13 +3043,17 @@ var MeshNetworkAdapter = class extends import_automerge_repo.NetworkAdapter {
2945
3043
  const extension = new import_teleport_extension_automerge_replicator.AutomergeReplicator({
2946
3044
  peerId: this.peerId
2947
3045
  }, {
2948
- onStartReplication: async (info) => {
3046
+ onStartReplication: async (info, remotePeerId) => {
2949
3047
  if (this._extensions.has(info.id)) {
2950
3048
  return;
2951
3049
  }
2952
3050
  peerInfo = info;
2953
3051
  this._extensions.set(info.id, extension);
2954
3052
  this.emit("peer-candidate", {
3053
+ // TODO(mykola): Hack, stop abusing `peerMetadata` field.
3054
+ peerMetadata: {
3055
+ dxos_deviceKey: remotePeerId.toHex()
3056
+ },
2955
3057
  peerId: info.id
2956
3058
  });
2957
3059
  },
@@ -2960,9 +3062,13 @@ var MeshNetworkAdapter = class extends import_automerge_repo.NetworkAdapter {
2960
3062
  this.emit("message", message);
2961
3063
  },
2962
3064
  onClose: async () => {
2963
- peerInfo && this.emit("peer-disconnected", {
3065
+ if (!peerInfo) {
3066
+ return;
3067
+ }
3068
+ this.emit("peer-disconnected", {
2964
3069
  peerId: peerInfo.id
2965
3070
  });
3071
+ this._extensions.delete(peerInfo.id);
2966
3072
  }
2967
3073
  });
2968
3074
  return extension;
@@ -2972,8 +3078,12 @@ var AutomergeStorageAdapter = class extends import_automerge_repo.StorageAdapter
2972
3078
  constructor(_directory) {
2973
3079
  super();
2974
3080
  this._directory = _directory;
3081
+ this._state = "opened";
2975
3082
  }
2976
3083
  async load(key) {
3084
+ if (this._state !== "opened") {
3085
+ return void 0;
3086
+ }
2977
3087
  const filename = this._getFilename(key);
2978
3088
  const file = this._directory.getOrCreateFile(filename);
2979
3089
  const { size } = await file.stat();
@@ -2984,6 +3094,9 @@ var AutomergeStorageAdapter = class extends import_automerge_repo.StorageAdapter
2984
3094
  return (0, import_util10.bufferToArray)(buffer);
2985
3095
  }
2986
3096
  async save(key, data) {
3097
+ if (this._state !== "opened") {
3098
+ return void 0;
3099
+ }
2987
3100
  const filename = this._getFilename(key);
2988
3101
  const file = this._directory.getOrCreateFile(filename);
2989
3102
  await file.write(0, (0, import_util10.arrayToBuffer)(data));
@@ -2991,11 +3104,17 @@ var AutomergeStorageAdapter = class extends import_automerge_repo.StorageAdapter
2991
3104
  await file.flush?.();
2992
3105
  }
2993
3106
  async remove(key) {
3107
+ if (this._state !== "opened") {
3108
+ return void 0;
3109
+ }
2994
3110
  const filename = this._getFilename(key);
2995
3111
  const file = this._directory.getOrCreateFile(filename);
2996
- await file.truncate?.(0);
3112
+ await file.destroy();
2997
3113
  }
2998
3114
  async loadRange(keyPrefix) {
3115
+ if (this._state !== "opened") {
3116
+ return [];
3117
+ }
2999
3118
  const filename = this._getFilename(keyPrefix);
3000
3119
  const entries = await this._directory.list();
3001
3120
  return Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
@@ -3009,13 +3128,19 @@ var AutomergeStorageAdapter = class extends import_automerge_repo.StorageAdapter
3009
3128
  }));
3010
3129
  }
3011
3130
  async removeRange(keyPrefix) {
3131
+ if (this._state !== "opened") {
3132
+ return void 0;
3133
+ }
3012
3134
  const filename = this._getFilename(keyPrefix);
3013
3135
  const entries = await this._directory.list();
3014
3136
  await Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
3015
- const file = this._directory.getOrCreateFile(filename);
3016
- await file.truncate?.(0);
3137
+ const file = this._directory.getOrCreateFile(entry);
3138
+ await file.destroy();
3017
3139
  }));
3018
3140
  }
3141
+ async close() {
3142
+ this._state = "closed";
3143
+ }
3019
3144
  _getFilename(key) {
3020
3145
  return key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-");
3021
3146
  }
@@ -3028,7 +3153,6 @@ var AutomergeStorageAdapter = class extends import_automerge_repo.StorageAdapter
3028
3153
  AuthExtension,
3029
3154
  AuthStatus,
3030
3155
  AutomergeHost,
3031
- AutomergeStorageAdapter,
3032
3156
  DataPipeline,
3033
3157
  DataServiceHost,
3034
3158
  DataServiceImpl,
@@ -3052,4 +3176,4 @@ var AutomergeStorageAdapter = class extends import_automerge_repo.StorageAdapter
3052
3176
  startAfter,
3053
3177
  valueEncoding
3054
3178
  });
3055
- //# sourceMappingURL=chunk-PZONK23P.cjs.map
3179
+ //# sourceMappingURL=chunk-WGNVVL2H.cjs.map