@playaos/api-client 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -391,7 +391,16 @@ interface ApplicationEvent {
391
391
  applicationId: string;
392
392
  actorId: string | null;
393
393
  actorName: string | null;
394
- type: "status_change" | "note_added" | "tags_updated" | "score_set";
394
+ /**
395
+ * Mirrors `APPLICATION_AUDIT_ACTIONS` in `@playa-os/portal-data`, except that
396
+ * the server's `status_changed` is surfaced as `status_change` for backwards
397
+ * compatibility with the original embed shape. `tags_updated` and `score_set`
398
+ * predate that vocabulary and are kept so existing consumers still compile.
399
+ *
400
+ * Widening the server list without widening this union lets a value escape
401
+ * the declared type through the cast in `client.ts` — see PLA-1199.
402
+ */
403
+ type: "status_change" | "note_added" | "tags_updated" | "score_set" | "message_sent" | "message_received" | "approved" | "rejected" | "waitlisted" | "interview_invite_sent" | "interview_scheduled_manually" | "interview_completed" | "interviewer_assigned" | "red_flag_added";
395
404
  timestamp: string;
396
405
  fromStatus?: string | null;
397
406
  toStatus?: string;
@@ -457,6 +466,137 @@ interface SelectCalendarInput {
457
466
  calendarId: string;
458
467
  calendarName?: string;
459
468
  }
469
+ /** Per-member status for one packing item. Mirrors `PACKING_ITEM_STATUSES`. */
470
+ type PackingItemStatus = "have" | "need" | "nope" | "packed" | "camp_has";
471
+ /** Which layer a resolved row came from (ADR-071). */
472
+ type PackingLayer = "global" | "camp" | "personal";
473
+ /**
474
+ * One row of the resolved list. Identity is `slug`, never a row uuid — the
475
+ * curated base is regenerated wholesale and uuids do not survive it (ADR-071).
476
+ */
477
+ interface PackingItem {
478
+ slug: string;
479
+ category: string;
480
+ name: string;
481
+ notes: string | null;
482
+ shelters: string[];
483
+ qty: number | null;
484
+ unit: string | null;
485
+ source: string | null;
486
+ contested: string | null;
487
+ sortOrder: number;
488
+ /** Base-layer rows only — which packing-template source this came from. */
489
+ sourceList?: string;
490
+ layer: PackingLayer;
491
+ status: string | null;
492
+ /** The member's own annotation. Distinct from the item's `notes`. */
493
+ memberNotes: string | null;
494
+ containerId: string | null;
495
+ containerName: string | null;
496
+ }
497
+ interface PackingListResponse {
498
+ items: PackingItem[];
499
+ year: number;
500
+ }
501
+ /** A row in the member's personal layer. These are user-owned, so keyed by uuid. */
502
+ interface PackingPersonalItem {
503
+ id: string;
504
+ catalogItemId: string | null;
505
+ name: string;
506
+ category: string;
507
+ tags: string[];
508
+ qty: number;
509
+ unit: string | null;
510
+ status: string;
511
+ containerId: string | null;
512
+ notes: string | null;
513
+ }
514
+ /** How the rental reaches the member. The server defaults to `camp_delivery`. */
515
+ type BikeRentalDeliveryMode = "individual_pickup" | "camp_delivery";
516
+ type BikeRentalFramePreference = "standard" | "step-through";
517
+ interface BikeRentalCatalogItem {
518
+ /** Customer-facing option label. Send it back as `model` when requesting a bike. */
519
+ model: string;
520
+ /** DustJunkie bike_type behind the option. */
521
+ bikeType: string;
522
+ framePreference: BikeRentalFramePreference;
523
+ /** Per-rental price. */
524
+ price: number;
525
+ /** Refundable security deposit for this bike type. */
526
+ deposit: number;
527
+ /** Transport fee for the requested delivery mode; 0 for pickup. */
528
+ transportFee: number;
529
+ /** Display estimate: price + deposit + transportFee. DustJunkie sets the amount it actually charges. */
530
+ estimatedTotal: number;
531
+ /** Bikes of this type tracked in the delivery pool, in any status. */
532
+ totalCount: number;
533
+ /** Bikes of this type ready to ride; 0 means sold out. */
534
+ ready: number;
535
+ }
536
+ interface BikeRentalCatalogResponse {
537
+ items: BikeRentalCatalogItem[];
538
+ }
539
+ interface BikeRentalWaiver {
540
+ /** Waiver version recorded with every request. */
541
+ version: string;
542
+ /** Full rental agreement and liability waiver. */
543
+ text: string;
544
+ /** Every box must be accepted to submit a request. */
545
+ checkboxes: string[];
546
+ }
547
+ /** Body of `POST /bike-rentals/requests`. The request is always for the acting member. */
548
+ interface BikeRentalRequestInput {
549
+ /** A `model` from `bikeRentals.catalog()`. */
550
+ model: string;
551
+ firstName: string;
552
+ lastName: string;
553
+ /** Must contain at least 10 digits. */
554
+ phone: string;
555
+ billingStreet: string;
556
+ billingCity: string;
557
+ billingState: string;
558
+ billingPostalCode: string;
559
+ billingCountry: string;
560
+ /** The member accepted the waiver and all of its checkboxes. */
561
+ agreementConfirmed: true;
562
+ }
563
+ interface BikeRentalRequestResult {
564
+ /** DustJunkie's id for the pending request. */
565
+ requestId: string | null;
566
+ status: string | null;
567
+ }
568
+ interface BikeRentalReservation {
569
+ id: string;
570
+ name: string;
571
+ email: string | null;
572
+ reservationType: string | null;
573
+ /** Bike description parsed from DustJunkie's notes. */
574
+ bikeSummary: string | null;
575
+ paymentAmount: number | null;
576
+ paymentStatus: string | null;
577
+ rentalStatus: string | null;
578
+ waiverStatus: string | null;
579
+ depositStatus: string | null;
580
+ deliveryType: string | null;
581
+ reservedAt: string | null;
582
+ }
583
+ interface BikeRentalReservationListResponse {
584
+ items: BikeRentalReservation[];
585
+ }
586
+ interface BikeRentalInterestedMember {
587
+ userId: string;
588
+ name: string | null;
589
+ email: string | null;
590
+ bikeTypePreference: string | null;
591
+ arrivalDate: string | null;
592
+ /** No email on file, so no reservation can ever match. */
593
+ unmatchable: boolean;
594
+ }
595
+ interface BikeRentalInterestedNotReservedResponse {
596
+ /** Active camp year; the calendar year when no camp year is active. */
597
+ year: number;
598
+ items: BikeRentalInterestedMember[];
599
+ }
460
600
  //#endregion
461
601
  //#region src/client.d.ts
462
602
  interface ClientOptions {
@@ -691,6 +831,42 @@ declare class PlayaOSClient {
691
831
  signal?: AbortSignal;
692
832
  }) => Promise<Bike>;
693
833
  };
834
+ /**
835
+ * DustJunkie bike rentals (PLA-1180), passed through to the vendor. A camp
836
+ * without the integration gets 403; a DustJunkie failure is a 502.
837
+ */
838
+ readonly bikeRentals: {
839
+ /** Bookable options with estimated totals for `delivery` (server default `camp_delivery`). Org key only. */
840
+ catalog: (params?: {
841
+ delivery?: BikeRentalDeliveryMode;
842
+ }, opts?: {
843
+ signal?: AbortSignal;
844
+ }) => Promise<BikeRentalCatalogResponse>;
845
+ /** The rental agreement the member must accept before `requestReservation`. Org key only. */
846
+ waiver: (opts?: {
847
+ signal?: AbortSignal;
848
+ }) => Promise<BikeRentalWaiver>;
849
+ /**
850
+ * Requires a member token. Admins get the whole camp when `memberId` is
851
+ * omitted; any other role gets their own reservations and 403 naming someone else.
852
+ */
853
+ reservations: (params?: {
854
+ memberId?: string;
855
+ }, opts?: {
856
+ signal?: AbortSignal;
857
+ }) => Promise<BikeRentalReservationListResponse>;
858
+ /**
859
+ * Requires a member token; always requests for the acting member. 409 when
860
+ * the model is sold out, 400 when it is unknown or no longer bookable.
861
+ */
862
+ requestReservation: (payload: BikeRentalRequestInput, opts?: {
863
+ signal?: AbortSignal;
864
+ }) => Promise<BikeRentalRequestResult>;
865
+ /** Members who said they want a bike but have no reservation, for the active camp year. Org key only. */
866
+ interestedNotReserved: (opts?: {
867
+ signal?: AbortSignal;
868
+ }) => Promise<BikeRentalInterestedNotReservedResponse>;
869
+ };
694
870
  readonly tags: {
695
871
  list: (opts?: {
696
872
  signal?: AbortSignal;
@@ -712,9 +888,87 @@ declare class PlayaOSClient {
712
888
  id: string;
713
889
  }>;
714
890
  };
891
+ /**
892
+ * Camp-scoped packing (PLA-1197). Every method is the acting member's own
893
+ * list — packing has no `memberId` to widen, so these require `memberToken`
894
+ * and 401 on an org key alone.
895
+ */
896
+ readonly packing: {
897
+ /** The resolved list: curated base + camp layer + personal layer (ADR-071). */
898
+ list: (params?: {
899
+ year?: number;
900
+ shelter?: string;
901
+ }, opts?: {
902
+ signal?: AbortSignal;
903
+ }) => Promise<PackingListResponse>;
904
+ /**
905
+ * Set the member's status for one item. The slug goes in the body, not the
906
+ * path: slugs are `${category}/${name}` and contain a `/`.
907
+ *
908
+ * Pass the same `shelter` the list was read under — validation filters by
909
+ * shelter, so an override omitted here rejects shelter-specific items.
910
+ */
911
+ setStatus: (payload: {
912
+ slug: string;
913
+ status: PackingItemStatus;
914
+ year?: number;
915
+ shelter?: string;
916
+ }, opts?: {
917
+ signal?: AbortSignal;
918
+ }) => Promise<{
919
+ ok: true;
920
+ }>;
921
+ personalItems: {
922
+ list: (params?: {
923
+ containerId?: string;
924
+ }, opts?: {
925
+ signal?: AbortSignal;
926
+ }) => Promise<{
927
+ items: PackingPersonalItem[];
928
+ }>;
929
+ create: (payload: {
930
+ name: string;
931
+ category: string;
932
+ qty?: number;
933
+ unit?: string | null;
934
+ notes?: string | null;
935
+ }, opts?: {
936
+ signal?: AbortSignal;
937
+ }) => Promise<{
938
+ id: string;
939
+ }>;
940
+ /**
941
+ * Flip the item between `need` and `have`. It does **not** set `packed` —
942
+ * use `setStatus` for the full vocabulary. 404 if the item is not the
943
+ * acting member's.
944
+ */
945
+ toggle: (id: string, opts?: {
946
+ signal?: AbortSignal;
947
+ }) => Promise<{
948
+ ok: true;
949
+ }>;
950
+ /** 404 if the item is not the acting member's. */
951
+ remove: (id: string, opts?: {
952
+ signal?: AbortSignal;
953
+ }) => Promise<{
954
+ ok: true;
955
+ }>;
956
+ };
957
+ };
715
958
  readonly admin: {
716
959
  applications: {
717
- /** Get application audit timeline (PLA-712). Requires admin Bearer token. */
960
+ /**
961
+ * Get application audit timeline (PLA-712). Requires admin Bearer token.
962
+ *
963
+ * @deprecated The embed handler for this method never existed — calls
964
+ * always 404'd (see PLA-1199). Retained as a compile-time compatibility
965
+ * surface for published-consumer code; delegates to the canonical
966
+ * `GET /api/v1/audit/application-logs?applicationId=` (ADR-054), which
967
+ * reads the same `application_audit_logs` table. The `accessToken`
968
+ * argument is accepted but unused — the v1 surface authenticates with
969
+ * the org API key (`audit:read` scope) instead of an admin JWT. Remove
970
+ * in the next major version.
971
+ */
718
972
  history: (id: string, opts: {
719
973
  accessToken: string;
720
974
  signal?: AbortSignal;
@@ -1007,5 +1261,5 @@ interface PublicMarketplaceClient {
1007
1261
  }
1008
1262
  declare function createPublicMarketplaceClient(opts: PublicMarketplaceClientOptions): PublicMarketplaceClient;
1009
1263
  //#endregion
1010
- export { ApiClientError, type Application, type ApplicationAnnotations, type ApplicationCreatePayload, type ApplicationCreateResponse, type ApplicationNote, type ApplicationScore, type ApplicationStatus, type ApplicationTransitionPayload, type ApplicationTransitionResponse, 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 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 };
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 };
1011
1265
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -90,6 +90,22 @@ async function post(url, auth, body, signal) {
90
90
  if (!res.ok) throw await parseError(res);
91
91
  return res.json();
92
92
  }
93
+ /** v1 write helpers. `request`/`post` predate these; same auth, other verbs. */
94
+ async function sendV1(method, url, auth, body, signal) {
95
+ const headers = v1Headers(auth);
96
+ const init = {
97
+ method,
98
+ headers,
99
+ signal
100
+ };
101
+ if (body !== void 0) {
102
+ headers["Content-Type"] = "application/json";
103
+ init.body = JSON.stringify(body);
104
+ }
105
+ const res = await fetch(url, init);
106
+ if (!res.ok) throw await parseError(res);
107
+ return res.json();
108
+ }
93
109
  async function postEmbed(url, campKey, body, opts) {
94
110
  const headers = {
95
111
  "X-Camp-Key": campKey,
@@ -194,7 +210,7 @@ var PlayaOSClient = class PlayaOSClient {
194
210
  selfUpdate: (payload, opts) => putEmbed(buildEmbedUrl(this.embedBaseUrl, "/members/self"), this.apiKey, payload, opts),
195
211
  /** Member-self shift signup + cancel (PLA-705). Requires camp key + member Bearer. */
196
212
  shifts: {
197
- signup: (payload, opts) => putEmbed(buildEmbedUrl(this.embedBaseUrl, "/shifts/signup"), this.apiKey, payload, opts),
213
+ signup: (payload, opts) => postEmbed(buildEmbedUrl(this.embedBaseUrl, "/shifts/signup"), this.apiKey, payload, opts),
198
214
  cancel: (signupId, opts) => deleteEmbed(buildEmbedUrl(this.embedBaseUrl, `/shifts/signups/${encodeURIComponent(signupId)}`), this.apiKey, opts)
199
215
  }
200
216
  };
@@ -245,16 +261,99 @@ var PlayaOSClient = class PlayaOSClient {
245
261
  list: (params, opts) => request(buildUrl(this.baseUrl, "/bikes", params), this.auth, opts?.signal),
246
262
  get: (id, opts) => request(buildUrl(this.baseUrl, `/bikes/${encodeURIComponent(id)}`), this.auth, opts?.signal)
247
263
  };
264
+ /**
265
+ * DustJunkie bike rentals (PLA-1180), passed through to the vendor. A camp
266
+ * without the integration gets 403; a DustJunkie failure is a 502.
267
+ */
268
+ bikeRentals = {
269
+ /** Bookable options with estimated totals for `delivery` (server default `camp_delivery`). Org key only. */
270
+ catalog: (params, opts) => request(buildUrl(this.baseUrl, "/bike-rentals/catalog", params), this.auth, opts?.signal),
271
+ /** The rental agreement the member must accept before `requestReservation`. Org key only. */
272
+ waiver: (opts) => request(buildUrl(this.baseUrl, "/bike-rentals/waiver"), this.auth, opts?.signal),
273
+ /**
274
+ * Requires a member token. Admins get the whole camp when `memberId` is
275
+ * omitted; any other role gets their own reservations and 403 naming someone else.
276
+ */
277
+ reservations: (params, opts) => request(buildUrl(this.baseUrl, "/bike-rentals/reservations", params), this.auth, opts?.signal),
278
+ /**
279
+ * Requires a member token; always requests for the acting member. 409 when
280
+ * the model is sold out, 400 when it is unknown or no longer bookable.
281
+ */
282
+ requestReservation: (payload, opts) => post(buildUrl(this.baseUrl, "/bike-rentals/requests"), this.auth, payload, opts?.signal),
283
+ /** Members who said they want a bike but have no reservation, for the active camp year. Org key only. */
284
+ interestedNotReserved: (opts) => request(buildUrl(this.baseUrl, "/bike-rentals/interested-not-reserved"), this.auth, opts?.signal)
285
+ };
248
286
  tags = { list: (opts) => request(buildUrl(this.baseUrl, "/tags"), this.auth, opts?.signal) };
249
287
  groups = {
250
288
  list: (opts) => request(buildUrl(this.baseUrl, "/groups"), this.auth, opts?.signal),
251
289
  get: (id, opts) => request(buildUrl(this.baseUrl, `/groups/${encodeURIComponent(id)}`), this.auth, opts?.signal),
252
290
  create: (payload, opts) => post(buildUrl(this.baseUrl, "/groups"), this.auth, payload, opts?.signal)
253
291
  };
292
+ /**
293
+ * Camp-scoped packing (PLA-1197). Every method is the acting member's own
294
+ * list — packing has no `memberId` to widen, so these require `memberToken`
295
+ * and 401 on an org key alone.
296
+ */
297
+ packing = {
298
+ /** The resolved list: curated base + camp layer + personal layer (ADR-071). */
299
+ list: (params, opts) => request(buildUrl(this.baseUrl, "/packing", params), this.auth, opts?.signal),
300
+ /**
301
+ * Set the member's status for one item. The slug goes in the body, not the
302
+ * path: slugs are `${category}/${name}` and contain a `/`.
303
+ *
304
+ * Pass the same `shelter` the list was read under — validation filters by
305
+ * shelter, so an override omitted here rejects shelter-specific items.
306
+ */
307
+ setStatus: (payload, opts) => sendV1("PUT", buildUrl(this.baseUrl, "/packing/items/status"), this.auth, payload, opts?.signal),
308
+ personalItems: {
309
+ list: (params, opts) => request(buildUrl(this.baseUrl, "/packing/personal-items", params), this.auth, opts?.signal),
310
+ create: (payload, opts) => post(buildUrl(this.baseUrl, "/packing/personal-items"), this.auth, payload, opts?.signal),
311
+ /**
312
+ * Flip the item between `need` and `have`. It does **not** set `packed` —
313
+ * use `setStatus` for the full vocabulary. 404 if the item is not the
314
+ * acting member's.
315
+ */
316
+ toggle: (id, opts) => sendV1("PATCH", buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`), this.auth, void 0, opts?.signal),
317
+ /** 404 if the item is not the acting member's. */
318
+ remove: (id, opts) => sendV1("DELETE", buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`), this.auth, void 0, opts?.signal)
319
+ }
320
+ };
254
321
  admin = {
255
322
  applications: {
256
- /** Get application audit timeline (PLA-712). Requires admin Bearer token. */
257
- history: (id, opts) => adminEmbed("GET", buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/history`), opts.accessToken, void 0, opts.signal),
323
+ /**
324
+ * Get application audit timeline (PLA-712). Requires admin Bearer token.
325
+ *
326
+ * @deprecated The embed handler for this method never existed — calls
327
+ * always 404'd (see PLA-1199). Retained as a compile-time compatibility
328
+ * surface for published-consumer code; delegates to the canonical
329
+ * `GET /api/v1/audit/application-logs?applicationId=` (ADR-054), which
330
+ * reads the same `application_audit_logs` table. The `accessToken`
331
+ * argument is accepted but unused — the v1 surface authenticates with
332
+ * the org API key (`audit:read` scope) instead of an admin JWT. Remove
333
+ * in the next major version.
334
+ */
335
+ history: async (id, opts) => {
336
+ const rows = [];
337
+ let cursor = null;
338
+ do {
339
+ const page = await request(buildUrl(this.baseUrl, "/audit/application-logs", {
340
+ applicationId: id,
341
+ limit: 100,
342
+ ...cursor ? { cursor } : {}
343
+ }), this.auth, opts?.signal);
344
+ rows.push(...page.data);
345
+ cursor = page.nextCursor;
346
+ } while (cursor);
347
+ return { events: rows.map((row) => ({
348
+ id: row.id,
349
+ applicationId: row.applicationId,
350
+ actorId: row.actorUserId,
351
+ actorName: null,
352
+ type: row.action === "status_changed" ? "status_change" : row.action,
353
+ timestamp: row.createdAt ?? "",
354
+ metadata: row.details ?? void 0
355
+ })) };
356
+ },
258
357
  transition: (id, payload, opts) => adminEmbed("PATCH", buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}`), opts.accessToken, payload, opts.signal),
259
358
  getAnnotations: (id, opts) => adminEmbed("GET", buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/annotations`), opts.accessToken, void 0, opts.signal),
260
359
  addNote: (id, payload, opts) => adminEmbed("POST", buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/notes`), opts.accessToken, payload, opts.signal),
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 ApplicationHistoryResponse,\n ApplicationNote,\n ApplicationScore,\n ApplicationStatus,\n ApplicationTransitionPayload,\n ApplicationTransitionResponse,\n Bike,\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 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\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 putEmbed(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 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 // 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 /** Get application audit timeline (PLA-712). Requires admin Bearer token. */\n history: (id: string, opts: { accessToken: string; signal?: AbortSignal }): Promise<ApplicationHistoryResponse> =>\n adminEmbed(\n \"GET\",\n buildEmbedUrl(this.embedBaseUrl, `/admin/applications/${encodeURIComponent(id)}/history`),\n opts.accessToken,\n undefined,\n opts.signal,\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 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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playaos/api-client",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Typed API client for PlayaOS \u2014 manage camp members, dues, shifts, applications, waivers, and annotations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",