@playaos/api-client 0.14.0 → 0.16.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;
@@ -73,6 +75,21 @@ interface Application {
73
75
  shelterType?: string | null;
74
76
  burningManBefore?: boolean | null;
75
77
  customFields?: Record<string, unknown> | null;
78
+ draftStep?: number | null;
79
+ burningManExperience?: string | null;
80
+ shelterMates?: string | null;
81
+ ticketStatus?: string | null;
82
+ buildAvailable?: boolean | null;
83
+ buildArrival?: string | null;
84
+ buildSkills?: string | null;
85
+ strikeAvailable?: boolean | null;
86
+ strikeDeparture?: string | null;
87
+ strikeHelp?: string | null;
88
+ agreesToPrinciples?: boolean | null;
89
+ interviewScheduledAt?: string | null;
90
+ interviewedAt?: string | null;
91
+ decision?: string | null;
92
+ rejectionReason?: string | null;
76
93
  }
77
94
  interface DuesStatus {
78
95
  userId: string | null;
@@ -185,8 +202,21 @@ interface Shelter {
185
202
  id: string;
186
203
  name: string | null;
187
204
  shelterType: string;
205
+ ownerUserId: string | null;
188
206
  year: number;
207
+ maxOccupants: number | null;
208
+ rvLengthFt: number | null;
209
+ rvAmperage: number | null;
210
+ shelterLengthFt: string | null;
211
+ shelterWidthFt: string | null;
212
+ shelterHeightFt: string | null;
213
+ needsPower: boolean | null;
214
+ needsPumping: boolean | null;
215
+ shelterDescription: string | null;
216
+ mapX: number | null;
217
+ mapY: number | null;
189
218
  orgId: string;
219
+ createdAt: string | null;
190
220
  }
191
221
  interface Bike {
192
222
  id: string;
@@ -417,6 +447,11 @@ interface AvailabilityWindow {
417
447
  interface SetAvailabilityInput {
418
448
  windows: AvailabilityWindow[];
419
449
  }
450
+ /** Response from GET /scheduling/availability/{id}. */
451
+ interface GetAvailabilityResponse {
452
+ windows: AvailabilityWindow[];
453
+ }
454
+ /** Response from PUT /scheduling/availability/{id}. */
420
455
  interface SetAvailabilityResponse {
421
456
  windows: {
422
457
  count: number;
@@ -511,6 +546,76 @@ interface PackingPersonalItem {
511
546
  containerId: string | null;
512
547
  notes: string | null;
513
548
  }
549
+ /**
550
+ * Camp packing-layer row (PLA-1204). Published identity is `slug`
551
+ * (`overrides_slug`, or `camp:<uuid>` when standalone) — not the row uuid alone.
552
+ */
553
+ interface PackingCampItem {
554
+ slug: string;
555
+ id: string;
556
+ categoryId: string;
557
+ categoryName: string;
558
+ name: string;
559
+ notes: string | null;
560
+ sortOrder: number;
561
+ overridesSlug: string | null;
562
+ }
563
+ interface UpsertPackingCampItemInput {
564
+ slug: string;
565
+ name: string;
566
+ category: string;
567
+ notes?: string | null;
568
+ sortOrder?: number;
569
+ }
570
+ /** Active-year allocation summary. Year is always the org's active camp year. */
571
+ interface SapAllocation {
572
+ year: number;
573
+ totalAllocated: number;
574
+ notes: string | null;
575
+ totalAssigned: number;
576
+ }
577
+ interface UpdateSapAllocationInput {
578
+ totalAllocated: number;
579
+ notes?: string | null;
580
+ }
581
+ interface SapDayAllocation {
582
+ id: string;
583
+ year: number;
584
+ accessDate: string;
585
+ slotsAvailable: number;
586
+ notes: string | null;
587
+ }
588
+ interface UpsertSapDayAllocationInput {
589
+ accessDate: string;
590
+ slotsAvailable: number;
591
+ notes?: string | null;
592
+ }
593
+ interface SapAssignment {
594
+ id: string;
595
+ userId: string;
596
+ year: number;
597
+ sapNumber: string | null;
598
+ vehicleDescription: string | null;
599
+ licensePlate: string | null;
600
+ arrivalDate: string | null;
601
+ notes: string | null;
602
+ }
603
+ interface CreateSapAssignmentInput {
604
+ userId: string;
605
+ sapNumber?: string | null;
606
+ vehicleDescription?: string | null;
607
+ licensePlate?: string | null;
608
+ arrivalDate?: string | null;
609
+ notes?: string | null;
610
+ }
611
+ interface UpdateSapAssignmentInput {
612
+ assignmentId: string;
613
+ sapNumber?: string | null;
614
+ vehicleDescription?: string | null;
615
+ licensePlate?: string | null;
616
+ arrivalDate?: string | null;
617
+ notes?: string | null;
618
+ }
514
619
  /** How the rental reaches the member. The server defaults to `camp_delivery`. */
515
620
  type BikeRentalDeliveryMode = "individual_pickup" | "camp_delivery";
516
621
  type BikeRentalFramePreference = "standard" | "step-through";
@@ -564,6 +669,8 @@ interface BikeRentalRequestResult {
564
669
  /** DustJunkie's id for the pending request. */
565
670
  requestId: string | null;
566
671
  status: string | null;
672
+ /** True when this matched an earlier request within the short dedupe window (ADR-091). */
673
+ duplicate?: boolean;
567
674
  }
568
675
  interface BikeRentalReservation {
569
676
  id: string;
@@ -632,6 +739,14 @@ declare class PlayaOSClient {
632
739
  * server that holds one org key and serves many signed-in members.
633
740
  */
634
741
  withMember(memberToken: string): PlayaOSClient;
742
+ /**
743
+ * Admin dual-path (PLA-1203): when the client has a memberToken, call `/api/v1`
744
+ * (org key + X-PlayaOS-Member-Token). Otherwise keep the legacy embed-admin
745
+ * Bearer-JWT path so published consumers without withMember() still work.
746
+ */
747
+ private adminV1OrEmbed;
748
+ /** Resolve admin credential: memberToken clients skip accessToken; embed path requires it. */
749
+ private adminAccess;
635
750
  readonly members: {
636
751
  list: (params?: {
637
752
  role?: MemberRole;
@@ -646,7 +761,7 @@ declare class PlayaOSClient {
646
761
  get: (id: string, opts?: {
647
762
  signal?: AbortSignal;
648
763
  }) => Promise<Member>;
649
- /** Member-self profile update (PLA-700). Requires camp key + member Bearer token. */
764
+ /** Member-self profile update (PLA-700 / PLA-1203). Prefers v1 when memberToken is set. */
650
765
  selfUpdate: (payload: {
651
766
  bio?: string | null;
652
767
  playaName?: string | null;
@@ -664,7 +779,7 @@ declare class PlayaOSClient {
664
779
  }) => Promise<{
665
780
  profileId: string;
666
781
  }>;
667
- /** Member-self shift signup + cancel (PLA-705). Requires camp key + member Bearer. */
782
+ /** Member-self shift signup + cancel (PLA-705 / PLA-1203). Prefers v1 when memberToken is set. */
668
783
  shifts: {
669
784
  signup: (payload: {
670
785
  shiftId: string;
@@ -830,6 +945,15 @@ declare class PlayaOSClient {
830
945
  get: (id: string, opts?: {
831
946
  signal?: AbortSignal;
832
947
  }) => Promise<Bike>;
948
+ /**
949
+ * Cancel an in-house fleet rental owned by the acting member (PLA-1232).
950
+ * Requires a member token. 404 when missing, not owned, or not cancellable.
951
+ */
952
+ cancelRental: (rentalId: string, opts?: {
953
+ signal?: AbortSignal;
954
+ }) => Promise<{
955
+ cancelled: true;
956
+ }>;
833
957
  };
834
958
  /**
835
959
  * DustJunkie bike rentals (PLA-1180), passed through to the vendor. A camp
@@ -954,6 +1078,65 @@ declare class PlayaOSClient {
954
1078
  ok: true;
955
1079
  }>;
956
1080
  };
1081
+ /**
1082
+ * Camp packing layer (PLA-1204). Admin/super_admin only — non-admins get 403.
1083
+ * Identity is the published slug (`overrides_slug` or `camp:<uuid>`).
1084
+ */
1085
+ campItems: {
1086
+ list: (opts?: {
1087
+ signal?: AbortSignal;
1088
+ }) => Promise<{
1089
+ items: PackingCampItem[];
1090
+ }>;
1091
+ upsert: (payload: UpsertPackingCampItemInput, opts?: {
1092
+ signal?: AbortSignal;
1093
+ }) => Promise<PackingCampItem>;
1094
+ };
1095
+ };
1096
+ /**
1097
+ * SAP — Special Access Pass, for early/overnight vehicle arrival (PLA-1202).
1098
+ * Admin/super_admin only; there is no member-facing SAP surface. Year is
1099
+ * always the org's active camp year — the server derives it, callers never
1100
+ * pass one.
1101
+ */
1102
+ readonly sap: {
1103
+ allocation: {
1104
+ get: (opts?: {
1105
+ signal?: AbortSignal;
1106
+ }) => Promise<SapAllocation>;
1107
+ update: (payload: UpdateSapAllocationInput, opts?: {
1108
+ signal?: AbortSignal;
1109
+ }) => Promise<SapAllocation>;
1110
+ };
1111
+ dayAllocations: {
1112
+ list: (opts?: {
1113
+ signal?: AbortSignal;
1114
+ }) => Promise<{
1115
+ items: SapDayAllocation[];
1116
+ }>;
1117
+ /** Upserts by (active year, accessDate); 409 on a cross-org date collision. */
1118
+ upsert: (payload: UpsertSapDayAllocationInput, opts?: {
1119
+ signal?: AbortSignal;
1120
+ }) => Promise<SapDayAllocation>;
1121
+ };
1122
+ assignments: {
1123
+ list: (opts?: {
1124
+ signal?: AbortSignal;
1125
+ }) => Promise<{
1126
+ items: SapAssignment[];
1127
+ }>;
1128
+ create: (payload: CreateSapAssignmentInput, opts?: {
1129
+ signal?: AbortSignal;
1130
+ }) => Promise<SapAssignment>;
1131
+ update: (payload: UpdateSapAssignmentInput, opts?: {
1132
+ signal?: AbortSignal;
1133
+ }) => Promise<SapAssignment>;
1134
+ remove: (assignmentId: string, opts?: {
1135
+ signal?: AbortSignal;
1136
+ }) => Promise<{
1137
+ ok: true;
1138
+ }>;
1139
+ };
957
1140
  };
958
1141
  readonly admin: {
959
1142
  applications: {
@@ -969,46 +1152,46 @@ declare class PlayaOSClient {
969
1152
  * the org API key (`audit:read` scope) instead of an admin JWT. Remove
970
1153
  * in the next major version.
971
1154
  */
972
- history: (id: string, opts: {
973
- accessToken: string;
1155
+ history: (id: string, opts?: {
1156
+ accessToken?: string;
974
1157
  signal?: AbortSignal;
975
1158
  }) => Promise<ApplicationHistoryResponse>;
976
- transition: (id: string, payload: ApplicationTransitionPayload, opts: {
977
- accessToken: string;
1159
+ transition: (id: string, payload: ApplicationTransitionPayload, opts?: {
1160
+ accessToken?: string;
978
1161
  signal?: AbortSignal;
979
1162
  }) => Promise<ApplicationTransitionResponse>;
980
- getAnnotations: (id: string, opts: {
981
- accessToken: string;
1163
+ getAnnotations: (id: string, opts?: {
1164
+ accessToken?: string;
982
1165
  signal?: AbortSignal;
983
1166
  }) => Promise<ApplicationAnnotations>;
984
1167
  addNote: (id: string, payload: {
985
1168
  body: string;
986
- }, opts: {
987
- accessToken: string;
1169
+ }, opts?: {
1170
+ accessToken?: string;
988
1171
  signal?: AbortSignal;
989
1172
  }) => Promise<ApplicationNote>;
990
1173
  setTags: (id: string, payload: {
991
1174
  tags: string[];
992
- }, opts: {
993
- accessToken: string;
1175
+ }, opts?: {
1176
+ accessToken?: string;
994
1177
  signal?: AbortSignal;
995
1178
  }) => Promise<string[]>;
996
1179
  setScore: (id: string, payload: {
997
1180
  value: number;
998
- }, opts: {
999
- accessToken: string;
1181
+ }, opts?: {
1182
+ accessToken?: string;
1000
1183
  signal?: AbortSignal;
1001
1184
  }) => Promise<ApplicationScore>;
1002
1185
  };
1003
1186
  givebutter: {
1004
1187
  campaigns: {
1005
- list: (opts: {
1006
- accessToken: string;
1188
+ list: (opts?: {
1189
+ accessToken?: string;
1007
1190
  signal?: AbortSignal;
1008
1191
  }) => Promise<unknown[]>;
1009
1192
  discountCodes: {
1010
- list: (campaignId: number, opts: {
1011
- accessToken: string;
1193
+ list: (campaignId: number, opts?: {
1194
+ accessToken?: string;
1012
1195
  signal?: AbortSignal;
1013
1196
  }) => Promise<unknown[]>;
1014
1197
  create: (campaignId: number, payload: {
@@ -1016,8 +1199,8 @@ declare class PlayaOSClient {
1016
1199
  value: number;
1017
1200
  type: "percent" | "fixed";
1018
1201
  expirationDate?: string;
1019
- }, opts: {
1020
- accessToken: string;
1202
+ }, opts?: {
1203
+ accessToken?: string;
1021
1204
  signal?: AbortSignal;
1022
1205
  }) => Promise<unknown>;
1023
1206
  };
@@ -1026,89 +1209,89 @@ declare class PlayaOSClient {
1026
1209
  name: string;
1027
1210
  price: number;
1028
1211
  totalQuantity?: number;
1029
- }, opts: {
1030
- accessToken: string;
1212
+ }, opts?: {
1213
+ accessToken?: string;
1031
1214
  signal?: AbortSignal;
1032
1215
  }) => Promise<unknown>;
1033
1216
  };
1034
1217
  };
1035
1218
  };
1036
1219
  members: {
1037
- create: (payload: MemberCreatePayload, opts: {
1038
- accessToken: string;
1220
+ create: (payload: MemberCreatePayload, opts?: {
1221
+ accessToken?: string;
1039
1222
  signal?: AbortSignal;
1040
1223
  }) => Promise<MemberCreateResponse>;
1041
- update: (id: string, patch: MemberUpdatePayload, opts: {
1042
- accessToken: string;
1224
+ update: (id: string, patch: MemberUpdatePayload, opts?: {
1225
+ accessToken?: string;
1043
1226
  signal?: AbortSignal;
1044
1227
  }) => Promise<MemberUpdateResponse>;
1045
- deactivate: (id: string, opts: {
1046
- accessToken: string;
1228
+ deactivate: (id: string, opts?: {
1229
+ accessToken?: string;
1047
1230
  signal?: AbortSignal;
1048
1231
  }) => Promise<MemberDeactivateResponse>;
1049
1232
  };
1050
1233
  announcements: {
1051
1234
  /** Send an email blast to camp members (PLA-706). Requires admin Bearer token. */
1052
- send: (payload: AnnouncementSendPayload, opts: {
1053
- accessToken: string;
1235
+ send: (payload: AnnouncementSendPayload, opts?: {
1236
+ accessToken?: string;
1054
1237
  signal?: AbortSignal;
1055
1238
  }) => Promise<AnnouncementSendResponse>;
1056
1239
  };
1057
1240
  dues: {
1058
1241
  /** Create a manual dues/payment record (PLA-708). Requires admin Bearer token. */
1059
- create: (payload: DuesCreatePayload, opts: {
1060
- accessToken: string;
1242
+ create: (payload: DuesCreatePayload, opts?: {
1243
+ accessToken?: string;
1061
1244
  signal?: AbortSignal;
1062
1245
  }) => Promise<DuesCreateResponse>;
1063
1246
  /** Update a dues/payment record (PLA-708). Requires admin Bearer token. */
1064
- update: (id: string, payload: DuesUpdatePayload, opts: {
1065
- accessToken: string;
1247
+ update: (id: string, payload: DuesUpdatePayload, opts?: {
1248
+ accessToken?: string;
1066
1249
  signal?: AbortSignal;
1067
1250
  }) => Promise<DuesUpdateResponse>;
1068
1251
  };
1069
1252
  org: {
1070
1253
  /** Update camp configuration settings (PLA-709). Requires admin Bearer token. */
1071
- update: (payload: OrgUpdatePayload, opts: {
1072
- accessToken: string;
1254
+ update: (payload: OrgUpdatePayload, opts?: {
1255
+ accessToken?: string;
1073
1256
  signal?: AbortSignal;
1074
1257
  }) => Promise<OrgUpdateResponse>;
1075
1258
  };
1076
1259
  scheduling: {
1077
1260
  availability: {
1078
1261
  /** Get interview availability for an interviewer (PLA-713). Requires admin Bearer token. */
1079
- get: (interviewerId: string, opts: {
1080
- accessToken: string;
1262
+ get: (interviewerId: string, opts?: {
1263
+ accessToken?: string;
1081
1264
  signal?: AbortSignal;
1082
- }) => Promise<SetAvailabilityResponse>;
1265
+ }) => Promise<GetAvailabilityResponse>;
1083
1266
  /** Set interview availability for an interviewer (PLA-713). Requires admin Bearer token. */
1084
- set: (interviewerId: string, payload: SetAvailabilityInput, opts: {
1085
- accessToken: string;
1267
+ set: (interviewerId: string, payload: SetAvailabilityInput, opts?: {
1268
+ accessToken?: string;
1086
1269
  signal?: AbortSignal;
1087
1270
  }) => Promise<SetAvailabilityResponse>;
1088
1271
  };
1089
1272
  calendar: {
1090
1273
  /** Get Google Calendar connection status for an interviewer (PLA-726). Requires admin Bearer. */
1091
- status: (interviewerId: string, opts: {
1092
- accessToken: string;
1274
+ status: (interviewerId: string, opts?: {
1275
+ accessToken?: string;
1093
1276
  signal?: AbortSignal;
1094
1277
  }) => Promise<CalendarStatus>;
1095
1278
  /** List available Google Calendars (PLA-726). Requires admin Bearer. */
1096
- listCalendars: (interviewerId: string, opts: {
1097
- accessToken: string;
1279
+ listCalendars: (interviewerId: string, opts?: {
1280
+ accessToken?: string;
1098
1281
  signal?: AbortSignal;
1099
1282
  }) => Promise<{
1100
1283
  calendars: GoogleCalendar[];
1101
1284
  }>;
1102
1285
  /** Select which Google Calendar to use (PLA-726). Requires admin Bearer. */
1103
- select: (interviewerId: string, payload: SelectCalendarInput, opts: {
1104
- accessToken: string;
1286
+ select: (interviewerId: string, payload: SelectCalendarInput, opts?: {
1287
+ accessToken?: string;
1105
1288
  signal?: AbortSignal;
1106
1289
  }) => Promise<{
1107
1290
  calendarId: string;
1108
1291
  }>;
1109
1292
  /** Disconnect Google Calendar from interviewer (PLA-726). Requires admin Bearer. */
1110
- disconnect: (interviewerId: string, opts: {
1111
- accessToken: string;
1293
+ disconnect: (interviewerId: string, opts?: {
1294
+ accessToken?: string;
1112
1295
  signal?: AbortSignal;
1113
1296
  }) => Promise<{
1114
1297
  disconnected: boolean;
@@ -1116,13 +1299,13 @@ declare class PlayaOSClient {
1116
1299
  };
1117
1300
  bookingTokens: {
1118
1301
  /** Create a booking token for an application's interview link (PLA-714). Requires admin Bearer token. */
1119
- create: (payload: CreateBookingTokenInput, opts: {
1120
- accessToken: string;
1302
+ create: (payload: CreateBookingTokenInput, opts?: {
1303
+ accessToken?: string;
1121
1304
  signal?: AbortSignal;
1122
1305
  }) => Promise<BookingToken>;
1123
1306
  /** Get an existing booking token for an application (PLA-714). Requires admin Bearer token. */
1124
- get: (applicationId: string, opts: {
1125
- accessToken: string;
1307
+ get: (applicationId: string, opts?: {
1308
+ accessToken?: string;
1126
1309
  signal?: AbortSignal;
1127
1310
  }) => Promise<BookingToken>;
1128
1311
  };
@@ -1261,5 +1444,5 @@ interface PublicMarketplaceClient {
1261
1444
  }
1262
1445
  declare function createPublicMarketplaceClient(opts: PublicMarketplaceClientOptions): PublicMarketplaceClient;
1263
1446
  //#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 };
1447
+ 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
1448
  //# 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.16.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
+ }