@palbase/web 2.0.1 → 4.0.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 (47) hide show
  1. package/README.md +11 -9
  2. package/dist/{analytics-facade-ChlBRcLZ.d.cts → analytics-facade-DwOtlXPP.d.cts} +13 -103
  3. package/dist/{analytics-facade-G0il4NrT.d.ts → analytics-facade-Nk6J9Ncm.d.ts} +13 -103
  4. package/dist/{chunk-VJXFABBW.js → chunk-6VGKMNXO.js} +11 -11
  5. package/dist/chunk-6VGKMNXO.js.map +1 -0
  6. package/dist/{chunk-AIPUO4QX.js → chunk-NP4NIY7A.js} +52 -48
  7. package/dist/chunk-NP4NIY7A.js.map +1 -0
  8. package/dist/chunk-S7NAY3MW.js +24 -0
  9. package/dist/chunk-S7NAY3MW.js.map +1 -0
  10. package/dist/gen/cli.cjs +32 -6
  11. package/dist/gen/cli.cjs.map +1 -1
  12. package/dist/gen/cli.js +28 -7
  13. package/dist/gen/cli.js.map +1 -1
  14. package/dist/index.cjs +25 -22
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +3 -4
  17. package/dist/index.d.ts +3 -4
  18. package/dist/index.js +2 -2
  19. package/dist/internal.cjs +55 -44
  20. package/dist/internal.cjs.map +1 -1
  21. package/dist/internal.d.cts +4 -16
  22. package/dist/internal.d.ts +4 -16
  23. package/dist/internal.js +2 -2
  24. package/dist/next/client.cjs +72 -58
  25. package/dist/next/client.cjs.map +1 -1
  26. package/dist/next/client.d.cts +1 -1
  27. package/dist/next/client.d.ts +1 -1
  28. package/dist/next/client.js +12 -10
  29. package/dist/next/client.js.map +1 -1
  30. package/dist/next/index.cjs +75 -59
  31. package/dist/next/index.cjs.map +1 -1
  32. package/dist/next/index.d.cts +10 -11
  33. package/dist/next/index.d.ts +10 -11
  34. package/dist/next/index.js +14 -13
  35. package/dist/next/index.js.map +1 -1
  36. package/dist/{pb-B_6o5p79.d.cts → pb-C9v5dEO6.d.cts} +1 -1
  37. package/dist/{pb-nPBhqhJr.d.ts → pb-FG_nV7NR.d.ts} +1 -1
  38. package/dist/react/index.cjs +1 -1
  39. package/dist/react/index.cjs.map +1 -1
  40. package/dist/react/index.d.cts +1 -2
  41. package/dist/react/index.d.ts +1 -2
  42. package/dist/react/index.js +2 -2
  43. package/package.json +3 -3
  44. package/dist/chunk-AIPUO4QX.js.map +0 -1
  45. package/dist/chunk-PZ5AY32C.js +0 -10
  46. package/dist/chunk-PZ5AY32C.js.map +0 -1
  47. package/dist/chunk-VJXFABBW.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  import {
2
- __export
3
- } from "./chunk-PZ5AY32C.js";
2
+ __export,
3
+ environmentRefFromPublishableApiKey
4
+ } from "./chunk-S7NAY3MW.js";
4
5
 
5
6
  // ../core/dist/index.js
6
7
  var CACHE_TTL_MS = 5 * 60 * 1e3;
@@ -17,18 +18,9 @@ var PalbaseError = class extends Error {
17
18
  }
18
19
  };
19
20
  var PALBASE_DEFAULT_HOST = "api.palbase.studio";
20
- var REF_LEN = 8;
21
- var BASE62_RE = /^[0-9A-Za-z]+$/;
22
- function parseProjectRef(apiKey) {
23
- if (apiKey.length < 13) return null;
24
- if (!apiKey.startsWith("pb_")) return null;
25
- if (apiKey[11] !== "_") return null;
26
- const ref = apiKey.slice(3, 11);
27
- if (ref.length !== REF_LEN) return null;
28
- if (!BASE62_RE.test(ref)) return null;
29
- const scope = apiKey[12];
30
- if (scope !== "c") return null;
31
- return ref;
21
+ var API_KEY_RE = /^pb_([a-z0-9]+)_c[A-Za-z0-9]{20}$/;
22
+ function parseEnvironmentRef(apiKey) {
23
+ return API_KEY_RE.exec(apiKey)?.[1] ?? null;
32
24
  }
33
25
  var MAX_RETRIES = 3;
34
26
  var INITIAL_BACKOFF_MS = 200;
@@ -58,8 +50,7 @@ var HttpClient = class _HttpClient {
58
50
  * with the parent at runtime — later changes on the parent propagate to
59
51
  * the scope and vice versa.
60
52
  *
61
- * Typical use: tagging admin calls with `x-palbase-project: <ref>` so the
62
- * gateway can route them to the correct project's data plane.
53
+ * Typical use: adding an Environment-routing header for an admin call.
63
54
  */
64
55
  withHeaders(extra) {
65
56
  const mergedHeaders = { ...this.options?.headers ?? {}, ...extra };
@@ -100,10 +91,10 @@ var HttpClient = class _HttpClient {
100
91
  if (this.options?.url) {
101
92
  return this.options.url;
102
93
  }
103
- if (this.apiKey && parseProjectRef(this.apiKey) === null) {
94
+ if (this.apiKey && parseEnvironmentRef(this.apiKey) === null) {
104
95
  throw new PalbaseError(
105
96
  "invalid_api_key",
106
- 'Invalid API key format. Expected pb_{ref}_{scope}{random}. For dev/staging pass `url: "https://api.dev.palbase.studio"` via options.',
97
+ 'Invalid API key format. Expected pb_{environment_ref}_c{20_base62_chars}. For dev/staging pass `url: "https://api.dev.palbase.studio"` via options.',
107
98
  0
108
99
  );
109
100
  }
@@ -116,10 +107,6 @@ var HttpClient = class _HttpClient {
116
107
  const effectiveKey = this.apiKey;
117
108
  if (effectiveKey) {
118
109
  headers["apikey"] = effectiveKey;
119
- const ref = parseProjectRef(effectiveKey);
120
- if (ref) {
121
- headers["X-Project-Ref"] = ref;
122
- }
123
110
  }
124
111
  const token = this.tokenManager?.getAccessToken();
125
112
  if (token) {
@@ -1125,13 +1112,6 @@ var AuthClient = class {
1125
1112
  }
1126
1113
  };
1127
1114
 
1128
- // src/api-key.ts
1129
- var API_KEY_RE = /^pb_([^_]+)_[cs][A-Za-z0-9]{20}$/;
1130
- function endpointRefFromApiKey(apiKey) {
1131
- const m = API_KEY_RE.exec(apiKey);
1132
- return m ? m[1] ?? "" : "";
1133
- }
1134
-
1135
1115
  // src/analytics-facade.ts
1136
1116
  var EVENT_NAME_RE = /^[a-zA-Z$][a-zA-Z0-9_.:$-]{0,63}$/;
1137
1117
  var FLUSH_AT = 20;
@@ -1189,7 +1169,7 @@ var AnalyticsState = class {
1189
1169
  idKey;
1190
1170
  optOutKey;
1191
1171
  constructor(rt) {
1192
- const ref = endpointRefFromApiKey(rt.config.apiKey);
1172
+ const ref = rt.config.environmentRef;
1193
1173
  this.idKey = ref ? `palbe.analytics.id.${ref}` : "palbe.analytics.id";
1194
1174
  this.optOutKey = ref ? `palbe.analytics.optout.${ref}` : "palbe.analytics.optout";
1195
1175
  rt.auth.onAuthEvent((event) => {
@@ -1755,19 +1735,29 @@ import {
1755
1735
  RoomEvent,
1756
1736
  Track
1757
1737
  } from "livekit-client";
1758
- var Call = class {
1738
+ var Call = class _Call {
1759
1739
  id;
1760
1740
  _state = "connecting";
1761
1741
  _participants = /* @__PURE__ */ new Map();
1762
1742
  _listeners = /* @__PURE__ */ new Set();
1763
1743
  _room;
1764
1744
  _keyProvider;
1765
- /** @internal obtain via PalbeCalls.start() / .accept() */
1745
+ // PRIVATE constructor + `@internal` factory: the media-engine types (`Room`,
1746
+ // `ExternalE2EEKeyProvider`) appear ONLY on a private constructor and an
1747
+ // `@internal` static factory, both of which `stripInternal` (set in this
1748
+ // package's tsconfig) removes from the emitted public `.d.ts`. So no engine type
1749
+ // ever reaches the public API surface — the same "no engine type in the public
1750
+ // interface" contract the iOS SDK enforces. Consumers obtain a `Call` only
1751
+ // through `pb.calls.start()` / `.accept()`.
1766
1752
  constructor(callId, room, keyProvider) {
1767
1753
  this.id = callId;
1768
1754
  this._room = room;
1769
1755
  this._keyProvider = keyProvider;
1770
- this._wireRoomEvents();
1756
+ this._wireMediaEvents();
1757
+ }
1758
+ /** @internal — facade-only factory; stripped from the public `.d.ts`. */
1759
+ static _create(callId, room, keyProvider) {
1760
+ return new _Call(callId, room, keyProvider);
1771
1761
  }
1772
1762
  // ─── State ──────────────────────────────────────────────────────────────
1773
1763
  get state() {
@@ -1777,9 +1767,9 @@ var Call = class {
1777
1767
  get participants() {
1778
1768
  return Array.from(this._participants.values());
1779
1769
  }
1780
- get localParticipant() {
1781
- return this._room.localParticipant;
1782
- }
1770
+ // (No `localParticipant` accessor: it would return a raw media-engine participant
1771
+ // object and leak the engine type onto the public API. Local mic/camera control is
1772
+ // exposed engine-agnostically via `mute()` / `setCamera()` below.)
1783
1773
  // ─── Subscribe ──────────────────────────────────────────────────────────
1784
1774
  /**
1785
1775
  * Subscribe to call changes (state + participant updates).
@@ -1803,7 +1793,7 @@ var Call = class {
1803
1793
  /**
1804
1794
  * Set a raw frame encryption key (ArrayBuffer) for this call.
1805
1795
  * Design seam for SP-1.x web-MLS: call this with the MLS exporter secret
1806
- * to enable frame-level E2EE via ExternalE2EEKeyProvider.
1796
+ * to enable frame-level E2EE via the media engine's external key provider.
1807
1797
  *
1808
1798
  * NOTE: The room must have been opened with `e2ee` options for this to take
1809
1799
  * effect. Currently calls connect WITHOUT e2ee — see module docstring.
@@ -1813,7 +1803,7 @@ var Call = class {
1813
1803
  async setMediaKey(key) {
1814
1804
  await this._keyProvider.setKey(key);
1815
1805
  }
1816
- /** Leave the call and disconnect from the LiveKit room. */
1806
+ /** Leave the call and disconnect from the media room. */
1817
1807
  async leave() {
1818
1808
  await this._room.disconnect();
1819
1809
  this._setState("ended");
@@ -1855,7 +1845,7 @@ var Call = class {
1855
1845
  }
1856
1846
  this._emit();
1857
1847
  }
1858
- _wireRoomEvents() {
1848
+ _wireMediaEvents() {
1859
1849
  this._room.on(RoomEvent.Connected, () => {
1860
1850
  this._setState("active");
1861
1851
  }).on(
@@ -1896,9 +1886,9 @@ var PalbeCalls = class {
1896
1886
  *
1897
1887
  * @param groupId - Messaging group display-id (`grp_<uuidv7>`)
1898
1888
  * @param media - Which media tracks to publish (default: audio + video)
1899
- * @returns A `Call` in `connecting` state; transitions to `active` once LiveKit connects.
1889
+ * @returns A `Call` in `connecting` state; transitions to `active` once the media room connects.
1900
1890
  *
1901
- * @throws BackendError('network', { code: 'call_service_unavailable' }) if LiveKit SFU is down (503)
1891
+ * @throws BackendError('network', { code: 'call_service_unavailable' }) if the SFU is down (503)
1902
1892
  * @throws BackendError('forbidden', { code: 'not_group_member' }) if the caller is not a member (403)
1903
1893
  * @throws BackendError('conflict', { code: 'call_room_full' }) if the room is full (409)
1904
1894
  */
@@ -1955,7 +1945,7 @@ var PalbeCalls = class {
1955
1945
  adaptiveStream: true,
1956
1946
  dynacast: true
1957
1947
  });
1958
- const call = new Call(callId, room, keyProvider);
1948
+ const call = Call._create(callId, room, keyProvider);
1959
1949
  await room.connect(edgeUrl, token);
1960
1950
  if (media.includes("audio")) {
1961
1951
  await room.localParticipant.setMicrophoneEnabled(true);
@@ -2548,7 +2538,7 @@ var PalbeFlags = class {
2548
2538
  constructor(rt) {
2549
2539
  this.transport = new FlagsClient(rt.http);
2550
2540
  const browser = typeof document !== "undefined";
2551
- const ref = endpointRefFromApiKey(rt.config.apiKey);
2541
+ const ref = rt.config.environmentRef;
2552
2542
  const options = {
2553
2543
  auth: palbeAuthAdapter(rt.auth),
2554
2544
  ...ref ? { storageKey: `palbe.flags.${ref}` } : {},
@@ -8287,7 +8277,7 @@ var AnonTokenProvider = class {
8287
8277
  }
8288
8278
  /**
8289
8279
  * Raw fetch, deliberately NOT through HttpClient/palbeRequest: the mint
8290
- * must carry the project apikey and NEVER a Bearer (iOS keeps
8280
+ * must carry the Environment API key and NEVER a Bearer (iOS keeps
8291
8281
  * `/auth/anonymous` on the unauthenticated-path list), and HttpClient's
8292
8282
  * pre-flight would try to refresh a stale session before an anon mint —
8293
8283
  * exactly the entanglement this provider exists to avoid.
@@ -8944,10 +8934,25 @@ function defaultSessionStorage(key) {
8944
8934
  }
8945
8935
 
8946
8936
  // src/version.ts
8947
- var VERSION = "2.0.1";
8937
+ var VERSION = "4.0.0";
8948
8938
 
8949
8939
  // src/runtime.ts
8950
8940
  function buildRuntime(config) {
8941
+ const keyEnvironmentRef = environmentRefFromPublishableApiKey(config.apiKey);
8942
+ if (keyEnvironmentRef === "") {
8943
+ throw new Error("PalbeConfig.apiKey does not contain a valid publishable Environment identity");
8944
+ } else if (config.environmentRef !== keyEnvironmentRef) {
8945
+ throw new Error("PalbeConfig.environmentRef must match the Environment identity in apiKey");
8946
+ }
8947
+ let runtimeURL;
8948
+ try {
8949
+ runtimeURL = new URL(config.url);
8950
+ } catch {
8951
+ throw new Error("PalbeConfig.url must be a valid URL");
8952
+ }
8953
+ if (runtimeURL.hostname.endsWith(".palbase.studio") && runtimeURL.hostname.split(".")[0] !== config.environmentRef) {
8954
+ throw new Error("PalbeConfig.url must match environmentRef for palbase.studio");
8955
+ }
8951
8956
  const http = new HttpClient(config.apiKey, {
8952
8957
  url: config.url,
8953
8958
  headers: { "X-Client-Info": `palbe-web/${VERSION}`, ...config.headers }
@@ -8956,7 +8961,7 @@ function buildRuntime(config) {
8956
8961
  const tokenManager = new TokenManager();
8957
8962
  http.tokenManager = tokenManager;
8958
8963
  const authClient = new AuthClient(http, tokenManager);
8959
- const ref = endpointRefFromApiKey(config.apiKey);
8964
+ const ref = config.environmentRef;
8960
8965
  const storage = config.storage ?? defaultSessionStorage(ref ? `palbe.session.${ref}` : void 0);
8961
8966
  const persisted = storage.load();
8962
8967
  if (persisted) {
@@ -9333,7 +9338,6 @@ function __reset() {
9333
9338
  }
9334
9339
 
9335
9340
  export {
9336
- endpointRefFromApiKey,
9337
9341
  BackendError,
9338
9342
  isBackendError,
9339
9343
  PalbeAnalytics,
@@ -9357,4 +9361,4 @@ export {
9357
9361
  pb,
9358
9362
  createBoundClient
9359
9363
  };
9360
- //# sourceMappingURL=chunk-AIPUO4QX.js.map
9364
+ //# sourceMappingURL=chunk-NP4NIY7A.js.map