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.d.cts CHANGED
@@ -340,6 +340,12 @@ type RealtimeConnectOpts = {
340
340
  /** Auth token to pass as query param */
341
341
  token?: string;
342
342
  };
343
+ /**
344
+ * Provides the current auth token at connect/reconnect time.
345
+ * Wired by {@link LazypockClient} from its `authStore` so the socket is
346
+ * always authenticated with the latest token (PocketBase parity).
347
+ */
348
+ type RealtimeTokenProvider = () => string | undefined;
343
349
  /**
344
350
  * Derive a WebSocket URL from an HTTP base URL.
345
351
  * http://localhost:4000/api → ws://localhost:4000/socket/websocket
@@ -370,6 +376,7 @@ declare class RealtimeService {
370
376
  onError?: (err: Event) => void;
371
377
  private url;
372
378
  private token;
379
+ private tokenProvider;
373
380
  /** Whether the WebSocket is currently open. */
374
381
  get isOpen(): boolean;
375
382
  /**
@@ -384,14 +391,35 @@ declare class RealtimeService {
384
391
  * auto-connect on the first {@link subscribe}.
385
392
  */
386
393
  setUrl(url: string): void;
394
+ /**
395
+ * Register a token provider consulted at every (re)connect.
396
+ * When set, it takes precedence over the token passed to {@link connect}.
397
+ */
398
+ setTokenProvider(provider: RealtimeTokenProvider): void;
399
+ /**
400
+ * Reconnect the socket immediately with the current token.
401
+ * Called by the SDK when auth changes (login/logout/token refresh) so
402
+ * private-channel joins are authorized with the new credentials. No-op
403
+ * when the socket has never been opened and nothing is subscribed.
404
+ */
405
+ refresh(): void;
387
406
  ensureConnected(): void;
388
407
  connect(opts: RealtimeConnectOpts): void;
389
408
  disconnect(): void;
390
409
  /**
391
- * Subscribe to a topic (e.g. "collection:posts" or "collection:posts:*").
410
+ * Subscribe to a topic (e.g. "collection:posts" or "custom:chat-room").
392
411
  * The backend Channel authorizes via listRule on join.
412
+ *
413
+ * @param joinPayload Optional payload forwarded with the channel join
414
+ * (available to the server's join callback / hooks, e.g. `expand`).
415
+ */
416
+ subscribe(topic: string, callback: (e: RealtimeEvent) => void, joinPayload?: Record<string, unknown>): void;
417
+ /**
418
+ * Remove all subscriptions for topics under `prefix` (the topic itself or
419
+ * any topic starting with `prefix + ":"`). Used by collection-level
420
+ * `unsubscribe()` to drop every subscription of a collection.
393
421
  */
394
- subscribe(topic: string, callback: (e: RealtimeEvent) => void): void;
422
+ unsubscribeByPrefix(prefix: string): void;
395
423
  /**
396
424
  * Unsubscribe a specific callback from a topic.
397
425
  */
@@ -452,6 +480,22 @@ interface RealtimeMessage {
452
480
  }
453
481
  /** Subscription callback for a collection's realtime events. */
454
482
  type RealtimeCallback = (e: RealtimeMessage) => void;
483
+ /**
484
+ * Options for {@link CollectionService.subscribe} (PocketBase-compatible).
485
+ *
486
+ * `expand` and any extra keys are forwarded to the server channel join
487
+ * payload (available to `onRealtimeSubscribeRequest` hooks). `headers` is
488
+ * accepted for PocketBase signature compatibility but has no effect over
489
+ * WebSocket — it is not forwarded.
490
+ */
491
+ interface RealtimeSubscribeOptions {
492
+ /** Fields to expand on the subscribed records (server join payload). */
493
+ expand?: string;
494
+ /** Accepted for PocketBase parity; not sent over the WebSocket. */
495
+ headers?: Record<string, string>;
496
+ /** Any extra keys are forwarded verbatim to the server join payload. */
497
+ [key: string]: unknown;
498
+ }
455
499
  /**
456
500
  * Typed CRUD service for a single dynamic collection.
457
501
  * Get an instance via {@link LazypockClient.collection}.
@@ -606,20 +650,33 @@ declare class CollectionService<T = ApiRecord, TData = never> {
606
650
  withSchema(schema: CollectionSchema): CollectionService<T, TData>;
607
651
  /**
608
652
  * Subscribe to realtime changes for this collection.
609
- * The event's `action` is one of `"create" | "update" | "delete"`.
653
+ * The event's `action` is one of `"create" | "update" | "delete"` and the
654
+ * callback always receives the **full record** (all fields, regardless of
655
+ * any `select()` projection on the service).
610
656
  *
611
657
  * Access is governed by the collection's `listRule` (PocketBase semantics):
612
658
  * public collections allow anonymous subscriptions; other collections
613
659
  * require a matching logged-in user or superuser.
614
660
  *
615
- * @param callback Received on every record change.
616
- * @param recordId Optional — subscribe to a single record instead of `*`.
661
+ * PocketBase-compatible argument forms:
662
+ * - `subscribe(cb)` — all records of the collection
663
+ * - `subscribe('*', cb)` — all records (explicit wildcard)
664
+ * - `subscribe('RECORD_ID', cb)` — a single record
665
+ * - `subscribe('*' | 'RECORD_ID', cb, options)` — with join options
666
+ *
667
+ * Legacy form (callback first) is still accepted: `subscribe(cb, recordId)`.
668
+ *
617
669
  * @returns A function that unsubscribes this callback.
618
670
  */
671
+ subscribe(callback: RealtimeCallback): () => void;
672
+ subscribe(recordId: string, callback: RealtimeCallback, options?: RealtimeSubscribeOptions): () => void;
673
+ /** @deprecated Use `subscribe(recordId, callback)` — PocketBase order. */
619
674
  subscribe(callback: RealtimeCallback, recordId?: string): () => void;
620
675
  /**
621
- * Unsubscribe all callbacks from this collection (or a specific record).
622
- * @param recordId Optional record id; omitting it unsubs everything.
676
+ * Unsubscribe from realtime changes (PocketBase-compatible):
677
+ * - `unsubscribe()` — remove **all** subscriptions of this collection
678
+ * - `unsubscribe('*')` — remove wildcard subscriptions
679
+ * - `unsubscribe('RECORD_ID')` — remove that record's subscriptions
623
680
  */
624
681
  unsubscribe(recordId?: string): void;
625
682
  /**
@@ -1039,4 +1096,4 @@ declare class TypedClient<TCollections extends LazypockCollections = LazypockCol
1039
1096
  */
1040
1097
  declare function createClient<TCollections extends LazypockCollections = LazypockCollections>(options: LazypockClientOptions): TypedClient<TCollections>;
1041
1098
 
1042
- export { ApiError, type ApiRecord, type AuthModel, AuthStore, type CollectionSchema, CollectionService, type CollectionsMessage, CollectionsService, type CreateData, type ExpandString, type FieldKey, type FileRecord, FilesService, type FilterOp, type FilterString, HttpClient, LazypockClient, type LazypockClientOptions, type LazypockCollections, type ListOptions, type ListResult, type ReadOptions, type RealtimeCallback, type RealtimeMessage, RealtimeService, type RecordShape, type RequestOptions, type SchemaField, type SortString, type StorageAdapter, type SystemFields, TypedClient, type UpdateData, collectionTypeName, createClient, fieldTypeKind, fieldTypeScriptType, generateTypes, getFileUrl, getScaleUrl, getThumbUrl, schemaFieldType, wsUrlFromBaseUrl };
1099
+ export { ApiError, type ApiRecord, type AuthModel, AuthStore, type CollectionSchema, CollectionService, type CollectionsMessage, CollectionsService, type CreateData, type ExpandString, type FieldKey, type FileRecord, FilesService, type FilterOp, type FilterString, HttpClient, LazypockClient, type LazypockClientOptions, type LazypockCollections, type ListOptions, type ListResult, type ReadOptions, type RealtimeCallback, type RealtimeMessage, RealtimeService, type RealtimeSubscribeOptions, type RecordShape, type RequestOptions, type SchemaField, type SortString, type StorageAdapter, type SystemFields, TypedClient, type UpdateData, collectionTypeName, createClient, fieldTypeKind, fieldTypeScriptType, generateTypes, getFileUrl, getScaleUrl, getThumbUrl, schemaFieldType, wsUrlFromBaseUrl };
package/dist/index.d.ts CHANGED
@@ -340,6 +340,12 @@ type RealtimeConnectOpts = {
340
340
  /** Auth token to pass as query param */
341
341
  token?: string;
342
342
  };
343
+ /**
344
+ * Provides the current auth token at connect/reconnect time.
345
+ * Wired by {@link LazypockClient} from its `authStore` so the socket is
346
+ * always authenticated with the latest token (PocketBase parity).
347
+ */
348
+ type RealtimeTokenProvider = () => string | undefined;
343
349
  /**
344
350
  * Derive a WebSocket URL from an HTTP base URL.
345
351
  * http://localhost:4000/api → ws://localhost:4000/socket/websocket
@@ -370,6 +376,7 @@ declare class RealtimeService {
370
376
  onError?: (err: Event) => void;
371
377
  private url;
372
378
  private token;
379
+ private tokenProvider;
373
380
  /** Whether the WebSocket is currently open. */
374
381
  get isOpen(): boolean;
375
382
  /**
@@ -384,14 +391,35 @@ declare class RealtimeService {
384
391
  * auto-connect on the first {@link subscribe}.
385
392
  */
386
393
  setUrl(url: string): void;
394
+ /**
395
+ * Register a token provider consulted at every (re)connect.
396
+ * When set, it takes precedence over the token passed to {@link connect}.
397
+ */
398
+ setTokenProvider(provider: RealtimeTokenProvider): void;
399
+ /**
400
+ * Reconnect the socket immediately with the current token.
401
+ * Called by the SDK when auth changes (login/logout/token refresh) so
402
+ * private-channel joins are authorized with the new credentials. No-op
403
+ * when the socket has never been opened and nothing is subscribed.
404
+ */
405
+ refresh(): void;
387
406
  ensureConnected(): void;
388
407
  connect(opts: RealtimeConnectOpts): void;
389
408
  disconnect(): void;
390
409
  /**
391
- * Subscribe to a topic (e.g. "collection:posts" or "collection:posts:*").
410
+ * Subscribe to a topic (e.g. "collection:posts" or "custom:chat-room").
392
411
  * The backend Channel authorizes via listRule on join.
412
+ *
413
+ * @param joinPayload Optional payload forwarded with the channel join
414
+ * (available to the server's join callback / hooks, e.g. `expand`).
415
+ */
416
+ subscribe(topic: string, callback: (e: RealtimeEvent) => void, joinPayload?: Record<string, unknown>): void;
417
+ /**
418
+ * Remove all subscriptions for topics under `prefix` (the topic itself or
419
+ * any topic starting with `prefix + ":"`). Used by collection-level
420
+ * `unsubscribe()` to drop every subscription of a collection.
393
421
  */
394
- subscribe(topic: string, callback: (e: RealtimeEvent) => void): void;
422
+ unsubscribeByPrefix(prefix: string): void;
395
423
  /**
396
424
  * Unsubscribe a specific callback from a topic.
397
425
  */
@@ -452,6 +480,22 @@ interface RealtimeMessage {
452
480
  }
453
481
  /** Subscription callback for a collection's realtime events. */
454
482
  type RealtimeCallback = (e: RealtimeMessage) => void;
483
+ /**
484
+ * Options for {@link CollectionService.subscribe} (PocketBase-compatible).
485
+ *
486
+ * `expand` and any extra keys are forwarded to the server channel join
487
+ * payload (available to `onRealtimeSubscribeRequest` hooks). `headers` is
488
+ * accepted for PocketBase signature compatibility but has no effect over
489
+ * WebSocket — it is not forwarded.
490
+ */
491
+ interface RealtimeSubscribeOptions {
492
+ /** Fields to expand on the subscribed records (server join payload). */
493
+ expand?: string;
494
+ /** Accepted for PocketBase parity; not sent over the WebSocket. */
495
+ headers?: Record<string, string>;
496
+ /** Any extra keys are forwarded verbatim to the server join payload. */
497
+ [key: string]: unknown;
498
+ }
455
499
  /**
456
500
  * Typed CRUD service for a single dynamic collection.
457
501
  * Get an instance via {@link LazypockClient.collection}.
@@ -606,20 +650,33 @@ declare class CollectionService<T = ApiRecord, TData = never> {
606
650
  withSchema(schema: CollectionSchema): CollectionService<T, TData>;
607
651
  /**
608
652
  * Subscribe to realtime changes for this collection.
609
- * The event's `action` is one of `"create" | "update" | "delete"`.
653
+ * The event's `action` is one of `"create" | "update" | "delete"` and the
654
+ * callback always receives the **full record** (all fields, regardless of
655
+ * any `select()` projection on the service).
610
656
  *
611
657
  * Access is governed by the collection's `listRule` (PocketBase semantics):
612
658
  * public collections allow anonymous subscriptions; other collections
613
659
  * require a matching logged-in user or superuser.
614
660
  *
615
- * @param callback Received on every record change.
616
- * @param recordId Optional — subscribe to a single record instead of `*`.
661
+ * PocketBase-compatible argument forms:
662
+ * - `subscribe(cb)` — all records of the collection
663
+ * - `subscribe('*', cb)` — all records (explicit wildcard)
664
+ * - `subscribe('RECORD_ID', cb)` — a single record
665
+ * - `subscribe('*' | 'RECORD_ID', cb, options)` — with join options
666
+ *
667
+ * Legacy form (callback first) is still accepted: `subscribe(cb, recordId)`.
668
+ *
617
669
  * @returns A function that unsubscribes this callback.
618
670
  */
671
+ subscribe(callback: RealtimeCallback): () => void;
672
+ subscribe(recordId: string, callback: RealtimeCallback, options?: RealtimeSubscribeOptions): () => void;
673
+ /** @deprecated Use `subscribe(recordId, callback)` — PocketBase order. */
619
674
  subscribe(callback: RealtimeCallback, recordId?: string): () => void;
620
675
  /**
621
- * Unsubscribe all callbacks from this collection (or a specific record).
622
- * @param recordId Optional record id; omitting it unsubs everything.
676
+ * Unsubscribe from realtime changes (PocketBase-compatible):
677
+ * - `unsubscribe()` — remove **all** subscriptions of this collection
678
+ * - `unsubscribe('*')` — remove wildcard subscriptions
679
+ * - `unsubscribe('RECORD_ID')` — remove that record's subscriptions
623
680
  */
624
681
  unsubscribe(recordId?: string): void;
625
682
  /**
@@ -1039,4 +1096,4 @@ declare class TypedClient<TCollections extends LazypockCollections = LazypockCol
1039
1096
  */
1040
1097
  declare function createClient<TCollections extends LazypockCollections = LazypockCollections>(options: LazypockClientOptions): TypedClient<TCollections>;
1041
1098
 
1042
- export { ApiError, type ApiRecord, type AuthModel, AuthStore, type CollectionSchema, CollectionService, type CollectionsMessage, CollectionsService, type CreateData, type ExpandString, type FieldKey, type FileRecord, FilesService, type FilterOp, type FilterString, HttpClient, LazypockClient, type LazypockClientOptions, type LazypockCollections, type ListOptions, type ListResult, type ReadOptions, type RealtimeCallback, type RealtimeMessage, RealtimeService, type RecordShape, type RequestOptions, type SchemaField, type SortString, type StorageAdapter, type SystemFields, TypedClient, type UpdateData, collectionTypeName, createClient, fieldTypeKind, fieldTypeScriptType, generateTypes, getFileUrl, getScaleUrl, getThumbUrl, schemaFieldType, wsUrlFromBaseUrl };
1099
+ export { ApiError, type ApiRecord, type AuthModel, AuthStore, type CollectionSchema, CollectionService, type CollectionsMessage, CollectionsService, type CreateData, type ExpandString, type FieldKey, type FileRecord, FilesService, type FilterOp, type FilterString, HttpClient, LazypockClient, type LazypockClientOptions, type LazypockCollections, type ListOptions, type ListResult, type ReadOptions, type RealtimeCallback, type RealtimeMessage, RealtimeService, type RealtimeSubscribeOptions, type RecordShape, type RequestOptions, type SchemaField, type SortString, type StorageAdapter, type SystemFields, TypedClient, type UpdateData, collectionTypeName, createClient, fieldTypeKind, fieldTypeScriptType, generateTypes, getFileUrl, getScaleUrl, getThumbUrl, schemaFieldType, wsUrlFromBaseUrl };
@@ -817,25 +817,24 @@ var Lazypock = (() => {
817
817
  derived.fieldsPreset = this.fieldsPreset;
818
818
  return derived;
819
819
  }
820
- // ── Realtime Subscriptions (PocketBase-style) ──
821
- /**
822
- * Subscribe to realtime changes for this collection.
823
- * The event's `action` is one of `"create" | "update" | "delete"`.
824
- *
825
- * Access is governed by the collection's `listRule` (PocketBase semantics):
826
- * public collections allow anonymous subscriptions; other collections
827
- * require a matching logged-in user or superuser.
828
- *
829
- * @param callback Received on every record change.
830
- * @param recordId Optional — subscribe to a single record instead of `*`.
831
- * @returns A function that unsubscribes this callback.
832
- */
833
- subscribe(callback, recordId) {
820
+ subscribe(topicOrCallback, maybeCallback, options) {
834
821
  if (!this.realtime) {
835
822
  console.warn("[lazypock] No realtime service configured.");
836
823
  return () => {
837
824
  };
838
825
  }
826
+ let recordId;
827
+ let callback;
828
+ let joinPayload;
829
+ if (typeof topicOrCallback === "function") {
830
+ callback = topicOrCallback;
831
+ if (typeof maybeCallback === "string") recordId = maybeCallback;
832
+ } else {
833
+ callback = maybeCallback;
834
+ recordId = topicOrCallback === "*" ? void 0 : topicOrCallback;
835
+ const { headers: _ignored, ...rest } = options ?? {};
836
+ if (Object.keys(rest).length > 0) joinPayload = rest;
837
+ }
839
838
  const topic = "collection:" + this.collectionName + (recordId ? ":" + recordId : "");
840
839
  const handler = (raw) => {
841
840
  const record = raw.payload?.["record"] ?? {};
@@ -846,15 +845,23 @@ var Lazypock = (() => {
846
845
  });
847
846
  };
848
847
  this.realtime.ensureConnected();
849
- this.realtime.subscribe(topic, handler);
848
+ this.realtime.subscribe(topic, handler, joinPayload);
850
849
  return () => this.realtime?.unsubscribe(topic, handler);
851
850
  }
852
851
  /**
853
- * Unsubscribe all callbacks from this collection (or a specific record).
854
- * @param recordId Optional record id; omitting it unsubs everything.
852
+ * Unsubscribe from realtime changes (PocketBase-compatible):
853
+ * - `unsubscribe()` — remove **all** subscriptions of this collection
854
+ * - `unsubscribe('*')` — remove wildcard subscriptions
855
+ * - `unsubscribe('RECORD_ID')` — remove that record's subscriptions
855
856
  */
856
857
  unsubscribe(recordId) {
857
- const topic = "collection:" + this.collectionName + (recordId ? ":" + recordId : "");
858
+ if (recordId === void 0) {
859
+ this.realtime?.unsubscribeByPrefix(
860
+ "collection:" + this.collectionName
861
+ );
862
+ return;
863
+ }
864
+ const topic = "collection:" + this.collectionName + (recordId === "*" ? "" : ":" + recordId);
858
865
  this.realtime?.unsubscribe(topic);
859
866
  }
860
867
  // ── Auth Collection Methods ──
@@ -921,6 +928,7 @@ var Lazypock = (() => {
921
928
  this.reconnectAttempt = 0;
922
929
  this.maxReconnectDelay = 5e3;
923
930
  this.url = "";
931
+ this.tokenProvider = null;
924
932
  // ── Heartbeat ──
925
933
  this.heartbeatInterval = null;
926
934
  }
@@ -946,6 +954,32 @@ var Lazypock = (() => {
946
954
  setUrl(url) {
947
955
  this.url = url;
948
956
  }
957
+ /**
958
+ * Register a token provider consulted at every (re)connect.
959
+ * When set, it takes precedence over the token passed to {@link connect}.
960
+ */
961
+ setTokenProvider(provider) {
962
+ this.tokenProvider = provider;
963
+ }
964
+ /**
965
+ * Reconnect the socket immediately with the current token.
966
+ * Called by the SDK when auth changes (login/logout/token refresh) so
967
+ * private-channel joins are authorized with the new credentials. No-op
968
+ * when the socket has never been opened and nothing is subscribed.
969
+ */
970
+ refresh() {
971
+ if (typeof WebSocket === "undefined") return;
972
+ if (!this.ws && this.subscriptions.size === 0) return;
973
+ this.clearReconnectTimer();
974
+ const ws = this.ws;
975
+ this.ws = null;
976
+ if (ws) {
977
+ ws.onclose = null;
978
+ ws.close();
979
+ }
980
+ this.reconnectAttempt = 0;
981
+ this.doConnect();
982
+ }
949
983
  /*
950
984
  * Ensure the socket is connected, then subscribe.
951
985
  * Used by collection-level convenience wrappers so a connection is opened
@@ -969,15 +1003,30 @@ var Lazypock = (() => {
969
1003
  this.ws = null;
970
1004
  }
971
1005
  /**
972
- * Subscribe to a topic (e.g. "collection:posts" or "collection:posts:*").
1006
+ * Subscribe to a topic (e.g. "collection:posts" or "custom:chat-room").
973
1007
  * The backend Channel authorizes via listRule on join.
1008
+ *
1009
+ * @param joinPayload Optional payload forwarded with the channel join
1010
+ * (available to the server's join callback / hooks, e.g. `expand`).
974
1011
  */
975
- subscribe(topic, callback) {
1012
+ subscribe(topic, callback, joinPayload) {
976
1013
  const subs = this.subscriptions.get(topic) || [];
977
- subs.push({ topic, callback });
1014
+ subs.push({ topic, callback, joinPayload });
978
1015
  this.subscriptions.set(topic, subs);
979
1016
  if (this.ws?.readyState === WebSocket.OPEN) {
980
- this.joinTopic(topic);
1017
+ this.joinTopic(topic, joinPayload);
1018
+ }
1019
+ }
1020
+ /**
1021
+ * Remove all subscriptions for topics under `prefix` (the topic itself or
1022
+ * any topic starting with `prefix + ":"`). Used by collection-level
1023
+ * `unsubscribe()` to drop every subscription of a collection.
1024
+ */
1025
+ unsubscribeByPrefix(prefix) {
1026
+ for (const topic of [...this.subscriptions.keys()]) {
1027
+ if (topic === prefix || topic.startsWith(prefix + ":")) {
1028
+ this.subscriptions.delete(topic);
1029
+ }
981
1030
  }
982
1031
  }
983
1032
  /**
@@ -996,9 +1045,14 @@ var Lazypock = (() => {
996
1045
  }
997
1046
  }
998
1047
  resubscribeAll() {
999
- for (const topic of this.subscriptions.keys()) {
1000
- if (this.ws?.readyState === WebSocket.OPEN) {
1001
- this.joinTopic(topic);
1048
+ const seen = /* @__PURE__ */ new Set();
1049
+ for (const entries of this.subscriptions.values()) {
1050
+ for (const entry of entries) {
1051
+ if (seen.has(entry.topic)) continue;
1052
+ seen.add(entry.topic);
1053
+ if (this.ws?.readyState === WebSocket.OPEN) {
1054
+ this.joinTopic(entry.topic, entry.joinPayload);
1055
+ }
1002
1056
  }
1003
1057
  }
1004
1058
  }
@@ -1010,8 +1064,9 @@ var Lazypock = (() => {
1010
1064
  return;
1011
1065
  }
1012
1066
  let url = this.url;
1013
- if (this.token) {
1014
- url += (url.includes("?") ? "&" : "?") + "token=" + encodeURIComponent(this.token);
1067
+ const token = this.tokenProvider ? this.tokenProvider() : this.token;
1068
+ if (token) {
1069
+ url += (url.includes("?") ? "&" : "?") + "token=" + encodeURIComponent(token);
1015
1070
  }
1016
1071
  this.ws = new WebSocket(url);
1017
1072
  this.ws.onopen = () => {
@@ -1058,12 +1113,12 @@ var Lazypock = (() => {
1058
1113
  }
1059
1114
  }
1060
1115
  }
1061
- joinTopic(topic) {
1116
+ joinTopic(topic, joinPayload) {
1062
1117
  const ref = this.nextRef();
1063
1118
  const msg = JSON.stringify({
1064
1119
  topic,
1065
1120
  event: "phx_join",
1066
- payload: {},
1121
+ payload: joinPayload ?? {},
1067
1122
  ref
1068
1123
  });
1069
1124
  this.ws?.send(msg);
@@ -1490,7 +1545,15 @@ var Lazypock = (() => {
1490
1545
  body
1491
1546
  })}`
1492
1547
  );
1493
- const createLines = fields.map((f) => createDataMemberLine(f)).filter((l) => l !== "");
1548
+ const createLines = [];
1549
+ const seenKeys = /* @__PURE__ */ new Set();
1550
+ for (const f of fields) {
1551
+ for (const { key, line } of createDataMemberLines(f)) {
1552
+ if (seenKeys.has(key)) continue;
1553
+ seenKeys.add(key);
1554
+ createLines.push(line);
1555
+ }
1556
+ }
1494
1557
  sections.push(
1495
1558
  `export interface ${typeName}CreateData${renderInterface({
1496
1559
  body: createLines.join("\n")
@@ -1592,14 +1655,23 @@ ${opts.body}
1592
1655
  if (type === "never") return "";
1593
1656
  return ` ${JSON.stringify(key)}${req}: ${type};`;
1594
1657
  }
1595
- function createDataMemberLine(f) {
1596
- if (f.type === "autodate") return "";
1597
- const key = fieldKey(f.name);
1658
+ function createDataMemberLines(f) {
1659
+ if (f.type === "autodate") return [];
1660
+ const rawName = fieldKey(f.name);
1598
1661
  const serverDefaulted = f.options?.defaultValue !== void 0 || f.system && (f.name === "verified" || f.name === "emailVisibility");
1599
1662
  const req = f.required && !serverDefaulted ? "" : "?";
1600
1663
  const type = f.type === "password" ? "string" : fieldTypeScriptType(f);
1601
- if (type === "never") return "";
1602
- return ` ${JSON.stringify(key)}${req}: ${type};`;
1664
+ if (type === "never") return [];
1665
+ const members = [
1666
+ { key: rawName, line: ` ${JSON.stringify(rawName)}${req}: ${type};` }
1667
+ ];
1668
+ if (f.type === "password" && rawName !== "password") {
1669
+ members.unshift({
1670
+ key: "password",
1671
+ line: ` ${JSON.stringify("password")}${req}: ${type};`
1672
+ });
1673
+ }
1674
+ return members;
1603
1675
  }
1604
1676
 
1605
1677
  // src/lazypock.ts
@@ -1618,6 +1690,9 @@ ${opts.body}
1618
1690
  if (!options.realtime) {
1619
1691
  this.realtime.setUrl(wsUrlFromBaseUrl(baseUrl));
1620
1692
  }
1693
+ this.realtime.setTokenProvider(() => this.authStore.token);
1694
+ this.authStore.onChange(() => this.realtime.refresh());
1695
+ this.authReady.then(() => this.realtime.refresh());
1621
1696
  this.files = new FilesService(this.http);
1622
1697
  this.collections = new CollectionsService(this.http, this.realtime);
1623
1698
  if (options.types?.schemas) {