@palbase/web 1.0.1 → 1.1.1

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.
@@ -1,3 +1,4 @@
1
+ import { Room, ExternalE2EEKeyProvider } from 'livekit-client';
1
2
  import { S as SessionStorageAdapter } from './storage-BPaeSG8K.cjs';
2
3
  import { F } from './pooled-flags-Bwq4usn0.js';
3
4
 
@@ -30,7 +31,7 @@ interface Session$1 {
30
31
  }
31
32
  type AuthStateEvent$1 = 'SESSION_SET' | 'SESSION_CLEARED';
32
33
  type AuthStateCallback$1 = (event: AuthStateEvent$1, session: Session$1 | null) => void;
33
- type Unsubscribe$2 = () => void;
34
+ type Unsubscribe$3 = () => void;
34
35
 
35
36
  declare class TokenManager$1 {
36
37
  private session;
@@ -44,7 +45,7 @@ declare class TokenManager$1 {
44
45
  clearSession(): void;
45
46
  isExpired(): boolean;
46
47
  refreshSession(): Promise<void>;
47
- onAuthStateChange(callback: AuthStateCallback$1): Unsubscribe$2;
48
+ onAuthStateChange(callback: AuthStateCallback$1): Unsubscribe$3;
48
49
  private executeRefresh;
49
50
  private notify;
50
51
  }
@@ -120,7 +121,7 @@ interface Session {
120
121
  }
121
122
  type AuthStateEvent = 'SESSION_SET' | 'SESSION_CLEARED';
122
123
  type AuthStateCallback = (event: AuthStateEvent, session: Session | null) => void;
123
- type Unsubscribe$1 = () => void;
124
+ type Unsubscribe$2 = () => void;
124
125
 
125
126
  declare class TokenManager {
126
127
  private session;
@@ -134,7 +135,7 @@ declare class TokenManager {
134
135
  clearSession(): void;
135
136
  isExpired(): boolean;
136
137
  refreshSession(): Promise<void>;
137
- onAuthStateChange(callback: AuthStateCallback): Unsubscribe$1;
138
+ onAuthStateChange(callback: AuthStateCallback): Unsubscribe$2;
138
139
  private executeRefresh;
139
140
  private notify;
140
141
  }
@@ -505,6 +506,107 @@ declare class AuthClient {
505
506
  private setSessionAndWireRefresh;
506
507
  }
507
508
 
509
+ type CallState = 'connecting' | 'active' | 'ended';
510
+ interface CallParticipant {
511
+ identity: string;
512
+ isSpeaking: boolean;
513
+ audioMuted: boolean;
514
+ videoEnabled: boolean;
515
+ /** The live <video> element for this participant, or null before track arrives. */
516
+ videoElement: HTMLVideoElement | null;
517
+ /** The live <audio> element for this participant, or null before track arrives. */
518
+ audioElement: HTMLAudioElement | null;
519
+ }
520
+ type CallChangeCallback = (call: Call) => void;
521
+ /**
522
+ * A live call session. Obtain via `pb.calls.start()` or `pb.calls.accept()`.
523
+ *
524
+ * Lifecycle:
525
+ * connecting → active (room joined, tracks flowing)
526
+ * active → ended (leave() / remote disconnect)
527
+ *
528
+ * Subscribe to changes via `call.subscribe(cb)` which fires on state or
529
+ * participant changes (mirrors flags `onChange` / realtime `on` pattern).
530
+ */
531
+ declare class Call {
532
+ readonly id: string;
533
+ private _state;
534
+ private readonly _participants;
535
+ private readonly _listeners;
536
+ private readonly _room;
537
+ private readonly _keyProvider;
538
+ /** @internal — obtain via PalbeCalls.start() / .accept() */
539
+ constructor(callId: string, room: Room, keyProvider: ExternalE2EEKeyProvider);
540
+ get state(): CallState;
541
+ /** Snapshot of current remote participants (does NOT include the local participant). */
542
+ get participants(): readonly CallParticipant[];
543
+ get localParticipant(): Room['localParticipant'];
544
+ /**
545
+ * Subscribe to call changes (state + participant updates).
546
+ * Returns an `Unsubscribe` function — matches the SDK's flags/auth pattern.
547
+ */
548
+ subscribe(callback: CallChangeCallback): Unsubscribe;
549
+ /** Mute / unmute the local microphone. */
550
+ mute(on: boolean): Promise<void>;
551
+ /** Enable / disable the local camera. */
552
+ setCamera(on: boolean): Promise<void>;
553
+ /**
554
+ * Set a raw frame encryption key (ArrayBuffer) for this call.
555
+ * Design seam for SP-1.x web-MLS: call this with the MLS exporter secret
556
+ * to enable frame-level E2EE via ExternalE2EEKeyProvider.
557
+ *
558
+ * NOTE: The room must have been opened with `e2ee` options for this to take
559
+ * effect. Currently calls connect WITHOUT e2ee — see module docstring.
560
+ *
561
+ * TODO(SP-1-web): wire this to MLS-derived key on session join.
562
+ */
563
+ setMediaKey(key: ArrayBuffer): Promise<void>;
564
+ /** Leave the call and disconnect from the LiveKit room. */
565
+ leave(): Promise<void>;
566
+ private _setState;
567
+ private _emit;
568
+ private _upsertParticipant;
569
+ private _attachTrack;
570
+ private _wireRoomEvents;
571
+ }
572
+ declare class PalbeCalls {
573
+ private readonly rt;
574
+ constructor(rt: PalbeRuntime);
575
+ /**
576
+ * Start a new call in a messaging group.
577
+ *
578
+ * @param groupId - Messaging group display-id (`grp_<uuidv7>`)
579
+ * @param media - Which media tracks to publish (default: audio + video)
580
+ * @returns A `Call` in `connecting` state; transitions to `active` once LiveKit connects.
581
+ *
582
+ * @throws BackendError('network', { code: 'call_service_unavailable' }) if LiveKit SFU is down (503)
583
+ * @throws BackendError('forbidden', { code: 'not_group_member' }) if the caller is not a member (403)
584
+ * @throws BackendError('conflict', { code: 'call_room_full' }) if the room is full (409)
585
+ */
586
+ start(groupId: string, { media }?: {
587
+ media?: Array<'audio' | 'video'>;
588
+ }): Promise<Call>;
589
+ /**
590
+ * Accept an incoming call in a messaging group.
591
+ *
592
+ * @param groupId - Messaging group display-id
593
+ * @param callId - Call identifier (from the push notification payload)
594
+ * @param media - Which media tracks to publish (default: audio + video)
595
+ */
596
+ accept(groupId: string, callId: string, { media }?: {
597
+ media?: Array<'audio' | 'video'>;
598
+ }): Promise<Call>;
599
+ /**
600
+ * Decline an incoming call.
601
+ *
602
+ * @param groupId - Messaging group display-id
603
+ * @param callId - Call identifier
604
+ * @param reason - Optional decline reason string
605
+ */
606
+ decline(groupId: string, callId: string, reason?: string): Promise<void>;
607
+ private _connect;
608
+ }
609
+
508
610
  interface PalbeOAuthConfig {
509
611
  google?: {
510
612
  enabled?: boolean;
@@ -598,6 +700,248 @@ declare class PalbeFlags {
598
700
  destroy(): void;
599
701
  }
600
702
 
703
+ /** A direct (1:1) chat or a multi-party group. */
704
+ type ChatKind = 'direct' | 'group';
705
+ /** A draft (local-only, not yet on the server) or an active (materialized) chat. */
706
+ type ChatState = 'draft' | 'active';
707
+ /** Server-side ACL role (group only; a direct chat has no roles). */
708
+ type ChatRole = 'owner' | 'admin' | 'member';
709
+ /** Whether a message was received (`incoming`) or sent by this device (`outgoing`). */
710
+ type MessageDirection = 'incoming' | 'outgoing';
711
+ /** A renderable message kind. `system` = a membership commit / control frame. */
712
+ type ChatMessageKind = 'text' | 'media' | 'system';
713
+ /** A participating USER (not a device). For a direct chat: `[me, peer]`. */
714
+ interface ChatMember {
715
+ /** == userId (stable identity). */
716
+ readonly id: string;
717
+ readonly userId: string;
718
+ readonly displayName: string | null;
719
+ readonly role: ChatRole;
720
+ readonly isSelf: boolean;
721
+ }
722
+ /**
723
+ * A resolved reply context — produced by `resolveReply` on the decode path.
724
+ * `state:'resolved'` means the parent was found in local history and `quoteText`
725
+ * is the REAL parent text (spoof-proof). `state:'unavailable'` means the parent
726
+ * was not in local history; `quoteText` is the embedded preview body (may be null).
727
+ */
728
+ interface ResolvedReply {
729
+ readonly parentClientMsgId: string;
730
+ readonly state: 'resolved' | 'unavailable';
731
+ readonly quoteSenderUserId: string;
732
+ readonly quoteText: string | null;
733
+ readonly quoteKind: string;
734
+ }
735
+ /** One message in a chat transcript. */
736
+ interface ChatMessage {
737
+ /** Routing-key-free id: `<chat.id>#<serverSeq>`. */
738
+ readonly id: string;
739
+ readonly kind: ChatMessageKind;
740
+ readonly direction: MessageDirection;
741
+ /** The sending USER id, when resolved (nil for system frames or unknown sender). */
742
+ readonly senderUserId: string | null;
743
+ readonly text: string | null;
744
+ /** The server-minted per-group monotonic sequence (sort key + read cursor). */
745
+ readonly serverSeq: number;
746
+ /** When this device decoded (incoming) or sent (outgoing) the message. */
747
+ readonly sentAt: Date;
748
+ /** The client-minted idempotency id for this message (empty string for legacy/system). */
749
+ readonly clientMsgId: string;
750
+ /** Resolved reply context, or null if this is not a reply. */
751
+ readonly replyTo: ResolvedReply | null;
752
+ }
753
+ /** The receipt from a send — the server's monotonic sequence + accepted epoch. */
754
+ interface SentReceipt {
755
+ readonly serverSeq: number;
756
+ readonly epoch: number;
757
+ }
758
+ /** Per-user comms privacy prefs (defaults both-true). */
759
+ interface CommsPrefs {
760
+ readonly sharePresence: boolean;
761
+ readonly shareReceipts: boolean;
762
+ }
763
+ /** A presence snapshot for a user in a chat (60s TTL, device-union). */
764
+ interface PresenceState {
765
+ readonly userId: string;
766
+ readonly isOnline: boolean;
767
+ readonly lastSeenAt: Date | null;
768
+ }
769
+ /** An unsubscribe handle (matches the flags/realtime/auth pattern). */
770
+ type Unsubscribe$1 = () => void;
771
+
772
+ /** A resolved group as the SDK tracks it. `name` is always null on web (no exporter). */
773
+ interface MessagingGroup {
774
+ displayId: string;
775
+ rfcGroupId: string;
776
+ currentEpoch: number;
777
+ ownerUserId: string | null;
778
+ directKey: string | null;
779
+ name: string | null;
780
+ }
781
+ interface QuotePreview {
782
+ kind: string;
783
+ author_user_id: string;
784
+ body?: string;
785
+ body_truncated: boolean;
786
+ }
787
+ interface ReplyRef {
788
+ v: number;
789
+ client_msg_id: string;
790
+ preview?: QuotePreview;
791
+ }
792
+
793
+ /** A decoded incoming message handed to chat listeners. */
794
+ interface IncomingMessage {
795
+ kind: 'application' | 'commit' | 'proposal' | 'welcome';
796
+ group: MessagingGroup;
797
+ text: string | null;
798
+ senderDeviceId: string | null;
799
+ epoch: number;
800
+ serverSeq: number;
801
+ receivedAt: Date;
802
+ /** The client-minted idempotency id from the decoded envelope (empty string for legacy/system). */
803
+ clientMsgId: string;
804
+ /** The decoded reply reference, if present in the envelope. */
805
+ replyRef: ReplyRef | null;
806
+ }
807
+
808
+ /** The intended participants of a draft chat (held until the first send). */
809
+ interface ChatDraft {
810
+ mode: {
811
+ kind: 'direct';
812
+ peerUserId: string;
813
+ } | {
814
+ kind: 'group';
815
+ members: string[];
816
+ };
817
+ /** The reserved local id a draft shows before it materializes. */
818
+ reservedId: string;
819
+ }
820
+ /** The seam the Chat talks to for the work needing the resolved machinery. */
821
+ interface ChatBackend {
822
+ selfUserId: string;
823
+ /** Materialize a draft → the active group (DM get-or-create / group create+add). */
824
+ materialize(draft: ChatDraft): Promise<MessagingGroup>;
825
+ sendText(group: MessagingGroup, text: string, replyTo?: ReplyRef | null): Promise<{
826
+ receipt: SentReceipt;
827
+ clientMsgId: string;
828
+ }>;
829
+ history(group: MessagingGroup, limit: number, before?: number): Promise<ChatMessage[]>;
830
+ members(group: MessagingGroup): Promise<ChatMember[]>;
831
+ addMember(group: MessagingGroup, userId: string): Promise<void>;
832
+ removeMember(group: MessagingGroup, userId: string): Promise<void>;
833
+ leave(group: MessagingGroup): Promise<void>;
834
+ registerActive(group: MessagingGroup): void;
835
+ setTyping(group: MessagingGroup, isTyping: boolean): void;
836
+ markRead(group: MessagingGroup, upToServerSeq: number): Promise<void>;
837
+ /** Subscribe live message + conv (presence/typing/read) for an active group. */
838
+ subscribeLive(group: MessagingGroup, chat: Chat): Unsubscribe$1;
839
+ /** Resolve a sender device id → its owning user id (for senderUserId). */
840
+ userIdForDevice(group: MessagingGroup, deviceId: string): Promise<string | null>;
841
+ }
842
+ declare class Chat {
843
+ /** Stable, URL/log-safe id (the grp_ display id once active; a reserved local id while draft). */
844
+ id: string;
845
+ readonly kind: ChatKind;
846
+ private _state;
847
+ private _group;
848
+ private _draft;
849
+ private readonly backend;
850
+ private messageList;
851
+ private memberCache;
852
+ private typingList;
853
+ private presenceStates;
854
+ private readWatermark;
855
+ private titleOverride;
856
+ private readonly seenKeys;
857
+ /** Index: clientMsgId → { text, senderUserId } for resolveReply lookups. */
858
+ private readonly byClientMsgId;
859
+ private loadedEarliestSeq;
860
+ private historyLoaded;
861
+ private wired;
862
+ private liveUnsub;
863
+ private readonly listeners;
864
+ /** @internal — obtain via pb.messaging.directChat / groupChat / chat(id). */
865
+ constructor(args: {
866
+ group: MessagingGroup;
867
+ kind: ChatKind;
868
+ backend: ChatBackend;
869
+ } | {
870
+ draft: ChatDraft;
871
+ kind: ChatKind;
872
+ backend: ChatBackend;
873
+ });
874
+ /** Subscribe to any change in this chat (messages/members/typing/state). */
875
+ onChange(cb: () => void): Unsubscribe$1;
876
+ private emit;
877
+ get state(): ChatState;
878
+ get isDirect(): boolean;
879
+ get messages(): readonly ChatMessage[];
880
+ get members(): readonly ChatMember[];
881
+ get typing(): readonly ChatMember[];
882
+ get lastMessage(): ChatMessage | null;
883
+ get unreadCount(): number;
884
+ get title(): string;
885
+ presence(userId: string): PresenceState | null;
886
+ private ensureWired;
887
+ private hydrateHistory;
888
+ private mergeHistory;
889
+ /** @internal — called by the backend's live subscription. */
890
+ ingestLive(incoming: IncomingMessage): Promise<void>;
891
+ /** @internal — called by the backend's conv subscription. */
892
+ applyConv(event: string, payload: Record<string, unknown>): void;
893
+ private kindOf;
894
+ private internalKey;
895
+ private publicId;
896
+ /** Page older messages in. Returns how many were prepended. */
897
+ loadEarlier(limit?: number): Promise<number>;
898
+ private refreshMembers;
899
+ private seedMembersFromGroup;
900
+ private seedDraftMembers;
901
+ send(text: string, opts?: {
902
+ replyTo?: ChatMessage;
903
+ }): Promise<SentReceipt>;
904
+ private appendOwnSend;
905
+ private materializeIfNeeded;
906
+ addMemberUser(userId: string): Promise<void>;
907
+ removeMemberUser(userId: string): Promise<void>;
908
+ leave(): Promise<void>;
909
+ setTyping(isTyping: boolean): void;
910
+ markRead(message: ChatMessage): Promise<void>;
911
+ }
912
+
913
+ declare class PalbeMessaging {
914
+ private readonly coordinator;
915
+ constructor(rt: PalbeRuntime);
916
+ /**
917
+ * Warm messaging at sign-in (optional). Enrolls this device + starts the live
918
+ * delivery source so incoming DMs/Welcomes drain before the chat list opens.
919
+ * Never REQUIRED — any chat op self-enrolls. Idempotent.
920
+ */
921
+ start(): Promise<void>;
922
+ /**
923
+ * Open the ONE direct chat with `userId`. INSTANT + LOCAL — no network, nothing
924
+ * created yet. Returns a draft `Chat` to show immediately; the server group +
925
+ * MLS material materialize LAZILY on the first `chat.send`. Idempotent + stable:
926
+ * the same two users always resolve to the SAME Chat.
927
+ */
928
+ directChat(userId: string): Chat;
929
+ /**
930
+ * Open a multi-party group chat. LOCAL + LAZY like `directChat`: pick the
931
+ * members, get a draft Chat, the group is created on the FIRST `chat.send`.
932
+ */
933
+ groupChat(opts?: {
934
+ members?: string[];
935
+ }): Chat;
936
+ /** Look up a chat by id (e.g. from a push payload / deep link). null if unknown. */
937
+ chat(id: string): Chat | null;
938
+ /** The observable chat list (DMs + groups, active only). Read it after an
939
+ * `onChatsChange` subscription to render the inbox. */
940
+ get chats(): readonly Chat[];
941
+ /** Subscribe to chat-list changes (a chat added/removed/hydrated). */
942
+ onChatsChange(cb: () => void): Unsubscribe$1;
943
+ }
944
+
601
945
  /**
602
946
  * The connection state of the shared realtime WebSocket (iOS enum parity), plus
603
947
  * `'error'` — surfaced when a channel could not be recovered after a
@@ -702,6 +1046,8 @@ interface PalbeRuntime {
702
1046
  flags: PalbeFlags;
703
1047
  realtime: PalbeRealtime;
704
1048
  analytics: PalbeAnalytics;
1049
+ calls: PalbeCalls;
1050
+ messaging: PalbeMessaging;
705
1051
  storage: SessionStorageAdapter;
706
1052
  /**
707
1053
  * Destroy the realtime facade if it was already constructed (no-op otherwise).
@@ -953,4 +1299,4 @@ declare class PalbeAnalytics {
953
1299
  private post;
954
1300
  }
955
1301
 
956
- export { type AnalyticsProperties as A, type FlagsView as F, type MagicLinkResult as M, type OAuthExchangeResult as O, PalbeAnalytics as P, RealtimeChannel as R, type Unsubscribe as U, type AuthChangeEvent as a, type AuthState as b, type AuthSuccess as c, type AuthUser as d, PalbeAuth as e, type PalbeConfig as f, PalbeFlags as g, type PalbeOAuthConfig as h, PalbeRealtime as i, type RealtimeConnectionState as j, type RealtimeHandler as k, type RealtimePayload as l, type RealtimeStatus as m, type RealtimeStatusSnapshot as n, type RealtimeSubscription as o, type PalbeRuntime as p, buildRuntime as q };
1302
+ export { type AnalyticsProperties as A, type RealtimeConnectionState as B, Call as C, type RealtimeHandler as D, type RealtimePayload as E, type FlagsView as F, type RealtimeStatus as G, type RealtimeStatusSnapshot as H, type RealtimeSubscription as I, type PalbeRuntime as J, buildRuntime as K, type MagicLinkResult as M, type OAuthExchangeResult as O, PalbeAnalytics as P, RealtimeChannel as R, type SentReceipt as S, type Unsubscribe as U, type AuthChangeEvent as a, type AuthState as b, type AuthSuccess as c, type AuthUser as d, type CallChangeCallback as e, type CallParticipant as f, type CallState as g, Chat as h, type ChatBackend as i, type ChatDraft as j, type ChatKind as k, type ChatMember as l, type ChatMessage as m, type ChatMessageKind as n, type ChatRole as o, type ChatState as p, type CommsPrefs as q, type MessageDirection as r, PalbeAuth as s, PalbeCalls as t, type PalbeConfig as u, PalbeFlags as v, PalbeMessaging as w, type PalbeOAuthConfig as x, PalbeRealtime as y, type PresenceState as z };