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/README.md +104 -20
- package/dist/{chunk-V2XSEOWF.js → chunk-CGQVJ7TT.js} +24 -7
- package/dist/chunk-CGQVJ7TT.js.map +1 -0
- package/dist/cli.cjs +23 -6
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.global.js +23 -6
- package/dist/cli.global.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +110 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -8
- package/dist/index.d.ts +65 -8
- package/dist/index.global.js +110 -35
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +88 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/codegen.ts +38 -11
- package/src/collection.ts +77 -9
- package/src/index.ts +1 -1
- package/src/lazypock.ts +10 -0
- package/src/realtime.ts +79 -11
- package/dist/chunk-V2XSEOWF.js.map +0 -1
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 "
|
|
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
|
-
|
|
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
|
-
*
|
|
616
|
-
*
|
|
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
|
|
622
|
-
*
|
|
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 "
|
|
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
|
-
|
|
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
|
-
*
|
|
616
|
-
*
|
|
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
|
|
622
|
-
*
|
|
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.global.js
CHANGED
|
@@ -817,25 +817,24 @@ var Lazypock = (() => {
|
|
|
817
817
|
derived.fieldsPreset = this.fieldsPreset;
|
|
818
818
|
return derived;
|
|
819
819
|
}
|
|
820
|
-
|
|
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
|
|
854
|
-
*
|
|
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
|
-
|
|
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 "
|
|
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
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
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
|
-
|
|
1014
|
-
|
|
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 =
|
|
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
|
|
1596
|
-
if (f.type === "autodate") return
|
|
1597
|
-
const
|
|
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
|
-
|
|
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) {
|