@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 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
- Required scopes per endpoint:
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). Requires camp key + member Bearer token. */
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). Requires camp key + member Bearer. */
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: string;
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: string;
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: string;
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: string;
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: string;
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: string;
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: string;
1160
+ list: (opts?: {
1161
+ accessToken?: string;
1007
1162
  signal?: AbortSignal;
1008
1163
  }) => Promise<unknown[]>;
1009
1164
  discountCodes: {
1010
- list: (campaignId: number, opts: {
1011
- accessToken: string;
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: string;
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: string;
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: string;
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: string;
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: string;
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: string;
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: string;
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: string;
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: string;
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: string;
1234
+ get: (interviewerId: string, opts?: {
1235
+ accessToken?: string;
1081
1236
  signal?: AbortSignal;
1082
- }) => Promise<SetAvailabilityResponse>;
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: string;
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: string;
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: string;
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: string;
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: string;
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: string;
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: string;
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). Requires camp key + member Bearer token. */
210
- selfUpdate: (payload, opts) => putEmbed(buildEmbedUrl(this.embedBaseUrl, "/members/self"), this.apiKey, payload, opts),
211
- /** Member-self shift signup + cancel (PLA-705). Requires camp key + member Bearer. */
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) => postEmbed(buildEmbedUrl(this.embedBaseUrl, "/shifts/signup"), this.apiKey, payload, opts),
214
- cancel: (signupId, opts) => deleteEmbed(buildEmbedUrl(this.embedBaseUrl, `/shifts/signups/${encodeURIComponent(signupId)}`), this.apiKey, opts)
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) => adminEmbed("PATCH", buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}`), opts.accessToken, payload, opts.signal),
358
- getAnnotations: (id, opts) => adminEmbed("GET", buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/annotations`), opts.accessToken, void 0, opts.signal),
359
- addNote: (id, payload, opts) => adminEmbed("POST", buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/notes`), opts.accessToken, payload, opts.signal),
360
- setTags: (id, payload, opts) => adminEmbed("PUT", buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/tags`), opts.accessToken, payload, opts.signal),
361
- setScore: (id, payload, opts) => adminEmbed("PUT", buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/scores`), opts.accessToken, payload, opts.signal)
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) => adminEmbed("GET", buildEmbedUrl(this.embedBaseUrl, "/admin/givebutter/campaigns"), opts.accessToken, void 0, opts.signal),
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) => adminEmbed("GET", buildEmbedUrl(this.embedBaseUrl, `/admin/givebutter/campaigns/${campaignId}/discount-codes`), opts.accessToken, void 0, opts.signal),
367
- create: (campaignId, payload, opts) => adminEmbed("POST", buildEmbedUrl(this.embedBaseUrl, `/admin/givebutter/campaigns/${campaignId}/discount-codes`), opts.accessToken, payload, opts.signal)
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) => adminEmbed("POST", buildEmbedUrl(this.embedBaseUrl, `/admin/givebutter/campaigns/${campaignId}/tickets`), opts.accessToken, payload, opts.signal) }
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) => adminEmbed("POST", buildEmbedUrl(this.embedBaseUrl, "/admin/members"), opts.accessToken, payload, opts.signal),
373
- update: (id, patch, opts) => adminEmbed("PATCH", buildEmbedUrl(this.embedBaseUrl, `/admin/members/${encodeURIComponent(id)}`), opts.accessToken, patch, opts.signal),
374
- deactivate: (id, opts) => adminEmbed("PATCH", buildEmbedUrl(this.embedBaseUrl, `/admin/members/${encodeURIComponent(id)}`), opts.accessToken, { status: "inactive" }, opts.signal)
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) => adminEmbed("POST", buildEmbedUrl(this.embedBaseUrl, "/admin/announcements/send"), opts.accessToken, payload, opts.signal) },
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) => adminEmbed("POST", buildEmbedUrl(this.embedBaseUrl, "/admin/dues"), opts.accessToken, payload, opts.signal),
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) => adminEmbed("PATCH", buildEmbedUrl(this.embedBaseUrl, `/admin/dues/${encodeURIComponent(id)}`), opts.accessToken, payload, opts.signal)
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) => adminEmbed("PATCH", buildEmbedUrl(this.embedBaseUrl, "/admin/org"), opts.accessToken, payload, opts.signal) },
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) => adminEmbed("GET", buildEmbedUrl(this.embedBaseUrl, `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`), opts.accessToken, void 0, opts.signal),
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) => adminEmbed("PUT", buildEmbedUrl(this.embedBaseUrl, `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`), opts.accessToken, payload, opts.signal)
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) => adminEmbed("GET", buildEmbedUrl(this.embedBaseUrl, `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/status`), opts.accessToken, void 0, opts.signal),
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) => adminEmbed("GET", buildEmbedUrl(this.embedBaseUrl, `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/calendars`), opts.accessToken, void 0, opts.signal),
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) => adminEmbed("PUT", buildEmbedUrl(this.embedBaseUrl, `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/select`), opts.accessToken, payload, opts.signal),
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) => adminEmbed("POST", buildEmbedUrl(this.embedBaseUrl, `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/disconnect`), opts.accessToken, void 0, opts.signal)
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) => adminEmbed("POST", buildEmbedUrl(this.embedBaseUrl, "/admin/booking-tokens"), opts.accessToken, payload, opts.signal),
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) => adminEmbed("GET", buildEmbedUrl(this.embedBaseUrl, `/admin/booking-tokens/${encodeURIComponent(applicationId)}`), opts.accessToken, void 0, opts.signal)
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.14.0",
4
- "description": "Typed API client for PlayaOS \u2014 manage camp members, dues, shifts, applications, waivers, and annotations",
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": ["dist", "README.md"],
19
- "scripts": {
20
- "build": "tsdown",
21
- "dev": "tsdown --watch",
22
- "typecheck": "tsc --noEmit",
23
- "test": "vitest run"
24
- },
25
- "keywords": ["playaos", "burning-man", "camp-management", "api-client"],
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.4.3"
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.4.3"
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
+ }