@palbase/web 2.0.1 → 4.0.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 +11 -9
- package/dist/{analytics-facade-ChlBRcLZ.d.cts → analytics-facade-DwOtlXPP.d.cts} +13 -103
- package/dist/{analytics-facade-G0il4NrT.d.ts → analytics-facade-Nk6J9Ncm.d.ts} +13 -103
- package/dist/{chunk-VJXFABBW.js → chunk-6VGKMNXO.js} +11 -11
- package/dist/chunk-6VGKMNXO.js.map +1 -0
- package/dist/{chunk-AIPUO4QX.js → chunk-NP4NIY7A.js} +52 -48
- package/dist/chunk-NP4NIY7A.js.map +1 -0
- package/dist/chunk-S7NAY3MW.js +24 -0
- package/dist/chunk-S7NAY3MW.js.map +1 -0
- package/dist/gen/cli.cjs +32 -6
- package/dist/gen/cli.cjs.map +1 -1
- package/dist/gen/cli.js +28 -7
- package/dist/gen/cli.js.map +1 -1
- package/dist/index.cjs +25 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.js +2 -2
- package/dist/internal.cjs +55 -44
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +4 -16
- package/dist/internal.d.ts +4 -16
- package/dist/internal.js +2 -2
- package/dist/next/client.cjs +72 -58
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.d.cts +1 -1
- package/dist/next/client.d.ts +1 -1
- package/dist/next/client.js +12 -10
- package/dist/next/client.js.map +1 -1
- package/dist/next/index.cjs +75 -59
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +10 -11
- package/dist/next/index.d.ts +10 -11
- package/dist/next/index.js +14 -13
- package/dist/next/index.js.map +1 -1
- package/dist/{pb-B_6o5p79.d.cts → pb-C9v5dEO6.d.cts} +1 -1
- package/dist/{pb-nPBhqhJr.d.ts → pb-FG_nV7NR.d.ts} +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1 -2
- package/dist/react/index.d.ts +1 -2
- package/dist/react/index.js +2 -2
- package/package.json +3 -3
- package/dist/chunk-AIPUO4QX.js.map +0 -1
- package/dist/chunk-PZ5AY32C.js +0 -10
- package/dist/chunk-PZ5AY32C.js.map +0 -1
- package/dist/chunk-VJXFABBW.js.map +0 -1
package/README.md
CHANGED
|
@@ -29,18 +29,20 @@ Then link your project and generate the typed client:
|
|
|
29
29
|
npx palbase web link
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
`palbase web link` writes
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
`palbase web link` writes the committed generator inputs
|
|
33
|
+
`Palbase/openapi.json` and `Palbase/palbase-config.json`, runs `palbe-gen` when
|
|
34
|
+
`@palbase/web` is installed, wires `import './palbe.gen';` into your app entry,
|
|
35
|
+
and adds a `predev`/`prebuild` hook that keeps the typed client in sync. Commit
|
|
36
|
+
the `Palbase/` inputs and `palbe.gen.ts`; the generated client is source your app
|
|
37
|
+
imports, not a build artifact.
|
|
38
|
+
|
|
39
|
+
The generated file calls `__configure(...)` with the linked Environment ref,
|
|
40
|
+
URL, app ID, and publishable API key at module load, so importing it once at
|
|
41
|
+
startup is all the setup there is.
|
|
40
42
|
If you forget to import it, every `pb` call throws a guided `BackendError`
|
|
41
43
|
(`kind: 'notConfigured'`).
|
|
42
44
|
|
|
43
|
-
> Regenerate any time your backend changes: `npx
|
|
45
|
+
> Regenerate any time your backend changes: `npx palbe-gen` (or just run
|
|
44
46
|
> `dev`/`build` — the hook does it for you).
|
|
45
47
|
|
|
46
48
|
---
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Room, ExternalE2EEKeyProvider } from 'livekit-client';
|
|
2
1
|
import { S as SessionStorageAdapter } from './storage-BPaeSG8K.cjs';
|
|
3
2
|
import { F } from './pooled-flags-4GtDtsiu.js';
|
|
4
3
|
|
|
@@ -79,8 +78,7 @@ declare class HttpClient$1 {
|
|
|
79
78
|
* with the parent at runtime — later changes on the parent propagate to
|
|
80
79
|
* the scope and vice versa.
|
|
81
80
|
*
|
|
82
|
-
* Typical use:
|
|
83
|
-
* gateway can route them to the correct project's data plane.
|
|
81
|
+
* Typical use: adding an Environment-routing header for an admin call.
|
|
84
82
|
*/
|
|
85
83
|
withHeaders(extra: Record<string, string>): HttpClient$1;
|
|
86
84
|
/** Add a request interceptor. Runs before every request. */
|
|
@@ -169,8 +167,7 @@ declare class HttpClient {
|
|
|
169
167
|
* with the parent at runtime — later changes on the parent propagate to
|
|
170
168
|
* the scope and vice versa.
|
|
171
169
|
*
|
|
172
|
-
* Typical use:
|
|
173
|
-
* gateway can route them to the correct project's data plane.
|
|
170
|
+
* Typical use: adding an Environment-routing header for an admin call.
|
|
174
171
|
*/
|
|
175
172
|
withHeaders(extra: Record<string, string>): HttpClient;
|
|
176
173
|
/** Add a request interceptor. Runs before every request. */
|
|
@@ -535,12 +532,9 @@ declare class Call {
|
|
|
535
532
|
private readonly _listeners;
|
|
536
533
|
private readonly _room;
|
|
537
534
|
private readonly _keyProvider;
|
|
538
|
-
/** @internal — obtain via PalbeCalls.start() / .accept() */
|
|
539
|
-
constructor(callId: string, room: Room, keyProvider: ExternalE2EEKeyProvider);
|
|
540
535
|
get state(): CallState;
|
|
541
536
|
/** Snapshot of current remote participants (does NOT include the local participant). */
|
|
542
537
|
get participants(): readonly CallParticipant[];
|
|
543
|
-
get localParticipant(): Room['localParticipant'];
|
|
544
538
|
/**
|
|
545
539
|
* Subscribe to call changes (state + participant updates).
|
|
546
540
|
* Returns an `Unsubscribe` function — matches the SDK's flags/auth pattern.
|
|
@@ -553,7 +547,7 @@ declare class Call {
|
|
|
553
547
|
/**
|
|
554
548
|
* Set a raw frame encryption key (ArrayBuffer) for this call.
|
|
555
549
|
* Design seam for SP-1.x web-MLS: call this with the MLS exporter secret
|
|
556
|
-
* to enable frame-level E2EE via
|
|
550
|
+
* to enable frame-level E2EE via the media engine's external key provider.
|
|
557
551
|
*
|
|
558
552
|
* NOTE: The room must have been opened with `e2ee` options for this to take
|
|
559
553
|
* effect. Currently calls connect WITHOUT e2ee — see module docstring.
|
|
@@ -561,13 +555,13 @@ declare class Call {
|
|
|
561
555
|
* TODO(SP-1-web): wire this to MLS-derived key on session join.
|
|
562
556
|
*/
|
|
563
557
|
setMediaKey(key: ArrayBuffer): Promise<void>;
|
|
564
|
-
/** Leave the call and disconnect from the
|
|
558
|
+
/** Leave the call and disconnect from the media room. */
|
|
565
559
|
leave(): Promise<void>;
|
|
566
560
|
private _setState;
|
|
567
561
|
private _emit;
|
|
568
562
|
private _upsertParticipant;
|
|
569
563
|
private _attachTrack;
|
|
570
|
-
private
|
|
564
|
+
private _wireMediaEvents;
|
|
571
565
|
}
|
|
572
566
|
declare class PalbeCalls {
|
|
573
567
|
private readonly rt;
|
|
@@ -577,9 +571,9 @@ declare class PalbeCalls {
|
|
|
577
571
|
*
|
|
578
572
|
* @param groupId - Messaging group display-id (`grp_<uuidv7>`)
|
|
579
573
|
* @param media - Which media tracks to publish (default: audio + video)
|
|
580
|
-
* @returns A `Call` in `connecting` state; transitions to `active` once
|
|
574
|
+
* @returns A `Call` in `connecting` state; transitions to `active` once the media room connects.
|
|
581
575
|
*
|
|
582
|
-
* @throws BackendError('network', { code: 'call_service_unavailable' }) if
|
|
576
|
+
* @throws BackendError('network', { code: 'call_service_unavailable' }) if the SFU is down (503)
|
|
583
577
|
* @throws BackendError('forbidden', { code: 'not_group_member' }) if the caller is not a member (403)
|
|
584
578
|
* @throws BackendError('conflict', { code: 'call_room_full' }) if the room is full (409)
|
|
585
579
|
*/
|
|
@@ -622,19 +616,13 @@ interface PalbeConfig {
|
|
|
622
616
|
apiKey: string;
|
|
623
617
|
/** Registered app identity persisted by `palbase web link`. */
|
|
624
618
|
appId: string;
|
|
619
|
+
/** Stable reference of the linked Palbase Environment. */
|
|
620
|
+
environmentRef: string;
|
|
621
|
+
oauth?: PalbeOAuthConfig;
|
|
625
622
|
/**
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
* `url` and `apiKey` ALREADY identify the environment (the ref is the host
|
|
629
|
-
* label and is embedded in the key), so nothing at runtime reads this: it is
|
|
630
|
-
* here so a developer looking at the generated file can see WHICH runtime it
|
|
631
|
-
* points at. It replaces the old `branch` field — the Palbase branch is gone
|
|
632
|
-
* as a resource, and a second, drift-prone name for the same runtime is
|
|
633
|
-
* exactly how a build ends up talking to production from a staging checkout.
|
|
623
|
+
* Refresh-token persistence. Default: environment-scoped localStorage in
|
|
624
|
+
* browsers, memory elsewhere.
|
|
634
625
|
*/
|
|
635
|
-
environmentRef?: string;
|
|
636
|
-
oauth?: PalbeOAuthConfig;
|
|
637
|
-
/** Refresh-token persistence. Default: endpoint-scoped localStorage in browsers, memory elsewhere. */
|
|
638
626
|
storage?: SessionStorageAdapter;
|
|
639
627
|
/** Extra headers on every request. */
|
|
640
628
|
headers?: Record<string, string>;
|
|
@@ -654,7 +642,7 @@ type FlagsView = Readonly<Record<string, F>>;
|
|
|
654
642
|
* one-shot snapshot fetches with zero timers and zero storage access, so a
|
|
655
643
|
* pbServer request that reads flags pays exactly one HTTP call.
|
|
656
644
|
*
|
|
657
|
-
* localStorage persistence is scoped per
|
|
645
|
+
* localStorage persistence is scoped per environment ref (`palbe.flags.<ref>`),
|
|
658
646
|
* mirroring the session-storage key convention.
|
|
659
647
|
*/
|
|
660
648
|
declare class PalbeFlags {
|
|
@@ -928,19 +916,6 @@ interface MentionRange {
|
|
|
928
916
|
length: number;
|
|
929
917
|
mentionedUserId: string;
|
|
930
918
|
}
|
|
931
|
-
interface ReactionPayload {
|
|
932
|
-
targetClientMsgId: string;
|
|
933
|
-
emoji: string;
|
|
934
|
-
op: 'add' | 'remove';
|
|
935
|
-
}
|
|
936
|
-
interface EditPayload {
|
|
937
|
-
targetClientMsgId: string;
|
|
938
|
-
newText: string;
|
|
939
|
-
}
|
|
940
|
-
interface DeletePayload {
|
|
941
|
-
targetClientMsgId: string;
|
|
942
|
-
scope: string;
|
|
943
|
-
}
|
|
944
919
|
/** Per-message TTL spec (decoded). senderSendTs present iff start === 'send'. */
|
|
945
920
|
interface ExpirySpec {
|
|
946
921
|
v: number;
|
|
@@ -949,51 +924,6 @@ interface ExpirySpec {
|
|
|
949
924
|
senderSendTs: number | null;
|
|
950
925
|
}
|
|
951
926
|
|
|
952
|
-
/** A decoded incoming message handed to chat listeners. */
|
|
953
|
-
interface IncomingMessage {
|
|
954
|
-
kind: 'application' | 'commit' | 'proposal' | 'welcome';
|
|
955
|
-
group: MessagingGroup;
|
|
956
|
-
text: string | null;
|
|
957
|
-
senderDeviceId: string | null;
|
|
958
|
-
epoch: number;
|
|
959
|
-
serverSeq: number;
|
|
960
|
-
receivedAt: Date;
|
|
961
|
-
/** The client-minted idempotency id from the decoded envelope (empty string for legacy/system). */
|
|
962
|
-
clientMsgId: string;
|
|
963
|
-
/** The decoded reply reference, if present in the envelope. */
|
|
964
|
-
replyRef: ReplyRef | null;
|
|
965
|
-
/**
|
|
966
|
-
* The decoded envelope discriminator (`'text'`/`'reaction'`/`'media'`/…).
|
|
967
|
-
* Defaults to `'text'` at every existing call site — only the reaction branch
|
|
968
|
-
* sets `'reaction'`, so the Chat can route a reaction into its fold instead of
|
|
969
|
-
* appending a visible bubble. Optional for forward-compat with old emitters.
|
|
970
|
-
*/
|
|
971
|
-
envelopeType?: string;
|
|
972
|
-
/** The decoded reaction payload, present only when `envelopeType === 'reaction'`. */
|
|
973
|
-
reaction?: ReactionPayload | null;
|
|
974
|
-
/** The decoded edit payload, present only when `envelopeType === 'edit'`. Lets
|
|
975
|
-
* the Chat route an edit into its EditFold instead of appending a visible bubble. */
|
|
976
|
-
edit?: EditPayload | null;
|
|
977
|
-
/** The decoded delete payload, present only when `envelopeType === 'delete'`. Lets
|
|
978
|
-
* the Chat route a delete-for-everyone tombstone into its DeleteFold instead of
|
|
979
|
-
* appending a visible bubble. */
|
|
980
|
-
delete?: DeletePayload | null;
|
|
981
|
-
/** The decoded mention ranges (raw, un-normalized). Present on a `'text'` bubble
|
|
982
|
-
* with `body_ranges` OR on an `'edit'` (the edit's replacement ranges). The Chat
|
|
983
|
-
* normalizes + resolves roster names → `ChatMessage.mentions` (mentions T6). */
|
|
984
|
-
bodyRanges?: MentionRange[] | null;
|
|
985
|
-
/** The decoded `timer_set` payload, present only when `envelopeType === 'timer_set'`
|
|
986
|
-
* (disappearing T10). Lets the Chat route a chat-default timer into its TimerFold
|
|
987
|
-
* instead of appending a visible bubble. */
|
|
988
|
-
timer?: {
|
|
989
|
-
ttlSeconds: number | null;
|
|
990
|
-
start: 'send' | 'read';
|
|
991
|
-
} | null;
|
|
992
|
-
/** The decoded per-message TTL spec, present only on a `'text'` bubble that carried an
|
|
993
|
-
* `expiry` (disappearing T10). Lets the Chat arm the message's purge on first display. */
|
|
994
|
-
expiry?: ExpirySpec | null;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
927
|
/** The intended participants of a draft chat (held until the first send). */
|
|
998
928
|
interface ChatDraft {
|
|
999
929
|
mode: {
|
|
@@ -1171,16 +1101,6 @@ declare class Chat {
|
|
|
1171
1101
|
* the SDK guarantees the DECISION, not the buzz. Mirrors iOS `Chat.onMentionElevation`.
|
|
1172
1102
|
*/
|
|
1173
1103
|
onMentionElevation?: (message: ChatMessage) => void;
|
|
1174
|
-
/** @internal — obtain via pb.messaging.directChat / groupChat / chat(id). */
|
|
1175
|
-
constructor(args: {
|
|
1176
|
-
group: MessagingGroup;
|
|
1177
|
-
kind: ChatKind;
|
|
1178
|
-
backend: ChatBackend;
|
|
1179
|
-
} | {
|
|
1180
|
-
draft: ChatDraft;
|
|
1181
|
-
kind: ChatKind;
|
|
1182
|
-
backend: ChatBackend;
|
|
1183
|
-
});
|
|
1184
1104
|
/** Subscribe to any change in this chat (messages/members/typing/state). */
|
|
1185
1105
|
onChange(cb: () => void): Unsubscribe$1;
|
|
1186
1106
|
private emit;
|
|
@@ -1220,8 +1140,6 @@ declare class Chat {
|
|
|
1220
1140
|
private loadElevated;
|
|
1221
1141
|
private hydrateHistory;
|
|
1222
1142
|
private mergeHistory;
|
|
1223
|
-
/** @internal — called by the backend's live subscription. */
|
|
1224
|
-
ingestLive(incoming: IncomingMessage): Promise<void>;
|
|
1225
1143
|
/** Normalize a decoded `IncomingMessage.expiry` / `StoredMessage.expiry` into the
|
|
1226
1144
|
* `ExpirySpec` the arm path consumes (or null when absent). */
|
|
1227
1145
|
private toExpirySpec;
|
|
@@ -1319,8 +1237,6 @@ declare class Chat {
|
|
|
1319
1237
|
* history fold) is preserved. PRESERVES reactions + replyTo.
|
|
1320
1238
|
*/
|
|
1321
1239
|
private applyEditOverlay;
|
|
1322
|
-
/** @internal — called by the backend's conv subscription. */
|
|
1323
|
-
applyConv(event: string, payload: Record<string, unknown>): void;
|
|
1324
1240
|
private kindOf;
|
|
1325
1241
|
private internalKey;
|
|
1326
1242
|
private publicId;
|
|
@@ -1636,8 +1552,6 @@ declare class RealtimeChannel {
|
|
|
1636
1552
|
/** The app-defined channel name (bare sub-topic, no "realtime:" prefix). */
|
|
1637
1553
|
readonly name: string;
|
|
1638
1554
|
private readonly owner;
|
|
1639
|
-
/** @internal — obtain channels via `pb.realtime.channel(name)`. */
|
|
1640
|
-
constructor(name: string, owner: PalbeRealtime);
|
|
1641
1555
|
/**
|
|
1642
1556
|
* Subscribe `handler` to `event` on this channel. Fire-and-forget: the
|
|
1643
1557
|
* join rides the shared socket asynchronously. Hold the returned
|
|
@@ -1673,10 +1587,6 @@ declare class PalbeRealtime {
|
|
|
1673
1587
|
destroy(): void;
|
|
1674
1588
|
/** The observable connection status. Safe to read anywhere (reports `idle` until a socket exists). */
|
|
1675
1589
|
get status(): RealtimeStatus;
|
|
1676
|
-
/** @internal */
|
|
1677
|
-
subscribe(topic: string, event: string, handler: RealtimeHandler): RealtimeSubscription;
|
|
1678
|
-
/** @internal */
|
|
1679
|
-
send(topic: string, event: string, payload: RealtimePayload): void;
|
|
1680
1590
|
/** Lazily build + start the shared socket on first subscription/send. */
|
|
1681
1591
|
private ensureSocket;
|
|
1682
1592
|
private route;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Room, ExternalE2EEKeyProvider } from 'livekit-client';
|
|
2
1
|
import { S as SessionStorageAdapter } from './storage-BPaeSG8K.js';
|
|
3
2
|
import { F } from './pooled-flags-4GtDtsiu.js';
|
|
4
3
|
|
|
@@ -79,8 +78,7 @@ declare class HttpClient$1 {
|
|
|
79
78
|
* with the parent at runtime — later changes on the parent propagate to
|
|
80
79
|
* the scope and vice versa.
|
|
81
80
|
*
|
|
82
|
-
* Typical use:
|
|
83
|
-
* gateway can route them to the correct project's data plane.
|
|
81
|
+
* Typical use: adding an Environment-routing header for an admin call.
|
|
84
82
|
*/
|
|
85
83
|
withHeaders(extra: Record<string, string>): HttpClient$1;
|
|
86
84
|
/** Add a request interceptor. Runs before every request. */
|
|
@@ -169,8 +167,7 @@ declare class HttpClient {
|
|
|
169
167
|
* with the parent at runtime — later changes on the parent propagate to
|
|
170
168
|
* the scope and vice versa.
|
|
171
169
|
*
|
|
172
|
-
* Typical use:
|
|
173
|
-
* gateway can route them to the correct project's data plane.
|
|
170
|
+
* Typical use: adding an Environment-routing header for an admin call.
|
|
174
171
|
*/
|
|
175
172
|
withHeaders(extra: Record<string, string>): HttpClient;
|
|
176
173
|
/** Add a request interceptor. Runs before every request. */
|
|
@@ -535,12 +532,9 @@ declare class Call {
|
|
|
535
532
|
private readonly _listeners;
|
|
536
533
|
private readonly _room;
|
|
537
534
|
private readonly _keyProvider;
|
|
538
|
-
/** @internal — obtain via PalbeCalls.start() / .accept() */
|
|
539
|
-
constructor(callId: string, room: Room, keyProvider: ExternalE2EEKeyProvider);
|
|
540
535
|
get state(): CallState;
|
|
541
536
|
/** Snapshot of current remote participants (does NOT include the local participant). */
|
|
542
537
|
get participants(): readonly CallParticipant[];
|
|
543
|
-
get localParticipant(): Room['localParticipant'];
|
|
544
538
|
/**
|
|
545
539
|
* Subscribe to call changes (state + participant updates).
|
|
546
540
|
* Returns an `Unsubscribe` function — matches the SDK's flags/auth pattern.
|
|
@@ -553,7 +547,7 @@ declare class Call {
|
|
|
553
547
|
/**
|
|
554
548
|
* Set a raw frame encryption key (ArrayBuffer) for this call.
|
|
555
549
|
* Design seam for SP-1.x web-MLS: call this with the MLS exporter secret
|
|
556
|
-
* to enable frame-level E2EE via
|
|
550
|
+
* to enable frame-level E2EE via the media engine's external key provider.
|
|
557
551
|
*
|
|
558
552
|
* NOTE: The room must have been opened with `e2ee` options for this to take
|
|
559
553
|
* effect. Currently calls connect WITHOUT e2ee — see module docstring.
|
|
@@ -561,13 +555,13 @@ declare class Call {
|
|
|
561
555
|
* TODO(SP-1-web): wire this to MLS-derived key on session join.
|
|
562
556
|
*/
|
|
563
557
|
setMediaKey(key: ArrayBuffer): Promise<void>;
|
|
564
|
-
/** Leave the call and disconnect from the
|
|
558
|
+
/** Leave the call and disconnect from the media room. */
|
|
565
559
|
leave(): Promise<void>;
|
|
566
560
|
private _setState;
|
|
567
561
|
private _emit;
|
|
568
562
|
private _upsertParticipant;
|
|
569
563
|
private _attachTrack;
|
|
570
|
-
private
|
|
564
|
+
private _wireMediaEvents;
|
|
571
565
|
}
|
|
572
566
|
declare class PalbeCalls {
|
|
573
567
|
private readonly rt;
|
|
@@ -577,9 +571,9 @@ declare class PalbeCalls {
|
|
|
577
571
|
*
|
|
578
572
|
* @param groupId - Messaging group display-id (`grp_<uuidv7>`)
|
|
579
573
|
* @param media - Which media tracks to publish (default: audio + video)
|
|
580
|
-
* @returns A `Call` in `connecting` state; transitions to `active` once
|
|
574
|
+
* @returns A `Call` in `connecting` state; transitions to `active` once the media room connects.
|
|
581
575
|
*
|
|
582
|
-
* @throws BackendError('network', { code: 'call_service_unavailable' }) if
|
|
576
|
+
* @throws BackendError('network', { code: 'call_service_unavailable' }) if the SFU is down (503)
|
|
583
577
|
* @throws BackendError('forbidden', { code: 'not_group_member' }) if the caller is not a member (403)
|
|
584
578
|
* @throws BackendError('conflict', { code: 'call_room_full' }) if the room is full (409)
|
|
585
579
|
*/
|
|
@@ -622,19 +616,13 @@ interface PalbeConfig {
|
|
|
622
616
|
apiKey: string;
|
|
623
617
|
/** Registered app identity persisted by `palbase web link`. */
|
|
624
618
|
appId: string;
|
|
619
|
+
/** Stable reference of the linked Palbase Environment. */
|
|
620
|
+
environmentRef: string;
|
|
621
|
+
oauth?: PalbeOAuthConfig;
|
|
625
622
|
/**
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
* `url` and `apiKey` ALREADY identify the environment (the ref is the host
|
|
629
|
-
* label and is embedded in the key), so nothing at runtime reads this: it is
|
|
630
|
-
* here so a developer looking at the generated file can see WHICH runtime it
|
|
631
|
-
* points at. It replaces the old `branch` field — the Palbase branch is gone
|
|
632
|
-
* as a resource, and a second, drift-prone name for the same runtime is
|
|
633
|
-
* exactly how a build ends up talking to production from a staging checkout.
|
|
623
|
+
* Refresh-token persistence. Default: environment-scoped localStorage in
|
|
624
|
+
* browsers, memory elsewhere.
|
|
634
625
|
*/
|
|
635
|
-
environmentRef?: string;
|
|
636
|
-
oauth?: PalbeOAuthConfig;
|
|
637
|
-
/** Refresh-token persistence. Default: endpoint-scoped localStorage in browsers, memory elsewhere. */
|
|
638
626
|
storage?: SessionStorageAdapter;
|
|
639
627
|
/** Extra headers on every request. */
|
|
640
628
|
headers?: Record<string, string>;
|
|
@@ -654,7 +642,7 @@ type FlagsView = Readonly<Record<string, F>>;
|
|
|
654
642
|
* one-shot snapshot fetches with zero timers and zero storage access, so a
|
|
655
643
|
* pbServer request that reads flags pays exactly one HTTP call.
|
|
656
644
|
*
|
|
657
|
-
* localStorage persistence is scoped per
|
|
645
|
+
* localStorage persistence is scoped per environment ref (`palbe.flags.<ref>`),
|
|
658
646
|
* mirroring the session-storage key convention.
|
|
659
647
|
*/
|
|
660
648
|
declare class PalbeFlags {
|
|
@@ -928,19 +916,6 @@ interface MentionRange {
|
|
|
928
916
|
length: number;
|
|
929
917
|
mentionedUserId: string;
|
|
930
918
|
}
|
|
931
|
-
interface ReactionPayload {
|
|
932
|
-
targetClientMsgId: string;
|
|
933
|
-
emoji: string;
|
|
934
|
-
op: 'add' | 'remove';
|
|
935
|
-
}
|
|
936
|
-
interface EditPayload {
|
|
937
|
-
targetClientMsgId: string;
|
|
938
|
-
newText: string;
|
|
939
|
-
}
|
|
940
|
-
interface DeletePayload {
|
|
941
|
-
targetClientMsgId: string;
|
|
942
|
-
scope: string;
|
|
943
|
-
}
|
|
944
919
|
/** Per-message TTL spec (decoded). senderSendTs present iff start === 'send'. */
|
|
945
920
|
interface ExpirySpec {
|
|
946
921
|
v: number;
|
|
@@ -949,51 +924,6 @@ interface ExpirySpec {
|
|
|
949
924
|
senderSendTs: number | null;
|
|
950
925
|
}
|
|
951
926
|
|
|
952
|
-
/** A decoded incoming message handed to chat listeners. */
|
|
953
|
-
interface IncomingMessage {
|
|
954
|
-
kind: 'application' | 'commit' | 'proposal' | 'welcome';
|
|
955
|
-
group: MessagingGroup;
|
|
956
|
-
text: string | null;
|
|
957
|
-
senderDeviceId: string | null;
|
|
958
|
-
epoch: number;
|
|
959
|
-
serverSeq: number;
|
|
960
|
-
receivedAt: Date;
|
|
961
|
-
/** The client-minted idempotency id from the decoded envelope (empty string for legacy/system). */
|
|
962
|
-
clientMsgId: string;
|
|
963
|
-
/** The decoded reply reference, if present in the envelope. */
|
|
964
|
-
replyRef: ReplyRef | null;
|
|
965
|
-
/**
|
|
966
|
-
* The decoded envelope discriminator (`'text'`/`'reaction'`/`'media'`/…).
|
|
967
|
-
* Defaults to `'text'` at every existing call site — only the reaction branch
|
|
968
|
-
* sets `'reaction'`, so the Chat can route a reaction into its fold instead of
|
|
969
|
-
* appending a visible bubble. Optional for forward-compat with old emitters.
|
|
970
|
-
*/
|
|
971
|
-
envelopeType?: string;
|
|
972
|
-
/** The decoded reaction payload, present only when `envelopeType === 'reaction'`. */
|
|
973
|
-
reaction?: ReactionPayload | null;
|
|
974
|
-
/** The decoded edit payload, present only when `envelopeType === 'edit'`. Lets
|
|
975
|
-
* the Chat route an edit into its EditFold instead of appending a visible bubble. */
|
|
976
|
-
edit?: EditPayload | null;
|
|
977
|
-
/** The decoded delete payload, present only when `envelopeType === 'delete'`. Lets
|
|
978
|
-
* the Chat route a delete-for-everyone tombstone into its DeleteFold instead of
|
|
979
|
-
* appending a visible bubble. */
|
|
980
|
-
delete?: DeletePayload | null;
|
|
981
|
-
/** The decoded mention ranges (raw, un-normalized). Present on a `'text'` bubble
|
|
982
|
-
* with `body_ranges` OR on an `'edit'` (the edit's replacement ranges). The Chat
|
|
983
|
-
* normalizes + resolves roster names → `ChatMessage.mentions` (mentions T6). */
|
|
984
|
-
bodyRanges?: MentionRange[] | null;
|
|
985
|
-
/** The decoded `timer_set` payload, present only when `envelopeType === 'timer_set'`
|
|
986
|
-
* (disappearing T10). Lets the Chat route a chat-default timer into its TimerFold
|
|
987
|
-
* instead of appending a visible bubble. */
|
|
988
|
-
timer?: {
|
|
989
|
-
ttlSeconds: number | null;
|
|
990
|
-
start: 'send' | 'read';
|
|
991
|
-
} | null;
|
|
992
|
-
/** The decoded per-message TTL spec, present only on a `'text'` bubble that carried an
|
|
993
|
-
* `expiry` (disappearing T10). Lets the Chat arm the message's purge on first display. */
|
|
994
|
-
expiry?: ExpirySpec | null;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
927
|
/** The intended participants of a draft chat (held until the first send). */
|
|
998
928
|
interface ChatDraft {
|
|
999
929
|
mode: {
|
|
@@ -1171,16 +1101,6 @@ declare class Chat {
|
|
|
1171
1101
|
* the SDK guarantees the DECISION, not the buzz. Mirrors iOS `Chat.onMentionElevation`.
|
|
1172
1102
|
*/
|
|
1173
1103
|
onMentionElevation?: (message: ChatMessage) => void;
|
|
1174
|
-
/** @internal — obtain via pb.messaging.directChat / groupChat / chat(id). */
|
|
1175
|
-
constructor(args: {
|
|
1176
|
-
group: MessagingGroup;
|
|
1177
|
-
kind: ChatKind;
|
|
1178
|
-
backend: ChatBackend;
|
|
1179
|
-
} | {
|
|
1180
|
-
draft: ChatDraft;
|
|
1181
|
-
kind: ChatKind;
|
|
1182
|
-
backend: ChatBackend;
|
|
1183
|
-
});
|
|
1184
1104
|
/** Subscribe to any change in this chat (messages/members/typing/state). */
|
|
1185
1105
|
onChange(cb: () => void): Unsubscribe$1;
|
|
1186
1106
|
private emit;
|
|
@@ -1220,8 +1140,6 @@ declare class Chat {
|
|
|
1220
1140
|
private loadElevated;
|
|
1221
1141
|
private hydrateHistory;
|
|
1222
1142
|
private mergeHistory;
|
|
1223
|
-
/** @internal — called by the backend's live subscription. */
|
|
1224
|
-
ingestLive(incoming: IncomingMessage): Promise<void>;
|
|
1225
1143
|
/** Normalize a decoded `IncomingMessage.expiry` / `StoredMessage.expiry` into the
|
|
1226
1144
|
* `ExpirySpec` the arm path consumes (or null when absent). */
|
|
1227
1145
|
private toExpirySpec;
|
|
@@ -1319,8 +1237,6 @@ declare class Chat {
|
|
|
1319
1237
|
* history fold) is preserved. PRESERVES reactions + replyTo.
|
|
1320
1238
|
*/
|
|
1321
1239
|
private applyEditOverlay;
|
|
1322
|
-
/** @internal — called by the backend's conv subscription. */
|
|
1323
|
-
applyConv(event: string, payload: Record<string, unknown>): void;
|
|
1324
1240
|
private kindOf;
|
|
1325
1241
|
private internalKey;
|
|
1326
1242
|
private publicId;
|
|
@@ -1636,8 +1552,6 @@ declare class RealtimeChannel {
|
|
|
1636
1552
|
/** The app-defined channel name (bare sub-topic, no "realtime:" prefix). */
|
|
1637
1553
|
readonly name: string;
|
|
1638
1554
|
private readonly owner;
|
|
1639
|
-
/** @internal — obtain channels via `pb.realtime.channel(name)`. */
|
|
1640
|
-
constructor(name: string, owner: PalbeRealtime);
|
|
1641
1555
|
/**
|
|
1642
1556
|
* Subscribe `handler` to `event` on this channel. Fire-and-forget: the
|
|
1643
1557
|
* join rides the shared socket asynchronously. Hold the returned
|
|
@@ -1673,10 +1587,6 @@ declare class PalbeRealtime {
|
|
|
1673
1587
|
destroy(): void;
|
|
1674
1588
|
/** The observable connection status. Safe to read anywhere (reports `idle` until a socket exists). */
|
|
1675
1589
|
get status(): RealtimeStatus;
|
|
1676
|
-
/** @internal */
|
|
1677
|
-
subscribe(topic: string, event: string, handler: RealtimeHandler): RealtimeSubscription;
|
|
1678
|
-
/** @internal */
|
|
1679
|
-
send(topic: string, event: string, payload: RealtimePayload): void;
|
|
1680
1590
|
/** Lazily build + start the shared socket on first subscription/send. */
|
|
1681
1591
|
private ensureSocket;
|
|
1682
1592
|
private route;
|
|
@@ -6,11 +6,11 @@ var SESSION_COOKIE_ATTRS = {
|
|
|
6
6
|
secure: true,
|
|
7
7
|
maxAge: 2592e3
|
|
8
8
|
};
|
|
9
|
-
function sessionCookieName(
|
|
10
|
-
return `palbe-session-${
|
|
9
|
+
function sessionCookieName(environmentRef) {
|
|
10
|
+
return `palbe-session-${environmentRef}`;
|
|
11
11
|
}
|
|
12
|
-
function encodeSessionCookies(
|
|
13
|
-
const name = sessionCookieName(
|
|
12
|
+
function encodeSessionCookies(environmentRef, session) {
|
|
13
|
+
const name = sessionCookieName(environmentRef);
|
|
14
14
|
const value = encodeURIComponent(
|
|
15
15
|
JSON.stringify({ a: session.accessToken, r: session.refreshToken, e: session.expiresAt })
|
|
16
16
|
);
|
|
@@ -29,15 +29,15 @@ function encodeSessionCookies(endpointRef, session) {
|
|
|
29
29
|
}
|
|
30
30
|
return { set: chunks, clear: [`${name}.${chunks.length}`] };
|
|
31
31
|
}
|
|
32
|
-
function encodeSessionCookiesDecoded(
|
|
33
|
-
const { set, clear } = encodeSessionCookies(
|
|
32
|
+
function encodeSessionCookiesDecoded(environmentRef, session) {
|
|
33
|
+
const { set, clear } = encodeSessionCookies(environmentRef, session);
|
|
34
34
|
return {
|
|
35
35
|
set: set.map(({ name, value }) => ({ name, value: decodeURIComponent(value) })),
|
|
36
36
|
clear
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
-
function decodeSessionCookies(get,
|
|
40
|
-
const base = sessionCookieName(
|
|
39
|
+
function decodeSessionCookies(get, environmentRef) {
|
|
40
|
+
const base = sessionCookieName(environmentRef);
|
|
41
41
|
let encoded = get(base);
|
|
42
42
|
if (encoded === void 0) {
|
|
43
43
|
let joined = "";
|
|
@@ -71,8 +71,8 @@ function parseStoredSession(json) {
|
|
|
71
71
|
return null;
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
function clearedSessionCookieNames(
|
|
75
|
-
const base = sessionCookieName(
|
|
74
|
+
function clearedSessionCookieNames(environmentRef, present) {
|
|
75
|
+
const base = sessionCookieName(environmentRef);
|
|
76
76
|
const names = [];
|
|
77
77
|
if (present(base)) names.push(base);
|
|
78
78
|
for (let i = 0; ; i++) {
|
|
@@ -91,4 +91,4 @@ export {
|
|
|
91
91
|
decodeSessionCookies,
|
|
92
92
|
clearedSessionCookieNames
|
|
93
93
|
};
|
|
94
|
-
//# sourceMappingURL=chunk-
|
|
94
|
+
//# sourceMappingURL=chunk-6VGKMNXO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/next/cookie-codec.ts"],"sourcesContent":["/**\n * Session-cookie codec shared by EVERY palbe/next surface (browser storage\n * adapter, pbServer cookie adapter, middleware, auth callback). Pure\n * functions — no 'next' imports, no palbe runtime imports — so both sides\n * provably read and write the SAME bytes.\n *\n * Format (P3 design contract):\n * - name: `palbe-session-<environmentRef>`; overflow chunk names append `.0`,\n * `.1`, … (cookie names otherwise avoid dots — tooling friendliness).\n * - value: `encodeURIComponent(JSON.stringify({ a, r, e }))` with a=access\n * token, r=refresh token, e=expiry (ms epoch).\n * - one cookie when the encoded value fits MAX_COOKIE_VALUE chars, else\n * chunks ONLY (the base name must not coexist with chunks — callers clear\n * stale names via clearedSessionCookieNames before writing, then honor the\n * encode result's `clear` overflow guard after writing).\n */\n\nexport { environmentRefFromApiKey } from '../api-key.js';\n\nexport interface StoredSession {\n accessToken: string;\n refreshToken: string;\n /** ms epoch */\n expiresAt: number;\n}\n\n/** Browsers cap a cookie at ~4096 bytes incl. name + attributes; 3500 leaves headroom. */\nconst MAX_COOKIE_VALUE = 3500;\n\n/**\n * The P3 cookie contract attributes, shared by every server-side writer\n * (pbServer adapter, middleware, callback); the browser writer mirrors them\n * in document.cookie string form (next/client.ts). NOT HttpOnly by design —\n * the browser SDK must read/write the session (Supabase-paradigm tradeoff);\n * Max-Age = 30d = the refresh-token TTL.\n */\nexport const SESSION_COOKIE_ATTRS = {\n path: '/',\n sameSite: 'lax',\n secure: true,\n maxAge: 2_592_000,\n} as const;\n\nexport function sessionCookieName(environmentRef: string): string {\n return `palbe-session-${environmentRef}`;\n}\n\nexport interface SessionCookieWrite {\n /** Cookies to SET, in order. */\n set: Array<{ name: string; value: string }>;\n /**\n * Names to DELETE alongside the set: the one-past-the-end OVERFLOW GUARD\n * (base write → `.0`; chunks `.0..n` → `.(n+1)`). Decode stops at the\n * first missing chunk, so deleting exactly one-past-the-end guarantees a\n * stale orphan chunk (left behind a gap, where presence-probing cleanup\n * cannot see it) can never concatenate into the freshly written run.\n * Writers MUST honor both lists.\n */\n clear: string[];\n}\n\nexport function encodeSessionCookies(\n environmentRef: string,\n session: StoredSession,\n): SessionCookieWrite {\n const name = sessionCookieName(environmentRef);\n const value = encodeURIComponent(\n JSON.stringify({ a: session.accessToken, r: session.refreshToken, e: session.expiresAt }),\n );\n if (value.length <= MAX_COOKIE_VALUE) {\n return { set: [{ name, value }], clear: [`${name}.0`] };\n }\n const chunks: Array<{ name: string; value: string }> = [];\n // Chunk WITHOUT splitting a %XX escape (every '%' in the encoded value\n // starts one — encodeURIComponent never emits a bare '%'). Next's cookie\n // layer percent-DECODES values on read and silently DROPS a cookie whose\n // value is an invalid escape sequence, so a split escape would lose that\n // chunk server-side; independent decodability also lets\n // encodeSessionCookiesDecoded mirror this run byte-exactly.\n for (let start = 0; start < value.length; ) {\n let end = Math.min(start + MAX_COOKIE_VALUE, value.length);\n if (end < value.length) {\n if (value[end - 1] === '%') end -= 1;\n else if (value[end - 2] === '%') end -= 2;\n }\n chunks.push({ name: `${name}.${chunks.length}`, value: value.slice(start, end) });\n start = end;\n }\n return { set: chunks, clear: [`${name}.${chunks.length}`] };\n}\n\n/**\n * encodeSessionCookies for percent-ENCODING cookie stores. Next's request\n * and response cookie APIs apply encodeURIComponent to values when\n * serializing (and decodeURIComponent on read) — handing them the codec's\n * already-encoded values would DOUBLE-encode the wire bytes and break the\n * browser-side reader. This variant returns the same cookie run with\n * DECODED values: `encodeURIComponent(value)` reproduces the\n * encodeSessionCookies bytes exactly (chunk boundaries never split an\n * escape), so an encoding store writes byte-identical cookies to a raw\n * writer like document.cookie.\n */\nexport function encodeSessionCookiesDecoded(\n environmentRef: string,\n session: StoredSession,\n): SessionCookieWrite {\n const { set, clear } = encodeSessionCookies(environmentRef, session);\n return {\n set: set.map(({ name, value }) => ({ name, value: decodeURIComponent(value) })),\n clear,\n };\n}\n\n/**\n * Read the session back from a cookie getter: the base name wins; otherwise\n * `.0`, `.1`, … are concatenated until the first missing chunk. Tolerant:\n * malformed URI escapes / JSON / shape → null (treated as \"no session\").\n *\n * Accepts BOTH value forms. Next's cookie stores percent-DECODE values once\n * on read, so server-side callers (pbServer adapter, middleware) hand us the\n * already-decoded JSON; raw readers (document.cookie) hand us the encoded\n * form. The raw (already-decoded) parse runs FIRST because it is\n * unambiguous — an encoded value can never raw-parse as JSON\n * (encodeURIComponent escapes `{` itself, so it starts with `%7B`) — whereas\n * decode-first would silently corrupt a literal `%XX` run inside a token\n * (decodeURIComponent('%41') → 'A', no throw) or throw on an invalid escape.\n */\nexport function decodeSessionCookies(\n get: (name: string) => string | undefined,\n environmentRef: string,\n): StoredSession | null {\n const base = sessionCookieName(environmentRef);\n let encoded = get(base);\n if (encoded === undefined) {\n let joined = '';\n for (let i = 0; ; i++) {\n const part = get(`${base}.${i}`);\n if (part === undefined) break;\n joined += part;\n }\n if (joined === '') return null;\n encoded = joined;\n }\n const raw = parseStoredSession(encoded);\n if (raw !== null) return raw;\n try {\n return parseStoredSession(decodeURIComponent(encoded));\n } catch {\n return null;\n }\n}\n\n/** JSON-parse + shape-check one candidate value; malformed → null. */\nfunction parseStoredSession(json: string): StoredSession | null {\n try {\n const parsed: unknown = JSON.parse(json);\n if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {\n const obj = parsed as Record<string, unknown>;\n if (typeof obj.a === 'string' && typeof obj.r === 'string' && typeof obj.e === 'number') {\n return { accessToken: obj.a, refreshToken: obj.r, expiresAt: obj.e };\n }\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Names a writer must delete before/while writing: the base name (when\n * present) plus every existing `.N` chunk, probed in order until the first\n * missing one (writes are always a contiguous `.0..n` run, so a gap means\n * the end of palbe-owned chunks).\n */\nexport function clearedSessionCookieNames(\n environmentRef: string,\n present: (name: string) => boolean,\n): string[] {\n const base = sessionCookieName(environmentRef);\n const names: string[] = [];\n if (present(base)) names.push(base);\n for (let i = 0; ; i++) {\n const chunk = `${base}.${i}`;\n if (!present(chunk)) break;\n names.push(chunk);\n }\n return names;\n}\n\n/**\n * Parse the canonical chunk index out of `palbe-session-<ref>.N`; non-chunk\n * names (the bare base, a foreign ref, junk suffixes like `.x` / `.01` /\n * `.-1`) → null. The index is a non-negative integer with NO leading zeros\n * (the encoder emits `.0`, `.1`, … verbatim), so `String(n) === suffix`\n * round-trips it exactly.\n */\nfunction chunkIndex(base: string, name: string): number | null {\n if (!name.startsWith(`${base}.`)) return null;\n const suffix = name.slice(base.length + 1);\n if (!/^\\d+$/.test(suffix)) return null;\n const idx = Number.parseInt(suffix, 10);\n return String(idx) === suffix ? idx : null;\n}\n\n/**\n * getAll-powered orphan sweep — the deletion list a writer with the FULL\n * cookie jar should clear, catching crash-orphans that presence-probing\n * (clearedSessionCookieNames, which stops at the first gap) CANNOT see.\n *\n * Given every cookie name in the jar, returns the `palbe-session-<ref>`-family\n * names that are NOT part of a single valid session:\n * - A valid session is EITHER the bare base alone, OR the contiguous chunk\n * run `.0, .1, …, n` (starting at `.0`, no gaps).\n * - Any `.N` beyond the first gap from `.0` is an orphan (incl. ALL chunks\n * when `.0` is absent — no run exists).\n * - The base coexisting with ANY chunk is inconsistent (the contract forbids\n * it; decode lets the base win and silently strands the chunks): the base\n * is kept, the chunks are swept (a fresh write replaces the base in place).\n *\n * Only canonical `.N` names count; foreign refs and malformed suffixes are\n * ignored. Output order: base (if inconsistent) first, then chunks ascending.\n */\nexport function orphanSessionCookieNames(environmentRef: string, allNames: string[]): string[] {\n const base = sessionCookieName(environmentRef);\n const hasBase = allNames.includes(base);\n const indices = new Set<number>();\n for (const name of allNames) {\n const idx = chunkIndex(base, name);\n if (idx !== null) indices.add(idx);\n }\n if (indices.size === 0) return []; // unchunked (base alone) or no palbe cookies\n\n // Length of the contiguous run from .0 (0 when .0 is missing).\n let runLen = 0;\n while (indices.has(runLen)) runLen++;\n\n const orphans: string[] = [];\n // Base coexisting with chunks: base wins on decode → chunks are stale.\n // Sweep the base too only when there are NO chunks behind the run to keep\n // (the contract forbids the mix; clearing chunks alone resolves it, but if\n // the run itself is invalid—no .0—the base is the real session and stays).\n // Decision: when base coexists with ANY chunk, the chunks are orphans; the\n // base is the live session and is kept — UNLESS the chunk set forms a valid\n // run AND there is also a gap-orphan, in which case both base+gap-orphan are\n // inconsistent leftovers. Concretely: keep it simple and SAFE — the base is\n // only swept when it sits alongside a partial/gapped chunk set (a crash mid\n // base→chunk migration), never when chunks form a clean run the base shadows.\n const everyChunkContiguous = indices.size === runLen && runLen > 0;\n if (hasBase && !everyChunkContiguous) orphans.push(base);\n\n for (const idx of [...indices].sort((a, b) => a - b)) {\n if (idx >= runLen) orphans.push(`${base}.${idx}`);\n }\n // Base + clean contiguous run: base wins on decode, chunks are stranded.\n if (hasBase && everyChunkContiguous) {\n for (let i = 0; i < runLen; i++) orphans.push(`${base}.${i}`);\n }\n return orphans;\n}\n"],"mappings":"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","names":[]}
|