lazypock 0.8.3 → 0.9.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.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  fieldTypeScriptType,
5
5
  generateTypes,
6
6
  schemaFieldType
7
- } from "./chunk-V2XSEOWF.js";
7
+ } from "./chunk-CGQVJ7TT.js";
8
8
 
9
9
  // src/types.ts
10
10
  var ApiError = class extends Error {
@@ -781,25 +781,24 @@ var CollectionService = class _CollectionService {
781
781
  derived.fieldsPreset = this.fieldsPreset;
782
782
  return derived;
783
783
  }
784
- // ── Realtime Subscriptions (PocketBase-style) ──
785
- /**
786
- * Subscribe to realtime changes for this collection.
787
- * The event's `action` is one of `"create" | "update" | "delete"`.
788
- *
789
- * Access is governed by the collection's `listRule` (PocketBase semantics):
790
- * public collections allow anonymous subscriptions; other collections
791
- * require a matching logged-in user or superuser.
792
- *
793
- * @param callback Received on every record change.
794
- * @param recordId Optional — subscribe to a single record instead of `*`.
795
- * @returns A function that unsubscribes this callback.
796
- */
797
- subscribe(callback, recordId) {
784
+ subscribe(topicOrCallback, maybeCallback, options) {
798
785
  if (!this.realtime) {
799
786
  console.warn("[lazypock] No realtime service configured.");
800
787
  return () => {
801
788
  };
802
789
  }
790
+ let recordId;
791
+ let callback;
792
+ let joinPayload;
793
+ if (typeof topicOrCallback === "function") {
794
+ callback = topicOrCallback;
795
+ if (typeof maybeCallback === "string") recordId = maybeCallback;
796
+ } else {
797
+ callback = maybeCallback;
798
+ recordId = topicOrCallback === "*" ? void 0 : topicOrCallback;
799
+ const { headers: _ignored, ...rest } = options ?? {};
800
+ if (Object.keys(rest).length > 0) joinPayload = rest;
801
+ }
803
802
  const topic = "collection:" + this.collectionName + (recordId ? ":" + recordId : "");
804
803
  const handler = (raw) => {
805
804
  const record = raw.payload?.["record"] ?? {};
@@ -810,15 +809,23 @@ var CollectionService = class _CollectionService {
810
809
  });
811
810
  };
812
811
  this.realtime.ensureConnected();
813
- this.realtime.subscribe(topic, handler);
812
+ this.realtime.subscribe(topic, handler, joinPayload);
814
813
  return () => this.realtime?.unsubscribe(topic, handler);
815
814
  }
816
815
  /**
817
- * Unsubscribe all callbacks from this collection (or a specific record).
818
- * @param recordId Optional record id; omitting it unsubs everything.
816
+ * Unsubscribe from realtime changes (PocketBase-compatible):
817
+ * - `unsubscribe()` — remove **all** subscriptions of this collection
818
+ * - `unsubscribe('*')` — remove wildcard subscriptions
819
+ * - `unsubscribe('RECORD_ID')` — remove that record's subscriptions
819
820
  */
820
821
  unsubscribe(recordId) {
821
- const topic = "collection:" + this.collectionName + (recordId ? ":" + recordId : "");
822
+ if (recordId === void 0) {
823
+ this.realtime?.unsubscribeByPrefix(
824
+ "collection:" + this.collectionName
825
+ );
826
+ return;
827
+ }
828
+ const topic = "collection:" + this.collectionName + (recordId === "*" ? "" : ":" + recordId);
822
829
  this.realtime?.unsubscribe(topic);
823
830
  }
824
831
  // ── Auth Collection Methods ──
@@ -885,6 +892,7 @@ var RealtimeService = class {
885
892
  this.reconnectAttempt = 0;
886
893
  this.maxReconnectDelay = 5e3;
887
894
  this.url = "";
895
+ this.tokenProvider = null;
888
896
  // ── Heartbeat ──
889
897
  this.heartbeatInterval = null;
890
898
  }
@@ -910,6 +918,32 @@ var RealtimeService = class {
910
918
  setUrl(url) {
911
919
  this.url = url;
912
920
  }
921
+ /**
922
+ * Register a token provider consulted at every (re)connect.
923
+ * When set, it takes precedence over the token passed to {@link connect}.
924
+ */
925
+ setTokenProvider(provider) {
926
+ this.tokenProvider = provider;
927
+ }
928
+ /**
929
+ * Reconnect the socket immediately with the current token.
930
+ * Called by the SDK when auth changes (login/logout/token refresh) so
931
+ * private-channel joins are authorized with the new credentials. No-op
932
+ * when the socket has never been opened and nothing is subscribed.
933
+ */
934
+ refresh() {
935
+ if (typeof WebSocket === "undefined") return;
936
+ if (!this.ws && this.subscriptions.size === 0) return;
937
+ this.clearReconnectTimer();
938
+ const ws = this.ws;
939
+ this.ws = null;
940
+ if (ws) {
941
+ ws.onclose = null;
942
+ ws.close();
943
+ }
944
+ this.reconnectAttempt = 0;
945
+ this.doConnect();
946
+ }
913
947
  /*
914
948
  * Ensure the socket is connected, then subscribe.
915
949
  * Used by collection-level convenience wrappers so a connection is opened
@@ -933,15 +967,30 @@ var RealtimeService = class {
933
967
  this.ws = null;
934
968
  }
935
969
  /**
936
- * Subscribe to a topic (e.g. "collection:posts" or "collection:posts:*").
970
+ * Subscribe to a topic (e.g. "collection:posts" or "custom:chat-room").
937
971
  * The backend Channel authorizes via listRule on join.
972
+ *
973
+ * @param joinPayload Optional payload forwarded with the channel join
974
+ * (available to the server's join callback / hooks, e.g. `expand`).
938
975
  */
939
- subscribe(topic, callback) {
976
+ subscribe(topic, callback, joinPayload) {
940
977
  const subs = this.subscriptions.get(topic) || [];
941
- subs.push({ topic, callback });
978
+ subs.push({ topic, callback, joinPayload });
942
979
  this.subscriptions.set(topic, subs);
943
980
  if (this.ws?.readyState === WebSocket.OPEN) {
944
- this.joinTopic(topic);
981
+ this.joinTopic(topic, joinPayload);
982
+ }
983
+ }
984
+ /**
985
+ * Remove all subscriptions for topics under `prefix` (the topic itself or
986
+ * any topic starting with `prefix + ":"`). Used by collection-level
987
+ * `unsubscribe()` to drop every subscription of a collection.
988
+ */
989
+ unsubscribeByPrefix(prefix) {
990
+ for (const topic of [...this.subscriptions.keys()]) {
991
+ if (topic === prefix || topic.startsWith(prefix + ":")) {
992
+ this.subscriptions.delete(topic);
993
+ }
945
994
  }
946
995
  }
947
996
  /**
@@ -960,9 +1009,14 @@ var RealtimeService = class {
960
1009
  }
961
1010
  }
962
1011
  resubscribeAll() {
963
- for (const topic of this.subscriptions.keys()) {
964
- if (this.ws?.readyState === WebSocket.OPEN) {
965
- this.joinTopic(topic);
1012
+ const seen = /* @__PURE__ */ new Set();
1013
+ for (const entries of this.subscriptions.values()) {
1014
+ for (const entry of entries) {
1015
+ if (seen.has(entry.topic)) continue;
1016
+ seen.add(entry.topic);
1017
+ if (this.ws?.readyState === WebSocket.OPEN) {
1018
+ this.joinTopic(entry.topic, entry.joinPayload);
1019
+ }
966
1020
  }
967
1021
  }
968
1022
  }
@@ -974,8 +1028,9 @@ var RealtimeService = class {
974
1028
  return;
975
1029
  }
976
1030
  let url = this.url;
977
- if (this.token) {
978
- url += (url.includes("?") ? "&" : "?") + "token=" + encodeURIComponent(this.token);
1031
+ const token = this.tokenProvider ? this.tokenProvider() : this.token;
1032
+ if (token) {
1033
+ url += (url.includes("?") ? "&" : "?") + "token=" + encodeURIComponent(token);
979
1034
  }
980
1035
  this.ws = new WebSocket(url);
981
1036
  this.ws.onopen = () => {
@@ -1022,12 +1077,12 @@ var RealtimeService = class {
1022
1077
  }
1023
1078
  }
1024
1079
  }
1025
- joinTopic(topic) {
1080
+ joinTopic(topic, joinPayload) {
1026
1081
  const ref = this.nextRef();
1027
1082
  const msg = JSON.stringify({
1028
1083
  topic,
1029
1084
  event: "phx_join",
1030
- payload: {},
1085
+ payload: joinPayload ?? {},
1031
1086
  ref
1032
1087
  });
1033
1088
  this.ws?.send(msg);
@@ -1333,6 +1388,9 @@ var LazypockClient = class {
1333
1388
  if (!options.realtime) {
1334
1389
  this.realtime.setUrl(wsUrlFromBaseUrl(baseUrl));
1335
1390
  }
1391
+ this.realtime.setTokenProvider(() => this.authStore.token);
1392
+ this.authStore.onChange(() => this.realtime.refresh());
1393
+ this.authReady.then(() => this.realtime.refresh());
1336
1394
  this.files = new FilesService(this.http);
1337
1395
  this.collections = new CollectionsService(this.http, this.realtime);
1338
1396
  if (options.types?.schemas) {