@playaos/api-client 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/index.d.ts +209 -54
- package/dist/index.js +101 -30
- package/dist/index.js.map +1 -1
- package/package.json +21 -13
package/README.md
CHANGED
|
@@ -73,7 +73,9 @@ This is useful when a deployment splits API-key-authenticated routes and embed r
|
|
|
73
73
|
|
|
74
74
|
Generate an API key in the PlayaOS platform console under your org's **Developer → API Keys** page. Keys use the format `pk_live_*` and are scoped to specific resources.
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
For the full `/api/v1` auth model, member-scoping rules, route conventions, and examples for packing and bike rentals, see [`docs/guides/public-api.md`](../../docs/guides/public-api.md). The live OpenAPI document remains the complete endpoint inventory.
|
|
77
|
+
|
|
78
|
+
Common required scopes:
|
|
77
79
|
|
|
78
80
|
| Endpoint | Scope |
|
|
79
81
|
|----------|-------|
|
package/dist/index.d.ts
CHANGED
|
@@ -55,6 +55,8 @@ interface Member {
|
|
|
55
55
|
emergencyContactRelationship?: string | null;
|
|
56
56
|
emergencyContactPhone?: string | null;
|
|
57
57
|
yearJoined?: number | null;
|
|
58
|
+
adminRoles?: string[] | null;
|
|
59
|
+
isDeveloper?: boolean | null;
|
|
58
60
|
}
|
|
59
61
|
interface Application {
|
|
60
62
|
id: string;
|
|
@@ -417,6 +419,11 @@ interface AvailabilityWindow {
|
|
|
417
419
|
interface SetAvailabilityInput {
|
|
418
420
|
windows: AvailabilityWindow[];
|
|
419
421
|
}
|
|
422
|
+
/** Response from GET /scheduling/availability/{id}. */
|
|
423
|
+
interface GetAvailabilityResponse {
|
|
424
|
+
windows: AvailabilityWindow[];
|
|
425
|
+
}
|
|
426
|
+
/** Response from PUT /scheduling/availability/{id}. */
|
|
420
427
|
interface SetAvailabilityResponse {
|
|
421
428
|
windows: {
|
|
422
429
|
count: number;
|
|
@@ -511,6 +518,76 @@ interface PackingPersonalItem {
|
|
|
511
518
|
containerId: string | null;
|
|
512
519
|
notes: string | null;
|
|
513
520
|
}
|
|
521
|
+
/**
|
|
522
|
+
* Camp packing-layer row (PLA-1204). Published identity is `slug`
|
|
523
|
+
* (`overrides_slug`, or `camp:<uuid>` when standalone) — not the row uuid alone.
|
|
524
|
+
*/
|
|
525
|
+
interface PackingCampItem {
|
|
526
|
+
slug: string;
|
|
527
|
+
id: string;
|
|
528
|
+
categoryId: string;
|
|
529
|
+
categoryName: string;
|
|
530
|
+
name: string;
|
|
531
|
+
notes: string | null;
|
|
532
|
+
sortOrder: number;
|
|
533
|
+
overridesSlug: string | null;
|
|
534
|
+
}
|
|
535
|
+
interface UpsertPackingCampItemInput {
|
|
536
|
+
slug: string;
|
|
537
|
+
name: string;
|
|
538
|
+
category: string;
|
|
539
|
+
notes?: string | null;
|
|
540
|
+
sortOrder?: number;
|
|
541
|
+
}
|
|
542
|
+
/** Active-year allocation summary. Year is always the org's active camp year. */
|
|
543
|
+
interface SapAllocation {
|
|
544
|
+
year: number;
|
|
545
|
+
totalAllocated: number;
|
|
546
|
+
notes: string | null;
|
|
547
|
+
totalAssigned: number;
|
|
548
|
+
}
|
|
549
|
+
interface UpdateSapAllocationInput {
|
|
550
|
+
totalAllocated: number;
|
|
551
|
+
notes?: string | null;
|
|
552
|
+
}
|
|
553
|
+
interface SapDayAllocation {
|
|
554
|
+
id: string;
|
|
555
|
+
year: number;
|
|
556
|
+
accessDate: string;
|
|
557
|
+
slotsAvailable: number;
|
|
558
|
+
notes: string | null;
|
|
559
|
+
}
|
|
560
|
+
interface UpsertSapDayAllocationInput {
|
|
561
|
+
accessDate: string;
|
|
562
|
+
slotsAvailable: number;
|
|
563
|
+
notes?: string | null;
|
|
564
|
+
}
|
|
565
|
+
interface SapAssignment {
|
|
566
|
+
id: string;
|
|
567
|
+
userId: string;
|
|
568
|
+
year: number;
|
|
569
|
+
sapNumber: string | null;
|
|
570
|
+
vehicleDescription: string | null;
|
|
571
|
+
licensePlate: string | null;
|
|
572
|
+
arrivalDate: string | null;
|
|
573
|
+
notes: string | null;
|
|
574
|
+
}
|
|
575
|
+
interface CreateSapAssignmentInput {
|
|
576
|
+
userId: string;
|
|
577
|
+
sapNumber?: string | null;
|
|
578
|
+
vehicleDescription?: string | null;
|
|
579
|
+
licensePlate?: string | null;
|
|
580
|
+
arrivalDate?: string | null;
|
|
581
|
+
notes?: string | null;
|
|
582
|
+
}
|
|
583
|
+
interface UpdateSapAssignmentInput {
|
|
584
|
+
assignmentId: string;
|
|
585
|
+
sapNumber?: string | null;
|
|
586
|
+
vehicleDescription?: string | null;
|
|
587
|
+
licensePlate?: string | null;
|
|
588
|
+
arrivalDate?: string | null;
|
|
589
|
+
notes?: string | null;
|
|
590
|
+
}
|
|
514
591
|
/** How the rental reaches the member. The server defaults to `camp_delivery`. */
|
|
515
592
|
type BikeRentalDeliveryMode = "individual_pickup" | "camp_delivery";
|
|
516
593
|
type BikeRentalFramePreference = "standard" | "step-through";
|
|
@@ -564,6 +641,8 @@ interface BikeRentalRequestResult {
|
|
|
564
641
|
/** DustJunkie's id for the pending request. */
|
|
565
642
|
requestId: string | null;
|
|
566
643
|
status: string | null;
|
|
644
|
+
/** True when this matched an earlier request within the short dedupe window (ADR-091). */
|
|
645
|
+
duplicate?: boolean;
|
|
567
646
|
}
|
|
568
647
|
interface BikeRentalReservation {
|
|
569
648
|
id: string;
|
|
@@ -632,6 +711,14 @@ declare class PlayaOSClient {
|
|
|
632
711
|
* server that holds one org key and serves many signed-in members.
|
|
633
712
|
*/
|
|
634
713
|
withMember(memberToken: string): PlayaOSClient;
|
|
714
|
+
/**
|
|
715
|
+
* Admin dual-path (PLA-1203): when the client has a memberToken, call `/api/v1`
|
|
716
|
+
* (org key + X-PlayaOS-Member-Token). Otherwise keep the legacy embed-admin
|
|
717
|
+
* Bearer-JWT path so published consumers without withMember() still work.
|
|
718
|
+
*/
|
|
719
|
+
private adminV1OrEmbed;
|
|
720
|
+
/** Resolve admin credential: memberToken clients skip accessToken; embed path requires it. */
|
|
721
|
+
private adminAccess;
|
|
635
722
|
readonly members: {
|
|
636
723
|
list: (params?: {
|
|
637
724
|
role?: MemberRole;
|
|
@@ -646,7 +733,7 @@ declare class PlayaOSClient {
|
|
|
646
733
|
get: (id: string, opts?: {
|
|
647
734
|
signal?: AbortSignal;
|
|
648
735
|
}) => Promise<Member>;
|
|
649
|
-
/** Member-self profile update (PLA-700).
|
|
736
|
+
/** Member-self profile update (PLA-700 / PLA-1203). Prefers v1 when memberToken is set. */
|
|
650
737
|
selfUpdate: (payload: {
|
|
651
738
|
bio?: string | null;
|
|
652
739
|
playaName?: string | null;
|
|
@@ -664,7 +751,7 @@ declare class PlayaOSClient {
|
|
|
664
751
|
}) => Promise<{
|
|
665
752
|
profileId: string;
|
|
666
753
|
}>;
|
|
667
|
-
/** Member-self shift signup + cancel (PLA-705).
|
|
754
|
+
/** Member-self shift signup + cancel (PLA-705 / PLA-1203). Prefers v1 when memberToken is set. */
|
|
668
755
|
shifts: {
|
|
669
756
|
signup: (payload: {
|
|
670
757
|
shiftId: string;
|
|
@@ -830,6 +917,15 @@ declare class PlayaOSClient {
|
|
|
830
917
|
get: (id: string, opts?: {
|
|
831
918
|
signal?: AbortSignal;
|
|
832
919
|
}) => Promise<Bike>;
|
|
920
|
+
/**
|
|
921
|
+
* Cancel an in-house fleet rental owned by the acting member (PLA-1232).
|
|
922
|
+
* Requires a member token. 404 when missing, not owned, or not cancellable.
|
|
923
|
+
*/
|
|
924
|
+
cancelRental: (rentalId: string, opts?: {
|
|
925
|
+
signal?: AbortSignal;
|
|
926
|
+
}) => Promise<{
|
|
927
|
+
cancelled: true;
|
|
928
|
+
}>;
|
|
833
929
|
};
|
|
834
930
|
/**
|
|
835
931
|
* DustJunkie bike rentals (PLA-1180), passed through to the vendor. A camp
|
|
@@ -954,6 +1050,65 @@ declare class PlayaOSClient {
|
|
|
954
1050
|
ok: true;
|
|
955
1051
|
}>;
|
|
956
1052
|
};
|
|
1053
|
+
/**
|
|
1054
|
+
* Camp packing layer (PLA-1204). Admin/super_admin only — non-admins get 403.
|
|
1055
|
+
* Identity is the published slug (`overrides_slug` or `camp:<uuid>`).
|
|
1056
|
+
*/
|
|
1057
|
+
campItems: {
|
|
1058
|
+
list: (opts?: {
|
|
1059
|
+
signal?: AbortSignal;
|
|
1060
|
+
}) => Promise<{
|
|
1061
|
+
items: PackingCampItem[];
|
|
1062
|
+
}>;
|
|
1063
|
+
upsert: (payload: UpsertPackingCampItemInput, opts?: {
|
|
1064
|
+
signal?: AbortSignal;
|
|
1065
|
+
}) => Promise<PackingCampItem>;
|
|
1066
|
+
};
|
|
1067
|
+
};
|
|
1068
|
+
/**
|
|
1069
|
+
* SAP — Special Access Pass, for early/overnight vehicle arrival (PLA-1202).
|
|
1070
|
+
* Admin/super_admin only; there is no member-facing SAP surface. Year is
|
|
1071
|
+
* always the org's active camp year — the server derives it, callers never
|
|
1072
|
+
* pass one.
|
|
1073
|
+
*/
|
|
1074
|
+
readonly sap: {
|
|
1075
|
+
allocation: {
|
|
1076
|
+
get: (opts?: {
|
|
1077
|
+
signal?: AbortSignal;
|
|
1078
|
+
}) => Promise<SapAllocation>;
|
|
1079
|
+
update: (payload: UpdateSapAllocationInput, opts?: {
|
|
1080
|
+
signal?: AbortSignal;
|
|
1081
|
+
}) => Promise<SapAllocation>;
|
|
1082
|
+
};
|
|
1083
|
+
dayAllocations: {
|
|
1084
|
+
list: (opts?: {
|
|
1085
|
+
signal?: AbortSignal;
|
|
1086
|
+
}) => Promise<{
|
|
1087
|
+
items: SapDayAllocation[];
|
|
1088
|
+
}>;
|
|
1089
|
+
/** Upserts by (active year, accessDate); 409 on a cross-org date collision. */
|
|
1090
|
+
upsert: (payload: UpsertSapDayAllocationInput, opts?: {
|
|
1091
|
+
signal?: AbortSignal;
|
|
1092
|
+
}) => Promise<SapDayAllocation>;
|
|
1093
|
+
};
|
|
1094
|
+
assignments: {
|
|
1095
|
+
list: (opts?: {
|
|
1096
|
+
signal?: AbortSignal;
|
|
1097
|
+
}) => Promise<{
|
|
1098
|
+
items: SapAssignment[];
|
|
1099
|
+
}>;
|
|
1100
|
+
create: (payload: CreateSapAssignmentInput, opts?: {
|
|
1101
|
+
signal?: AbortSignal;
|
|
1102
|
+
}) => Promise<SapAssignment>;
|
|
1103
|
+
update: (payload: UpdateSapAssignmentInput, opts?: {
|
|
1104
|
+
signal?: AbortSignal;
|
|
1105
|
+
}) => Promise<SapAssignment>;
|
|
1106
|
+
remove: (assignmentId: string, opts?: {
|
|
1107
|
+
signal?: AbortSignal;
|
|
1108
|
+
}) => Promise<{
|
|
1109
|
+
ok: true;
|
|
1110
|
+
}>;
|
|
1111
|
+
};
|
|
957
1112
|
};
|
|
958
1113
|
readonly admin: {
|
|
959
1114
|
applications: {
|
|
@@ -969,46 +1124,46 @@ declare class PlayaOSClient {
|
|
|
969
1124
|
* the org API key (`audit:read` scope) instead of an admin JWT. Remove
|
|
970
1125
|
* in the next major version.
|
|
971
1126
|
*/
|
|
972
|
-
history: (id: string, opts
|
|
973
|
-
accessToken
|
|
1127
|
+
history: (id: string, opts?: {
|
|
1128
|
+
accessToken?: string;
|
|
974
1129
|
signal?: AbortSignal;
|
|
975
1130
|
}) => Promise<ApplicationHistoryResponse>;
|
|
976
|
-
transition: (id: string, payload: ApplicationTransitionPayload, opts
|
|
977
|
-
accessToken
|
|
1131
|
+
transition: (id: string, payload: ApplicationTransitionPayload, opts?: {
|
|
1132
|
+
accessToken?: string;
|
|
978
1133
|
signal?: AbortSignal;
|
|
979
1134
|
}) => Promise<ApplicationTransitionResponse>;
|
|
980
|
-
getAnnotations: (id: string, opts
|
|
981
|
-
accessToken
|
|
1135
|
+
getAnnotations: (id: string, opts?: {
|
|
1136
|
+
accessToken?: string;
|
|
982
1137
|
signal?: AbortSignal;
|
|
983
1138
|
}) => Promise<ApplicationAnnotations>;
|
|
984
1139
|
addNote: (id: string, payload: {
|
|
985
1140
|
body: string;
|
|
986
|
-
}, opts
|
|
987
|
-
accessToken
|
|
1141
|
+
}, opts?: {
|
|
1142
|
+
accessToken?: string;
|
|
988
1143
|
signal?: AbortSignal;
|
|
989
1144
|
}) => Promise<ApplicationNote>;
|
|
990
1145
|
setTags: (id: string, payload: {
|
|
991
1146
|
tags: string[];
|
|
992
|
-
}, opts
|
|
993
|
-
accessToken
|
|
1147
|
+
}, opts?: {
|
|
1148
|
+
accessToken?: string;
|
|
994
1149
|
signal?: AbortSignal;
|
|
995
1150
|
}) => Promise<string[]>;
|
|
996
1151
|
setScore: (id: string, payload: {
|
|
997
1152
|
value: number;
|
|
998
|
-
}, opts
|
|
999
|
-
accessToken
|
|
1153
|
+
}, opts?: {
|
|
1154
|
+
accessToken?: string;
|
|
1000
1155
|
signal?: AbortSignal;
|
|
1001
1156
|
}) => Promise<ApplicationScore>;
|
|
1002
1157
|
};
|
|
1003
1158
|
givebutter: {
|
|
1004
1159
|
campaigns: {
|
|
1005
|
-
list: (opts
|
|
1006
|
-
accessToken
|
|
1160
|
+
list: (opts?: {
|
|
1161
|
+
accessToken?: string;
|
|
1007
1162
|
signal?: AbortSignal;
|
|
1008
1163
|
}) => Promise<unknown[]>;
|
|
1009
1164
|
discountCodes: {
|
|
1010
|
-
list: (campaignId: number, opts
|
|
1011
|
-
accessToken
|
|
1165
|
+
list: (campaignId: number, opts?: {
|
|
1166
|
+
accessToken?: string;
|
|
1012
1167
|
signal?: AbortSignal;
|
|
1013
1168
|
}) => Promise<unknown[]>;
|
|
1014
1169
|
create: (campaignId: number, payload: {
|
|
@@ -1016,8 +1171,8 @@ declare class PlayaOSClient {
|
|
|
1016
1171
|
value: number;
|
|
1017
1172
|
type: "percent" | "fixed";
|
|
1018
1173
|
expirationDate?: string;
|
|
1019
|
-
}, opts
|
|
1020
|
-
accessToken
|
|
1174
|
+
}, opts?: {
|
|
1175
|
+
accessToken?: string;
|
|
1021
1176
|
signal?: AbortSignal;
|
|
1022
1177
|
}) => Promise<unknown>;
|
|
1023
1178
|
};
|
|
@@ -1026,89 +1181,89 @@ declare class PlayaOSClient {
|
|
|
1026
1181
|
name: string;
|
|
1027
1182
|
price: number;
|
|
1028
1183
|
totalQuantity?: number;
|
|
1029
|
-
}, opts
|
|
1030
|
-
accessToken
|
|
1184
|
+
}, opts?: {
|
|
1185
|
+
accessToken?: string;
|
|
1031
1186
|
signal?: AbortSignal;
|
|
1032
1187
|
}) => Promise<unknown>;
|
|
1033
1188
|
};
|
|
1034
1189
|
};
|
|
1035
1190
|
};
|
|
1036
1191
|
members: {
|
|
1037
|
-
create: (payload: MemberCreatePayload, opts
|
|
1038
|
-
accessToken
|
|
1192
|
+
create: (payload: MemberCreatePayload, opts?: {
|
|
1193
|
+
accessToken?: string;
|
|
1039
1194
|
signal?: AbortSignal;
|
|
1040
1195
|
}) => Promise<MemberCreateResponse>;
|
|
1041
|
-
update: (id: string, patch: MemberUpdatePayload, opts
|
|
1042
|
-
accessToken
|
|
1196
|
+
update: (id: string, patch: MemberUpdatePayload, opts?: {
|
|
1197
|
+
accessToken?: string;
|
|
1043
1198
|
signal?: AbortSignal;
|
|
1044
1199
|
}) => Promise<MemberUpdateResponse>;
|
|
1045
|
-
deactivate: (id: string, opts
|
|
1046
|
-
accessToken
|
|
1200
|
+
deactivate: (id: string, opts?: {
|
|
1201
|
+
accessToken?: string;
|
|
1047
1202
|
signal?: AbortSignal;
|
|
1048
1203
|
}) => Promise<MemberDeactivateResponse>;
|
|
1049
1204
|
};
|
|
1050
1205
|
announcements: {
|
|
1051
1206
|
/** Send an email blast to camp members (PLA-706). Requires admin Bearer token. */
|
|
1052
|
-
send: (payload: AnnouncementSendPayload, opts
|
|
1053
|
-
accessToken
|
|
1207
|
+
send: (payload: AnnouncementSendPayload, opts?: {
|
|
1208
|
+
accessToken?: string;
|
|
1054
1209
|
signal?: AbortSignal;
|
|
1055
1210
|
}) => Promise<AnnouncementSendResponse>;
|
|
1056
1211
|
};
|
|
1057
1212
|
dues: {
|
|
1058
1213
|
/** Create a manual dues/payment record (PLA-708). Requires admin Bearer token. */
|
|
1059
|
-
create: (payload: DuesCreatePayload, opts
|
|
1060
|
-
accessToken
|
|
1214
|
+
create: (payload: DuesCreatePayload, opts?: {
|
|
1215
|
+
accessToken?: string;
|
|
1061
1216
|
signal?: AbortSignal;
|
|
1062
1217
|
}) => Promise<DuesCreateResponse>;
|
|
1063
1218
|
/** Update a dues/payment record (PLA-708). Requires admin Bearer token. */
|
|
1064
|
-
update: (id: string, payload: DuesUpdatePayload, opts
|
|
1065
|
-
accessToken
|
|
1219
|
+
update: (id: string, payload: DuesUpdatePayload, opts?: {
|
|
1220
|
+
accessToken?: string;
|
|
1066
1221
|
signal?: AbortSignal;
|
|
1067
1222
|
}) => Promise<DuesUpdateResponse>;
|
|
1068
1223
|
};
|
|
1069
1224
|
org: {
|
|
1070
1225
|
/** Update camp configuration settings (PLA-709). Requires admin Bearer token. */
|
|
1071
|
-
update: (payload: OrgUpdatePayload, opts
|
|
1072
|
-
accessToken
|
|
1226
|
+
update: (payload: OrgUpdatePayload, opts?: {
|
|
1227
|
+
accessToken?: string;
|
|
1073
1228
|
signal?: AbortSignal;
|
|
1074
1229
|
}) => Promise<OrgUpdateResponse>;
|
|
1075
1230
|
};
|
|
1076
1231
|
scheduling: {
|
|
1077
1232
|
availability: {
|
|
1078
1233
|
/** Get interview availability for an interviewer (PLA-713). Requires admin Bearer token. */
|
|
1079
|
-
get: (interviewerId: string, opts
|
|
1080
|
-
accessToken
|
|
1234
|
+
get: (interviewerId: string, opts?: {
|
|
1235
|
+
accessToken?: string;
|
|
1081
1236
|
signal?: AbortSignal;
|
|
1082
|
-
}) => Promise<
|
|
1237
|
+
}) => Promise<GetAvailabilityResponse>;
|
|
1083
1238
|
/** Set interview availability for an interviewer (PLA-713). Requires admin Bearer token. */
|
|
1084
|
-
set: (interviewerId: string, payload: SetAvailabilityInput, opts
|
|
1085
|
-
accessToken
|
|
1239
|
+
set: (interviewerId: string, payload: SetAvailabilityInput, opts?: {
|
|
1240
|
+
accessToken?: string;
|
|
1086
1241
|
signal?: AbortSignal;
|
|
1087
1242
|
}) => Promise<SetAvailabilityResponse>;
|
|
1088
1243
|
};
|
|
1089
1244
|
calendar: {
|
|
1090
1245
|
/** Get Google Calendar connection status for an interviewer (PLA-726). Requires admin Bearer. */
|
|
1091
|
-
status: (interviewerId: string, opts
|
|
1092
|
-
accessToken
|
|
1246
|
+
status: (interviewerId: string, opts?: {
|
|
1247
|
+
accessToken?: string;
|
|
1093
1248
|
signal?: AbortSignal;
|
|
1094
1249
|
}) => Promise<CalendarStatus>;
|
|
1095
1250
|
/** List available Google Calendars (PLA-726). Requires admin Bearer. */
|
|
1096
|
-
listCalendars: (interviewerId: string, opts
|
|
1097
|
-
accessToken
|
|
1251
|
+
listCalendars: (interviewerId: string, opts?: {
|
|
1252
|
+
accessToken?: string;
|
|
1098
1253
|
signal?: AbortSignal;
|
|
1099
1254
|
}) => Promise<{
|
|
1100
1255
|
calendars: GoogleCalendar[];
|
|
1101
1256
|
}>;
|
|
1102
1257
|
/** Select which Google Calendar to use (PLA-726). Requires admin Bearer. */
|
|
1103
|
-
select: (interviewerId: string, payload: SelectCalendarInput, opts
|
|
1104
|
-
accessToken
|
|
1258
|
+
select: (interviewerId: string, payload: SelectCalendarInput, opts?: {
|
|
1259
|
+
accessToken?: string;
|
|
1105
1260
|
signal?: AbortSignal;
|
|
1106
1261
|
}) => Promise<{
|
|
1107
1262
|
calendarId: string;
|
|
1108
1263
|
}>;
|
|
1109
1264
|
/** Disconnect Google Calendar from interviewer (PLA-726). Requires admin Bearer. */
|
|
1110
|
-
disconnect: (interviewerId: string, opts
|
|
1111
|
-
accessToken
|
|
1265
|
+
disconnect: (interviewerId: string, opts?: {
|
|
1266
|
+
accessToken?: string;
|
|
1112
1267
|
signal?: AbortSignal;
|
|
1113
1268
|
}) => Promise<{
|
|
1114
1269
|
disconnected: boolean;
|
|
@@ -1116,13 +1271,13 @@ declare class PlayaOSClient {
|
|
|
1116
1271
|
};
|
|
1117
1272
|
bookingTokens: {
|
|
1118
1273
|
/** Create a booking token for an application's interview link (PLA-714). Requires admin Bearer token. */
|
|
1119
|
-
create: (payload: CreateBookingTokenInput, opts
|
|
1120
|
-
accessToken
|
|
1274
|
+
create: (payload: CreateBookingTokenInput, opts?: {
|
|
1275
|
+
accessToken?: string;
|
|
1121
1276
|
signal?: AbortSignal;
|
|
1122
1277
|
}) => Promise<BookingToken>;
|
|
1123
1278
|
/** Get an existing booking token for an application (PLA-714). Requires admin Bearer token. */
|
|
1124
|
-
get: (applicationId: string, opts
|
|
1125
|
-
accessToken
|
|
1279
|
+
get: (applicationId: string, opts?: {
|
|
1280
|
+
accessToken?: string;
|
|
1126
1281
|
signal?: AbortSignal;
|
|
1127
1282
|
}) => Promise<BookingToken>;
|
|
1128
1283
|
};
|
|
@@ -1261,5 +1416,5 @@ interface PublicMarketplaceClient {
|
|
|
1261
1416
|
}
|
|
1262
1417
|
declare function createPublicMarketplaceClient(opts: PublicMarketplaceClientOptions): PublicMarketplaceClient;
|
|
1263
1418
|
//#endregion
|
|
1264
|
-
export { ApiClientError, type Application, type ApplicationAnnotations, type ApplicationCreatePayload, type ApplicationCreateResponse, type ApplicationNote, type ApplicationScore, type ApplicationStatus, type ApplicationTransitionPayload, type ApplicationTransitionResponse, type BikeRentalCatalogItem, type BikeRentalCatalogResponse, type BikeRentalDeliveryMode, type BikeRentalFramePreference, type BikeRentalInterestedMember, type BikeRentalInterestedNotReservedResponse, type BikeRentalRequestInput, type BikeRentalRequestResult, type BikeRentalReservation, type BikeRentalReservationListResponse, type BikeRentalWaiver, type Commitment, type CommitmentDataType, type CommitmentValue, type CommitmentsListResponse, type DuesStatus, type ExchangeParams, type ExchangeResult, type ImageUploadTarget, type ListingImage, MAX_IMAGE_POSITION, type MarketplaceFlagReason, type Member, type MemberCreatePayload, type MemberCreateResponse, type MemberDeactivateResponse, type MemberRole, type MemberUpdatePayload, type MemberUpdateResponse, type NewListingInput, type OrgConfig, type PackingItem, type PackingItemStatus, type PackingLayer, type PackingListResponse, type PackingPersonalItem, type PaymentPageResponse, PlayaOSClient, type PublicMarketplaceClient, type PublicMarketplaceClientOptions, type Shift, type ShiftSignup, type ShiftType, type Waiver, type WaiverContent, type WaiverSection, type WaiverSignPayload, type WaiverSignResponse, type WaiverStatus, createClient, createPublicMarketplaceClient, exchangeCode };
|
|
1419
|
+
export { ApiClientError, type Application, type ApplicationAnnotations, type ApplicationCreatePayload, type ApplicationCreateResponse, type ApplicationNote, type ApplicationScore, type ApplicationStatus, type ApplicationTransitionPayload, type ApplicationTransitionResponse, type BikeRentalCatalogItem, type BikeRentalCatalogResponse, type BikeRentalDeliveryMode, type BikeRentalFramePreference, type BikeRentalInterestedMember, type BikeRentalInterestedNotReservedResponse, type BikeRentalRequestInput, type BikeRentalRequestResult, type BikeRentalReservation, type BikeRentalReservationListResponse, type BikeRentalWaiver, type Commitment, type CommitmentDataType, type CommitmentValue, type CommitmentsListResponse, type CreateSapAssignmentInput, type DuesStatus, type ExchangeParams, type ExchangeResult, type ImageUploadTarget, type ListingImage, MAX_IMAGE_POSITION, type MarketplaceFlagReason, type Member, type MemberCreatePayload, type MemberCreateResponse, type MemberDeactivateResponse, type MemberRole, type MemberUpdatePayload, type MemberUpdateResponse, type NewListingInput, type OrgConfig, type PackingCampItem, type PackingItem, type PackingItemStatus, type PackingLayer, type PackingListResponse, type PackingPersonalItem, type PaymentPageResponse, PlayaOSClient, type PublicMarketplaceClient, type PublicMarketplaceClientOptions, type SapAllocation, type SapAssignment, type SapDayAllocation, type Shift, type ShiftSignup, type ShiftType, type UpdateSapAllocationInput, type UpdateSapAssignmentInput, type UpsertPackingCampItemInput, type UpsertSapDayAllocationInput, type Waiver, type WaiverContent, type WaiverSection, type WaiverSignPayload, type WaiverSignResponse, type WaiverStatus, createClient, createPublicMarketplaceClient, exchangeCode };
|
|
1265
1420
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -199,6 +199,32 @@ var PlayaOSClient = class PlayaOSClient {
|
|
|
199
199
|
memberToken
|
|
200
200
|
});
|
|
201
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Admin dual-path (PLA-1203): when the client has a memberToken, call `/api/v1`
|
|
204
|
+
* (org key + X-PlayaOS-Member-Token). Otherwise keep the legacy embed-admin
|
|
205
|
+
* Bearer-JWT path so published consumers without withMember() still work.
|
|
206
|
+
*/
|
|
207
|
+
adminV1OrEmbed(method, v1Path, embedPath, accessToken, body, signal) {
|
|
208
|
+
if (this.memberToken) {
|
|
209
|
+
const url = buildUrl(this.baseUrl, v1Path);
|
|
210
|
+
if (method === "GET") return request(url, this.auth, signal);
|
|
211
|
+
if (method === "POST") return post(url, this.auth, body ?? {}, signal);
|
|
212
|
+
return sendV1(method, url, this.auth, body, signal);
|
|
213
|
+
}
|
|
214
|
+
return adminEmbed(method, buildEmbedUrl(this.embedBaseUrl, embedPath), accessToken, body, signal);
|
|
215
|
+
}
|
|
216
|
+
/** Resolve admin credential: memberToken clients skip accessToken; embed path requires it. */
|
|
217
|
+
adminAccess(opts) {
|
|
218
|
+
if (this.memberToken) return {
|
|
219
|
+
accessToken: opts?.accessToken ?? "",
|
|
220
|
+
signal: opts?.signal
|
|
221
|
+
};
|
|
222
|
+
if (!opts?.accessToken) throw new Error("accessToken is required; call withMember(token) or pass { accessToken }");
|
|
223
|
+
return {
|
|
224
|
+
accessToken: opts.accessToken,
|
|
225
|
+
signal: opts.signal
|
|
226
|
+
};
|
|
227
|
+
}
|
|
202
228
|
members = {
|
|
203
229
|
list: (params, opts) => request(buildUrl(this.baseUrl, "/members", params), this.auth, opts?.signal),
|
|
204
230
|
/**
|
|
@@ -206,12 +232,21 @@ var PlayaOSClient = class PlayaOSClient {
|
|
|
206
232
|
* `"me"` for the acting member — non-admins may fetch only themselves.
|
|
207
233
|
*/
|
|
208
234
|
get: (id, opts) => request(buildUrl(this.baseUrl, `/members/${encodeURIComponent(id)}`), this.auth, opts?.signal),
|
|
209
|
-
/** Member-self profile update (PLA-700).
|
|
210
|
-
selfUpdate: (payload, opts) => putEmbed(buildEmbedUrl(this.embedBaseUrl, "/members/self"), this.apiKey, payload, opts),
|
|
211
|
-
/** Member-self shift signup + cancel (PLA-705).
|
|
235
|
+
/** Member-self profile update (PLA-700 / PLA-1203). Prefers v1 when memberToken is set. */
|
|
236
|
+
selfUpdate: (payload, opts) => this.memberToken ? sendV1("PUT", buildUrl(this.baseUrl, "/members/me"), this.auth, payload, opts.signal) : putEmbed(buildEmbedUrl(this.embedBaseUrl, "/members/self"), this.apiKey, payload, opts),
|
|
237
|
+
/** Member-self shift signup + cancel (PLA-705 / PLA-1203). Prefers v1 when memberToken is set. */
|
|
212
238
|
shifts: {
|
|
213
|
-
signup: (payload, opts) =>
|
|
214
|
-
|
|
239
|
+
signup: async (payload, opts) => {
|
|
240
|
+
if (this.memberToken) {
|
|
241
|
+
const assigned = await post(buildUrl(this.baseUrl, `/shifts/${encodeURIComponent(payload.shiftId)}/assign`), this.auth, { role: payload.role }, opts.signal);
|
|
242
|
+
return {
|
|
243
|
+
signupId: assigned.id,
|
|
244
|
+
waitlisted: assigned.waitlisted ?? false
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
return postEmbed(buildEmbedUrl(this.embedBaseUrl, "/shifts/signup"), this.apiKey, payload, opts);
|
|
248
|
+
},
|
|
249
|
+
cancel: (signupId, opts) => this.memberToken ? sendV1("DELETE", buildUrl(this.baseUrl, `/shifts/signups/${encodeURIComponent(signupId)}`), this.auth, void 0, opts.signal) : deleteEmbed(buildEmbedUrl(this.embedBaseUrl, `/shifts/signups/${encodeURIComponent(signupId)}`), this.apiKey, opts)
|
|
215
250
|
}
|
|
216
251
|
};
|
|
217
252
|
applications = {
|
|
@@ -259,7 +294,12 @@ var PlayaOSClient = class PlayaOSClient {
|
|
|
259
294
|
};
|
|
260
295
|
bikes = {
|
|
261
296
|
list: (params, opts) => request(buildUrl(this.baseUrl, "/bikes", params), this.auth, opts?.signal),
|
|
262
|
-
get: (id, opts) => request(buildUrl(this.baseUrl, `/bikes/${encodeURIComponent(id)}`), this.auth, opts?.signal)
|
|
297
|
+
get: (id, opts) => request(buildUrl(this.baseUrl, `/bikes/${encodeURIComponent(id)}`), this.auth, opts?.signal),
|
|
298
|
+
/**
|
|
299
|
+
* Cancel an in-house fleet rental owned by the acting member (PLA-1232).
|
|
300
|
+
* Requires a member token. 404 when missing, not owned, or not cancellable.
|
|
301
|
+
*/
|
|
302
|
+
cancelRental: (rentalId, opts) => sendV1("DELETE", buildUrl(this.baseUrl, `/members/bikes/${encodeURIComponent(rentalId)}`), this.auth, void 0, opts?.signal)
|
|
263
303
|
};
|
|
264
304
|
/**
|
|
265
305
|
* DustJunkie bike rentals (PLA-1180), passed through to the vendor. A camp
|
|
@@ -316,6 +356,37 @@ var PlayaOSClient = class PlayaOSClient {
|
|
|
316
356
|
toggle: (id, opts) => sendV1("PATCH", buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`), this.auth, void 0, opts?.signal),
|
|
317
357
|
/** 404 if the item is not the acting member's. */
|
|
318
358
|
remove: (id, opts) => sendV1("DELETE", buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`), this.auth, void 0, opts?.signal)
|
|
359
|
+
},
|
|
360
|
+
/**
|
|
361
|
+
* Camp packing layer (PLA-1204). Admin/super_admin only — non-admins get 403.
|
|
362
|
+
* Identity is the published slug (`overrides_slug` or `camp:<uuid>`).
|
|
363
|
+
*/
|
|
364
|
+
campItems: {
|
|
365
|
+
list: (opts) => request(buildUrl(this.baseUrl, "/packing/camp-items"), this.auth, opts?.signal),
|
|
366
|
+
upsert: (payload, opts) => sendV1("PUT", buildUrl(this.baseUrl, "/packing/camp-items"), this.auth, payload, opts?.signal)
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* SAP — Special Access Pass, for early/overnight vehicle arrival (PLA-1202).
|
|
371
|
+
* Admin/super_admin only; there is no member-facing SAP surface. Year is
|
|
372
|
+
* always the org's active camp year — the server derives it, callers never
|
|
373
|
+
* pass one.
|
|
374
|
+
*/
|
|
375
|
+
sap = {
|
|
376
|
+
allocation: {
|
|
377
|
+
get: (opts) => request(buildUrl(this.baseUrl, "/sap/allocation"), this.auth, opts?.signal),
|
|
378
|
+
update: (payload, opts) => sendV1("PUT", buildUrl(this.baseUrl, "/sap/allocation"), this.auth, payload, opts?.signal)
|
|
379
|
+
},
|
|
380
|
+
dayAllocations: {
|
|
381
|
+
list: (opts) => request(buildUrl(this.baseUrl, "/sap/day-allocations"), this.auth, opts?.signal),
|
|
382
|
+
/** Upserts by (active year, accessDate); 409 on a cross-org date collision. */
|
|
383
|
+
upsert: (payload, opts) => sendV1("PUT", buildUrl(this.baseUrl, "/sap/day-allocations"), this.auth, payload, opts?.signal)
|
|
384
|
+
},
|
|
385
|
+
assignments: {
|
|
386
|
+
list: (opts) => request(buildUrl(this.baseUrl, "/sap/assignments"), this.auth, opts?.signal),
|
|
387
|
+
create: (payload, opts) => post(buildUrl(this.baseUrl, "/sap/assignments"), this.auth, payload, opts?.signal),
|
|
388
|
+
update: (payload, opts) => sendV1("PATCH", buildUrl(this.baseUrl, "/sap/assignments"), this.auth, payload, opts?.signal),
|
|
389
|
+
remove: (assignmentId, opts) => sendV1("DELETE", buildUrl(this.baseUrl, "/sap/assignments"), this.auth, { assignmentId }, opts?.signal)
|
|
319
390
|
}
|
|
320
391
|
};
|
|
321
392
|
admin = {
|
|
@@ -354,59 +425,59 @@ var PlayaOSClient = class PlayaOSClient {
|
|
|
354
425
|
metadata: row.details ?? void 0
|
|
355
426
|
})) };
|
|
356
427
|
},
|
|
357
|
-
transition: (id, payload, opts) =>
|
|
358
|
-
getAnnotations: (id, opts) =>
|
|
359
|
-
addNote: (id, payload, opts) =>
|
|
360
|
-
setTags: (id, payload, opts) =>
|
|
361
|
-
setScore: (id, payload, opts) =>
|
|
428
|
+
transition: (id, payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("PATCH", `/applications/${encodeURIComponent(id)}`, `/admin/applications/${encodeURIComponent(id)}`, accessToken, payload, signal))(this.adminAccess(opts)),
|
|
429
|
+
getAnnotations: (id, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("GET", `/applications/${encodeURIComponent(id)}/annotations`, `/admin/applications/${encodeURIComponent(id)}/annotations`, accessToken, void 0, signal))(this.adminAccess(opts)),
|
|
430
|
+
addNote: (id, payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("POST", `/applications/${encodeURIComponent(id)}/notes`, `/admin/applications/${encodeURIComponent(id)}/notes`, accessToken, payload, signal))(this.adminAccess(opts)),
|
|
431
|
+
setTags: (id, payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("PUT", `/applications/${encodeURIComponent(id)}/tags`, `/admin/applications/${encodeURIComponent(id)}/tags`, accessToken, payload, signal))(this.adminAccess(opts)),
|
|
432
|
+
setScore: (id, payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("PUT", `/applications/${encodeURIComponent(id)}/scores`, `/admin/applications/${encodeURIComponent(id)}/scores`, accessToken, payload, signal))(this.adminAccess(opts))
|
|
362
433
|
},
|
|
363
434
|
givebutter: { campaigns: {
|
|
364
|
-
list: (opts) =>
|
|
435
|
+
list: (opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("GET", "/givebutter/campaigns", "/admin/givebutter/campaigns", accessToken, void 0, signal))(this.adminAccess(opts)),
|
|
365
436
|
discountCodes: {
|
|
366
|
-
list: (campaignId, opts) =>
|
|
367
|
-
create: (campaignId, payload, opts) =>
|
|
437
|
+
list: (campaignId, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("GET", `/givebutter/campaigns/${campaignId}/discount-codes`, `/admin/givebutter/campaigns/${campaignId}/discount-codes`, accessToken, void 0, signal))(this.adminAccess(opts)),
|
|
438
|
+
create: (campaignId, payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("POST", `/givebutter/campaigns/${campaignId}/discount-codes`, `/admin/givebutter/campaigns/${campaignId}/discount-codes`, accessToken, payload, signal))(this.adminAccess(opts))
|
|
368
439
|
},
|
|
369
|
-
tickets: { create: (campaignId, payload, opts) =>
|
|
440
|
+
tickets: { create: (campaignId, payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("POST", `/givebutter/campaigns/${campaignId}/tickets`, `/admin/givebutter/campaigns/${campaignId}/tickets`, accessToken, payload, signal))(this.adminAccess(opts)) }
|
|
370
441
|
} },
|
|
371
442
|
members: {
|
|
372
|
-
create: (payload, opts) =>
|
|
373
|
-
update: (id, patch, opts) =>
|
|
374
|
-
deactivate: (id, opts) =>
|
|
443
|
+
create: (payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("POST", "/members", "/admin/members", accessToken, payload, signal))(this.adminAccess(opts)),
|
|
444
|
+
update: (id, patch, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("PATCH", `/members/${encodeURIComponent(id)}`, `/admin/members/${encodeURIComponent(id)}`, accessToken, patch, signal))(this.adminAccess(opts)),
|
|
445
|
+
deactivate: (id, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("PATCH", `/members/${encodeURIComponent(id)}`, `/admin/members/${encodeURIComponent(id)}`, accessToken, { status: "inactive" }, signal))(this.adminAccess(opts))
|
|
375
446
|
},
|
|
376
447
|
announcements: {
|
|
377
448
|
/** Send an email blast to camp members (PLA-706). Requires admin Bearer token. */
|
|
378
|
-
send: (payload, opts) =>
|
|
449
|
+
send: (payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("POST", "/announcements/send", "/admin/announcements/send", accessToken, payload, signal))(this.adminAccess(opts)) },
|
|
379
450
|
dues: {
|
|
380
451
|
/** Create a manual dues/payment record (PLA-708). Requires admin Bearer token. */
|
|
381
|
-
create: (payload, opts) =>
|
|
452
|
+
create: (payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("POST", "/dues", "/admin/dues", accessToken, payload, signal))(this.adminAccess(opts)),
|
|
382
453
|
/** Update a dues/payment record (PLA-708). Requires admin Bearer token. */
|
|
383
|
-
update: (id, payload, opts) =>
|
|
454
|
+
update: (id, payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("PATCH", `/dues/${encodeURIComponent(id)}`, `/admin/dues/${encodeURIComponent(id)}`, accessToken, payload, signal))(this.adminAccess(opts))
|
|
384
455
|
},
|
|
385
456
|
org: {
|
|
386
457
|
/** Update camp configuration settings (PLA-709). Requires admin Bearer token. */
|
|
387
|
-
update: (payload, opts) =>
|
|
458
|
+
update: (payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("PATCH", "/org", "/admin/org", accessToken, payload, signal))(this.adminAccess(opts)) },
|
|
388
459
|
scheduling: {
|
|
389
460
|
availability: {
|
|
390
461
|
/** Get interview availability for an interviewer (PLA-713). Requires admin Bearer token. */
|
|
391
|
-
get: (interviewerId, opts) =>
|
|
462
|
+
get: (interviewerId, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("GET", `/scheduling/availability/${encodeURIComponent(interviewerId)}`, `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`, accessToken, void 0, signal))(this.adminAccess(opts)),
|
|
392
463
|
/** Set interview availability for an interviewer (PLA-713). Requires admin Bearer token. */
|
|
393
|
-
set: (interviewerId, payload, opts) =>
|
|
464
|
+
set: (interviewerId, payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("PUT", `/scheduling/availability/${encodeURIComponent(interviewerId)}`, `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`, accessToken, payload, signal))(this.adminAccess(opts))
|
|
394
465
|
},
|
|
395
466
|
calendar: {
|
|
396
467
|
/** Get Google Calendar connection status for an interviewer (PLA-726). Requires admin Bearer. */
|
|
397
|
-
status: (interviewerId, opts) =>
|
|
468
|
+
status: (interviewerId, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("GET", `/scheduling/calendar/${encodeURIComponent(interviewerId)}/status`, `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/status`, accessToken, void 0, signal))(this.adminAccess(opts)),
|
|
398
469
|
/** List available Google Calendars (PLA-726). Requires admin Bearer. */
|
|
399
|
-
listCalendars: (interviewerId, opts) =>
|
|
470
|
+
listCalendars: (interviewerId, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("GET", `/scheduling/calendar/${encodeURIComponent(interviewerId)}/calendars`, `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/calendars`, accessToken, void 0, signal))(this.adminAccess(opts)),
|
|
400
471
|
/** Select which Google Calendar to use (PLA-726). Requires admin Bearer. */
|
|
401
|
-
select: (interviewerId, payload, opts) =>
|
|
472
|
+
select: (interviewerId, payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("PUT", `/scheduling/calendar/${encodeURIComponent(interviewerId)}/select`, `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/select`, accessToken, payload, signal))(this.adminAccess(opts)),
|
|
402
473
|
/** Disconnect Google Calendar from interviewer (PLA-726). Requires admin Bearer. */
|
|
403
|
-
disconnect: (interviewerId, opts) =>
|
|
474
|
+
disconnect: (interviewerId, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("POST", `/scheduling/calendar/${encodeURIComponent(interviewerId)}/disconnect`, `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/disconnect`, accessToken, void 0, signal))(this.adminAccess(opts))
|
|
404
475
|
},
|
|
405
476
|
bookingTokens: {
|
|
406
477
|
/** Create a booking token for an application's interview link (PLA-714). Requires admin Bearer token. */
|
|
407
|
-
create: (payload, opts) =>
|
|
478
|
+
create: (payload, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("POST", "/booking-tokens", "/admin/booking-tokens", accessToken, payload, signal))(this.adminAccess(opts)),
|
|
408
479
|
/** Get an existing booking token for an application (PLA-714). Requires admin Bearer token. */
|
|
409
|
-
get: (applicationId, opts) =>
|
|
480
|
+
get: (applicationId, opts) => (({ accessToken, signal }) => this.adminV1OrEmbed("GET", `/booking-tokens/${encodeURIComponent(applicationId)}`, `/admin/booking-tokens/${encodeURIComponent(applicationId)}`, accessToken, void 0, signal))(this.adminAccess(opts))
|
|
410
481
|
}
|
|
411
482
|
}
|
|
412
483
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/error.ts","../src/client.ts","../src/exchange.ts","../src/public-marketplace.ts"],"sourcesContent":["export class ApiClientError extends Error {\n constructor(\n public readonly status: number,\n public readonly code: string,\n message: string,\n /**\n * Seconds to wait before retrying, parsed from a numeric `Retry-After`\n * response header when the server sends one (commonly on 429 and 503).\n * Undefined when the header is absent or in HTTP-date form.\n */\n public readonly retryAfter?: number,\n ) {\n super(message);\n this.name = \"ApiClientError\";\n }\n}\n\n/**\n * Parse the `Retry-After` header into integer seconds. Only the delta-seconds\n * form is honored; the HTTP-date form is ignored (returns undefined) since\n * callers expect a seconds hint.\n */\nfunction parseRetryAfter(res: Response): number | undefined {\n const header = res.headers?.get?.(\"retry-after\")?.trim();\n return header && /^\\d+$/.test(header) ? parseInt(header, 10) : undefined;\n}\n\nexport async function parseError(res: Response): Promise<ApiClientError> {\n const retryAfter = parseRetryAfter(res);\n try {\n const body = (await res.json()) as { error?: string; code?: string };\n return new ApiClientError(res.status, body.code ?? \"UNKNOWN\", body.error ?? res.statusText, retryAfter);\n } catch {\n return new ApiClientError(res.status, \"UNKNOWN\", res.statusText, retryAfter);\n }\n}\n","import { type ApiClientError, parseError } from \"./error.js\";\nimport type {\n Account,\n AnnouncementSendPayload,\n AnnouncementSendResponse,\n Application,\n ApplicationAnnotations,\n ApplicationCreatePayload,\n ApplicationCreateResponse,\n ApplicationEvent,\n ApplicationHistoryResponse,\n ApplicationNote,\n ApplicationScore,\n ApplicationStatus,\n ApplicationTransitionPayload,\n ApplicationTransitionResponse,\n Bike,\n BikeRentalCatalogResponse,\n BikeRentalDeliveryMode,\n BikeRentalInterestedNotReservedResponse,\n BikeRentalRequestInput,\n BikeRentalRequestResult,\n BikeRentalReservationListResponse,\n BikeRentalWaiver,\n BookingToken,\n BookSlotInput,\n BookSlotResponse,\n CalendarStatus,\n CampDocument,\n CommitmentsListResponse,\n Contact,\n CreateBookingTokenInput,\n DuesCreatePayload,\n DuesCreateResponse,\n DuesStatus,\n DuesUpdatePayload,\n DuesUpdateResponse,\n GoogleCalendar,\n Member,\n MemberCreatePayload,\n MemberCreateResponse,\n MemberDeactivateResponse,\n MemberGroup,\n MemberGroupRosterRow,\n MemberRole,\n MemberTag,\n MemberUpdatePayload,\n MemberUpdateResponse,\n NotificationLog,\n OrgConfig,\n OrgUpdatePayload,\n OrgUpdateResponse,\n PackingItemStatus,\n PackingListResponse,\n PackingPersonalItem,\n Paginated,\n PaginationParams,\n PaymentLedgerRow,\n PaymentPageResponse,\n RescheduleInput,\n SelectCalendarInput,\n SetAvailabilityInput,\n SetAvailabilityResponse,\n Shelter,\n Shift,\n Waiver,\n WaiverSignPayload,\n WaiverSignResponse,\n WaiverStatus,\n} from \"./types.js\";\n\nexport type { ApiClientError };\n\ninterface ClientOptions {\n /** Base URL for authenticated /api/v1 routes, e.g. https://api.playaos.app */\n baseUrl: string;\n /** Optional base URL for /api/embed/v1 routes when they live on a different host. */\n embedBaseUrl?: string;\n /** API key in the format pk_live_* */\n apiKey: string;\n /**\n * Supabase session JWT of the acting member, sent as `X-PlayaOS-Member-Token`\n * on every /api/v1 call (PLA-1195). Member-scoped endpoints (a member's own\n * dues, payments, application, shelter, shifts signup, …) require it and\n * return 401 without it. Org-level endpoints do not require it, but a token\n * that is sent must still verify — an expired or invalid one is a 401 on any\n * /api/v1 route that installs the member middleware. Prefer\n * `client.withMember(token)` to derive a per-request client from a shared\n * server-side one rather than constructing a client per user.\n */\n memberToken?: string;\n}\n\n/** Credentials for /api/v1: the org key names the org, the member token names the person. */\ninterface V1Auth {\n apiKey: string;\n memberToken?: string;\n}\n\nfunction v1Headers(auth: V1Auth): Record<string, string> {\n const headers: Record<string, string> = { Authorization: `Bearer ${auth.apiKey}` };\n if (auth.memberToken) headers[\"X-PlayaOS-Member-Token\"] = auth.memberToken;\n return headers;\n}\n\nfunction buildUrl(base: string, path: string, params?: Record<string, string | number | boolean | undefined>): string {\n const url = new URL(`${base}/api/v1${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n // Skip undefined and false booleans — z.coerce.boolean() on the server uses Boolean(),\n // which treats any non-empty string (including \"false\") as true. Omitting a false boolean\n // param has the same effect as the server default (unfiltered).\n if (v !== undefined && v !== false) url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n}\n\nfunction buildEmbedUrl(base: string, path: string): string {\n return `${base}/api/embed/v1${path}`;\n}\n\nfunction withCampKey(url: string, campKey: string): string {\n const embedUrl = new URL(url);\n embedUrl.searchParams.set(\"camp_key\", campKey);\n return embedUrl.toString();\n}\n\nasync function getEmbed<T>(url: string, campKey: string, signal?: AbortSignal): Promise<T> {\n const res = await fetch(withCampKey(url, campKey), {\n headers: { \"X-Camp-Key\": campKey },\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function getEmbedAuthed<T>(\n url: string,\n campKey: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = { \"X-Camp-Key\": campKey };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), { headers, signal: opts?.signal });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function request<T>(url: string, auth: V1Auth, signal?: AbortSignal): Promise<T> {\n const res = await fetch(url, {\n headers: v1Headers(auth),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function post<T>(url: string, auth: V1Auth, body: unknown, signal?: AbortSignal): Promise<T> {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { ...v1Headers(auth), \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\n/** v1 write helpers. `request`/`post` predate these; same auth, other verbs. */\nasync function sendV1<T>(\n method: \"PUT\" | \"PATCH\" | \"DELETE\",\n url: string,\n auth: V1Auth,\n body?: unknown,\n signal?: AbortSignal,\n): Promise<T> {\n const headers: Record<string, string> = v1Headers(auth);\n const init: RequestInit = { method, headers, signal };\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n init.body = JSON.stringify(body);\n }\n const res = await fetch(url, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function postEmbed<T>(\n url: string,\n campKey: string,\n body: unknown,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = {\n \"X-Camp-Key\": campKey,\n \"Content-Type\": \"application/json\",\n };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: opts?.signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function putEmbed<T>(\n url: string,\n campKey: string,\n body: unknown,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = {\n \"X-Camp-Key\": campKey,\n \"Content-Type\": \"application/json\",\n };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), {\n method: \"PUT\",\n headers,\n body: JSON.stringify(body),\n signal: opts?.signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function deleteEmbed<T>(\n url: string,\n campKey: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = { \"X-Camp-Key\": campKey };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), { method: \"DELETE\", headers, signal: opts?.signal });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\n/**\n * Bearer-only helper for /api/embed/v1/admin/* (PLA-489). The admin token is\n * the sole credential (no X-Camp-Key — orgId comes from the JWT claims\n * server-side). `method` can be GET, POST, PATCH, or PUT; `body` is optional\n * (omitted for GET reads like getAnnotations).\n */\nasync function adminEmbed<T>(\n method: \"GET\" | \"POST\" | \"PATCH\" | \"PUT\",\n url: string,\n accessToken: string,\n body?: unknown,\n signal?: AbortSignal,\n): Promise<T> {\n const headers: Record<string, string> = { Authorization: `Bearer ${accessToken}` };\n const init: RequestInit = { method, headers, signal };\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n init.body = JSON.stringify(body);\n }\n const res = await fetch(url, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nexport class PlayaOSClient {\n private readonly baseUrl: string;\n private readonly embedBaseUrl: string;\n private readonly apiKey: string;\n private readonly memberToken: string | undefined;\n\n constructor(opts: ClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n this.embedBaseUrl = (opts.embedBaseUrl ?? opts.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = opts.apiKey;\n this.memberToken = opts.memberToken;\n }\n\n /** Credentials for /api/v1 calls; the embed surface uses `apiKey` alone as the camp key. */\n private get auth(): V1Auth {\n return { apiKey: this.apiKey, memberToken: this.memberToken };\n }\n\n /**\n * Derive a client that acts as one member (PLA-1195): same host and org key,\n * plus the member's Supabase session JWT on every /api/v1 call. Use this in a\n * server that holds one org key and serves many signed-in members.\n */\n withMember(memberToken: string): PlayaOSClient {\n return new PlayaOSClient({\n baseUrl: this.baseUrl,\n embedBaseUrl: this.embedBaseUrl,\n apiKey: this.apiKey,\n memberToken,\n });\n }\n\n readonly members = {\n list: (\n params?: { role?: MemberRole; status?: string } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Member>> => request(buildUrl(this.baseUrl, \"/members\", params), this.auth, opts?.signal),\n\n /**\n * Full profile (phone, emergency contact). Requires a member token; pass\n * `\"me\"` for the acting member — non-admins may fetch only themselves.\n */\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Member> =>\n request(buildUrl(this.baseUrl, `/members/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n /** Member-self profile update (PLA-700). Requires camp key + member Bearer token. */\n selfUpdate: (\n payload: {\n bio?: string | null;\n playaName?: string | null;\n socialMedia?: Record<string, unknown> | null;\n showSocialsInDirectory?: boolean;\n phone?: string | null;\n emergencyContactName?: string | null;\n emergencyContactRelationship?: string | null;\n emergencyContactPhone?: string | null;\n profilePhotoPath?: string | null;\n yearJoined?: number | null;\n },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ profileId: string }> =>\n putEmbed(buildEmbedUrl(this.embedBaseUrl, \"/members/self\"), this.apiKey, payload, opts),\n\n /** Member-self shift signup + cancel (PLA-705). Requires camp key + member Bearer. */\n shifts: {\n signup: (\n payload: { shiftId: string; role?: string },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ signupId: string; waitlisted: boolean }> =>\n postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/shifts/signup\"), this.apiKey, payload, opts),\n cancel: (\n signupId: string,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ canceled: boolean; promotedSignupId: string | null }> =>\n deleteEmbed(\n buildEmbedUrl(this.embedBaseUrl, `/shifts/signups/${encodeURIComponent(signupId)}`),\n this.apiKey,\n opts,\n ),\n },\n };\n\n readonly applications = {\n list: (\n params?: { status?: ApplicationStatus; year?: number } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Application>> =>\n request(buildUrl(this.baseUrl, \"/applications\", params), this.auth, opts?.signal),\n\n // Anonymous external-camp submission against POST /api/embed/v1/applications\n // (PLA-481). Uses the X-Camp-Key header rather than Bearer auth. Pass\n // `accessToken` to additionally send a PlayaOS IdP JWT (PLA-573 path) so\n // the server trusts the verified profile claim and skips the email-based\n // bootstrap.\n create: (\n payload: ApplicationCreatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationCreateResponse> =>\n postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/applications\"), this.apiKey, payload, opts),\n };\n\n readonly waivers = {\n /** Get the active waiver for an org for the current year. */\n active: (orgId: string, opts?: { signal?: AbortSignal }): Promise<Waiver> =>\n getEmbed(buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/active`), this.apiKey, opts?.signal),\n\n /** Sign a waiver. Requires X-Camp-Key; optional accessToken for Bearer path. */\n sign: (\n payload: WaiverSignPayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<WaiverSignResponse> =>\n postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/waivers/sign\"), this.apiKey, payload, opts),\n\n /** Has this applicant/member signed the active waiver? Anchor: applicationId query or Bearer accessToken. */\n status: (\n orgId: string,\n opts?: { applicationId?: string; accessToken?: string; signal?: AbortSignal },\n ): Promise<WaiverStatus> => {\n const query = opts?.applicationId ? `?applicationId=${encodeURIComponent(opts.applicationId)}` : \"\";\n return getEmbedAuthed(buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/status${query}`), this.apiKey, opts);\n },\n\n /** Get a short-lived download URL for a completed signature's PDF. Anchor: applicationId query or Bearer. */\n signedPdf: (\n orgId: string,\n signatureId: string,\n opts?: { applicationId?: string; accessToken?: string; signal?: AbortSignal },\n ): Promise<{ url: string }> => {\n const query = opts?.applicationId ? `?applicationId=${encodeURIComponent(opts.applicationId)}` : \"\";\n return getEmbedAuthed(\n buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/signatures/${encodeURIComponent(signatureId)}/pdf${query}`),\n this.apiKey,\n opts,\n );\n },\n };\n\n readonly dues = {\n list: (\n params?: { userId?: string; year?: number; paymentStatus?: \"unpaid\" | \"partial\" | \"paid\" } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<DuesStatus>> => request(buildUrl(this.baseUrl, \"/dues\", params), this.auth, opts?.signal),\n };\n\n readonly shifts = {\n list: (\n params?: {\n year?: number;\n fromDate?: string;\n toDate?: string;\n publishedOnly?: boolean;\n openOnly?: boolean;\n } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Shift>> => request(buildUrl(this.baseUrl, \"/shifts\", params), this.auth, opts?.signal),\n };\n\n readonly org = {\n get: (opts?: { signal?: AbortSignal }): Promise<OrgConfig> =>\n request(buildUrl(this.baseUrl, \"/org\"), this.auth, opts?.signal),\n };\n\n // Public embed surface: active commitment definitions for the org's current\n // year, so the <ApplicationForm> can render + validate them (PLA-682). Uses\n // the X-Camp-Key (the apiKey doubles as the camp key), same as applications.create.\n readonly commitments = {\n list: (opts?: { signal?: AbortSignal }): Promise<CommitmentsListResponse> =>\n getEmbed(buildEmbedUrl(this.embedBaseUrl, \"/commitments\"), this.apiKey, opts?.signal),\n };\n\n readonly payments = {\n list: (\n params?: {\n type?: \"dues\" | \"payment\";\n memberId?: string;\n from?: string;\n to?: string;\n limit?: number;\n offset?: number;\n },\n opts?: { signal?: AbortSignal },\n ): Promise<PaymentLedgerRow[]> => request(buildUrl(this.baseUrl, \"/payments\", params), this.auth, opts?.signal),\n\n /** Requires a member token. `memberId` may be omitted by a non-admin (defaults to themselves); admins must pass it. */\n page: (\n memberId?: string,\n duesCollectionId?: string,\n opts?: { signal?: AbortSignal },\n ): Promise<PaymentPageResponse> =>\n post(buildUrl(this.baseUrl, \"/payments/page\"), this.auth, { memberId, duesCollectionId }, opts?.signal),\n };\n\n readonly accounts = {\n list: (params?: { limit?: number; offset?: number }, opts?: { signal?: AbortSignal }): Promise<Account[]> =>\n request(buildUrl(this.baseUrl, \"/accounts\", params), this.auth, opts?.signal),\n };\n\n readonly contacts = {\n list: (\n params?: {\n role?: MemberRole;\n status?: string;\n search?: string;\n sort?: \"name\" | \"email\";\n limit?: number;\n offset?: number;\n },\n opts?: { signal?: AbortSignal },\n ): Promise<Contact[]> => request(buildUrl(this.baseUrl, \"/contacts\", params), this.auth, opts?.signal),\n };\n\n readonly notifications = {\n list: (\n params?: { category?: string; status?: string; recipientId?: string; limit?: number },\n opts?: { signal?: AbortSignal },\n ): Promise<NotificationLog[]> => request(buildUrl(this.baseUrl, \"/notifications\", params), this.auth, opts?.signal),\n };\n\n readonly documents = {\n list: (params?: { type?: string; year?: number }, opts?: { signal?: AbortSignal }): Promise<CampDocument[]> =>\n request(buildUrl(this.baseUrl, \"/documents\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<CampDocument> =>\n request(buildUrl(this.baseUrl, `/documents/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n };\n\n readonly shelters = {\n list: (\n params?: { ownerId?: string; shelterType?: string; year?: number },\n opts?: { signal?: AbortSignal },\n ): Promise<Shelter[]> => request(buildUrl(this.baseUrl, \"/shelters\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Shelter> =>\n request(buildUrl(this.baseUrl, `/shelters/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n };\n\n readonly bikes = {\n list: (params?: { status?: string }, opts?: { signal?: AbortSignal }): Promise<Bike[]> =>\n request(buildUrl(this.baseUrl, \"/bikes\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Bike> =>\n request(buildUrl(this.baseUrl, `/bikes/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n };\n\n /**\n * DustJunkie bike rentals (PLA-1180), passed through to the vendor. A camp\n * without the integration gets 403; a DustJunkie failure is a 502.\n */\n readonly bikeRentals = {\n /** Bookable options with estimated totals for `delivery` (server default `camp_delivery`). Org key only. */\n catalog: (\n params?: { delivery?: BikeRentalDeliveryMode },\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalCatalogResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/catalog\", params), this.auth, opts?.signal),\n\n /** The rental agreement the member must accept before `requestReservation`. Org key only. */\n waiver: (opts?: { signal?: AbortSignal }): Promise<BikeRentalWaiver> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/waiver\"), this.auth, opts?.signal),\n\n /**\n * Requires a member token. Admins get the whole camp when `memberId` is\n * omitted; any other role gets their own reservations and 403 naming someone else.\n */\n reservations: (\n params?: { memberId?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalReservationListResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/reservations\", params), this.auth, opts?.signal),\n\n /**\n * Requires a member token; always requests for the acting member. 409 when\n * the model is sold out, 400 when it is unknown or no longer bookable.\n */\n requestReservation: (\n payload: BikeRentalRequestInput,\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalRequestResult> =>\n post(buildUrl(this.baseUrl, \"/bike-rentals/requests\"), this.auth, payload, opts?.signal),\n\n /** Members who said they want a bike but have no reservation, for the active camp year. Org key only. */\n interestedNotReserved: (opts?: { signal?: AbortSignal }): Promise<BikeRentalInterestedNotReservedResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/interested-not-reserved\"), this.auth, opts?.signal),\n };\n\n readonly tags = {\n list: (opts?: { signal?: AbortSignal }): Promise<MemberTag[]> =>\n request(buildUrl(this.baseUrl, \"/tags\"), this.auth, opts?.signal),\n };\n\n readonly groups = {\n list: (opts?: { signal?: AbortSignal }): Promise<MemberGroup[]> =>\n request(buildUrl(this.baseUrl, \"/groups\"), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<MemberGroupRosterRow[]> =>\n request(buildUrl(this.baseUrl, `/groups/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n create: (\n payload: { name: string; leaderProfileId: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ id: string }> => post(buildUrl(this.baseUrl, \"/groups\"), this.auth, payload, opts?.signal),\n };\n\n /**\n * Camp-scoped packing (PLA-1197). Every method is the acting member's own\n * list — packing has no `memberId` to widen, so these require `memberToken`\n * and 401 on an org key alone.\n */\n readonly packing = {\n /** The resolved list: curated base + camp layer + personal layer (ADR-071). */\n list: (\n params?: { year?: number; shelter?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<PackingListResponse> => request(buildUrl(this.baseUrl, \"/packing\", params), this.auth, opts?.signal),\n\n /**\n * Set the member's status for one item. The slug goes in the body, not the\n * path: slugs are `${category}/${name}` and contain a `/`.\n *\n * Pass the same `shelter` the list was read under — validation filters by\n * shelter, so an override omitted here rejects shelter-specific items.\n */\n setStatus: (\n payload: { slug: string; status: PackingItemStatus; year?: number; shelter?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ ok: true }> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/packing/items/status\"), this.auth, payload, opts?.signal),\n\n personalItems: {\n list: (\n params?: { containerId?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ items: PackingPersonalItem[] }> =>\n request(buildUrl(this.baseUrl, \"/packing/personal-items\", params), this.auth, opts?.signal),\n\n create: (\n payload: { name: string; category: string; qty?: number; unit?: string | null; notes?: string | null },\n opts?: { signal?: AbortSignal },\n ): Promise<{ id: string }> =>\n post(buildUrl(this.baseUrl, \"/packing/personal-items\"), this.auth, payload, opts?.signal),\n\n /**\n * Flip the item between `need` and `have`. It does **not** set `packed` —\n * use `setStatus` for the full vocabulary. 404 if the item is not the\n * acting member's.\n */\n toggle: (id: string, opts?: { signal?: AbortSignal }): Promise<{ ok: true }> =>\n sendV1(\n \"PATCH\",\n buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n\n /** 404 if the item is not the acting member's. */\n remove: (id: string, opts?: { signal?: AbortSignal }): Promise<{ ok: true }> =>\n sendV1(\n \"DELETE\",\n buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n },\n };\n\n // Admin write APIs (PLA-489). Each method requires `accessToken` — a Supabase\n // JWT for a camp admin/super_admin. The org boundary is enforced server-side\n // from the JWT claims; these endpoints do not use the X-Camp-Key.\n readonly admin = {\n applications: {\n /**\n * Get application audit timeline (PLA-712). Requires admin Bearer token.\n *\n * @deprecated The embed handler for this method never existed — calls\n * always 404'd (see PLA-1199). Retained as a compile-time compatibility\n * surface for published-consumer code; delegates to the canonical\n * `GET /api/v1/audit/application-logs?applicationId=` (ADR-054), which\n * reads the same `application_audit_logs` table. The `accessToken`\n * argument is accepted but unused — the v1 surface authenticates with\n * the org API key (`audit:read` scope) instead of an admin JWT. Remove\n * in the next major version.\n */\n history: async (\n id: string,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<ApplicationHistoryResponse> => {\n type AuditRow = {\n id: string;\n applicationId: string;\n actorUserId: string | null;\n action: string;\n details: Record<string, unknown> | null;\n createdAt: string | null;\n };\n\n // The old embed shape returned the whole timeline in one object, so the\n // cursor has to be followed here — returning only the first 100 rows\n // would silently truncate long-running applications.\n const rows: AuditRow[] = [];\n let cursor: string | null = null;\n do {\n const page: Paginated<AuditRow> = await request<Paginated<AuditRow>>(\n buildUrl(this.baseUrl, \"/audit/application-logs\", {\n applicationId: id,\n limit: 100,\n ...(cursor ? { cursor } : {}),\n }),\n this.auth,\n opts?.signal,\n );\n rows.push(...page.data);\n cursor = page.nextCursor;\n } while (cursor);\n\n return {\n events: rows.map((row) => ({\n id: row.id,\n applicationId: row.applicationId,\n actorId: row.actorUserId,\n actorName: null,\n type: (row.action === \"status_changed\" ? \"status_change\" : row.action) as ApplicationEvent[\"type\"],\n timestamp: row.createdAt ?? \"\",\n metadata: row.details ?? undefined,\n })),\n };\n },\n transition: (\n id: string,\n payload: ApplicationTransitionPayload,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<ApplicationTransitionResponse> =>\n adminEmbed(\n \"PATCH\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}`),\n opts.accessToken,\n payload,\n opts.signal,\n ),\n getAnnotations: (\n id: string,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<ApplicationAnnotations> =>\n adminEmbed(\n \"GET\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/annotations`),\n opts.accessToken,\n undefined,\n opts.signal,\n ),\n addNote: (\n id: string,\n payload: { body: string },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<ApplicationNote> =>\n adminEmbed(\n \"POST\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/notes`),\n opts.accessToken,\n payload,\n opts.signal,\n ),\n setTags: (\n id: string,\n payload: { tags: string[] },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<string[]> =>\n adminEmbed(\n \"PUT\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/tags`),\n opts.accessToken,\n payload,\n opts.signal,\n ),\n setScore: (\n id: string,\n payload: { value: number },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<ApplicationScore> =>\n adminEmbed(\n \"PUT\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/scores`),\n opts.accessToken,\n payload,\n opts.signal,\n ),\n },\n givebutter: {\n campaigns: {\n list: (opts: { accessToken: string; signal?: AbortSignal }): Promise<unknown[]> =>\n adminEmbed(\n \"GET\",\n buildEmbedUrl(this.embedBaseUrl, \"/admin/givebutter/campaigns\"),\n opts.accessToken,\n undefined,\n opts.signal,\n ),\n discountCodes: {\n list: (campaignId: number, opts: { accessToken: string; signal?: AbortSignal }): Promise<unknown[]> =>\n adminEmbed(\n \"GET\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/givebutter/campaigns/${campaignId}/discount-codes`),\n opts.accessToken,\n undefined,\n opts.signal,\n ),\n create: (\n campaignId: number,\n payload: { code: string; value: number; type: \"percent\" | \"fixed\"; expirationDate?: string },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<unknown> =>\n adminEmbed(\n \"POST\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/givebutter/campaigns/${campaignId}/discount-codes`),\n opts.accessToken,\n payload,\n opts.signal,\n ),\n },\n tickets: {\n create: (\n campaignId: number,\n payload: { name: string; price: number; totalQuantity?: number },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<unknown> =>\n adminEmbed(\n \"POST\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/givebutter/campaigns/${campaignId}/tickets`),\n opts.accessToken,\n payload,\n opts.signal,\n ),\n },\n },\n },\n members: {\n create: (\n payload: MemberCreatePayload,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<MemberCreateResponse> =>\n adminEmbed(\"POST\", buildEmbedUrl(this.embedBaseUrl, \"/admin/members\"), opts.accessToken, payload, opts.signal),\n\n update: (\n id: string,\n patch: MemberUpdatePayload,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<MemberUpdateResponse> =>\n adminEmbed(\n \"PATCH\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/members/${encodeURIComponent(id)}`),\n opts.accessToken,\n patch,\n opts.signal,\n ),\n\n deactivate: (\n id: string,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<MemberDeactivateResponse> =>\n adminEmbed(\n \"PATCH\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/members/${encodeURIComponent(id)}`),\n opts.accessToken,\n { status: \"inactive\" },\n opts.signal,\n ),\n },\n announcements: {\n /** Send an email blast to camp members (PLA-706). Requires admin Bearer token. */\n send: (\n payload: AnnouncementSendPayload,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<AnnouncementSendResponse> =>\n adminEmbed(\n \"POST\",\n buildEmbedUrl(this.embedBaseUrl, \"/admin/announcements/send\"),\n opts.accessToken,\n payload,\n opts.signal,\n ),\n },\n dues: {\n /** Create a manual dues/payment record (PLA-708). Requires admin Bearer token. */\n create: (\n payload: DuesCreatePayload,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<DuesCreateResponse> =>\n adminEmbed(\"POST\", buildEmbedUrl(this.embedBaseUrl, \"/admin/dues\"), opts.accessToken, payload, opts.signal),\n\n /** Update a dues/payment record (PLA-708). Requires admin Bearer token. */\n update: (\n id: string,\n payload: DuesUpdatePayload,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<DuesUpdateResponse> =>\n adminEmbed(\n \"PATCH\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/dues/${encodeURIComponent(id)}`),\n opts.accessToken,\n payload,\n opts.signal,\n ),\n },\n org: {\n /** Update camp configuration settings (PLA-709). Requires admin Bearer token. */\n update: (\n payload: OrgUpdatePayload,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<OrgUpdateResponse> =>\n adminEmbed(\"PATCH\", buildEmbedUrl(this.embedBaseUrl, \"/admin/org\"), opts.accessToken, payload, opts.signal),\n },\n scheduling: {\n availability: {\n /** Get interview availability for an interviewer (PLA-713). Requires admin Bearer token. */\n get: (\n interviewerId: string,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<SetAvailabilityResponse> =>\n adminEmbed(\n \"GET\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`),\n opts.accessToken,\n undefined,\n opts.signal,\n ),\n /** Set interview availability for an interviewer (PLA-713). Requires admin Bearer token. */\n set: (\n interviewerId: string,\n payload: SetAvailabilityInput,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<SetAvailabilityResponse> =>\n adminEmbed(\n \"PUT\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`),\n opts.accessToken,\n payload,\n opts.signal,\n ),\n },\n calendar: {\n /** Get Google Calendar connection status for an interviewer (PLA-726). Requires admin Bearer. */\n status: (interviewerId: string, opts: { accessToken: string; signal?: AbortSignal }): Promise<CalendarStatus> =>\n adminEmbed(\n \"GET\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/status`),\n opts.accessToken,\n undefined,\n opts.signal,\n ),\n /** List available Google Calendars (PLA-726). Requires admin Bearer. */\n listCalendars: (\n interviewerId: string,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ calendars: GoogleCalendar[] }> =>\n adminEmbed(\n \"GET\",\n buildEmbedUrl(\n this.embedBaseUrl,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/calendars`,\n ),\n opts.accessToken,\n undefined,\n opts.signal,\n ),\n /** Select which Google Calendar to use (PLA-726). Requires admin Bearer. */\n select: (\n interviewerId: string,\n payload: SelectCalendarInput,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ calendarId: string }> =>\n adminEmbed(\n \"PUT\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/select`),\n opts.accessToken,\n payload,\n opts.signal,\n ),\n /** Disconnect Google Calendar from interviewer (PLA-726). Requires admin Bearer. */\n disconnect: (\n interviewerId: string,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ disconnected: boolean }> =>\n adminEmbed(\n \"POST\",\n buildEmbedUrl(\n this.embedBaseUrl,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/disconnect`,\n ),\n opts.accessToken,\n undefined,\n opts.signal,\n ),\n },\n bookingTokens: {\n /** Create a booking token for an application's interview link (PLA-714). Requires admin Bearer token. */\n create: (\n payload: CreateBookingTokenInput,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<BookingToken> =>\n adminEmbed(\n \"POST\",\n buildEmbedUrl(this.embedBaseUrl, \"/admin/booking-tokens\"),\n opts.accessToken,\n payload,\n opts.signal,\n ),\n /** Get an existing booking token for an application (PLA-714). Requires admin Bearer token. */\n get: (applicationId: string, opts: { accessToken: string; signal?: AbortSignal }): Promise<BookingToken> =>\n adminEmbed(\n \"GET\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/booking-tokens/${encodeURIComponent(applicationId)}`),\n opts.accessToken,\n undefined,\n opts.signal,\n ),\n },\n },\n };\n\n // Public embed-booking endpoints (PLA-714). No auth — these are the\n // applicant-facing schedule surface using the hashed booking token.\n readonly schedule = {\n /** List available interview slots for a booking token (PLA-714). Public. */\n getSlots: (\n token: string,\n opts?: { signal?: AbortSignal },\n ): Promise<{ slots: { startsAt: string; endsAt: string }[] }> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}`;\n return fetch(url, { signal: opts?.signal }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<{ slots: { startsAt: string; endsAt: string }[] }>;\n });\n },\n /** Book an interview slot (PLA-714). Public. */\n book: (token: string, payload: BookSlotInput, opts?: { signal?: AbortSignal }): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/book`;\n return fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: opts?.signal,\n }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n /** Cancel an interview booking (PLA-714). Public. */\n cancel: (token: string, opts?: { signal?: AbortSignal }): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/cancel`;\n return fetch(url, { method: \"POST\", signal: opts?.signal }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n /** Reschedule an interview booking (PLA-714). Public. */\n reschedule: (\n token: string,\n payload: RescheduleInput,\n opts?: { signal?: AbortSignal },\n ): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/reschedule`;\n return fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: opts?.signal,\n }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n };\n}\n\n/** Convenience factory — equivalent to `new PlayaOSClient(opts)`. */\nexport function createClient(opts: ClientOptions): PlayaOSClient {\n return new PlayaOSClient(opts);\n}\n","/**\n * Server-side OAuth-code → ID-token exchange.\n *\n * Swaps a one-time authorization code from the PlayaOS IdP for a short-lived\n * ID token. Confidential clients pass `clientSecret`, which is sent to the\n * token endpoint server-side. Public/PKCE-only clients omit it — the\n * authorization-code + code_verifier pair is the sole credential. Public\n * clients can also exchange directly from the browser via `usePlayaOSAuth`\n * in `@playaos/react`.\n */\n\nexport interface ExchangeParams {\n authBaseUrl?: string;\n code: string;\n codeVerifier: string;\n clientId: string;\n /** Confidential clients only. Omit for public/PKCE-only clients. */\n clientSecret?: string;\n redirectUri: string;\n}\n\nexport interface ExchangeResult {\n idToken: string;\n expiresAt: string;\n /** Confidential clients only. Undefined for public clients. */\n refreshToken?: string;\n}\n\nexport async function exchangeCode(params: ExchangeParams): Promise<ExchangeResult> {\n const base = params.authBaseUrl ?? \"https://auth.playaos.app\";\n // A confidential client is identified by passing clientSecret at all — even an\n // empty string. We forward it as-is so the server validates it (an empty or\n // wrong secret is rejected there); public clients omit the field entirely.\n const isConfidential = params.clientSecret !== undefined;\n const res = await fetch(`${base}/api/auth/v1/exchange`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n code: params.code,\n code_verifier: params.codeVerifier,\n client_id: params.clientId,\n ...(isConfidential ? { client_secret: params.clientSecret } : {}),\n redirect_uri: params.redirectUri,\n }),\n });\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n throw new Error(`Exchange failed: non-JSON response (${res.status})`);\n }\n\n if (!res.ok) {\n const errorReason =\n typeof body === \"object\" && body !== null && \"error\" in body && typeof body.error === \"string\"\n ? body.error\n : String(res.status);\n throw new Error(`Exchange failed: ${errorReason}`);\n }\n\n if (\n typeof body !== \"object\" ||\n body === null ||\n !(\"idToken\" in body) ||\n typeof body.idToken !== \"string\" ||\n !(\"expiresAt\" in body) ||\n typeof body.expiresAt !== \"string\"\n ) {\n throw new Error(\"Exchange failed: malformed success response\");\n }\n\n // The server mints a refresh token only for confidential clients (it sets\n // `withRefreshToken: client.type === \"confidential\"`); public clients get\n // none. Surface it when present, otherwise leave it undefined.\n const refreshToken = \"refreshToken\" in body && typeof body.refreshToken === \"string\" ? body.refreshToken : undefined;\n\n // A confidential client that gets no refresh token means the server response\n // is malformed or the rotation flow is broken — surface it rather than\n // silently returning a result the caller can't refresh.\n if (isConfidential && refreshToken === undefined) {\n throw new Error(\"Exchange failed: confidential client response missing refreshToken\");\n }\n\n return {\n idToken: body.idToken,\n expiresAt: body.expiresAt,\n ...(refreshToken !== undefined ? { refreshToken } : {}),\n };\n}\n","import { parseError } from \"./error.js\";\n\n/** A listing holds at most this many images (matches the DB's position 1–6 check). */\nexport const MAX_IMAGE_POSITION = 6;\n\n/**\n * Typed client for the anonymous gift-layer marketplace API (`/api/public/marketplace/*`).\n *\n * Unlike `PlayaOSClient` (api-key auth for `/api/v1`), this surface authenticates\n * writes with a Supabase **Bearer JWT** belonging to a public `global_accounts`\n * user. The token is supplied by an injected `getToken` provider so the same\n * client works from any consumer (the marketing UI supplies the browser\n * Supabase session token; a future surface could supply its own). Keeps the\n * public API as the single write contract — the UI is just another consumer.\n */\nexport interface PublicMarketplaceClientOptions {\n /** API base, e.g. `https://api.playaos.app`. */\n baseUrl: string;\n /** Supplies the Supabase access token (Bearer) for authenticated calls; null/undefined when signed out. */\n getToken: () => Promise<string | null | undefined> | string | null | undefined;\n}\n\nexport interface NewListingInput {\n category: string;\n subcategory?: string;\n title: string;\n body: string;\n price?: number;\n location?: string;\n replyEmail: string;\n}\n\nexport interface ImageUploadTarget {\n /** Supabase signed upload URL — PUT the file bytes here. */\n uploadUrl: string;\n /** Storage path to pass back to `attachImage` once the PUT succeeds. */\n storagePath: string;\n}\n\n/** Moderation flag reasons accepted by the API (mirrors the DB enum). */\nexport type MarketplaceFlagReason = \"spam\" | \"prohibited\" | \"other\";\n\nexport interface ListingImage {\n /** Short-lived signed download URL for the image. */\n url: string;\n /** 1-based display order. */\n position: number;\n}\n\nexport interface PublicMarketplaceClient {\n /**\n * Create a listing as the signed-in account. Throws a plain `Error` when there\n * is no token (signed out), or `ApiClientError` on a non-2xx response.\n */\n createListing(input: NewListingInput, signal?: AbortSignal): Promise<{ id: string }>;\n /** Request a signed upload URL for an image on a listing the caller owns. */\n getImageUploadUrl(listingId: string, signal?: AbortSignal): Promise<ImageUploadTarget>;\n /** Attach an already-uploaded image (by storage path) to a listing at a 1–6 position. */\n attachImage(\n listingId: string,\n input: { storagePath: string; position: number },\n signal?: AbortSignal,\n ): Promise<{ id: string }>;\n /** Anonymous: list an active listing's images as short-lived signed URLs (for public display). */\n listListingImages(listingId: string, signal?: AbortSignal): Promise<{ images: ListingImage[] }>;\n /** Anonymous: batch-fetch first-image signed thumbnail URLs (listingId -> url) for browse cards. */\n listThumbnails(listingIds: string[], signal?: AbortSignal): Promise<{ thumbnails: Record<string, string> }>;\n /** Flag a listing for moderation (signed-in). Idempotent per (listing, user). */\n flagListing(listingId: string, reason: MarketplaceFlagReason, signal?: AbortSignal): Promise<{ ok: boolean }>;\n /** Contact a listing's owner (signed-in); records the reply + queues a notification email. */\n replyToListing(listingId: string, message: string | undefined, signal?: AbortSignal): Promise<{ ok: boolean }>;\n}\n\nexport function createPublicMarketplaceClient(opts: PublicMarketplaceClientOptions): PublicMarketplaceClient {\n const base = opts.baseUrl.replace(/\\/+$/, \"\");\n if (!base) {\n // An empty base would issue relative requests to the caller's own origin.\n throw new Error(\"createPublicMarketplaceClient: baseUrl is required\");\n }\n\n async function authedPost<T>(path: string, body: unknown, signal?: AbortSignal): Promise<T> {\n const token = await opts.getToken();\n if (!token) throw new Error(\"Not signed in\");\n const res = await fetch(`${base}/api/public/marketplace${path}`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}`, \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n }\n\n async function publicGet<T>(path: string, signal?: AbortSignal): Promise<T> {\n // no-store: responses carry short-lived signed URLs — never let the framework\n // (e.g. Next's fetch cache) memoize them and serve expired URLs. `cache` is a\n // valid fetch option at runtime but absent from @types/node's RequestInit,\n // so the init is typed with an intersection.\n const init: RequestInit & { cache: \"no-store\" } = { signal, cache: \"no-store\" };\n const res = await fetch(`${base}/api/public/marketplace${path}`, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n }\n\n const seg = (listingId: string) => `/listings/${encodeURIComponent(listingId)}`;\n\n return {\n createListing: (input, signal) => authedPost(\"/listings\", input, signal),\n getImageUploadUrl: (listingId, signal) => authedPost(`${seg(listingId)}/image-upload-url`, {}, signal),\n attachImage: (listingId, input, signal) => {\n // Fail fast on a misuse the API would otherwise reject with a vague 400.\n if (!Number.isInteger(input.position) || input.position < 1 || input.position > MAX_IMAGE_POSITION) {\n return Promise.reject(new Error(`attachImage: position must be 1–${MAX_IMAGE_POSITION}`));\n }\n return authedPost(`${seg(listingId)}/images`, input, signal);\n },\n listListingImages: (listingId, signal) => publicGet(`${seg(listingId)}/images`, signal),\n listThumbnails: (listingIds, signal) =>\n publicGet(`/thumbnails?ids=${encodeURIComponent(listingIds.join(\",\"))}`, signal),\n flagListing: (listingId, reason, signal) => authedPost(`${seg(listingId)}/flag`, { reason }, signal),\n replyToListing: (listingId, message, signal) => authedPost(`${seg(listingId)}/reply`, { message }, signal),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/error.ts","../src/client.ts","../src/exchange.ts","../src/public-marketplace.ts"],"sourcesContent":["export class ApiClientError extends Error {\n constructor(\n public readonly status: number,\n public readonly code: string,\n message: string,\n /**\n * Seconds to wait before retrying, parsed from a numeric `Retry-After`\n * response header when the server sends one (commonly on 429 and 503).\n * Undefined when the header is absent or in HTTP-date form.\n */\n public readonly retryAfter?: number,\n ) {\n super(message);\n this.name = \"ApiClientError\";\n }\n}\n\n/**\n * Parse the `Retry-After` header into integer seconds. Only the delta-seconds\n * form is honored; the HTTP-date form is ignored (returns undefined) since\n * callers expect a seconds hint.\n */\nfunction parseRetryAfter(res: Response): number | undefined {\n const header = res.headers?.get?.(\"retry-after\")?.trim();\n return header && /^\\d+$/.test(header) ? parseInt(header, 10) : undefined;\n}\n\nexport async function parseError(res: Response): Promise<ApiClientError> {\n const retryAfter = parseRetryAfter(res);\n try {\n const body = (await res.json()) as { error?: string; code?: string };\n return new ApiClientError(res.status, body.code ?? \"UNKNOWN\", body.error ?? res.statusText, retryAfter);\n } catch {\n return new ApiClientError(res.status, \"UNKNOWN\", res.statusText, retryAfter);\n }\n}\n","import { type ApiClientError, parseError } from \"./error.js\";\nimport type {\n Account,\n AnnouncementSendPayload,\n AnnouncementSendResponse,\n Application,\n ApplicationAnnotations,\n ApplicationCreatePayload,\n ApplicationCreateResponse,\n ApplicationEvent,\n ApplicationHistoryResponse,\n ApplicationNote,\n ApplicationScore,\n ApplicationStatus,\n ApplicationTransitionPayload,\n ApplicationTransitionResponse,\n Bike,\n BikeRentalCatalogResponse,\n BikeRentalDeliveryMode,\n BikeRentalInterestedNotReservedResponse,\n BikeRentalRequestInput,\n BikeRentalRequestResult,\n BikeRentalReservationListResponse,\n BikeRentalWaiver,\n BookingToken,\n BookSlotInput,\n BookSlotResponse,\n CalendarStatus,\n CampDocument,\n CommitmentsListResponse,\n Contact,\n CreateBookingTokenInput,\n CreateSapAssignmentInput,\n DuesCreatePayload,\n DuesCreateResponse,\n DuesStatus,\n DuesUpdatePayload,\n DuesUpdateResponse,\n GetAvailabilityResponse,\n GoogleCalendar,\n Member,\n MemberCreatePayload,\n MemberCreateResponse,\n MemberDeactivateResponse,\n MemberGroup,\n MemberGroupRosterRow,\n MemberRole,\n MemberTag,\n MemberUpdatePayload,\n MemberUpdateResponse,\n NotificationLog,\n OrgConfig,\n OrgUpdatePayload,\n OrgUpdateResponse,\n PackingCampItem,\n PackingItemStatus,\n PackingListResponse,\n PackingPersonalItem,\n Paginated,\n PaginationParams,\n PaymentLedgerRow,\n PaymentPageResponse,\n RescheduleInput,\n SapAllocation,\n SapAssignment,\n SapDayAllocation,\n SelectCalendarInput,\n SetAvailabilityInput,\n SetAvailabilityResponse,\n Shelter,\n Shift,\n UpdateSapAllocationInput,\n UpdateSapAssignmentInput,\n UpsertPackingCampItemInput,\n UpsertSapDayAllocationInput,\n Waiver,\n WaiverSignPayload,\n WaiverSignResponse,\n WaiverStatus,\n} from \"./types.js\";\n\nexport type { ApiClientError };\n\ninterface ClientOptions {\n /** Base URL for authenticated /api/v1 routes, e.g. https://api.playaos.app */\n baseUrl: string;\n /** Optional base URL for /api/embed/v1 routes when they live on a different host. */\n embedBaseUrl?: string;\n /** API key in the format pk_live_* */\n apiKey: string;\n /**\n * Supabase session JWT of the acting member, sent as `X-PlayaOS-Member-Token`\n * on every /api/v1 call (PLA-1195). Member-scoped endpoints (a member's own\n * dues, payments, application, shelter, shifts signup, …) require it and\n * return 401 without it. Org-level endpoints do not require it, but a token\n * that is sent must still verify — an expired or invalid one is a 401 on any\n * /api/v1 route that installs the member middleware. Prefer\n * `client.withMember(token)` to derive a per-request client from a shared\n * server-side one rather than constructing a client per user.\n */\n memberToken?: string;\n}\n\n/** Credentials for /api/v1: the org key names the org, the member token names the person. */\ninterface V1Auth {\n apiKey: string;\n memberToken?: string;\n}\n\nfunction v1Headers(auth: V1Auth): Record<string, string> {\n const headers: Record<string, string> = { Authorization: `Bearer ${auth.apiKey}` };\n if (auth.memberToken) headers[\"X-PlayaOS-Member-Token\"] = auth.memberToken;\n return headers;\n}\n\nfunction buildUrl(base: string, path: string, params?: Record<string, string | number | boolean | undefined>): string {\n const url = new URL(`${base}/api/v1${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n // Skip undefined and false booleans — z.coerce.boolean() on the server uses Boolean(),\n // which treats any non-empty string (including \"false\") as true. Omitting a false boolean\n // param has the same effect as the server default (unfiltered).\n if (v !== undefined && v !== false) url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n}\n\nfunction buildEmbedUrl(base: string, path: string): string {\n return `${base}/api/embed/v1${path}`;\n}\n\nfunction withCampKey(url: string, campKey: string): string {\n const embedUrl = new URL(url);\n embedUrl.searchParams.set(\"camp_key\", campKey);\n return embedUrl.toString();\n}\n\nasync function getEmbed<T>(url: string, campKey: string, signal?: AbortSignal): Promise<T> {\n const res = await fetch(withCampKey(url, campKey), {\n headers: { \"X-Camp-Key\": campKey },\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function getEmbedAuthed<T>(\n url: string,\n campKey: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = { \"X-Camp-Key\": campKey };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), { headers, signal: opts?.signal });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function request<T>(url: string, auth: V1Auth, signal?: AbortSignal): Promise<T> {\n const res = await fetch(url, {\n headers: v1Headers(auth),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function post<T>(url: string, auth: V1Auth, body: unknown, signal?: AbortSignal): Promise<T> {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { ...v1Headers(auth), \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\n/** v1 write helpers. `request`/`post` predate these; same auth, other verbs. */\nasync function sendV1<T>(\n method: \"PUT\" | \"PATCH\" | \"DELETE\",\n url: string,\n auth: V1Auth,\n body?: unknown,\n signal?: AbortSignal,\n): Promise<T> {\n const headers: Record<string, string> = v1Headers(auth);\n const init: RequestInit = { method, headers, signal };\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n init.body = JSON.stringify(body);\n }\n const res = await fetch(url, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function postEmbed<T>(\n url: string,\n campKey: string,\n body: unknown,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = {\n \"X-Camp-Key\": campKey,\n \"Content-Type\": \"application/json\",\n };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: opts?.signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function putEmbed<T>(\n url: string,\n campKey: string,\n body: unknown,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = {\n \"X-Camp-Key\": campKey,\n \"Content-Type\": \"application/json\",\n };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), {\n method: \"PUT\",\n headers,\n body: JSON.stringify(body),\n signal: opts?.signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function deleteEmbed<T>(\n url: string,\n campKey: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = { \"X-Camp-Key\": campKey };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), { method: \"DELETE\", headers, signal: opts?.signal });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\n/**\n * Bearer-only helper for /api/embed/v1/admin/* (PLA-489). The admin token is\n * the sole credential (no X-Camp-Key — orgId comes from the JWT claims\n * server-side). `method` can be GET, POST, PATCH, or PUT; `body` is optional\n * (omitted for GET reads like getAnnotations).\n */\nasync function adminEmbed<T>(\n method: \"GET\" | \"POST\" | \"PATCH\" | \"PUT\",\n url: string,\n accessToken: string,\n body?: unknown,\n signal?: AbortSignal,\n): Promise<T> {\n const headers: Record<string, string> = { Authorization: `Bearer ${accessToken}` };\n const init: RequestInit = { method, headers, signal };\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n init.body = JSON.stringify(body);\n }\n const res = await fetch(url, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nexport class PlayaOSClient {\n private readonly baseUrl: string;\n private readonly embedBaseUrl: string;\n private readonly apiKey: string;\n private readonly memberToken: string | undefined;\n\n constructor(opts: ClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n this.embedBaseUrl = (opts.embedBaseUrl ?? opts.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = opts.apiKey;\n this.memberToken = opts.memberToken;\n }\n\n /** Credentials for /api/v1 calls; the embed surface uses `apiKey` alone as the camp key. */\n private get auth(): V1Auth {\n return { apiKey: this.apiKey, memberToken: this.memberToken };\n }\n\n /**\n * Derive a client that acts as one member (PLA-1195): same host and org key,\n * plus the member's Supabase session JWT on every /api/v1 call. Use this in a\n * server that holds one org key and serves many signed-in members.\n */\n withMember(memberToken: string): PlayaOSClient {\n return new PlayaOSClient({\n baseUrl: this.baseUrl,\n embedBaseUrl: this.embedBaseUrl,\n apiKey: this.apiKey,\n memberToken,\n });\n }\n\n /**\n * Admin dual-path (PLA-1203): when the client has a memberToken, call `/api/v1`\n * (org key + X-PlayaOS-Member-Token). Otherwise keep the legacy embed-admin\n * Bearer-JWT path so published consumers without withMember() still work.\n */\n private adminV1OrEmbed<T>(\n method: \"GET\" | \"POST\" | \"PATCH\" | \"PUT\",\n v1Path: string,\n embedPath: string,\n accessToken: string,\n body?: unknown,\n signal?: AbortSignal,\n ): Promise<T> {\n if (this.memberToken) {\n const url = buildUrl(this.baseUrl, v1Path);\n if (method === \"GET\") return request(url, this.auth, signal);\n if (method === \"POST\") return post(url, this.auth, body ?? {}, signal);\n return sendV1(method, url, this.auth, body, signal);\n }\n return adminEmbed(method, buildEmbedUrl(this.embedBaseUrl, embedPath), accessToken, body, signal);\n }\n\n /** Resolve admin credential: memberToken clients skip accessToken; embed path requires it. */\n private adminAccess(opts?: { accessToken?: string; signal?: AbortSignal }): {\n accessToken: string;\n signal?: AbortSignal;\n } {\n if (this.memberToken) {\n return { accessToken: opts?.accessToken ?? \"\", signal: opts?.signal };\n }\n if (!opts?.accessToken) {\n throw new Error(\"accessToken is required; call withMember(token) or pass { accessToken }\");\n }\n return { accessToken: opts.accessToken, signal: opts.signal };\n }\n\n readonly members = {\n list: (\n params?: { role?: MemberRole; status?: string } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Member>> => request(buildUrl(this.baseUrl, \"/members\", params), this.auth, opts?.signal),\n\n /**\n * Full profile (phone, emergency contact). Requires a member token; pass\n * `\"me\"` for the acting member — non-admins may fetch only themselves.\n */\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Member> =>\n request(buildUrl(this.baseUrl, `/members/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n /** Member-self profile update (PLA-700 / PLA-1203). Prefers v1 when memberToken is set. */\n selfUpdate: (\n payload: {\n bio?: string | null;\n playaName?: string | null;\n socialMedia?: Record<string, unknown> | null;\n showSocialsInDirectory?: boolean;\n phone?: string | null;\n emergencyContactName?: string | null;\n emergencyContactRelationship?: string | null;\n emergencyContactPhone?: string | null;\n profilePhotoPath?: string | null;\n yearJoined?: number | null;\n },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ profileId: string }> =>\n this.memberToken\n ? sendV1(\"PUT\", buildUrl(this.baseUrl, \"/members/me\"), this.auth, payload, opts.signal)\n : putEmbed(buildEmbedUrl(this.embedBaseUrl, \"/members/self\"), this.apiKey, payload, opts),\n\n /** Member-self shift signup + cancel (PLA-705 / PLA-1203). Prefers v1 when memberToken is set. */\n shifts: {\n signup: async (\n payload: { shiftId: string; role?: string },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ signupId: string; waitlisted: boolean }> => {\n if (this.memberToken) {\n const assigned = await post<{ id: string; shiftId: string; memberId: string; waitlisted?: boolean }>(\n buildUrl(this.baseUrl, `/shifts/${encodeURIComponent(payload.shiftId)}/assign`),\n this.auth,\n { role: payload.role },\n opts.signal,\n );\n return { signupId: assigned.id, waitlisted: assigned.waitlisted ?? false };\n }\n return postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/shifts/signup\"), this.apiKey, payload, opts);\n },\n cancel: (\n signupId: string,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ canceled: boolean; promotedSignupId: string | null }> =>\n this.memberToken\n ? sendV1(\n \"DELETE\",\n buildUrl(this.baseUrl, `/shifts/signups/${encodeURIComponent(signupId)}`),\n this.auth,\n undefined,\n opts.signal,\n )\n : deleteEmbed(\n buildEmbedUrl(this.embedBaseUrl, `/shifts/signups/${encodeURIComponent(signupId)}`),\n this.apiKey,\n opts,\n ),\n },\n };\n\n readonly applications = {\n list: (\n params?: { status?: ApplicationStatus; year?: number } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Application>> =>\n request(buildUrl(this.baseUrl, \"/applications\", params), this.auth, opts?.signal),\n\n // Anonymous external-camp submission against POST /api/embed/v1/applications\n // (PLA-481). Uses the X-Camp-Key header rather than Bearer auth. Pass\n // `accessToken` to additionally send a PlayaOS IdP JWT (PLA-573 path) so\n // the server trusts the verified profile claim and skips the email-based\n // bootstrap.\n create: (\n payload: ApplicationCreatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationCreateResponse> =>\n postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/applications\"), this.apiKey, payload, opts),\n };\n\n readonly waivers = {\n /** Get the active waiver for an org for the current year. */\n active: (orgId: string, opts?: { signal?: AbortSignal }): Promise<Waiver> =>\n getEmbed(buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/active`), this.apiKey, opts?.signal),\n\n /** Sign a waiver. Requires X-Camp-Key; optional accessToken for Bearer path. */\n sign: (\n payload: WaiverSignPayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<WaiverSignResponse> =>\n postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/waivers/sign\"), this.apiKey, payload, opts),\n\n /** Has this applicant/member signed the active waiver? Anchor: applicationId query or Bearer accessToken. */\n status: (\n orgId: string,\n opts?: { applicationId?: string; accessToken?: string; signal?: AbortSignal },\n ): Promise<WaiverStatus> => {\n const query = opts?.applicationId ? `?applicationId=${encodeURIComponent(opts.applicationId)}` : \"\";\n return getEmbedAuthed(buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/status${query}`), this.apiKey, opts);\n },\n\n /** Get a short-lived download URL for a completed signature's PDF. Anchor: applicationId query or Bearer. */\n signedPdf: (\n orgId: string,\n signatureId: string,\n opts?: { applicationId?: string; accessToken?: string; signal?: AbortSignal },\n ): Promise<{ url: string }> => {\n const query = opts?.applicationId ? `?applicationId=${encodeURIComponent(opts.applicationId)}` : \"\";\n return getEmbedAuthed(\n buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/signatures/${encodeURIComponent(signatureId)}/pdf${query}`),\n this.apiKey,\n opts,\n );\n },\n };\n\n readonly dues = {\n list: (\n params?: { userId?: string; year?: number; paymentStatus?: \"unpaid\" | \"partial\" | \"paid\" } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<DuesStatus>> => request(buildUrl(this.baseUrl, \"/dues\", params), this.auth, opts?.signal),\n };\n\n readonly shifts = {\n list: (\n params?: {\n year?: number;\n fromDate?: string;\n toDate?: string;\n publishedOnly?: boolean;\n openOnly?: boolean;\n } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Shift>> => request(buildUrl(this.baseUrl, \"/shifts\", params), this.auth, opts?.signal),\n };\n\n readonly org = {\n get: (opts?: { signal?: AbortSignal }): Promise<OrgConfig> =>\n request(buildUrl(this.baseUrl, \"/org\"), this.auth, opts?.signal),\n };\n\n // Public embed surface: active commitment definitions for the org's current\n // year, so the <ApplicationForm> can render + validate them (PLA-682). Uses\n // the X-Camp-Key (the apiKey doubles as the camp key), same as applications.create.\n readonly commitments = {\n list: (opts?: { signal?: AbortSignal }): Promise<CommitmentsListResponse> =>\n getEmbed(buildEmbedUrl(this.embedBaseUrl, \"/commitments\"), this.apiKey, opts?.signal),\n };\n\n readonly payments = {\n list: (\n params?: {\n type?: \"dues\" | \"payment\";\n memberId?: string;\n from?: string;\n to?: string;\n limit?: number;\n offset?: number;\n },\n opts?: { signal?: AbortSignal },\n ): Promise<PaymentLedgerRow[]> => request(buildUrl(this.baseUrl, \"/payments\", params), this.auth, opts?.signal),\n\n /** Requires a member token. `memberId` may be omitted by a non-admin (defaults to themselves); admins must pass it. */\n page: (\n memberId?: string,\n duesCollectionId?: string,\n opts?: { signal?: AbortSignal },\n ): Promise<PaymentPageResponse> =>\n post(buildUrl(this.baseUrl, \"/payments/page\"), this.auth, { memberId, duesCollectionId }, opts?.signal),\n };\n\n readonly accounts = {\n list: (params?: { limit?: number; offset?: number }, opts?: { signal?: AbortSignal }): Promise<Account[]> =>\n request(buildUrl(this.baseUrl, \"/accounts\", params), this.auth, opts?.signal),\n };\n\n readonly contacts = {\n list: (\n params?: {\n role?: MemberRole;\n status?: string;\n search?: string;\n sort?: \"name\" | \"email\";\n limit?: number;\n offset?: number;\n },\n opts?: { signal?: AbortSignal },\n ): Promise<Contact[]> => request(buildUrl(this.baseUrl, \"/contacts\", params), this.auth, opts?.signal),\n };\n\n readonly notifications = {\n list: (\n params?: { category?: string; status?: string; recipientId?: string; limit?: number },\n opts?: { signal?: AbortSignal },\n ): Promise<NotificationLog[]> => request(buildUrl(this.baseUrl, \"/notifications\", params), this.auth, opts?.signal),\n };\n\n readonly documents = {\n list: (params?: { type?: string; year?: number }, opts?: { signal?: AbortSignal }): Promise<CampDocument[]> =>\n request(buildUrl(this.baseUrl, \"/documents\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<CampDocument> =>\n request(buildUrl(this.baseUrl, `/documents/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n };\n\n readonly shelters = {\n list: (\n params?: { ownerId?: string; shelterType?: string; year?: number },\n opts?: { signal?: AbortSignal },\n ): Promise<Shelter[]> => request(buildUrl(this.baseUrl, \"/shelters\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Shelter> =>\n request(buildUrl(this.baseUrl, `/shelters/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n };\n\n readonly bikes = {\n list: (params?: { status?: string }, opts?: { signal?: AbortSignal }): Promise<Bike[]> =>\n request(buildUrl(this.baseUrl, \"/bikes\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Bike> =>\n request(buildUrl(this.baseUrl, `/bikes/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n /**\n * Cancel an in-house fleet rental owned by the acting member (PLA-1232).\n * Requires a member token. 404 when missing, not owned, or not cancellable.\n */\n cancelRental: (rentalId: string, opts?: { signal?: AbortSignal }): Promise<{ cancelled: true }> =>\n sendV1(\n \"DELETE\",\n buildUrl(this.baseUrl, `/members/bikes/${encodeURIComponent(rentalId)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n };\n\n /**\n * DustJunkie bike rentals (PLA-1180), passed through to the vendor. A camp\n * without the integration gets 403; a DustJunkie failure is a 502.\n */\n readonly bikeRentals = {\n /** Bookable options with estimated totals for `delivery` (server default `camp_delivery`). Org key only. */\n catalog: (\n params?: { delivery?: BikeRentalDeliveryMode },\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalCatalogResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/catalog\", params), this.auth, opts?.signal),\n\n /** The rental agreement the member must accept before `requestReservation`. Org key only. */\n waiver: (opts?: { signal?: AbortSignal }): Promise<BikeRentalWaiver> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/waiver\"), this.auth, opts?.signal),\n\n /**\n * Requires a member token. Admins get the whole camp when `memberId` is\n * omitted; any other role gets their own reservations and 403 naming someone else.\n */\n reservations: (\n params?: { memberId?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalReservationListResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/reservations\", params), this.auth, opts?.signal),\n\n /**\n * Requires a member token; always requests for the acting member. 409 when\n * the model is sold out, 400 when it is unknown or no longer bookable.\n */\n requestReservation: (\n payload: BikeRentalRequestInput,\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalRequestResult> =>\n post(buildUrl(this.baseUrl, \"/bike-rentals/requests\"), this.auth, payload, opts?.signal),\n\n /** Members who said they want a bike but have no reservation, for the active camp year. Org key only. */\n interestedNotReserved: (opts?: { signal?: AbortSignal }): Promise<BikeRentalInterestedNotReservedResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/interested-not-reserved\"), this.auth, opts?.signal),\n };\n\n readonly tags = {\n list: (opts?: { signal?: AbortSignal }): Promise<MemberTag[]> =>\n request(buildUrl(this.baseUrl, \"/tags\"), this.auth, opts?.signal),\n };\n\n readonly groups = {\n list: (opts?: { signal?: AbortSignal }): Promise<MemberGroup[]> =>\n request(buildUrl(this.baseUrl, \"/groups\"), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<MemberGroupRosterRow[]> =>\n request(buildUrl(this.baseUrl, `/groups/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n create: (\n payload: { name: string; leaderProfileId: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ id: string }> => post(buildUrl(this.baseUrl, \"/groups\"), this.auth, payload, opts?.signal),\n };\n\n /**\n * Camp-scoped packing (PLA-1197). Every method is the acting member's own\n * list — packing has no `memberId` to widen, so these require `memberToken`\n * and 401 on an org key alone.\n */\n readonly packing = {\n /** The resolved list: curated base + camp layer + personal layer (ADR-071). */\n list: (\n params?: { year?: number; shelter?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<PackingListResponse> => request(buildUrl(this.baseUrl, \"/packing\", params), this.auth, opts?.signal),\n\n /**\n * Set the member's status for one item. The slug goes in the body, not the\n * path: slugs are `${category}/${name}` and contain a `/`.\n *\n * Pass the same `shelter` the list was read under — validation filters by\n * shelter, so an override omitted here rejects shelter-specific items.\n */\n setStatus: (\n payload: { slug: string; status: PackingItemStatus; year?: number; shelter?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ ok: true }> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/packing/items/status\"), this.auth, payload, opts?.signal),\n\n personalItems: {\n list: (\n params?: { containerId?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ items: PackingPersonalItem[] }> =>\n request(buildUrl(this.baseUrl, \"/packing/personal-items\", params), this.auth, opts?.signal),\n\n create: (\n payload: { name: string; category: string; qty?: number; unit?: string | null; notes?: string | null },\n opts?: { signal?: AbortSignal },\n ): Promise<{ id: string }> =>\n post(buildUrl(this.baseUrl, \"/packing/personal-items\"), this.auth, payload, opts?.signal),\n\n /**\n * Flip the item between `need` and `have`. It does **not** set `packed` —\n * use `setStatus` for the full vocabulary. 404 if the item is not the\n * acting member's.\n */\n toggle: (id: string, opts?: { signal?: AbortSignal }): Promise<{ ok: true }> =>\n sendV1(\n \"PATCH\",\n buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n\n /** 404 if the item is not the acting member's. */\n remove: (id: string, opts?: { signal?: AbortSignal }): Promise<{ ok: true }> =>\n sendV1(\n \"DELETE\",\n buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n },\n\n /**\n * Camp packing layer (PLA-1204). Admin/super_admin only — non-admins get 403.\n * Identity is the published slug (`overrides_slug` or `camp:<uuid>`).\n */\n campItems: {\n list: (opts?: { signal?: AbortSignal }): Promise<{ items: PackingCampItem[] }> =>\n request(buildUrl(this.baseUrl, \"/packing/camp-items\"), this.auth, opts?.signal),\n\n upsert: (payload: UpsertPackingCampItemInput, opts?: { signal?: AbortSignal }): Promise<PackingCampItem> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/packing/camp-items\"), this.auth, payload, opts?.signal),\n },\n };\n\n /**\n * SAP — Special Access Pass, for early/overnight vehicle arrival (PLA-1202).\n * Admin/super_admin only; there is no member-facing SAP surface. Year is\n * always the org's active camp year — the server derives it, callers never\n * pass one.\n */\n readonly sap = {\n allocation: {\n get: (opts?: { signal?: AbortSignal }): Promise<SapAllocation> =>\n request(buildUrl(this.baseUrl, \"/sap/allocation\"), this.auth, opts?.signal),\n\n update: (payload: UpdateSapAllocationInput, opts?: { signal?: AbortSignal }): Promise<SapAllocation> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/sap/allocation\"), this.auth, payload, opts?.signal),\n },\n\n dayAllocations: {\n list: (opts?: { signal?: AbortSignal }): Promise<{ items: SapDayAllocation[] }> =>\n request(buildUrl(this.baseUrl, \"/sap/day-allocations\"), this.auth, opts?.signal),\n\n /** Upserts by (active year, accessDate); 409 on a cross-org date collision. */\n upsert: (payload: UpsertSapDayAllocationInput, opts?: { signal?: AbortSignal }): Promise<SapDayAllocation> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/sap/day-allocations\"), this.auth, payload, opts?.signal),\n },\n\n assignments: {\n list: (opts?: { signal?: AbortSignal }): Promise<{ items: SapAssignment[] }> =>\n request(buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, opts?.signal),\n\n create: (payload: CreateSapAssignmentInput, opts?: { signal?: AbortSignal }): Promise<SapAssignment> =>\n post(buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, payload, opts?.signal),\n\n update: (payload: UpdateSapAssignmentInput, opts?: { signal?: AbortSignal }): Promise<SapAssignment> =>\n sendV1(\"PATCH\", buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, payload, opts?.signal),\n\n remove: (assignmentId: string, opts?: { signal?: AbortSignal }): Promise<{ ok: true }> =>\n sendV1(\"DELETE\", buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, { assignmentId }, opts?.signal),\n },\n };\n\n // Admin write APIs (PLA-489). Each method requires `accessToken` — a Supabase\n // JWT for a camp admin/super_admin. The org boundary is enforced server-side\n // from the JWT claims; these endpoints do not use the X-Camp-Key.\n readonly admin = {\n applications: {\n /**\n * Get application audit timeline (PLA-712). Requires admin Bearer token.\n *\n * @deprecated The embed handler for this method never existed — calls\n * always 404'd (see PLA-1199). Retained as a compile-time compatibility\n * surface for published-consumer code; delegates to the canonical\n * `GET /api/v1/audit/application-logs?applicationId=` (ADR-054), which\n * reads the same `application_audit_logs` table. The `accessToken`\n * argument is accepted but unused — the v1 surface authenticates with\n * the org API key (`audit:read` scope) instead of an admin JWT. Remove\n * in the next major version.\n */\n history: async (\n id: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationHistoryResponse> => {\n type AuditRow = {\n id: string;\n applicationId: string;\n actorUserId: string | null;\n action: string;\n details: Record<string, unknown> | null;\n createdAt: string | null;\n };\n\n // The old embed shape returned the whole timeline in one object, so the\n // cursor has to be followed here — returning only the first 100 rows\n // would silently truncate long-running applications.\n const rows: AuditRow[] = [];\n let cursor: string | null = null;\n do {\n const page: Paginated<AuditRow> = await request<Paginated<AuditRow>>(\n buildUrl(this.baseUrl, \"/audit/application-logs\", {\n applicationId: id,\n limit: 100,\n ...(cursor ? { cursor } : {}),\n }),\n this.auth,\n opts?.signal,\n );\n rows.push(...page.data);\n cursor = page.nextCursor;\n } while (cursor);\n\n return {\n events: rows.map((row) => ({\n id: row.id,\n applicationId: row.applicationId,\n actorId: row.actorUserId,\n actorName: null,\n type: (row.action === \"status_changed\" ? \"status_change\" : row.action) as ApplicationEvent[\"type\"],\n timestamp: row.createdAt ?? \"\",\n metadata: row.details ?? undefined,\n })),\n };\n },\n transition: (\n id: string,\n payload: ApplicationTransitionPayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationTransitionResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/applications/${encodeURIComponent(id)}`,\n `/admin/applications/${encodeURIComponent(id)}`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n getAnnotations: (\n id: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationAnnotations> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/applications/${encodeURIComponent(id)}/annotations`,\n `/admin/applications/${encodeURIComponent(id)}/annotations`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n addNote: (\n id: string,\n payload: { body: string },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationNote> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/applications/${encodeURIComponent(id)}/notes`,\n `/admin/applications/${encodeURIComponent(id)}/notes`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n setTags: (\n id: string,\n payload: { tags: string[] },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<string[]> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/applications/${encodeURIComponent(id)}/tags`,\n `/admin/applications/${encodeURIComponent(id)}/tags`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n setScore: (\n id: string,\n payload: { value: number },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationScore> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/applications/${encodeURIComponent(id)}/scores`,\n `/admin/applications/${encodeURIComponent(id)}/scores`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n givebutter: {\n campaigns: {\n list: (opts?: { accessToken?: string; signal?: AbortSignal }): Promise<unknown[]> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n \"/givebutter/campaigns\",\n \"/admin/givebutter/campaigns\",\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n discountCodes: {\n list: (campaignId: number, opts?: { accessToken?: string; signal?: AbortSignal }): Promise<unknown[]> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/givebutter/campaigns/${campaignId}/discount-codes`,\n `/admin/givebutter/campaigns/${campaignId}/discount-codes`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n create: (\n campaignId: number,\n payload: { code: string; value: number; type: \"percent\" | \"fixed\"; expirationDate?: string },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<unknown> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/givebutter/campaigns/${campaignId}/discount-codes`,\n `/admin/givebutter/campaigns/${campaignId}/discount-codes`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n tickets: {\n create: (\n campaignId: number,\n payload: { name: string; price: number; totalQuantity?: number },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<unknown> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/givebutter/campaigns/${campaignId}/tickets`,\n `/admin/givebutter/campaigns/${campaignId}/tickets`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n },\n },\n members: {\n create: (\n payload: MemberCreatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<MemberCreateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\"POST\", \"/members\", \"/admin/members\", accessToken, payload, signal))(\n this.adminAccess(opts),\n ),\n\n update: (\n id: string,\n patch: MemberUpdatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<MemberUpdateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/members/${encodeURIComponent(id)}`,\n `/admin/members/${encodeURIComponent(id)}`,\n accessToken,\n patch,\n signal,\n ))(this.adminAccess(opts)),\n\n deactivate: (\n id: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<MemberDeactivateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/members/${encodeURIComponent(id)}`,\n `/admin/members/${encodeURIComponent(id)}`,\n accessToken,\n { status: \"inactive\" },\n signal,\n ))(this.adminAccess(opts)),\n },\n announcements: {\n /** Send an email blast to camp members (PLA-706). Requires admin Bearer token. */\n send: (\n payload: AnnouncementSendPayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<AnnouncementSendResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n \"/announcements/send\",\n \"/admin/announcements/send\",\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n dues: {\n /** Create a manual dues/payment record (PLA-708). Requires admin Bearer token. */\n create: (\n payload: DuesCreatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<DuesCreateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\"POST\", \"/dues\", \"/admin/dues\", accessToken, payload, signal))(this.adminAccess(opts)),\n\n /** Update a dues/payment record (PLA-708). Requires admin Bearer token. */\n update: (\n id: string,\n payload: DuesUpdatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<DuesUpdateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/dues/${encodeURIComponent(id)}`,\n `/admin/dues/${encodeURIComponent(id)}`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n org: {\n /** Update camp configuration settings (PLA-709). Requires admin Bearer token. */\n update: (\n payload: OrgUpdatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<OrgUpdateResponse> =>\n (({ accessToken, signal }) => this.adminV1OrEmbed(\"PATCH\", \"/org\", \"/admin/org\", accessToken, payload, signal))(\n this.adminAccess(opts),\n ),\n },\n scheduling: {\n availability: {\n /** Get interview availability for an interviewer (PLA-713). Requires admin Bearer token. */\n get: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<GetAvailabilityResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n /** Set interview availability for an interviewer (PLA-713). Requires admin Bearer token. */\n set: (\n interviewerId: string,\n payload: SetAvailabilityInput,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<SetAvailabilityResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n calendar: {\n /** Get Google Calendar connection status for an interviewer (PLA-726). Requires admin Bearer. */\n status: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<CalendarStatus> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/status`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/status`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n /** List available Google Calendars (PLA-726). Requires admin Bearer. */\n listCalendars: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<{ calendars: GoogleCalendar[] }> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/calendars`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/calendars`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n /** Select which Google Calendar to use (PLA-726). Requires admin Bearer. */\n select: (\n interviewerId: string,\n payload: SelectCalendarInput,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<{ calendarId: string }> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/select`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/select`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n /** Disconnect Google Calendar from interviewer (PLA-726). Requires admin Bearer. */\n disconnect: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<{ disconnected: boolean }> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/disconnect`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/disconnect`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n },\n bookingTokens: {\n /** Create a booking token for an application's interview link (PLA-714). Requires admin Bearer token. */\n create: (\n payload: CreateBookingTokenInput,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<BookingToken> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\"POST\", \"/booking-tokens\", \"/admin/booking-tokens\", accessToken, payload, signal))(\n this.adminAccess(opts),\n ),\n /** Get an existing booking token for an application (PLA-714). Requires admin Bearer token. */\n get: (applicationId: string, opts?: { accessToken?: string; signal?: AbortSignal }): Promise<BookingToken> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/booking-tokens/${encodeURIComponent(applicationId)}`,\n `/admin/booking-tokens/${encodeURIComponent(applicationId)}`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n },\n },\n };\n\n // Public embed-booking endpoints (PLA-714). No auth — these are the\n // applicant-facing schedule surface using the hashed booking token.\n readonly schedule = {\n /** List available interview slots for a booking token (PLA-714). Public. */\n getSlots: (\n token: string,\n opts?: { signal?: AbortSignal },\n ): Promise<{ slots: { startsAt: string; endsAt: string }[] }> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}`;\n return fetch(url, { signal: opts?.signal }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<{ slots: { startsAt: string; endsAt: string }[] }>;\n });\n },\n /** Book an interview slot (PLA-714). Public. */\n book: (token: string, payload: BookSlotInput, opts?: { signal?: AbortSignal }): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/book`;\n return fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: opts?.signal,\n }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n /** Cancel an interview booking (PLA-714). Public. */\n cancel: (token: string, opts?: { signal?: AbortSignal }): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/cancel`;\n return fetch(url, { method: \"POST\", signal: opts?.signal }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n /** Reschedule an interview booking (PLA-714). Public. */\n reschedule: (\n token: string,\n payload: RescheduleInput,\n opts?: { signal?: AbortSignal },\n ): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/reschedule`;\n return fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: opts?.signal,\n }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n };\n}\n\n/** Convenience factory — equivalent to `new PlayaOSClient(opts)`. */\nexport function createClient(opts: ClientOptions): PlayaOSClient {\n return new PlayaOSClient(opts);\n}\n","/**\n * Server-side OAuth-code → ID-token exchange.\n *\n * Swaps a one-time authorization code from the PlayaOS IdP for a short-lived\n * ID token. Confidential clients pass `clientSecret`, which is sent to the\n * token endpoint server-side. Public/PKCE-only clients omit it — the\n * authorization-code + code_verifier pair is the sole credential. Public\n * clients can also exchange directly from the browser via `usePlayaOSAuth`\n * in `@playaos/react`.\n */\n\nexport interface ExchangeParams {\n authBaseUrl?: string;\n code: string;\n codeVerifier: string;\n clientId: string;\n /** Confidential clients only. Omit for public/PKCE-only clients. */\n clientSecret?: string;\n redirectUri: string;\n}\n\nexport interface ExchangeResult {\n idToken: string;\n expiresAt: string;\n /** Confidential clients only. Undefined for public clients. */\n refreshToken?: string;\n}\n\nexport async function exchangeCode(params: ExchangeParams): Promise<ExchangeResult> {\n const base = params.authBaseUrl ?? \"https://auth.playaos.app\";\n // A confidential client is identified by passing clientSecret at all — even an\n // empty string. We forward it as-is so the server validates it (an empty or\n // wrong secret is rejected there); public clients omit the field entirely.\n const isConfidential = params.clientSecret !== undefined;\n const res = await fetch(`${base}/api/auth/v1/exchange`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n code: params.code,\n code_verifier: params.codeVerifier,\n client_id: params.clientId,\n ...(isConfidential ? { client_secret: params.clientSecret } : {}),\n redirect_uri: params.redirectUri,\n }),\n });\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n throw new Error(`Exchange failed: non-JSON response (${res.status})`);\n }\n\n if (!res.ok) {\n const errorReason =\n typeof body === \"object\" && body !== null && \"error\" in body && typeof body.error === \"string\"\n ? body.error\n : String(res.status);\n throw new Error(`Exchange failed: ${errorReason}`);\n }\n\n if (\n typeof body !== \"object\" ||\n body === null ||\n !(\"idToken\" in body) ||\n typeof body.idToken !== \"string\" ||\n !(\"expiresAt\" in body) ||\n typeof body.expiresAt !== \"string\"\n ) {\n throw new Error(\"Exchange failed: malformed success response\");\n }\n\n // The server mints a refresh token only for confidential clients (it sets\n // `withRefreshToken: client.type === \"confidential\"`); public clients get\n // none. Surface it when present, otherwise leave it undefined.\n const refreshToken = \"refreshToken\" in body && typeof body.refreshToken === \"string\" ? body.refreshToken : undefined;\n\n // A confidential client that gets no refresh token means the server response\n // is malformed or the rotation flow is broken — surface it rather than\n // silently returning a result the caller can't refresh.\n if (isConfidential && refreshToken === undefined) {\n throw new Error(\"Exchange failed: confidential client response missing refreshToken\");\n }\n\n return {\n idToken: body.idToken,\n expiresAt: body.expiresAt,\n ...(refreshToken !== undefined ? { refreshToken } : {}),\n };\n}\n","import { parseError } from \"./error.js\";\n\n/** A listing holds at most this many images (matches the DB's position 1–6 check). */\nexport const MAX_IMAGE_POSITION = 6;\n\n/**\n * Typed client for the anonymous gift-layer marketplace API (`/api/public/marketplace/*`).\n *\n * Unlike `PlayaOSClient` (api-key auth for `/api/v1`), this surface authenticates\n * writes with a Supabase **Bearer JWT** belonging to a public `global_accounts`\n * user. The token is supplied by an injected `getToken` provider so the same\n * client works from any consumer (the marketing UI supplies the browser\n * Supabase session token; a future surface could supply its own). Keeps the\n * public API as the single write contract — the UI is just another consumer.\n */\nexport interface PublicMarketplaceClientOptions {\n /** API base, e.g. `https://api.playaos.app`. */\n baseUrl: string;\n /** Supplies the Supabase access token (Bearer) for authenticated calls; null/undefined when signed out. */\n getToken: () => Promise<string | null | undefined> | string | null | undefined;\n}\n\nexport interface NewListingInput {\n category: string;\n subcategory?: string;\n title: string;\n body: string;\n price?: number;\n location?: string;\n replyEmail: string;\n}\n\nexport interface ImageUploadTarget {\n /** Supabase signed upload URL — PUT the file bytes here. */\n uploadUrl: string;\n /** Storage path to pass back to `attachImage` once the PUT succeeds. */\n storagePath: string;\n}\n\n/** Moderation flag reasons accepted by the API (mirrors the DB enum). */\nexport type MarketplaceFlagReason = \"spam\" | \"prohibited\" | \"other\";\n\nexport interface ListingImage {\n /** Short-lived signed download URL for the image. */\n url: string;\n /** 1-based display order. */\n position: number;\n}\n\nexport interface PublicMarketplaceClient {\n /**\n * Create a listing as the signed-in account. Throws a plain `Error` when there\n * is no token (signed out), or `ApiClientError` on a non-2xx response.\n */\n createListing(input: NewListingInput, signal?: AbortSignal): Promise<{ id: string }>;\n /** Request a signed upload URL for an image on a listing the caller owns. */\n getImageUploadUrl(listingId: string, signal?: AbortSignal): Promise<ImageUploadTarget>;\n /** Attach an already-uploaded image (by storage path) to a listing at a 1–6 position. */\n attachImage(\n listingId: string,\n input: { storagePath: string; position: number },\n signal?: AbortSignal,\n ): Promise<{ id: string }>;\n /** Anonymous: list an active listing's images as short-lived signed URLs (for public display). */\n listListingImages(listingId: string, signal?: AbortSignal): Promise<{ images: ListingImage[] }>;\n /** Anonymous: batch-fetch first-image signed thumbnail URLs (listingId -> url) for browse cards. */\n listThumbnails(listingIds: string[], signal?: AbortSignal): Promise<{ thumbnails: Record<string, string> }>;\n /** Flag a listing for moderation (signed-in). Idempotent per (listing, user). */\n flagListing(listingId: string, reason: MarketplaceFlagReason, signal?: AbortSignal): Promise<{ ok: boolean }>;\n /** Contact a listing's owner (signed-in); records the reply + queues a notification email. */\n replyToListing(listingId: string, message: string | undefined, signal?: AbortSignal): Promise<{ ok: boolean }>;\n}\n\nexport function createPublicMarketplaceClient(opts: PublicMarketplaceClientOptions): PublicMarketplaceClient {\n const base = opts.baseUrl.replace(/\\/+$/, \"\");\n if (!base) {\n // An empty base would issue relative requests to the caller's own origin.\n throw new Error(\"createPublicMarketplaceClient: baseUrl is required\");\n }\n\n async function authedPost<T>(path: string, body: unknown, signal?: AbortSignal): Promise<T> {\n const token = await opts.getToken();\n if (!token) throw new Error(\"Not signed in\");\n const res = await fetch(`${base}/api/public/marketplace${path}`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}`, \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n }\n\n async function publicGet<T>(path: string, signal?: AbortSignal): Promise<T> {\n // no-store: responses carry short-lived signed URLs — never let the framework\n // (e.g. Next's fetch cache) memoize them and serve expired URLs. `cache` is a\n // valid fetch option at runtime but absent from @types/node's RequestInit,\n // so the init is typed with an intersection.\n const init: RequestInit & { cache: \"no-store\" } = { signal, cache: \"no-store\" };\n const res = await fetch(`${base}/api/public/marketplace${path}`, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n }\n\n const seg = (listingId: string) => `/listings/${encodeURIComponent(listingId)}`;\n\n return {\n createListing: (input, signal) => authedPost(\"/listings\", input, signal),\n getImageUploadUrl: (listingId, signal) => authedPost(`${seg(listingId)}/image-upload-url`, {}, signal),\n attachImage: (listingId, input, signal) => {\n // Fail fast on a misuse the API would otherwise reject with a vague 400.\n if (!Number.isInteger(input.position) || input.position < 1 || input.position > MAX_IMAGE_POSITION) {\n return Promise.reject(new Error(`attachImage: position must be 1–${MAX_IMAGE_POSITION}`));\n }\n return authedPost(`${seg(listingId)}/images`, input, signal);\n },\n listListingImages: (listingId, signal) => publicGet(`${seg(listingId)}/images`, signal),\n listThumbnails: (listingIds, signal) =>\n publicGet(`/thumbnails?ids=${encodeURIComponent(listingIds.join(\",\"))}`, signal),\n flagListing: (listingId, reason, signal) => authedPost(`${seg(listingId)}/flag`, { reason }, signal),\n replyToListing: (listingId, message, signal) => authedPost(`${seg(listingId)}/reply`, { message }, signal),\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playaos/api-client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Typed API client for PlayaOS
|
|
3
|
+
"version": "0.15.0",
|
|
4
|
+
"description": "Typed API client for PlayaOS — manage camp members, dues, shifts, applications, waivers, and annotations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -15,17 +15,19 @@
|
|
|
15
15
|
"import": "./dist/applications-schema.js"
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
|
-
"files": [
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"playaos",
|
|
24
|
+
"burning-man",
|
|
25
|
+
"camp-management",
|
|
26
|
+
"api-client"
|
|
27
|
+
],
|
|
26
28
|
"license": "MIT",
|
|
27
29
|
"peerDependencies": {
|
|
28
|
-
"zod": "^4.
|
|
30
|
+
"zod": "^4.6.5"
|
|
29
31
|
},
|
|
30
32
|
"peerDependenciesMeta": {
|
|
31
33
|
"zod": {
|
|
@@ -36,6 +38,12 @@
|
|
|
36
38
|
"tsdown": "^0.22.14",
|
|
37
39
|
"typescript": "^7.0.2",
|
|
38
40
|
"vitest": "^4.1.10",
|
|
39
|
-
"zod": "^4.
|
|
41
|
+
"zod": "^4.6.5"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsdown",
|
|
45
|
+
"dev": "tsdown --watch",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"test": "vitest run"
|
|
40
48
|
}
|
|
41
|
-
}
|
|
49
|
+
}
|