@playaos/api-client 0.23.0 → 0.25.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
@@ -779,6 +779,50 @@ interface EmailRetryListResponse {
779
779
  data: EmailRetry[];
780
780
  counts: EmailRetryCount[];
781
781
  }
782
+ /** Result of signing a camp document (PLA-1258). */
783
+ interface CampDocumentSignature {
784
+ id: string;
785
+ signedAt: string | null;
786
+ signedPdfPath: string | null;
787
+ }
788
+ /** A short-lived download URL for the member's copy of a document (PLA-1258). */
789
+ interface CampDocumentDownloadUrl {
790
+ url: string;
791
+ /** True when the URL points at the member's signed PDF rather than the source file. */
792
+ signed: boolean;
793
+ }
794
+ interface MeetingDateOption {
795
+ id: string;
796
+ startsAt: string;
797
+ endsAt: string | null;
798
+ location: string | null;
799
+ }
800
+ interface Meeting {
801
+ id: string;
802
+ orgId: string;
803
+ year: number;
804
+ title: string;
805
+ description: string | null;
806
+ isMandatory: boolean;
807
+ targetGroup: string;
808
+ isActive: boolean;
809
+ dateOptions: MeetingDateOption[];
810
+ }
811
+ interface CreateMeetingInput {
812
+ title: string;
813
+ description?: string | null;
814
+ isMandatory: boolean;
815
+ targetGroup: "all_members" | "admins" | "virgin_burners";
816
+ dateOptions: Array<{
817
+ startsAt: string;
818
+ endsAt?: string | null;
819
+ location?: string | null;
820
+ }>;
821
+ }
822
+ interface MeetingListResponse {
823
+ data: Meeting[];
824
+ nextCursor: string | null;
825
+ }
782
826
  //#endregion
783
827
  //#region src/client.d.ts
784
828
  interface ClientOptions {
@@ -1058,6 +1102,43 @@ declare class PlayaOSClient {
1058
1102
  get: (id: string, opts?: {
1059
1103
  signal?: AbortSignal;
1060
1104
  }) => Promise<CampDocument>;
1105
+ /** Sign a camp document for the acting member (PLA-1258). Requires a member token. */
1106
+ sign: (id: string, payload?: {
1107
+ signature?: {
1108
+ dataUrl: string;
1109
+ type: "checkbox" | "drawn" | "typed";
1110
+ signerName?: string;
1111
+ };
1112
+ }, opts?: {
1113
+ signal?: AbortSignal;
1114
+ }) => Promise<CampDocumentSignature>;
1115
+ /** Signed download URL for the member's copy — signed PDF if present, else the source (PLA-1258). */
1116
+ downloadUrl: (id: string, opts?: {
1117
+ signal?: AbortSignal;
1118
+ }) => Promise<CampDocumentDownloadUrl>;
1119
+ };
1120
+ readonly meetings: {
1121
+ list: (params?: {
1122
+ year?: number;
1123
+ limit?: number;
1124
+ cursor?: string;
1125
+ }, opts?: {
1126
+ signal?: AbortSignal;
1127
+ }) => Promise<MeetingListResponse>;
1128
+ get: (id: string, opts?: {
1129
+ signal?: AbortSignal;
1130
+ }) => Promise<Meeting>;
1131
+ /** Create a meeting (PLA-1266). Admin-only; requires a member token. */
1132
+ create: (payload: CreateMeetingInput, opts?: {
1133
+ signal?: AbortSignal;
1134
+ }) => Promise<Meeting>;
1135
+ /** Archive a meeting (soft delete). Admin-only; requires a member token. */
1136
+ archive: (id: string, opts?: {
1137
+ signal?: AbortSignal;
1138
+ }) => Promise<{
1139
+ id: string;
1140
+ deleted: boolean;
1141
+ }>;
1061
1142
  };
1062
1143
  readonly shelters: {
1063
1144
  list: (params?: {
@@ -1625,5 +1706,5 @@ interface PublicMarketplaceClient {
1625
1706
  }
1626
1707
  declare function createPublicMarketplaceClient(opts: PublicMarketplaceClientOptions): PublicMarketplaceClient;
1627
1708
  //#endregion
1628
- export { type AdminNotificationPrefs, ApiClientError, type Application, type ApplicationAdmin, type ApplicationAnnotations, type ApplicationCreatePayload, type ApplicationCreateResponse, type ApplicationNote, type ApplicationScore, type ApplicationStatus, type ApplicationTransitionPayload, type ApplicationTransitionResponse, type BikeRentalCatalogItem, type BikeRentalCatalogResponse, type BikeRentalDeliveryMode, type BikeRentalFramePreference, type BikeRentalInterestedMember, type BikeRentalInterestedNotReservedResponse, type BikeRentalRequestInput, type BikeRentalRequestResult, type BikeRentalReservation, type BikeRentalReservationListResponse, type BikeRentalWaiver, type Commitment, type CommitmentDataType, type CommitmentValue, type CommitmentsListResponse, type CreateSapAssignmentInput, type DuesStatus, type EmailRetry, type EmailRetryCount, type EmailRetryListResponse, type EmailTemplate, type ExchangeParams, type ExchangeResult, type ImageUploadTarget, type ImportantDate, type ListingImage, MAX_IMAGE_POSITION, type MarketplaceFlagReason, type Member, type MemberCreatePayload, type MemberCreateResponse, type MemberDeactivateResponse, type MemberDevice, type MemberPreferences, type MemberRole, type MemberUpdatePayload, type MemberUpdateResponse, type NewListingInput, type OnboardingProgress, type OrgConfig, type PackingCampItem, type PackingItem, type PackingItemStatus, type PackingLayer, type PackingListResponse, type PackingPersonalItem, type PaymentPageResponse, PlayaOSClient, type PublicMarketplaceClient, type PublicMarketplaceClientOptions, type SapAllocation, type SapAssignment, type SapDayAllocation, type Shift, type ShiftSignup, type ShiftType, type UpdateSapAllocationInput, type UpdateSapAssignmentInput, type UpsertPackingCampItemInput, type UpsertSapDayAllocationInput, type Waiver, type WaiverContent, type WaiverSection, type WaiverSignPayload, type WaiverSignResponse, type WaiverStatus, createClient, createPublicMarketplaceClient, exchangeCode };
1709
+ export { type AdminNotificationPrefs, ApiClientError, type Application, type ApplicationAdmin, 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 CampDocumentDownloadUrl, type CampDocumentSignature, type Commitment, type CommitmentDataType, type CommitmentValue, type CommitmentsListResponse, type CreateMeetingInput, type CreateSapAssignmentInput, type DuesStatus, type EmailRetry, type EmailRetryCount, type EmailRetryListResponse, type EmailTemplate, type ExchangeParams, type ExchangeResult, type ImageUploadTarget, type ImportantDate, type ListingImage, MAX_IMAGE_POSITION, type MarketplaceFlagReason, type Meeting, type MeetingDateOption, type MeetingListResponse, type Member, type MemberCreatePayload, type MemberCreateResponse, type MemberDeactivateResponse, type MemberDevice, type MemberPreferences, type MemberRole, type MemberUpdatePayload, type MemberUpdateResponse, type NewListingInput, type OnboardingProgress, type OrgConfig, type PackingCampItem, type PackingItem, type PackingItemStatus, type PackingLayer, type PackingListResponse, type PackingPersonalItem, type PaymentPageResponse, PlayaOSClient, type PublicMarketplaceClient, type PublicMarketplaceClientOptions, type SapAllocation, type SapAssignment, type SapDayAllocation, type Shift, type ShiftSignup, type ShiftType, type UpdateSapAllocationInput, type UpdateSapAssignmentInput, type UpsertPackingCampItemInput, type UpsertSapDayAllocationInput, type Waiver, type WaiverContent, type WaiverSection, type WaiverSignPayload, type WaiverSignResponse, type WaiverStatus, createClient, createPublicMarketplaceClient, exchangeCode };
1629
1710
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -301,7 +301,19 @@ var PlayaOSClient = class PlayaOSClient {
301
301
  };
302
302
  documents = {
303
303
  list: (params, opts) => request(buildUrl(this.baseUrl, "/documents", params), this.auth, opts?.signal),
304
- get: (id, opts) => request(buildUrl(this.baseUrl, `/documents/${encodeURIComponent(id)}`), this.auth, opts?.signal)
304
+ get: (id, opts) => request(buildUrl(this.baseUrl, `/documents/${encodeURIComponent(id)}`), this.auth, opts?.signal),
305
+ /** Sign a camp document for the acting member (PLA-1258). Requires a member token. */
306
+ sign: (id, payload, opts) => post(buildUrl(this.baseUrl, `/members/documents/${encodeURIComponent(id)}/sign`), this.auth, payload ?? {}, opts?.signal),
307
+ /** Signed download URL for the member's copy — signed PDF if present, else the source (PLA-1258). */
308
+ downloadUrl: (id, opts) => request(buildUrl(this.baseUrl, `/members/documents/${encodeURIComponent(id)}/download-url`), this.auth, opts?.signal)
309
+ };
310
+ meetings = {
311
+ list: (params, opts) => request(buildUrl(this.baseUrl, "/meetings", params), this.auth, opts?.signal),
312
+ get: (id, opts) => request(buildUrl(this.baseUrl, `/meetings/${encodeURIComponent(id)}`), this.auth, opts?.signal),
313
+ /** Create a meeting (PLA-1266). Admin-only; requires a member token. */
314
+ create: (payload, opts) => post(buildUrl(this.baseUrl, "/meetings"), this.auth, payload, opts?.signal),
315
+ /** Archive a meeting (soft delete). Admin-only; requires a member token. */
316
+ archive: (id, opts) => sendV1("DELETE", buildUrl(this.baseUrl, `/meetings/${encodeURIComponent(id)}`), this.auth, void 0, opts?.signal)
305
317
  };
306
318
  shelters = {
307
319
  list: (params, opts) => request(buildUrl(this.baseUrl, "/shelters", params), this.auth, 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 AdminNotificationPrefs,\n AnnouncementSendPayload,\n AnnouncementSendResponse,\n Application,\n ApplicationAdmin,\n ApplicationAnnotations,\n ApplicationCreatePayload,\n ApplicationCreateResponse,\n ApplicationEvent,\n ApplicationHistoryResponse,\n ApplicationNote,\n ApplicationScore,\n ApplicationStatus,\n ApplicationTransitionPayload,\n ApplicationTransitionResponse,\n Bike,\n BikeRentalCatalogResponse,\n BikeRentalDeliveryMode,\n BikeRentalInterestedNotReservedResponse,\n BikeRentalRequestInput,\n BikeRentalRequestResult,\n BikeRentalReservationListResponse,\n BikeRentalWaiver,\n BookingToken,\n BookSlotInput,\n BookSlotResponse,\n CalendarStatus,\n CampDocument,\n CommitmentsListResponse,\n Contact,\n CreateBookingTokenInput,\n CreateSapAssignmentInput,\n DuesCreatePayload,\n DuesCreateResponse,\n DuesStatus,\n DuesUpdatePayload,\n DuesUpdateResponse,\n EmailRetryListResponse,\n EmailTemplate,\n GetAvailabilityResponse,\n GoogleCalendar,\n ImportantDate,\n Member,\n MemberCreatePayload,\n MemberCreateResponse,\n MemberDeactivateResponse,\n MemberDevice,\n MemberGroup,\n MemberGroupRosterRow,\n MemberPreferences,\n MemberRole,\n MemberTag,\n MemberUpdatePayload,\n MemberUpdateResponse,\n NotificationLog,\n OnboardingProgress,\n OrgConfig,\n OrgUpdatePayload,\n OrgUpdateResponse,\n PackingCampItem,\n PackingItemStatus,\n PackingListResponse,\n PackingPersonalItem,\n Paginated,\n PaginationParams,\n PaymentLedgerRow,\n PaymentPageResponse,\n RescheduleInput,\n SapAllocation,\n SapAssignment,\n SapDayAllocation,\n SelectCalendarInput,\n SetAvailabilityInput,\n SetAvailabilityResponse,\n Shelter,\n Shift,\n UpdateSapAllocationInput,\n UpdateSapAssignmentInput,\n UpsertPackingCampItemInput,\n UpsertSapDayAllocationInput,\n Waiver,\n WaiverSignPayload,\n WaiverSignResponse,\n WaiverStatus,\n} from \"./types.js\";\n\nexport type { ApiClientError };\n\ninterface ClientOptions {\n /** Base URL for authenticated /api/v1 routes, e.g. https://api.playaos.app */\n baseUrl: string;\n /** Optional base URL for /api/embed/v1 routes when they live on a different host. */\n embedBaseUrl?: string;\n /** API key in the format pk_live_* */\n apiKey: string;\n /**\n * Supabase session JWT of the acting member, sent as `X-PlayaOS-Member-Token`\n * on every /api/v1 call (PLA-1195). Member-scoped endpoints (a member's own\n * dues, payments, application, shelter, shifts signup, …) require it and\n * return 401 without it. Org-level endpoints do not require it, but a token\n * that is sent must still verify — an expired or invalid one is a 401 on any\n * /api/v1 route that installs the member middleware. Prefer\n * `client.withMember(token)` to derive a per-request client from a shared\n * server-side one rather than constructing a client per user.\n */\n memberToken?: string;\n}\n\n/** Credentials for /api/v1: the org key names the org, the member token names the person. */\ninterface V1Auth {\n apiKey: string;\n memberToken?: string;\n}\n\nfunction v1Headers(auth: V1Auth): Record<string, string> {\n const headers: Record<string, string> = { Authorization: `Bearer ${auth.apiKey}` };\n if (auth.memberToken) headers[\"X-PlayaOS-Member-Token\"] = auth.memberToken;\n return headers;\n}\n\nfunction buildUrl(base: string, path: string, params?: Record<string, string | number | boolean | undefined>): string {\n const url = new URL(`${base}/api/v1${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n // Skip undefined and false booleans — z.coerce.boolean() on the server uses Boolean(),\n // which treats any non-empty string (including \"false\") as true. Omitting a false boolean\n // param has the same effect as the server default (unfiltered).\n if (v !== undefined && v !== false) url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n}\n\nfunction buildEmbedUrl(base: string, path: string): string {\n return `${base}/api/embed/v1${path}`;\n}\n\nfunction withCampKey(url: string, campKey: string): string {\n const embedUrl = new URL(url);\n embedUrl.searchParams.set(\"camp_key\", campKey);\n return embedUrl.toString();\n}\n\nasync function getEmbed<T>(url: string, campKey: string, signal?: AbortSignal): Promise<T> {\n const res = await fetch(withCampKey(url, campKey), {\n headers: { \"X-Camp-Key\": campKey },\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function getEmbedAuthed<T>(\n url: string,\n campKey: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = { \"X-Camp-Key\": campKey };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), { headers, signal: opts?.signal });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function request<T>(url: string, auth: V1Auth, signal?: AbortSignal): Promise<T> {\n const res = await fetch(url, {\n headers: v1Headers(auth),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function post<T>(url: string, auth: V1Auth, body: unknown, signal?: AbortSignal): Promise<T> {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { ...v1Headers(auth), \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\n/** v1 write helpers. `request`/`post` predate these; same auth, other verbs. */\nasync function sendV1<T>(\n method: \"PUT\" | \"PATCH\" | \"DELETE\",\n url: string,\n auth: V1Auth,\n body?: unknown,\n signal?: AbortSignal,\n): Promise<T> {\n const headers: Record<string, string> = v1Headers(auth);\n const init: RequestInit = { method, headers, signal };\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n init.body = JSON.stringify(body);\n }\n const res = await fetch(url, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function postEmbed<T>(\n url: string,\n campKey: string,\n body: unknown,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = {\n \"X-Camp-Key\": campKey,\n \"Content-Type\": \"application/json\",\n };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: opts?.signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function putEmbed<T>(\n url: string,\n campKey: string,\n body: unknown,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = {\n \"X-Camp-Key\": campKey,\n \"Content-Type\": \"application/json\",\n };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), {\n method: \"PUT\",\n headers,\n body: JSON.stringify(body),\n signal: opts?.signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function deleteEmbed<T>(\n url: string,\n campKey: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = { \"X-Camp-Key\": campKey };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), { method: \"DELETE\", headers, signal: opts?.signal });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\n/**\n * Bearer-only helper for /api/embed/v1/admin/* (PLA-489). The admin token is\n * the sole credential (no X-Camp-Key — orgId comes from the JWT claims\n * server-side). `method` can be GET, POST, PATCH, or PUT; `body` is optional\n * (omitted for GET reads like getAnnotations).\n */\nasync function adminEmbed<T>(\n method: \"GET\" | \"POST\" | \"PATCH\" | \"PUT\",\n url: string,\n accessToken: string,\n body?: unknown,\n signal?: AbortSignal,\n): Promise<T> {\n const headers: Record<string, string> = { Authorization: `Bearer ${accessToken}` };\n const init: RequestInit = { method, headers, signal };\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n init.body = JSON.stringify(body);\n }\n const res = await fetch(url, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nexport class PlayaOSClient {\n private readonly baseUrl: string;\n private readonly embedBaseUrl: string;\n private readonly apiKey: string;\n private readonly memberToken: string | undefined;\n\n constructor(opts: ClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n this.embedBaseUrl = (opts.embedBaseUrl ?? opts.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = opts.apiKey;\n this.memberToken = opts.memberToken;\n }\n\n /** Credentials for /api/v1 calls; the embed surface uses `apiKey` alone as the camp key. */\n private get auth(): V1Auth {\n return { apiKey: this.apiKey, memberToken: this.memberToken };\n }\n\n /**\n * Derive a client that acts as one member (PLA-1195): same host and org key,\n * plus the member's Supabase session JWT on every /api/v1 call. Use this in a\n * server that holds one org key and serves many signed-in members.\n */\n withMember(memberToken: string): PlayaOSClient {\n return new PlayaOSClient({\n baseUrl: this.baseUrl,\n embedBaseUrl: this.embedBaseUrl,\n apiKey: this.apiKey,\n memberToken,\n });\n }\n\n /**\n * Admin dual-path (PLA-1203): when the client has a memberToken, call `/api/v1`\n * (org key + X-PlayaOS-Member-Token). Otherwise keep the legacy embed-admin\n * Bearer-JWT path so published consumers without withMember() still work.\n */\n private adminV1OrEmbed<T>(\n method: \"GET\" | \"POST\" | \"PATCH\" | \"PUT\",\n v1Path: string,\n embedPath: string,\n accessToken: string,\n body?: unknown,\n signal?: AbortSignal,\n ): Promise<T> {\n if (this.memberToken) {\n const url = buildUrl(this.baseUrl, v1Path);\n if (method === \"GET\") return request(url, this.auth, signal);\n if (method === \"POST\") return post(url, this.auth, body ?? {}, signal);\n return sendV1(method, url, this.auth, body, signal);\n }\n return adminEmbed(method, buildEmbedUrl(this.embedBaseUrl, embedPath), accessToken, body, signal);\n }\n\n /** Resolve admin credential: memberToken clients skip accessToken; embed path requires it. */\n private adminAccess(opts?: { accessToken?: string; signal?: AbortSignal }): {\n accessToken: string;\n signal?: AbortSignal;\n } {\n if (this.memberToken) {\n return { accessToken: opts?.accessToken ?? \"\", signal: opts?.signal };\n }\n if (!opts?.accessToken) {\n throw new Error(\"accessToken is required; call withMember(token) or pass { accessToken }\");\n }\n return { accessToken: opts.accessToken, signal: opts.signal };\n }\n\n readonly members = {\n /** Presigned profile-photo upload (PLA-1263). PUT the bytes, then setPhoto. */\n createPhotoUploadUrl: (\n payload: { contentType: \"image/jpeg\" | \"image/png\" | \"image/webp\" },\n opts?: { signal?: AbortSignal },\n ): Promise<{ uploadUrl: string; path: string; token: string; key: string }> =>\n post(buildUrl(this.baseUrl, \"/members/me/photo/upload-url\"), this.auth, payload, opts?.signal),\n\n setPhoto: (payload: { key: string }, opts?: { signal?: AbortSignal }): Promise<{ avatarUrl: string }> =>\n post(buildUrl(this.baseUrl, \"/members/me/photo\"), this.auth, payload, opts?.signal),\n\n deletePhoto: (opts?: { signal?: AbortSignal }): Promise<{ success: boolean }> =>\n sendV1(\"DELETE\", buildUrl(this.baseUrl, \"/members/me/photo\"), this.auth, {}, opts?.signal),\n\n /** Active push device tokens for the acting member (PLA-1261). */\n listDevices: (opts?: { signal?: AbortSignal }): Promise<MemberDevice[]> =>\n request<{ devices: MemberDevice[] }>(buildUrl(this.baseUrl, \"/members/devices\"), this.auth, opts?.signal).then(\n (r) => r.devices,\n ),\n\n registerDevice: (\n payload: { token: string; platform: \"ios\" | \"android\"; environment?: \"sandbox\" | \"production\" },\n opts?: { signal?: AbortSignal },\n ): Promise<{ id: string; registered: boolean }> =>\n post(buildUrl(this.baseUrl, \"/members/devices\"), this.auth, payload, opts?.signal),\n\n deleteDevice: (payload: { token: string }, opts?: { signal?: AbortSignal }): Promise<{ unregistered: boolean }> =>\n sendV1(\"DELETE\", buildUrl(this.baseUrl, \"/members/devices\"), this.auth, payload, opts?.signal),\n\n /** The acting member's communication + (admin) notification preferences (PLA-1262). */\n getPreferences: (opts?: { signal?: AbortSignal }): Promise<MemberPreferences> =>\n request(buildUrl(this.baseUrl, \"/members/me/preferences\"), this.auth, opts?.signal),\n\n updatePreferences: (\n payload: { emailMarketingOptIn: boolean; adminNotifications?: AdminNotificationPrefs },\n opts?: { signal?: AbortSignal },\n ): Promise<MemberPreferences> =>\n sendV1(\"PATCH\", buildUrl(this.baseUrl, \"/members/me/preferences\"), this.auth, payload, opts?.signal),\n\n list: (\n params?: { role?: MemberRole; status?: string } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Member>> => request(buildUrl(this.baseUrl, \"/members\", params), this.auth, opts?.signal),\n\n /**\n * Full profile (phone, emergency contact). Requires a member token; pass\n * `\"me\"` for the acting member — non-admins may fetch only themselves.\n */\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Member> =>\n request(buildUrl(this.baseUrl, `/members/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n /** Member-self profile update (PLA-700 / PLA-1203). Prefers v1 when memberToken is set. */\n selfUpdate: (\n payload: {\n bio?: string | null;\n playaName?: string | null;\n socialMedia?: Record<string, unknown> | null;\n showSocialsInDirectory?: boolean;\n phone?: string | null;\n emergencyContactName?: string | null;\n emergencyContactRelationship?: string | null;\n emergencyContactPhone?: string | null;\n profilePhotoPath?: string | null;\n yearJoined?: number | null;\n },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ profileId: string }> =>\n this.memberToken\n ? sendV1(\"PUT\", buildUrl(this.baseUrl, \"/members/me\"), this.auth, payload, opts.signal)\n : putEmbed(buildEmbedUrl(this.embedBaseUrl, \"/members/self\"), this.apiKey, payload, opts),\n\n /** Member-self shift signup + cancel (PLA-705 / PLA-1203). Prefers v1 when memberToken is set. */\n shifts: {\n signup: async (\n payload: { shiftId: string; role?: string },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ signupId: string; waitlisted: boolean }> => {\n if (this.memberToken) {\n const assigned = await post<{ id: string; shiftId: string; memberId: string; waitlisted?: boolean }>(\n buildUrl(this.baseUrl, `/shifts/${encodeURIComponent(payload.shiftId)}/assign`),\n this.auth,\n { role: payload.role },\n opts.signal,\n );\n return { signupId: assigned.id, waitlisted: assigned.waitlisted ?? false };\n }\n return postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/shifts/signup\"), this.apiKey, payload, opts);\n },\n cancel: (\n signupId: string,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ canceled: boolean; promotedSignupId: string | null }> =>\n this.memberToken\n ? sendV1(\n \"DELETE\",\n buildUrl(this.baseUrl, `/shifts/signups/${encodeURIComponent(signupId)}`),\n this.auth,\n undefined,\n opts.signal,\n )\n : deleteEmbed(\n buildEmbedUrl(this.embedBaseUrl, `/shifts/signups/${encodeURIComponent(signupId)}`),\n this.apiKey,\n opts,\n ),\n },\n };\n\n readonly applications = {\n list: (\n params?: { status?: ApplicationStatus; year?: number } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Application>> =>\n request(buildUrl(this.baseUrl, \"/applications\", params), this.auth, opts?.signal),\n\n // Anonymous external-camp submission against POST /api/embed/v1/applications\n // (PLA-481). Uses the X-Camp-Key header rather than Bearer auth. Pass\n // `accessToken` to additionally send a PlayaOS IdP JWT (PLA-573 path) so\n // the server trusts the verified profile claim and skips the email-based\n // bootstrap.\n create: (\n payload: ApplicationCreatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationCreateResponse> =>\n postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/applications\"), this.apiKey, payload, opts),\n };\n\n readonly waivers = {\n /** Get the active waiver for an org for the current year. */\n active: (orgId: string, opts?: { signal?: AbortSignal }): Promise<Waiver> =>\n getEmbed(buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/active`), this.apiKey, opts?.signal),\n\n /** Sign a waiver. Requires X-Camp-Key; optional accessToken for Bearer path. */\n sign: (\n payload: WaiverSignPayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<WaiverSignResponse> =>\n postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/waivers/sign\"), this.apiKey, payload, opts),\n\n /** Has this applicant/member signed the active waiver? Anchor: applicationId query or Bearer accessToken. */\n status: (\n orgId: string,\n opts?: { applicationId?: string; accessToken?: string; signal?: AbortSignal },\n ): Promise<WaiverStatus> => {\n const query = opts?.applicationId ? `?applicationId=${encodeURIComponent(opts.applicationId)}` : \"\";\n return getEmbedAuthed(buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/status${query}`), this.apiKey, opts);\n },\n\n /** Get a short-lived download URL for a completed signature's PDF. Anchor: applicationId query or Bearer. */\n signedPdf: (\n orgId: string,\n signatureId: string,\n opts?: { applicationId?: string; accessToken?: string; signal?: AbortSignal },\n ): Promise<{ url: string }> => {\n const query = opts?.applicationId ? `?applicationId=${encodeURIComponent(opts.applicationId)}` : \"\";\n return getEmbedAuthed(\n buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/signatures/${encodeURIComponent(signatureId)}/pdf${query}`),\n this.apiKey,\n opts,\n );\n },\n };\n\n readonly dues = {\n list: (\n params?: { userId?: string; year?: number; paymentStatus?: \"unpaid\" | \"partial\" | \"paid\" } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<DuesStatus>> => request(buildUrl(this.baseUrl, \"/dues\", params), this.auth, opts?.signal),\n };\n\n readonly shifts = {\n list: (\n params?: {\n year?: number;\n fromDate?: string;\n toDate?: string;\n publishedOnly?: boolean;\n openOnly?: boolean;\n } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Shift>> => request(buildUrl(this.baseUrl, \"/shifts\", params), this.auth, opts?.signal),\n };\n\n readonly org = {\n get: (opts?: { signal?: AbortSignal }): Promise<OrgConfig> =>\n request(buildUrl(this.baseUrl, \"/org\"), this.auth, opts?.signal),\n };\n\n // Public embed surface: active commitment definitions for the org's current\n // year, so the <ApplicationForm> can render + validate them (PLA-682). Uses\n // the X-Camp-Key (the apiKey doubles as the camp key), same as applications.create.\n readonly commitments = {\n list: (opts?: { signal?: AbortSignal }): Promise<CommitmentsListResponse> =>\n getEmbed(buildEmbedUrl(this.embedBaseUrl, \"/commitments\"), this.apiKey, opts?.signal),\n };\n\n readonly payments = {\n list: (\n params?: {\n type?: \"dues\" | \"payment\";\n memberId?: string;\n from?: string;\n to?: string;\n limit?: number;\n offset?: number;\n },\n opts?: { signal?: AbortSignal },\n ): Promise<PaymentLedgerRow[]> => request(buildUrl(this.baseUrl, \"/payments\", params), this.auth, opts?.signal),\n\n /** Requires a member token. `memberId` may be omitted by a non-admin (defaults to themselves); admins must pass it. */\n page: (\n memberId?: string,\n duesCollectionId?: string,\n opts?: { signal?: AbortSignal },\n ): Promise<PaymentPageResponse> =>\n post(buildUrl(this.baseUrl, \"/payments/page\"), this.auth, { memberId, duesCollectionId }, opts?.signal),\n };\n\n readonly accounts = {\n list: (params?: { limit?: number; offset?: number }, opts?: { signal?: AbortSignal }): Promise<Account[]> =>\n request(buildUrl(this.baseUrl, \"/accounts\", params), this.auth, opts?.signal),\n };\n\n readonly contacts = {\n list: (\n params?: {\n role?: MemberRole;\n status?: string;\n search?: string;\n sort?: \"name\" | \"email\";\n limit?: number;\n offset?: number;\n },\n opts?: { signal?: AbortSignal },\n ): Promise<Contact[]> => request(buildUrl(this.baseUrl, \"/contacts\", params), this.auth, opts?.signal),\n };\n\n readonly notifications = {\n /** Set the acting member's notification high-water mark to now (PLA-1261). */\n markSeen: (opts?: { signal?: AbortSignal }): Promise<{ seenAt: string }> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/notifications/seen\"), this.auth, {}, opts?.signal),\n\n list: (\n params?: { category?: string; status?: string; recipientId?: string; limit?: number },\n opts?: { signal?: AbortSignal },\n ): Promise<NotificationLog[]> => request(buildUrl(this.baseUrl, \"/notifications\", params), this.auth, opts?.signal),\n };\n\n readonly documents = {\n list: (params?: { type?: string; year?: number }, opts?: { signal?: AbortSignal }): Promise<CampDocument[]> =>\n request(buildUrl(this.baseUrl, \"/documents\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<CampDocument> =>\n request(buildUrl(this.baseUrl, `/documents/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n };\n\n readonly shelters = {\n list: (\n params?: { ownerId?: string; shelterType?: string; year?: number },\n opts?: { signal?: AbortSignal },\n ): Promise<Shelter[]> => request(buildUrl(this.baseUrl, \"/shelters\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Shelter> =>\n request(buildUrl(this.baseUrl, `/shelters/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n };\n\n readonly bikes = {\n list: (params?: { status?: string }, opts?: { signal?: AbortSignal }): Promise<Bike[]> =>\n request(buildUrl(this.baseUrl, \"/bikes\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Bike> =>\n request(buildUrl(this.baseUrl, `/bikes/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n /**\n * Cancel an in-house fleet rental owned by the acting member (PLA-1232).\n * Requires a member token. 404 when missing, not owned, or not cancellable.\n */\n cancelRental: (rentalId: string, opts?: { signal?: AbortSignal }): Promise<{ cancelled: true }> =>\n sendV1(\n \"DELETE\",\n buildUrl(this.baseUrl, `/members/bikes/${encodeURIComponent(rentalId)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n };\n\n /**\n * DustJunkie bike rentals (PLA-1180), passed through to the vendor. A camp\n * without the integration gets 403; a DustJunkie failure is a 502.\n */\n readonly bikeRentals = {\n /** Bookable options with estimated totals for `delivery` (server default `camp_delivery`). Org key only. */\n catalog: (\n params?: { delivery?: BikeRentalDeliveryMode },\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalCatalogResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/catalog\", params), this.auth, opts?.signal),\n\n /** The rental agreement the member must accept before `requestReservation`. Org key only. */\n waiver: (opts?: { signal?: AbortSignal }): Promise<BikeRentalWaiver> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/waiver\"), this.auth, opts?.signal),\n\n /**\n * Requires a member token. Admins get the whole camp when `memberId` is\n * omitted; any other role gets their own reservations and 403 naming someone else.\n */\n reservations: (\n params?: { memberId?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalReservationListResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/reservations\", params), this.auth, opts?.signal),\n\n /**\n * Requires a member token; always requests for the acting member. 409 when\n * the model is sold out, 400 when it is unknown or no longer bookable.\n */\n requestReservation: (\n payload: BikeRentalRequestInput,\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalRequestResult> =>\n post(buildUrl(this.baseUrl, \"/bike-rentals/requests\"), this.auth, payload, opts?.signal),\n\n /** Members who said they want a bike but have no reservation, for the active camp year. Org key only. */\n interestedNotReserved: (opts?: { signal?: AbortSignal }): Promise<BikeRentalInterestedNotReservedResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/interested-not-reserved\"), this.auth, opts?.signal),\n };\n\n readonly tags = {\n list: (opts?: { signal?: AbortSignal }): Promise<MemberTag[]> =>\n request(buildUrl(this.baseUrl, \"/tags\"), this.auth, opts?.signal),\n };\n\n readonly groups = {\n list: (opts?: { signal?: AbortSignal }): Promise<MemberGroup[]> =>\n request(buildUrl(this.baseUrl, \"/groups\"), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<MemberGroupRosterRow[]> =>\n request(buildUrl(this.baseUrl, `/groups/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n create: (\n payload: { name: string; leaderProfileId: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ id: string }> => post(buildUrl(this.baseUrl, \"/groups\"), this.auth, payload, opts?.signal),\n };\n\n /**\n * Camp-scoped packing (PLA-1197). Every method is the acting member's own\n * list — packing has no `memberId` to widen, so these require `memberToken`\n * and 401 on an org key alone.\n */\n readonly packing = {\n /** The resolved list: curated base + camp layer + personal layer (ADR-071). */\n list: (\n params?: { year?: number; shelter?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<PackingListResponse> => request(buildUrl(this.baseUrl, \"/packing\", params), this.auth, opts?.signal),\n\n /**\n * Set the member's status for one item. The slug goes in the body, not the\n * path: slugs are `${category}/${name}` and contain a `/`.\n *\n * Pass the same `shelter` the list was read under — validation filters by\n * shelter, so an override omitted here rejects shelter-specific items.\n */\n setStatus: (\n payload: { slug: string; status: PackingItemStatus; year?: number; shelter?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ ok: true }> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/packing/items/status\"), this.auth, payload, opts?.signal),\n\n personalItems: {\n list: (\n params?: { containerId?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ items: PackingPersonalItem[] }> =>\n request(buildUrl(this.baseUrl, \"/packing/personal-items\", params), this.auth, opts?.signal),\n\n create: (\n payload: { name: string; category: string; qty?: number; unit?: string | null; notes?: string | null },\n opts?: { signal?: AbortSignal },\n ): Promise<{ id: string }> =>\n post(buildUrl(this.baseUrl, \"/packing/personal-items\"), this.auth, payload, opts?.signal),\n\n /**\n * Flip the item between `need` and `have`. It does **not** set `packed` —\n * use `setStatus` for the full vocabulary. 404 if the item is not the\n * acting member's.\n */\n toggle: (id: string, opts?: { signal?: AbortSignal }): Promise<{ ok: true }> =>\n sendV1(\n \"PATCH\",\n buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n\n /** 404 if the item is not the acting member's. */\n remove: (id: string, opts?: { signal?: AbortSignal }): Promise<{ ok: true }> =>\n sendV1(\n \"DELETE\",\n buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n },\n\n /**\n * Camp packing layer (PLA-1204). Admin/super_admin only — non-admins get 403.\n * Identity is the published slug (`overrides_slug` or `camp:<uuid>`).\n */\n campItems: {\n list: (opts?: { signal?: AbortSignal }): Promise<{ items: PackingCampItem[] }> =>\n request(buildUrl(this.baseUrl, \"/packing/camp-items\"), this.auth, opts?.signal),\n\n upsert: (payload: UpsertPackingCampItemInput, opts?: { signal?: AbortSignal }): Promise<PackingCampItem> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/packing/camp-items\"), this.auth, payload, opts?.signal),\n },\n };\n\n /**\n * SAP — Special Access Pass, for early/overnight vehicle arrival (PLA-1202).\n * Admin/super_admin only; there is no member-facing SAP surface. Year is\n * always the org's active camp year — the server derives it, callers never\n * pass one.\n */\n readonly sap = {\n allocation: {\n get: (opts?: { signal?: AbortSignal }): Promise<SapAllocation> =>\n request(buildUrl(this.baseUrl, \"/sap/allocation\"), this.auth, opts?.signal),\n\n update: (payload: UpdateSapAllocationInput, opts?: { signal?: AbortSignal }): Promise<SapAllocation> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/sap/allocation\"), this.auth, payload, opts?.signal),\n },\n\n dayAllocations: {\n list: (opts?: { signal?: AbortSignal }): Promise<{ items: SapDayAllocation[] }> =>\n request(buildUrl(this.baseUrl, \"/sap/day-allocations\"), this.auth, opts?.signal),\n\n /** Upserts by (active year, accessDate); 409 on a cross-org date collision. */\n upsert: (payload: UpsertSapDayAllocationInput, opts?: { signal?: AbortSignal }): Promise<SapDayAllocation> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/sap/day-allocations\"), this.auth, payload, opts?.signal),\n },\n\n assignments: {\n list: (opts?: { signal?: AbortSignal }): Promise<{ items: SapAssignment[] }> =>\n request(buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, opts?.signal),\n\n create: (payload: CreateSapAssignmentInput, opts?: { signal?: AbortSignal }): Promise<SapAssignment> =>\n post(buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, payload, opts?.signal),\n\n update: (payload: UpdateSapAssignmentInput, opts?: { signal?: AbortSignal }): Promise<SapAssignment> =>\n sendV1(\"PATCH\", buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, payload, opts?.signal),\n\n remove: (assignmentId: string, opts?: { signal?: AbortSignal }): Promise<{ ok: true }> =>\n sendV1(\"DELETE\", buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, { assignmentId }, opts?.signal),\n },\n };\n\n // Org-level reads (PLA-1268): API key + org scopes, no member token.\n readonly importantDates = {\n /** Visible camp dates (PLA-1268), optionally pinned to a year. */\n list: (params?: { year?: number }, opts?: { signal?: AbortSignal }): Promise<ImportantDate[]> =>\n request(buildUrl(this.baseUrl, \"/important-dates\", params), this.auth, opts?.signal),\n };\n\n readonly emails = {\n /** Admin template registry (PLA-1265). */\n listTemplates: (opts?: { signal?: AbortSignal }): Promise<EmailTemplate[]> =>\n request<{ data: EmailTemplate[] }>(buildUrl(this.baseUrl, \"/email/templates\"), this.auth, opts?.signal).then(\n (r) => r.data,\n ),\n\n /** Render-only template preview, as HTML (PLA-1265). */\n previewTemplate: (id: string, opts?: { signal?: AbortSignal }): Promise<string> =>\n post<{ html: string }>(\n buildUrl(this.baseUrl, `/email/templates/${encodeURIComponent(id)}/preview`),\n this.auth,\n {},\n opts?.signal,\n ).then((r) => r.html),\n\n /** Admin email retry state + per-status counts (PLA-1265). */\n listRetries: (\n params?: { status?: string; recipient?: string; from?: string; to?: string; limit?: number; offset?: number },\n opts?: { signal?: AbortSignal },\n ): Promise<EmailRetryListResponse> =>\n request<EmailRetryListResponse>(buildUrl(this.baseUrl, \"/email/retries\", params), this.auth, opts?.signal),\n };\n\n readonly onboarding = {\n /** Tick a checklist item for the acting member (PLA-1259). */\n setProgress: (\n itemId: string,\n payload: { completed: boolean; year?: number },\n opts?: { signal?: AbortSignal },\n ): Promise<OnboardingProgress> =>\n sendV1(\n \"PUT\",\n buildUrl(this.baseUrl, `/onboarding/progress/${encodeURIComponent(itemId)}`),\n this.auth,\n payload,\n opts?.signal,\n ),\n };\n\n // Admin write APIs (PLA-489). Each method requires `accessToken` — a Supabase\n // JWT for a camp admin/super_admin. The org boundary is enforced server-side\n // from the JWT claims; these endpoints do not use the X-Camp-Key.\n readonly admin = {\n applications: {\n /**\n * Admin-scoped application detail (PLA-1269): the member-safe shape plus\n * admin-managed metadata (tags, referral, assigned interviewer, review\n * timestamp). v1-only — requires a member token (`withMember`).\n */\n getDetail: (id: string, opts?: { signal?: AbortSignal }): Promise<ApplicationAdmin> => {\n if (!this.memberToken) {\n throw new Error(\"applications.getDetail requires withMember(token)\");\n }\n return request(\n buildUrl(this.baseUrl, `/admin/applications/${encodeURIComponent(id)}`),\n this.auth,\n opts?.signal,\n );\n },\n /**\n * Get application audit timeline (PLA-712). Requires admin Bearer token.\n *\n * @deprecated The embed handler for this method never existed — calls\n * always 404'd (see PLA-1199). Retained as a compile-time compatibility\n * surface for published-consumer code; delegates to the canonical\n * `GET /api/v1/audit/application-logs?applicationId=` (ADR-054), which\n * reads the same `application_audit_logs` table. The `accessToken`\n * argument is accepted but unused — the v1 surface authenticates with\n * the org API key (`audit:read` scope) instead of an admin JWT. Remove\n * in the next major version.\n */\n history: async (\n id: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationHistoryResponse> => {\n type AuditRow = {\n id: string;\n applicationId: string;\n actorUserId: string | null;\n action: string;\n details: Record<string, unknown> | null;\n createdAt: string | null;\n };\n\n // The old embed shape returned the whole timeline in one object, so the\n // cursor has to be followed here — returning only the first 100 rows\n // would silently truncate long-running applications.\n const rows: AuditRow[] = [];\n let cursor: string | null = null;\n do {\n const page: Paginated<AuditRow> = await request<Paginated<AuditRow>>(\n buildUrl(this.baseUrl, \"/audit/application-logs\", {\n applicationId: id,\n limit: 100,\n ...(cursor ? { cursor } : {}),\n }),\n this.auth,\n opts?.signal,\n );\n rows.push(...page.data);\n cursor = page.nextCursor;\n } while (cursor);\n\n return {\n events: rows.map((row) => ({\n id: row.id,\n applicationId: row.applicationId,\n actorId: row.actorUserId,\n actorName: null,\n type: (row.action === \"status_changed\" ? \"status_change\" : row.action) as ApplicationEvent[\"type\"],\n timestamp: row.createdAt ?? \"\",\n metadata: row.details ?? undefined,\n })),\n };\n },\n transition: (\n id: string,\n payload: ApplicationTransitionPayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationTransitionResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/applications/${encodeURIComponent(id)}`,\n `/admin/applications/${encodeURIComponent(id)}`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n getAnnotations: (\n id: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationAnnotations> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/applications/${encodeURIComponent(id)}/annotations`,\n `/admin/applications/${encodeURIComponent(id)}/annotations`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n addNote: (\n id: string,\n payload: { body: string },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationNote> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/applications/${encodeURIComponent(id)}/notes`,\n `/admin/applications/${encodeURIComponent(id)}/notes`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n setTags: (\n id: string,\n payload: { tags: string[] },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<string[]> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/applications/${encodeURIComponent(id)}/tags`,\n `/admin/applications/${encodeURIComponent(id)}/tags`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n setScore: (\n id: string,\n payload: { value: number },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationScore> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/applications/${encodeURIComponent(id)}/scores`,\n `/admin/applications/${encodeURIComponent(id)}/scores`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n givebutter: {\n campaigns: {\n list: (opts?: { accessToken?: string; signal?: AbortSignal }): Promise<unknown[]> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n \"/givebutter/campaigns\",\n \"/admin/givebutter/campaigns\",\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n discountCodes: {\n list: (campaignId: number, opts?: { accessToken?: string; signal?: AbortSignal }): Promise<unknown[]> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/givebutter/campaigns/${campaignId}/discount-codes`,\n `/admin/givebutter/campaigns/${campaignId}/discount-codes`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n create: (\n campaignId: number,\n payload: { code: string; value: number; type: \"percent\" | \"fixed\"; expirationDate?: string },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<unknown> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/givebutter/campaigns/${campaignId}/discount-codes`,\n `/admin/givebutter/campaigns/${campaignId}/discount-codes`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n tickets: {\n create: (\n campaignId: number,\n payload: { name: string; price: number; totalQuantity?: number },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<unknown> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/givebutter/campaigns/${campaignId}/tickets`,\n `/admin/givebutter/campaigns/${campaignId}/tickets`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n },\n },\n members: {\n create: (\n payload: MemberCreatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<MemberCreateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\"POST\", \"/members\", \"/admin/members\", accessToken, payload, signal))(\n this.adminAccess(opts),\n ),\n\n update: (\n id: string,\n patch: MemberUpdatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<MemberUpdateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/members/${encodeURIComponent(id)}`,\n `/admin/members/${encodeURIComponent(id)}`,\n accessToken,\n patch,\n signal,\n ))(this.adminAccess(opts)),\n\n deactivate: (\n id: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<MemberDeactivateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/members/${encodeURIComponent(id)}`,\n `/admin/members/${encodeURIComponent(id)}`,\n accessToken,\n { status: \"inactive\" },\n signal,\n ))(this.adminAccess(opts)),\n },\n announcements: {\n /** Send an email blast to camp members (PLA-706). Requires admin Bearer token. */\n send: (\n payload: AnnouncementSendPayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<AnnouncementSendResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n \"/announcements/send\",\n \"/admin/announcements/send\",\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n dues: {\n /** Create a manual dues/payment record (PLA-708). Requires admin Bearer token. */\n create: (\n payload: DuesCreatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<DuesCreateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\"POST\", \"/dues\", \"/admin/dues\", accessToken, payload, signal))(this.adminAccess(opts)),\n\n /** Update a dues/payment record (PLA-708). Requires admin Bearer token. */\n update: (\n id: string,\n payload: DuesUpdatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<DuesUpdateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/dues/${encodeURIComponent(id)}`,\n `/admin/dues/${encodeURIComponent(id)}`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n org: {\n /** Update camp configuration settings (PLA-709). Requires admin Bearer token. */\n update: (\n payload: OrgUpdatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<OrgUpdateResponse> =>\n (({ accessToken, signal }) => this.adminV1OrEmbed(\"PATCH\", \"/org\", \"/admin/org\", accessToken, payload, signal))(\n this.adminAccess(opts),\n ),\n },\n scheduling: {\n availability: {\n /** Get interview availability for an interviewer (PLA-713). Requires admin Bearer token. */\n get: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<GetAvailabilityResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n /** Set interview availability for an interviewer (PLA-713). Requires admin Bearer token. */\n set: (\n interviewerId: string,\n payload: SetAvailabilityInput,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<SetAvailabilityResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n calendar: {\n /** Get Google Calendar connection status for an interviewer (PLA-726). Requires admin Bearer. */\n status: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<CalendarStatus> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/status`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/status`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n /** List available Google Calendars (PLA-726). Requires admin Bearer. */\n listCalendars: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<{ calendars: GoogleCalendar[] }> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/calendars`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/calendars`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n /** Select which Google Calendar to use (PLA-726). Requires admin Bearer. */\n select: (\n interviewerId: string,\n payload: SelectCalendarInput,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<{ calendarId: string }> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/select`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/select`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n /** Disconnect Google Calendar from interviewer (PLA-726). Requires admin Bearer. */\n disconnect: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<{ disconnected: boolean }> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/disconnect`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/disconnect`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n },\n bookingTokens: {\n /** Create a booking token for an application's interview link (PLA-714). Requires admin Bearer token. */\n create: (\n payload: CreateBookingTokenInput,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<BookingToken> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\"POST\", \"/booking-tokens\", \"/admin/booking-tokens\", accessToken, payload, signal))(\n this.adminAccess(opts),\n ),\n /** Get an existing booking token for an application (PLA-714). Requires admin Bearer token. */\n get: (applicationId: string, opts?: { accessToken?: string; signal?: AbortSignal }): Promise<BookingToken> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/booking-tokens/${encodeURIComponent(applicationId)}`,\n `/admin/booking-tokens/${encodeURIComponent(applicationId)}`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n },\n },\n };\n\n // Public embed-booking endpoints (PLA-714). No auth — these are the\n // applicant-facing schedule surface using the hashed booking token.\n readonly schedule = {\n /** List available interview slots for a booking token (PLA-714). Public. */\n getSlots: (\n token: string,\n opts?: { signal?: AbortSignal },\n ): Promise<{ slots: { startsAt: string; endsAt: string }[] }> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}`;\n return fetch(url, { signal: opts?.signal }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<{ slots: { startsAt: string; endsAt: string }[] }>;\n });\n },\n /** Book an interview slot (PLA-714). Public. */\n book: (token: string, payload: BookSlotInput, opts?: { signal?: AbortSignal }): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/book`;\n return fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: opts?.signal,\n }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n /** Cancel an interview booking (PLA-714). Public. */\n cancel: (token: string, opts?: { signal?: AbortSignal }): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/cancel`;\n return fetch(url, { method: \"POST\", signal: opts?.signal }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n /** Reschedule an interview booking (PLA-714). Public. */\n reschedule: (\n token: string,\n payload: RescheduleInput,\n opts?: { signal?: AbortSignal },\n ): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/reschedule`;\n return fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: opts?.signal,\n }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n };\n}\n\n/** Convenience factory — equivalent to `new PlayaOSClient(opts)`. */\nexport function createClient(opts: ClientOptions): PlayaOSClient {\n return new PlayaOSClient(opts);\n}\n","/**\n * Server-side OAuth-code → ID-token exchange.\n *\n * Swaps a one-time authorization code from the PlayaOS IdP for a short-lived\n * ID token. Confidential clients pass `clientSecret`, which is sent to the\n * token endpoint server-side. Public/PKCE-only clients omit it — the\n * authorization-code + code_verifier pair is the sole credential. Public\n * clients can also exchange directly from the browser via `usePlayaOSAuth`\n * in `@playaos/react`.\n */\n\nexport interface ExchangeParams {\n authBaseUrl?: string;\n code: string;\n codeVerifier: string;\n clientId: string;\n /** Confidential clients only. Omit for public/PKCE-only clients. */\n clientSecret?: string;\n redirectUri: string;\n}\n\nexport interface ExchangeResult {\n idToken: string;\n expiresAt: string;\n /** Confidential clients only. Undefined for public clients. */\n refreshToken?: string;\n}\n\nexport async function exchangeCode(params: ExchangeParams): Promise<ExchangeResult> {\n const base = params.authBaseUrl ?? \"https://auth.playaos.app\";\n // A confidential client is identified by passing clientSecret at all — even an\n // empty string. We forward it as-is so the server validates it (an empty or\n // wrong secret is rejected there); public clients omit the field entirely.\n const isConfidential = params.clientSecret !== undefined;\n const res = await fetch(`${base}/api/auth/v1/exchange`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n code: params.code,\n code_verifier: params.codeVerifier,\n client_id: params.clientId,\n ...(isConfidential ? { client_secret: params.clientSecret } : {}),\n redirect_uri: params.redirectUri,\n }),\n });\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n throw new Error(`Exchange failed: non-JSON response (${res.status})`);\n }\n\n if (!res.ok) {\n const errorReason =\n typeof body === \"object\" && body !== null && \"error\" in body && typeof body.error === \"string\"\n ? body.error\n : String(res.status);\n throw new Error(`Exchange failed: ${errorReason}`);\n }\n\n if (\n typeof body !== \"object\" ||\n body === null ||\n !(\"idToken\" in body) ||\n typeof body.idToken !== \"string\" ||\n !(\"expiresAt\" in body) ||\n typeof body.expiresAt !== \"string\"\n ) {\n throw new Error(\"Exchange failed: malformed success response\");\n }\n\n // The server mints a refresh token only for confidential clients (it sets\n // `withRefreshToken: client.type === \"confidential\"`); public clients get\n // none. Surface it when present, otherwise leave it undefined.\n const refreshToken = \"refreshToken\" in body && typeof body.refreshToken === \"string\" ? body.refreshToken : undefined;\n\n // A confidential client that gets no refresh token means the server response\n // is malformed or the rotation flow is broken — surface it rather than\n // silently returning a result the caller can't refresh.\n if (isConfidential && refreshToken === undefined) {\n throw new Error(\"Exchange failed: confidential client response missing refreshToken\");\n }\n\n return {\n idToken: body.idToken,\n expiresAt: body.expiresAt,\n ...(refreshToken !== undefined ? { refreshToken } : {}),\n };\n}\n","import { parseError } from \"./error.js\";\n\n/** A listing holds at most this many images (matches the DB's position 1–6 check). */\nexport const MAX_IMAGE_POSITION = 6;\n\n/**\n * Typed client for the anonymous gift-layer marketplace API (`/api/public/marketplace/*`).\n *\n * Unlike `PlayaOSClient` (api-key auth for `/api/v1`), this surface authenticates\n * writes with a Supabase **Bearer JWT** belonging to a public `global_accounts`\n * user. The token is supplied by an injected `getToken` provider so the same\n * client works from any consumer (the marketing UI supplies the browser\n * Supabase session token; a future surface could supply its own). Keeps the\n * public API as the single write contract — the UI is just another consumer.\n */\nexport interface PublicMarketplaceClientOptions {\n /** API base, e.g. `https://api.playaos.app`. */\n baseUrl: string;\n /** Supplies the Supabase access token (Bearer) for authenticated calls; null/undefined when signed out. */\n getToken: () => Promise<string | null | undefined> | string | null | undefined;\n}\n\nexport interface NewListingInput {\n category: string;\n subcategory?: string;\n title: string;\n body: string;\n price?: number;\n location?: string;\n replyEmail: string;\n}\n\nexport interface ImageUploadTarget {\n /** Supabase signed upload URL — PUT the file bytes here. */\n uploadUrl: string;\n /** Storage path to pass back to `attachImage` once the PUT succeeds. */\n storagePath: string;\n}\n\n/** Moderation flag reasons accepted by the API (mirrors the DB enum). */\nexport type MarketplaceFlagReason = \"spam\" | \"prohibited\" | \"other\";\n\nexport interface ListingImage {\n /** Short-lived signed download URL for the image. */\n url: string;\n /** 1-based display order. */\n position: number;\n}\n\nexport interface PublicMarketplaceClient {\n /**\n * Create a listing as the signed-in account. Throws a plain `Error` when there\n * is no token (signed out), or `ApiClientError` on a non-2xx response.\n */\n createListing(input: NewListingInput, signal?: AbortSignal): Promise<{ id: string }>;\n /** Request a signed upload URL for an image on a listing the caller owns. */\n getImageUploadUrl(listingId: string, signal?: AbortSignal): Promise<ImageUploadTarget>;\n /** Attach an already-uploaded image (by storage path) to a listing at a 1–6 position. */\n attachImage(\n listingId: string,\n input: { storagePath: string; position: number },\n signal?: AbortSignal,\n ): Promise<{ id: string }>;\n /** Anonymous: list an active listing's images as short-lived signed URLs (for public display). */\n listListingImages(listingId: string, signal?: AbortSignal): Promise<{ images: ListingImage[] }>;\n /** Anonymous: batch-fetch first-image signed thumbnail URLs (listingId -> url) for browse cards. */\n listThumbnails(listingIds: string[], signal?: AbortSignal): Promise<{ thumbnails: Record<string, string> }>;\n /** Flag a listing for moderation (signed-in). Idempotent per (listing, user). */\n flagListing(listingId: string, reason: MarketplaceFlagReason, signal?: AbortSignal): Promise<{ ok: boolean }>;\n /** Contact a listing's owner (signed-in); records the reply + queues a notification email. */\n replyToListing(listingId: string, message: string | undefined, signal?: AbortSignal): Promise<{ ok: boolean }>;\n}\n\nexport function createPublicMarketplaceClient(opts: PublicMarketplaceClientOptions): PublicMarketplaceClient {\n const base = opts.baseUrl.replace(/\\/+$/, \"\");\n if (!base) {\n // An empty base would issue relative requests to the caller's own origin.\n throw new Error(\"createPublicMarketplaceClient: baseUrl is required\");\n }\n\n async function authedPost<T>(path: string, body: unknown, signal?: AbortSignal): Promise<T> {\n const token = await opts.getToken();\n if (!token) throw new Error(\"Not signed in\");\n const res = await fetch(`${base}/api/public/marketplace${path}`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}`, \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n }\n\n async function publicGet<T>(path: string, signal?: AbortSignal): Promise<T> {\n // no-store: responses carry short-lived signed URLs — never let the framework\n // (e.g. Next's fetch cache) memoize them and serve expired URLs. `cache` is a\n // valid fetch option at runtime but absent from @types/node's RequestInit,\n // so the init is typed with an intersection.\n const init: RequestInit & { cache: \"no-store\" } = { signal, cache: \"no-store\" };\n const res = await fetch(`${base}/api/public/marketplace${path}`, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n }\n\n const seg = (listingId: string) => `/listings/${encodeURIComponent(listingId)}`;\n\n return {\n createListing: (input, signal) => authedPost(\"/listings\", input, signal),\n getImageUploadUrl: (listingId, signal) => authedPost(`${seg(listingId)}/image-upload-url`, {}, signal),\n attachImage: (listingId, input, signal) => {\n // Fail fast on a misuse the API would otherwise reject with a vague 400.\n if (!Number.isInteger(input.position) || input.position < 1 || input.position > MAX_IMAGE_POSITION) {\n return Promise.reject(new Error(`attachImage: position must be 1–${MAX_IMAGE_POSITION}`));\n }\n return authedPost(`${seg(listingId)}/images`, input, signal);\n },\n listListingImages: (listingId, signal) => publicGet(`${seg(listingId)}/images`, signal),\n listThumbnails: (listingIds, signal) =>\n publicGet(`/thumbnails?ids=${encodeURIComponent(listingIds.join(\",\"))}`, signal),\n flagListing: (listingId, reason, signal) => authedPost(`${seg(listingId)}/flag`, { reason }, signal),\n replyToListing: (listingId, message, signal) => authedPost(`${seg(listingId)}/reply`, { message }, signal),\n };\n}\n"],"mappings":"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"}
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 AdminNotificationPrefs,\n AnnouncementSendPayload,\n AnnouncementSendResponse,\n Application,\n ApplicationAdmin,\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 CampDocumentDownloadUrl,\n CampDocumentSignature,\n CommitmentsListResponse,\n Contact,\n CreateBookingTokenInput,\n CreateMeetingInput,\n CreateSapAssignmentInput,\n DuesCreatePayload,\n DuesCreateResponse,\n DuesStatus,\n DuesUpdatePayload,\n DuesUpdateResponse,\n EmailRetryListResponse,\n EmailTemplate,\n GetAvailabilityResponse,\n GoogleCalendar,\n ImportantDate,\n Meeting,\n MeetingListResponse,\n Member,\n MemberCreatePayload,\n MemberCreateResponse,\n MemberDeactivateResponse,\n MemberDevice,\n MemberGroup,\n MemberGroupRosterRow,\n MemberPreferences,\n MemberRole,\n MemberTag,\n MemberUpdatePayload,\n MemberUpdateResponse,\n NotificationLog,\n OnboardingProgress,\n OrgConfig,\n OrgUpdatePayload,\n OrgUpdateResponse,\n PackingCampItem,\n PackingItemStatus,\n PackingListResponse,\n PackingPersonalItem,\n Paginated,\n PaginationParams,\n PaymentLedgerRow,\n PaymentPageResponse,\n RescheduleInput,\n SapAllocation,\n SapAssignment,\n SapDayAllocation,\n SelectCalendarInput,\n SetAvailabilityInput,\n SetAvailabilityResponse,\n Shelter,\n Shift,\n UpdateSapAllocationInput,\n UpdateSapAssignmentInput,\n UpsertPackingCampItemInput,\n UpsertSapDayAllocationInput,\n Waiver,\n WaiverSignPayload,\n WaiverSignResponse,\n WaiverStatus,\n} from \"./types.js\";\n\nexport type { ApiClientError };\n\ninterface ClientOptions {\n /** Base URL for authenticated /api/v1 routes, e.g. https://api.playaos.app */\n baseUrl: string;\n /** Optional base URL for /api/embed/v1 routes when they live on a different host. */\n embedBaseUrl?: string;\n /** API key in the format pk_live_* */\n apiKey: string;\n /**\n * Supabase session JWT of the acting member, sent as `X-PlayaOS-Member-Token`\n * on every /api/v1 call (PLA-1195). Member-scoped endpoints (a member's own\n * dues, payments, application, shelter, shifts signup, …) require it and\n * return 401 without it. Org-level endpoints do not require it, but a token\n * that is sent must still verify — an expired or invalid one is a 401 on any\n * /api/v1 route that installs the member middleware. Prefer\n * `client.withMember(token)` to derive a per-request client from a shared\n * server-side one rather than constructing a client per user.\n */\n memberToken?: string;\n}\n\n/** Credentials for /api/v1: the org key names the org, the member token names the person. */\ninterface V1Auth {\n apiKey: string;\n memberToken?: string;\n}\n\nfunction v1Headers(auth: V1Auth): Record<string, string> {\n const headers: Record<string, string> = { Authorization: `Bearer ${auth.apiKey}` };\n if (auth.memberToken) headers[\"X-PlayaOS-Member-Token\"] = auth.memberToken;\n return headers;\n}\n\nfunction buildUrl(base: string, path: string, params?: Record<string, string | number | boolean | undefined>): string {\n const url = new URL(`${base}/api/v1${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n // Skip undefined and false booleans — z.coerce.boolean() on the server uses Boolean(),\n // which treats any non-empty string (including \"false\") as true. Omitting a false boolean\n // param has the same effect as the server default (unfiltered).\n if (v !== undefined && v !== false) url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n}\n\nfunction buildEmbedUrl(base: string, path: string): string {\n return `${base}/api/embed/v1${path}`;\n}\n\nfunction withCampKey(url: string, campKey: string): string {\n const embedUrl = new URL(url);\n embedUrl.searchParams.set(\"camp_key\", campKey);\n return embedUrl.toString();\n}\n\nasync function getEmbed<T>(url: string, campKey: string, signal?: AbortSignal): Promise<T> {\n const res = await fetch(withCampKey(url, campKey), {\n headers: { \"X-Camp-Key\": campKey },\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function getEmbedAuthed<T>(\n url: string,\n campKey: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = { \"X-Camp-Key\": campKey };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), { headers, signal: opts?.signal });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function request<T>(url: string, auth: V1Auth, signal?: AbortSignal): Promise<T> {\n const res = await fetch(url, {\n headers: v1Headers(auth),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function post<T>(url: string, auth: V1Auth, body: unknown, signal?: AbortSignal): Promise<T> {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { ...v1Headers(auth), \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\n/** v1 write helpers. `request`/`post` predate these; same auth, other verbs. */\nasync function sendV1<T>(\n method: \"PUT\" | \"PATCH\" | \"DELETE\",\n url: string,\n auth: V1Auth,\n body?: unknown,\n signal?: AbortSignal,\n): Promise<T> {\n const headers: Record<string, string> = v1Headers(auth);\n const init: RequestInit = { method, headers, signal };\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n init.body = JSON.stringify(body);\n }\n const res = await fetch(url, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function postEmbed<T>(\n url: string,\n campKey: string,\n body: unknown,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = {\n \"X-Camp-Key\": campKey,\n \"Content-Type\": \"application/json\",\n };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: opts?.signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function putEmbed<T>(\n url: string,\n campKey: string,\n body: unknown,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = {\n \"X-Camp-Key\": campKey,\n \"Content-Type\": \"application/json\",\n };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), {\n method: \"PUT\",\n headers,\n body: JSON.stringify(body),\n signal: opts?.signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nasync function deleteEmbed<T>(\n url: string,\n campKey: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n): Promise<T> {\n const headers: Record<string, string> = { \"X-Camp-Key\": campKey };\n if (opts?.accessToken) headers.Authorization = `Bearer ${opts.accessToken}`;\n const res = await fetch(withCampKey(url, campKey), { method: \"DELETE\", headers, signal: opts?.signal });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\n/**\n * Bearer-only helper for /api/embed/v1/admin/* (PLA-489). The admin token is\n * the sole credential (no X-Camp-Key — orgId comes from the JWT claims\n * server-side). `method` can be GET, POST, PATCH, or PUT; `body` is optional\n * (omitted for GET reads like getAnnotations).\n */\nasync function adminEmbed<T>(\n method: \"GET\" | \"POST\" | \"PATCH\" | \"PUT\",\n url: string,\n accessToken: string,\n body?: unknown,\n signal?: AbortSignal,\n): Promise<T> {\n const headers: Record<string, string> = { Authorization: `Bearer ${accessToken}` };\n const init: RequestInit = { method, headers, signal };\n if (body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n init.body = JSON.stringify(body);\n }\n const res = await fetch(url, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n}\n\nexport class PlayaOSClient {\n private readonly baseUrl: string;\n private readonly embedBaseUrl: string;\n private readonly apiKey: string;\n private readonly memberToken: string | undefined;\n\n constructor(opts: ClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n this.embedBaseUrl = (opts.embedBaseUrl ?? opts.baseUrl).replace(/\\/+$/, \"\");\n this.apiKey = opts.apiKey;\n this.memberToken = opts.memberToken;\n }\n\n /** Credentials for /api/v1 calls; the embed surface uses `apiKey` alone as the camp key. */\n private get auth(): V1Auth {\n return { apiKey: this.apiKey, memberToken: this.memberToken };\n }\n\n /**\n * Derive a client that acts as one member (PLA-1195): same host and org key,\n * plus the member's Supabase session JWT on every /api/v1 call. Use this in a\n * server that holds one org key and serves many signed-in members.\n */\n withMember(memberToken: string): PlayaOSClient {\n return new PlayaOSClient({\n baseUrl: this.baseUrl,\n embedBaseUrl: this.embedBaseUrl,\n apiKey: this.apiKey,\n memberToken,\n });\n }\n\n /**\n * Admin dual-path (PLA-1203): when the client has a memberToken, call `/api/v1`\n * (org key + X-PlayaOS-Member-Token). Otherwise keep the legacy embed-admin\n * Bearer-JWT path so published consumers without withMember() still work.\n */\n private adminV1OrEmbed<T>(\n method: \"GET\" | \"POST\" | \"PATCH\" | \"PUT\",\n v1Path: string,\n embedPath: string,\n accessToken: string,\n body?: unknown,\n signal?: AbortSignal,\n ): Promise<T> {\n if (this.memberToken) {\n const url = buildUrl(this.baseUrl, v1Path);\n if (method === \"GET\") return request(url, this.auth, signal);\n if (method === \"POST\") return post(url, this.auth, body ?? {}, signal);\n return sendV1(method, url, this.auth, body, signal);\n }\n return adminEmbed(method, buildEmbedUrl(this.embedBaseUrl, embedPath), accessToken, body, signal);\n }\n\n /** Resolve admin credential: memberToken clients skip accessToken; embed path requires it. */\n private adminAccess(opts?: { accessToken?: string; signal?: AbortSignal }): {\n accessToken: string;\n signal?: AbortSignal;\n } {\n if (this.memberToken) {\n return { accessToken: opts?.accessToken ?? \"\", signal: opts?.signal };\n }\n if (!opts?.accessToken) {\n throw new Error(\"accessToken is required; call withMember(token) or pass { accessToken }\");\n }\n return { accessToken: opts.accessToken, signal: opts.signal };\n }\n\n readonly members = {\n /** Presigned profile-photo upload (PLA-1263). PUT the bytes, then setPhoto. */\n createPhotoUploadUrl: (\n payload: { contentType: \"image/jpeg\" | \"image/png\" | \"image/webp\" },\n opts?: { signal?: AbortSignal },\n ): Promise<{ uploadUrl: string; path: string; token: string; key: string }> =>\n post(buildUrl(this.baseUrl, \"/members/me/photo/upload-url\"), this.auth, payload, opts?.signal),\n\n setPhoto: (payload: { key: string }, opts?: { signal?: AbortSignal }): Promise<{ avatarUrl: string }> =>\n post(buildUrl(this.baseUrl, \"/members/me/photo\"), this.auth, payload, opts?.signal),\n\n deletePhoto: (opts?: { signal?: AbortSignal }): Promise<{ success: boolean }> =>\n sendV1(\"DELETE\", buildUrl(this.baseUrl, \"/members/me/photo\"), this.auth, {}, opts?.signal),\n\n /** Active push device tokens for the acting member (PLA-1261). */\n listDevices: (opts?: { signal?: AbortSignal }): Promise<MemberDevice[]> =>\n request<{ devices: MemberDevice[] }>(buildUrl(this.baseUrl, \"/members/devices\"), this.auth, opts?.signal).then(\n (r) => r.devices,\n ),\n\n registerDevice: (\n payload: { token: string; platform: \"ios\" | \"android\"; environment?: \"sandbox\" | \"production\" },\n opts?: { signal?: AbortSignal },\n ): Promise<{ id: string; registered: boolean }> =>\n post(buildUrl(this.baseUrl, \"/members/devices\"), this.auth, payload, opts?.signal),\n\n deleteDevice: (payload: { token: string }, opts?: { signal?: AbortSignal }): Promise<{ unregistered: boolean }> =>\n sendV1(\"DELETE\", buildUrl(this.baseUrl, \"/members/devices\"), this.auth, payload, opts?.signal),\n\n /** The acting member's communication + (admin) notification preferences (PLA-1262). */\n getPreferences: (opts?: { signal?: AbortSignal }): Promise<MemberPreferences> =>\n request(buildUrl(this.baseUrl, \"/members/me/preferences\"), this.auth, opts?.signal),\n\n updatePreferences: (\n payload: { emailMarketingOptIn: boolean; adminNotifications?: AdminNotificationPrefs },\n opts?: { signal?: AbortSignal },\n ): Promise<MemberPreferences> =>\n sendV1(\"PATCH\", buildUrl(this.baseUrl, \"/members/me/preferences\"), this.auth, payload, opts?.signal),\n\n list: (\n params?: { role?: MemberRole; status?: string } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Member>> => request(buildUrl(this.baseUrl, \"/members\", params), this.auth, opts?.signal),\n\n /**\n * Full profile (phone, emergency contact). Requires a member token; pass\n * `\"me\"` for the acting member — non-admins may fetch only themselves.\n */\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Member> =>\n request(buildUrl(this.baseUrl, `/members/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n /** Member-self profile update (PLA-700 / PLA-1203). Prefers v1 when memberToken is set. */\n selfUpdate: (\n payload: {\n bio?: string | null;\n playaName?: string | null;\n socialMedia?: Record<string, unknown> | null;\n showSocialsInDirectory?: boolean;\n phone?: string | null;\n emergencyContactName?: string | null;\n emergencyContactRelationship?: string | null;\n emergencyContactPhone?: string | null;\n profilePhotoPath?: string | null;\n yearJoined?: number | null;\n },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ profileId: string }> =>\n this.memberToken\n ? sendV1(\"PUT\", buildUrl(this.baseUrl, \"/members/me\"), this.auth, payload, opts.signal)\n : putEmbed(buildEmbedUrl(this.embedBaseUrl, \"/members/self\"), this.apiKey, payload, opts),\n\n /** Member-self shift signup + cancel (PLA-705 / PLA-1203). Prefers v1 when memberToken is set. */\n shifts: {\n signup: async (\n payload: { shiftId: string; role?: string },\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ signupId: string; waitlisted: boolean }> => {\n if (this.memberToken) {\n const assigned = await post<{ id: string; shiftId: string; memberId: string; waitlisted?: boolean }>(\n buildUrl(this.baseUrl, `/shifts/${encodeURIComponent(payload.shiftId)}/assign`),\n this.auth,\n { role: payload.role },\n opts.signal,\n );\n return { signupId: assigned.id, waitlisted: assigned.waitlisted ?? false };\n }\n return postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/shifts/signup\"), this.apiKey, payload, opts);\n },\n cancel: (\n signupId: string,\n opts: { accessToken: string; signal?: AbortSignal },\n ): Promise<{ canceled: boolean; promotedSignupId: string | null }> =>\n this.memberToken\n ? sendV1(\n \"DELETE\",\n buildUrl(this.baseUrl, `/shifts/signups/${encodeURIComponent(signupId)}`),\n this.auth,\n undefined,\n opts.signal,\n )\n : deleteEmbed(\n buildEmbedUrl(this.embedBaseUrl, `/shifts/signups/${encodeURIComponent(signupId)}`),\n this.apiKey,\n opts,\n ),\n },\n };\n\n readonly applications = {\n list: (\n params?: { status?: ApplicationStatus; year?: number } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Application>> =>\n request(buildUrl(this.baseUrl, \"/applications\", params), this.auth, opts?.signal),\n\n // Anonymous external-camp submission against POST /api/embed/v1/applications\n // (PLA-481). Uses the X-Camp-Key header rather than Bearer auth. Pass\n // `accessToken` to additionally send a PlayaOS IdP JWT (PLA-573 path) so\n // the server trusts the verified profile claim and skips the email-based\n // bootstrap.\n create: (\n payload: ApplicationCreatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationCreateResponse> =>\n postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/applications\"), this.apiKey, payload, opts),\n };\n\n readonly waivers = {\n /** Get the active waiver for an org for the current year. */\n active: (orgId: string, opts?: { signal?: AbortSignal }): Promise<Waiver> =>\n getEmbed(buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/active`), this.apiKey, opts?.signal),\n\n /** Sign a waiver. Requires X-Camp-Key; optional accessToken for Bearer path. */\n sign: (\n payload: WaiverSignPayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<WaiverSignResponse> =>\n postEmbed(buildEmbedUrl(this.embedBaseUrl, \"/waivers/sign\"), this.apiKey, payload, opts),\n\n /** Has this applicant/member signed the active waiver? Anchor: applicationId query or Bearer accessToken. */\n status: (\n orgId: string,\n opts?: { applicationId?: string; accessToken?: string; signal?: AbortSignal },\n ): Promise<WaiverStatus> => {\n const query = opts?.applicationId ? `?applicationId=${encodeURIComponent(opts.applicationId)}` : \"\";\n return getEmbedAuthed(buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/status${query}`), this.apiKey, opts);\n },\n\n /** Get a short-lived download URL for a completed signature's PDF. Anchor: applicationId query or Bearer. */\n signedPdf: (\n orgId: string,\n signatureId: string,\n opts?: { applicationId?: string; accessToken?: string; signal?: AbortSignal },\n ): Promise<{ url: string }> => {\n const query = opts?.applicationId ? `?applicationId=${encodeURIComponent(opts.applicationId)}` : \"\";\n return getEmbedAuthed(\n buildEmbedUrl(this.embedBaseUrl, `/waivers/${orgId}/signatures/${encodeURIComponent(signatureId)}/pdf${query}`),\n this.apiKey,\n opts,\n );\n },\n };\n\n readonly dues = {\n list: (\n params?: { userId?: string; year?: number; paymentStatus?: \"unpaid\" | \"partial\" | \"paid\" } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<DuesStatus>> => request(buildUrl(this.baseUrl, \"/dues\", params), this.auth, opts?.signal),\n };\n\n readonly shifts = {\n list: (\n params?: {\n year?: number;\n fromDate?: string;\n toDate?: string;\n publishedOnly?: boolean;\n openOnly?: boolean;\n } & PaginationParams,\n opts?: { signal?: AbortSignal },\n ): Promise<Paginated<Shift>> => request(buildUrl(this.baseUrl, \"/shifts\", params), this.auth, opts?.signal),\n };\n\n readonly org = {\n get: (opts?: { signal?: AbortSignal }): Promise<OrgConfig> =>\n request(buildUrl(this.baseUrl, \"/org\"), this.auth, opts?.signal),\n };\n\n // Public embed surface: active commitment definitions for the org's current\n // year, so the <ApplicationForm> can render + validate them (PLA-682). Uses\n // the X-Camp-Key (the apiKey doubles as the camp key), same as applications.create.\n readonly commitments = {\n list: (opts?: { signal?: AbortSignal }): Promise<CommitmentsListResponse> =>\n getEmbed(buildEmbedUrl(this.embedBaseUrl, \"/commitments\"), this.apiKey, opts?.signal),\n };\n\n readonly payments = {\n list: (\n params?: {\n type?: \"dues\" | \"payment\";\n memberId?: string;\n from?: string;\n to?: string;\n limit?: number;\n offset?: number;\n },\n opts?: { signal?: AbortSignal },\n ): Promise<PaymentLedgerRow[]> => request(buildUrl(this.baseUrl, \"/payments\", params), this.auth, opts?.signal),\n\n /** Requires a member token. `memberId` may be omitted by a non-admin (defaults to themselves); admins must pass it. */\n page: (\n memberId?: string,\n duesCollectionId?: string,\n opts?: { signal?: AbortSignal },\n ): Promise<PaymentPageResponse> =>\n post(buildUrl(this.baseUrl, \"/payments/page\"), this.auth, { memberId, duesCollectionId }, opts?.signal),\n };\n\n readonly accounts = {\n list: (params?: { limit?: number; offset?: number }, opts?: { signal?: AbortSignal }): Promise<Account[]> =>\n request(buildUrl(this.baseUrl, \"/accounts\", params), this.auth, opts?.signal),\n };\n\n readonly contacts = {\n list: (\n params?: {\n role?: MemberRole;\n status?: string;\n search?: string;\n sort?: \"name\" | \"email\";\n limit?: number;\n offset?: number;\n },\n opts?: { signal?: AbortSignal },\n ): Promise<Contact[]> => request(buildUrl(this.baseUrl, \"/contacts\", params), this.auth, opts?.signal),\n };\n\n readonly notifications = {\n /** Set the acting member's notification high-water mark to now (PLA-1261). */\n markSeen: (opts?: { signal?: AbortSignal }): Promise<{ seenAt: string }> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/notifications/seen\"), this.auth, {}, opts?.signal),\n\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 /** Sign a camp document for the acting member (PLA-1258). Requires a member token. */\n sign: (\n id: string,\n payload?: { signature?: { dataUrl: string; type: \"checkbox\" | \"drawn\" | \"typed\"; signerName?: string } },\n opts?: { signal?: AbortSignal },\n ): Promise<CampDocumentSignature> =>\n post(\n buildUrl(this.baseUrl, `/members/documents/${encodeURIComponent(id)}/sign`),\n this.auth,\n payload ?? {},\n opts?.signal,\n ),\n\n /** Signed download URL for the member's copy — signed PDF if present, else the source (PLA-1258). */\n downloadUrl: (id: string, opts?: { signal?: AbortSignal }): Promise<CampDocumentDownloadUrl> =>\n request(\n buildUrl(this.baseUrl, `/members/documents/${encodeURIComponent(id)}/download-url`),\n this.auth,\n opts?.signal,\n ),\n };\n\n readonly meetings = {\n list: (\n params?: { year?: number; limit?: number; cursor?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<MeetingListResponse> =>\n request<MeetingListResponse>(buildUrl(this.baseUrl, \"/meetings\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Meeting> =>\n request(buildUrl(this.baseUrl, `/meetings/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n /** Create a meeting (PLA-1266). Admin-only; requires a member token. */\n create: (payload: CreateMeetingInput, opts?: { signal?: AbortSignal }): Promise<Meeting> =>\n post(buildUrl(this.baseUrl, \"/meetings\"), this.auth, payload, opts?.signal),\n\n /** Archive a meeting (soft delete). Admin-only; requires a member token. */\n archive: (id: string, opts?: { signal?: AbortSignal }): Promise<{ id: string; deleted: boolean }> =>\n sendV1(\n \"DELETE\",\n buildUrl(this.baseUrl, `/meetings/${encodeURIComponent(id)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n };\n\n readonly shelters = {\n list: (\n params?: { ownerId?: string; shelterType?: string; year?: number },\n opts?: { signal?: AbortSignal },\n ): Promise<Shelter[]> => request(buildUrl(this.baseUrl, \"/shelters\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Shelter> =>\n request(buildUrl(this.baseUrl, `/shelters/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n };\n\n readonly bikes = {\n list: (params?: { status?: string }, opts?: { signal?: AbortSignal }): Promise<Bike[]> =>\n request(buildUrl(this.baseUrl, \"/bikes\", params), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<Bike> =>\n request(buildUrl(this.baseUrl, `/bikes/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n /**\n * Cancel an in-house fleet rental owned by the acting member (PLA-1232).\n * Requires a member token. 404 when missing, not owned, or not cancellable.\n */\n cancelRental: (rentalId: string, opts?: { signal?: AbortSignal }): Promise<{ cancelled: true }> =>\n sendV1(\n \"DELETE\",\n buildUrl(this.baseUrl, `/members/bikes/${encodeURIComponent(rentalId)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n };\n\n /**\n * DustJunkie bike rentals (PLA-1180), passed through to the vendor. A camp\n * without the integration gets 403; a DustJunkie failure is a 502.\n */\n readonly bikeRentals = {\n /** Bookable options with estimated totals for `delivery` (server default `camp_delivery`). Org key only. */\n catalog: (\n params?: { delivery?: BikeRentalDeliveryMode },\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalCatalogResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/catalog\", params), this.auth, opts?.signal),\n\n /** The rental agreement the member must accept before `requestReservation`. Org key only. */\n waiver: (opts?: { signal?: AbortSignal }): Promise<BikeRentalWaiver> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/waiver\"), this.auth, opts?.signal),\n\n /**\n * Requires a member token. Admins get the whole camp when `memberId` is\n * omitted; any other role gets their own reservations and 403 naming someone else.\n */\n reservations: (\n params?: { memberId?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalReservationListResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/reservations\", params), this.auth, opts?.signal),\n\n /**\n * Requires a member token; always requests for the acting member. 409 when\n * the model is sold out, 400 when it is unknown or no longer bookable.\n */\n requestReservation: (\n payload: BikeRentalRequestInput,\n opts?: { signal?: AbortSignal },\n ): Promise<BikeRentalRequestResult> =>\n post(buildUrl(this.baseUrl, \"/bike-rentals/requests\"), this.auth, payload, opts?.signal),\n\n /** Members who said they want a bike but have no reservation, for the active camp year. Org key only. */\n interestedNotReserved: (opts?: { signal?: AbortSignal }): Promise<BikeRentalInterestedNotReservedResponse> =>\n request(buildUrl(this.baseUrl, \"/bike-rentals/interested-not-reserved\"), this.auth, opts?.signal),\n };\n\n readonly tags = {\n list: (opts?: { signal?: AbortSignal }): Promise<MemberTag[]> =>\n request(buildUrl(this.baseUrl, \"/tags\"), this.auth, opts?.signal),\n };\n\n readonly groups = {\n list: (opts?: { signal?: AbortSignal }): Promise<MemberGroup[]> =>\n request(buildUrl(this.baseUrl, \"/groups\"), this.auth, opts?.signal),\n\n get: (id: string, opts?: { signal?: AbortSignal }): Promise<MemberGroupRosterRow[]> =>\n request(buildUrl(this.baseUrl, `/groups/${encodeURIComponent(id)}`), this.auth, opts?.signal),\n\n create: (\n payload: { name: string; leaderProfileId: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ id: string }> => post(buildUrl(this.baseUrl, \"/groups\"), this.auth, payload, opts?.signal),\n };\n\n /**\n * Camp-scoped packing (PLA-1197). Every method is the acting member's own\n * list — packing has no `memberId` to widen, so these require `memberToken`\n * and 401 on an org key alone.\n */\n readonly packing = {\n /** The resolved list: curated base + camp layer + personal layer (ADR-071). */\n list: (\n params?: { year?: number; shelter?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<PackingListResponse> => request(buildUrl(this.baseUrl, \"/packing\", params), this.auth, opts?.signal),\n\n /**\n * Set the member's status for one item. The slug goes in the body, not the\n * path: slugs are `${category}/${name}` and contain a `/`.\n *\n * Pass the same `shelter` the list was read under — validation filters by\n * shelter, so an override omitted here rejects shelter-specific items.\n */\n setStatus: (\n payload: { slug: string; status: PackingItemStatus; year?: number; shelter?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ ok: true }> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/packing/items/status\"), this.auth, payload, opts?.signal),\n\n personalItems: {\n list: (\n params?: { containerId?: string },\n opts?: { signal?: AbortSignal },\n ): Promise<{ items: PackingPersonalItem[] }> =>\n request(buildUrl(this.baseUrl, \"/packing/personal-items\", params), this.auth, opts?.signal),\n\n create: (\n payload: { name: string; category: string; qty?: number; unit?: string | null; notes?: string | null },\n opts?: { signal?: AbortSignal },\n ): Promise<{ id: string }> =>\n post(buildUrl(this.baseUrl, \"/packing/personal-items\"), this.auth, payload, opts?.signal),\n\n /**\n * Flip the item between `need` and `have`. It does **not** set `packed` —\n * use `setStatus` for the full vocabulary. 404 if the item is not the\n * acting member's.\n */\n toggle: (id: string, opts?: { signal?: AbortSignal }): Promise<{ ok: true }> =>\n sendV1(\n \"PATCH\",\n buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n\n /** 404 if the item is not the acting member's. */\n remove: (id: string, opts?: { signal?: AbortSignal }): Promise<{ ok: true }> =>\n sendV1(\n \"DELETE\",\n buildUrl(this.baseUrl, `/packing/personal-items/${encodeURIComponent(id)}`),\n this.auth,\n undefined,\n opts?.signal,\n ),\n },\n\n /**\n * Camp packing layer (PLA-1204). Admin/super_admin only — non-admins get 403.\n * Identity is the published slug (`overrides_slug` or `camp:<uuid>`).\n */\n campItems: {\n list: (opts?: { signal?: AbortSignal }): Promise<{ items: PackingCampItem[] }> =>\n request(buildUrl(this.baseUrl, \"/packing/camp-items\"), this.auth, opts?.signal),\n\n upsert: (payload: UpsertPackingCampItemInput, opts?: { signal?: AbortSignal }): Promise<PackingCampItem> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/packing/camp-items\"), this.auth, payload, opts?.signal),\n },\n };\n\n /**\n * SAP — Special Access Pass, for early/overnight vehicle arrival (PLA-1202).\n * Admin/super_admin only; there is no member-facing SAP surface. Year is\n * always the org's active camp year — the server derives it, callers never\n * pass one.\n */\n readonly sap = {\n allocation: {\n get: (opts?: { signal?: AbortSignal }): Promise<SapAllocation> =>\n request(buildUrl(this.baseUrl, \"/sap/allocation\"), this.auth, opts?.signal),\n\n update: (payload: UpdateSapAllocationInput, opts?: { signal?: AbortSignal }): Promise<SapAllocation> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/sap/allocation\"), this.auth, payload, opts?.signal),\n },\n\n dayAllocations: {\n list: (opts?: { signal?: AbortSignal }): Promise<{ items: SapDayAllocation[] }> =>\n request(buildUrl(this.baseUrl, \"/sap/day-allocations\"), this.auth, opts?.signal),\n\n /** Upserts by (active year, accessDate); 409 on a cross-org date collision. */\n upsert: (payload: UpsertSapDayAllocationInput, opts?: { signal?: AbortSignal }): Promise<SapDayAllocation> =>\n sendV1(\"PUT\", buildUrl(this.baseUrl, \"/sap/day-allocations\"), this.auth, payload, opts?.signal),\n },\n\n assignments: {\n list: (opts?: { signal?: AbortSignal }): Promise<{ items: SapAssignment[] }> =>\n request(buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, opts?.signal),\n\n create: (payload: CreateSapAssignmentInput, opts?: { signal?: AbortSignal }): Promise<SapAssignment> =>\n post(buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, payload, opts?.signal),\n\n update: (payload: UpdateSapAssignmentInput, opts?: { signal?: AbortSignal }): Promise<SapAssignment> =>\n sendV1(\"PATCH\", buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, payload, opts?.signal),\n\n remove: (assignmentId: string, opts?: { signal?: AbortSignal }): Promise<{ ok: true }> =>\n sendV1(\"DELETE\", buildUrl(this.baseUrl, \"/sap/assignments\"), this.auth, { assignmentId }, opts?.signal),\n },\n };\n\n // Org-level reads (PLA-1268): API key + org scopes, no member token.\n readonly importantDates = {\n /** Visible camp dates (PLA-1268), optionally pinned to a year. */\n list: (params?: { year?: number }, opts?: { signal?: AbortSignal }): Promise<ImportantDate[]> =>\n request(buildUrl(this.baseUrl, \"/important-dates\", params), this.auth, opts?.signal),\n };\n\n readonly emails = {\n /** Admin template registry (PLA-1265). */\n listTemplates: (opts?: { signal?: AbortSignal }): Promise<EmailTemplate[]> =>\n request<{ data: EmailTemplate[] }>(buildUrl(this.baseUrl, \"/email/templates\"), this.auth, opts?.signal).then(\n (r) => r.data,\n ),\n\n /** Render-only template preview, as HTML (PLA-1265). */\n previewTemplate: (id: string, opts?: { signal?: AbortSignal }): Promise<string> =>\n post<{ html: string }>(\n buildUrl(this.baseUrl, `/email/templates/${encodeURIComponent(id)}/preview`),\n this.auth,\n {},\n opts?.signal,\n ).then((r) => r.html),\n\n /** Admin email retry state + per-status counts (PLA-1265). */\n listRetries: (\n params?: { status?: string; recipient?: string; from?: string; to?: string; limit?: number; offset?: number },\n opts?: { signal?: AbortSignal },\n ): Promise<EmailRetryListResponse> =>\n request<EmailRetryListResponse>(buildUrl(this.baseUrl, \"/email/retries\", params), this.auth, opts?.signal),\n };\n\n readonly onboarding = {\n /** Tick a checklist item for the acting member (PLA-1259). */\n setProgress: (\n itemId: string,\n payload: { completed: boolean; year?: number },\n opts?: { signal?: AbortSignal },\n ): Promise<OnboardingProgress> =>\n sendV1(\n \"PUT\",\n buildUrl(this.baseUrl, `/onboarding/progress/${encodeURIComponent(itemId)}`),\n this.auth,\n payload,\n opts?.signal,\n ),\n };\n\n // Admin write APIs (PLA-489). Each method requires `accessToken` — a Supabase\n // JWT for a camp admin/super_admin. The org boundary is enforced server-side\n // from the JWT claims; these endpoints do not use the X-Camp-Key.\n readonly admin = {\n applications: {\n /**\n * Admin-scoped application detail (PLA-1269): the member-safe shape plus\n * admin-managed metadata (tags, referral, assigned interviewer, review\n * timestamp). v1-only — requires a member token (`withMember`).\n */\n getDetail: (id: string, opts?: { signal?: AbortSignal }): Promise<ApplicationAdmin> => {\n if (!this.memberToken) {\n throw new Error(\"applications.getDetail requires withMember(token)\");\n }\n return request(\n buildUrl(this.baseUrl, `/admin/applications/${encodeURIComponent(id)}`),\n this.auth,\n opts?.signal,\n );\n },\n /**\n * Get application audit timeline (PLA-712). Requires admin Bearer token.\n *\n * @deprecated The embed handler for this method never existed — calls\n * always 404'd (see PLA-1199). Retained as a compile-time compatibility\n * surface for published-consumer code; delegates to the canonical\n * `GET /api/v1/audit/application-logs?applicationId=` (ADR-054), which\n * reads the same `application_audit_logs` table. The `accessToken`\n * argument is accepted but unused — the v1 surface authenticates with\n * the org API key (`audit:read` scope) instead of an admin JWT. Remove\n * in the next major version.\n */\n history: async (\n id: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationHistoryResponse> => {\n type AuditRow = {\n id: string;\n applicationId: string;\n actorUserId: string | null;\n action: string;\n details: Record<string, unknown> | null;\n createdAt: string | null;\n };\n\n // The old embed shape returned the whole timeline in one object, so the\n // cursor has to be followed here — returning only the first 100 rows\n // would silently truncate long-running applications.\n const rows: AuditRow[] = [];\n let cursor: string | null = null;\n do {\n const page: Paginated<AuditRow> = await request<Paginated<AuditRow>>(\n buildUrl(this.baseUrl, \"/audit/application-logs\", {\n applicationId: id,\n limit: 100,\n ...(cursor ? { cursor } : {}),\n }),\n this.auth,\n opts?.signal,\n );\n rows.push(...page.data);\n cursor = page.nextCursor;\n } while (cursor);\n\n return {\n events: rows.map((row) => ({\n id: row.id,\n applicationId: row.applicationId,\n actorId: row.actorUserId,\n actorName: null,\n type: (row.action === \"status_changed\" ? \"status_change\" : row.action) as ApplicationEvent[\"type\"],\n timestamp: row.createdAt ?? \"\",\n metadata: row.details ?? undefined,\n })),\n };\n },\n transition: (\n id: string,\n payload: ApplicationTransitionPayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationTransitionResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/applications/${encodeURIComponent(id)}`,\n `/admin/applications/${encodeURIComponent(id)}`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n getAnnotations: (\n id: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationAnnotations> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/applications/${encodeURIComponent(id)}/annotations`,\n `/admin/applications/${encodeURIComponent(id)}/annotations`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n addNote: (\n id: string,\n payload: { body: string },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationNote> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/applications/${encodeURIComponent(id)}/notes`,\n `/admin/applications/${encodeURIComponent(id)}/notes`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n setTags: (\n id: string,\n payload: { tags: string[] },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<string[]> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/applications/${encodeURIComponent(id)}/tags`,\n `/admin/applications/${encodeURIComponent(id)}/tags`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n setScore: (\n id: string,\n payload: { value: number },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<ApplicationScore> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/applications/${encodeURIComponent(id)}/scores`,\n `/admin/applications/${encodeURIComponent(id)}/scores`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n givebutter: {\n campaigns: {\n list: (opts?: { accessToken?: string; signal?: AbortSignal }): Promise<unknown[]> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n \"/givebutter/campaigns\",\n \"/admin/givebutter/campaigns\",\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n discountCodes: {\n list: (campaignId: number, opts?: { accessToken?: string; signal?: AbortSignal }): Promise<unknown[]> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/givebutter/campaigns/${campaignId}/discount-codes`,\n `/admin/givebutter/campaigns/${campaignId}/discount-codes`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n create: (\n campaignId: number,\n payload: { code: string; value: number; type: \"percent\" | \"fixed\"; expirationDate?: string },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<unknown> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/givebutter/campaigns/${campaignId}/discount-codes`,\n `/admin/givebutter/campaigns/${campaignId}/discount-codes`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n tickets: {\n create: (\n campaignId: number,\n payload: { name: string; price: number; totalQuantity?: number },\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<unknown> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/givebutter/campaigns/${campaignId}/tickets`,\n `/admin/givebutter/campaigns/${campaignId}/tickets`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n },\n },\n members: {\n create: (\n payload: MemberCreatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<MemberCreateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\"POST\", \"/members\", \"/admin/members\", accessToken, payload, signal))(\n this.adminAccess(opts),\n ),\n\n update: (\n id: string,\n patch: MemberUpdatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<MemberUpdateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/members/${encodeURIComponent(id)}`,\n `/admin/members/${encodeURIComponent(id)}`,\n accessToken,\n patch,\n signal,\n ))(this.adminAccess(opts)),\n\n deactivate: (\n id: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<MemberDeactivateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/members/${encodeURIComponent(id)}`,\n `/admin/members/${encodeURIComponent(id)}`,\n accessToken,\n { status: \"inactive\" },\n signal,\n ))(this.adminAccess(opts)),\n },\n announcements: {\n /** Send an email blast to camp members (PLA-706). Requires admin Bearer token. */\n send: (\n payload: AnnouncementSendPayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<AnnouncementSendResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n \"/announcements/send\",\n \"/admin/announcements/send\",\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n dues: {\n /** Create a manual dues/payment record (PLA-708). Requires admin Bearer token. */\n create: (\n payload: DuesCreatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<DuesCreateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\"POST\", \"/dues\", \"/admin/dues\", accessToken, payload, signal))(this.adminAccess(opts)),\n\n /** Update a dues/payment record (PLA-708). Requires admin Bearer token. */\n update: (\n id: string,\n payload: DuesUpdatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<DuesUpdateResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PATCH\",\n `/dues/${encodeURIComponent(id)}`,\n `/admin/dues/${encodeURIComponent(id)}`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n org: {\n /** Update camp configuration settings (PLA-709). Requires admin Bearer token. */\n update: (\n payload: OrgUpdatePayload,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<OrgUpdateResponse> =>\n (({ accessToken, signal }) => this.adminV1OrEmbed(\"PATCH\", \"/org\", \"/admin/org\", accessToken, payload, signal))(\n this.adminAccess(opts),\n ),\n },\n scheduling: {\n availability: {\n /** Get interview availability for an interviewer (PLA-713). Requires admin Bearer token. */\n get: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<GetAvailabilityResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n /** Set interview availability for an interviewer (PLA-713). Requires admin Bearer token. */\n set: (\n interviewerId: string,\n payload: SetAvailabilityInput,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<SetAvailabilityResponse> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n `/admin/scheduling/availability/${encodeURIComponent(interviewerId)}`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n },\n calendar: {\n /** Get Google Calendar connection status for an interviewer (PLA-726). Requires admin Bearer. */\n status: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<CalendarStatus> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/status`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/status`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n /** List available Google Calendars (PLA-726). Requires admin Bearer. */\n listCalendars: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<{ calendars: GoogleCalendar[] }> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/calendars`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/calendars`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n /** Select which Google Calendar to use (PLA-726). Requires admin Bearer. */\n select: (\n interviewerId: string,\n payload: SelectCalendarInput,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<{ calendarId: string }> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"PUT\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/select`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/select`,\n accessToken,\n payload,\n signal,\n ))(this.adminAccess(opts)),\n /** Disconnect Google Calendar from interviewer (PLA-726). Requires admin Bearer. */\n disconnect: (\n interviewerId: string,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<{ disconnected: boolean }> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"POST\",\n `/scheduling/calendar/${encodeURIComponent(interviewerId)}/disconnect`,\n `/admin/scheduling/calendar/${encodeURIComponent(interviewerId)}/disconnect`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n },\n bookingTokens: {\n /** Create a booking token for an application's interview link (PLA-714). Requires admin Bearer token. */\n create: (\n payload: CreateBookingTokenInput,\n opts?: { accessToken?: string; signal?: AbortSignal },\n ): Promise<BookingToken> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\"POST\", \"/booking-tokens\", \"/admin/booking-tokens\", accessToken, payload, signal))(\n this.adminAccess(opts),\n ),\n /** Get an existing booking token for an application (PLA-714). Requires admin Bearer token. */\n get: (applicationId: string, opts?: { accessToken?: string; signal?: AbortSignal }): Promise<BookingToken> =>\n (({ accessToken, signal }) =>\n this.adminV1OrEmbed(\n \"GET\",\n `/booking-tokens/${encodeURIComponent(applicationId)}`,\n `/admin/booking-tokens/${encodeURIComponent(applicationId)}`,\n accessToken,\n undefined,\n signal,\n ))(this.adminAccess(opts)),\n },\n },\n };\n\n // Public embed-booking endpoints (PLA-714). No auth — these are the\n // applicant-facing schedule surface using the hashed booking token.\n readonly schedule = {\n /** List available interview slots for a booking token (PLA-714). Public. */\n getSlots: (\n token: string,\n opts?: { signal?: AbortSignal },\n ): Promise<{ slots: { startsAt: string; endsAt: string }[] }> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}`;\n return fetch(url, { signal: opts?.signal }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<{ slots: { startsAt: string; endsAt: string }[] }>;\n });\n },\n /** Book an interview slot (PLA-714). Public. */\n book: (token: string, payload: BookSlotInput, opts?: { signal?: AbortSignal }): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/book`;\n return fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: opts?.signal,\n }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n /** Cancel an interview booking (PLA-714). Public. */\n cancel: (token: string, opts?: { signal?: AbortSignal }): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/cancel`;\n return fetch(url, { method: \"POST\", signal: opts?.signal }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n /** Reschedule an interview booking (PLA-714). Public. */\n reschedule: (\n token: string,\n payload: RescheduleInput,\n opts?: { signal?: AbortSignal },\n ): Promise<BookSlotResponse> => {\n const url = `${this.embedBaseUrl}/api/embed/v1/schedule/${encodeURIComponent(token)}/reschedule`;\n return fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n signal: opts?.signal,\n }).then(async (res) => {\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<BookSlotResponse>;\n });\n },\n };\n}\n\n/** Convenience factory — equivalent to `new PlayaOSClient(opts)`. */\nexport function createClient(opts: ClientOptions): PlayaOSClient {\n return new PlayaOSClient(opts);\n}\n","/**\n * Server-side OAuth-code → ID-token exchange.\n *\n * Swaps a one-time authorization code from the PlayaOS IdP for a short-lived\n * ID token. Confidential clients pass `clientSecret`, which is sent to the\n * token endpoint server-side. Public/PKCE-only clients omit it — the\n * authorization-code + code_verifier pair is the sole credential. Public\n * clients can also exchange directly from the browser via `usePlayaOSAuth`\n * in `@playaos/react`.\n */\n\nexport interface ExchangeParams {\n authBaseUrl?: string;\n code: string;\n codeVerifier: string;\n clientId: string;\n /** Confidential clients only. Omit for public/PKCE-only clients. */\n clientSecret?: string;\n redirectUri: string;\n}\n\nexport interface ExchangeResult {\n idToken: string;\n expiresAt: string;\n /** Confidential clients only. Undefined for public clients. */\n refreshToken?: string;\n}\n\nexport async function exchangeCode(params: ExchangeParams): Promise<ExchangeResult> {\n const base = params.authBaseUrl ?? \"https://auth.playaos.app\";\n // A confidential client is identified by passing clientSecret at all — even an\n // empty string. We forward it as-is so the server validates it (an empty or\n // wrong secret is rejected there); public clients omit the field entirely.\n const isConfidential = params.clientSecret !== undefined;\n const res = await fetch(`${base}/api/auth/v1/exchange`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n code: params.code,\n code_verifier: params.codeVerifier,\n client_id: params.clientId,\n ...(isConfidential ? { client_secret: params.clientSecret } : {}),\n redirect_uri: params.redirectUri,\n }),\n });\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n throw new Error(`Exchange failed: non-JSON response (${res.status})`);\n }\n\n if (!res.ok) {\n const errorReason =\n typeof body === \"object\" && body !== null && \"error\" in body && typeof body.error === \"string\"\n ? body.error\n : String(res.status);\n throw new Error(`Exchange failed: ${errorReason}`);\n }\n\n if (\n typeof body !== \"object\" ||\n body === null ||\n !(\"idToken\" in body) ||\n typeof body.idToken !== \"string\" ||\n !(\"expiresAt\" in body) ||\n typeof body.expiresAt !== \"string\"\n ) {\n throw new Error(\"Exchange failed: malformed success response\");\n }\n\n // The server mints a refresh token only for confidential clients (it sets\n // `withRefreshToken: client.type === \"confidential\"`); public clients get\n // none. Surface it when present, otherwise leave it undefined.\n const refreshToken = \"refreshToken\" in body && typeof body.refreshToken === \"string\" ? body.refreshToken : undefined;\n\n // A confidential client that gets no refresh token means the server response\n // is malformed or the rotation flow is broken — surface it rather than\n // silently returning a result the caller can't refresh.\n if (isConfidential && refreshToken === undefined) {\n throw new Error(\"Exchange failed: confidential client response missing refreshToken\");\n }\n\n return {\n idToken: body.idToken,\n expiresAt: body.expiresAt,\n ...(refreshToken !== undefined ? { refreshToken } : {}),\n };\n}\n","import { parseError } from \"./error.js\";\n\n/** A listing holds at most this many images (matches the DB's position 1–6 check). */\nexport const MAX_IMAGE_POSITION = 6;\n\n/**\n * Typed client for the anonymous gift-layer marketplace API (`/api/public/marketplace/*`).\n *\n * Unlike `PlayaOSClient` (api-key auth for `/api/v1`), this surface authenticates\n * writes with a Supabase **Bearer JWT** belonging to a public `global_accounts`\n * user. The token is supplied by an injected `getToken` provider so the same\n * client works from any consumer (the marketing UI supplies the browser\n * Supabase session token; a future surface could supply its own). Keeps the\n * public API as the single write contract — the UI is just another consumer.\n */\nexport interface PublicMarketplaceClientOptions {\n /** API base, e.g. `https://api.playaos.app`. */\n baseUrl: string;\n /** Supplies the Supabase access token (Bearer) for authenticated calls; null/undefined when signed out. */\n getToken: () => Promise<string | null | undefined> | string | null | undefined;\n}\n\nexport interface NewListingInput {\n category: string;\n subcategory?: string;\n title: string;\n body: string;\n price?: number;\n location?: string;\n replyEmail: string;\n}\n\nexport interface ImageUploadTarget {\n /** Supabase signed upload URL — PUT the file bytes here. */\n uploadUrl: string;\n /** Storage path to pass back to `attachImage` once the PUT succeeds. */\n storagePath: string;\n}\n\n/** Moderation flag reasons accepted by the API (mirrors the DB enum). */\nexport type MarketplaceFlagReason = \"spam\" | \"prohibited\" | \"other\";\n\nexport interface ListingImage {\n /** Short-lived signed download URL for the image. */\n url: string;\n /** 1-based display order. */\n position: number;\n}\n\nexport interface PublicMarketplaceClient {\n /**\n * Create a listing as the signed-in account. Throws a plain `Error` when there\n * is no token (signed out), or `ApiClientError` on a non-2xx response.\n */\n createListing(input: NewListingInput, signal?: AbortSignal): Promise<{ id: string }>;\n /** Request a signed upload URL for an image on a listing the caller owns. */\n getImageUploadUrl(listingId: string, signal?: AbortSignal): Promise<ImageUploadTarget>;\n /** Attach an already-uploaded image (by storage path) to a listing at a 1–6 position. */\n attachImage(\n listingId: string,\n input: { storagePath: string; position: number },\n signal?: AbortSignal,\n ): Promise<{ id: string }>;\n /** Anonymous: list an active listing's images as short-lived signed URLs (for public display). */\n listListingImages(listingId: string, signal?: AbortSignal): Promise<{ images: ListingImage[] }>;\n /** Anonymous: batch-fetch first-image signed thumbnail URLs (listingId -> url) for browse cards. */\n listThumbnails(listingIds: string[], signal?: AbortSignal): Promise<{ thumbnails: Record<string, string> }>;\n /** Flag a listing for moderation (signed-in). Idempotent per (listing, user). */\n flagListing(listingId: string, reason: MarketplaceFlagReason, signal?: AbortSignal): Promise<{ ok: boolean }>;\n /** Contact a listing's owner (signed-in); records the reply + queues a notification email. */\n replyToListing(listingId: string, message: string | undefined, signal?: AbortSignal): Promise<{ ok: boolean }>;\n}\n\nexport function createPublicMarketplaceClient(opts: PublicMarketplaceClientOptions): PublicMarketplaceClient {\n const base = opts.baseUrl.replace(/\\/+$/, \"\");\n if (!base) {\n // An empty base would issue relative requests to the caller's own origin.\n throw new Error(\"createPublicMarketplaceClient: baseUrl is required\");\n }\n\n async function authedPost<T>(path: string, body: unknown, signal?: AbortSignal): Promise<T> {\n const token = await opts.getToken();\n if (!token) throw new Error(\"Not signed in\");\n const res = await fetch(`${base}/api/public/marketplace${path}`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}`, \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal,\n });\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n }\n\n async function publicGet<T>(path: string, signal?: AbortSignal): Promise<T> {\n // no-store: responses carry short-lived signed URLs — never let the framework\n // (e.g. Next's fetch cache) memoize them and serve expired URLs. `cache` is a\n // valid fetch option at runtime but absent from @types/node's RequestInit,\n // so the init is typed with an intersection.\n const init: RequestInit & { cache: \"no-store\" } = { signal, cache: \"no-store\" };\n const res = await fetch(`${base}/api/public/marketplace${path}`, init);\n if (!res.ok) throw await parseError(res);\n return res.json() as Promise<T>;\n }\n\n const seg = (listingId: string) => `/listings/${encodeURIComponent(listingId)}`;\n\n return {\n createListing: (input, signal) => authedPost(\"/listings\", input, signal),\n getImageUploadUrl: (listingId, signal) => authedPost(`${seg(listingId)}/image-upload-url`, {}, signal),\n attachImage: (listingId, input, signal) => {\n // Fail fast on a misuse the API would otherwise reject with a vague 400.\n if (!Number.isInteger(input.position) || input.position < 1 || input.position > MAX_IMAGE_POSITION) {\n return Promise.reject(new Error(`attachImage: position must be 1–${MAX_IMAGE_POSITION}`));\n }\n return authedPost(`${seg(listingId)}/images`, input, signal);\n },\n listListingImages: (listingId, signal) => publicGet(`${seg(listingId)}/images`, signal),\n listThumbnails: (listingIds, signal) =>\n publicGet(`/thumbnails?ids=${encodeURIComponent(listingIds.join(\",\"))}`, signal),\n flagListing: (listingId, reason, signal) => authedPost(`${seg(listingId)}/flag`, { reason }, signal),\n replyToListing: (listingId, message, signal) => authedPost(`${seg(listingId)}/reply`, { message }, signal),\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playaos/api-client",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "Typed API client for PlayaOS — manage camp members, dues, shifts, applications, waivers, and annotations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",