palbase 0.17.1 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/index.js +2 -2
- package/dist/backend/engine.js +2 -2
- package/dist/backend/env.js +1 -1
- package/dist/backend/index.js +3 -3
- package/dist/backend/stack.js +1 -1
- package/dist/backend/test.js +2 -2
- package/dist/chunks/{OER3S5NN.js → 32XY6IBN.js} +2 -2
- package/dist/chunks/{ZSUSEU5H.js → 3GWBIPGH.js} +2 -2
- package/dist/chunks/{Y6NZV7LU.js → 4HFD24QY.js} +1 -1
- package/dist/chunks/{XT3I7PG3.js → 4S4ODZVM.js} +2 -2
- package/dist/chunks/{KBDCHYSD.js → 6IMY2J5W.js} +1 -1
- package/dist/chunks/{B2IIU37G.js → 7QFBZLAK.js} +1 -1
- package/dist/chunks/{LAHIVWPV.js → 7R4WTDHI.js} +1 -1
- package/dist/chunks/{VXT46THA.js → ART5HP5M.js} +2 -2
- package/dist/chunks/{22M4UQVQ.js → BKGX3AZA.js} +2 -2
- package/dist/chunks/{6WGPEHCE.js → BW5DFI3C.js} +1 -1
- package/dist/chunks/{7C7HACEZ.js → CAZYHE64.js} +2 -2
- package/dist/chunks/EVBWED24.js +22 -0
- package/dist/chunks/{DWRLUP7O.js → FT7G3QQ4.js} +2 -2
- package/dist/chunks/{NJFKRHS6.js → JKA2W4E5.js} +2 -2
- package/dist/chunks/{K23K6ZFG.js → KRQZOF2L.js} +2 -2
- package/dist/chunks/{FWX3RGVS.js → OC32TP3L.js} +2 -2
- package/dist/chunks/{2PIDGENK.js → PMQOJ7FF.js} +2 -2
- package/dist/chunks/{E27BZ5SM.js → PPK2UEAY.js} +2 -2
- package/dist/chunks/{3UVLEWTM.js → T2O6XEQO.js} +1 -1
- package/dist/chunks/{3Y4K6F6T.js → VQXYHAU4.js} +2 -2
- package/dist/chunks/{R7PRW7FG.js → XF3JEDIQ.js} +1 -1
- package/dist/chunks/{LR5ONXTF.js → XHNZDLR4.js} +2 -2
- package/dist/chunks/{CYLNEHKQ.js → ZXV3ZKVM.js} +2 -2
- package/dist/cli.js +2 -2
- package/dist/refuse/ai.js +1 -1
- package/dist/refuse/backend.js +1 -1
- package/dist/refuse/server.js +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/testing.js +2 -2
- package/dist/web/index.js +2 -2
- package/dist/web/message.js +2 -2
- package/dist/web/palbe.js +2 -2
- package/dist/web/paywall.js +2 -2
- package/dist/web/push-sw.js +1 -1
- package/dist/web/ssr.js +2 -2
- package/dist/web/vite.js +2 -2
- package/package.json +2 -2
- package/types/internal/src/messaging/engine.d.ts +31 -0
- package/types/internal/src/messaging/files.d.ts +11 -0
- package/types/internal/src/messaging/index.d.ts +5 -0
- package/types/internal/src/messaging/local.d.ts +31 -0
- package/types/internal/src/messaging/outbox.d.ts +53 -0
- package/types/internal/src/messaging/store.d.ts +67 -0
- package/types/internal/src/modules/purchases.d.ts +2 -2
- package/types/web/src/client.d.ts +5 -0
- package/types/web/src/index.d.ts +1 -0
- package/types/web/src/messaging.d.ts +280 -0
- package/dist/chunks/LIKE2KDM.js +0 -22
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { messaging as api } from '../../internal/src/modules/index.js';
|
|
2
|
+
import { Engine, type Entry, type KeyValue, type OutboxItem, type Touched } from '../../internal/src/messaging/index.js';
|
|
3
|
+
import { type Fetch, type Transport } from '../../internal/src/transport.js';
|
|
4
|
+
import { type SessionManager } from './session.js';
|
|
5
|
+
import type { RealtimeSocket } from './socket.js';
|
|
6
|
+
export type Conversation = api.Conversation;
|
|
7
|
+
export type Message = api.Message;
|
|
8
|
+
export type Member = api.Member;
|
|
9
|
+
export type MyProfile = api.MyProfile;
|
|
10
|
+
export type Profile = api.Profile;
|
|
11
|
+
export type ScheduledMessage = api.ScheduledMessage;
|
|
12
|
+
export type ThreadState = api.ThreadState;
|
|
13
|
+
export type { Entry, OutboxItem } from '../../internal/src/messaging/index.js';
|
|
14
|
+
export interface MessagingOptions {
|
|
15
|
+
/**
|
|
16
|
+
* What the device keeps of a person's conversations when they sign out:
|
|
17
|
+
* dropped unless true — then it is theirs again when they come back, and
|
|
18
|
+
* no one else who signs in on the device reads it.
|
|
19
|
+
*/
|
|
20
|
+
keepOnSignOut?: boolean;
|
|
21
|
+
/** Where the device keeps it: IndexedDB in a browser, memory where there is none, unless given. */
|
|
22
|
+
storage?: KeyValue;
|
|
23
|
+
}
|
|
24
|
+
/** A file to send: its bytes are encrypted on the device before they are uploaded. */
|
|
25
|
+
export interface OutgoingFile {
|
|
26
|
+
data: Blob | Uint8Array;
|
|
27
|
+
contentType: string;
|
|
28
|
+
name?: string;
|
|
29
|
+
width?: number;
|
|
30
|
+
height?: number;
|
|
31
|
+
durationMs?: number;
|
|
32
|
+
/** A small preview the app makes (a blurhash, a tiny data URL): sealed in the message, as the file's key is. */
|
|
33
|
+
thumbnail?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface SendOptions {
|
|
36
|
+
text?: string;
|
|
37
|
+
mentions?: api.Mention[];
|
|
38
|
+
/** The message it answers inline. */
|
|
39
|
+
replyTo?: string;
|
|
40
|
+
/** The message whose thread it answers in. */
|
|
41
|
+
threadId?: string;
|
|
42
|
+
/** A thread's answer the conversation's timeline shows too. */
|
|
43
|
+
alsoInConversation?: boolean;
|
|
44
|
+
files?: OutgoingFile[];
|
|
45
|
+
/** Seconds it lives: from when it is sent, or (expiresFrom 'read') from when everyone it was for read it. */
|
|
46
|
+
expiresIn?: number;
|
|
47
|
+
expiresFrom?: 'send' | 'read';
|
|
48
|
+
/** Its files are seen a limited number of times: once (1) or once more (2), each for seconds at most. */
|
|
49
|
+
viewOnce?: {
|
|
50
|
+
limit: 1 | 2;
|
|
51
|
+
seconds?: number;
|
|
52
|
+
};
|
|
53
|
+
/** Sent then, by the server, the person's device off or not. */
|
|
54
|
+
sendAt?: Date;
|
|
55
|
+
}
|
|
56
|
+
/** A file opened: its bytes, decrypted on the device. */
|
|
57
|
+
export interface OpenedFile {
|
|
58
|
+
id: string;
|
|
59
|
+
name: string | null;
|
|
60
|
+
contentType: string;
|
|
61
|
+
bytes: Uint8Array;
|
|
62
|
+
}
|
|
63
|
+
type Listener = () => void;
|
|
64
|
+
/** Something that keeps itself up to date: state, and a way to hear it change. */
|
|
65
|
+
export interface Observed<S> {
|
|
66
|
+
readonly state: S;
|
|
67
|
+
subscribe(listener: Listener): () => void;
|
|
68
|
+
}
|
|
69
|
+
export interface ConversationListState {
|
|
70
|
+
/** The person's conversations, the latest first. */
|
|
71
|
+
items: Conversation[];
|
|
72
|
+
/** How many messages they have not read, across them. */
|
|
73
|
+
unread: number;
|
|
74
|
+
/** The device's copy was drawn and the sync has caught up. */
|
|
75
|
+
synced: boolean;
|
|
76
|
+
}
|
|
77
|
+
export interface ConversationViewState {
|
|
78
|
+
conversation: Conversation | null;
|
|
79
|
+
/** Its timeline: its messages, the oldest first, then what is on its way. */
|
|
80
|
+
entries: Entry[];
|
|
81
|
+
members: Member[];
|
|
82
|
+
/** Who is typing now, by user id. */
|
|
83
|
+
typing: string[];
|
|
84
|
+
/** Older messages are there to read (loadEarlier). */
|
|
85
|
+
hasEarlier: boolean;
|
|
86
|
+
}
|
|
87
|
+
export interface ThreadViewState {
|
|
88
|
+
root: Message | null;
|
|
89
|
+
entries: Entry[];
|
|
90
|
+
thread: ThreadState | null;
|
|
91
|
+
}
|
|
92
|
+
/** Where a browser keeps it: IndexedDB, one object store of each person's state. */
|
|
93
|
+
export declare function indexedDBKeyValue(name?: string): KeyValue | null;
|
|
94
|
+
type Client = ReturnType<typeof api.client>;
|
|
95
|
+
export declare class Messaging {
|
|
96
|
+
/** The module's API with whoever is signed in now: everything the views do not. */
|
|
97
|
+
readonly api: Client;
|
|
98
|
+
private readonly local;
|
|
99
|
+
private readonly transportFor;
|
|
100
|
+
/** Each person's API: what is done for one — what they wrote, what they read — never goes with another's token. */
|
|
101
|
+
private readonly clients;
|
|
102
|
+
private user;
|
|
103
|
+
private engine;
|
|
104
|
+
private starting;
|
|
105
|
+
private channel;
|
|
106
|
+
private off;
|
|
107
|
+
private readonly heard;
|
|
108
|
+
private synced;
|
|
109
|
+
private syncing;
|
|
110
|
+
private resync;
|
|
111
|
+
private flushing;
|
|
112
|
+
private reflush;
|
|
113
|
+
private retries;
|
|
114
|
+
private timers;
|
|
115
|
+
private readonly delivered;
|
|
116
|
+
private readonly expiring;
|
|
117
|
+
private readonly typingBy;
|
|
118
|
+
private readonly typedAt;
|
|
119
|
+
private readonly loaded;
|
|
120
|
+
private readonly earlier;
|
|
121
|
+
private saving;
|
|
122
|
+
private readonly reopeners;
|
|
123
|
+
private readonly incoming;
|
|
124
|
+
private readonly session;
|
|
125
|
+
private readonly socket;
|
|
126
|
+
private readonly ref;
|
|
127
|
+
private readonly fetchFn;
|
|
128
|
+
private readonly opts;
|
|
129
|
+
constructor(transport: Transport, transportFor: (user: string) => Transport, session: SessionManager, socket: RealtimeSocket, ref: string, fetchFn: Fetch, opts?: MessagingOptions);
|
|
130
|
+
/**
|
|
131
|
+
* Starts following the signed-in person's conversations — the views do it
|
|
132
|
+
* themselves: the device's copy first, then the person's channel and the
|
|
133
|
+
* sync. Rejects when no one is signed in.
|
|
134
|
+
*/
|
|
135
|
+
ready(): Promise<Engine>;
|
|
136
|
+
/** The person signed out (or another signed in): what the device keeps is dropped unless kept, and nothing of theirs is followed. */
|
|
137
|
+
private end;
|
|
138
|
+
private unfollow;
|
|
139
|
+
private follow;
|
|
140
|
+
/** The app is back (online, in view): catch up and send what waits. */
|
|
141
|
+
private wake;
|
|
142
|
+
/** Reads what changed since the cursor the device holds, until nothing is left. */
|
|
143
|
+
sync(): Promise<void>;
|
|
144
|
+
/**
|
|
145
|
+
* Tells the app of a message someone else wrote, as it comes live — what an app shows a banner of while it is in
|
|
146
|
+
* front (its pushes are not shown then): once, never what a sync or a page reads, an edit, a removal or the
|
|
147
|
+
* person's own. Returns the unsubscribe.
|
|
148
|
+
*/
|
|
149
|
+
onIncoming(listener: (m: Message) => void): () => void;
|
|
150
|
+
private heardLive;
|
|
151
|
+
/** Applies what changed to the person's conversations — to e's alone: what came for one who is gone goes nowhere. */
|
|
152
|
+
private changed;
|
|
153
|
+
/** What follows a change: timers to take messages away, deliveries told, the device's copy saved. */
|
|
154
|
+
private after;
|
|
155
|
+
/** A message whose time is up goes from the device at once: the server says so too, a moment after. */
|
|
156
|
+
private expireAt;
|
|
157
|
+
private deliver;
|
|
158
|
+
private save;
|
|
159
|
+
/** Sends what waits, in each conversation's order; tries again later while the network or the server is away. */
|
|
160
|
+
flush(): Promise<void>;
|
|
161
|
+
/** Sends one message with its writer's token — none other: signed out meanwhile, it waits for them. */
|
|
162
|
+
private post;
|
|
163
|
+
private presence;
|
|
164
|
+
private as;
|
|
165
|
+
/** The signed-in person's place: what is done for them goes with their token, and comes back to them alone. */
|
|
166
|
+
private seat;
|
|
167
|
+
private typed;
|
|
168
|
+
private tell;
|
|
169
|
+
/** The person's conversations, the latest first, kept up to date. */
|
|
170
|
+
conversations(): ConversationList;
|
|
171
|
+
/** A conversation of the person's, kept up to date: its timeline, its members, who is typing. */
|
|
172
|
+
conversation(conversationId: string): ConversationView;
|
|
173
|
+
/** The direct conversation with someone — the one there is, or a new one. */
|
|
174
|
+
direct(userId: string): Promise<ConversationView>;
|
|
175
|
+
/** A new group, the person its owner. */
|
|
176
|
+
group(input: {
|
|
177
|
+
title: string;
|
|
178
|
+
memberIds?: string[];
|
|
179
|
+
description?: string;
|
|
180
|
+
photo?: string;
|
|
181
|
+
settings?: api.GroupSettings;
|
|
182
|
+
}): Promise<{
|
|
183
|
+
conversation: ConversationView;
|
|
184
|
+
notAdded: api.NotAdded[];
|
|
185
|
+
}>;
|
|
186
|
+
/** A thread: a message's answers, kept up to date. */
|
|
187
|
+
thread(conversationId: string, rootId: string): ThreadView;
|
|
188
|
+
/** The person's messages scheduled for later, kept up to date. */
|
|
189
|
+
scheduled(): ScheduledList;
|
|
190
|
+
/** The threads the person follows, the latest answered first. */
|
|
191
|
+
threads(): Promise<api.ThreadItem[]>;
|
|
192
|
+
/** Writes a message: drawn at once, sent now or once the network is back — once. A message for later is in scheduled(). */
|
|
193
|
+
send(conversationId: string, input: string | SendOptions): Promise<OutboxItem>;
|
|
194
|
+
/** Each file encrypted with a key of its own, uploaded: what a message carries of them. */
|
|
195
|
+
private upload;
|
|
196
|
+
/** A file of a message, downloaded and decrypted on the device. A message seen once gives its files by viewOnce alone. */
|
|
197
|
+
open(message: Message, attachmentId: string): Promise<OpenedFile>;
|
|
198
|
+
/** Opens a message seen a limited number of times: its files, decrypted — held by the app, never by the device. */
|
|
199
|
+
viewOnce(message: Message): Promise<OpenedFile[]>;
|
|
200
|
+
private bytes;
|
|
201
|
+
edit(conversationId: string, messageId: string, text: string, mentions?: api.Mention[]): Promise<Message>;
|
|
202
|
+
/** Removes a message: for everyone (its writer, within 48 hours; a group's admin) or for the person alone. */
|
|
203
|
+
remove(conversationId: string, messageId: string, scope?: 'everyone' | 'me'): Promise<void>;
|
|
204
|
+
/** Reacts with an emoji, beside the person's other reactions (replace: in their place). */
|
|
205
|
+
react(conversationId: string, messageId: string, emoji: string, opts?: {
|
|
206
|
+
replace?: boolean;
|
|
207
|
+
}): Promise<Message>;
|
|
208
|
+
unreact(conversationId: string, messageId: string, emoji: string): Promise<Message>;
|
|
209
|
+
/** The person read a conversation up to seq (its last message unless given): their unread count goes, and the others see it unless reads are hidden. */
|
|
210
|
+
markRead(conversationId: string, seq?: number, threadId?: string): Promise<void>;
|
|
211
|
+
/** The person is typing: told to the others, at most every two seconds. */
|
|
212
|
+
typing(conversationId: string, threadId?: string): Promise<void>;
|
|
213
|
+
/** Changes a conversation: its title, picture, timer, vanish mode, policies. */
|
|
214
|
+
update(conversationId: string, change: api.UpdateConversation): Promise<Conversation>;
|
|
215
|
+
/** The person leaves a conversation in vanish mode: what they read in it goes. */
|
|
216
|
+
close(conversationId: string): Promise<void>;
|
|
217
|
+
/** The person took a screenshot of a conversation: the others are told (an app on a phone knows it; a browser does not). */
|
|
218
|
+
screenshot(conversationId: string): Promise<Message>;
|
|
219
|
+
leave(conversationId: string): Promise<void>;
|
|
220
|
+
deleteConversation(conversationId: string): Promise<void>;
|
|
221
|
+
notifications(conversationId: string, change: api.NotificationsRequest): Promise<void>;
|
|
222
|
+
cancelScheduled(id: string): Promise<void>;
|
|
223
|
+
editScheduled(id: string, change: api.UpdateScheduled): Promise<ScheduledMessage>;
|
|
224
|
+
me(): Promise<MyProfile>;
|
|
225
|
+
/** Changes the person's profile and settings: name, picture, last seen, read receipts, the timer of conversations they open. */
|
|
226
|
+
updateMe(change: api.UpdateProfile): Promise<MyProfile>;
|
|
227
|
+
profiles(userIds: string[]): Promise<Profile[]>;
|
|
228
|
+
block(userId: string): Promise<void>;
|
|
229
|
+
unblock(userId: string): Promise<void>;
|
|
230
|
+
report(input: api.ReportRequest): Promise<api.ReportCreated>;
|
|
231
|
+
}
|
|
232
|
+
declare abstract class View<S> implements Observed<S> {
|
|
233
|
+
protected listeners: Set<Listener>;
|
|
234
|
+
private unlisten;
|
|
235
|
+
private unperson;
|
|
236
|
+
private cached;
|
|
237
|
+
protected readonly m: Messaging;
|
|
238
|
+
constructor(m: Messaging);
|
|
239
|
+
/** What it is now: kept while it is subscribed, read again each time when not. */
|
|
240
|
+
get state(): S;
|
|
241
|
+
subscribe(listener: Listener): () => void;
|
|
242
|
+
protected opened(): void;
|
|
243
|
+
protected abstract touches(t: Touched): boolean;
|
|
244
|
+
protected abstract read(): S;
|
|
245
|
+
}
|
|
246
|
+
export declare class ConversationList extends View<ConversationListState> {
|
|
247
|
+
protected touches(t: Touched): boolean;
|
|
248
|
+
protected read(): ConversationListState;
|
|
249
|
+
}
|
|
250
|
+
export declare class ConversationView extends View<ConversationViewState> {
|
|
251
|
+
readonly id: string;
|
|
252
|
+
constructor(m: Messaging, id: string);
|
|
253
|
+
protected opened(): void;
|
|
254
|
+
protected touches(t: Touched): boolean;
|
|
255
|
+
protected read(): ConversationViewState;
|
|
256
|
+
/** Reads the conversation's newest page now (opening it does). */
|
|
257
|
+
refresh(): Promise<boolean>;
|
|
258
|
+
/** Reads the page of messages before the oldest one drawn; answers whether there are more. */
|
|
259
|
+
loadEarlier(): Promise<boolean>;
|
|
260
|
+
send(input: string | SendOptions): Promise<OutboxItem>;
|
|
261
|
+
markRead(seq?: number): Promise<void>;
|
|
262
|
+
typing(): Promise<void>;
|
|
263
|
+
thread(rootId: string): ThreadView;
|
|
264
|
+
}
|
|
265
|
+
export declare class ThreadView extends View<ThreadViewState> {
|
|
266
|
+
readonly conversationId: string;
|
|
267
|
+
readonly rootId: string;
|
|
268
|
+
constructor(m: Messaging, conversationId: string, rootId: string);
|
|
269
|
+
protected opened(): void;
|
|
270
|
+
protected touches(t: Touched): boolean;
|
|
271
|
+
protected read(): ThreadViewState;
|
|
272
|
+
/** Answers in the thread (alsoInConversation: the conversation's timeline shows it too). */
|
|
273
|
+
send(input: string | Omit<SendOptions, 'threadId'>): Promise<OutboxItem>;
|
|
274
|
+
markRead(): Promise<void>;
|
|
275
|
+
}
|
|
276
|
+
export declare class ScheduledList extends View<ScheduledMessage[]> {
|
|
277
|
+
protected opened(): void;
|
|
278
|
+
protected touches(t: Touched): boolean;
|
|
279
|
+
protected read(): ScheduledMessage[];
|
|
280
|
+
}
|
package/dist/chunks/LIKE2KDM.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/*! palbase 0.17.1 — Palbase SDK License (see LICENSE) */
|
|
2
|
-
import{e as Re,g as Ae,h as Oe}from"./FWX3RGVS.js";import{h as Ce}from"./7C7HACEZ.js";import{a as Ee}from"./E27BZ5SM.js";import{r as xe,t as Pe,u as Te}from"./R7PRW7FG.js";import{b as V,c as j,e as Se,g as K,h as _e}from"./CYLNEHKQ.js";import{a as Ie,b as H}from"./DWRLUP7O.js";import{b as P,d as U}from"./3Y4K6F6T.js";function pt(n){let e=n,t=e?.body,s=t&&typeof t=="object"?t.reason:void 0;return s==="user_deleted"?"userDeleted":s==="user_banned"?"userBanned":e?.code==="session_expired"||e?.code==="token_expired"?"expired":"revoked"}var T=class extends Error{code="session_changed";constructor(e){super(e),this.name="SessionChangedError"}};function Me(){let n=null;return{load:()=>n,save:e=>{n=e},clear:()=>{n=null},shared:!1}}function Ne(n){let e=null,t=!0,s=()=>{try{return globalThis.localStorage}catch{return}};return{shared:!0,load(){try{let i=s()?.getItem(n);return i==null?t?null:e:JSON.parse(i)}catch{return e}},save(i){e=i;try{let r=s();if(!r)throw new Error("no storage");r.setItem(n,JSON.stringify(i)),t=!0}catch{t=!1}},clear(){e=null,t=!0;try{s()?.removeItem(n)}catch{}},watch(i){let r=globalThis;if(typeof r.addEventListener!="function")return()=>{};let a=o=>{(o.key===n||o.key===null)&&i()};return r.addEventListener("storage",a),()=>r.removeEventListener?.("storage",a)}}}function fe(n){try{let e=n.split(".")[1]??"",t=atob(e.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(e.length/4)*4,"=")),s=JSON.parse(t).sub;return typeof s=="string"?s:""}catch{return""}}var ft=6e4,gt=15e3;function yt(n,e,t){let s=n?globalThis.navigator?.locks:void 0;return s?s.request(e,t):t()}var G=class{current=null;loaded;inflight=null;endReason=null;listeners=new Set;store;refresher;isRejected;now;lockName;refreshTimeoutMs;mode;constructor(e,t,s,i={}){this.store=e,this.refresher=t,this.isRejected=s,this.now=i.now??Date.now,this.lockName=i.lockName??"palbase.session.refresh",this.refreshTimeoutMs=i.refreshTimeoutMs??gt,this.mode=i.refresh??"behind",this.loaded=Promise.resolve(e.load()).then(r=>{this.current=r}),e.watch?.(()=>{this.reconcile()})}async session(){return await this.loaded,this.current}snapshot(){return this.current}onChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}async set(e,t,s){await this.loaded;let i=t==="TOKEN_REFRESHED"?this.current:null,r={accessToken:e.access_token,refreshToken:e.refresh_token,expiresAt:this.now()+e.expires_in*1e3,userId:s?.id??i?.userId??fe(e.access_token),user:s??i?.user};return this.current=r,await this.store.save(r),this.emit(t,r),r}async setUser(e,t){await this.loaded,!(!this.current||!t||this.current.userId!==t.userId)&&(this.current={...this.current,user:e},await this.store.save(this.current),this.emit("USER_UPDATED",this.current))}async clear(e,t){await this.loaded;let s=this.current;this.current=null,this.inflight=null;let i=await this.store.load();(!i||!s||i.userId===s.userId)&&await this.store.clear(),s&&(e==="SESSION_EXPIRED"&&(this.endReason=t??"revoked"),this.emit(e,null))}async accessToken(){await this.loaded;let e=this.current;if(!e)return;let t=e.expiresAt-this.now();if(t>ft)return e.accessToken;if(this.mode==="never")return t>0?e.accessToken:void 0;if(t>0&&this.mode==="behind")return this.refresh().catch(()=>{}),e.accessToken;if(t>0)try{return(await this.refresh()).accessToken}catch(s){if(this.current===e)return e.accessToken;throw s}return(await this.refresh()).accessToken}refresh(){if(this.mode==="never")return Promise.reject(new Error("this client does not renew its session (refresh: 'never'): where the session cannot be written back, the request's middleware renews it"));if(this.inflight)return this.inflight;let e=yt(this.store.shared===!0,this.lockName,async()=>{await this.loaded;let t=this.current;if(!t)throw new T("no session to refresh");let s=await this.adoptStored(t);if(s)return s;try{let i=await this.withTimeout(this.refresher(t.refreshToken));if(this.current?.refreshToken!==t.refreshToken)throw new T("the session changed while it was refreshed");return await this.set(i,"TOKEN_REFRESHED")}catch(i){throw this.isRejected(i)&&this.current?.refreshToken===t.refreshToken&&await this.clear("SESSION_EXPIRED",pt(i)),i}});return this.inflight=e,e.finally(()=>{this.inflight===e&&(this.inflight=null)}).catch(()=>{}),e}async adoptStored(e){let t=await this.store.load();if(!t)throw this.current=null,this.emit("SIGNED_OUT",null),new T("signed out in another tab");if(t.userId!==e.userId)throw this.current=t,this.emit("SIGNED_OUT",null),this.emit("SIGNED_IN",t),new T("another user signed in in another tab");if(t.refreshToken!==e.refreshToken&&t.expiresAt>=e.expiresAt)return this.current=t,this.emit("TOKEN_REFRESHED",t),t}async reconcile(){await this.loaded;let e=this.current,t=await this.store.load();if(!e){t&&(this.current=t,this.emit("SIGNED_IN",t));return}await this.adoptStored(e).catch(()=>{})}withTimeout(e){let t,s=new Promise((i,r)=>{t=setTimeout(()=>r(new Error(`the refresh did not answer within ${this.refreshTimeoutMs/1e3} s`)),this.refreshTimeoutMs)});return Promise.race([e,s]).finally(()=>clearTimeout(t))}emit(e,t){(e==="SIGNED_IN"||e==="SIGNED_OUT")&&(this.endReason=null);for(let s of this.listeners)try{s(e,t)}catch{}}};var ge=class{state="closed";refusal;logSeq;joinRef=null;listeners=new Map;closers=new Set;joiners=new Set;joinWaiters=[];name;socket;constructor(e,t,s={}){this.name=e,this.socket=t,this.logSeq=s.after}get topic(){return`realtime:${this.name}`}join(){if(this.state==="joined")return Promise.resolve();let e=new Promise((t,s)=>this.joinWaiters.push({resolve:t,reject:s}));return this.state!=="joining"&&this.socket.join(this),e}leave(){this.socket.leave(this)}push(e,t){return this.socket.request(this,e,t)}on(e,t){let s=this.listeners.get(e);return s||this.listeners.set(e,s=new Set),s.add(t),()=>s.delete(t)}onClosed(e){return this.closers.add(e),()=>this.closers.delete(e)}onJoined(e){return this.joiners.add(e),()=>this.joiners.delete(e)}deliver(e,t){e==="broadcast"&&typeof t.seq=="number"&&(this.logSeq=t.seq);for(let s of this.listeners.get(e)??[])try{s(t)}catch{}}settled(e,t){e&&typeof t.log_seq=="number"&&(this.logSeq=t.log_seq),this.state=e?"joined":"refused",this.refusal=e?void 0:t;let s=this.joinWaiters.splice(0);for(let i of s)e?i.resolve():i.reject(new Error(`join ${this.name} refused: ${JSON.stringify(t)}`));if(e)for(let i of[...this.joiners])try{i()}catch{}}closed(e){this.state="closed",this.joinRef=null;let t=this.joinWaiters.splice(0);for(let s of t)s.reject(new Error(`join ${this.name}: ${e}`));for(let s of[...this.closers])try{s()}catch{}}},J=class{ws=null;opening=null;ref=0;channels=new Map;replies=new Map;heartbeat=null;heartbeatRef=null;reconnectTimer=null;attempts=0;closedByUs=!1;reconnects=0;opts;constructor(e){this.opts=e}channel(e,t){let s=this.channels.get(e);return s||this.channels.set(e,s=new ge(e,this,t)),s}disconnect(){this.closedByUs=!0,this.reconnectTimer&&clearTimeout(this.reconnectTimer),this.reconnectTimer=null,this.stopHeartbeat();let e=this.ws;this.ws=null,this.opening=null,e?.close(1e3);for(let[,t]of this.replies)t("error",{reason:"socket closed"});this.replies.clear();for(let t of this.channels.values())t.closed("the socket was closed")}async tokenChanged(){if(!this.ws||this.ws.readyState!==1)return;let e=await this.opts.accessToken();if(e)for(let t of this.channels.values())t.state==="joined"&&this.push(t.joinRef,t.topic,"access_token",{access_token:e})}join(e){e.state="joining",this.open().then(()=>this.sendJoin(e)).catch(t=>e.settled(!1,{reason:t instanceof Error?t.message:String(t)}))}leave(e){e.state==="joined"&&this.ws?.readyState===1&&this.push(e.joinRef,e.topic,"phx_leave",{}),e.state="closed",this.channels.delete(e.name)}async request(e,t,s){let i=this.ws;if(this.channels.get(e.name)!==e||e.state!=="joined"||i?.readyState!==1)return{status:"error",response:{reason:"not joined"}};let r=this.nextRef(),a=JSON.stringify([e.joinRef,r,e.topic,t,s]),o=this.awaitReply(r);return i.send(a),o}open(){if(this.ws?.readyState===1)return Promise.resolve();if(this.opening)return this.opening;this.closedByUs=!1;let e=this.opts.webSocket??globalThis.WebSocket,t=`${this.opts.baseUrl.replace(/^http/,"ws")}/realtime/v1/websocket?vsn=2.0.0&apikey=${encodeURIComponent(this.opts.publishableKey)}`,s=new Promise((i,r)=>{let a=new e(t);this.ws=a,a.onopen=()=>{this.attempts=0,this.startHeartbeat(),i()},a.onmessage=o=>this.receive(String(o.data)),a.onerror=()=>r(new Error("the realtime socket could not be opened")),a.onclose=()=>this.dropped(a)});return this.opening=s,s.finally(()=>{this.opening===s&&(this.opening=null)}).catch(()=>{}),s}dropped(e){if(this.ws!==e)return;this.ws=null,this.stopHeartbeat();for(let[,i]of this.replies)i("error",{reason:"socket closed"});this.replies.clear();for(let i of this.channels.values())i.state==="joined"&&(i.state="joining");if(this.closedByUs||![...this.channels.values()].some(i=>i.state==="joining"))return;let t=this.opts.backoff??[500,1e3,2e3,5e3,1e4,3e4],s=t[Math.min(this.attempts,t.length-1)]*(.8+Math.random()*.4);this.attempts++,this.reconnectTimer=W(setTimeout(()=>{this.reconnectTimer=null,this.reconnects++;let i=[...this.channels.values()].filter(r=>r.state==="joining");this.open().then(()=>Promise.all(i.map(r=>this.sendJoin(r)))).catch(()=>{})},s))}async sendJoin(e){let t=await this.opts.accessToken(),s=this.nextRef();e.joinRef=s;let i=this.awaitReply(s),r={broadcast:{self:!1}};e.logSeq!==void 0&&(r.log={after:e.logSeq}),this.push(s,e.topic,"phx_join",{access_token:t,config:r},s);let{status:a,response:o}=await i;if(this.channels.get(e.name)!==e||e.state!=="joining"){a==="ok"&&this.ws?.readyState===1&&this.push(s,e.topic,"phx_leave",{});return}e.settled(a==="ok",o)}awaitReply(e){return new Promise(t=>{let s=W(setTimeout(()=>{this.replies.delete(e),t({status:"timeout",response:{reason:"no reply"}})},this.opts.replyTimeoutMs??1e4));this.replies.set(e,(i,r)=>{clearTimeout(s),this.replies.delete(e),t({status:i,response:r})})})}receive(e){let t;try{t=JSON.parse(e)}catch{return}if(!Array.isArray(t)||t.length!==5||typeof t[2]!="string"||typeof t[3]!="string")return;let[,s,i,r,a]=t,o=typeof a=="object"&&a!==null?a:{};if(r==="phx_reply"&&typeof s=="string"){if(s===this.heartbeatRef){this.heartbeatRef=null;return}this.replies.get(s)?.(String(o.status),o.response??{});return}let c=[...this.channels.values()].find(l=>l.topic===i);if(c){if(r==="phx_close"){c.state="closed";return}if(r==="phx_error"){c.state="joining",W(setTimeout(()=>this.channels.get(c.name)===c&&c.state==="joining"&&this.ws?.readyState===1&&void this.sendJoin(c),1e3));return}c.deliver(r,o)}}push(e,t,s,i,r=this.nextRef()){this.ws?.send(JSON.stringify([e,r,t,s,i]))}nextRef(){return String(++this.ref)}startHeartbeat(){this.stopHeartbeat(),this.heartbeat=W(setInterval(()=>{if(this.heartbeatRef!==null){this.heartbeatRef=null,this.ws?.close(4e3);return}this.heartbeatRef=this.nextRef(),this.push(null,"phoenix","heartbeat",{},this.heartbeatRef)},this.opts.heartbeatMs??25e3))}stopHeartbeat(){this.heartbeat&&clearInterval(this.heartbeat),this.heartbeat=null,this.heartbeatRef=null}};function W(n){return n.unref?.(),n}var A="X-Palbase-Installation-Secret",X="X-Palbase-Installation",De=new WeakMap;function O(n){return De.get(n)}var Ue=new WeakSet;function je(n){return Ue.has(n)}var mt=/^[A-Za-z0-9_-]{43}$/,B=class{id;constructor(e){let t=`palbase.installation.secret.${e}`,s;try{let i=Le()?.getItem(t);i&&mt.test(i)&&(s=i)}catch{}if(!s){Ue.add(this),s=Ke(crypto.getRandomValues(new Uint8Array(32)));try{Le()?.setItem(t,s)}catch{}}De.set(this,s),this.id=vt(s)}};function vt(n){return Ke(bt(new TextEncoder().encode(n)).subarray(0,16))}function Le(){try{return globalThis.localStorage}catch{return}}function Ke(n){let e="";for(let t of n)e+=String.fromCharCode(t);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}var wt=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),E=(n,e)=>n>>>e|n<<32-e;function bt(n){let e=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),t=new Uint8Array(Math.ceil((n.length+9)/64)*64);t.set(n),t[n.length]=128;let s=new DataView(t.buffer);s.setUint32(t.length-8,Math.floor(n.length/536870912)),s.setUint32(t.length-4,n.length*8>>>0);let i=new Uint32Array(64);for(let o=0;o<t.length;o+=64){for(let f=0;f<16;f++)i[f]=s.getUint32(o+f*4);for(let f=16;f<64;f++){let m=E(i[f-15],7)^E(i[f-15],18)^i[f-15]>>>3,b=E(i[f-2],17)^E(i[f-2],19)^i[f-2]>>>10;i[f]=i[f-16]+m+i[f-7]+b|0}let[c,l,d,g,p,k,S,u]=e;for(let f=0;f<64;f++){let m=u+(E(p,6)^E(p,11)^E(p,25))+(p&k^~p&S)+wt[f]+i[f]|0,b=(E(c,2)^E(c,13)^E(c,22))+(c&l^c&d^l&d)|0;u=S,S=k,k=p,p=g+m|0,g=d,d=l,l=c,c=m+b|0}e[0]+=c,e[1]+=l,e[2]+=d,e[3]+=g,e[4]+=p,e[5]+=k,e[6]+=S,e[7]+=u}let r=new Uint8Array(32),a=new DataView(r.buffer);for(let o=0;o<8;o++)a.setUint32(o*4,e[o]);return r}var St=30*6e4,$e=1e3,_t=100,It=60*1024,z=()=>globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;function D(){try{return globalThis.localStorage}catch{return}}var Z=class{api;closingApi;perfApi;closingPerfApi;flushMs;flushAt;now;anonKey;sessionKey;onceKey;events=[];samples=[];timer;memoryAnon;memorySession;memoryOnce;appVersion;stopAuto;session;consent;identifyPending=!1;listeners=new Set;people={set:e=>this.person({set:e}),setOnce:e=>this.person({set_once:e}),unset:e=>this.person({unset:[...e]}),add:e=>this.person({add:e})};constructor(e,t,s,i,r,a,o={}){this.session=s,this.consent=i;let c={send:d=>e.send(this.granted("analytics")?{...d,headers:{...d.headers,[X]:r.id}}:d)};this.api=V.client(c);let l={send:d=>(this.granted("analytics")?e:t).send(d)};this.perfApi=V.client(l),this.closingApi=V.client({send:d=>c.send({...d,keepalive:!0})}),this.closingPerfApi=V.client({send:d=>l.send({...d,keepalive:!0})}),this.flushMs=o.flushMs??5e3,this.flushAt=o.flushAt??20,this.now=o.now??Date.now,this.anonKey=`palbase.analytics.anonymous.${a}`,this.sessionKey=`palbase.analytics.session.${a}`,this.onceKey=`palbase.analytics.once.${a}`,s.onChange(d=>{d==="SIGNED_IN"?(this.identifyPending=!0,this.soon()):d==="SIGNED_OUT"&&(this.identifyPending=!1,this.reset())}),i.onChange((d,g)=>{g!=="granted"&&(d==="analytics"?(this.events=[],this.identifyPending=!1,this.samples=this.samples.map(ye),this.reset()):d==="performance"&&(this.samples=[]))})}capture(e,t){for(let i of this.listeners)i(e,t);if(!this.granted("analytics"))return;let s=this.now();this.hold({event:e,distinct_id:this.distinctId(),properties:t,timestamp:s,session_id:this.sessionId(s),...this.appVersion?{app_version:this.appVersion}:{}})}captureOnce(e,t,s){if(!this.granted("analytics"))return;let i=this.sessionId(this.now()),r=this.readOnce(),a=r?.session===i?r.keys:[];a.includes(e)||(this.writeOnce({session:i,keys:[...a,e].slice(-500)}),this.capture(t,s))}readOnce(){try{let e=D()?.getItem(this.onceKey);if(e)return JSON.parse(e)}catch{}return this.memoryOnce}writeOnce(e){this.memoryOnce=e;try{D()?.setItem(this.onceKey,JSON.stringify(e))}catch{}}onEvent(e){return this.listeners.add(e),()=>this.listeners.delete(e)}page(e={}){let t=globalThis.location,s=globalThis.document,i=e.url??(t?`${t.origin}${$(t.pathname)}`:"");if(!i)return;let r=e.referrer??At(s?.referrer);this.capture("$pageview",{...e.properties,url:i,...e.title??s?.title?{title:e.title??s?.title}:{},...r?{referrer:r}:{}})}async identify(e){this.identifyPending=!1;let t=this.session.snapshot()?.userId;!t||!this.granted("analytics")||(await this.flush(),await this.sendIdentify(this.api,t,e))}async sendIdentify(e,t,s){try{await e.identify({body:{distinct_id:t,anonymous_id:this.anonymousId(),traits:s,timestamp:this.now(),sent_at:this.now()}})}catch{}}reset(){this.memoryAnon=void 0,this.memorySession=void 0,this.memoryOnce=void 0;try{D()?.removeItem(this.anonKey),D()?.removeItem(this.sessionKey),D()?.removeItem(this.onceKey)}catch{}}async flush(e=!1){this.timer&&clearTimeout(this.timer),this.timer=void 0,this.granted("analytics")||(this.events=[]),this.granted("performance")?this.granted("analytics")||(this.samples=this.samples.map(ye)):this.samples=[];let t=e?this.closingApi:this.api,s=e?this.closingPerfApi:this.perfApi,i=this.now(),r=this.session.snapshot()?.userId;for(this.identifyPending&&r&&this.granted("analytics")&&(this.identifyPending=!1,await this.sendIdentify(t,r));this.events.length>0;){let a=this.take(this.events,e);try{await t.batch({body:{events:a.map(o=>({...o,sent_at:i}))}})}catch{}}for(;this.samples.length>0;){let a=this.take(this.samples,e);try{await s.sendPerf({body:{items:a}})}catch{}}}start(e={}){this.stopAuto?.(),this.appVersion=e.appVersion;let t=globalThis;if(typeof t.addEventListener!="function"||typeof globalThis.document>"u")return()=>{};let s=[];e.pageViews!==!1&&s.push(this.watchPages(t)),e.webVitals!==!1&&s.push(Tt((a,o)=>this.sample("web_vital",a,o))),e.network!==!1&&s.push(this.watchFetch(t));let i=()=>{document.visibilityState==="hidden"&&this.flush(!0)},r=()=>{this.flush(!0)};return document.addEventListener("visibilitychange",i),t.addEventListener("pagehide",r),s.push(()=>{document.removeEventListener("visibilitychange",i),t.removeEventListener("pagehide",r)}),this.stopAuto=()=>{for(let a of s.splice(0))a();this.stopAuto=void 0},this.stopAuto}granted(e){return this.consent.state(e)==="granted"}async person(e){if(!this.granted("analytics"))return;let t=this.session.snapshot()?.userId,s=this.now();try{await this.api.setPersonProperties({body:{...e,...t?{}:{distinct_id:this.anonymousId()},timestamp:s,sent_at:s}})}catch{}}hold(e){this.events.length>=$e&&this.events.shift(),this.events.push(e),this.soon()}sample(e,t,s,i={}){if(!this.granted("performance"))return;this.samples.length>=$e&&this.samples.shift();let r={row_id:z(),trace_type:e,name:t,value:Math.max(0,s),timestamp:this.now(),...i};this.samples.push(this.granted("analytics")?{...r,distinct_id:this.distinctId()}:ye(r)),this.soon()}soon(){if(this.events.length+this.samples.length>=this.flushAt){this.flush();return}this.timer||(this.timer=setTimeout(()=>{this.flush()},this.flushMs),this.timer.unref?.())}take(e,t){let s=e.splice(0,_t);if(!t)return s;for(;s.length>1&&JSON.stringify(s).length>It;)e.unshift(s.pop());return s}distinctId(){return this.session.snapshot()?.userId??this.anonymousId()}anonymousId(){let e=D();try{let t=e?.getItem(this.anonKey);if(t)return t;let s=`anon_${z()}`;if(e?.setItem(this.anonKey,s),e?.getItem(this.anonKey)===s)return s}catch{}return this.memoryAnon??=`anon_${z()}`,this.memoryAnon}sessionId(e){let t=D(),s=this.memorySession;try{let r=t?.getItem(this.sessionKey);r&&(s=JSON.parse(r))}catch{}let i=s&&e-s.last<St?{id:s.id,last:e}:{id:`ses_${z()}`,last:e};this.memorySession=i;try{t?.setItem(this.sessionKey,JSON.stringify(i))}catch{}return i.id}watchPages(e){let t="",s=()=>{let o=`${e.location.origin}${e.location.pathname}`;if(o===t)return;t=o;let c=`${e.location.origin}${$(e.location.pathname)}`;setTimeout(()=>this.page({url:c}),0)},i=e.history,r=i.pushState.bind(i),a=i.replaceState.bind(i);return i.pushState=(...o)=>{r(...o),s()},i.replaceState=(...o)=>{a(...o),s()},e.addEventListener("popstate",s),s(),()=>{i.pushState=r,i.replaceState=a,e.removeEventListener("popstate",s)}}watchFetch(e){let t=e.fetch;if(typeof t!="function")return()=>{};let s=async(i,r)=>{let a=performance.now(),o=i instanceof Request?i:void 0,c=(r?.method??o?.method??"GET").toUpperCase(),l;try{l=new URL(o?.url??String(i),e.location.href)}catch{l=void 0}let d=!!l&&l.pathname.startsWith("/analytics/")||Et(r?.headers??o?.headers);try{let g=await t(i,r);return l&&!d&&this.sample("network",`${c} ${l.origin}${$(l.pathname)}`,performance.now()-a,{attrs:{status:String(g.status)},...g.headers.get("x-request-id")?{request_id:g.headers.get("x-request-id")}:{}}),g}catch(g){throw l&&!d&&this.sample("network",`${c} ${l.origin}${$(l.pathname)}`,performance.now()-a,{attrs:{status:"0"}}),g}};return e.fetch=s,()=>{e.fetch===s&&(e.fetch=t)}}};function ye(n){let{distinct_id:e,request_id:t,...s}=n;return s}var xt=n=>n.entryType==="layout-shift"&&"value"in n&&"hadRecentInput"in n,Pt=n=>n.entryType==="event"||n.entryType==="first-input";function Y(n,e){if(!(typeof PerformanceObserver>"u"))try{let t=new PerformanceObserver(s=>e(s.getEntries()));return t.observe({type:n,buffered:!0}),t}catch{return}}function Tt(n){if(typeof document>"u"||typeof performance>"u"||typeof performance.getEntriesByType!="function")return()=>{};let e=0,t=0,s=0,i=[Y("largest-contentful-paint",l=>{for(let d of l)e=Math.max(e,d.startTime)}),Y("layout-shift",l=>{for(let d of l)xt(d)&&!d.hadRecentInput&&(t+=d.value)}),Y("event",l=>{for(let d of l)Pt(d)&&(s=Math.max(s,d.duration))}),Y("paint",l=>{for(let d of l)d.name==="first-contentful-paint"&&n("FCP",d.startTime)})],r=performance.getEntriesByType("navigation")[0];r&&r.responseStart>0&&n("TTFB",r.responseStart);let a=!1,o=()=>{a||(a=!0,e>0&&n("LCP",e),n("CLS",t),s>0&&n("INP",s))},c=()=>{document.visibilityState==="hidden"&&o()};return document.addEventListener("visibilitychange",c),()=>{o(),document.removeEventListener("visibilitychange",c);for(let l of i)l?.disconnect()}}function Et(n){if(!n)return!1;try{return new Headers(n).has("next-router-prefetch")}catch{return!1}}var Rt=/^[a-z][a-z0-9_-]{0,31}$/;function $(n){return n.split("/").map(e=>{if(e==="")return e;let t=e.split(";",1)[0],s=t.toLowerCase();return Rt.test(s)&&(s.match(/\d/g)?.length??0)<=2&&t.slice(1)===s.slice(1)&&s.split(/[-_]/).every(r=>r.length<=16)?s:":id"}).join("/")}function At(n){if(!n)return"";try{let e=new URL(n);return`${e.origin}${$(e.pathname)}`}catch{return $(n.split(/[?#]/,1)[0]??"")}}var Ye=/^custom\.[a-z0-9_]{1,48}$/,Ot=/^[a-z][a-z0-9_]{0,63}$/,qe=n=>Ot.test(n)||Ye.test(n),Ct=50,Fe=[5e3,3e4,12e4,6e5],Mt=100,ee=class{userApi;deviceApi;session;socket;ref;installation;start;textVersion;customKeys;storeKey;now;kept;listeners=new Set;engaged=!1;platformKeys;watch;sending;sendAgain=!1;retryTimer;retries=0;readFor;stale=!1;lastW=0;lastChosen=0;gpc=globalThis.navigator?.globalPrivacyControl===!0;constructor(e){let t=e.options??{};for(let[c,l]of Object.entries(t.start??{})){if(!qe(c))throw new TypeError(`consent.start: ${JSON.stringify(c)} is not a consent key (a platform key, or custom.<name>)`);if(l!=="granted"&&l!=="denied")throw new TypeError(`consent.start.${c} is granted or denied`)}for(let c of t.customKeys??[])if(!Ye.test(c))throw new TypeError(`consent.customKeys: ${JSON.stringify(c)} is not custom.<name> (a-z, 0-9 and _, 48 at most)`);if(t.textVersion!==void 0&&(t.textVersion===""||t.textVersion.length>64))throw new TypeError("consent.textVersion: 1 to 64 characters");this.userApi=e.userApi,this.deviceApi=e.deviceApi,this.session=e.session,this.socket=e.socket,this.ref=e.ref,this.installation=e.installation,this.start={...t.start},this.textVersion=t.textVersion,this.customKeys=[...t.customKeys??[]],this.storeKey=`palbase.consent.${e.origin}.${e.installation.id}`,this.now=e.now??Date.now;let s=this.load(),i=()=>je(this.installation)?{}:{unknown:{on:!0,w:this.stamp()}},r={whose:null,install:this.installation.id,choices:{},unsent:[]};typeof s!="object"?this.kept={...r,...s==="unreadable"?{unknown:{on:!0,w:this.stamp()}}:i()}:s.whose==null&&s.install!==void 0&&s.install!==this.installation.id?this.kept={...r,unsent:s.unsent.filter(c=>c.user!==null),...s.keys?{keys:s.keys}:{},...i()}:this.kept=s,e.session.onChange((c,l)=>{this.engaged&&(c==="SIGNED_IN"&&l?this.signedIn(l):(c==="SIGNED_OUT"||c==="SESSION_EXPIRED")&&this.signedOut())});let a=globalThis;typeof a.addEventListener=="function"&&(a.addEventListener("storage",c=>{(c.key===this.storeKey||c.key===null)&&this.reload()}),a.addEventListener("online",()=>{this.engaged&&this.send()}));let o=this.kept;(e.options!==void 0||s!=="empty"&&(o.unknown?.on||o.unsent.length>0||o.link!==void 0||Object.keys(o.choices).length>0))&&this.engage()}async keys(){return this.engage(),[...(await this.platform()).map(t=>({key:t.key,category:t.category,title:{...t.title},description:{...t.description},ads:t.ads})),...this.customKeys.map(t=>({key:t,category:"custom",title:{},description:{},ads:!1}))]}state(e){if(_(this.kept)!==this.holder()||this.gpcRefuses(e))return"denied";let t=Ge(this.kept,e);return t&&t.state!=="unset"?t.state:this.kept.unknown?.on?"denied":this.start[e]}owesRead(){return this.stale||this.kept.unknown?.on===!0||_(this.kept)!==this.holder()||Object.values(this.kept.choices).some(e=>e.provisional)}holder(){let e=this.session.snapshot()?.userId;return e?`user:${e}`:`device:${this.installation.id}`}lastDeniedAt(e){let t=this.kept.choices[e]?.last_denied_at;return t?new Date(t):void 0}set(e,t){this.setMany({[e]:t})}setMany(e){let t=Object.entries(e);for(let[a,o]of t){if(!qe(a))throw new TypeError(`${JSON.stringify(a)} is not a consent key (a platform key, or custom.<name>)`);if(o!=="granted"&&o!=="denied")throw new TypeError(`${a}: a choice is granted or denied`)}if(t.length===0)return;this.engage();let s=this.chosenAt(),i=this.session.snapshot()?.userId??null,r=this.states();for(let[a,o]of t)this.queue({key:a,state:o,source:"app",chosen_at:s,user:i,...this.textVersion!==void 0?{text_version:this.textVersion}:{}});this.commit(r),this.send()}onChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}async region(){this.engage();let e=await this.subject();if(this.readFor!==e)try{await this.read(e)}catch(t){if(!this.kept.region)throw t}return this.kept.region}async needsAsking(e){this.engage();let t=await this.subject();this.readFor!==t&&await this.read(t).catch(()=>{});let s=e??(await this.keys()).map(c=>c.key),i=await this.platform().catch(()=>this.kept.keys??[]),r=new Set(i.filter(c=>c.ads).map(c=>c.key)),a=this.kept.region?.jurisdiction==="us",o=new Date(this.now());return o.setUTCMonth(o.getUTCMonth()-12),s.filter(c=>{let l=this.kept.choices[c];return a&&r.has(c)&&l?.last_denied_at!==void 0&&Date.parse(l.last_denied_at)>o.getTime()?!1:!l||l.state==="unset"?!0:this.textVersion!==void 0&&l.source==="app"&&l.text_version!==this.textVersion})}engage(){this.engaged||(this.engaged=!0,this.session.session().then(e=>{e&&!this.watch&&this.follow(e),this.send(),this.refuseByGpc()}))}async subject(){return(await this.session.session())?.userId??null}secret(){return{[A]:O(this.installation)}}platform(){return this.platformKeys??=this.deviceApi.listConsentKeys().then(e=>(this.kept={...this.kept,keys:e.data.keys},this.commit(),e.data.keys),e=>{if(this.platformKeys=void 0,this.kept.keys)return this.kept.keys;throw e}),this.platformKeys}async read(e){let s=(await(e===null?this.deviceApi:this.userApi(e)).getConsents({query:{installation_id:this.installation.id},headers:this.secret()})).data;this.adopt(s,e)}adopt(e,t,s=[]){if(this.kept={...this.kept,region:e.region},(this.session.snapshot()?.userId??null)!==t){this.commit();return}let i=this.states(),r={};for(let u of e.choices)r[u.key]={state:u.state,source:u.source,chosen_at:u.chosen_at,...u.text_version!==void 0?{text_version:u.text_version}:{},...u.last_denied_at!==void 0?{last_denied_at:u.last_denied_at}:{}};let a=s.filter(u=>r[u.key]?.state!==u.state||Date.parse(r[u.key]?.chosen_at??"")!==Date.parse(u.chosen_at)).map(u=>C(u.key,u)),c=_(this.kept)===(t===null?`device:${this.installation.id}`:`user:${t}`)?Object.entries(this.kept.choices).filter(([,u])=>u.provisional).map(([u,f])=>C(u,f)):[];if(a.length+c.length>0&&(this.kept={...this.kept,void:M([...this.kept.void??[],...a,...c])}),t===null&&this.kept.resetAt!==void 0)for(let[u,f]of Object.entries(r))Date.parse(f.chosen_at)<this.kept.resetAt&&delete r[u];let l=new Set(Object.entries(r).map(([u,f])=>C(u,f))),d=(this.kept.void??[]).filter(u=>l.has(u));d.length>0&&(this.kept={...this.kept,unvoid:M([...this.kept.unvoid??[],...d])});let g=Ze(this.kept),p;if(_(this.kept)!==(t===null?`device:${this.installation.id}`:`user:${t}`))p=r;else{p={};for(let u of[...new Set([...Object.keys(this.kept.choices),...Object.keys(r)])].sort()){let f=this.kept.choices[u],m=f&&!f.provisional&&!g.has(C(u,f))?f:void 0,b=r[u],R=b&&(!m||Date.parse(b.chosen_at)>=Date.parse(m.chosen_at))?b:m;R&&(p[u]=R)}}for(let u of this.kept.unsent){if(u.user!==null&&u.user!==t||u.user===null&&u.device!==void 0&&u.device!==this.installation.id||u.user===null&&t!==null)continue;let f=p[u.key];f&&Date.parse(f.chosen_at)>Date.parse(u.chosen_at)||(p[u.key]=Ve(u,f))}let{install:k,...S}=this.kept;this.kept={...S,whose:t,...t===null?{install:this.installation.id}:{},choices:p,unknown:{on:!1,w:this.stamp()}},this.readFor=t,this.stale=!1,this.commit(i),this.refuseByGpc()}async refused(e,t,s){let i=t===e&&_(this.kept)===(t===null?`device:${this.installation.id}`:`user:${t}`),r=M([...this.kept.void??[],...s.map(c=>C(c.key,c))]);if(!i){this.kept={...this.kept,void:r},this.commit();return}let a=this.states(),o={...this.kept.choices};for(let c of s){if(this.kept.unsent.some(d=>d.key===c.key&&(d.user===null||d.user===e)&&Date.parse(d.chosen_at)>Date.parse(c.chosen_at)))continue;let l=o[c.key];o[c.key]={state:"denied",source:"app",chosen_at:c.chosen_at,...l?.last_denied_at!==void 0?{last_denied_at:l.last_denied_at}:{},provisional:!0}}this.kept={...this.kept,choices:o,void:r},this.commit(a);try{await this.read(e)}catch{this.stale=!0}}queue(e){let t=e.user===null?{...e,device:this.installation.id}:e,s=_(this.kept)===(t.user===null?`device:${this.installation.id}`:`user:${t.user}`);this.kept={...this.kept,unsent:Qe([...this.kept.unsent,t]),...s?{choices:{...this.kept.choices,[t.key]:Ve(t,this.kept.choices[t.key])}}:{}}}send(){if(this.sendAgain=!0,this.sending)return;let e=(async()=>{for(;this.sendAgain;)this.sendAgain=!1,await this.sendUnsent()||(this.sendAgain=!1)})();this.sending=e,e.finally(()=>{this.sending===e&&(this.sending=void 0)})}async sendUnsent(){this.retryTimer&&clearTimeout(this.retryTimer),this.retryTimer=void 0;let e=null;try{e=await this.subject();let t=await this.sendOf(null,e);if(e!==null&&(this.kept.link===e||t)){let s;try{s=(await this.userApi(e).linkConsents({headers:this.secret(),body:{installation_id:this.installation.id}})).data}catch(i){if(!Be(i))throw i}if(this.kept.link===e){let{link:i,...r}=this.kept;this.kept=r,this.commit()}if(s)this.adopt(s,e);else{let i=this.states();this.kept={...this.kept,unknown:{on:!0,w:this.stamp()}},this.commit(i)}}if(e!==null&&await this.sendOf(e,e),this.owesRead()&&(await this.read(e),this.owesRead()))throw new Error("the choices are not read yet");return this.retries=0,!0}catch(t){return t instanceof T&&(this.session.snapshot()?.userId??null)!==e?(this.sendAgain=!0,!0):(this.retryLater(),!1)}}async sendOf(e,t){let s=!1;for(;;){let i=this.nextGroup(e);if(i.length===0)return s;let r=i[0],a=e===null?this.deviceApi:this.userApi(e),o;try{o=(await a.chooseConsents({headers:this.secret(),body:{installation_id:this.installation.id,...r.source==="gpc"?{source:"gpc"}:{},...r.text_version!==void 0?{text_version:r.text_version}:{},choices:i.map(c=>({key:c.key,state:c.state,chosen_at:c.chosen_at}))}})).data}catch(c){if(!Be(c))throw c;if(i.length>1){this.kept={...this.kept,unsent:this.kept.unsent.map(l=>i.some(d=>Je(d,l))?{...l,alone:!0}:l)},this.commit();continue}}this.kept={...this.kept,unsent:this.kept.unsent.filter(c=>!i.some(l=>Je(l,c))),done:M([...this.kept.done??[],...i.map(te)])},this.commit(),o?(s=!0,e===t&&this.adopt(o,e,i)):await this.refused(t,e,i)}}nextGroup(e){let t=this.kept.unsent.filter(a=>a.user===e&&(e!==null||(a.device??this.installation.id)===this.installation.id)),s=t[0];if(!s)return[];let i=[],r=new Set;if(s.alone)return[s];for(let a of t)if(!r.has(a.key)&&(r.add(a.key),!(a.alone||a.source!==s.source||a.text_version!==s.text_version)&&(i.push(a),i.length===Ct)))break;return i}retryLater(){if(this.retryTimer)return;let e=Fe[Math.min(this.retries,Fe.length-1)];this.retries++,this.retryTimer=setTimeout(()=>{this.retryTimer=void 0,this.send()},e),this.retryTimer.unref?.()}signedIn(e){this.readFor=void 0,this.kept={...this.kept,link:e.userId},this.commit(),this.follow(e),this.send()}signedOut(){this.unfollow(),this.readFor=void 0;let e=this.states(),t=this.chosenAt(),s=new Set([...Object.entries(this.kept.choices).filter(([,o])=>o.state!=="unset").map(([o])=>o),...this.kept.unsent.filter(o=>o.user===null&&(o.device??this.installation.id)===this.installation.id).map(o=>o.key),...Object.keys(this.start),...this.customKeys,...(this.kept.keys??[]).map(o=>o.key)]),i={};for(let[o,c]of Object.entries(this.kept.choices))i[o]={state:"unset",source:"app",chosen_at:t,...c.last_denied_at!==void 0?{last_denied_at:c.last_denied_at}:{}};let r=o=>o.user===null&&(o.device??this.installation.id)===this.installation.id,a=this.kept.unsent.filter(r);this.kept={whose:null,install:this.installation.id,resetAt:Date.parse(t),choices:i,unsent:this.kept.unsent.filter(o=>!r(o)),...this.kept.void?{void:this.kept.void}:{},...this.kept.unvoid?{unvoid:this.kept.unvoid}:{},done:M([...this.kept.done??[],...a.map(te)]),...this.kept.region?{region:this.kept.region}:{},...this.kept.keys?{keys:this.kept.keys}:{},...this.kept.gpc?{gpc:this.kept.gpc}:{},...this.kept.unknown?{unknown:this.kept.unknown}:{}};for(let o of s)this.queue({key:o,state:"unset",source:"app",chosen_at:t,user:null});this.commit(e),this.send(),this.refuseByGpc()}follow(e){this.unfollow();let t=this.socket.channel(`consents:${this.ref}:${e.userId}`),s={userId:e.userId,channel:t,off:()=>{},version:-1},i=[t.on("broadcast",r=>{r.event==="changed"&&this.changed(s,me(r.payload))}),t.on("state_snapshot",r=>this.held(s,me(ze(r.entries)))),t.on("state_diff",r=>this.held(s,me(ze(r.set))))];s.off=()=>i.forEach(r=>r()),this.watch=s,t.join().catch(()=>{})}unfollow(){let e=this.watch;e&&(this.watch=void 0,e.off(),e.channel.leave())}held(e,t){t!==void 0&&this.changed(e,t)}changed(e,t){if(this.watch===e){if(t!==void 0){if(t<=e.version)return;e.version=t}this.read(e.userId).catch(()=>{this.watch===e&&(this.stale=!0,this.retryLater())})}}gpcRefuses(e){if(!this.gpc||!(this.kept.keys??[]).some(r=>r.key===e&&r.ads))return!1;let t=Ge(this.kept,e);if(t?.state==="denied")return!1;let s=this.kept.gpc?.[_(this.kept)],i=s!==void 0&&(this.kept.whose!=null||s>=(this.kept.resetAt??0));return!(t?.state==="granted"&&t.source==="app"&&i&&Date.parse(t.chosen_at)>s)}async refuseByGpc(){if(!this.gpc||_(this.kept)!==this.holder())return;let e;try{e=await this.platform()}catch{return}if(_(this.kept)!==this.holder())return;let t=this.session.snapshot()?.userId??null,s=e.filter(a=>a.ads&&this.gpcRefuses(a.key)&&!this.kept.unsent.some(o=>o.key===a.key&&o.source==="gpc"&&o.user===t));if(s.length===0)return;let i=this.chosenAt(),r=this.states();for(let a of s)this.queue({key:a.key,state:"denied",source:"gpc",chosen_at:i,user:t});this.kept={...this.kept,gpc:{...this.kept.gpc,[_(this.kept)]:Date.parse(i)}},this.commit(r),this.send()}states(){let e=new Map;for(let t of[...Object.keys(this.start),...Object.keys(this.kept.choices)])e.set(t,this.state(t));return e}tell(e){let t=this.states();for(let s of new Set([...e.keys(),...t.keys()])){let i=t.get(s);if(e.get(s)!==i)for(let r of[...this.listeners])try{r(s,i)}catch{}}}load(){let e;try{e=Xe()?.getItem(this.storeKey)}catch{return"unreadable"}if(e==null)return"empty";try{let t=JSON.parse(e);if(Ut(t))return t}catch{}return"unreadable"}reload(){let e=this.load();if(typeof e!="object"){this.write();return}let t=this.states();this.kept=He(e,this.kept,"theirs",this.holder()),_(e)===_(this.kept)&&We(this.kept)!==We(e)&&this.write(),this.tell(t);let s=this.session.snapshot()?.userId??null;this.engaged&&this.kept.unsent.some(i=>i.user!==null&&i.user===s||i.user===null&&(i.device??this.installation.id)===this.installation.id)&&this.retryLater(),this.engaged&&this.refuseByGpc()}commit(e=this.states()){let t=this.load();typeof t=="object"&&(this.kept=He(t,this.kept,"ours",this.holder())),this.write(),this.tell(e)}write(){try{Xe()?.setItem(this.storeKey,JSON.stringify(this.kept))}catch{}}chosenAt(){return this.lastChosen=Math.max(this.now(),this.lastChosen+1),new Date(this.lastChosen).toISOString()}stamp(){let e=this.kept,t=e?Math.max(0,e.unknown?.w??0):0;return this.lastW=Math.max(this.now(),this.lastW+1,t+1),this.lastW}};function Ve(n,e){let t=n.state==="denied"?n.chosen_at:e?.last_denied_at;return{state:n.state,source:n.source,chosen_at:n.chosen_at,...n.text_version!==void 0?{text_version:n.text_version}:{},...t!==void 0?{last_denied_at:t}:{}}}function C(n,e){return`${n}|${e.provisional?"provisional":e.state}|${Date.parse(e.chosen_at)}`}function Ze(n){let e=new Set(n.unvoid??[]);return new Set((n.void??[]).filter(t=>!e.has(t)))}var Q={denied:2,unset:1,granted:0};function Nt(n,e,t,s){let i=e&&!s.has(C(n,e))?e:void 0,r=t&&!s.has(C(n,t))?t:void 0;if(!i||!r)return i??r;let a=Date.parse(i.chosen_at),o=Date.parse(r.chosen_at);return a!==o?a>o?i:r:Q[i.state]!==Q[r.state]?Q[i.state]>Q[r.state]?i:r:i.provisional?r:i}function Lt(n,e){return!n||!e?n??e:e.w>n.w||e.w===n.w&&e.on?e:n}function He(n,e,t,s){let i=M([...n.void??[],...e.void??[]]),r=M([...n.unvoid??[],...e.unvoid??[]]),a=Ze({void:i,unvoid:r}),o={},c,l={...n.gpc};for(let[m,b]of Object.entries(e.gpc??{}))l[m]=Math.max(l[m]??0,b);let d;if(_(n)===_(e)){c=e;for(let m of[...new Set([...Object.keys(n.choices),...Object.keys(e.choices)])].sort()){let b=Nt(m,n.choices[m],e.choices[m],a);b&&(o[m]=b)}d=Lt(n.unknown,e.unknown)}else{c=_(e)===s?e:_(n)===s?n:t==="ours"?e:n;for(let[m,b]of Object.entries(c.choices))a.has(C(m,b))||(o[m]=b);d=c.unknown}let g=M([...n.done??[],...e.done??[]]),p=Qe([...n.unsent,...e.unsent]).filter(m=>!g.includes(te(m))),k=t==="ours"?e:n,S=t==="ours"?n:e,u=k.region??S.region,f=k.keys??S.keys;return{whose:c.whose??null,...c.whose==null&&c.install!==void 0?{install:c.install}:{},...c.whose==null&&(n.resetAt!==void 0||e.resetAt!==void 0)&&_(n)===_(e)?{resetAt:Math.max(n.resetAt??0,e.resetAt??0)}:c.whose==null&&c.resetAt!==void 0?{resetAt:c.resetAt}:{},choices:o,unsent:p,...g.length>0?{done:g}:{},...i.length>0?{void:i}:{},...r.length>0?{unvoid:r}:{},...k.link!==void 0?{link:k.link}:{},...u?{region:u}:{},...Object.keys(l).length>0?{gpc:l}:{},...f?{keys:f}:{},...d?{unknown:d}:{}}}function te(n){return`${n.user??`device:${n.device??""}`}|${n.key}|${n.state}|${n.source}|${n.chosen_at}`}function Ge(n,e){let t=n.choices[e];if(!t||n.whose!=null||n.resetAt===void 0||Date.parse(t.chosen_at)>=n.resetAt)return t}function _(n){return n.whose!=null?`user:${n.whose}`:`device:${n.install??""}`}function M(n){return[...new Set(n)].slice(-Mt)}function We(n){return JSON.stringify(n,(e,t)=>typeof t=="object"&&t!==null&&!Array.isArray(t)?Object.fromEntries(Object.entries(t).sort(([s],[i])=>s.localeCompare(i))):t)}function Qe(n){let e=new Map;for(let t of n){let s=te(t),i=e.get(s);e.set(s,i?i.alone||!t.alone?i:{...i,alone:!0}:t)}return[...e.values()].sort((t,s)=>Date.parse(t.chosen_at)-Date.parse(s.chosen_at))}var Dt=new Set(["granted","denied","unset"]);function Ut(n){if(typeof n!="object"||n===null)return!1;let e=n;if(typeof e.choices!="object"||e.choices===null||Array.isArray(e.choices)||!Array.isArray(e.unsent))return!1;let t=(o,c)=>{if(typeof o!="object"||o===null)return!1;let l=o;return Dt.has(l.state)&&typeof l.chosen_at=="string"&&(!c||typeof l.key=="string")},s=o=>o===void 0||typeof o=="object"&&o!==null&&typeof o.on=="boolean"&&typeof o.w=="number",i=n,r=o=>o===void 0||Array.isArray(o)&&o.every(c=>typeof c=="string"),a=i.whose===void 0||i.whose===null||typeof i.whose=="string";return Object.values(e.choices).every(o=>t(o,!1))&&e.unsent.every(o=>t(o,!0))&&(i.gpc===void 0||typeof i.gpc=="object"&&i.gpc!==null&&Object.values(i.gpc).every(o=>typeof o=="number"))&&s(i.unknown)&&r(i.done)&&r(i.void)&&r(i.unvoid)&&a}function Je(n,e){return n.key===e.key&&n.user===e.user&&n.state===e.state&&n.source===e.source&&n.chosen_at===e.chosen_at}function Be(n){return n instanceof P&&n.status>=400&&n.status<500&&n.status!==401&&n.status!==408&&n.status!==429}function Xe(){try{return globalThis.localStorage}catch{return}}function ze(n){let e=typeof n=="object"&&n!==null?n.version:void 0;return typeof e=="object"&&e!==null?e.v:void 0}function me(n){let e=typeof n=="object"&&n!==null?n.version:void 0;return typeof e=="number"&&Number.isFinite(e)?e:void 0}var jt=`
|
|
3
|
-
:host{display:block;color-scheme:light dark;font:15px/1.4 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif}
|
|
4
|
-
.list{display:flex;flex-direction:column;gap:8px;margin:0;padding:0;list-style:none}
|
|
5
|
-
.item{position:relative;display:flex;gap:12px;align-items:flex-start;padding:12px 40px 12px 12px;border-radius:12px;background:var(--bg);color:var(--fg);cursor:pointer;outline:none}
|
|
6
|
-
.item:focus-visible{box-shadow:0 0 0 2px var(--accent)}
|
|
7
|
-
.item.unread .title{font-weight:600}
|
|
8
|
-
.item .dot{flex:0 0 8px;height:8px;margin-top:7px;border-radius:50%;background:transparent}
|
|
9
|
-
.item.unread .dot{background:var(--accent)}
|
|
10
|
-
.item img{flex:0 0 48px;width:48px;height:48px;border-radius:8px;object-fit:cover}
|
|
11
|
-
.text{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 auto}
|
|
12
|
-
.title{overflow-wrap:anywhere}
|
|
13
|
-
.body{color:var(--muted);overflow-wrap:anywhere}
|
|
14
|
-
.when{color:var(--muted);font-size:12px}
|
|
15
|
-
.card{position:relative;padding-right:32px;cursor:pointer}
|
|
16
|
-
.card.unread::before{content:"";position:absolute;left:-12px;top:14px;width:8px;height:8px;border-radius:50%;background:var(--accent)}
|
|
17
|
-
.delete{position:absolute;top:8px;right:8px;width:28px;height:28px;border:0;border-radius:14px;background:transparent;color:var(--muted);font-size:18px;line-height:1;cursor:pointer}
|
|
18
|
-
.delete:hover,.delete:focus-visible{background:var(--hover)}
|
|
19
|
-
.empty{padding:24px 12px;text-align:center;color:var(--muted)}
|
|
20
|
-
.light{--bg:#f4f4f6;--fg:#111;--muted:#5c5c66;--accent:#2f6bff;--hover:#0000000f}
|
|
21
|
-
.dark{--bg:#1f1f24;--fg:#f2f2f5;--muted:#a0a0ab;--accent:#5b8cff;--hover:#ffffff14}
|
|
22
|
-
`,se=class{api;session;constructor(e,t){this.api=K.client(e),this.session=t}async list(e={}){return(await this.api.listMyInbox({query:{limit:e.limit,cursor:e.cursor,locale:e.locale}})).data}async unread(){return(await this.list({limit:1})).unread}async markRead(e){let t=e==="all"?{all:!0}:{ids:[...e]};return(await this.api.readMyInbox({body:t})).data.read}async remove(e){await this.api.deleteMyInboxMessage({path:{id:e}})}mount(e,t={}){let s=e.ownerDocument,i=s.defaultView,r=s.createElement("div");r.setAttribute("data-palbase-inbox","");let a=r.attachShadow({mode:"open"});Te(s,a,jt);let o=s.createElement("ul");o.className="list",a.append(o),e.append(r);let c=()=>t.appearance??(i?.matchMedia?.("(prefers-color-scheme: dark)").matches?"dark":"light"),l=[],d=0,g=[],p=!1,k=h=>{d=h,t.onUnread?.(h)},S=(h,v)=>{h.read_at||(h.read_at=new Date().toISOString(),k(Math.max(0,d-1)),m(),this.markRead([h.id]).catch(()=>{})),!(!v||!xe(v))&&(t.onOpen?t.onOpen(h,v):v.startsWith("https://")?i?.open(v,"_blank","noopener,noreferrer"):i?.location.assign(v))},u=async h=>{l=l.filter(v=>v.id!==h.id),h.read_at||k(Math.max(0,d-1)),m(),await this.remove(h.id).catch(()=>{})},f=h=>{try{return new Intl.DateTimeFormat(t.locale,{dateStyle:"medium",timeStyle:"short"}).format(new Date(h))}catch{return h}};function m(){if(g.forEach(h=>h.destroy()),g=[],o.replaceChildren(),o.className=`list ${c()}`,!l.length){let h=s.createElement("li");h.className="empty",h.textContent=t.labels?.empty??"No messages",o.append(h);return}for(let h of l)o.append(b(h))}let b=h=>{let v=s.createElement("li");v.setAttribute("data-id",h.id),v.tabIndex=0;let y=s.createElement("button");if(y.type="button",y.className="delete",y.textContent="\xD7",y.setAttribute("aria-label",t.labels?.delete??"Delete"),y.addEventListener("click",w=>{w.stopPropagation(),u(h)}),h.card){v.className=`card ${h.read_at?"":"unread"}`;let w=s.createElement("div");v.append(w,y);let I={onAction:()=>S(h,void 0),onDeepLink:x=>S(h,x),onLink:x=>S(h,x),onCustom:t.onCustom};g.push(Pe(w,{definition:h.card,locale:t.locale??i?.navigator.language??"en",appearance:c(),variables:h.variables??{}},I)),v.addEventListener("click",x=>{x.composedPath().some(F=>F instanceof HTMLElement&&F.tagName==="BUTTON")||S(h,h.deep_link)})}else{v.className=`item ${h.read_at?"":"unread"}`;let w=s.createElement("span");if(w.className="dot",v.append(w),h.image?.startsWith("https://")){let x=s.createElement("img");x.src=h.image,x.alt="",v.append(x)}let I=s.createElement("div");I.className="text";for(let[x,F]of[["title",h.title],["body",h.body],["when",f(h.created_at)]]){if(!F)continue;let pe=s.createElement("span");pe.className=x,pe.textContent=F,I.append(pe)}v.append(I,y),v.addEventListener("click",()=>S(h,h.deep_link))}return v.addEventListener("keydown",w=>{w.key==="Enter"&&w.target===v&&S(h,h.deep_link)}),v},R=0,L=async()=>{let h=++R;if(!(await this.session.session())?.userId){if(p||h!==R)return;l=[],k(0),m();return}let v=await this.list({limit:t.limit??50,locale:t.locale});p||h!==R||(l=v.items,k(v.unread),m())},q=()=>{s.visibilityState==="visible"&&L().catch(()=>{})};s.addEventListener("visibilitychange",q);let he=this.session.onChange(()=>{L().catch(()=>{})});return m(),L().catch(()=>{}),{refresh:L,get items(){return l},get unread(){return d},destroy(){p=!0,s.removeEventListener("visibilitychange",q),he?.(),g.forEach(h=>h.destroy()),r.remove()}}}};var Kt=30*6e4,ne="session_start";function ie(n){try{return n.localStorage}catch{return}}var $t=()=>globalThis.crypto?.randomUUID?globalThis.crypto.randomUUID():`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;function qt(n,e){for(let[t,s]of Object.entries(n??{})){let i=e?.[t];if(i==null||String(i)!==s)return!1}return!0}var re=class{api;session;installation;g;now;requestPush;analyticsAllowed;purchases;asked=0;person=0;sessionKey;pendingKey;opts;messages=[];limits={per_session:1,per_day:3,min_minutes:10};shown={session:0,day:0,total:0};loaded=Promise.resolve();away=!1;memorySession;memoryPending=[];showing;stopWatching;queue=Promise.resolve();constructor(e,t,s,i,r,a,o,c=globalThis,l=Date.now){this.api=K.client({send:d=>e.send({...d,headers:{...d.headers,[A]:O(s)}})}),this.session=t,this.installation=s,this.requestPush=r,this.analyticsAllowed=a,this.purchases=o,this.g=c,this.now=l,this.sessionKey=`palbase.notify.inapp.session.${i}`,this.pendingKey=`palbase.notify.inapp.conversions.${i}`,t.onChange(d=>{d!=="SIGNED_IN"&&d!=="SIGNED_OUT"&&d!=="SESSION_EXPIRED"||(this.forget(),this.opts&&(this.showing?.message.close(),this.loaded=this.load()))})}get started(){return this.opts!==void 0}start(e={}){let t=!this.opts;if(this.opts=e,!t)return;let s=this.g.document,i=()=>{s?.visibilityState==="visible"?this.enqueue(ne,void 0,!0):this.away=!0};s?.addEventListener("visibilitychange",i),this.stopWatching=()=>s?.removeEventListener("visibilitychange",i);let r=this.touch();this.loaded=this.load(),r&&this.trigger(ne)}stop(){this.opts=void 0,this.stopWatching?.(),this.stopWatching=void 0,this.showing?.message.close()}refresh(){return this.loaded=this.load(),this.loaded}trigger(e,t){this.enqueue(e,t,!1)}settled(){return this.queue}enqueue(e,t,s){this.queue=this.queue.then(()=>this.take(e,t,s)).catch(()=>{})}async take(e,t,s){if(await this.converted(e),!!this.opts){if(this.touch())this.loaded=this.load(),e!==ne&&await this.show(ne,void 0);else if(this.away&&(this.loaded=this.load()),s)return;await this.show(e,t)}}async show(e,t){if(await this.loaded,!(!this.opts||this.showing)){for(let s of this.messages)if(!(s.trigger.event!==e||!qt(s.trigger.where,t)||this.capped(s))&&await this.open(s))return}}capped(e){let t=this.now(),s=(o,c)=>o!==void 0&&c!==void 0&&t-Date.parse(o)<c*6e4,i=this.shown,r=e.shown,a=e.limits;return i.session>=this.limits.per_session||i.day>=this.limits.per_day||s(i.last_at,this.limits.min_minutes)||a.per_session!==void 0&&r.session>=a.per_session||a.per_day!==void 0&&r.day>=a.per_day||s(r.last_at,a.min_minutes)||a.max_total!==void 0&&r.total>=a.max_total}async open(e){let t=this.opts,s=this.person,i=await this.subject(),r,a;try{({id:r,variables:a}=(await this.api.showInAppMessage({body:{campaign_id:e.campaign_id,session_id:this.sessionId(),installation_id:this.installation.id}})).data)}catch(d){return d instanceof P&&d.status===409&&(this.loaded=this.load()),!1}if(!this.opts||this.showing||s!==this.person)return!0;let o=new Date(this.now()).toISOString();for(let d of[this.shown,e.shown])d.session++,d.day++,d.total++,d.last_at=o;e.conversion&&this.pend({impression:r,campaign:e.campaign_id,event:e.conversion.event,until:this.now()+e.conversion.hours*36e5,subject:i});let c=(d,g)=>{this.api.reportInAppEvent({path:{id:r},query:{installation_id:this.installation.id},body:{type:d,...g?{action:g}:{}}}).catch(()=>{})},l=Ee({definition:e.definition,locale:t.locale??this.g.navigator?.language??"en",appearance:t.appearance??this.appearance(),variables:{...e.variables,...a}},{onAction:d=>{d.type!=="close"&&d.type!=="sheet"&&c("clicked",d.type)},onLink:t.onLink,onDeepLink:t.onDeepLink,onCustom:t.onCustom,onShowPaywall:t.onShowPaywall,onOffer:t.onOffer??(d=>this.takeOffer(d,t.onOfferError)),onRequestPush:t.onRequestPush??(()=>this.requestPush().then(()=>{})),labels:t.labels,onClose:d=>{this.showing?.message===l&&(this.showing=void 0),d!=="action"&&d!=="app"&&c("dismissed"),t.onClose?.(e.campaign_id,d)}},t.root?{root:t.root}:{});return this.showing={campaign:e.campaign_id,message:l},t.onShow?.(e.campaign_id),!0}async takeOffer(e,t){try{let s=(await this.purchases.offers()).find(o=>o.key===e);if(s?.kind==="grant"){await this.purchases.claimOffer(e);return}let i=s?.web?.plans[0];if(!s?.product||i===void 0)throw new P({op:"TakeOffer",status:0,code:"offer_not_open",message:`the offer ${e} is not the customer's to take on the web now`});let r=this.g.location,a=await this.purchases.checkout({product:s.product,plan:i,successUrl:r.href,cancelUrl:r.href,offer:e});r.assign(a)}catch(s){if(!t)throw s;t(s,e)}}async converted(e){let t=this.now(),s=this.pending().filter(a=>a.until>t),i=await this.subject(),r=this.analyticsAllowed()?s.filter(a=>a.event===e&&a.subject===i):[];this.keepPending(s.filter(a=>!r.includes(a))),await Promise.all(r.map(a=>this.api.reportInAppEvent({path:{id:a.impression},query:{installation_id:this.installation.id},body:{type:"converted"}}).catch(()=>{})))}forget(){this.person++,this.asked++,this.messages=[],this.shown={session:0,day:0,total:0}}async load(){this.away=!1;let e=++this.asked;try{let t=(await this.api.listMyInAppMessages({query:{session_id:this.sessionId(!1),installation_id:this.installation.id}})).data;if(e!==this.asked)return;this.messages=t.messages,this.limits=t.limits,this.shown=t.shown}catch{}}async subject(){let e=(await this.session.session())?.userId;return e?`u:${e}`:`i:${this.installation.id}`}appearance(){return this.g.matchMedia?.("(prefers-color-scheme: dark)").matches?"dark":"light"}touch(){let e=this.now(),t=this.readSession(),s=!t||e-t.last>=Kt;return this.writeSession(s?{id:`ses_${$t()}`,last:e}:{id:t.id,last:e}),s}sessionId(e=!0){return e&&this.touch(),(this.readSession()??this.memorySession).id}readSession(){try{let e=ie(this.g)?.getItem(this.sessionKey);if(e)return JSON.parse(e)}catch{}return this.memorySession}writeSession(e){this.memorySession=e;try{ie(this.g)?.setItem(this.sessionKey,JSON.stringify(e))}catch{}}pending(){try{let e=ie(this.g)?.getItem(this.pendingKey);if(e)return JSON.parse(e)}catch{}return this.memoryPending}keepPending(e){this.memoryPending=e;try{let t=ie(this.g);e.length?t?.setItem(this.pendingKey,JSON.stringify(e)):t?.removeItem(this.pendingKey)}catch{}}pend(e){this.keepPending([...this.pending().filter(t=>t.until>this.now()),e].slice(-50))}};var et=n=>{let e=n.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(n.length/4)*4,"="),t=atob(e),s=new Uint8Array(t.length);for(let i=0;i<t.length;i++)s[i]=t.charCodeAt(i);return s},ve=class{api;session;installation;baseUrl;publishableKey;g;registered;changing=Promise.resolve();constructor(e,t,s,i,r,a=globalThis){this.api=K.client(e),this.session=t,this.installation=s,this.baseUrl=i,this.publishableKey=r,this.g=a,t.onChange(o=>{(o==="SIGNED_IN"||o==="SIGNED_OUT"||o==="SESSION_EXPIRED")&&(this.registered=void 0,this.changing=this.refresh().catch(()=>this.unsubscribe().catch(()=>{})))})}supported(){return!!this.g.navigator?.serviceWorker&&this.g.PushManager!==void 0&&this.g.Notification!==void 0}permission(){return this.supported()?this.g.Notification.permission:"unsupported"}workerUrl(e="/palbase-sw.js"){let t=new URLSearchParams({url:this.baseUrl,key:this.publishableKey});return`${e}${e.includes("?")?"&":"?"}${t}`}async subscribe(e={}){if(!this.supported())return!1;let t=this.g.Notification;if(t.permission==="default"&&await t.requestPermission()!=="granted"||t.permission==="denied")return!1;let s=this.g.navigator.serviceWorker,i=await s.register(this.workerUrl(e.serviceWorker),e.scope?{scope:e.scope}:void 0);await s.ready;let r=await i.pushManager.getSubscription(),a=(await this.api.getWebPushKey()).data.public_key;return r&&!Ft(r.options.applicationServerKey,a)&&(await r.unsubscribe(),r=null),r??=await i.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:et(a)}),await this.register(r),!0}async unsubscribe(){let e=await this.current();e&&await e.unsubscribe(),this.registered=void 0}async refresh(){if(!this.supported()||this.permission()!=="granted")return;let e=await this.current();e&&await this.register(e)}async current(){let e=this.g.navigator?.serviceWorker;return e?await(await e.getRegistration())?.pushManager.getSubscription()??null:null}async register(e){let t=e.toJSON(),s={endpoint:t.endpoint??e.endpoint,keys:{p256dh:t.keys?.p256dh??"",auth:t.keys?.auth??""}},r=`${this.session.snapshot()?.userId??""}|${s.endpoint}`;this.registered!==r&&(await this.api.registerDevice({headers:{[A]:O(this.installation)},body:{device_id:`web-${this.installation.id}`,token:JSON.stringify(s),platform:"web",locale:this.g.navigator?.language??null,installation_id:this.installation.id,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone}}),this.registered=r)}};function Ft(n,e){if(!n)return!1;let t=new Uint8Array(n),s=et(e);return t.length===s.length&&t.every((i,r)=>i===s[r])}var oe=class{push;inbox;inApp;constructor(e,t,s,i,r,a,o){this.push=new ve(e,t,s,a,o),this.inbox=new se(e,t),this.inApp=new re(e,t,s,new URL(a).origin,()=>this.push.subscribe(),()=>i.state("analytics")==="granted",r)}};var ae=class{api;session;socket;ref;fetch;appVersion;app;listeners=new Set;watch;following;last;constructor(e,t,s,i,r,a,o){this.api=_e.client(e),this.session=t,this.socket=s,this.ref=i,this.fetch=r,this.appVersion=a,this.app=o}async me(){let e=this.session.snapshot()?.userId,t=(await this.api.getMyCustomerInfo()).data;return this.watch&&this.watch.userId===e&&this.offer(this.watch,t),t}async offerings(e="web"){return(await this.api.getOfferings({query:{channel:e}})).data}async paywall(e,t={}){return Ce(this.api,this.ref,e,s=>this.checkout(s),{signal:t.signal,fetch:this.fetch,attributes:t.attributes,locale:t.locale,appVersion:this.appVersion,app:this.app})}async checkout(e){let t={product:e.product,plan:e.plan,success_url:e.successUrl,cancel_url:e.cancelUrl,source:e.source,...e.offer!==void 0?{offer:e.offer}:{}},s=(await this.api.createCheckout({body:t})).data;return s.redemption_key&&Ht(this.keyName(s.session_id),s.redemption_key),s.url}async redemptionLink(e,t={}){let s=t.key??Gt(this.keyName(e));if(!s)throw new P({op:"CreateCheckoutRedemption",status:0,code:"redemption_key_missing",message:"no redemption key for this checkout in this tab: the link was sent to the buyer's email"});let i=Date.now()+(t.waitSeconds??20)*1e3;for(;;)try{return(await this.api.createCheckoutRedemption({body:{session_id:e,key:s},signal:t.signal})).data}catch(r){let a=(r instanceof P&&r.code==="checkout_not_paid"?r.retryAfter??2:-1)*1e3;if(a<0||Date.now()+a>i)throw r;await Wt(a,t.signal)}}async redeem(e){let t=Vt(e);if(!t)throw new P({op:"RedeemPurchase",status:0,code:"invalid_redemption_link",message:"not a redemption link: <scheme>://palbase/redeem?token=\u2026 or \u2026/purchases/redeem?token=\u2026"});let s=this.session.snapshot()?.userId,i=(await this.api.redeemPurchase({body:{token:t}})).data;return this.watch&&this.watch.userId===s&&this.offer(this.watch,i),i}async offers(){return(await this.api.listMyOffers()).data.offers}async offerShown(e){await this.api.recordOfferView({path:{offer_key:e}})}async claimOffer(e){return(await this.api.claimOffer({path:{offer_key:e}})).data}async redeemCoupon(e){return(await this.api.redeemCoupon({body:{code:e}})).data}async portal(e){return(await this.api.createPortalSession({body:{return_url:e}})).data.url}async mergeGrant(){return(await this.api.createMergeGrant()).data}async merge(e){let t=this.session.snapshot()?.userId,s=(await this.api.mergeGuest({body:{grant:typeof e=="string"?e:e.grant}})).data;return this.watch&&this.watch.userId===t&&this.offer(this.watch,s),s}keyName(e){return`palbase:${this.ref}:redemption:${e}`}onCustomerInfo(e){if(this.listeners.add(e),this.listeners.size===1)this.start();else if(this.last!==void 0){let t=this.last;queueMicrotask(()=>this.listeners.has(e)&&tt(e,t))}return()=>{this.listeners.delete(e)&&this.listeners.size===0&&this.stop()}}start(){this.following=this.session.onChange((e,t)=>{(e==="SIGNED_IN"||e==="SIGNED_OUT"||e==="SESSION_EXPIRED")&&this.follow(t)}),this.session.session().then(e=>{this.following&&!this.watch&&this.last===void 0&&this.follow(e)})}stop(){this.following?.(),this.following=void 0,this.unfollow(),this.last=void 0}follow(e){if(this.unfollow(),!e){this.tell(null);return}let t=this.socket.channel(`purchases:${this.ref}:${e.userId}`),s={userId:e.userId,channel:t,off:()=>{},revision:-1,reading:!1,wanted:Number.NEGATIVE_INFINITY},i=[t.on("broadcast",r=>{r.event==="changed"&&this.changed(s,we(r.payload))}),t.on("state_snapshot",r=>this.held(s,we(st(r.entries)))),t.on("state_diff",r=>this.held(s,we(st(r.set))))];s.off=()=>i.forEach(r=>r()),this.watch=s,t.join().catch(()=>{}),this.read(s)}unfollow(){let e=this.watch;e&&(this.watch=void 0,e.off(),e.channel.leave())}changed(e,t){this.watch!==e||t!==void 0&&t<=e.revision||(e.reading?e.wanted=Math.max(e.wanted,t??Number.POSITIVE_INFINITY):this.read(e))}held(e,t){t!==void 0&&this.changed(e,t)}async read(e){e.reading=!0;try{for(;;){e.wanted=Number.NEGATIVE_INFINITY;try{let t=(await this.api.getMyCustomerInfo()).data;if(this.watch!==e)return;this.offer(e,t)}catch{}if(this.watch!==e||e.wanted<=e.revision)return}}finally{e.reading=!1}}offer(e,t){this.watch!==e||t.revision<=e.revision||(e.revision=t.revision,this.tell(t))}tell(e){if(!(this.last===null&&e===null)){this.last=e;for(let t of[...this.listeners])tt(t,e)}}};function tt(n,e){try{n(e)}catch{}}function st(n){let e=typeof n=="object"&&n!==null?n.revision:void 0;return typeof e=="object"&&e!==null?e.v:void 0}function we(n){let e=typeof n=="object"&&n!==null?n.revision:void 0;return typeof e=="number"&&Number.isFinite(e)?e:void 0}var nt=/^[A-Za-z0-9_-]{43}$/;function Vt(n){let e=n.trim();if(nt.test(e))return e;let t;try{t=new URL(e)}catch{return}let s=t.host==="palbase"&&t.pathname==="/redeem",i=(t.protocol==="https:"||t.protocol==="http:")&&t.pathname==="/purchases/redeem",r=t.searchParams.get("token");return(s||i)&&r!==null&&nt.test(r)?r:void 0}function Ht(n,e){try{globalThis.sessionStorage?.setItem(n,e)}catch{}}function Gt(n){try{return globalThis.sessionStorage?.getItem(n)??void 0}catch{return}}function Wt(n,e){return new Promise((t,s)=>{if(e?.aborted)return s(e.reason);let i=setTimeout(()=>{e?.removeEventListener("abort",r),t()},n),r=()=>{clearTimeout(i),s(e?.reason)};e?.addEventListener("abort",r,{once:!0})})}var ce=class{api;session;socket;installation;ref;analytics;appVersion;storageKey;held;listeners=new Set;started;leave=[];running;queued;fresh=!0;constructor(e,t,s,i,r,a,o,c){this.api=Se.client(e),this.session=t,this.socket=s,this.installation=i,this.ref=r,this.analytics=o,this.appVersion=c,this.storageKey=`palbase.flags.${a}`,this.held=Jt(this.storageKey)}value(e){let t=this.mine();if(!t||!Object.hasOwn(t.values,e))return;let s=t.experiments[e];return s&&this.analytics.captureOnce(`$flag_exposure:${e}:${s.experiment_id}`,"$flag_exposure",{flag:e,experiment:s.experiment_id,variant:s.variant}),t.values[e]}bool(e,t){let s=this.value(e);return typeof s=="boolean"?s:t}string(e,t){let s=this.value(e);return typeof s=="string"?s:t}number(e,t){let s=this.value(e);return typeof s=="number"&&Number.isFinite(s)?s:t}json(e,t){let s=this.value(e);return typeof s=="object"&&s!==null?s:t}all(){return{...this.mine()?.values}}source(e){return this.mine()?.sources[e]}get version(){return this.mine()?.syncVersion}onChange(e){return this.listeners.add(e),this.start(),()=>{this.listeners.delete(e)}}refresh(){return this.started?this.read():this.start()}mine(){this.start();let e=this.held;return e&&e.user===(this.session.snapshot()?.userId??null)?e:void 0}start(){if(this.started)return this.started;this.session.onChange((t,s)=>{(t==="SIGNED_IN"||t==="SIGNED_OUT"||t==="SESSION_EXPIRED")&&this.follow(s).catch(()=>{})});let e=this.session.session().then(t=>this.follow(t));return e.catch(()=>{}),this.started=e,e}follow(e){let t=e?.userId??null;if(this.held&&this.held.user!==t){let s=Object.keys(this.held.values);this.held=void 0,it(this.storageKey,void 0),this.tell(s)}return this.join(t),this.fresh=!0,this.read()}join(e){for(let s of this.leave.splice(0))s();let t=[`flags:${this.ref}`,...e!==null?[`flags:${this.ref}:${e}`]:[]];for(let s of t){let i=this.socket.channel(s),r=[i.on("broadcast",a=>{a.event==="changed"&&this.changed(be(a.payload))}),i.on("state_snapshot",a=>this.changed(be(rt(a.entries)))),i.on("state_diff",a=>this.changed(be(rt(a.set))))];i.join().catch(()=>{}),this.leave.push(()=>{r.forEach(a=>a()),i.leave()})}}changed(e){if(e===void 0)return;let t=this.mine();t&&Number(t.syncVersion)>=e||this.read().catch(()=>{})}read(){if(this.queued)return this.queued;let e=(this.running??Promise.resolve()).catch(()=>{}).then(()=>(this.queued=void 0,this.fetch()));this.queued=e,this.running=e;let t=()=>{this.running===e&&(this.running=void 0)};return e.then(t,t),e}async fetch(){let e=(await this.session.session())?.userId??null,t=this.held?.user===e?this.held:void 0,s=this.headers(e,t?.etag);if(t&&!this.fresh)try{let l=await this.api.getDelta({query:{since:Number(t.syncVersion)},headers:s});if(l.status===304)return;let d={...t,values:{...t.values},sources:{...t.sources},experiments:{...t.experiments},syncVersion:l.data.sync_version,etag:l.headers.get("etag")??t.etag},g=new Set;for(let p of l.data.ops)g.add(p.key),p.op==="delete"?(delete d.values[p.key],delete d.sources[p.key],delete d.experiments[p.key]):(d.values[p.key]=p.value??null,d.sources[p.key]=p.source,p.experiment?d.experiments[p.key]=p.experiment:delete d.experiments[p.key]);this.apply(d,[...g]);return}catch(l){if(!(l instanceof P&&l.status===410))throw l}let i=await this.api.getSnapshot({headers:s});if(this.fresh=!1,i.status===304)return;let r=i.data,a={user:e,values:r.values,sources:r.sources,experiments:r.experiments??{},syncVersion:r.sync_version,contextHash:r.context_hash,etag:i.headers.get("etag")??void 0},o=t?.values??{},c=[...new Set([...Object.keys(o),...Object.keys(a.values)])].filter(l=>JSON.stringify(o[l])!==JSON.stringify(a.values[l]));this.apply(a,c)}headers(e,t){return{"X-Platform":"web",...this.appVersion?{"X-Palbase-Client-Version":this.appVersion}:{},[X]:this.installation.id,...e===null?{[A]:O(this.installation)}:{},...t?{"If-None-Match":t}:{}}}apply(e,t){if(e.user!==(this.session.snapshot()?.userId??null))return;let s=this.held?.user===e.user?this.held:void 0;s&&!(Number(e.syncVersion)>Number(s.syncVersion)||e.syncVersion===s.syncVersion&&e.contextHash!==s.contextHash)||(this.held=e,it(this.storageKey,e),t.length>0&&this.tell(t))}tell(e){for(let t of[...this.listeners])try{t(e)}catch{}}};function ke(){try{return globalThis.localStorage}catch{return}}function Jt(n){try{let e=ke()?.getItem(n);if(!e)return;let t=JSON.parse(e);return typeof t!="object"||t===null||typeof t.values!="object"||t.values===null||typeof t.syncVersion!="string"?void 0:{user:typeof t.user=="string"?t.user:null,values:t.values,sources:t.sources??{},experiments:t.experiments??{},syncVersion:t.syncVersion,contextHash:t.contextHash??"",...typeof t.etag=="string"?{etag:t.etag}:{}}}catch{return}}function it(n,e){try{e?ke()?.setItem(n,JSON.stringify(e)):ke()?.removeItem(n)}catch{}}function rt(n){let e=typeof n=="object"&&n!==null?n.sync_version:void 0;return typeof e=="object"&&e!==null?e.v:void 0}function be(n){let e=typeof n=="object"&&n!==null?n.sync_version:void 0;return typeof e=="number"&&Number.isFinite(e)?e:void 0}var le=class{api;open;session;credentials;mfa;passkey;magicLink;phone;password;email;sessions;constructor(e,t,s,i){this.api=j.client(e),this.open=j.client(t),this.session=s,this.credentials=i;let r=this.api,a=this.open;this.mfa={challenge:async(o,c,l)=>this.signedIn((await a.mfaChallenge({body:{mfa_token:o,type:c,code:l}})).data),recovery:async(o,c)=>this.signedIn((await a.mfaRecovery({body:{mfa_token:o,code:c}})).data),sendSmsCode:async o=>{await a.mfaSmsChallenge({body:{mfa_token:o}})},sendEmailCode:async o=>{await a.mfaEmailChallenge({body:{mfa_token:o}})},enrollTotp:async()=>{let o=(await r.mfaEnroll({body:{type:"totp"}})).data;return{enrollmentId:o.enrollment_id,secret:o.secret,otpUrl:o.otp_url,qrCode:o.qr_code,recoveryCodes:o.recovery_codes}},verifyTotp:async o=>{await r.mfaVerifyEnrollment({body:{code:o}})},enrollSms:async o=>(await r.mfaSmsEnroll({body:{phone:o}})).data,verifySms:async o=>{await r.mfaSmsVerifyEnrollment({body:{code:o}})},enrollEmail:async()=>{await r.mfaEmailEnroll()},factors:async()=>(await r.mfaListFactors()).data,removeFactor:async(o,c)=>{await r.mfaRemoveFactor({path:{id:o},body:{current_password:c}})},regenerateRecoveryCodes:async()=>(await r.mfaRegenerateRecoveryCodes()).data},this.passkey={register:async o=>{let c=(await r.webauthnRegisterBegin({body:{name:o}})).data,l=await this.authenticator().create({publicKey:ot(c.options.publicKey)});return(await r.webauthnRegisterFinish({body:ct(l)})).data},signIn:async(o={})=>{let c=(await a.webauthnLoginBegin({body:o.userId?{user_id:o.userId}:{}})).data,l=await this.authenticator().get({publicKey:at(c.options.publicKey)}),d=await a.webauthnLoginFinish({query:o.userId?{user_id:o.userId}:void 0,body:lt(l)});return this.signedIn(d.data)},signUp:async(o,c)=>{let l=(await a.webauthnSignupBegin({body:{identifier:o,user_name:c}})).data,d=await this.authenticator().create({publicKey:ot(l.options.publicKey)});await a.webauthnSignupFinish({query:{user_id:l.user_id},body:ct(d)});let g=(await a.webauthnLoginBegin({body:{user_id:l.user_id}})).data,p=await this.authenticator().get({publicKey:at(g.options.publicKey)});return this.signedIn((await a.webauthnLoginFinish({query:{user_id:l.user_id},body:lt(p)})).data)},list:async()=>(await r.webauthnListCredentials()).data,remove:async o=>{await r.webauthnDeleteCredential({path:{id:o}})}},this.magicLink={send:async(o,c={})=>{await a.magicLinkRequest({body:{email:o,...c.redirectTo?{redirect_to:c.redirectTo}:{}}})},verify:async o=>this.signedIn((await a.magicLinkVerify({body:{token:o}})).data)},this.phone={sendCode:async o=>(await a.requestPhoneOtp({body:{phone:o,channel:"sms"}})).data,verifyCode:async(o,c)=>this.signInResult((await a.verifyPhoneOtp({body:{phone:o,token:c}})).data)},this.password={requestReset:async(o,c={})=>{await a.passwordResetRequest({body:{email:o,...c.redirectTo?{redirect_to:c.redirectTo}:{}}})},confirmReset:async(o,c)=>{await a.passwordResetConfirm({body:{token:o,new_password:c}})},change:async o=>(await r.passwordChange({body:o})).data,set:async o=>(await r.setPassword({body:o})).data},this.email={verify:async o=>{await a.verifyEmail({body:o})},resendVerification:async o=>(await a.resendVerification({body:{email:o}})).data},this.sessions={list:async()=>(await r.listSessions()).data,revoke:async o=>{await r.revokeSession({path:{id:o}})},revokeAll:async()=>{await r.revokeAllSessions()}}}onAuthStateChange(e){return this.session.onChange(e)}currentSession(){return this.session.session()}get sessionEndReason(){return this.session.endReason}async signUp(e){let t=(await this.open.signup({body:e})).data;return t.access_token&&t.refresh_token&&t.expires_in!==void 0&&await this.session.set({access_token:t.access_token,refresh_token:t.refresh_token,expires_in:t.expires_in},"SIGNED_IN",t.user),t}async signIn(e,t){return this.signInResult((await this.open.login({body:{email:e,password:t}})).data)}async signOut(){try{await this.session.session()&&await this.api.logout()}finally{await this.session.clear("SIGNED_OUT")}}async getUser(){let e=this.session.snapshot(),t=(await this.api.getMe()).data;return await this.session.setUser(t,e),t}async refreshSession(){return this.session.refresh()}async deleteAccount(e){await this.api.deleteAccount(e===void 0?void 0:{body:{password:e}}),await this.session.clear("SIGNED_OUT")}async signInResult(e){return"mfa_required"in e&&e.mfa_required?{mfaRequired:{mfaToken:e.mfa_token,factors:e.factors}}:{user:await this.signedIn(e)}}async setSession(e){return this.signedIn(e)}async signedIn(e){let t=await this.session.set({access_token:e.access_token,refresh_token:e.refresh_token,expires_in:e.expires_in},"SIGNED_IN",e.user);if(e.user)return e.user;let s=(await this.api.verifyTokenUser()).data;return await this.session.setUser(s,t),s}authenticator(){if(!this.credentials)throw new Error("passkeys need navigator.credentials (or createClient({ webauthn }))");return this.credentials}},de=n=>{let e=atob(n.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(n.length/4)*4,"=")),t=new Uint8Array(e.length);for(let s=0;s<e.length;s++)t[s]=e.charCodeAt(s);return t.buffer},N=n=>{if(!n)return;let e=n instanceof ArrayBuffer?new Uint8Array(n):new Uint8Array(n.buffer,n.byteOffset,n.byteLength),t="";for(let s of e)t+=String.fromCharCode(s);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},dt=n=>Array.isArray(n)?n.map(e=>({...e,id:de(String(e.id))})):void 0;function ot(n){let e=n.user;return{...n,challenge:de(String(n.challenge)),user:{...e,id:de(String(e.id))},excludeCredentials:dt(n.excludeCredentials)}}function at(n){return{...n,challenge:de(String(n.challenge)),allowCredentials:dt(n.allowCredentials)}}function ct(n){let e=n,t=e.response;return{id:e.id,rawId:N(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:N(t.clientDataJSON),attestationObject:N(t.attestationObject),transports:t.getTransports?.()}}}function lt(n){let e=n,t=e.response;return{id:e.id,rawId:N(e.rawId),type:"public-key",authenticatorAttachment:e.authenticatorAttachment??void 0,clientExtensionResults:e.getClientExtensionResults?.()??{},response:{clientDataJSON:N(t.clientDataJSON),authenticatorData:N(t.authenticatorData),signature:N(t.signature),userHandle:N(t.userHandle)}}}var ut=new WeakMap;var Bt=/^pb_[a-z0-9]+_s/,Xt=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,zt=new Set(["invalid_token","token_expired","session_expired","session_revoked","missing_token"]),Yt=new Set(["invalid_token","token_reuse","token_expired","session_revoked","session_expired","session_device_changed"]);function Zt(n){return n.status===400&&n.code==="invalid_request"}function zs(n){if(Bt.test(n.publishableKey)||"secretKey"in n)throw new TypeError("a secret key never goes into a client app: palbase/web takes the publishable key (pb_<ref>_c\u2026); servers use palbase/server");let e=/^pb_([a-z0-9]+)_c/.exec(n.publishableKey)?.[1];if(e===void 0)throw new TypeError("publishableKey is the project publishable key (pb_<ref>_c\u2026)");if(n.appId!==void 0&&!Xt.test(n.appId))throw new TypeError("appId is the registered app's id, a UUID (settings.appId of palbase apps:sync), not its slug");let t=ht(n.language),s=(y,w)=>{let I=n.fetch??globalThis.fetch;if(t===void 0)return I(y,w);let x=new Headers(w?.headers);return x.has("accept-language")||x.set("accept-language",t),I(y,{...w,headers:x})},i=new URL(n.url).origin,r=n.storage??(es()?Ne(`palbase.session.${i}`):Me()),a=n.retry??Ie,o=H(U({baseUrl:n.url,credentials:{publishableKey:n.publishableKey},fetch:s}),a),c=j.client(o),l=new G(r,async y=>(await c.refreshToken({body:{refresh_token:y}})).data,y=>y instanceof P&&(y.status===401&&Yt.has(y.code)||Zt(y)),{lockName:`palbase.session.refresh.${i}`,refresh:n.refresh}),d=U({baseUrl:n.url,credentials:{publishableKey:n.publishableKey,accessToken:()=>l.accessToken()},fetch:s,xmlHttpRequest:n.xmlHttpRequest??(n.fetch===void 0?globalThis.XMLHttpRequest:void 0)}),g=H(ue(d,l),a),p=new J({baseUrl:n.url,publishableKey:n.publishableKey,accessToken:()=>l.accessToken(),webSocket:n.webSocket});l.onChange(y=>{y==="SIGNED_OUT"||y==="SESSION_EXPIRED"||y==="SIGNED_IN"?p.disconnect():y==="TOKEN_REFRESHED"&&p.tokenChanged()});let k=new B(i),S=y=>H(ue(U({baseUrl:n.url,credentials:{publishableKey:n.publishableKey,accessToken:async()=>{let w=await l.accessToken();if(w===void 0||fe(w)!==y)throw new T(`the session is no longer ${y}'s`);return w}},fetch:s}),l),a),u=y=>j.client(S(y)),f=new ee({userApi:u,deviceApi:c,session:l,socket:p,ref:e,installation:k,origin:i,options:n.consent}),m=U({baseUrl:n.url,credentials:{publishableKey:n.publishableKey},fetch:s}),b=new Z(ue(d,l),m,l,f,k,i),R=new ae(g,l,p,e,s,n.appVersion,n.appId),L=new oe(g,l,k,f,R,n.url,n.publishableKey);b.onEvent((y,w)=>L.inApp.trigger(y,w)),n.analytics&&b.start(n.analytics===!0?{}:n.analytics);let q=new Map,he=y=>{let w=new URL(y).origin,I=q.get(w);return I||(I=H(ue(U({baseUrl:w,credentials:{accessToken:()=>l.accessToken()},fetch:s}),l),a),q.set(w,I)),I},h=Re(g),v=Object.assign(Object.create(Ae),{auth:new le(g,o,l,n.webauthn??globalThis.navigator?.credentials),socket:p,transport:g,analytics:b,consent:f,installation:k,purchases:R,notify:L,flags:new ce(g,l,p,k,e,i,b,n.appVersion),setLanguage(y){t=ht(y??void 0)},chatToolCall:(y,w,I={})=>h.toolCall(y,w,I.signal),chatWorkspaceFile:(y,w,I,x={})=>h.workspaceFile(y,w,I,x.signal)});return Oe(v,i,he,g,p,()=>l.snapshot()?.userId),ut.set(v,{transport:g,transportFor:S,session:l,socket:p,ref:e,fetch:s}),v}var Qt=/^[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*$/;function ht(n){if(n===void 0)return;let e=typeof n=="string"?[n]:[...n];if(e.length!==0){for(let t of e)if(!Qt.test(t))throw new TypeError(`language ${JSON.stringify(t)} is a BCP 47 tag ("tr", "pt-BR")`);return e.map((t,s)=>s===0?t:`${t};q=${Math.max(.1,1-s/10).toFixed(1)}`).join(", ")}}function es(){try{return typeof globalThis.localStorage<"u"}catch{return!1}}function ue(n,e){return{async send(t){let s=await e.session();try{return await n.send(t)}catch(i){let r=t.auth.some(a=>a.includes("userJWT"));if(!(i instanceof P)||i.status!==401||!zt.has(i.code)||!r||!s)throw i;try{e.snapshot()?.refreshToken===s.refreshToken&&await e.refresh()}catch{throw i}if(e.snapshot()?.userId!==s.userId)throw i;return n.send(t)}}}}export{T as a,Me as b,Ne as c,ge as d,J as e,B as f,Z as g,ee as h,se as i,ne as j,re as k,ve as l,oe as m,ae as n,Vt as o,ce as p,zs as q};
|