@afterrealism/dendri-client 2.4.0 → 2.6.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.
Files changed (44) hide show
  1. package/README.md +35 -18
  2. package/dist/chunk-G3PMV62Z.js +33 -0
  3. package/dist/chunk-G3PMV62Z.js.map +1 -0
  4. package/dist/{chunk-MBMSG4EC.js → chunk-YLWDCKUW.js} +73 -44
  5. package/dist/chunk-YLWDCKUW.js.map +1 -0
  6. package/dist/dendri.browser.global.js +70 -13
  7. package/dist/dendri.browser.global.js.map +1 -1
  8. package/dist/dendri.cjs +70 -13
  9. package/dist/dendri.cjs.map +1 -1
  10. package/dist/dendri.d.cts +13 -4
  11. package/dist/dendri.d.ts +13 -4
  12. package/dist/dendri.js +3 -2
  13. package/dist/dendri.js.map +1 -1
  14. package/dist/dendri.min.global.js +7 -7
  15. package/dist/dendri.min.global.js.map +1 -1
  16. package/dist/react.cjs +16 -0
  17. package/dist/react.cjs.map +1 -0
  18. package/dist/react.d.cts +25 -0
  19. package/dist/react.d.ts +25 -0
  20. package/dist/react.js +14 -0
  21. package/dist/react.js.map +1 -0
  22. package/dist/serializer.msgpack.d.cts +14 -0
  23. package/dist/serializer.msgpack.d.ts +14 -0
  24. package/dist/{store-DVE0ih44.d.cts → store-C3Nwl62R.d.cts} +14 -0
  25. package/dist/{store-DVE0ih44.d.ts → store-C3Nwl62R.d.ts} +14 -0
  26. package/dist/store.cjs +70 -13
  27. package/dist/store.cjs.map +1 -1
  28. package/dist/store.d.cts +1 -1
  29. package/dist/store.d.ts +1 -1
  30. package/dist/store.js +2 -1
  31. package/dist/svelte.cjs +15 -0
  32. package/dist/svelte.cjs.map +1 -0
  33. package/dist/svelte.d.cts +29 -0
  34. package/dist/svelte.d.ts +29 -0
  35. package/dist/svelte.js +15 -0
  36. package/dist/svelte.js.map +1 -0
  37. package/dist/vue.cjs +19 -0
  38. package/dist/vue.cjs.map +1 -0
  39. package/dist/vue.d.cts +25 -0
  40. package/dist/vue.d.ts +25 -0
  41. package/dist/vue.js +17 -0
  42. package/dist/vue.js.map +1 -0
  43. package/package.json +49 -2
  44. package/dist/chunk-MBMSG4EC.js.map +0 -1
package/README.md CHANGED
@@ -10,30 +10,26 @@ npm install @afterrealism/dendri-client
10
10
 
11
11
  ## Connect To Your Server
12
12
 
13
- Dendri is self-host-first. You must provide the signaling server that your app should use:
13
+ Pass the signaling server your app should use as a single URL:
14
14
 
15
15
  ```ts
16
16
  import { Dendri } from "@afterrealism/dendri-client";
17
17
 
18
18
  const peer = new Dendri({
19
- host: "signal.example.com",
20
- port: 443,
21
- secure: true,
22
- path: "/",
19
+ url: "wss://signal.example.com",
20
+ apiKey: "your-api-key", // only needed for hosted / multi-tenant deployments
23
21
  });
24
22
  ```
25
23
 
24
+ `url` is shorthand for `host`/`port`/`secure`/`path` — pass those individually if you
25
+ prefer; explicitly passed fields win over url-derived ones.
26
+
26
27
  You can also pass an explicit peer id as the first argument: `new Dendri("my-peer-id", { ... })`.
27
28
 
28
29
  Local development usually looks like:
29
30
 
30
31
  ```ts
31
- const peer = new Dendri({
32
- host: "localhost",
33
- port: 9876,
34
- secure: false,
35
- path: "/",
36
- });
32
+ const peer = new Dendri({ url: "ws://localhost:9876" });
37
33
  ```
38
34
 
39
35
  ## Quick Start
@@ -65,12 +61,7 @@ Use `createDendriStore()` when integrating with UI frameworks:
65
61
  ```ts
66
62
  import { createDendriStore } from "@afterrealism/dendri-client";
67
63
 
68
- const store = createDendriStore({
69
- host: "signal.example.com",
70
- port: 443,
71
- secure: true,
72
- path: "/",
73
- });
64
+ const store = createDendriStore({ url: "wss://signal.example.com" });
74
65
 
75
66
  const unsubscribe = store.subscribe(() => {
76
67
  console.log(store.connectionState, store.peers);
@@ -79,7 +70,33 @@ const unsubscribe = store.subscribe(() => {
79
70
  store.join("my-room");
80
71
  ```
81
72
 
82
- React can wrap `store.subscribe` and `store.getSnapshot()` with `useSyncExternalStore`. Vue can mirror snapshots into `shallowRef`. Svelte can create the store in `onMount` or a `.svelte.ts` factory and call `destroy()` during cleanup.
73
+ ## Framework Adapters
74
+
75
+ Ready-made bindings ship as subpath exports (`react` and `vue` are optional peer
76
+ dependencies; the Svelte adapter is dependency-free):
77
+
78
+ ```tsx
79
+ // React — re-renders on store changes (useSyncExternalStore under the hood)
80
+ import { useDendriStore } from "@afterrealism/dendri-client/react";
81
+ const { connectionState, peers } = useDendriStore(store);
82
+ ```
83
+
84
+ ```ts
85
+ // Vue — shallowRef that tracks the store, auto-unsubscribes with the component
86
+ import { useDendriStore } from "@afterrealism/dendri-client/vue";
87
+ const snapshot = useDendriStore(store); // snapshot.value.connectionState
88
+ ```
89
+
90
+ ```svelte
91
+ <!-- Svelte — standard store contract, works with $ auto-subscription (Svelte 4 + 5) -->
92
+ <script>
93
+ import { toSvelteStore } from "@afterrealism/dendri-client/svelte";
94
+ const snapshot = toSvelteStore(store);
95
+ </script>
96
+ {$snapshot.connectionState}
97
+ ```
98
+
99
+ Any other framework can wrap `store.subscribe` and `store.getSnapshot()` the same way.
83
100
 
84
101
  ## Features
85
102
 
@@ -0,0 +1,33 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
30
+
31
+ export { __commonJS, __export, __toESM };
32
+ //# sourceMappingURL=chunk-G3PMV62Z.js.map
33
+ //# sourceMappingURL=chunk-G3PMV62Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-G3PMV62Z.js"}
@@ -1,32 +1,4 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __commonJS = (cb, mod) => function __require() {
8
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
- };
10
- var __export = (target, all) => {
11
- for (var name in all)
12
- __defProp(target, name, { get: all[name], enumerable: true });
13
- };
14
- var __copyProps = (to, from, except, desc) => {
15
- if (from && typeof from === "object" || typeof from === "function") {
16
- for (let key of __getOwnPropNames(from))
17
- if (!__hasOwnProp.call(to, key) && key !== except)
18
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
- }
20
- return to;
21
- };
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
- // If the importer is in node compatibility mode or this is not an ESM
24
- // file that has been converted to a CommonJS file using a Babel-
25
- // compatible transform (i.e. "__esModule" has not been set), then set
26
- // "default" to the CommonJS "module.exports" for node compatibility.
27
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
- mod
29
- ));
1
+ import { __commonJS, __export, __toESM } from './chunk-G3PMV62Z.js';
30
2
 
31
3
  // node_modules/.pnpm/sdp@3.2.2/node_modules/sdp/sdp.js
32
4
  var require_sdp = __commonJS({
@@ -3529,7 +3501,7 @@ var Util = class extends BinaryPackChunker {
3529
3501
  var util = new Util();
3530
3502
 
3531
3503
  // src/api.ts
3532
- var version = "2.4.0";
3504
+ var version = "2.6.0";
3533
3505
  var API = class _API {
3534
3506
  constructor(_options) {
3535
3507
  this._options = _options;
@@ -3542,6 +3514,7 @@ var API = class _API {
3542
3514
  const url = new URL(`${protocol}://${host}:${port}${path}${key}/${method}`);
3543
3515
  url.searchParams.set("ts", `${Date.now()}${Math.random()}`);
3544
3516
  url.searchParams.set("version", version);
3517
+ if (this._options.apiKey) url.searchParams.set("api_key", this._options.apiKey);
3545
3518
  const controller = new AbortController();
3546
3519
  const timeoutId = setTimeout(() => controller.abort(), _API.FETCH_TIMEOUT);
3547
3520
  return fetch(url.href, {
@@ -3570,11 +3543,12 @@ var API = class _API {
3570
3543
  async getTurnCredentials() {
3571
3544
  const protocol = this._options.secure ? "https" : "http";
3572
3545
  const { host, port, path, key } = this._options;
3573
- const url = `${protocol}://${host}:${port}${path}${key}/turn-credentials`;
3546
+ const url = new URL(`${protocol}://${host}:${port}${path}${key}/turn-credentials`);
3547
+ if (this._options.apiKey) url.searchParams.set("api_key", this._options.apiKey);
3574
3548
  try {
3575
3549
  const controller = new AbortController();
3576
3550
  const timeoutId = setTimeout(() => controller.abort(), _API.FETCH_TIMEOUT);
3577
- const response = await fetch(url, {
3551
+ const response = await fetch(url.href, {
3578
3552
  referrerPolicy: this._options.referrerPolicy,
3579
3553
  signal: controller.signal
3580
3554
  }).finally(() => clearTimeout(timeoutId));
@@ -5401,17 +5375,29 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
5401
5375
  _heartbeatTimer;
5402
5376
  _lastSeq = 0;
5403
5377
  _baseUrl;
5378
+ _key;
5379
+ _jwt;
5380
+ _apiKey;
5404
5381
  _pingInterval;
5405
5382
  _abortController;
5406
5383
  /** Backoff schedule base delays in milliseconds. */
5407
5384
  static BACKOFF_SCHEDULE = [0, 1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
5408
5385
  /** Random jitter range in milliseconds (applied as +/-). */
5409
5386
  static BACKOFF_JITTER = 500;
5410
- constructor(secure, host, port, path, _key, pingInterval = 5e3, _jwt) {
5387
+ constructor(secure, host, port, path, key, pingInterval = 5e3, jwt, apiKey) {
5411
5388
  super();
5412
5389
  const protocol = secure ? "https://" : "http://";
5413
5390
  this._baseUrl = `${protocol + host}:${port}${path}`;
5414
5391
  this._pingInterval = pingInterval;
5392
+ this._key = key;
5393
+ this._jwt = jwt;
5394
+ this._apiKey = apiKey;
5395
+ }
5396
+ /** Append the shared auth params (key, jwt, api_key) so every HTTP call authenticates like the WS transport. */
5397
+ _applyAuthParams(params) {
5398
+ params.set("key", this._key);
5399
+ if (this._jwt) params.set("jwt", this._jwt);
5400
+ if (this._apiKey) params.set("api_key", this._apiKey);
5415
5401
  }
5416
5402
  get reconnectAttempt() {
5417
5403
  return this._reconnectAttempt;
@@ -5439,6 +5425,7 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
5439
5425
  id: this._id,
5440
5426
  token: this._token
5441
5427
  });
5428
+ this._applyAuthParams(params);
5442
5429
  if (this._lastSeq > 0) params.set("last_seq", String(this._lastSeq));
5443
5430
  const response = await fetch(`${this._baseUrl}http/poll?${params}`, {
5444
5431
  signal: this._abortController.signal
@@ -5477,6 +5464,7 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
5477
5464
  id: this._id,
5478
5465
  token: this._token
5479
5466
  });
5467
+ this._applyAuthParams(params);
5480
5468
  try {
5481
5469
  await fetch(`${this._baseUrl}http/send?${params}`, {
5482
5470
  method: "POST",
@@ -5541,13 +5529,16 @@ var PollingTransport = class _PollingTransport extends SignalingTransport {
5541
5529
  };
5542
5530
 
5543
5531
  // src/socket.ts
5544
- var version2 = "2.4.0";
5532
+ var version2 = "2.6.0";
5545
5533
  var Socket = class _Socket extends SignalingTransport {
5546
- constructor(secure, host, port, path, key, pingInterval = 5e3, jwt) {
5534
+ constructor(secure, host, port, path, key, pingInterval = 5e3, jwt, apiKey) {
5547
5535
  super();
5548
5536
  this.pingInterval = pingInterval;
5549
5537
  const wsProtocol = secure ? "wss://" : "ws://";
5550
5538
  this._baseUrl = `${wsProtocol + host}:${port}${path}dendri?key=${key}`;
5539
+ if (apiKey) {
5540
+ this._baseUrl += `&api_key=${encodeURIComponent(apiKey)}`;
5541
+ }
5551
5542
  this._jwt = jwt;
5552
5543
  }
5553
5544
  pingInterval;
@@ -5853,18 +5844,28 @@ var SSETransport = class _SSETransport extends SignalingTransport {
5853
5844
  _heartbeatTimer;
5854
5845
  _lastSeq = 0;
5855
5846
  _baseUrl;
5847
+ _key;
5856
5848
  _jwt;
5849
+ _apiKey;
5857
5850
  _pingInterval;
5858
5851
  /** Backoff schedule base delays in milliseconds. */
5859
5852
  static BACKOFF_SCHEDULE = [0, 1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
5860
5853
  /** Random jitter range in milliseconds (applied as +/-). */
5861
5854
  static BACKOFF_JITTER = 500;
5862
- constructor(secure, host, port, path, _key, pingInterval = 5e3, jwt) {
5855
+ constructor(secure, host, port, path, key, pingInterval = 5e3, jwt, apiKey) {
5863
5856
  super();
5864
5857
  const protocol = secure ? "https://" : "http://";
5865
5858
  this._baseUrl = `${protocol + host}:${port}${path}`;
5866
5859
  this._pingInterval = pingInterval;
5860
+ this._key = key;
5867
5861
  this._jwt = jwt;
5862
+ this._apiKey = apiKey;
5863
+ }
5864
+ /** Append the shared auth params (key, jwt, api_key) so every HTTP call authenticates like the WS transport. */
5865
+ _applyAuthParams(params) {
5866
+ params.set("key", this._key);
5867
+ if (this._jwt) params.set("jwt", this._jwt);
5868
+ if (this._apiKey) params.set("api_key", this._apiKey);
5868
5869
  }
5869
5870
  get reconnectAttempt() {
5870
5871
  return this._reconnectAttempt;
@@ -5882,10 +5883,9 @@ var SSETransport = class _SSETransport extends SignalingTransport {
5882
5883
  if (this._disconnected) return;
5883
5884
  const params = new URLSearchParams({
5884
5885
  id: this._id,
5885
- token: this._token,
5886
- key: "dendri"
5886
+ token: this._token
5887
5887
  });
5888
- if (this._jwt) params.set("jwt", this._jwt);
5888
+ this._applyAuthParams(params);
5889
5889
  if (this._lastSeq > 0) params.set("last_seq", String(this._lastSeq));
5890
5890
  const url = `${this._baseUrl}http/sse?${params}`;
5891
5891
  try {
@@ -5959,6 +5959,7 @@ var SSETransport = class _SSETransport extends SignalingTransport {
5959
5959
  id: this._id,
5960
5960
  token: this._token
5961
5961
  });
5962
+ this._applyAuthParams(params);
5962
5963
  try {
5963
5964
  await fetch(`${this._baseUrl}http/send?${params}`, {
5964
5965
  method: "POST",
@@ -6031,6 +6032,28 @@ var SSETransport = class _SSETransport extends SignalingTransport {
6031
6032
  };
6032
6033
 
6033
6034
  // src/dendri.ts
6035
+ function parseServerUrl(url) {
6036
+ let parsed;
6037
+ try {
6038
+ parsed = new URL(url);
6039
+ } catch {
6040
+ throw new Error(
6041
+ `Invalid Dendri "url" option: "${url}". Expected a full URL like "wss://signal.example.com".`
6042
+ );
6043
+ }
6044
+ const secure = parsed.protocol === "wss:" || parsed.protocol === "https:";
6045
+ if (!secure && parsed.protocol !== "ws:" && parsed.protocol !== "http:") {
6046
+ throw new Error(
6047
+ `Invalid Dendri "url" protocol: "${parsed.protocol}". Use wss://, ws://, https://, or http://.`
6048
+ );
6049
+ }
6050
+ return {
6051
+ host: parsed.hostname,
6052
+ port: parsed.port ? Number(parsed.port) : secure ? 443 : 80,
6053
+ secure,
6054
+ path: parsed.pathname || "/"
6055
+ };
6056
+ }
6034
6057
  var Dendri = class _Dendri extends EventEmitterWithError {
6035
6058
  static DEFAULT_KEY = "dendri";
6036
6059
  _serializers = {
@@ -6121,6 +6144,9 @@ var Dendri = class _Dendri extends EventEmitterWithError {
6121
6144
  } else if (id) {
6122
6145
  userId = id.toString();
6123
6146
  }
6147
+ if (providedOptions?.url) {
6148
+ providedOptions = { ...parseServerUrl(providedOptions.url), ...providedOptions };
6149
+ }
6124
6150
  const normalizedOptions = {
6125
6151
  debug: 0,
6126
6152
  // 1: Errors, 2: Warnings, 3: All logs
@@ -6239,7 +6265,8 @@ var Dendri = class _Dendri extends EventEmitterWithError {
6239
6265
  this._options.path,
6240
6266
  this._options.key,
6241
6267
  this._options.pingInterval,
6242
- this._options.jwt
6268
+ this._options.jwt,
6269
+ this._options.apiKey
6243
6270
  ) : transport === "polling" ? new PollingTransport(
6244
6271
  this._options.secure ?? false,
6245
6272
  this._options.host,
@@ -6247,7 +6274,8 @@ var Dendri = class _Dendri extends EventEmitterWithError {
6247
6274
  this._options.path,
6248
6275
  this._options.key,
6249
6276
  this._options.pingInterval,
6250
- this._options.jwt
6277
+ this._options.jwt,
6278
+ this._options.apiKey
6251
6279
  ) : new Socket(
6252
6280
  this._options.secure ?? false,
6253
6281
  this._options.host,
@@ -6255,7 +6283,8 @@ var Dendri = class _Dendri extends EventEmitterWithError {
6255
6283
  this._options.path,
6256
6284
  this._options.key,
6257
6285
  this._options.pingInterval,
6258
- this._options.jwt
6286
+ this._options.jwt,
6287
+ this._options.apiKey
6259
6288
  );
6260
6289
  socket.on("message" /* Message */, (data) => {
6261
6290
  this._handleMessage(data);
@@ -7967,5 +7996,5 @@ function createDendriStore(input) {
7967
7996
  }
7968
7997
 
7969
7998
  export { AckManager, BaseConnectionErrorType, BufferedConnection, ConnectionQuality, ConnectionState, ConnectionType, DataConnection, DataConnectionErrorType, Dendri, DendriError, DendriErrorType, HybridConnection, PollingTransport, PresenceManager, RelayEncryption, Room, RpcError, RpcErrorCode, RpcManager, SSETransport, SerializationType, ServerMessageType, SignalingTransport, SocketEventType, TopicClass, TopicManager, TransportMode, createDendriStore, electNewHost, isRpcRequest, isRpcResponse, isTopicEnvelope, logger_default, util };
7970
- //# sourceMappingURL=chunk-MBMSG4EC.js.map
7971
- //# sourceMappingURL=chunk-MBMSG4EC.js.map
7999
+ //# sourceMappingURL=chunk-YLWDCKUW.js.map
8000
+ //# sourceMappingURL=chunk-YLWDCKUW.js.map