@palbase/web 7.3.9 → 7.4.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.
- package/dist/{analytics-facade-BER0EyYT.d.ts → analytics-facade-But6gu2r.d.ts} +135 -16
- package/dist/{analytics-facade-CQXCQSoF.d.cts → analytics-facade-f8IVujJW.d.cts} +135 -16
- package/dist/{chunk-EAOROUSW.js → chunk-4WMJTUDN.js} +26 -17
- package/dist/chunk-4WMJTUDN.js.map +1 -0
- package/dist/{chunk-Q5DUDL77.js → chunk-G56VGUYZ.js} +1 -1
- package/dist/chunk-G56VGUYZ.js.map +1 -0
- package/dist/{chunk-FCIMEU2E.js → chunk-VHUCJBBQ.js} +2 -2
- package/dist/chunk-VHUCJBBQ.js.map +1 -0
- package/dist/{chunk-H6YSCGQC.js → chunk-XJBMBUHU.js} +502 -38
- package/dist/chunk-XJBMBUHU.js.map +1 -0
- package/dist/gen/cli.cjs +2 -2
- package/dist/gen/cli.cjs.map +1 -1
- package/dist/gen/cli.js +3 -3
- package/dist/gen/cli.js.map +1 -1
- package/dist/index.cjs +514 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/internal.cjs +524 -51
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +24 -4
- package/dist/internal.d.ts +24 -4
- package/dist/internal.js +3 -3
- package/dist/next/client.cjs +518 -48
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.js +3 -3
- package/dist/next/index.cjs +524 -51
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +2 -2
- package/dist/next/index.d.ts +2 -2
- package/dist/next/index.js +4 -4
- package/dist/next/index.js.map +1 -1
- package/dist/next/proxy.cjs.map +1 -1
- package/dist/next/proxy.js +3 -3
- package/dist/{pb-WAQvwCfM.d.cts → pb-9MMDNQ9p.d.cts} +6 -1
- package/dist/{pb-BRlmBIAm.d.ts → pb-DRmdWQzG.d.ts} +6 -1
- package/dist/react/index.cjs +22 -19
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-EAOROUSW.js.map +0 -1
- package/dist/chunk-FCIMEU2E.js.map +0 -1
- package/dist/chunk-H6YSCGQC.js.map +0 -1
- package/dist/chunk-Q5DUDL77.js.map +0 -1
|
@@ -612,9 +612,15 @@ declare class PalbeCalls {
|
|
|
612
612
|
* @param media - Which media tracks to publish (default: audio + video)
|
|
613
613
|
* @returns A `Call` in `connecting` state; transitions to `active` once the media room connects.
|
|
614
614
|
*
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
*
|
|
615
|
+
* Every failure below arrives as kind `'server'` — this SDK's error kinds are
|
|
616
|
+
* `notConfigured | validation | unauthorized | rateLimited | server | network
|
|
617
|
+
* | decode`, and only a 401, a 429 or a 400 carrying a field-error array gets
|
|
618
|
+
* its own kind. So branch on `err.code`, never on the kind.
|
|
619
|
+
*
|
|
620
|
+
* @throws BackendError('server', { code: 'calling_unavailable' }) no SFU configured on this stack (503)
|
|
621
|
+
* @throws BackendError('server', { code: 'not_group_member' }) the caller is not a member of the group (403)
|
|
622
|
+
* @throws BackendError('server', { code: 'call_room_full' }) the call is at its participant limit (409)
|
|
623
|
+
* @throws BackendError('server', { code: 'call_provider_error' }) the media provider failed upstream (502)
|
|
618
624
|
*/
|
|
619
625
|
start(groupId: string, { media }?: {
|
|
620
626
|
media?: Array<'audio' | 'video'>;
|
|
@@ -623,7 +629,11 @@ declare class PalbeCalls {
|
|
|
623
629
|
* Accept an incoming call in a messaging group.
|
|
624
630
|
*
|
|
625
631
|
* @param groupId - Messaging group display-id
|
|
626
|
-
* @param callId - Call identifier
|
|
632
|
+
* @param callId - Call identifier, carried by the `call_invite` the server
|
|
633
|
+
* fans onto the group's conversation topic
|
|
634
|
+
* (`pb.realtime.channel('messaging:conv:<rfcGroupId>').on('call_invite', …)`).
|
|
635
|
+
* This SDK ships no web push: on the web the invite arrives over realtime or
|
|
636
|
+
* over whatever signalling the app already runs.
|
|
627
637
|
* @param media - Which media tracks to publish (default: audio + video)
|
|
628
638
|
*/
|
|
629
639
|
accept(groupId: string, callId: string, { media }?: {
|
|
@@ -1579,6 +1589,19 @@ interface RealtimeStatus {
|
|
|
1579
1589
|
readonly lastEventAt: Date | null;
|
|
1580
1590
|
onChange(callback: (status: RealtimeStatusSnapshot) => void): Unsubscribe;
|
|
1581
1591
|
}
|
|
1592
|
+
/** Why the server refused a channel. */
|
|
1593
|
+
interface RealtimeChannelError {
|
|
1594
|
+
/** The channel this is about. */
|
|
1595
|
+
topic: string;
|
|
1596
|
+
/** Exactly what the server said: `"unauthorized"` or `"unavailable"`. */
|
|
1597
|
+
reason: string;
|
|
1598
|
+
/**
|
|
1599
|
+
* Whether asking again could succeed. `unavailable` (the project could not be
|
|
1600
|
+
* reached to decide) is retryable and the socket retries it on reconnect;
|
|
1601
|
+
* `unauthorized` is a settled answer and is not.
|
|
1602
|
+
*/
|
|
1603
|
+
retryable: boolean;
|
|
1604
|
+
}
|
|
1582
1605
|
/**
|
|
1583
1606
|
* A subscription handle for one realtime channel (returned by
|
|
1584
1607
|
* `pb.realtime.channel(name)` — the SAME instance per name). A channel is
|
|
@@ -1595,12 +1618,62 @@ declare class RealtimeChannel {
|
|
|
1595
1618
|
* subscription and `cancel()` it to stop.
|
|
1596
1619
|
*/
|
|
1597
1620
|
on(event: string, handler: RealtimeHandler): RealtimeSubscription;
|
|
1621
|
+
/**
|
|
1622
|
+
* Called when the server REFUSES this channel.
|
|
1623
|
+
*
|
|
1624
|
+
* A join is an authorization decision, and a decision the app never hears is
|
|
1625
|
+
* the same as no decision at all: silence looks exactly like a slow network.
|
|
1626
|
+
* This is where a refusal arrives, carrying the server's own distinction —
|
|
1627
|
+
* `retryable: false` means "you may not" and asking again will not help;
|
|
1628
|
+
* `retryable: true` means the project could not be asked, and the socket's
|
|
1629
|
+
* next reconnect retries on its own.
|
|
1630
|
+
*
|
|
1631
|
+
* pb.realtime.channel('room:42').onError((err) => {
|
|
1632
|
+
* if (!err.retryable) showJoinDenied()
|
|
1633
|
+
* })
|
|
1634
|
+
*/
|
|
1635
|
+
onError(handler: (error: RealtimeChannelError) => void): RealtimeSubscription;
|
|
1598
1636
|
/**
|
|
1599
1637
|
* Broadcast `payload` to the channel's other subscribers (web addition —
|
|
1600
1638
|
* iOS is receive-only). Joins the channel if it isn't already; queued
|
|
1601
1639
|
* until the join is live on the socket.
|
|
1602
1640
|
*/
|
|
1603
1641
|
send(event: string, payload?: RealtimePayload): void;
|
|
1642
|
+
/**
|
|
1643
|
+
* Watch one key of the channel's shared state.
|
|
1644
|
+
*
|
|
1645
|
+
* The handler is called with the CURRENT value straight away when there is
|
|
1646
|
+
* one, and again on every change. That is the difference from `on()`: a
|
|
1647
|
+
* subscriber to an event learns nothing until the next one, while state is
|
|
1648
|
+
* already there when you ask.
|
|
1649
|
+
*/
|
|
1650
|
+
onState(key: string, handler: (value: unknown) => void): RealtimeSubscription;
|
|
1651
|
+
/** Read one key without subscribing. */
|
|
1652
|
+
stateValue(key: string): unknown;
|
|
1653
|
+
/** Write one key. `durable` outlives this connection; `ephemeral` is reaped
|
|
1654
|
+
* when it closes, which is what presence is built on. */
|
|
1655
|
+
setState(key: string, value: unknown, opts?: {
|
|
1656
|
+
life?: 'ephemeral' | 'durable';
|
|
1657
|
+
}): void;
|
|
1658
|
+
/** Remove a key this connection wrote. */
|
|
1659
|
+
clearState(key: string): void;
|
|
1660
|
+
/**
|
|
1661
|
+
* Announce this client on the channel. `meta` is whatever other participants
|
|
1662
|
+
* should see — a name, an avatar, a cursor.
|
|
1663
|
+
*
|
|
1664
|
+
* It is ephemeral state keyed by this connection, so it disappears when the
|
|
1665
|
+
* socket does. Nothing has to be un-announced on a crash.
|
|
1666
|
+
*/
|
|
1667
|
+
presenceEnter(meta: RealtimePayload): void;
|
|
1668
|
+
/** Replace the announced value — a cursor moving is this, at whatever rate
|
|
1669
|
+
* the app likes: the server conflates writes it cannot deliver fast enough. */
|
|
1670
|
+
presenceUpdate(meta: RealtimePayload): void;
|
|
1671
|
+
/** Leave early. Closing the socket does this on its own. */
|
|
1672
|
+
presenceLeave(): void;
|
|
1673
|
+
/** Everyone else currently announced, this client excluded. */
|
|
1674
|
+
presenceOthers(): unknown[];
|
|
1675
|
+
/** Watch the announced set. Called on every change. */
|
|
1676
|
+
onPresence(handler: (others: unknown[]) => void): RealtimeSubscription;
|
|
1604
1677
|
}
|
|
1605
1678
|
declare class PalbeRealtime {
|
|
1606
1679
|
private readonly rt;
|
|
@@ -1608,7 +1681,13 @@ declare class PalbeRealtime {
|
|
|
1608
1681
|
private readonly channels;
|
|
1609
1682
|
private readonly statusStore;
|
|
1610
1683
|
private readonly handlers;
|
|
1684
|
+
private readonly errorHandlers;
|
|
1611
1685
|
private readonly topicRefcount;
|
|
1686
|
+
private readonly states;
|
|
1687
|
+
private readonly connIds;
|
|
1688
|
+
private readonly pendingPresence;
|
|
1689
|
+
private readonly stateWatchers;
|
|
1690
|
+
private readonly presenceWatchers;
|
|
1612
1691
|
constructor(rt: PalbeRuntime);
|
|
1613
1692
|
/**
|
|
1614
1693
|
* Get the handle for an app-defined channel (e.g. "room:42"). The same
|
|
@@ -1624,16 +1703,52 @@ declare class PalbeRealtime {
|
|
|
1624
1703
|
destroy(): void;
|
|
1625
1704
|
/** The observable connection status. Safe to read anywhere (reports `idle` until a socket exists). */
|
|
1626
1705
|
get status(): RealtimeStatus;
|
|
1706
|
+
/**
|
|
1707
|
+
* Hand the socket a fresher credential for the SAME user, without rejoining.
|
|
1708
|
+
*
|
|
1709
|
+
* Called when the app's token rotates. The alternative — letting the channels
|
|
1710
|
+
* die at expiry and rejoining — reaps this connection's ephemeral entries
|
|
1711
|
+
* (its presence, on every channel) and forces a full state resync. A token
|
|
1712
|
+
* getting older is not a disconnection and must not cost one.
|
|
1713
|
+
*
|
|
1714
|
+
* A no-op before a socket exists: the first connect resolves a fresh token
|
|
1715
|
+
* on its own.
|
|
1716
|
+
*/
|
|
1717
|
+
refreshToken(token: string): void;
|
|
1627
1718
|
/** Lazily build + start the shared socket on first subscription/send. */
|
|
1628
1719
|
private ensureSocket;
|
|
1629
1720
|
private route;
|
|
1630
1721
|
/**
|
|
1631
|
-
|
|
1632
|
-
*
|
|
1633
|
-
*
|
|
1634
|
-
*
|
|
1722
|
+
/**
|
|
1723
|
+
* The server refused a channel. Tell whoever asked, and — when the answer is
|
|
1724
|
+
* final — stop pretending the app is subscribed to it.
|
|
1725
|
+
*
|
|
1726
|
+
* `unavailable` leaves everything in place: the project could not be reached
|
|
1727
|
+
* to decide, the socket rejoins on its next reconnect, and dropping the app's
|
|
1728
|
+
* handlers would make a momentary outage look like a permanent denial.
|
|
1729
|
+
*/
|
|
1730
|
+
private handleChannelRefused;
|
|
1731
|
+
/**
|
|
1732
|
+
* A channel died for good — a token-expiry rejoin that exhausted its attempts.
|
|
1733
|
+
* The app must stop expecting anything on it, and the status observable flips
|
|
1734
|
+
* to `'error'` (the React `useChannel` hook reports that).
|
|
1735
|
+
*
|
|
1736
|
+
* It clears the SAME registries a final refusal clears, and used to clear only
|
|
1737
|
+
* the event handlers. A state or presence watcher left behind here waits
|
|
1738
|
+
* forever for a snapshot that cannot arrive, and fires twice if the app ever
|
|
1739
|
+
* re-subscribes — the identical failure its sibling three functions up
|
|
1740
|
+
* describes, on a channel that was given up on rather than refused.
|
|
1635
1741
|
*/
|
|
1636
1742
|
private handleChannelError;
|
|
1743
|
+
/** Drop every registration this topic holds. One place, because "which
|
|
1744
|
+
* registries" is a question two callers must never answer differently. */
|
|
1745
|
+
private forgetTopic;
|
|
1746
|
+
private retainTopic;
|
|
1747
|
+
private releaseTopic;
|
|
1748
|
+
private applySnapshot;
|
|
1749
|
+
private applyDiff;
|
|
1750
|
+
private applyJoinInfo;
|
|
1751
|
+
private notifyState;
|
|
1637
1752
|
}
|
|
1638
1753
|
|
|
1639
1754
|
interface PalbeRuntime {
|
|
@@ -1758,10 +1873,16 @@ declare class PalbeAuth {
|
|
|
1758
1873
|
* Self-service account erasure ("right to be forgotten"). Calls palauth
|
|
1759
1874
|
* `DELETE /auth/user` (session-authed + fresh re-auth): password users pass
|
|
1760
1875
|
* `{ password }`; passwordless/OAuth users rely on a freshly stepped-up
|
|
1761
|
-
* session.
|
|
1762
|
-
* already revoked server-side — so we tear down
|
|
1763
|
-
* `signOut()`'s clear, minus the pointless `/logout`)
|
|
1764
|
-
* `signedOut{reason:'accountDeleted'}`.
|
|
1876
|
+
* session. The handler answers **204 with no body** — the erasure has already
|
|
1877
|
+
* finished and every session is already revoked server-side — so we tear down
|
|
1878
|
+
* local state (mirroring `signOut()`'s clear, minus the pointless `/logout`)
|
|
1879
|
+
* and emit `signedOut{reason:'accountDeleted'}`.
|
|
1880
|
+
*
|
|
1881
|
+
* Returns nothing, because there is nothing to return: the handler used to
|
|
1882
|
+
* answer 202 with an `{erasure_id}` naming an asynchronous run, and that id
|
|
1883
|
+
* was removed along with the run (`gdpr_handlers.go:221-229`). Reading it
|
|
1884
|
+
* here threw a `TypeError` AFTER the account was already gone — a success
|
|
1885
|
+
* reported as a failure.
|
|
1765
1886
|
*
|
|
1766
1887
|
* On 401 `reauth_required` / 503 `not_configured` (or `erasure_unavailable`)
|
|
1767
1888
|
* the request throws BEFORE the teardown line, so the local session is left
|
|
@@ -1769,9 +1890,7 @@ declare class PalbeAuth {
|
|
|
1769
1890
|
*/
|
|
1770
1891
|
deleteAccount(params?: {
|
|
1771
1892
|
password?: string;
|
|
1772
|
-
}): Promise<
|
|
1773
|
-
erasureId: string;
|
|
1774
|
-
}>;
|
|
1893
|
+
}): Promise<void>;
|
|
1775
1894
|
getUser(): Promise<AuthUser>;
|
|
1776
1895
|
/**
|
|
1777
1896
|
* Which credentials this account actually has.
|
|
@@ -2014,4 +2133,4 @@ declare class PalbeAnalytics {
|
|
|
2014
2133
|
private post;
|
|
2015
2134
|
}
|
|
2016
2135
|
|
|
2017
|
-
export { type AuthUser as A, PalbeMessaging as B, Chat as C, type PalbeOAuthConfig as D, PalbeRealtime as E, type FlagsView as F, type PresenceState as G, RealtimeChannel as H, type
|
|
2136
|
+
export { type AuthUser as A, PalbeMessaging as B, Chat as C, type PalbeOAuthConfig as D, PalbeRealtime as E, type FlagsView as F, type PresenceState as G, RealtimeChannel as H, type RealtimeChannelError as I, type RealtimeHandler as J, type RealtimeStatus as K, type RealtimeStatusSnapshot as L, type MagicLinkResult as M, type NotifyScope as N, type OAuthExchangeResult as O, type PalbeConfig as P, type RealtimeSubscription as Q, type RealtimeConnectionState as R, type ResolvedMention as S, type ResolvedReply as T, type SentReceipt as U, type SignInMethods as V, type UnreadView as W, type Unsubscribe as X, PalbePerf as Y, type RealtimePayload as a, type ChatMember as b, type ChatMessage as c, type PalbeRuntime as d, buildRuntime as e, type AnalyticsProperties as f, type AuthChangeEvent as g, type AuthState as h, type AuthSuccess as i, Call as j, type CallChangeCallback as k, type CallParticipant as l, type CallState as m, type ChatBackend as n, type ChatDraft as o, type ChatKind as p, type ChatMessageKind as q, type ChatRole as r, type ChatState as s, type CommsPrefs as t, type MentionRange as u, type MessageDirection as v, PalbeAnalytics as w, PalbeAuth as x, PalbeCalls as y, PalbeFlags as z };
|
|
@@ -612,9 +612,15 @@ declare class PalbeCalls {
|
|
|
612
612
|
* @param media - Which media tracks to publish (default: audio + video)
|
|
613
613
|
* @returns A `Call` in `connecting` state; transitions to `active` once the media room connects.
|
|
614
614
|
*
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
*
|
|
615
|
+
* Every failure below arrives as kind `'server'` — this SDK's error kinds are
|
|
616
|
+
* `notConfigured | validation | unauthorized | rateLimited | server | network
|
|
617
|
+
* | decode`, and only a 401, a 429 or a 400 carrying a field-error array gets
|
|
618
|
+
* its own kind. So branch on `err.code`, never on the kind.
|
|
619
|
+
*
|
|
620
|
+
* @throws BackendError('server', { code: 'calling_unavailable' }) no SFU configured on this stack (503)
|
|
621
|
+
* @throws BackendError('server', { code: 'not_group_member' }) the caller is not a member of the group (403)
|
|
622
|
+
* @throws BackendError('server', { code: 'call_room_full' }) the call is at its participant limit (409)
|
|
623
|
+
* @throws BackendError('server', { code: 'call_provider_error' }) the media provider failed upstream (502)
|
|
618
624
|
*/
|
|
619
625
|
start(groupId: string, { media }?: {
|
|
620
626
|
media?: Array<'audio' | 'video'>;
|
|
@@ -623,7 +629,11 @@ declare class PalbeCalls {
|
|
|
623
629
|
* Accept an incoming call in a messaging group.
|
|
624
630
|
*
|
|
625
631
|
* @param groupId - Messaging group display-id
|
|
626
|
-
* @param callId - Call identifier
|
|
632
|
+
* @param callId - Call identifier, carried by the `call_invite` the server
|
|
633
|
+
* fans onto the group's conversation topic
|
|
634
|
+
* (`pb.realtime.channel('messaging:conv:<rfcGroupId>').on('call_invite', …)`).
|
|
635
|
+
* This SDK ships no web push: on the web the invite arrives over realtime or
|
|
636
|
+
* over whatever signalling the app already runs.
|
|
627
637
|
* @param media - Which media tracks to publish (default: audio + video)
|
|
628
638
|
*/
|
|
629
639
|
accept(groupId: string, callId: string, { media }?: {
|
|
@@ -1579,6 +1589,19 @@ interface RealtimeStatus {
|
|
|
1579
1589
|
readonly lastEventAt: Date | null;
|
|
1580
1590
|
onChange(callback: (status: RealtimeStatusSnapshot) => void): Unsubscribe;
|
|
1581
1591
|
}
|
|
1592
|
+
/** Why the server refused a channel. */
|
|
1593
|
+
interface RealtimeChannelError {
|
|
1594
|
+
/** The channel this is about. */
|
|
1595
|
+
topic: string;
|
|
1596
|
+
/** Exactly what the server said: `"unauthorized"` or `"unavailable"`. */
|
|
1597
|
+
reason: string;
|
|
1598
|
+
/**
|
|
1599
|
+
* Whether asking again could succeed. `unavailable` (the project could not be
|
|
1600
|
+
* reached to decide) is retryable and the socket retries it on reconnect;
|
|
1601
|
+
* `unauthorized` is a settled answer and is not.
|
|
1602
|
+
*/
|
|
1603
|
+
retryable: boolean;
|
|
1604
|
+
}
|
|
1582
1605
|
/**
|
|
1583
1606
|
* A subscription handle for one realtime channel (returned by
|
|
1584
1607
|
* `pb.realtime.channel(name)` — the SAME instance per name). A channel is
|
|
@@ -1595,12 +1618,62 @@ declare class RealtimeChannel {
|
|
|
1595
1618
|
* subscription and `cancel()` it to stop.
|
|
1596
1619
|
*/
|
|
1597
1620
|
on(event: string, handler: RealtimeHandler): RealtimeSubscription;
|
|
1621
|
+
/**
|
|
1622
|
+
* Called when the server REFUSES this channel.
|
|
1623
|
+
*
|
|
1624
|
+
* A join is an authorization decision, and a decision the app never hears is
|
|
1625
|
+
* the same as no decision at all: silence looks exactly like a slow network.
|
|
1626
|
+
* This is where a refusal arrives, carrying the server's own distinction —
|
|
1627
|
+
* `retryable: false` means "you may not" and asking again will not help;
|
|
1628
|
+
* `retryable: true` means the project could not be asked, and the socket's
|
|
1629
|
+
* next reconnect retries on its own.
|
|
1630
|
+
*
|
|
1631
|
+
* pb.realtime.channel('room:42').onError((err) => {
|
|
1632
|
+
* if (!err.retryable) showJoinDenied()
|
|
1633
|
+
* })
|
|
1634
|
+
*/
|
|
1635
|
+
onError(handler: (error: RealtimeChannelError) => void): RealtimeSubscription;
|
|
1598
1636
|
/**
|
|
1599
1637
|
* Broadcast `payload` to the channel's other subscribers (web addition —
|
|
1600
1638
|
* iOS is receive-only). Joins the channel if it isn't already; queued
|
|
1601
1639
|
* until the join is live on the socket.
|
|
1602
1640
|
*/
|
|
1603
1641
|
send(event: string, payload?: RealtimePayload): void;
|
|
1642
|
+
/**
|
|
1643
|
+
* Watch one key of the channel's shared state.
|
|
1644
|
+
*
|
|
1645
|
+
* The handler is called with the CURRENT value straight away when there is
|
|
1646
|
+
* one, and again on every change. That is the difference from `on()`: a
|
|
1647
|
+
* subscriber to an event learns nothing until the next one, while state is
|
|
1648
|
+
* already there when you ask.
|
|
1649
|
+
*/
|
|
1650
|
+
onState(key: string, handler: (value: unknown) => void): RealtimeSubscription;
|
|
1651
|
+
/** Read one key without subscribing. */
|
|
1652
|
+
stateValue(key: string): unknown;
|
|
1653
|
+
/** Write one key. `durable` outlives this connection; `ephemeral` is reaped
|
|
1654
|
+
* when it closes, which is what presence is built on. */
|
|
1655
|
+
setState(key: string, value: unknown, opts?: {
|
|
1656
|
+
life?: 'ephemeral' | 'durable';
|
|
1657
|
+
}): void;
|
|
1658
|
+
/** Remove a key this connection wrote. */
|
|
1659
|
+
clearState(key: string): void;
|
|
1660
|
+
/**
|
|
1661
|
+
* Announce this client on the channel. `meta` is whatever other participants
|
|
1662
|
+
* should see — a name, an avatar, a cursor.
|
|
1663
|
+
*
|
|
1664
|
+
* It is ephemeral state keyed by this connection, so it disappears when the
|
|
1665
|
+
* socket does. Nothing has to be un-announced on a crash.
|
|
1666
|
+
*/
|
|
1667
|
+
presenceEnter(meta: RealtimePayload): void;
|
|
1668
|
+
/** Replace the announced value — a cursor moving is this, at whatever rate
|
|
1669
|
+
* the app likes: the server conflates writes it cannot deliver fast enough. */
|
|
1670
|
+
presenceUpdate(meta: RealtimePayload): void;
|
|
1671
|
+
/** Leave early. Closing the socket does this on its own. */
|
|
1672
|
+
presenceLeave(): void;
|
|
1673
|
+
/** Everyone else currently announced, this client excluded. */
|
|
1674
|
+
presenceOthers(): unknown[];
|
|
1675
|
+
/** Watch the announced set. Called on every change. */
|
|
1676
|
+
onPresence(handler: (others: unknown[]) => void): RealtimeSubscription;
|
|
1604
1677
|
}
|
|
1605
1678
|
declare class PalbeRealtime {
|
|
1606
1679
|
private readonly rt;
|
|
@@ -1608,7 +1681,13 @@ declare class PalbeRealtime {
|
|
|
1608
1681
|
private readonly channels;
|
|
1609
1682
|
private readonly statusStore;
|
|
1610
1683
|
private readonly handlers;
|
|
1684
|
+
private readonly errorHandlers;
|
|
1611
1685
|
private readonly topicRefcount;
|
|
1686
|
+
private readonly states;
|
|
1687
|
+
private readonly connIds;
|
|
1688
|
+
private readonly pendingPresence;
|
|
1689
|
+
private readonly stateWatchers;
|
|
1690
|
+
private readonly presenceWatchers;
|
|
1612
1691
|
constructor(rt: PalbeRuntime);
|
|
1613
1692
|
/**
|
|
1614
1693
|
* Get the handle for an app-defined channel (e.g. "room:42"). The same
|
|
@@ -1624,16 +1703,52 @@ declare class PalbeRealtime {
|
|
|
1624
1703
|
destroy(): void;
|
|
1625
1704
|
/** The observable connection status. Safe to read anywhere (reports `idle` until a socket exists). */
|
|
1626
1705
|
get status(): RealtimeStatus;
|
|
1706
|
+
/**
|
|
1707
|
+
* Hand the socket a fresher credential for the SAME user, without rejoining.
|
|
1708
|
+
*
|
|
1709
|
+
* Called when the app's token rotates. The alternative — letting the channels
|
|
1710
|
+
* die at expiry and rejoining — reaps this connection's ephemeral entries
|
|
1711
|
+
* (its presence, on every channel) and forces a full state resync. A token
|
|
1712
|
+
* getting older is not a disconnection and must not cost one.
|
|
1713
|
+
*
|
|
1714
|
+
* A no-op before a socket exists: the first connect resolves a fresh token
|
|
1715
|
+
* on its own.
|
|
1716
|
+
*/
|
|
1717
|
+
refreshToken(token: string): void;
|
|
1627
1718
|
/** Lazily build + start the shared socket on first subscription/send. */
|
|
1628
1719
|
private ensureSocket;
|
|
1629
1720
|
private route;
|
|
1630
1721
|
/**
|
|
1631
|
-
|
|
1632
|
-
*
|
|
1633
|
-
*
|
|
1634
|
-
*
|
|
1722
|
+
/**
|
|
1723
|
+
* The server refused a channel. Tell whoever asked, and — when the answer is
|
|
1724
|
+
* final — stop pretending the app is subscribed to it.
|
|
1725
|
+
*
|
|
1726
|
+
* `unavailable` leaves everything in place: the project could not be reached
|
|
1727
|
+
* to decide, the socket rejoins on its next reconnect, and dropping the app's
|
|
1728
|
+
* handlers would make a momentary outage look like a permanent denial.
|
|
1729
|
+
*/
|
|
1730
|
+
private handleChannelRefused;
|
|
1731
|
+
/**
|
|
1732
|
+
* A channel died for good — a token-expiry rejoin that exhausted its attempts.
|
|
1733
|
+
* The app must stop expecting anything on it, and the status observable flips
|
|
1734
|
+
* to `'error'` (the React `useChannel` hook reports that).
|
|
1735
|
+
*
|
|
1736
|
+
* It clears the SAME registries a final refusal clears, and used to clear only
|
|
1737
|
+
* the event handlers. A state or presence watcher left behind here waits
|
|
1738
|
+
* forever for a snapshot that cannot arrive, and fires twice if the app ever
|
|
1739
|
+
* re-subscribes — the identical failure its sibling three functions up
|
|
1740
|
+
* describes, on a channel that was given up on rather than refused.
|
|
1635
1741
|
*/
|
|
1636
1742
|
private handleChannelError;
|
|
1743
|
+
/** Drop every registration this topic holds. One place, because "which
|
|
1744
|
+
* registries" is a question two callers must never answer differently. */
|
|
1745
|
+
private forgetTopic;
|
|
1746
|
+
private retainTopic;
|
|
1747
|
+
private releaseTopic;
|
|
1748
|
+
private applySnapshot;
|
|
1749
|
+
private applyDiff;
|
|
1750
|
+
private applyJoinInfo;
|
|
1751
|
+
private notifyState;
|
|
1637
1752
|
}
|
|
1638
1753
|
|
|
1639
1754
|
interface PalbeRuntime {
|
|
@@ -1758,10 +1873,16 @@ declare class PalbeAuth {
|
|
|
1758
1873
|
* Self-service account erasure ("right to be forgotten"). Calls palauth
|
|
1759
1874
|
* `DELETE /auth/user` (session-authed + fresh re-auth): password users pass
|
|
1760
1875
|
* `{ password }`; passwordless/OAuth users rely on a freshly stepped-up
|
|
1761
|
-
* session.
|
|
1762
|
-
* already revoked server-side — so we tear down
|
|
1763
|
-
* `signOut()`'s clear, minus the pointless `/logout`)
|
|
1764
|
-
* `signedOut{reason:'accountDeleted'}`.
|
|
1876
|
+
* session. The handler answers **204 with no body** — the erasure has already
|
|
1877
|
+
* finished and every session is already revoked server-side — so we tear down
|
|
1878
|
+
* local state (mirroring `signOut()`'s clear, minus the pointless `/logout`)
|
|
1879
|
+
* and emit `signedOut{reason:'accountDeleted'}`.
|
|
1880
|
+
*
|
|
1881
|
+
* Returns nothing, because there is nothing to return: the handler used to
|
|
1882
|
+
* answer 202 with an `{erasure_id}` naming an asynchronous run, and that id
|
|
1883
|
+
* was removed along with the run (`gdpr_handlers.go:221-229`). Reading it
|
|
1884
|
+
* here threw a `TypeError` AFTER the account was already gone — a success
|
|
1885
|
+
* reported as a failure.
|
|
1765
1886
|
*
|
|
1766
1887
|
* On 401 `reauth_required` / 503 `not_configured` (or `erasure_unavailable`)
|
|
1767
1888
|
* the request throws BEFORE the teardown line, so the local session is left
|
|
@@ -1769,9 +1890,7 @@ declare class PalbeAuth {
|
|
|
1769
1890
|
*/
|
|
1770
1891
|
deleteAccount(params?: {
|
|
1771
1892
|
password?: string;
|
|
1772
|
-
}): Promise<
|
|
1773
|
-
erasureId: string;
|
|
1774
|
-
}>;
|
|
1893
|
+
}): Promise<void>;
|
|
1775
1894
|
getUser(): Promise<AuthUser>;
|
|
1776
1895
|
/**
|
|
1777
1896
|
* Which credentials this account actually has.
|
|
@@ -2014,4 +2133,4 @@ declare class PalbeAnalytics {
|
|
|
2014
2133
|
private post;
|
|
2015
2134
|
}
|
|
2016
2135
|
|
|
2017
|
-
export { type AuthUser as A, PalbeMessaging as B, Chat as C, type PalbeOAuthConfig as D, PalbeRealtime as E, type FlagsView as F, type PresenceState as G, RealtimeChannel as H, type
|
|
2136
|
+
export { type AuthUser as A, PalbeMessaging as B, Chat as C, type PalbeOAuthConfig as D, PalbeRealtime as E, type FlagsView as F, type PresenceState as G, RealtimeChannel as H, type RealtimeChannelError as I, type RealtimeHandler as J, type RealtimeStatus as K, type RealtimeStatusSnapshot as L, type MagicLinkResult as M, type NotifyScope as N, type OAuthExchangeResult as O, type PalbeConfig as P, type RealtimeSubscription as Q, type RealtimeConnectionState as R, type ResolvedMention as S, type ResolvedReply as T, type SentReceipt as U, type SignInMethods as V, type UnreadView as W, type Unsubscribe as X, PalbePerf as Y, type RealtimePayload as a, type ChatMember as b, type ChatMessage as c, type PalbeRuntime as d, buildRuntime as e, type AnalyticsProperties as f, type AuthChangeEvent as g, type AuthState as h, type AuthSuccess as i, Call as j, type CallChangeCallback as k, type CallParticipant as l, type CallState as m, type ChatBackend as n, type ChatDraft as o, type ChatKind as p, type ChatMessageKind as q, type ChatRole as r, type ChatState as s, type CommsPrefs as t, type MentionRange as u, type MessageDirection as v, PalbeAnalytics as w, PalbeAuth as x, PalbeCalls as y, PalbeFlags as z };
|
|
@@ -144,6 +144,15 @@ function parseEnvironmentRef(apiKey) {
|
|
|
144
144
|
var MAX_RETRIES = 3;
|
|
145
145
|
var INITIAL_BACKOFF_MS = 200;
|
|
146
146
|
var MAX_RETRY_DELAY_MS = 1e4;
|
|
147
|
+
function withRetryHint(body, response) {
|
|
148
|
+
if (response.status !== 429) return body;
|
|
149
|
+
const data = body?.data;
|
|
150
|
+
const alreadyStated = typeof body?.retry_after === "number" || typeof data === "object" && data !== null && "retryAfter" in data;
|
|
151
|
+
if (alreadyStated) return body;
|
|
152
|
+
const seconds = Number.parseInt(response.headers.get("Retry-After") ?? "", 10);
|
|
153
|
+
if (Number.isNaN(seconds) || seconds <= 0) return body;
|
|
154
|
+
return { ...body, retry_after: seconds };
|
|
155
|
+
}
|
|
147
156
|
var HttpClient = class _HttpClient {
|
|
148
157
|
apiKey;
|
|
149
158
|
options;
|
|
@@ -319,7 +328,7 @@ var HttpClient = class _HttpClient {
|
|
|
319
328
|
errorBody?.error ?? "unknown_error",
|
|
320
329
|
errorBody?.error_description ?? response.statusText,
|
|
321
330
|
response.status,
|
|
322
|
-
errorBody
|
|
331
|
+
withRetryHint(errorBody, response)
|
|
323
332
|
),
|
|
324
333
|
status: response.status
|
|
325
334
|
};
|
|
@@ -442,6 +451,15 @@ function isFieldErrorArray(value) {
|
|
|
442
451
|
(v) => typeof v === "object" && v !== null && typeof v.field === "string" && typeof v.message === "string"
|
|
443
452
|
);
|
|
444
453
|
}
|
|
454
|
+
function fieldErrorsOf(envelope) {
|
|
455
|
+
const scoped = pickField(pickField(envelope, "data"), "fields");
|
|
456
|
+
if (isFieldErrorArray(scoped)) return scoped;
|
|
457
|
+
const flat = pickField(envelope, "fields");
|
|
458
|
+
return isFieldErrorArray(flat) ? flat : void 0;
|
|
459
|
+
}
|
|
460
|
+
function retryAfterOf(envelope) {
|
|
461
|
+
return pickNumber(envelope, "retry_after") ?? pickNumber(pickField(envelope, "data"), "retryAfter");
|
|
462
|
+
}
|
|
445
463
|
function pickField(value, key) {
|
|
446
464
|
if (typeof value === "object" && value !== null) {
|
|
447
465
|
return value[key];
|
|
@@ -467,20 +485,15 @@ function fromPalbaseError(err) {
|
|
|
467
485
|
if (err.code === "network_error") return new BackendError("network", base);
|
|
468
486
|
if (err.status === 401) return new BackendError("unauthorized", base);
|
|
469
487
|
if (err.status === 429)
|
|
470
|
-
return new BackendError("rateLimited", {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
});
|
|
474
|
-
const nested = pickField(err.details, "details");
|
|
475
|
-
if (err.status === 400 && isFieldErrorArray(nested))
|
|
476
|
-
return new BackendError("validation", { ...base, fields: nested });
|
|
488
|
+
return new BackendError("rateLimited", { ...base, retryAfter: retryAfterOf(err.details) });
|
|
489
|
+
const fields = fieldErrorsOf(err.details);
|
|
490
|
+
if (err.status === 400 && fields) return new BackendError("validation", { ...base, fields });
|
|
477
491
|
return new BackendError("server", base);
|
|
478
492
|
}
|
|
479
493
|
function fromEnvelope(status, body) {
|
|
480
494
|
const code = pickString(body, "error") ?? "http_error";
|
|
481
495
|
const message = pickString(body, "error_description") ?? `HTTP ${status}`;
|
|
482
496
|
const requestId = pickString(body, "request_id");
|
|
483
|
-
const details = pickField(body, "details");
|
|
484
497
|
const params = {
|
|
485
498
|
code,
|
|
486
499
|
message,
|
|
@@ -490,13 +503,9 @@ function fromEnvelope(status, body) {
|
|
|
490
503
|
};
|
|
491
504
|
if (status === 401) return new BackendError("unauthorized", params);
|
|
492
505
|
if (status === 429)
|
|
493
|
-
return new BackendError("rateLimited", {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
retryAfter: pickNumber(body, "retry_after") ?? pickNumber(details, "retry_after")
|
|
497
|
-
});
|
|
498
|
-
if (status === 400 && isFieldErrorArray(details))
|
|
499
|
-
return new BackendError("validation", { ...params, fields: details });
|
|
506
|
+
return new BackendError("rateLimited", { ...params, retryAfter: retryAfterOf(body) });
|
|
507
|
+
const fields = fieldErrorsOf(body);
|
|
508
|
+
if (status === 400 && fields) return new BackendError("validation", { ...params, fields });
|
|
500
509
|
return new BackendError("server", params);
|
|
501
510
|
}
|
|
502
511
|
function isBackendError(e) {
|
|
@@ -525,4 +534,4 @@ export {
|
|
|
525
534
|
asPalbaseError,
|
|
526
535
|
unwrap
|
|
527
536
|
};
|
|
528
|
-
//# sourceMappingURL=chunk-
|
|
537
|
+
//# sourceMappingURL=chunk-4WMJTUDN.js.map
|