@xnetjs/runtime 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -187,6 +187,14 @@ interface SyncManager {
187
187
  track(nodeId: string, schemaId: string): void;
188
188
  /** Stop tracking a Node */
189
189
  untrack(nodeId: string): void;
190
+ /**
191
+ * Subscribe (receive-only) to a share room — e.g. a channel's
192
+ * `xnet-channel-<id>` — so grant-covered nodes the hub fans in reach the
193
+ * local store (exploration 0298). Idempotent. No-op without a node store.
194
+ */
195
+ subscribeShareRoom(room: string): void;
196
+ /** Stop receiving a share room's changes. */
197
+ unsubscribeShareRoom(room: string): void;
190
198
  /** Acquire a Y.Doc (used by useNode) */
191
199
  acquire(nodeId: string): Promise<Y.Doc>;
192
200
  /** Release a Y.Doc (component unmounted) */
@@ -944,6 +952,13 @@ declare function createMultiHubSyncManager(config: MultiHubSyncManagerConfig): M
944
952
  * genuine backlog can't trip the hub's per-connection rate limiter (1008).
945
953
  */
946
954
 
955
+ /**
956
+ * The share room that carries a channel's nodes to its grantees (0298). Must
957
+ * match the hub's `channelShareRoom` so `topicToResource` resolves the grant.
958
+ */
959
+ declare const channelShareRoom: (channelId: string) => string;
960
+ /** The share room that carries a workspace (bench) node to its grantees (0298). */
961
+ declare const workspaceShareRoom: (workspaceId: string) => string;
947
962
  type SerializedNodeChange = {
948
963
  id: string;
949
964
  type: string;
@@ -984,6 +999,7 @@ type SyncBlockedListener = (reason: SyncBlockedReason, detail: string) => void;
984
999
  declare class NodeStoreSyncProvider {
985
1000
  private store;
986
1001
  private room;
1002
+ private subscribeOnly;
987
1003
  /** Confirmed, persisted high-water mark (advanced from the hub's response). */
988
1004
  private lastSyncedLamport;
989
1005
  /** Optimistic in-memory cursor: lamport of the last change actually sent. */
@@ -1005,7 +1021,15 @@ declare class NodeStoreSyncProvider {
1005
1021
  private outboundHalted;
1006
1022
  private clearResolver;
1007
1023
  private firstRemoteApplyMarked;
1008
- constructor(store: NodeStore, room: string);
1024
+ /**
1025
+ * Subscribe-only providers (channel share rooms, 0298) RECEIVE and apply a
1026
+ * room's changes but never publish local changes into it (the hub owns
1027
+ * fan-out) and never advance the cursor from a live broadcast's author
1028
+ * lamport — a share room's cursor is a per-room `seq` carried opaquely in the
1029
+ * sync-response high-water mark, and author lamports across members are not
1030
+ * mutually ordered.
1031
+ */
1032
+ constructor(store: NodeStore, room: string, subscribeOnly?: boolean);
1009
1033
  /**
1010
1034
  * Mark the first remote apply once. Platform-agnostic and defensive: a
1011
1035
  * missing `performance` global, or a throw, is a no-op — instrumentation
@@ -1313,4 +1337,4 @@ declare function negotiateProtocolVersion(ours: readonly string[], theirs: reado
1313
1337
  */
1314
1338
  declare function isProtocolCompatible(theirs: readonly string[]): boolean;
1315
1339
 
1316
- export { type AdapterConformanceCheck, AdapterConformanceError, type AdapterConformanceResult, type BlobStoreForSync, type ConformanceClientFactory, type ConnectionManager, type ConnectionManagerConfig, type ConnectionStatus, type CreateXNetClientOptions, type HubConnection, type HubTransport, type InitialSyncManager, type InitialSyncMessage, type LiveQuery, type LiveQueryValue, METABRIDGE_ORIGIN, METABRIDGE_SEED_ORIGIN, type MetaBridge, type MultiHubConnectionManagerConfig, type MultiHubSyncManager, type MultiHubSyncManagerConfig, type NodePool, type NodePoolConfig, NodeStoreSyncProvider, type NodeSyncResponse, type OfflineQueue, type OfflineQueueConfig, type PlannedHub, type PoolEntryState, type ProgressListener, type QueueEntry, type Registry, type RegistryConfig, type RegistryStorage, type ReplicaTrust, type ReplicationDestinationSpec, type ReplicationScopeNode, type ScopedRoomHandle, type SerializedNodeChange, type SpaceReplicationPolicy, type SyncBlockedListener, type SyncBlockedReason, type SyncManager, type SyncManagerConfig, type SyncPhase, type SyncProgress, type SyncReconciliationOptions, type SyncReconciliationReport, type SyncStatus, type TrackedNode, WebSocketSyncProvider, type WebSocketSyncProviderOptions, XNET_AWARENESS_VERSION, XNET_DATA_MODEL_VERSION, XNET_PROTOCOL_VERSION, XNET_SCHEMA_VERSION, XNET_SUPPORTED_PROTOCOL_VERSIONS, XNET_SYNC_ENVELOPE_VERSION, XNET_UCAN_PROFILE, type XNetClient, type XNetClientBridgeMode, type XNetClientPluginOptions, type XNetClientRuntimePhase, type XNetClientRuntimeStatus, type XNetClientSyncOptions, type XNetClientTelemetry, type XNetClientUndoOptions, type XNetProtocolBundle, createConnectionManager, createInitialSyncManager, createMetaBridge, createMultiHubConnectionManager, createMultiHubSyncManager, createNodePool, createOfflineQueue, createRegistry, createSyncManager, createXNetClient, isProtocolCompatible, liveQuery, namespaceForNode, negotiateProtocolVersion, replicationConfigFromPolicies, runAdapterConformance, spaceNamespace, systemNamespace };
1340
+ export { type AdapterConformanceCheck, AdapterConformanceError, type AdapterConformanceResult, type BlobStoreForSync, type ConformanceClientFactory, type ConnectionManager, type ConnectionManagerConfig, type ConnectionStatus, type CreateXNetClientOptions, type HubConnection, type HubTransport, type InitialSyncManager, type InitialSyncMessage, type LiveQuery, type LiveQueryValue, METABRIDGE_ORIGIN, METABRIDGE_SEED_ORIGIN, type MetaBridge, type MultiHubConnectionManagerConfig, type MultiHubSyncManager, type MultiHubSyncManagerConfig, type NodePool, type NodePoolConfig, NodeStoreSyncProvider, type NodeSyncResponse, type OfflineQueue, type OfflineQueueConfig, type PlannedHub, type PoolEntryState, type ProgressListener, type QueueEntry, type Registry, type RegistryConfig, type RegistryStorage, type ReplicaTrust, type ReplicationDestinationSpec, type ReplicationScopeNode, type ScopedRoomHandle, type SerializedNodeChange, type SpaceReplicationPolicy, type SyncBlockedListener, type SyncBlockedReason, type SyncManager, type SyncManagerConfig, type SyncPhase, type SyncProgress, type SyncReconciliationOptions, type SyncReconciliationReport, type SyncStatus, type TrackedNode, WebSocketSyncProvider, type WebSocketSyncProviderOptions, XNET_AWARENESS_VERSION, XNET_DATA_MODEL_VERSION, XNET_PROTOCOL_VERSION, XNET_SCHEMA_VERSION, XNET_SUPPORTED_PROTOCOL_VERSIONS, XNET_SYNC_ENVELOPE_VERSION, XNET_UCAN_PROFILE, type XNetClient, type XNetClientBridgeMode, type XNetClientPluginOptions, type XNetClientRuntimePhase, type XNetClientRuntimeStatus, type XNetClientSyncOptions, type XNetClientTelemetry, type XNetClientUndoOptions, type XNetProtocolBundle, channelShareRoom, createConnectionManager, createInitialSyncManager, createMetaBridge, createMultiHubConnectionManager, createMultiHubSyncManager, createNodePool, createOfflineQueue, createRegistry, createSyncManager, createXNetClient, isProtocolCompatible, liveQuery, namespaceForNode, negotiateProtocolVersion, replicationConfigFromPolicies, runAdapterConformance, spaceNamespace, systemNamespace, workspaceShareRoom };
package/dist/index.js CHANGED
@@ -901,11 +901,22 @@ function nowMs2() {
901
901
  function yieldToEventLoop() {
902
902
  return new Promise((resolve) => setTimeout(resolve, 0));
903
903
  }
904
+ var channelShareRoom = (channelId) => `xnet-channel-${channelId}`;
905
+ var workspaceShareRoom = (workspaceId) => `xnet-workspace-${workspaceId}`;
904
906
  var CAPACITY_REJECTION_CODES = /* @__PURE__ */ new Set(["QUOTA_EXCEEDED", "STORAGE_FULL"]);
905
907
  var NodeStoreSyncProvider = class {
906
- constructor(store, room) {
908
+ /**
909
+ * Subscribe-only providers (channel share rooms, 0298) RECEIVE and apply a
910
+ * room's changes but never publish local changes into it (the hub owns
911
+ * fan-out) and never advance the cursor from a live broadcast's author
912
+ * lamport — a share room's cursor is a per-room `seq` carried opaquely in the
913
+ * sync-response high-water mark, and author lamports across members are not
914
+ * mutually ordered.
915
+ */
916
+ constructor(store, room, subscribeOnly = false) {
907
917
  this.store = store;
908
918
  this.room = room;
919
+ this.subscribeOnly = subscribeOnly;
909
920
  }
910
921
  /** Confirmed, persisted high-water mark (advanced from the hub's response). */
911
922
  lastSyncedLamport = 0;
@@ -990,10 +1001,12 @@ var NodeStoreSyncProvider = class {
990
1001
  this.onDisconnected();
991
1002
  }
992
1003
  });
993
- this.storeCleanup = this.store.subscribe((event) => {
994
- if (event.isRemote) return;
995
- this.enqueueChange(event.change);
996
- });
1004
+ if (!this.subscribeOnly) {
1005
+ this.storeCleanup = this.store.subscribe((event) => {
1006
+ if (event.isRemote) return;
1007
+ this.enqueueChange(event.change);
1008
+ });
1009
+ }
997
1010
  if (connection.status === "connected") {
998
1011
  void this.onConnected();
999
1012
  }
@@ -1026,7 +1039,7 @@ var NodeStoreSyncProvider = class {
1026
1039
  if (!this.connection || this.connection.status !== "connected") return;
1027
1040
  this.requestSync();
1028
1041
  await this.waitForSyncResponse();
1029
- await this.syncLocalChanges();
1042
+ if (!this.subscribeOnly) await this.syncLocalChanges();
1030
1043
  }
1031
1044
  onDisconnected() {
1032
1045
  this.clearSendQueue();
@@ -1180,7 +1193,7 @@ var NodeStoreSyncProvider = class {
1180
1193
  }
1181
1194
  async handleRemoteChange(serialized, peerId = "unknown") {
1182
1195
  const change = this.deserializeChange(serialized);
1183
- if (serialized.lamportTime > this.lastSyncedLamport) {
1196
+ if (!this.subscribeOnly && serialized.lamportTime > this.lastSyncedLamport) {
1184
1197
  this.lastSyncedLamport = serialized.lamportTime;
1185
1198
  }
1186
1199
  if (!KNOWN_CHANGE_TYPES.has(change.type)) {
@@ -1798,6 +1811,7 @@ function createSyncManager(config) {
1798
1811
  });
1799
1812
  let offlineQueueReady = Promise.resolve();
1800
1813
  const nodeSyncProvider = config.nodeSyncRoom ? new NodeStoreSyncProvider(config.nodeStore, config.nodeSyncRoom) : null;
1814
+ const shareRoomProviders = /* @__PURE__ */ new Map();
1801
1815
  let blobSync = null;
1802
1816
  if (config.blobStore) {
1803
1817
  const underlyingStore = config.blobStore;
@@ -2269,6 +2283,7 @@ function createSyncManager(config) {
2269
2283
  log2("Connecting to signaling server...");
2270
2284
  connection.connect();
2271
2285
  nodeSyncProvider?.attach(connection);
2286
+ for (const provider of shareRoomProviders.values()) provider.attach(connection);
2272
2287
  blobSync?.start();
2273
2288
  const tracked = registry.getTracked();
2274
2289
  log2("Joining rooms for", tracked.length, "tracked nodes");
@@ -2286,6 +2301,8 @@ function createSyncManager(config) {
2286
2301
  });
2287
2302
  blobSync?.stop();
2288
2303
  nodeSyncProvider?.detach();
2304
+ for (const provider of shareRoomProviders.values()) provider.detach();
2305
+ shareRoomProviders.clear();
2289
2306
  for (const nodeId of Array.from(roomCleanups.keys())) {
2290
2307
  leaveNodeRoom(nodeId);
2291
2308
  }
@@ -2314,6 +2331,18 @@ function createSyncManager(config) {
2314
2331
  scheduleRegistrySave();
2315
2332
  leaveNodeRoom(nodeId);
2316
2333
  },
2334
+ subscribeShareRoom(room) {
2335
+ if (shareRoomProviders.has(room)) return;
2336
+ const provider = new NodeStoreSyncProvider(config.nodeStore, room, true);
2337
+ shareRoomProviders.set(room, provider);
2338
+ provider.attach(connection);
2339
+ },
2340
+ unsubscribeShareRoom(room) {
2341
+ const provider = shareRoomProviders.get(room);
2342
+ if (!provider) return;
2343
+ provider.detach();
2344
+ shareRoomProviders.delete(room);
2345
+ },
2317
2346
  async acquire(nodeId) {
2318
2347
  log2("Acquiring doc for node:", nodeId);
2319
2348
  registry.touch(nodeId);
@@ -3492,6 +3521,7 @@ export {
3492
3521
  XNET_SUPPORTED_PROTOCOL_VERSIONS,
3493
3522
  XNET_SYNC_ENVELOPE_VERSION,
3494
3523
  XNET_UCAN_PROFILE,
3524
+ channelShareRoom,
3495
3525
  createConnectionManager,
3496
3526
  createInitialSyncManager,
3497
3527
  createMetaBridge,
@@ -3509,5 +3539,6 @@ export {
3509
3539
  replicationConfigFromPolicies,
3510
3540
  runAdapterConformance,
3511
3541
  spaceNamespace,
3512
- systemNamespace
3542
+ systemNamespace,
3543
+ workspaceShareRoom
3513
3544
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xnetjs/runtime",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Framework-agnostic xNet runtime: createXNetClient() and sync orchestration, usable from any framework, a CLI, a worker, or a Node service",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,15 +28,15 @@
28
28
  "dependencies": {
29
29
  "y-protocols": "^1.0.6",
30
30
  "yjs": "^13.6.24",
31
- "@xnetjs/core": "0.10.0",
32
- "@xnetjs/crypto": "0.10.0",
33
- "@xnetjs/data": "0.10.0",
34
- "@xnetjs/data-bridge": "0.10.0",
35
- "@xnetjs/history": "0.10.0",
36
- "@xnetjs/identity": "0.10.0",
37
- "@xnetjs/plugins": "0.10.0",
38
- "@xnetjs/storage": "0.10.0",
39
- "@xnetjs/sync": "0.10.0"
31
+ "@xnetjs/core": "0.11.0",
32
+ "@xnetjs/data": "0.11.0",
33
+ "@xnetjs/crypto": "0.11.0",
34
+ "@xnetjs/data-bridge": "0.11.0",
35
+ "@xnetjs/history": "0.11.0",
36
+ "@xnetjs/identity": "0.11.0",
37
+ "@xnetjs/plugins": "0.11.0",
38
+ "@xnetjs/storage": "0.11.0",
39
+ "@xnetjs/sync": "0.11.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "jsdom": "^26.0.0",