palbase 0.26.0 → 0.27.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/{2LNRLAVP.js → 2VZXMKE4.js} +2 -2
- package/dist/chunks/{HMQIA6DH.js → 5ETIB37E.js} +2 -2
- package/dist/chunks/{BN5FJ3YM.js → 5PLOENVJ.js} +1 -1
- package/dist/chunks/{DVRO2E2S.js → 7CVC2UYK.js} +2 -2
- package/dist/chunks/{4I34RRBK.js → AVQ7DQA4.js} +1 -1
- package/dist/chunks/{72VOVUBT.js → BRK5A42K.js} +3 -3
- package/dist/chunks/BXJGHBB5.js +2 -0
- package/dist/chunks/{RC4ZSGS2.js → CTKJ7E5R.js} +2 -2
- package/dist/chunks/{CZMQEBC6.js → HHQ5RAYH.js} +2 -2
- package/dist/chunks/{5RWEOPF2.js → HKLIKCYR.js} +2 -2
- package/dist/chunks/{QUX35QKY.js → JCS5FSY6.js} +2 -2
- package/dist/chunks/{OTWMAAPL.js → LXS4IDDQ.js} +2 -2
- package/dist/chunks/{B4ZHHG4H.js → NGAXCQJ4.js} +2 -2
- package/dist/chunks/{EAHHUIQP.js → O5LG6IFL.js} +1 -1
- package/dist/chunks/{V2OJIKUV.js → QL42CXIT.js} +1 -1
- package/dist/chunks/{DK2JMPU3.js → R2KG2E4H.js} +2 -2
- package/dist/chunks/{GHQTIJT7.js → UJATFHC4.js} +2 -2
- package/dist/chunks/{SB36QYBM.js → UWZP4YV6.js} +2 -2
- package/dist/chunks/{UKRY3HRA.js → XUZ532UW.js} +1 -1
- package/dist/chunks/{Q4E3WXGS.js → Y2RBMBJB.js} +1 -1
- package/dist/chunks/{FBCZT7JT.js → YS5GF7JB.js} +2 -2
- package/dist/chunks/ZBY3Q6Q2.js +2 -0
- package/dist/chunks/{4W2CWOGO.js → ZN4ELT45.js} +1 -1
- package/dist/cli.js +116 -116
- package/dist/cloud/index.js +2 -2
- package/dist/refuse/ai.js +1 -1
- package/dist/refuse/backend.js +1 -1
- package/dist/refuse/cloud.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/modules/events.d.ts +2 -2
- package/types/internal/src/modules/messaging.d.ts +245 -12
- package/types/server/src/server.d.ts +8 -0
- package/types/web/src/messaging.d.ts +47 -6
- package/dist/chunks/M5MRZQPV.js +0 -2
- package/dist/chunks/QUPZ6GF5.js +0 -2
|
@@ -80,15 +80,27 @@ export type AdminConversationRequest = {
|
|
|
80
80
|
*/
|
|
81
81
|
photo?: string;
|
|
82
82
|
settings?: GroupSettings;
|
|
83
|
+
/**
|
|
84
|
+
* The place of the app's it belongs to, as the app names it (org:<id>, project:<id>): 1 to 128 letters, digits and : _ . / @ -. Fixed as it is made; absent: none.
|
|
85
|
+
*/
|
|
86
|
+
space?: string;
|
|
83
87
|
/**
|
|
84
88
|
* A group's title.
|
|
85
89
|
*/
|
|
86
90
|
title?: string;
|
|
91
|
+
/**
|
|
92
|
+
* open (a space named: required): found in its space's open groups and joined by whom the project's hook lets (POST …/join); closed (the default): joined when someone adds you. A direct conversation is never open.
|
|
93
|
+
*/
|
|
94
|
+
visibility?: "open" | "closed";
|
|
87
95
|
};
|
|
88
96
|
/**
|
|
89
|
-
* A message the project's server says, as the
|
|
97
|
+
* A message the project's server says: as the app, or as one of the conversation's people (as_user_id, with via).
|
|
90
98
|
*/
|
|
91
99
|
export type AdminMessageRequest = {
|
|
100
|
+
/**
|
|
101
|
+
* The person it is written as: one of the conversation's people now. The message is theirs, as if they sent it — what they may send there, their read of it, the others' unread counts and pushes, from them — and says via what wrote it. Each is in the access log, the person named.
|
|
102
|
+
*/
|
|
103
|
+
as_user_id?: string;
|
|
92
104
|
/**
|
|
93
105
|
* The server's own id of it: sent again with it, it is the same message.
|
|
94
106
|
*/
|
|
@@ -101,6 +113,14 @@ export type AdminMessageRequest = {
|
|
|
101
113
|
* What it says.
|
|
102
114
|
*/
|
|
103
115
|
text: string;
|
|
116
|
+
/**
|
|
117
|
+
* The message whose thread it answers.
|
|
118
|
+
*/
|
|
119
|
+
thread_id?: string;
|
|
120
|
+
/**
|
|
121
|
+
* What wrote it (as pal), shown with the message (Message.via): 1 to 32 letters, digits and _ . -. Required with as_user_id — the others always know it was not the person's own hand.
|
|
122
|
+
*/
|
|
123
|
+
via?: string;
|
|
104
124
|
};
|
|
105
125
|
/**
|
|
106
126
|
* The project's server's word on a person's name and picture.
|
|
@@ -159,6 +179,10 @@ export type AdminUpdateConversation = {
|
|
|
159
179
|
* A direct conversation's vanish mode.
|
|
160
180
|
*/
|
|
161
181
|
vanish?: boolean;
|
|
182
|
+
/**
|
|
183
|
+
* A group's: open (found in its space's open groups and joined by whom the project's hook lets; the group has a space — 400 space_required otherwise) or closed. Its admins' (or the project's server's); a person opening one is asked of the hook first (open_group): refused, 403 not_allowed. Opened, whoever joins reads what its history shows newcomers (history_for_new_members).
|
|
184
|
+
*/
|
|
185
|
+
visibility?: "open" | "closed";
|
|
162
186
|
};
|
|
163
187
|
/**
|
|
164
188
|
* A file a message carries.
|
|
@@ -335,6 +359,10 @@ export type Conversation = {
|
|
|
335
359
|
*/
|
|
336
360
|
photo: string | null;
|
|
337
361
|
settings: ConversationSettings;
|
|
362
|
+
/**
|
|
363
|
+
* The place of the app's it belongs to (org:<id>, project:<id>), fixed as it was made; null: none. Always sent; absent (an answer kept from before it was): null.
|
|
364
|
+
*/
|
|
365
|
+
space?: string | null;
|
|
338
366
|
/**
|
|
339
367
|
* A group's title.
|
|
340
368
|
*/
|
|
@@ -343,6 +371,10 @@ export type Conversation = {
|
|
|
343
371
|
* How many times it changed.
|
|
344
372
|
*/
|
|
345
373
|
version: number;
|
|
374
|
+
/**
|
|
375
|
+
* open: a group found in its space's open groups and joined by whom the project's hook lets; closed: joined when someone adds you (every direct conversation). Always sent; absent (an answer kept from before it was): closed.
|
|
376
|
+
*/
|
|
377
|
+
visibility?: "open" | "closed";
|
|
346
378
|
};
|
|
347
379
|
/**
|
|
348
380
|
* A conversation made, and whom it did not take.
|
|
@@ -374,6 +406,10 @@ export type ConversationCreatedEvent = {
|
|
|
374
406
|
* Its people.
|
|
375
407
|
*/
|
|
376
408
|
member_ids: string[];
|
|
409
|
+
/**
|
|
410
|
+
* Its space; null: none.
|
|
411
|
+
*/
|
|
412
|
+
space?: string | null;
|
|
377
413
|
};
|
|
378
414
|
/**
|
|
379
415
|
* messaging.conversation.deleted
|
|
@@ -398,6 +434,31 @@ export type ConversationPage = {
|
|
|
398
434
|
*/
|
|
399
435
|
next_cursor?: string;
|
|
400
436
|
};
|
|
437
|
+
/**
|
|
438
|
+
* messaging.conversation.read
|
|
439
|
+
*/
|
|
440
|
+
export type ConversationReadEvent = {
|
|
441
|
+
/**
|
|
442
|
+
* The conversation.
|
|
443
|
+
*/
|
|
444
|
+
conversation_id: string;
|
|
445
|
+
/**
|
|
446
|
+
* How far they read it (a message's seq).
|
|
447
|
+
*/
|
|
448
|
+
read_seq: number;
|
|
449
|
+
/**
|
|
450
|
+
* The conversation's space; null: none.
|
|
451
|
+
*/
|
|
452
|
+
space: string | null;
|
|
453
|
+
/**
|
|
454
|
+
* The thread they read; null: the conversation itself.
|
|
455
|
+
*/
|
|
456
|
+
thread_id: string | null;
|
|
457
|
+
/**
|
|
458
|
+
* Who read it.
|
|
459
|
+
*/
|
|
460
|
+
user_id: string;
|
|
461
|
+
};
|
|
401
462
|
/**
|
|
402
463
|
* How a conversation runs.
|
|
403
464
|
*/
|
|
@@ -432,9 +493,13 @@ export type ConversationSettings = {
|
|
|
432
493
|
vanish: boolean;
|
|
433
494
|
};
|
|
434
495
|
/**
|
|
435
|
-
* Opens the direct conversation with a person.
|
|
496
|
+
* Opens the direct conversation with a person, in a space.
|
|
436
497
|
*/
|
|
437
498
|
export type DirectRequest = {
|
|
499
|
+
/**
|
|
500
|
+
* The space it is in (org:<id>): the pair has one direct conversation in each space, and one with none. 1 to 128 letters, digits and : _ . / @ -; absent: none.
|
|
501
|
+
*/
|
|
502
|
+
space?: string;
|
|
438
503
|
/**
|
|
439
504
|
* The other person.
|
|
440
505
|
*/
|
|
@@ -521,10 +586,18 @@ export type GroupRequest = {
|
|
|
521
586
|
*/
|
|
522
587
|
photo?: string;
|
|
523
588
|
settings?: GroupSettings;
|
|
589
|
+
/**
|
|
590
|
+
* The place of the app's it belongs to, as the app names it (org:<id>, project:<id>): 1 to 128 letters, digits and : _ . / @ -. Fixed as it is made; absent: none.
|
|
591
|
+
*/
|
|
592
|
+
space?: string;
|
|
524
593
|
/**
|
|
525
594
|
* Its title.
|
|
526
595
|
*/
|
|
527
596
|
title: string;
|
|
597
|
+
/**
|
|
598
|
+
* open (a space named: required): found in its space's open groups and joined by whom the project's hook lets (POST …/join); closed (the default): joined when someone adds you. A person's open group is asked of the project's hook first (open_group, the space named): refused, 403 not_allowed.
|
|
599
|
+
*/
|
|
600
|
+
visibility?: "open" | "closed";
|
|
528
601
|
};
|
|
529
602
|
/**
|
|
530
603
|
* How a group runs, as it is made.
|
|
@@ -569,7 +642,7 @@ export type HiddenMessage = {
|
|
|
569
642
|
*/
|
|
570
643
|
export type HookSettings = {
|
|
571
644
|
/**
|
|
572
|
-
* When it does not answer: allow everyone, or deny (the client retries).
|
|
645
|
+
* When it does not answer: allow everyone, or deny (the client retries). Allow is for a direct conversation and people added to a group alone: a space's open groups — having one, finding them, joining one — are refused (503 hook_unavailable) while it is silent, whatever this says.
|
|
573
646
|
*/
|
|
574
647
|
on_error: "allow" | "deny";
|
|
575
648
|
/**
|
|
@@ -586,7 +659,7 @@ export type HookSettings = {
|
|
|
586
659
|
*/
|
|
587
660
|
export type HookSettingsRequest = {
|
|
588
661
|
/**
|
|
589
|
-
* allow or deny (default).
|
|
662
|
+
* allow or deny (default). Allow never opens a space's open groups (open_group, list_open, join): those are refused while the hook is silent.
|
|
590
663
|
*/
|
|
591
664
|
on_error?: "allow" | "deny";
|
|
592
665
|
/**
|
|
@@ -837,11 +910,76 @@ export type Message = {
|
|
|
837
910
|
* How many times it changed (a reaction, an answer in its thread, an edit).
|
|
838
911
|
*/
|
|
839
912
|
version: number;
|
|
913
|
+
/**
|
|
914
|
+
* What the project's server wrote it through, as one of the conversation's people or as the app (as pal): show it beside the message ("sent by Pal"). null: its writer wrote it. Always sent; absent (an answer kept from before it was): null.
|
|
915
|
+
*/
|
|
916
|
+
via?: string | null;
|
|
840
917
|
/**
|
|
841
918
|
* When it is seen a limited number of times.
|
|
842
919
|
*/
|
|
843
920
|
view_once: ViewOnce | null;
|
|
844
921
|
};
|
|
922
|
+
/**
|
|
923
|
+
* messaging.message.created
|
|
924
|
+
*/
|
|
925
|
+
export type MessageCreatedEvent = {
|
|
926
|
+
/**
|
|
927
|
+
* The conversation.
|
|
928
|
+
*/
|
|
929
|
+
conversation_id: string;
|
|
930
|
+
/**
|
|
931
|
+
* direct or group.
|
|
932
|
+
*/
|
|
933
|
+
conversation_kind: string;
|
|
934
|
+
/**
|
|
935
|
+
* When it was written.
|
|
936
|
+
*/
|
|
937
|
+
created_at: string;
|
|
938
|
+
/**
|
|
939
|
+
* Whether it carries files.
|
|
940
|
+
*/
|
|
941
|
+
has_attachments: boolean;
|
|
942
|
+
/**
|
|
943
|
+
* text or media (files).
|
|
944
|
+
*/
|
|
945
|
+
kind: string;
|
|
946
|
+
/**
|
|
947
|
+
* Whom its words name.
|
|
948
|
+
*/
|
|
949
|
+
mention_ids: string[];
|
|
950
|
+
/**
|
|
951
|
+
* The message: read it with the secret key (GET /messaging/admin/conversations/{conversation_id}/messages).
|
|
952
|
+
*/
|
|
953
|
+
message_id: string;
|
|
954
|
+
/**
|
|
955
|
+
* Whom it is for: the conversation's people but its writer (and one blocking them, whom it never reaches).
|
|
956
|
+
*/
|
|
957
|
+
recipient_ids: string[];
|
|
958
|
+
/**
|
|
959
|
+
* Its writer; null: the project's server, as the app.
|
|
960
|
+
*/
|
|
961
|
+
sender_id: string | null;
|
|
962
|
+
/**
|
|
963
|
+
* Its place in the conversation.
|
|
964
|
+
*/
|
|
965
|
+
seq: number;
|
|
966
|
+
/**
|
|
967
|
+
* The conversation's space; null: none.
|
|
968
|
+
*/
|
|
969
|
+
space: string | null;
|
|
970
|
+
/**
|
|
971
|
+
* What it says, when the project lets the event say it (settings.event_text) — never a message meant to go (vanish mode, seen a limited number of times, living a while): the event stream keeps an event 7 days; absent otherwise.
|
|
972
|
+
*/
|
|
973
|
+
text?: string;
|
|
974
|
+
/**
|
|
975
|
+
* The message whose thread it answers; null: none.
|
|
976
|
+
*/
|
|
977
|
+
thread_id: string | null;
|
|
978
|
+
/**
|
|
979
|
+
* What the project's server wrote it through (as pal); null: its writer wrote it.
|
|
980
|
+
*/
|
|
981
|
+
via: string | null;
|
|
982
|
+
};
|
|
845
983
|
export type MessagePage = {
|
|
846
984
|
/**
|
|
847
985
|
* The messages.
|
|
@@ -915,6 +1053,54 @@ export type NotificationsRequest = {
|
|
|
915
1053
|
*/
|
|
916
1054
|
notify_level?: "all" | "mentions" | "none";
|
|
917
1055
|
};
|
|
1056
|
+
/**
|
|
1057
|
+
* An open group of a space, as one who may find it reads it.
|
|
1058
|
+
*/
|
|
1059
|
+
export type OpenGroup = {
|
|
1060
|
+
/**
|
|
1061
|
+
* When it was made.
|
|
1062
|
+
*/
|
|
1063
|
+
created_at: string;
|
|
1064
|
+
/**
|
|
1065
|
+
* Its description.
|
|
1066
|
+
*/
|
|
1067
|
+
description: string | null;
|
|
1068
|
+
/**
|
|
1069
|
+
* The group.
|
|
1070
|
+
*/
|
|
1071
|
+
id: string;
|
|
1072
|
+
/**
|
|
1073
|
+
* Whether the reader is in it.
|
|
1074
|
+
*/
|
|
1075
|
+
joined: boolean;
|
|
1076
|
+
/**
|
|
1077
|
+
* When something was last said in it; null: nothing yet.
|
|
1078
|
+
*/
|
|
1079
|
+
last_message_at: string | null;
|
|
1080
|
+
/**
|
|
1081
|
+
* How many people are in it.
|
|
1082
|
+
*/
|
|
1083
|
+
member_count: number;
|
|
1084
|
+
/**
|
|
1085
|
+
* Where the app reads its picture.
|
|
1086
|
+
*/
|
|
1087
|
+
photo: string | null;
|
|
1088
|
+
/**
|
|
1089
|
+
* Its space.
|
|
1090
|
+
*/
|
|
1091
|
+
space: string;
|
|
1092
|
+
/**
|
|
1093
|
+
* Its title.
|
|
1094
|
+
*/
|
|
1095
|
+
title: string | null;
|
|
1096
|
+
};
|
|
1097
|
+
export type OpenGroupPage = {
|
|
1098
|
+
data: OpenGroup[];
|
|
1099
|
+
/**
|
|
1100
|
+
* The next page's cursor; absent on the last.
|
|
1101
|
+
*/
|
|
1102
|
+
next_cursor?: string;
|
|
1103
|
+
};
|
|
918
1104
|
/**
|
|
919
1105
|
* A person as the conversations show them.
|
|
920
1106
|
*/
|
|
@@ -1397,6 +1583,10 @@ export type Settings = {
|
|
|
1397
1583
|
* A deleted user's messages: keep (their writer anonymous) or delete.
|
|
1398
1584
|
*/
|
|
1399
1585
|
deleted_user_messages: "keep" | "delete";
|
|
1586
|
+
/**
|
|
1587
|
+
* Whether messaging.message.created says what the message says (text) — never a message meant to go (vanish mode, seen a limited number of times, living a while): the words leave the sealed store for the project's backend, kept on the event stream for 7 days. false: the backend reads the message with the secret key. Always sent; absent: false.
|
|
1588
|
+
*/
|
|
1589
|
+
event_text?: boolean;
|
|
1400
1590
|
/**
|
|
1401
1591
|
* The hook asked whom one may reach; null: anyone may reach anyone.
|
|
1402
1592
|
*/
|
|
@@ -1426,6 +1616,10 @@ export type SettingsRequest = {
|
|
|
1426
1616
|
* keep or delete.
|
|
1427
1617
|
*/
|
|
1428
1618
|
deleted_user_messages?: "keep" | "delete";
|
|
1619
|
+
/**
|
|
1620
|
+
* Whether messaging.message.created says what the message says (text).
|
|
1621
|
+
*/
|
|
1622
|
+
event_text?: boolean;
|
|
1429
1623
|
/**
|
|
1430
1624
|
* The hook; null removes it.
|
|
1431
1625
|
*/
|
|
@@ -1505,7 +1699,7 @@ export type SystemEvent = {
|
|
|
1505
1699
|
*/
|
|
1506
1700
|
title?: string;
|
|
1507
1701
|
/**
|
|
1508
|
-
* What happened: created, members_added, member_left, member_removed, role_changed, title_changed, description_changed, photo_changed, timer_changed, vanish_on, vanish_off, settings_changed, read_only_on, read_only_off, screenshot. A person whose account was deleted is named deleted_… here, as everywhere.
|
|
1702
|
+
* What happened: created, members_added, member_joined (one joined an open group by themselves), member_left, member_removed, role_changed, title_changed, description_changed, photo_changed, timer_changed, vanish_on, vanish_off, settings_changed, read_only_on, read_only_off, screenshot. A person whose account was deleted is named deleted_… here, as everywhere.
|
|
1509
1703
|
*/
|
|
1510
1704
|
type: string;
|
|
1511
1705
|
/**
|
|
@@ -1608,6 +1802,10 @@ export type UpdateConversation = {
|
|
|
1608
1802
|
* A direct conversation's vanish mode.
|
|
1609
1803
|
*/
|
|
1610
1804
|
vanish?: boolean;
|
|
1805
|
+
/**
|
|
1806
|
+
* A group's: open (found in its space's open groups and joined by whom the project's hook lets; the group has a space — 400 space_required otherwise) or closed. Its admins' (or the project's server's); a person opening one is asked of the hook first (open_group): refused, 403 not_allowed. Opened, whoever joins reads what its history shows newcomers (history_for_new_members).
|
|
1807
|
+
*/
|
|
1808
|
+
visibility?: "open" | "closed";
|
|
1611
1809
|
};
|
|
1612
1810
|
/**
|
|
1613
1811
|
* Changes a member's role.
|
|
@@ -1788,6 +1986,14 @@ export interface Events {
|
|
|
1788
1986
|
* messaging.conversation.deleted: a conversation was deleted for everyone.
|
|
1789
1987
|
*/
|
|
1790
1988
|
"messaging.conversation.deleted": ConversationDeletedEvent;
|
|
1989
|
+
/**
|
|
1990
|
+
* messaging.conversation.read: a person read a conversation, or a thread of it, further (a read receipt, or clearing it). Told only to the endpoints that name it, and written only while one does.
|
|
1991
|
+
*/
|
|
1992
|
+
"messaging.conversation.read": ConversationReadEvent;
|
|
1993
|
+
/**
|
|
1994
|
+
* messaging.message.created: a message reached a conversation — a person's, or the project's server's (as the app, or as a person: via) — with whom it is for and whom it names. Told only to the endpoints that name it (an endpoint of every event is not sent it), and written only while one does.
|
|
1995
|
+
*/
|
|
1996
|
+
"messaging.message.created": MessageCreatedEvent;
|
|
1791
1997
|
/**
|
|
1792
1998
|
* messaging.report.created: a person reported a conversation, someone in it or messages of it; read it with the secret key.
|
|
1793
1999
|
*/
|
|
@@ -1814,10 +2020,11 @@ export declare function client(t: Transport): {
|
|
|
1814
2020
|
*/
|
|
1815
2021
|
adminListConversations(input?: {
|
|
1816
2022
|
query?: {
|
|
1817
|
-
user_id?: string; /** Another person, beside user_id: the direct conversation of the two (none when they have none). */
|
|
2023
|
+
user_id?: string; /** Another person, beside user_id: the direct conversation of the two (none when they have none): their direct conversations in every space (space narrows them). */
|
|
1818
2024
|
with?: string; /** How many (1 to 100; 30 when absent). */
|
|
1819
2025
|
limit?: number; /** The cursor a page handed out (next_cursor). */
|
|
1820
|
-
cursor?: string;
|
|
2026
|
+
cursor?: string; /** Only the conversations of these spaces: one space a parameter, repeated for more, at most 20. */
|
|
2027
|
+
space?: string[];
|
|
1821
2028
|
}; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
1822
2029
|
signal?: AbortSignal;
|
|
1823
2030
|
}): Promise<Reply<200, ConversationPage>>;
|
|
@@ -1906,7 +2113,7 @@ export declare function client(t: Transport): {
|
|
|
1906
2113
|
/**
|
|
1907
2114
|
* Say something in a conversation
|
|
1908
2115
|
*
|
|
1909
|
-
* The project's server says something in a conversation, as the
|
|
2116
|
+
* The project's server says something in a conversation — as the app (sender_id null), or as one of its people (as_user_id, with via): the message is theirs, as if they sent it (what they may send there, their read of it, the others' unread counts and pushes, from them), and says what wrote it (Message.via). In a thread too (thread_id). Sent again with the same client_message_id, it is the same message (200).
|
|
1910
2117
|
*/
|
|
1911
2118
|
adminSendMessage(input: {
|
|
1912
2119
|
path: {
|
|
@@ -2037,12 +2244,13 @@ export declare function client(t: Transport): {
|
|
|
2037
2244
|
/**
|
|
2038
2245
|
* The reader's conversations
|
|
2039
2246
|
*
|
|
2040
|
-
* The signed-in person's conversations, the latest first, with their own place in each, what they have not read and the last message each shows. A direct conversation someone else opened shows once something is said in it; one they cleared, once something new is.
|
|
2247
|
+
* The signed-in person's conversations (of the spaces it names, when it names any), the latest first, with their own place in each, what they have not read and the last message each shows. A direct conversation someone else opened shows once something is said in it; one they cleared, once something new is.
|
|
2041
2248
|
*/
|
|
2042
2249
|
listConversations(input?: {
|
|
2043
2250
|
query?: {
|
|
2044
2251
|
limit?: number; /** The cursor a page handed out (next_cursor). */
|
|
2045
|
-
cursor?: string;
|
|
2252
|
+
cursor?: string; /** Only the conversations of these spaces: one space a parameter, repeated for more (space=org:a&space=org:b), at most 20. */
|
|
2253
|
+
space?: string[];
|
|
2046
2254
|
}; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
2047
2255
|
signal?: AbortSignal;
|
|
2048
2256
|
}): Promise<Reply<200, ConversationPage>>;
|
|
@@ -2123,6 +2331,17 @@ export declare function client(t: Transport): {
|
|
|
2123
2331
|
}; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
2124
2332
|
signal?: AbortSignal;
|
|
2125
2333
|
}): Promise<Reply<204, undefined>>;
|
|
2334
|
+
/**
|
|
2335
|
+
* Join an open group
|
|
2336
|
+
*
|
|
2337
|
+
* The reader joins an open group by themselves — when the project's hook lets them (action join, the group and its space named; with no hook, anyone) and it has room. They read it as one added to it does (its history when it shows it to newcomers), and its people are told (member_joined). Joining one they are in answers it as it is. One an admin removed does not join again by themselves.
|
|
2338
|
+
*/
|
|
2339
|
+
joinGroup(input: {
|
|
2340
|
+
path: {
|
|
2341
|
+
conversation_id: string;
|
|
2342
|
+
}; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
2343
|
+
signal?: AbortSignal;
|
|
2344
|
+
}): Promise<Reply<200, Conversation>>;
|
|
2126
2345
|
/**
|
|
2127
2346
|
* A conversation's people
|
|
2128
2347
|
*
|
|
@@ -2371,6 +2590,19 @@ export declare function client(t: Transport): {
|
|
|
2371
2590
|
body: UploadRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
2372
2591
|
signal?: AbortSignal;
|
|
2373
2592
|
}): Promise<Reply<201, Upload>>;
|
|
2593
|
+
/**
|
|
2594
|
+
* A space's open groups
|
|
2595
|
+
*
|
|
2596
|
+
* A space's open groups, the oldest first, each with whether the reader is in it — when the project's hook lets the reader find them (action list_open, the space named; with no hook, anyone). Join one with POST /messaging/conversations/{conversation_id}/join.
|
|
2597
|
+
*/
|
|
2598
|
+
listOpenGroups(input: {
|
|
2599
|
+
query: {
|
|
2600
|
+
space: string; /** How many (1 to 100; 50 when absent). */
|
|
2601
|
+
limit?: number; /** The cursor a page handed out (next_cursor). */
|
|
2602
|
+
cursor?: string;
|
|
2603
|
+
}; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
2604
|
+
signal?: AbortSignal;
|
|
2605
|
+
}): Promise<Reply<200, OpenGroupPage>>;
|
|
2374
2606
|
/**
|
|
2375
2607
|
* The reader's own profile
|
|
2376
2608
|
*
|
|
@@ -2466,7 +2698,8 @@ export declare function client(t: Transport): {
|
|
|
2466
2698
|
by?: "words" | "meaning"; /** Search one conversation of the reader's only. */
|
|
2467
2699
|
conversation_id?: string; /** How many (1 to 50; 20 when absent). */
|
|
2468
2700
|
limit?: number; /** The cursor a page handed out (next_cursor). */
|
|
2469
|
-
cursor?: string;
|
|
2701
|
+
cursor?: string; /** Search only the conversations of these spaces: one space a parameter, repeated for more, at most 20. */
|
|
2702
|
+
space?: string[];
|
|
2470
2703
|
}; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
2471
2704
|
signal?: AbortSignal;
|
|
2472
2705
|
}): Promise<Reply<200, SearchPage>>;
|
|
@@ -2481,7 +2714,7 @@ export declare function client(t: Transport): {
|
|
|
2481
2714
|
/**
|
|
2482
2715
|
* Change how the project runs its conversations
|
|
2483
2716
|
*
|
|
2484
|
-
* What it names changes: how long messages are kept (null: for good), whether pushes say what a message says, what becomes of a deleted user's messages,
|
|
2717
|
+
* What it names changes: how long messages are kept (null: for good), whether pushes say what a message says, what becomes of a deleted user's messages, the hook asked whom one may reach (null: none), and whether messaging.message.created says what a message says (event_text). The hook is POSTed `{event: "messaging.can_message", action: "direct" | "group_add" | "open_group" | "list_open" | "join", from_user_id, to_user_ids, conversation_id, space}` — whom of to_user_ids from_user_id may reach (a direct conversation, a group they are added to), or, to_user_ids being [from_user_id], whether they may have an open group in a space (open_group: making one, or opening theirs), find a space's open groups (list_open) or join one (join); space is the conversation's (absent: none), signed as Standard Webhooks sign (webhook-id, webhook-timestamp, webhook-signature), and answers 200 `{allowed_user_ids: [...]}`. A hook set for the first time is given its signing secret, here, once.
|
|
2485
2718
|
*/
|
|
2486
2719
|
putSettings(input: {
|
|
2487
2720
|
body: SettingsRequest; /** Stops the call: the request in flight, a wait before a retry, a proof-of-work being solved. */
|
|
@@ -35,6 +35,14 @@ export interface PalbaseServer {
|
|
|
35
35
|
fields: Fields;
|
|
36
36
|
flags: ReturnType<typeof modules.flags.client>;
|
|
37
37
|
machines: ReturnType<typeof modules.machines.client>;
|
|
38
|
+
/**
|
|
39
|
+
* The messaging module's calls as its contract states them. The project's server makes its admin ones with the
|
|
40
|
+
* secret key: a conversation for people (adminCreateConversation, in a space), a message as the app or as one of
|
|
41
|
+
* the conversation's people (adminSendMessage with as_user_id and via: "pal" — the others see it was not their own
|
|
42
|
+
* hand), its conversations by person, pair or space (adminListConversations). A person's own calls are their app's
|
|
43
|
+
* (palbase/web, the iOS and Android SDKs), with their session.
|
|
44
|
+
*/
|
|
45
|
+
messaging: ReturnType<typeof modules.messaging.client>;
|
|
38
46
|
notify: ReturnType<typeof modules.notify.client>;
|
|
39
47
|
purchases: ReturnType<typeof modules.purchases.client>;
|
|
40
48
|
realtime: ReturnType<typeof modules.realtime.client>;
|
|
@@ -11,6 +11,7 @@ export type Profile = api.Profile;
|
|
|
11
11
|
export type ScheduledMessage = api.ScheduledMessage;
|
|
12
12
|
export type ThreadState = api.ThreadState;
|
|
13
13
|
export type SearchMatch = api.SearchMatch;
|
|
14
|
+
export type OpenGroup = api.OpenGroup;
|
|
14
15
|
export type { DeletedGroup, Entry, Hit, OutboxItem } from '../../internal/src/messaging/index.js';
|
|
15
16
|
export interface MessagingOptions {
|
|
16
17
|
/**
|
|
@@ -117,6 +118,8 @@ export interface SearchOptions {
|
|
|
117
118
|
by?: 'words' | 'meaning';
|
|
118
119
|
/** Search one conversation of the person's only. */
|
|
119
120
|
conversationId?: string;
|
|
121
|
+
/** Search the conversations of one space only (org:<id>): a place of the app's they belong to. */
|
|
122
|
+
space?: string;
|
|
120
123
|
/** How many messages a page holds (1 to 50; 20 when absent). */
|
|
121
124
|
limit?: number;
|
|
122
125
|
/** The page after the one that handed out this cursor (nextCursor): a search by words alone. */
|
|
@@ -256,8 +259,13 @@ export declare class Messaging {
|
|
|
256
259
|
private seat;
|
|
257
260
|
private typed;
|
|
258
261
|
private tell;
|
|
259
|
-
/**
|
|
260
|
-
|
|
262
|
+
/**
|
|
263
|
+
* The person's conversations, the latest first, kept up to date — those of some spaces only (spaces: the places of
|
|
264
|
+
* the app's they belong to, as org:<id>), when it names any.
|
|
265
|
+
*/
|
|
266
|
+
conversations(opts?: {
|
|
267
|
+
spaces?: string[];
|
|
268
|
+
}): ConversationList;
|
|
261
269
|
/**
|
|
262
270
|
* The groups the person was in that someone deleted, kept up to date while the person may still report them
|
|
263
271
|
* (reportableUntil, 14 days after), the latest to stop first: report() names one by its id, no message needed. A
|
|
@@ -273,15 +281,27 @@ export declare class Messaging {
|
|
|
273
281
|
conversation(conversationId: string, opts?: {
|
|
274
282
|
at?: string;
|
|
275
283
|
}): ConversationView;
|
|
276
|
-
/**
|
|
277
|
-
|
|
278
|
-
|
|
284
|
+
/**
|
|
285
|
+
* The direct conversation with someone — the one there is, or a new one — in a space (org:<id>): the two have one in
|
|
286
|
+
* each space, and one with none. The project's hook is asked, the space named.
|
|
287
|
+
*/
|
|
288
|
+
direct(userId: string, opts?: {
|
|
289
|
+
space?: string;
|
|
290
|
+
}): Promise<ConversationView>;
|
|
291
|
+
/**
|
|
292
|
+
* A new group, the person its owner — in a space (org:<id>), and open (found in the space's open groups and joined
|
|
293
|
+
* by whom the project's hook lets: openGroups, join) or closed (the default: joined when someone adds you). An open
|
|
294
|
+
* group names its space ('space_required'), and the project's hook is asked whether the person may make one there
|
|
295
|
+
* ('open_group'; refused: 'not_allowed').
|
|
296
|
+
*/
|
|
279
297
|
group(input: {
|
|
280
298
|
title: string;
|
|
281
299
|
memberIds?: string[];
|
|
282
300
|
description?: string;
|
|
283
301
|
photo?: string;
|
|
284
302
|
settings?: api.GroupSettings;
|
|
303
|
+
space?: string;
|
|
304
|
+
visibility?: 'open' | 'closed';
|
|
285
305
|
}): Promise<{
|
|
286
306
|
conversation: ConversationView;
|
|
287
307
|
notAdded: api.NotAdded[];
|
|
@@ -301,8 +321,26 @@ export declare class Messaging {
|
|
|
301
321
|
* means instead, the nearest first, each with its score: one page, no conversations by name. Opened as any find is.
|
|
302
322
|
*/
|
|
303
323
|
search(query: string, opts?: SearchOptions): Promise<SearchResults>;
|
|
304
|
-
/** The person's conversations whose name says every word asked: a group's title, the other person's name. */
|
|
324
|
+
/** The person's conversations (of a space, when one is named) whose name says every word asked: a group's title, the other person's name. */
|
|
305
325
|
private named;
|
|
326
|
+
/**
|
|
327
|
+
* A space's open groups (org:<id>), the oldest first, a page at a time — each with whether the person is in it
|
|
328
|
+
* (joined) — when the project's hook lets them find them; refused otherwise (a PalbaseError, code 'not_allowed').
|
|
329
|
+
*/
|
|
330
|
+
openGroups(space: string, opts?: {
|
|
331
|
+
limit?: number;
|
|
332
|
+
cursor?: string;
|
|
333
|
+
}): Promise<{
|
|
334
|
+
items: OpenGroup[];
|
|
335
|
+
nextCursor: string | null;
|
|
336
|
+
}>;
|
|
337
|
+
/**
|
|
338
|
+
* Joins an open group by themselves — when the project's hook lets them and it has room — and answers it, the person
|
|
339
|
+
* in it. Joining one they are in answers it as it is. Refused (a PalbaseError) when the hook does not let them
|
|
340
|
+
* ('not_allowed'), an admin removed them ('removed'), it is read-only ('read_only') or full ('group_full'); a closed
|
|
341
|
+
* group is not found.
|
|
342
|
+
*/
|
|
343
|
+
join(conversationId: string): Promise<ConversationView>;
|
|
306
344
|
/** The person's messages scheduled for later, kept up to date. */
|
|
307
345
|
scheduled(): ScheduledList;
|
|
308
346
|
/** The threads the person follows, the latest answered first. */
|
|
@@ -373,6 +411,9 @@ declare abstract class View<S> implements Observed<S> {
|
|
|
373
411
|
protected abstract read(): S;
|
|
374
412
|
}
|
|
375
413
|
export declare class ConversationList extends View<ConversationListState> {
|
|
414
|
+
/** The spaces it is narrowed to (none: every conversation). */
|
|
415
|
+
readonly spaces: readonly string[];
|
|
416
|
+
constructor(m: Messaging, spaces?: readonly string[]);
|
|
376
417
|
protected touches(t: Touched): boolean;
|
|
377
418
|
protected read(): ConversationListState;
|
|
378
419
|
}
|
package/dist/chunks/M5MRZQPV.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! palbase 0.26.0 — Palbase SDK License (see LICENSE) */
|
|
2
|
-
import{b as R}from"./Q4E3WXGS.js";import{a as m,c as J,d as Y,e as G,f as X,h as Z,i as Q,j as A,k as ee,l as te,o as P}from"./4W2CWOGO.js";import{a as ne}from"./EAHHUIQP.js";import{a as U,b as C,c as L,d as $,e as N,g as I,i as F,j as D,k as W,l as B,m as H,n as q}from"./QUPZ6GF5.js";import{a as z,b as V}from"./GHQTIJT7.js";import{b as T,d as v}from"./FBCZT7JT.js";var f=class extends Error{status=400;code;data;constructor(e,t,r={}){super(t),this.name="TransitRefusal",this.code=e,this.data=r}},Ee=6e4,_e=1e3;function x(n){return/^t[1-9][0-9]{0,5}$/.test(n)?Number(n.slice(1)):0}var k=class{keys=new Map;retired=new Set;order=[];project;timer;fetchedAt=0;heldFrom=0;fetching;opts;now;sleep;constructor(e){this.opts=e,this.now=e.now??Date.now,this.sleep=e.sleep??(t=>new Promise(r=>setTimeout(r,t)))}get loaded(){return this.project!==void 0}get projectId(){if(this.project===void 0)throw new Error("the project's transit keys are not loaded: await palbase.transit.load() at startup");return this.project}current(){return this.order[0]}async load(e){await this.refresh(e),this.timer===void 0&&(this.timer=setInterval(()=>{this.refresh().catch(()=>{})},Ee),this.timer.unref?.())}close(){clearInterval(this.timer),this.timer=void 0}refresh(e){return this.fetching??=(async()=>{let t=this.now();try{let r=await this.opts.fetch(e),s=new Map;for(let i of r.keys){let o=Y(i.key);s.set(i.id,{privateKey:o,publicKey:this.keys.get(i.id)?.publicKey??await G(o)})}this.keys=s,this.order=r.keys.map(i=>i.id),this.retired=new Set(r.retired),this.project=r.project,this.fetchedAt=this.now(),this.heldFrom=t}finally{this.fetching=void 0}})(),this.fetching}newest(){return Math.max(0,...this.order.map(x),...[...this.retired].map(x))}async key(e){let t=this.now();for(;x(e)>this.newest()&&this.heldFrom<t;){let i=this.fetchedAt+_e-this.now();if(i>0){await this.sleep(i);continue}await this.refresh()}let r=this.keys.get(e),s=this.current();if(this.retired.has(e))throw new f("encryption_key_retired",`the request is sealed to ${e}, retired: fetch the project's keys again`,{current:s});if(r===void 0)throw new f("encryption_key_unknown",`the request is sealed to ${e}, which the project has not made`,{current:s});return r}async request(e){if(e.header===void 0||e.header===null||e.header==="")throw new f("encryption_required",`this route carries encrypted fields: the request names its key in ${m}`,{field:m,current:this.current()});let t;try{t=Z(e.header).kid}catch{throw new f("encryption_unopenable",`${m} is not one`,{field:m})}let r=await this.key(t),s;try{s=X(this.projectId,e.method,e.path,e.params??[])}catch{throw new f("encryption_unopenable","the request's path holds a value no key is sealed for",{field:m})}try{return new S(t,await Q(e.header,r.privateKey,r.publicKey,s))}catch(i){throw i instanceof J?new f("encryption_unopenable","the request's key does not open: sealed for another project, route or path, or changed",{field:m}):i}}},S=class{kid;key;constructor(e,t){this.kid=e,this.key=t}async open(e,t,r){return P(e,t,r,async(s,i)=>{if(!ee(i))throw new f("encryption_required",`${s} is an encrypted field: it came plain`,{field:s});try{return await te(this.key,s,i)}catch{throw new f("encryption_unopenable",`${s} does not open: changed, moved from another field, or another request's`,{field:s})}})}async seal(e,t){return P(e,"/response",t,(r,s)=>A(this.key,r,s))}sealField(e,t){return A(this.key,e,t)}};var Te=/^pb_[a-z0-9]+_s/;function O(n){if(ne())throw new TypeError("palbase/server runs on a server: its secret key never goes into a browser or a mobile app \u2014 apps use palbase/web (or the native SDKs) with the publishable key");if(typeof n.secretKey!="string"||!Te.test(n.secretKey))throw new TypeError("secretKey is the project secret key (pb_<ref>_s\u2026); a publishable key belongs in palbase/web");let e=V(v({baseUrl:n.url,credentials:{secretKey:n.secretKey},fetch:n.fetch,solveProofOfWork:n.solveProofOfWork??!1}),n.retry??z),t=B.client(e);return{ai:U.client(e),analytics:C.client(e),auth:L.client(e),cache:$.client(e),fields:new R({fetch:async r=>(await t.getFieldKeys({signal:r})).data}),flags:N.client(e),machines:I.client(e),notify:F.client(e),purchases:D.client(e),realtime:W.client(e),secrets:t,storage:H.client(e),stores:q.client(e),transit:new k({fetch:async r=>(await t.getTransitKeys({signal:r})).data}),transport:e,url:new URL(n.url).origin}}var h=class extends Error{code;constructor(e,t){super(t),this.name="WebhookSignatureError",this.code=e}},Pe=300,Re=/^[0-9]{1,12}$/,xe=/^[0-9a-f]{64}$/,re=8,Oe=/^whsec_[0-9A-Za-z]{32,}$/,je=1024*1024;async function se(n){if(typeof n.secret!="string"||!Oe.test(n.secret))throw new TypeError("secret is the webhook endpoint secret (whsec_\u2026), not an API key");await ie(n);let e;try{e=JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(ae(n.body)))}catch{throw new h("invalid_body","the signed body is not JSON")}if(!$e(e))throw new h("invalid_body","the signed body is not a Palbase event (id, type, project_id, created_at, data)");return e}async function ie(n){if(typeof n.secret!="string"||n.secret==="")throw new TypeError("secret is the key the request was signed with");let e=ae(n.body),{t,v1:r}=oe(n),s=await crypto.subtle.importKey("raw",new TextEncoder().encode(n.secret),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),i=new Uint8Array(await crypto.subtle.sign("HMAC",s,Le(new TextEncoder().encode(`${t}.`),e))),o=!1;for(let d of r)Ce(i,Ue(d))&&(o=!0);if(!o)throw new h("signature_mismatch","no v1 in Palbase-Signature is this body signed with this secret")}function oe(n){let e=n.toleranceSeconds??Pe;if(!Number.isFinite(e)||e<0)throw new TypeError(`toleranceSeconds is a number of seconds, 0 or more (got ${String(n.toleranceSeconds)})`);let t=(n.now??Date.now)();if(!Number.isFinite(t))throw new TypeError(`now() returns epoch milliseconds (got ${String(t)})`);let r=n.signature;if(typeof r!="string"||r.trim()==="")throw new h("missing_signature","the request carries no Palbase-Signature header");let s,i=[];for(let o of r.split(",")){let d=o.indexOf("=");if(d<=0)throw new h("malformed_signature","Palbase-Signature is t=<seconds>,v1=<hex>");let c=o.slice(0,d).trim(),a=o.slice(d+1).trim();if(c==="t"){if(s!==void 0||!Re.test(a))throw new h("malformed_signature","Palbase-Signature carries one t, in unix seconds");s=a}else if(c==="v1"){if(!xe.test(a))throw new h("malformed_signature","a v1 is 64 lowercase hex characters");if(i.length===re)throw new h("malformed_signature",`Palbase-Signature carries at most ${re} v1`);i.push(a)}}if(s===void 0||i.length===0)throw new h("malformed_signature","Palbase-Signature is t=<seconds>,v1=<hex>");if(Math.abs(t/1e3-Number(s))>e)throw new h("stale_timestamp",`the signature's time is more than ${e} s from now: an old delivery sent again is not taken`);return{t:s,v1:i}}async function Me(n,e,t={}){let r=await Ke(n,t.maxBytes??je);return se({toleranceSeconds:t.toleranceSeconds,now:t.now,secret:e,signature:n.headers.get("palbase-signature"),body:r})}async function Ke(n,e){let t=()=>new h("body_too_large",`the body is larger than ${e} bytes`),r=Number(n.headers.get("content-length")??"NaN");if(Number.isFinite(r)&&r>e)throw t();if(!n.body)return new Uint8Array(0);let s=n.body.getReader(),i=[],o=0;for(;;){let{done:a,value:l}=await s.read();if(a)break;if(o+=l.byteLength,o>e)throw await s.cancel().catch(()=>{}),t();i.push(l)}let d=new Uint8Array(o),c=0;for(let a of i)d.set(a,c),c+=a.byteLength;return d}function ae(n){if(typeof n=="string")return new TextEncoder().encode(n);if(n instanceof Uint8Array)return n;if(n instanceof ArrayBuffer)return new Uint8Array(n);throw new TypeError("body is the raw request body (string or bytes): a parsed object is not what was signed \u2014 read the body before any JSON middleware")}function Ue(n){let e=new Uint8Array(n.length/2);for(let t=0;t<e.length;t++)e[t]=parseInt(n.slice(t*2,t*2+2),16);return e}function Ce(n,e){if(n.byteLength!==e.byteLength)return!1;let t=0;for(let r=0;r<n.byteLength;r++)t|=n[r]^e[r];return t===0}function Le(n,e){let t=new Uint8Array(n.byteLength+e.byteLength);return t.set(n,0),t.set(e,n.byteLength),t}function $e(n){if(typeof n!="object"||n===null)return!1;let e=n;return typeof e.id=="string"&&typeof e.type=="string"&&typeof e.project_id=="string"&&typeof e.created_at=="string"&&"data"in e}var ce=60,Ne=60,Ie=8*1024,Fe=1e5;function j(n){let e=n instanceof Uint8Array?n:new Uint8Array(n),t="";for(let r of e)t+=String.fromCharCode(r);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function le(n){let e=n.replace(/[\s=]+/g,"");if(!/^[A-Za-z0-9+/_-]*$/.test(e)||e.length%4===1)return;let t=atob(e.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(e.length/4)*4,"=")),r=new Uint8Array(t.length);for(let s=0;s<t.length;s++)r[s]=t.charCodeAt(s);return r}function de(n){let e=le(n);if(e)try{let t=JSON.parse(new TextDecoder().decode(e));return typeof t=="object"&&t!==null&&!Array.isArray(t)?t:void 0}catch{return}}var E=class{byKey=new Map;held=0;sweptAt=Number.NEGATIVE_INFINITY;max;constructor(e=Fe){this.max=e}spend(e,t){if(t>=e.until)throw new u("proof","the DPoP proof is not taken: it was checked too long ago");let r=this.byKey.get(e.jkt);if(r){this.forgetOld(e.jkt,r,t);let s=r.get(e.jti);if(s!==void 0&&s>t)throw new u("proof","the DPoP proof is not taken: it was used before");s!==void 0&&r.delete(e.jti)&&this.held--}this.held>=this.max&&this.makeRoom(t),r=this.byKey.get(e.jkt),r||(r=new Map,this.byKey.set(e.jkt,r)),r.set(e.jti,e.until),this.held++}forgetOld(e,t,r){for(let[s,i]of t){if(i>r)break;t.delete(s),this.held--}t.size===0&&this.byKey.delete(e)}makeRoom(e){if(e-this.sweptAt>=1e3){this.sweptAt=e;for(let[r,s]of this.byKey){for(let[i,o]of s)o>e||(s.delete(i),this.held--);s.size===0&&this.byKey.delete(r)}this.held=0;for(let r of this.byKey.values())this.held+=r.size}if(this.held<this.max)return;let t=[...this.byKey].sort((r,s)=>s[1].size-r[1].size);for(let[r,s]of t){if(this.held<=this.max*.9)break;this.byKey.delete(r),this.held-=s.size}}};async function De(n,e){let t=`{"crv":"P-256","kty":"EC","x":"${n}","y":"${e}"}`;return j(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t)))}function ue(n){try{let e=new URL(n);return e.username!==""||e.password!==""?void 0:`${e.protocol}//${e.host}${e.pathname}`}catch{return}}async function he(n,e,t,r){let s=Se=>{throw new u("proof",`the DPoP proof is not taken: ${Se}`)},i=t.proof;if(!i)return s("there is none (a DPoP-bound token comes with a DPoP header)");if(i.length>Ie)return s("it is too long");let o=i.split(".");if(o.length!==3)return s("it is not a JWS of three parts");let d=de(o[0]),c=de(o[1]);if(!d||!c)return s("its header or claims are not base64url JSON");if(d.typ!=="dpop+jwt")return s("its typ is not dpop+jwt");if(d.alg!=="ES256")return s(`it is signed with ${String(d.alg)}; only ES256 is taken`);let a=d.jwk;if(!a||typeof a!="object"||a.kty!=="EC"||a.crv!=="P-256"||typeof a.x!="string"||typeof a.y!="string")return s("its header carries no P-256 public key");if("d"in a)return s("its header carries a private key");if(await De(a.x,a.y)!==e)return s("it is signed by a key the token does not name");let l;try{l=await crypto.subtle.importKey("jwk",{kty:"EC",crv:"P-256",x:a.x,y:a.y,ext:!0},{name:"ECDSA",namedCurve:"P-256"},!1,["verify"])}catch{return s("its key is not a P-256 point")}let y=le(o[2]);if(!y||!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},l,y,new TextEncoder().encode(`${o[0]}.${o[1]}`)).catch(()=>!1))return s("its signature does not verify");if(typeof c.htm!="string"||c.htm.toUpperCase()!==t.method.toUpperCase())return s(`it is for ${String(c.htm)}, not ${t.method}`);let p=typeof c.htu=="string"?ue(c.htu):void 0,g=ue(t.url);if(!p||!g||p!==g)return s(`it is for ${String(c.htu)}, not ${g??t.url}`);let be=r/1e3;if(typeof c.iat!="number"||Math.abs(c.iat-be)>ce)return s("it was not made within a minute of now");let ke=j(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(n)));if(c.ath!==ke)return s("it is not for this token (ath)");if(typeof c.jti!="string"||c.jti===""||c.jti.length>256)return s("it has no jti (or one longer than 256)");let ve=j(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(c.jti)));return{jkt:e,jti:ve,until:(c.iat+ce+Ne)*1e3+1}}var u=class extends Error{reason;constructor(e,t){super(t),this.name="TokenError",this.reason=e}},w=class extends Error{constructor(e,t){super(e,t),this.name="AuthUnavailable"}},We=new Set(["invalid_api_key","missing_api_key","secret_key_in_browser"]);function Be(n){return async e=>{let t=v({baseUrl:n.url,credentials:{secretKey:n.secretKey,accessToken:()=>e},fetch:n.fetch});try{return await t.send({op:"SessionStanding",method:"GET",path:"/auth/session/standing",auth:[["ApiKeyAuth","userJWT"]],answers:{204:"empty"}}),!0}catch(r){if(r instanceof T&&r.status===401&&!We.has(r.code))return!1;throw new w("a session's standing could not be told",{cause:r})}}}var M={ES256:{kty:"EC",import:{name:"ECDSA",namedCurve:"P-256"},verify:{name:"ECDSA",hash:"SHA-256"}},PS256:{kty:"RSA",import:{name:"RSA-PSS",hash:"SHA-256"},verify:{name:"RSA-PSS",saltLength:32}}},fe=60,He=16*1024,qe=10*6e4,ze=5e4,pe=n=>typeof n=="string"&&Object.hasOwn(M,n),K=class{issuer;projectId;fetchImpl;now;maxKeyAgeMs;refetchIntervalMs;fetchTimeoutMs;standing;standingTtlMs;standingStaleMs;standings=new Map;asking=new Map;keys=new Map;keysUntil=0;lastFetch=Number.NEGATIVE_INFINITY;lastFailure=void 0;inflight=null;seenProofs=new E;constructor(e){let t=new URL(e.issuer);if(t.origin!==e.issuer.replace(/\/$/,""))throw new TypeError(`issuer is the project's origin (https://<ref>.<domain>), not ${e.issuer}`);if(typeof e.projectId!="string"||e.projectId==="")throw new TypeError("projectId is the project id the tokens carry");if(this.issuer=t.origin,this.projectId=e.projectId,this.fetchImpl=e.fetch??globalThis.fetch,this.now=e.now??Date.now,this.maxKeyAgeMs=e.maxKeyAgeMs??60*6e4,this.refetchIntervalMs=e.refetchIntervalMs??3e4,this.fetchTimeoutMs=e.fetchTimeoutMs??5e3,typeof e.standing!="function")throw new TypeError("standing is how the verifier asks whether a token's session stands");this.standing=e.standing,this.standingTtlMs=e.standingTtlMs??1e3,this.standingStaleMs=e.standingStaleMs??15e3}async verify(e,t){if(typeof e!="string"||e.length===0||e.length>He)throw new u("malformed","the token is not a JWT");let r=e.split(".");if(r.length!==3)throw new u("malformed","the token is not a JWS of three parts");let s=ye(r[0]),i=ye(r[1]);if(!s||!i)throw new u("malformed","the token header or claims are not base64url JSON");let o=s.alg;if(!pe(o))throw new u("algorithm",`the token is signed with ${String(o)}; only ES256 and PS256 are taken`);let d=s.kid;if(typeof d!="string"||d==="")throw new u("malformed","the token header names no kid");let c=await this.key(d);if(!c)throw new u("unknown_key",`no key ${d} in the project's key set`);if(c.alg!==o)throw new u("algorithm",`key ${d} is ${c.alg}, the token says ${o}`);let a=me(r[2]);if(!a)throw new u("malformed","the signature is not base64url");let l=new TextEncoder().encode(`${r[0]}.${r[1]}`);if(!await crypto.subtle.verify(M[c.alg].verify,c.key,a,l).catch(()=>!1))throw new u("signature","the signature does not verify");let b=this.check(i),p=i.cnf,g;if(p!==void 0){if(!t)throw new u("bound","the token is bound to a key (DPoP): it comes with the DPoP scheme and a proof, not as a Bearer");if(typeof p!="object"||p===null||typeof p.jkt!="string"||p.jkt==="")throw new u("bound","the token is bound to a key it does not name (cnf.jkt)");g=await he(e,p.jkt,t,this.now())}else if(t)throw new u("not_bound","the DPoP scheme came with a token bound to no key");if(!await this.stands(e,b.sessionId))throw new u("session_ended","the token's session has ended (signed out, revoked, or its user banned)");return g&&this.seenProofs.spend(g,this.now()),b}async verifyRequest(e){let t=e.headers instanceof Headers?e.headers:Je(e.headers),r=t.get("authorization")??"";if(r==="")return null;let s=/^(bearer|dpop)\s+(\S+)$/i.exec(r);if(!s)throw new u("malformed","the Authorization header is not a Bearer or DPoP token");let i=s[1].toLowerCase()==="dpop",o=new URL(e.url,`http://${t.get("host")??"localhost"}`);return this.verify(s[2],i?{proof:t.get("dpop"),method:e.method,url:ge(t,o)}:void 0)}async stands(e,t){let r=this.now(),s=this.standings.get(t);if(s&&r<s.until)return s.live;let i=this.asking.get(t);i||(i=this.standing(e,t).finally(()=>this.asking.delete(t)),this.asking.set(t,i));let o;try{o=await i}catch(c){let a=this.standings.get(t),l=this.now();if(a&&l<a.at+this.standingStaleMs)return a.until=Math.min(l+this.standingTtlMs,a.at+this.standingStaleMs),a.live;throw new w("a session's standing cannot be read now",{cause:c})}let d=this.now();return this.standings.delete(t),this.standings.set(t,{live:o,at:d,until:d+this.standingTtlMs}),this.standings.size>ze&&this.standings.delete(this.standings.keys().next().value),o}check(e){if(e.iss!==this.issuer)throw new u("issuer",`the token was issued by ${String(e.iss)}, not this project`);if(!(Array.isArray(e.aud)?e.aud:[e.aud]).includes(this.issuer))throw new u("audience","the token is not meant for this project");if(e.project_id!==this.projectId)throw new u("project","the token names another project");let r=this.now()/1e3;if(typeof e.exp!="number"||e.exp+fe<=r)throw new u("expired","the token has expired");if(e.nbf!==void 0&&(typeof e.nbf!="number"||e.nbf-fe>r))throw new u("not_yet_valid","the token is not valid yet");if(typeof e.sub!="string"||e.sub===""||typeof e.auth_time!="number")throw new u("not_a_user","the token is not a user's");if(typeof e.session_id!="string"||e.session_id==="")throw new u("not_a_session","the token is no session's");let s=e.custom_claims;if(s!==void 0&&(typeof s!="object"||s===null||s.type!==void 0))throw new u("not_a_session","the token is a custom one (an exchange or an approval), not a session's");return{id:e.sub,email:typeof e.email=="string"?e.email:null,emailVerified:e.email_verified===!0,role:typeof e.role=="string"?e.role:null,sessionId:typeof e.session_id=="string"?e.session_id:null,claims:Object.freeze({...e})}}async key(e){let t=this.now();if(t>=this.keysUntil){let s=this.keys.size>0&&t<this.keysUntil+qe;if(this.lastFailure!==void 0&&t-this.lastFetch<this.refetchIntervalMs){if(!s)throw new w("the project's key set cannot be read now",{cause:this.lastFailure})}else try{await this.refresh()}catch(i){if(!s)throw i}}let r=this.keys.get(e);return!r&&t-this.lastFetch>=this.refetchIntervalMs&&(await this.refresh(),r=this.keys.get(e)),r}refresh(){if(this.inflight)return this.inflight;let e=this.load().finally(()=>{this.inflight=null});return this.inflight=e,e}async load(){this.lastFetch=this.now();let e,t;try{if(t=await this.fetchImpl(`${this.issuer}/.well-known/jwks.json`,{redirect:"error",headers:{accept:"application/json"},signal:AbortSignal.timeout(this.fetchTimeoutMs)}),!t.ok)throw new Error(`the project's key set answered ${t.status}`);e=await t.json()}catch(i){throw this.lastFailure=i,new w("the project's key set cannot be read now",{cause:i})}this.lastFailure=void 0;let r=new Map;for(let i of Array.isArray(e.keys)?e.keys:[]){let o=i.alg;if(typeof i.kid!="string"||!pe(o))continue;let d=M[o];if(i.kty!==d.kty||i.use!==void 0&&i.use!=="sig")continue;let{d:c,...a}=i;try{r.set(i.kid,{alg:o,key:await crypto.subtle.importKey("jwk",a,d.import,!1,["verify"])})}catch{}}this.keys=r;let s=Ye(t.headers.get("cache-control"))??this.maxKeyAgeMs;this.keysUntil=this.now()+Math.min(Math.max(s,this.refetchIntervalMs),this.maxKeyAgeMs)}};function ge(n,e){let t=n.get("x-forwarded-proto")?.split(",")[0]?.trim().toLowerCase(),r=t==="https"||t==="http"?t:e.protocol.slice(0,-1),s=n.get("host")??e.host;return Ve.test(s)?`${r}://${s}${e.pathname}`:""}var Ve=/^(?:[a-z0-9-]+(?:\.[a-z0-9-]+)*|\[[0-9a-f:.]+\])(?::[0-9]{1,5})?$/i;function Je(n){let e=new Headers;for(let[t,r]of Object.entries(n))if(r!==void 0)for(let s of Array.isArray(r)?r:[r])e.append(t,s);return e}function Ye(n){let e=/(?:^|,)\s*max-age=(\d+)/i.exec(n??"");return e?Number(e[1])*1e3:void 0}function me(n){if(!/^[A-Za-z0-9_-]*$/.test(n)||n.length%4===1)return null;let e=atob(n.replace(/-/g,"+").replace(/_/g,"/").padEnd(Math.ceil(n.length/4)*4,"=")),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t}function ye(n){let e=me(n);if(!e)return null;try{let t=JSON.parse(new TextDecoder("utf-8",{fatal:!0}).decode(e));return typeof t=="object"&&t!==null&&!Array.isArray(t)?t:null}catch{return null}}function Ge(n,e,t=Date.now()){let r=Object.hasOwn(n.entitlements,e)?n.entitlements[e]:void 0;return r?.active?r.expires_at===null?!0:Date.parse(r.expires_at)>(typeof t=="number"?t:t.getTime()):!1}var _=class extends Error{receipt;constructor(e){super(`the reservation ${JSON.stringify(e.idempotency_key)} is ${e.status} already: its job is not run again (a new one is a new Idempotency-Key)`),this.name="ReservationSettled",this.receipt=e}};async function Xe(n,e,t,r){let{idempotencyKey:s,amount:i,ttlSeconds:o,metadata:d}=t;if(typeof s!="string"||s==="")throw new TypeError("idempotencyKey names the reservation for good: a retry with it is the same hold, never a second");let c={amount:i,...t.credits!==void 0?{credits:t.credits}:{limit:t.limit},...o!==void 0?{ttl_seconds:o}:{},...d!==void 0?{metadata:d}:{}},a=(await n.purchases.holdSpend({path:{customer_id:e},headers:{"Idempotency-Key":s},body:c})).data;if(a.status!=="held")throw new _(a);let l={customer_id:a.customer,spend_id:a.id},y;try{y=await r(a)}catch(b){throw await n.purchases.releaseSpend({path:l}).catch(()=>{}),b}return await n.purchases.commitSpend({path:l}),y}async function*Ze(n){let e,t=new Set;do{let r=(await n(e)).data;yield r;let s=r.next_cursor??void 0;if(s!==void 0&&t.has(s))throw new Error(`the listing answered a cursor it had answered before (${s})`);s!==void 0&&t.add(s),e=s}while(e)}var Qe=/^[A-Za-z_][A-Za-z0-9_]{0,127}$/,et=/^(PALBASE_|NODE_|BUN_|NPM_|LD_|DYLD_|GIT_|SSH_)|^(PATH|HOME|SHELL|USER|TMPDIR|TMP|TEMP|PWD|IFS|ENV|BASH_ENV|SSL_CERT_FILE|SSL_CERT_DIR|CURL_CA_BUNDLE|REQUESTS_CA_BUNDLE|NO_PROXY|ALL_PROXY|HTTP_PROXY|HTTPS_PROXY|PG\w*)$/i;function we(n){return!Qe.test(n)||et.test(n)||/_PROXY$/i.test(n)}var tt=/^(PORT|PALBASE_(URL|PROJECT_ID|MACHINE|REPLICAS|SECRET_KEY|WEBHOOK_SECRET|PLATFORM_SECRET|CONTRACT_OUT|SECRETS|DB_[A-Z0-9_]+))$/;function nt(n){return tt.test(n)}async function rt(n={}){let e=n.env??process.env,t=e.PALBASE_SECRETS;if(t===void 0||t==="")return;if(t!=="development"&&t!=="production")throw new TypeError(`PALBASE_SECRETS is development or production, not ${t}`);let r=n.url??e.PALBASE_URL??"",s=n.secretKey??e.PALBASE_SECRET_KEY??"";if(r===""||s==="")throw new TypeError("PALBASE_SECRETS reads the project's Secrets with PALBASE_URL and PALBASE_SECRET_KEY: give both (palbase env:pull writes them)");let i=O({url:new URL(r).origin,secretKey:s,fetch:n.fetch}),{data:o}=await i.secrets.getEnvironmentValues({path:{environment:t}}),d=[],c=[],a=[];for(let[l,y]of Object.entries(o.values)){if(we(l)){a.push(l);continue}if(e[l]!==void 0&&e[l]!==""){c.push(l);continue}e[l]=y,d.push(l)}return{set:t,loaded:d.sort(),kept:c.sort(),refused:a.sort()}}export{f as a,k as b,S as c,O as d,h as e,se as f,ie as g,oe as h,Me as i,u as j,w as k,Be as l,K as m,ge as n,Ge as o,_ as p,Xe as q,Ze as r,we as s,nt as t,rt as u};
|