@use-everywhere/core 0.8.0 → 0.10.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/README.md CHANGED
@@ -161,7 +161,7 @@ tabB.getSnapshot().n; // 1
161
161
  - SSR-safe: without `BroadcastChannel`, engines fall back to a local no-op
162
162
  transport.
163
163
 
164
- 📖 **[Documentation](https://rxova.github.io/use-everywhere/)** — mental
164
+ 📖 **[Documentation](https://rxova.org/packages/use-everywhere/)** — mental
165
165
  model, how sync works, security model, recipes, and generated API reference.
166
166
  Source and demo app (with a real cross-origin payment flow):
167
167
  [github.com/rxova/use-everywhere](https://github.com/rxova/use-everywhere)
package/dist/index.cjs CHANGED
@@ -25,6 +25,7 @@ __export(src_exports, {
25
25
  DEFAULT_NAME: () => DEFAULT_NAME,
26
26
  HandshakeTimeoutError: () => HandshakeTimeoutError,
27
27
  NoopTransport: () => NoopTransport,
28
+ SharedWorkerTransport: () => SharedWorkerTransport,
28
29
  StorageTransport: () => StorageTransport,
29
30
  WIRE_VERSION: () => WIRE_VERSION,
30
31
  WindowClosedError: () => WindowClosedError,
@@ -42,6 +43,7 @@ __export(src_exports, {
42
43
  getWireSkew: () => getWireSkew,
43
44
  indexedDbAdapter: () => indexedDbAdapter,
44
45
  isBroadcastChannelAvailable: () => isBroadcastChannelAvailable,
46
+ isSharedWorkerAvailable: () => isSharedWorkerAvailable,
45
47
  isStorageEventAvailable: () => isStorageEventAvailable,
46
48
  jsonSerializer: () => jsonSerializer,
47
49
  localStorageAdapter: () => localStorageAdapter,
@@ -56,6 +58,26 @@ module.exports = __toCommonJS(src_exports);
56
58
  // src/defaults.ts
57
59
  var DEFAULT_NAME = "use-everywhere";
58
60
 
61
+ // src/dev.ts
62
+ var inDev = false;
63
+ try {
64
+ inDev = process.env.NODE_ENV !== "production";
65
+ } catch {
66
+ }
67
+ var warned = /* @__PURE__ */ new Set();
68
+ var DOCS = "https://rxova.org/packages/use-everywhere/errors";
69
+ function diagnostic(code, message) {
70
+ return `[use-everywhere] ${code}: ${message}
71
+ \u2192 ${DOCS}/#${code.toLowerCase()}`;
72
+ }
73
+ function devWarn(code, message) {
74
+ if (!inDev) return;
75
+ const line = diagnostic(code, message);
76
+ if (warned.has(line)) return;
77
+ warned.add(line);
78
+ console.warn(line);
79
+ }
80
+
59
81
  // src/debug.ts
60
82
  var observers = /* @__PURE__ */ new Map();
61
83
  function emitBusEvent(name, direction, wire) {
@@ -66,7 +88,7 @@ function emitBusEvent(name, direction, wire) {
66
88
  try {
67
89
  fn(event);
68
90
  } catch (error) {
69
- console.error(`[use-everywhere] a bus observer for "${name}" threw`, error);
91
+ console.error(diagnostic("UE1012", `a bus observer for "${name}" threw`), error);
70
92
  }
71
93
  }
72
94
  }
@@ -93,19 +115,6 @@ function enableDebug(options = {}) {
93
115
  });
94
116
  }
95
117
 
96
- // src/dev.ts
97
- var inDev = false;
98
- try {
99
- inDev = process.env.NODE_ENV !== "production";
100
- } catch {
101
- }
102
- var warned = /* @__PURE__ */ new Set();
103
- function devWarn(message) {
104
- if (!inDev || warned.has(message)) return;
105
- warned.add(message);
106
- console.warn(message);
107
- }
108
-
109
118
  // src/ids.ts
110
119
  function randomHex(bytes) {
111
120
  const crypto = globalThis.crypto;
@@ -117,7 +126,8 @@ function randomHex(bytes) {
117
126
  }
118
127
  if (process.env.NODE_ENV !== "production") {
119
128
  devWarn(
120
- "[use-everywhere] crypto.getRandomValues is unavailable; falling back to Math.random for ids. Cross-origin window nonces are not cryptographically strong in this environment."
129
+ "UE1006",
130
+ "crypto.getRandomValues is unavailable; falling back to Math.random for ids. Cross-origin window nonces are not cryptographically strong in this environment."
121
131
  );
122
132
  }
123
133
  let out = "";
@@ -145,7 +155,8 @@ function announce() {
145
155
  if (census.protocols.length > 1) {
146
156
  if (process.env.NODE_ENV !== "production") {
147
157
  devWarn(
148
- `[use-everywhere] two incompatible versions of this library are loaded on one page (rendezvous protocols ${census.protocols.join(", ")}). They will not share a client identity: expect one presence entry per version and no synchronous delivery between them. They still sync over the bus. Align the versions to fix it.`
158
+ "UE1008",
159
+ `two incompatible versions of this library are loaded on one page (rendezvous protocols ${census.protocols.join(", ")}). They will not share a client identity: expect one presence entry per version and no synchronous delivery between them. They still sync over the bus. Align the versions to fix it.`
149
160
  );
150
161
  }
151
162
  }
@@ -218,7 +229,7 @@ var jsonSerializer = {
218
229
  const type = lossyType(this[key], forJson);
219
230
  if (type) {
220
231
  throw new TypeError(
221
- `use-everywhere: ${key ? `"${key}" is ` : ""}${type}, which JSON cannot round-trip. https://rxova.org/guides/serialization/`
232
+ `use-everywhere: ${key ? `"${key}" is ` : ""}${type}, which JSON cannot round-trip. https://rxova.org/packages/use-everywhere/guides/serialization/`
222
233
  );
223
234
  }
224
235
  return forJson;
@@ -235,7 +246,10 @@ var StorageTransport = class {
235
246
  this.seq = 0;
236
247
  if (!storage) {
237
248
  throw new Error(
238
- "[use-everywhere] StorageTransport needs localStorage; workers have none. Use BroadcastChannel there."
249
+ diagnostic(
250
+ "UE1011",
251
+ "StorageTransport needs localStorage; workers have none. Use BroadcastChannel there."
252
+ )
239
253
  );
240
254
  }
241
255
  this.serializer = serializer;
@@ -293,14 +307,16 @@ function defaultTransport(name) {
293
307
  if (isStorageEventAvailable()) {
294
308
  if (process.env.NODE_ENV !== "production") {
295
309
  devWarn(
296
- "[use-everywhere] no BroadcastChannel; using the storage-event fallback. Values serialise as JSON, not structured clone \u2014 keep them JSON-shaped."
310
+ "UE1009",
311
+ "no BroadcastChannel; using the storage-event fallback. Values serialise as JSON, not structured clone \u2014 keep them JSON-shaped."
297
312
  );
298
313
  }
299
314
  return new StorageTransport(name);
300
315
  }
301
316
  if (process.env.NODE_ENV !== "production") {
302
317
  devWarn(
303
- "[use-everywhere] no BroadcastChannel and no usable localStorage: nothing is shared between tabs. Storage is probably blocked."
318
+ "UE1010",
319
+ "no BroadcastChannel and no usable localStorage: nothing is shared between tabs. Storage is probably blocked."
304
320
  );
305
321
  }
306
322
  return new NoopTransport();
@@ -330,7 +346,8 @@ function recordSkew(name, version) {
330
346
  versions.add(version);
331
347
  if (process.env.NODE_ENV !== "production") {
332
348
  devWarn(
333
- `[use-everywhere] bus "${name}": a peer speaks wire protocol v${version}, this build speaks v${WIRE_VERSION} \u2014 a ${version > WIRE_VERSION ? "newer" : "older"} deploy. They cannot share state, presence, or a leader seat. https://rxova.org/under-the-hood/version-skew/`
349
+ "UE1007",
350
+ `bus "${name}": a peer speaks wire protocol v${version}, this build speaks v${WIRE_VERSION} \u2014 a ${version > WIRE_VERSION ? "newer" : "older"} deploy. They cannot share state, presence, or a leader seat. https://rxova.org/packages/use-everywhere/under-the-hood/version-skew/`
334
351
  );
335
352
  }
336
353
  }
@@ -462,15 +479,14 @@ function getBus(name, options = {}) {
462
479
  if (options.heartbeatMs !== void 0 && options.heartbeatMs !== core.heartbeatMs) {
463
480
  if (process.env.NODE_ENV !== "production") {
464
481
  devWarn(
465
- `[use-everywhere] bus "${name}": heartbeatMs ignored \u2014 the first creator fixes bus options`
482
+ "UE1004",
483
+ `bus "${name}": heartbeatMs ignored \u2014 the first creator fixes bus options`
466
484
  );
467
485
  }
468
486
  }
469
487
  if (options.kind !== void 0 && options.kind !== core.kind) {
470
488
  if (process.env.NODE_ENV !== "production") {
471
- devWarn(
472
- `[use-everywhere] bus "${name}": kind ignored \u2014 the first creator fixes bus options`
473
- );
489
+ devWarn("UE1005", `bus "${name}": kind ignored \u2014 the first creator fixes bus options`);
474
490
  }
475
491
  }
476
492
  }
@@ -499,7 +515,8 @@ function createGate(name, schemas, onInvalid) {
499
515
  if (onInvalid) onInvalid(info);
500
516
  else if (process.env.NODE_ENV !== "production") {
501
517
  devWarn(
502
- `[use-everywhere] ${name}/${key}: ${direction}bound payload rejected by its schema \u2014 ${result.issues.join("; ")}. https://rxova.org/guides/validating-payloads/`
518
+ "UE1003",
519
+ `${name}/${key}: ${direction}bound payload rejected by its schema \u2014 ${result.issues.join("; ")}. https://rxova.org/packages/use-everywhere/guides/validating-payloads/`
503
520
  );
504
521
  }
505
522
  return result.issues;
@@ -678,7 +695,8 @@ function createSharedStore(name, initial, options = {}) {
678
695
  if (live > 0) {
679
696
  if (process.env.NODE_ENV !== "production") {
680
697
  devWarn(
681
- `[use-everywhere] second shared store for "${name}" in this tab \u2014 they stay in sync, but you are paying twice for one store's state, subscriptions, and persistence writes. Reuse one per name.`
698
+ "UE1001",
699
+ `second shared store for "${name}" in this tab \u2014 they stay in sync, but you are paying twice for one store's state, subscriptions, and persistence writes. Reuse one per name.`
682
700
  );
683
701
  }
684
702
  }
@@ -842,7 +860,8 @@ function createSharedStore(name, initial, options = {}) {
842
860
  if (onRestoreError) onRestoreError(error);
843
861
  else if (process.env.NODE_ENV !== "production") {
844
862
  devWarn(
845
- `[use-everywhere] ${name}: persisted schema v${error.found} not restored, expected v${error.expected} (${error.reason}). https://rxova.org/guides/persistence/`
863
+ "UE1002",
864
+ `${name}: persisted schema v${error.found} not restored, expected v${error.expected} (${error.reason}). https://rxova.org/packages/use-everywhere/guides/persistence/`
846
865
  );
847
866
  }
848
867
  };
@@ -1873,6 +1892,42 @@ function createNamespace(namespace) {
1873
1892
  createLeader: (name, options) => createLeader(busName(name), options)
1874
1893
  };
1875
1894
  }
1895
+
1896
+ // src/transport/shared-worker-transport.ts
1897
+ var SharedWorkerTransport = class {
1898
+ constructor(options) {
1899
+ this.kind = "shared-worker";
1900
+ this.listeners = /* @__PURE__ */ new Set();
1901
+ this.closed = false;
1902
+ const name = options.name ?? "use-everywhere";
1903
+ const factory = options.factory ?? ((url, workerName) => new SharedWorker(url, { name: workerName }));
1904
+ const worker = factory(String(options.url), name);
1905
+ this.port = worker.port;
1906
+ this.onMessage = (event) => {
1907
+ for (const listener of this.listeners) listener(event.data);
1908
+ };
1909
+ this.port.addEventListener("message", this.onMessage);
1910
+ this.port.start?.();
1911
+ }
1912
+ post(data) {
1913
+ if (this.closed) return;
1914
+ this.port.postMessage(data);
1915
+ }
1916
+ subscribe(listener) {
1917
+ this.listeners.add(listener);
1918
+ return () => this.listeners.delete(listener);
1919
+ }
1920
+ close() {
1921
+ if (this.closed) return;
1922
+ this.closed = true;
1923
+ this.listeners.clear();
1924
+ this.port.removeEventListener("message", this.onMessage);
1925
+ this.port.close();
1926
+ }
1927
+ };
1928
+ function isSharedWorkerAvailable() {
1929
+ return typeof SharedWorker !== "undefined";
1930
+ }
1876
1931
  // Annotate the CommonJS export names for ESM import in node:
1877
1932
  0 && (module.exports = {
1878
1933
  BroadcastChannelTransport,
@@ -1880,6 +1935,7 @@ function createNamespace(namespace) {
1880
1935
  DEFAULT_NAME,
1881
1936
  HandshakeTimeoutError,
1882
1937
  NoopTransport,
1938
+ SharedWorkerTransport,
1883
1939
  StorageTransport,
1884
1940
  WIRE_VERSION,
1885
1941
  WindowClosedError,
@@ -1897,6 +1953,7 @@ function createNamespace(namespace) {
1897
1953
  getWireSkew,
1898
1954
  indexedDbAdapter,
1899
1955
  isBroadcastChannelAvailable,
1956
+ isSharedWorkerAvailable,
1900
1957
  isStorageEventAvailable,
1901
1958
  jsonSerializer,
1902
1959
  localStorageAdapter,
package/dist/index.d.cts CHANGED
@@ -349,7 +349,13 @@ interface LeaderOptions extends CommonOptions {
349
349
  eligible?: boolean;
350
350
  /** How to arbitrate the seat. Default 'auto'. */
351
351
  strategy?: LeaderStrategy;
352
- /** @internal Test seam for the Web Locks manager. Defaults to navigator.locks. */
352
+ /**
353
+ * The Web Locks manager to elect on. Defaults to `navigator.locks`.
354
+ *
355
+ * A test seam: `@use-everywhere/test-utils` passes a `FakeLockManager` here
356
+ * so several simulated tabs can queue on one seat — and so a crashed tab's
357
+ * lock is reclaimed — in a plain test process.
358
+ */
353
359
  locks?: LockManagerLike;
354
360
  }
355
361
  /** The slice of the Web Locks API this library uses. */
@@ -1084,6 +1090,98 @@ declare class StorageTransport implements Transport {
1084
1090
  close(): void;
1085
1091
  }
1086
1092
 
1093
+ /**
1094
+ * The subset of `SharedWorker` this transport uses. Narrower than the DOM type
1095
+ * on purpose: tests supply a fake, and a fake that has to implement
1096
+ * `EventTarget` to be accepted is a fake nobody writes.
1097
+ */
1098
+ interface SharedWorkerLike {
1099
+ readonly port: MessagePortLike;
1100
+ }
1101
+ interface MessagePortLike {
1102
+ postMessage(data: unknown): void;
1103
+ start?: () => void;
1104
+ close(): void;
1105
+ addEventListener(type: 'message', listener: (event: {
1106
+ data: unknown;
1107
+ }) => void): void;
1108
+ removeEventListener(type: 'message', listener: (event: {
1109
+ data: unknown;
1110
+ }) => void): void;
1111
+ }
1112
+ interface SharedWorkerTransportOptions {
1113
+ /**
1114
+ * The relay script. A `URL` rather than a string in the common case, because
1115
+ * `new URL('./relay.js', import.meta.url)` is what survives a bundler.
1116
+ *
1117
+ * It must be a *stable* URL, and that is the whole reason this option exists
1118
+ * rather than the library inlining a worker from a Blob the way it could for
1119
+ * a dedicated one: a SharedWorker's identity is its script URL plus its name,
1120
+ * and every tab that builds its own Blob URL gets its own worker. Inlining
1121
+ * would produce N private workers that share nothing — the failure this
1122
+ * transport exists to prevent, wearing the costume of a fix.
1123
+ */
1124
+ url: string | URL;
1125
+ /**
1126
+ * Distinguishes workers loaded from the same script. Defaults to the bus
1127
+ * name, which is what makes two buses on one origin independent.
1128
+ */
1129
+ name?: string;
1130
+ /**
1131
+ * Constructs the worker. Only tests should pass this; the default is
1132
+ * `globalThis.SharedWorker`.
1133
+ */
1134
+ factory?: (url: string, name: string) => SharedWorkerLike;
1135
+ }
1136
+ /**
1137
+ * Cross-tab delivery through one SharedWorker per origin.
1138
+ *
1139
+ * BroadcastChannel is the better default for pure fan-out and stays the
1140
+ * default. This transport buys something else: a single place that is not a
1141
+ * tab. The relay outlives any individual tab, so the thing every "the leader
1142
+ * owns the socket" design actually wants — one connection, held somewhere no
1143
+ * user can close mid-flight — becomes possible without electing a leader at
1144
+ * all.
1145
+ *
1146
+ * What it does not buy: durability. The worker is torn down when the last port
1147
+ * closes, exactly like a BroadcastChannel with no listeners. State still lives
1148
+ * in the tabs; this moves the *wire*, not the source of truth.
1149
+ *
1150
+ * The relay script is three lines and ships with the library:
1151
+ *
1152
+ * ```js
1153
+ * // sw-relay.js — your app hosts this file
1154
+ * import 'use-everywhere/shared-worker';
1155
+ * ```
1156
+ *
1157
+ * ```ts
1158
+ * createSharedStore('cart', {
1159
+ * transport: new SharedWorkerTransport({
1160
+ * url: new URL('./sw-relay.js', import.meta.url),
1161
+ * }),
1162
+ * });
1163
+ * ```
1164
+ */
1165
+ declare class SharedWorkerTransport implements Transport {
1166
+ readonly kind: TransportKind;
1167
+ private port;
1168
+ private listeners;
1169
+ private onMessage;
1170
+ private closed;
1171
+ constructor(options: SharedWorkerTransportOptions);
1172
+ post(data: unknown): void;
1173
+ subscribe(listener: (data: unknown) => void): () => void;
1174
+ close(): void;
1175
+ }
1176
+ /**
1177
+ * Whether this context can construct a SharedWorker at all.
1178
+ *
1179
+ * Notably false in every dedicated worker (they cannot nest a SharedWorker) and
1180
+ * in Chrome on Android. Worth checking before choosing this transport, since
1181
+ * the constructor throws rather than degrading.
1182
+ */
1183
+ declare function isSharedWorkerAvailable(): boolean;
1184
+
1087
1185
  declare function isBroadcastChannelAvailable(): boolean;
1088
1186
  /**
1089
1187
  * Can we hear other tabs through the `storage` event?
@@ -1105,4 +1203,4 @@ declare function isStorageEventAvailable(): boolean;
1105
1203
  */
1106
1204
  declare function defaultTransport(name: string): Transport;
1107
1205
 
1108
- export { type AskOptions, BroadcastChannelTransport, type BusEvent, type BusObserver, type BusWire, CID_PARAM, type Channel, type ChannelOptions, type CommonOptions, type ConnectToOpenerOptions, DEFAULT_NAME, type DebugOptions, HandshakeTimeoutError, type IndexedDbAdapterOptions, type InvalidPayload, type Leader, type LeaderOptions, type LeaderSnapshot, type LeaderStrategy, type MessageEventLike, type MessageMap, type MessageMeta, type Namespace, NoopTransport, type OnInvalid, type OnOptions, type OpenWindowOptions, type OpenedWindow, type OpenerConnection, type Peer, type PeerKind, type PersistAdapter, type PersistOptions, type Persisted, type PostOptions, type Presence, type PresenceOptions, type ReplyMap, type RestoreError, type SchemaMap, type SchemaOptions, type Serializer, type SharedReducer, type SharedReducerOptions, type SharedStore, type SharedStoreOptions, type StandardSchemaV1, type StorageLike, StorageTransport, Transport, TransportKind, type Version, WIRE_VERSION, type WebStorageAdapterOptions, WindowClosedError, type WindowEventTarget, type WindowLike, connectToOpener, createChannel, createLeader, createNamespace, createPresence, createSharedReducer, createSharedStore, defaultTransport, enableDebug, getBusNames, getTransportKind, getWireSkew, indexedDbAdapter, isBroadcastChannelAvailable, isStorageEventAvailable, jsonSerializer, localStorageAdapter, newer, observeBus, openWindow, sessionStorageAdapter, webStorageAdapter };
1206
+ export { type AskOptions, BroadcastChannelTransport, type BusEvent, type BusObserver, type BusWire, CID_PARAM, type Channel, type ChannelOptions, type CommonOptions, type ConnectToOpenerOptions, DEFAULT_NAME, type DebugOptions, HandshakeTimeoutError, type IndexedDbAdapterOptions, type InvalidPayload, type Leader, type LeaderOptions, type LeaderSnapshot, type LeaderStrategy, type LockManagerLike, type MessageEventLike, type MessageMap, type MessageMeta, type MessagePortLike, type Namespace, NoopTransport, type OnInvalid, type OnOptions, type OpenWindowOptions, type OpenedWindow, type OpenerConnection, type Peer, type PeerKind, type PersistAdapter, type PersistOptions, type Persisted, type PostOptions, type Presence, type PresenceOptions, type ReplyMap, type RestoreError, type SchemaMap, type SchemaOptions, type Serializer, type SharedReducer, type SharedReducerOptions, type SharedStore, type SharedStoreOptions, type SharedWorkerLike, SharedWorkerTransport, type SharedWorkerTransportOptions, type StandardSchemaV1, type StorageLike, StorageTransport, Transport, TransportKind, type Version, WIRE_VERSION, type WebStorageAdapterOptions, WindowClosedError, type WindowEventTarget, type WindowLike, connectToOpener, createChannel, createLeader, createNamespace, createPresence, createSharedReducer, createSharedStore, defaultTransport, enableDebug, getBusNames, getTransportKind, getWireSkew, indexedDbAdapter, isBroadcastChannelAvailable, isSharedWorkerAvailable, isStorageEventAvailable, jsonSerializer, localStorageAdapter, newer, observeBus, openWindow, sessionStorageAdapter, webStorageAdapter };
package/dist/index.d.ts CHANGED
@@ -349,7 +349,13 @@ interface LeaderOptions extends CommonOptions {
349
349
  eligible?: boolean;
350
350
  /** How to arbitrate the seat. Default 'auto'. */
351
351
  strategy?: LeaderStrategy;
352
- /** @internal Test seam for the Web Locks manager. Defaults to navigator.locks. */
352
+ /**
353
+ * The Web Locks manager to elect on. Defaults to `navigator.locks`.
354
+ *
355
+ * A test seam: `@use-everywhere/test-utils` passes a `FakeLockManager` here
356
+ * so several simulated tabs can queue on one seat — and so a crashed tab's
357
+ * lock is reclaimed — in a plain test process.
358
+ */
353
359
  locks?: LockManagerLike;
354
360
  }
355
361
  /** The slice of the Web Locks API this library uses. */
@@ -1084,6 +1090,98 @@ declare class StorageTransport implements Transport {
1084
1090
  close(): void;
1085
1091
  }
1086
1092
 
1093
+ /**
1094
+ * The subset of `SharedWorker` this transport uses. Narrower than the DOM type
1095
+ * on purpose: tests supply a fake, and a fake that has to implement
1096
+ * `EventTarget` to be accepted is a fake nobody writes.
1097
+ */
1098
+ interface SharedWorkerLike {
1099
+ readonly port: MessagePortLike;
1100
+ }
1101
+ interface MessagePortLike {
1102
+ postMessage(data: unknown): void;
1103
+ start?: () => void;
1104
+ close(): void;
1105
+ addEventListener(type: 'message', listener: (event: {
1106
+ data: unknown;
1107
+ }) => void): void;
1108
+ removeEventListener(type: 'message', listener: (event: {
1109
+ data: unknown;
1110
+ }) => void): void;
1111
+ }
1112
+ interface SharedWorkerTransportOptions {
1113
+ /**
1114
+ * The relay script. A `URL` rather than a string in the common case, because
1115
+ * `new URL('./relay.js', import.meta.url)` is what survives a bundler.
1116
+ *
1117
+ * It must be a *stable* URL, and that is the whole reason this option exists
1118
+ * rather than the library inlining a worker from a Blob the way it could for
1119
+ * a dedicated one: a SharedWorker's identity is its script URL plus its name,
1120
+ * and every tab that builds its own Blob URL gets its own worker. Inlining
1121
+ * would produce N private workers that share nothing — the failure this
1122
+ * transport exists to prevent, wearing the costume of a fix.
1123
+ */
1124
+ url: string | URL;
1125
+ /**
1126
+ * Distinguishes workers loaded from the same script. Defaults to the bus
1127
+ * name, which is what makes two buses on one origin independent.
1128
+ */
1129
+ name?: string;
1130
+ /**
1131
+ * Constructs the worker. Only tests should pass this; the default is
1132
+ * `globalThis.SharedWorker`.
1133
+ */
1134
+ factory?: (url: string, name: string) => SharedWorkerLike;
1135
+ }
1136
+ /**
1137
+ * Cross-tab delivery through one SharedWorker per origin.
1138
+ *
1139
+ * BroadcastChannel is the better default for pure fan-out and stays the
1140
+ * default. This transport buys something else: a single place that is not a
1141
+ * tab. The relay outlives any individual tab, so the thing every "the leader
1142
+ * owns the socket" design actually wants — one connection, held somewhere no
1143
+ * user can close mid-flight — becomes possible without electing a leader at
1144
+ * all.
1145
+ *
1146
+ * What it does not buy: durability. The worker is torn down when the last port
1147
+ * closes, exactly like a BroadcastChannel with no listeners. State still lives
1148
+ * in the tabs; this moves the *wire*, not the source of truth.
1149
+ *
1150
+ * The relay script is three lines and ships with the library:
1151
+ *
1152
+ * ```js
1153
+ * // sw-relay.js — your app hosts this file
1154
+ * import 'use-everywhere/shared-worker';
1155
+ * ```
1156
+ *
1157
+ * ```ts
1158
+ * createSharedStore('cart', {
1159
+ * transport: new SharedWorkerTransport({
1160
+ * url: new URL('./sw-relay.js', import.meta.url),
1161
+ * }),
1162
+ * });
1163
+ * ```
1164
+ */
1165
+ declare class SharedWorkerTransport implements Transport {
1166
+ readonly kind: TransportKind;
1167
+ private port;
1168
+ private listeners;
1169
+ private onMessage;
1170
+ private closed;
1171
+ constructor(options: SharedWorkerTransportOptions);
1172
+ post(data: unknown): void;
1173
+ subscribe(listener: (data: unknown) => void): () => void;
1174
+ close(): void;
1175
+ }
1176
+ /**
1177
+ * Whether this context can construct a SharedWorker at all.
1178
+ *
1179
+ * Notably false in every dedicated worker (they cannot nest a SharedWorker) and
1180
+ * in Chrome on Android. Worth checking before choosing this transport, since
1181
+ * the constructor throws rather than degrading.
1182
+ */
1183
+ declare function isSharedWorkerAvailable(): boolean;
1184
+
1087
1185
  declare function isBroadcastChannelAvailable(): boolean;
1088
1186
  /**
1089
1187
  * Can we hear other tabs through the `storage` event?
@@ -1105,4 +1203,4 @@ declare function isStorageEventAvailable(): boolean;
1105
1203
  */
1106
1204
  declare function defaultTransport(name: string): Transport;
1107
1205
 
1108
- export { type AskOptions, BroadcastChannelTransport, type BusEvent, type BusObserver, type BusWire, CID_PARAM, type Channel, type ChannelOptions, type CommonOptions, type ConnectToOpenerOptions, DEFAULT_NAME, type DebugOptions, HandshakeTimeoutError, type IndexedDbAdapterOptions, type InvalidPayload, type Leader, type LeaderOptions, type LeaderSnapshot, type LeaderStrategy, type MessageEventLike, type MessageMap, type MessageMeta, type Namespace, NoopTransport, type OnInvalid, type OnOptions, type OpenWindowOptions, type OpenedWindow, type OpenerConnection, type Peer, type PeerKind, type PersistAdapter, type PersistOptions, type Persisted, type PostOptions, type Presence, type PresenceOptions, type ReplyMap, type RestoreError, type SchemaMap, type SchemaOptions, type Serializer, type SharedReducer, type SharedReducerOptions, type SharedStore, type SharedStoreOptions, type StandardSchemaV1, type StorageLike, StorageTransport, Transport, TransportKind, type Version, WIRE_VERSION, type WebStorageAdapterOptions, WindowClosedError, type WindowEventTarget, type WindowLike, connectToOpener, createChannel, createLeader, createNamespace, createPresence, createSharedReducer, createSharedStore, defaultTransport, enableDebug, getBusNames, getTransportKind, getWireSkew, indexedDbAdapter, isBroadcastChannelAvailable, isStorageEventAvailable, jsonSerializer, localStorageAdapter, newer, observeBus, openWindow, sessionStorageAdapter, webStorageAdapter };
1206
+ export { type AskOptions, BroadcastChannelTransport, type BusEvent, type BusObserver, type BusWire, CID_PARAM, type Channel, type ChannelOptions, type CommonOptions, type ConnectToOpenerOptions, DEFAULT_NAME, type DebugOptions, HandshakeTimeoutError, type IndexedDbAdapterOptions, type InvalidPayload, type Leader, type LeaderOptions, type LeaderSnapshot, type LeaderStrategy, type LockManagerLike, type MessageEventLike, type MessageMap, type MessageMeta, type MessagePortLike, type Namespace, NoopTransport, type OnInvalid, type OnOptions, type OpenWindowOptions, type OpenedWindow, type OpenerConnection, type Peer, type PeerKind, type PersistAdapter, type PersistOptions, type Persisted, type PostOptions, type Presence, type PresenceOptions, type ReplyMap, type RestoreError, type SchemaMap, type SchemaOptions, type Serializer, type SharedReducer, type SharedReducerOptions, type SharedStore, type SharedStoreOptions, type SharedWorkerLike, SharedWorkerTransport, type SharedWorkerTransportOptions, type StandardSchemaV1, type StorageLike, StorageTransport, Transport, TransportKind, type Version, WIRE_VERSION, type WebStorageAdapterOptions, WindowClosedError, type WindowEventTarget, type WindowLike, connectToOpener, createChannel, createLeader, createNamespace, createPresence, createSharedReducer, createSharedStore, defaultTransport, enableDebug, getBusNames, getTransportKind, getWireSkew, indexedDbAdapter, isBroadcastChannelAvailable, isSharedWorkerAvailable, isStorageEventAvailable, jsonSerializer, localStorageAdapter, newer, observeBus, openWindow, sessionStorageAdapter, webStorageAdapter };
package/dist/index.js CHANGED
@@ -1,6 +1,26 @@
1
1
  // src/defaults.ts
2
2
  var DEFAULT_NAME = "use-everywhere";
3
3
 
4
+ // src/dev.ts
5
+ var inDev = false;
6
+ try {
7
+ inDev = process.env.NODE_ENV !== "production";
8
+ } catch {
9
+ }
10
+ var warned = /* @__PURE__ */ new Set();
11
+ var DOCS = "https://rxova.org/packages/use-everywhere/errors";
12
+ function diagnostic(code, message) {
13
+ return `[use-everywhere] ${code}: ${message}
14
+ \u2192 ${DOCS}/#${code.toLowerCase()}`;
15
+ }
16
+ function devWarn(code, message) {
17
+ if (!inDev) return;
18
+ const line = diagnostic(code, message);
19
+ if (warned.has(line)) return;
20
+ warned.add(line);
21
+ console.warn(line);
22
+ }
23
+
4
24
  // src/debug.ts
5
25
  var observers = /* @__PURE__ */ new Map();
6
26
  function emitBusEvent(name, direction, wire) {
@@ -11,7 +31,7 @@ function emitBusEvent(name, direction, wire) {
11
31
  try {
12
32
  fn(event);
13
33
  } catch (error) {
14
- console.error(`[use-everywhere] a bus observer for "${name}" threw`, error);
34
+ console.error(diagnostic("UE1012", `a bus observer for "${name}" threw`), error);
15
35
  }
16
36
  }
17
37
  }
@@ -38,19 +58,6 @@ function enableDebug(options = {}) {
38
58
  });
39
59
  }
40
60
 
41
- // src/dev.ts
42
- var inDev = false;
43
- try {
44
- inDev = process.env.NODE_ENV !== "production";
45
- } catch {
46
- }
47
- var warned = /* @__PURE__ */ new Set();
48
- function devWarn(message) {
49
- if (!inDev || warned.has(message)) return;
50
- warned.add(message);
51
- console.warn(message);
52
- }
53
-
54
61
  // src/ids.ts
55
62
  function randomHex(bytes) {
56
63
  const crypto = globalThis.crypto;
@@ -62,7 +69,8 @@ function randomHex(bytes) {
62
69
  }
63
70
  if (process.env.NODE_ENV !== "production") {
64
71
  devWarn(
65
- "[use-everywhere] crypto.getRandomValues is unavailable; falling back to Math.random for ids. Cross-origin window nonces are not cryptographically strong in this environment."
72
+ "UE1006",
73
+ "crypto.getRandomValues is unavailable; falling back to Math.random for ids. Cross-origin window nonces are not cryptographically strong in this environment."
66
74
  );
67
75
  }
68
76
  let out = "";
@@ -90,7 +98,8 @@ function announce() {
90
98
  if (census.protocols.length > 1) {
91
99
  if (process.env.NODE_ENV !== "production") {
92
100
  devWarn(
93
- `[use-everywhere] two incompatible versions of this library are loaded on one page (rendezvous protocols ${census.protocols.join(", ")}). They will not share a client identity: expect one presence entry per version and no synchronous delivery between them. They still sync over the bus. Align the versions to fix it.`
101
+ "UE1008",
102
+ `two incompatible versions of this library are loaded on one page (rendezvous protocols ${census.protocols.join(", ")}). They will not share a client identity: expect one presence entry per version and no synchronous delivery between them. They still sync over the bus. Align the versions to fix it.`
94
103
  );
95
104
  }
96
105
  }
@@ -163,7 +172,7 @@ var jsonSerializer = {
163
172
  const type = lossyType(this[key], forJson);
164
173
  if (type) {
165
174
  throw new TypeError(
166
- `use-everywhere: ${key ? `"${key}" is ` : ""}${type}, which JSON cannot round-trip. https://rxova.org/guides/serialization/`
175
+ `use-everywhere: ${key ? `"${key}" is ` : ""}${type}, which JSON cannot round-trip. https://rxova.org/packages/use-everywhere/guides/serialization/`
167
176
  );
168
177
  }
169
178
  return forJson;
@@ -180,7 +189,10 @@ var StorageTransport = class {
180
189
  this.seq = 0;
181
190
  if (!storage) {
182
191
  throw new Error(
183
- "[use-everywhere] StorageTransport needs localStorage; workers have none. Use BroadcastChannel there."
192
+ diagnostic(
193
+ "UE1011",
194
+ "StorageTransport needs localStorage; workers have none. Use BroadcastChannel there."
195
+ )
184
196
  );
185
197
  }
186
198
  this.serializer = serializer;
@@ -238,14 +250,16 @@ function defaultTransport(name) {
238
250
  if (isStorageEventAvailable()) {
239
251
  if (process.env.NODE_ENV !== "production") {
240
252
  devWarn(
241
- "[use-everywhere] no BroadcastChannel; using the storage-event fallback. Values serialise as JSON, not structured clone \u2014 keep them JSON-shaped."
253
+ "UE1009",
254
+ "no BroadcastChannel; using the storage-event fallback. Values serialise as JSON, not structured clone \u2014 keep them JSON-shaped."
242
255
  );
243
256
  }
244
257
  return new StorageTransport(name);
245
258
  }
246
259
  if (process.env.NODE_ENV !== "production") {
247
260
  devWarn(
248
- "[use-everywhere] no BroadcastChannel and no usable localStorage: nothing is shared between tabs. Storage is probably blocked."
261
+ "UE1010",
262
+ "no BroadcastChannel and no usable localStorage: nothing is shared between tabs. Storage is probably blocked."
249
263
  );
250
264
  }
251
265
  return new NoopTransport();
@@ -275,7 +289,8 @@ function recordSkew(name, version) {
275
289
  versions.add(version);
276
290
  if (process.env.NODE_ENV !== "production") {
277
291
  devWarn(
278
- `[use-everywhere] bus "${name}": a peer speaks wire protocol v${version}, this build speaks v${WIRE_VERSION} \u2014 a ${version > WIRE_VERSION ? "newer" : "older"} deploy. They cannot share state, presence, or a leader seat. https://rxova.org/under-the-hood/version-skew/`
292
+ "UE1007",
293
+ `bus "${name}": a peer speaks wire protocol v${version}, this build speaks v${WIRE_VERSION} \u2014 a ${version > WIRE_VERSION ? "newer" : "older"} deploy. They cannot share state, presence, or a leader seat. https://rxova.org/packages/use-everywhere/under-the-hood/version-skew/`
279
294
  );
280
295
  }
281
296
  }
@@ -407,15 +422,14 @@ function getBus(name, options = {}) {
407
422
  if (options.heartbeatMs !== void 0 && options.heartbeatMs !== core.heartbeatMs) {
408
423
  if (process.env.NODE_ENV !== "production") {
409
424
  devWarn(
410
- `[use-everywhere] bus "${name}": heartbeatMs ignored \u2014 the first creator fixes bus options`
425
+ "UE1004",
426
+ `bus "${name}": heartbeatMs ignored \u2014 the first creator fixes bus options`
411
427
  );
412
428
  }
413
429
  }
414
430
  if (options.kind !== void 0 && options.kind !== core.kind) {
415
431
  if (process.env.NODE_ENV !== "production") {
416
- devWarn(
417
- `[use-everywhere] bus "${name}": kind ignored \u2014 the first creator fixes bus options`
418
- );
432
+ devWarn("UE1005", `bus "${name}": kind ignored \u2014 the first creator fixes bus options`);
419
433
  }
420
434
  }
421
435
  }
@@ -444,7 +458,8 @@ function createGate(name, schemas, onInvalid) {
444
458
  if (onInvalid) onInvalid(info);
445
459
  else if (process.env.NODE_ENV !== "production") {
446
460
  devWarn(
447
- `[use-everywhere] ${name}/${key}: ${direction}bound payload rejected by its schema \u2014 ${result.issues.join("; ")}. https://rxova.org/guides/validating-payloads/`
461
+ "UE1003",
462
+ `${name}/${key}: ${direction}bound payload rejected by its schema \u2014 ${result.issues.join("; ")}. https://rxova.org/packages/use-everywhere/guides/validating-payloads/`
448
463
  );
449
464
  }
450
465
  return result.issues;
@@ -623,7 +638,8 @@ function createSharedStore(name, initial, options = {}) {
623
638
  if (live > 0) {
624
639
  if (process.env.NODE_ENV !== "production") {
625
640
  devWarn(
626
- `[use-everywhere] second shared store for "${name}" in this tab \u2014 they stay in sync, but you are paying twice for one store's state, subscriptions, and persistence writes. Reuse one per name.`
641
+ "UE1001",
642
+ `second shared store for "${name}" in this tab \u2014 they stay in sync, but you are paying twice for one store's state, subscriptions, and persistence writes. Reuse one per name.`
627
643
  );
628
644
  }
629
645
  }
@@ -787,7 +803,8 @@ function createSharedStore(name, initial, options = {}) {
787
803
  if (onRestoreError) onRestoreError(error);
788
804
  else if (process.env.NODE_ENV !== "production") {
789
805
  devWarn(
790
- `[use-everywhere] ${name}: persisted schema v${error.found} not restored, expected v${error.expected} (${error.reason}). https://rxova.org/guides/persistence/`
806
+ "UE1002",
807
+ `${name}: persisted schema v${error.found} not restored, expected v${error.expected} (${error.reason}). https://rxova.org/packages/use-everywhere/guides/persistence/`
791
808
  );
792
809
  }
793
810
  };
@@ -1818,12 +1835,49 @@ function createNamespace(namespace) {
1818
1835
  createLeader: (name, options) => createLeader(busName(name), options)
1819
1836
  };
1820
1837
  }
1838
+
1839
+ // src/transport/shared-worker-transport.ts
1840
+ var SharedWorkerTransport = class {
1841
+ constructor(options) {
1842
+ this.kind = "shared-worker";
1843
+ this.listeners = /* @__PURE__ */ new Set();
1844
+ this.closed = false;
1845
+ const name = options.name ?? "use-everywhere";
1846
+ const factory = options.factory ?? ((url, workerName) => new SharedWorker(url, { name: workerName }));
1847
+ const worker = factory(String(options.url), name);
1848
+ this.port = worker.port;
1849
+ this.onMessage = (event) => {
1850
+ for (const listener of this.listeners) listener(event.data);
1851
+ };
1852
+ this.port.addEventListener("message", this.onMessage);
1853
+ this.port.start?.();
1854
+ }
1855
+ post(data) {
1856
+ if (this.closed) return;
1857
+ this.port.postMessage(data);
1858
+ }
1859
+ subscribe(listener) {
1860
+ this.listeners.add(listener);
1861
+ return () => this.listeners.delete(listener);
1862
+ }
1863
+ close() {
1864
+ if (this.closed) return;
1865
+ this.closed = true;
1866
+ this.listeners.clear();
1867
+ this.port.removeEventListener("message", this.onMessage);
1868
+ this.port.close();
1869
+ }
1870
+ };
1871
+ function isSharedWorkerAvailable() {
1872
+ return typeof SharedWorker !== "undefined";
1873
+ }
1821
1874
  export {
1822
1875
  BroadcastChannelTransport,
1823
1876
  CID_PARAM,
1824
1877
  DEFAULT_NAME,
1825
1878
  HandshakeTimeoutError,
1826
1879
  NoopTransport,
1880
+ SharedWorkerTransport,
1827
1881
  StorageTransport,
1828
1882
  WIRE_VERSION,
1829
1883
  WindowClosedError,
@@ -1841,6 +1895,7 @@ export {
1841
1895
  getWireSkew,
1842
1896
  indexedDbAdapter,
1843
1897
  isBroadcastChannelAvailable,
1898
+ isSharedWorkerAvailable,
1844
1899
  isStorageEventAvailable,
1845
1900
  jsonSerializer,
1846
1901
  localStorageAdapter,
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/shared-worker.ts
21
+ var shared_worker_exports = {};
22
+ __export(shared_worker_exports, {
23
+ startRelay: () => startRelay
24
+ });
25
+ module.exports = __toCommonJS(shared_worker_exports);
26
+ function startRelay(scope) {
27
+ const ports = /* @__PURE__ */ new Set();
28
+ scope.onconnect = (event) => {
29
+ const port = event.ports[0];
30
+ if (!port) return;
31
+ ports.add(port);
32
+ port.addEventListener("message", (message) => {
33
+ const dead = [];
34
+ for (const peer of ports) {
35
+ if (peer === port) continue;
36
+ try {
37
+ peer.postMessage(message.data);
38
+ } catch {
39
+ dead.push(peer);
40
+ }
41
+ }
42
+ for (const corpse of dead) ports.delete(corpse);
43
+ });
44
+ port.start?.();
45
+ };
46
+ }
47
+ if (typeof self !== "undefined" && "onconnect" in self) {
48
+ startRelay(self);
49
+ }
50
+ // Annotate the CommonJS export names for ESM import in node:
51
+ 0 && (module.exports = {
52
+ startRelay
53
+ });
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The relay that runs *inside* a SharedWorker. Host a one-line module and point
3
+ * `SharedWorkerTransport` at it:
4
+ *
5
+ * ```js
6
+ * // sw-relay.js
7
+ * import '@use-everywhere/core/shared-worker';
8
+ * ```
9
+ *
10
+ * Importing this module installs the `connect` handler, which is why the entry
11
+ * point is a side effect rather than a function you call: a SharedWorker script
12
+ * has one job, and making the caller remember to invoke it adds a way to get a
13
+ * worker that accepts connections and forwards nothing.
14
+ *
15
+ * `startRelay` is exported anyway, for a worker that also does other work — an
16
+ * app whose relay owns the WebSocket, say — and for tests, which cannot install
17
+ * a global `onconnect`.
18
+ */
19
+ interface RelayPort {
20
+ postMessage(data: unknown): void;
21
+ start?: () => void;
22
+ addEventListener(type: 'message', listener: (event: {
23
+ data: unknown;
24
+ }) => void): void;
25
+ }
26
+ interface RelayScope {
27
+ onconnect: ((event: {
28
+ ports: readonly RelayPort[];
29
+ }) => void) | null;
30
+ }
31
+ /**
32
+ * Fan every message out to the other connected ports.
33
+ *
34
+ * Two properties the buses above this depend on:
35
+ *
36
+ * 1. **No self-echo.** A sender never receives its own message, matching
37
+ * BroadcastChannel exactly. Without it every store would apply its own
38
+ * writes twice and every presence roster would count each tab as two.
39
+ * 2. **A dead port is dropped, not thrown over.** A tab that goes away without
40
+ * closing its port leaves an entangled port whose `postMessage` throws; one
41
+ * of those must not stop delivery to the tabs still listening, so the send
42
+ * loop is individually guarded and the corpse is pruned.
43
+ */
44
+ declare function startRelay(scope: RelayScope): void;
45
+
46
+ export { type RelayPort, type RelayScope, startRelay };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The relay that runs *inside* a SharedWorker. Host a one-line module and point
3
+ * `SharedWorkerTransport` at it:
4
+ *
5
+ * ```js
6
+ * // sw-relay.js
7
+ * import '@use-everywhere/core/shared-worker';
8
+ * ```
9
+ *
10
+ * Importing this module installs the `connect` handler, which is why the entry
11
+ * point is a side effect rather than a function you call: a SharedWorker script
12
+ * has one job, and making the caller remember to invoke it adds a way to get a
13
+ * worker that accepts connections and forwards nothing.
14
+ *
15
+ * `startRelay` is exported anyway, for a worker that also does other work — an
16
+ * app whose relay owns the WebSocket, say — and for tests, which cannot install
17
+ * a global `onconnect`.
18
+ */
19
+ interface RelayPort {
20
+ postMessage(data: unknown): void;
21
+ start?: () => void;
22
+ addEventListener(type: 'message', listener: (event: {
23
+ data: unknown;
24
+ }) => void): void;
25
+ }
26
+ interface RelayScope {
27
+ onconnect: ((event: {
28
+ ports: readonly RelayPort[];
29
+ }) => void) | null;
30
+ }
31
+ /**
32
+ * Fan every message out to the other connected ports.
33
+ *
34
+ * Two properties the buses above this depend on:
35
+ *
36
+ * 1. **No self-echo.** A sender never receives its own message, matching
37
+ * BroadcastChannel exactly. Without it every store would apply its own
38
+ * writes twice and every presence roster would count each tab as two.
39
+ * 2. **A dead port is dropped, not thrown over.** A tab that goes away without
40
+ * closing its port leaves an entangled port whose `postMessage` throws; one
41
+ * of those must not stop delivery to the tabs still listening, so the send
42
+ * loop is individually guarded and the corpse is pruned.
43
+ */
44
+ declare function startRelay(scope: RelayScope): void;
45
+
46
+ export { type RelayPort, type RelayScope, startRelay };
@@ -0,0 +1,28 @@
1
+ // src/shared-worker.ts
2
+ function startRelay(scope) {
3
+ const ports = /* @__PURE__ */ new Set();
4
+ scope.onconnect = (event) => {
5
+ const port = event.ports[0];
6
+ if (!port) return;
7
+ ports.add(port);
8
+ port.addEventListener("message", (message) => {
9
+ const dead = [];
10
+ for (const peer of ports) {
11
+ if (peer === port) continue;
12
+ try {
13
+ peer.postMessage(message.data);
14
+ } catch {
15
+ dead.push(peer);
16
+ }
17
+ }
18
+ for (const corpse of dead) ports.delete(corpse);
19
+ });
20
+ port.start?.();
21
+ };
22
+ }
23
+ if (typeof self !== "undefined" && "onconnect" in self) {
24
+ startRelay(self);
25
+ }
26
+ export {
27
+ startRelay
28
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@use-everywhere/core",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Cross-tab shared state, events, presence, and cross-origin window channels",
5
5
  "license": "MIT",
6
6
  "author": "Jonatan Kruszewski <jonakrusze@gmail.com>",
@@ -24,7 +24,10 @@
24
24
  "access": "public"
25
25
  },
26
26
  "type": "module",
27
- "sideEffects": false,
27
+ "sideEffects": [
28
+ "./dist/shared-worker.js",
29
+ "./dist/shared-worker.cjs"
30
+ ],
28
31
  "main": "./dist/index.cjs",
29
32
  "module": "./dist/index.js",
30
33
  "types": "./dist/index.d.ts",
@@ -39,6 +42,16 @@
39
42
  "default": "./dist/index.cjs"
40
43
  }
41
44
  },
45
+ "./shared-worker": {
46
+ "import": {
47
+ "types": "./dist/shared-worker.d.ts",
48
+ "default": "./dist/shared-worker.js"
49
+ },
50
+ "require": {
51
+ "types": "./dist/shared-worker.d.cts",
52
+ "default": "./dist/shared-worker.cjs"
53
+ }
54
+ },
42
55
  "./testing": {
43
56
  "import": {
44
57
  "types": "./dist/testing.d.ts",
@@ -120,6 +133,18 @@
120
133
  "import": "{ indexedDbAdapter }",
121
134
  "limit": "447 B"
122
135
  },
136
+ {
137
+ "name": "SharedWorkerTransport",
138
+ "path": "dist/index.js",
139
+ "import": "{ SharedWorkerTransport }",
140
+ "limit": "380 B"
141
+ },
142
+ {
143
+ "name": "SharedWorker relay (shared-worker subpath)",
144
+ "path": "dist/shared-worker.js",
145
+ "import": "*",
146
+ "limit": "280 B"
147
+ },
123
148
  {
124
149
  "name": "MemoryHub (testing subpath)",
125
150
  "path": "dist/testing.js",
@@ -145,6 +170,9 @@
145
170
  },
146
171
  "typesVersions": {
147
172
  "*": {
173
+ "shared-worker": [
174
+ "./dist/shared-worker.d.ts"
175
+ ],
148
176
  "testing": [
149
177
  "./dist/testing.d.ts"
150
178
  ]