UNPKG

@whop/api

Version:
1,618 lines (1,594 loc) 79.5 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.node.ts var index_node_exports = {}; __export(index_node_exports, { WhopClientSdk: () => WhopClientSdk, WhopServerSdk: () => WhopServerSdk, getUserToken: () => getUserToken, makeUserTokenVerifier: () => makeUserTokenVerifier, makeWebhookValidator: () => makeWebhookValidator, proto: () => proto_exports, verifyUserToken: () => verifyUserToken }); module.exports = __toCommonJS(index_node_exports); // src/utils/retry.ts var RetryError = class extends Error { constructor(message, errors, maxRetries) { super(message); this.errors = errors; this.maxRetries = maxRetries; this.name = "RetryError"; } }; async function retry(fn, maxRetries, signal, ...args) { let tries = 0; const errors = []; while (tries < maxRetries) { signal?.throwIfAborted(); try { const res = await fn(...args); return res; } catch (error) { errors.push(error); tries++; } } for (const error of errors) { console.error(error); } throw new RetryError("Failed to retry", errors, maxRetries); } // src/attachments/upload-parts.ts var uploadTasks = []; var workerCount = 0; var maxWorkers = 10; async function uploadWorker(uploadPart) { if (workerCount >= maxWorkers) { return; } workerCount++; while (uploadTasks.length > 0) { const task = uploadTasks.shift(); if (!task) { continue; } try { const etag = await retry(uploadPart, 10, task.task.signal, task.task); task.resolve({ etag, partNumber: task.task.partNumber }); } catch (e) { task.reject(e); } } workerCount--; } function uploadParts(tasks, uploadPart, priority = false) { const promises = tasks.map((task) => { return new Promise( (resolve, reject) => { if (priority) { uploadTasks.unshift({ task, resolve, reject }); } else { uploadTasks.push({ task, resolve, reject }); } } ); }); for (let i = 0; i < Math.min(tasks.length, maxWorkers); i++) { void uploadWorker(uploadPart); } return Promise.all(promises); } // src/utils/sum.ts function sum(...args) { return args.reduce((acc, curr) => acc + curr, 0); } // src/attachments/upload.ts async function handleUpload({ data, ...preparedFile }, { onProgress, signal, uploadPart }) { if (preparedFile.multipart) { const loaded = Array(preparedFile.multipartUploadUrls.length).fill(0); const result = await uploadParts( preparedFile.multipartUploadUrls.map((part, index) => ({ ...part, fullData: data, onProgress: (event) => { loaded[index] = event.loaded; const total = sum(...loaded); onProgress?.(Math.round(total / data.size * 100)); }, signal })), uploadPart ); return result; } await uploadParts( [ { url: preparedFile.uploadUrl, fullData: data, partNumber: 1, headers: preparedFile.headers, onProgress: (event) => { onProgress?.(Math.round(event.loaded / data.size * 100)); }, signal } ], uploadPart, true ); return []; } function getMediaType(data) { switch (true) { case data.type.startsWith("image/"): return "image"; case data.type.startsWith("video/"): return "video"; case data.type.startsWith("audio/"): return "audio"; default: return "other"; } } function makeUploadAttachmentFunction({ uploadPart }) { return async function uploadAttachment(input, { onProgress, signal } = {}) { const preparedAttachment = "record" in input && "file" in input ? await this.prepareAttachmentForUpload(input.file, input.record) : await input; const result = await handleUpload(preparedAttachment, { onProgress, signal, uploadPart }); const mediaType = getMediaType(preparedAttachment.data); if (preparedAttachment.multipart) { await this.attachments.processAttachment({ directUploadId: preparedAttachment.id, mediaType, multipartUploadId: preparedAttachment.multipartUploadId, multipartParts: result }); } else { await this.attachments.processAttachment({ directUploadId: preparedAttachment.id, mediaType }); } const attachment = await this.analyzeAttachment(preparedAttachment.id, { signal }); if (!attachment) { throw new Error("Failed to analyze Attachment"); } return { directUploadId: preparedAttachment.id, record: preparedAttachment.record, attachment }; }; } // src/attachments/upload-part-node.ts var import_node_https = require("https"); var import_node_stream = require("stream"); // src/attachments/common.ts var MULTIPART_UPLOAD_CHUNK_SIZE = 5 * 1024 * 1024; // src/attachments/upload-part-node.ts async function uploadPartImpl({ url, fullData, partNumber, headers, onProgress, signal }) { const offset = (partNumber - 1) * MULTIPART_UPLOAD_CHUNK_SIZE; const data = fullData.slice( offset, Math.min(offset + MULTIPART_UPLOAD_CHUNK_SIZE, fullData.size) ); signal?.throwIfAborted(); return new Promise((resolve, reject) => { const fullURL = new URL(url); const req = (0, import_node_https.request)(fullURL, { method: "PUT", headers: { ...headers, host: fullURL.host, "content-length": data.size.toString() }, signal }); let uploadedBytes = 0; req.on("response", async (res) => { const statusCode = res.statusCode ?? 0; if (statusCode >= 200 && statusCode < 300) { const etag = res.headers.etag; if (!etag) { reject(new Error("Missing etag on upload response")); return; } resolve(etag.slice(1, -1)); } else { let chunks = ""; for await (const chunk of res) { chunks += chunk.toString(); } reject( new Error( `Failed to upload part with ${statusCode}: ${res.statusMessage}`, { cause: chunks } ) ); } }); req.on("error", (error) => { reject(error); }); req.on("drain", () => { onProgress?.({ total: data.size, loaded: uploadedBytes }); }); import_node_stream.Readable.fromWeb(data.stream()).on("data", (chunk) => { uploadedBytes += chunk.length; onProgress?.({ total: data.size, loaded: uploadedBytes }); }).pipe(req); onProgress?.({ total: data.size, loaded: 0 }); }); } // src/attachments/analyze.ts async function analyzeAttachment(signedId, opts) { while (!opts?.signal?.aborted) { const attachment = await this.attachments.getAttachment({ id: signedId }, { signal: opts?.signal }).catch(() => null); if (attachment) { return attachment; } } } // src/utils/with-awaitable-params.ts var withAwaitableParams = (fn) => { return (...args) => { const casted = args; const hasPromises = casted.some((arg) => arg instanceof Promise); if (hasPromises) { return new Promise((resolve, reject) => { return Promise.all(casted).then((args2) => { return fn(...args2); }).then(resolve).catch(reject); }); } return fn(...args); }; }; // src/utils/b64.ts var encodings = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; function b64Raw(arrayBuffer) { let base64 = ""; const bytes = new Uint8Array(arrayBuffer); const byteLength = bytes.byteLength; const byteRemainder = byteLength % 3; const mainLength = byteLength - byteRemainder; let a; let b; let c; let d; let chunk; for (let i = 0; i < mainLength; i = i + 3) { chunk = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2]; a = (chunk & 16515072) >> 18; b = (chunk & 258048) >> 12; c = (chunk & 4032) >> 6; d = chunk & 63; base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; } if (byteRemainder === 1) { chunk = bytes[mainLength]; a = (chunk & 252) >> 2; b = (chunk & 3) << 4; base64 += `${encodings[a]}${encodings[b]}==`; } else if (byteRemainder === 2) { chunk = bytes[mainLength] << 8 | bytes[mainLength + 1]; a = (chunk & 64512) >> 10; b = (chunk & 1008) >> 4; c = (chunk & 15) << 2; base64 += `${encodings[a]}${encodings[b]}${encodings[c]}=`; } return base64; } var b64 = withAwaitableParams(b64Raw); // src/utils/md5.ts var import_js_md5 = require("js-md5"); async function md5(stream) { const hasher = import_js_md5.md5.create(); await stream.pipeTo( new WritableStream({ write(chunk) { hasher.update(chunk); } }) ); return hasher.arrayBuffer(); } // src/attachments/prepare.ts async function prepareAttachmentForUpload(data, record) { const isMultipart = data.size > MULTIPART_UPLOAD_CHUNK_SIZE; const mediaDirectUpload = await this.attachments.uploadMedia({ byteSizeV2: data.size.toString(), record, filename: data instanceof File ? data.name : crypto.randomUUID(), contentType: data.type, checksum: await b64(md5(data.stream())), multipart: isMultipart }); if (isMultipart) { if (!mediaDirectUpload?.multipartUploadId || !mediaDirectUpload.multipartUploadUrls) { throw new Error("Failed to prepare file"); } return { data, id: mediaDirectUpload.id, multipartUploadUrls: mediaDirectUpload.multipartUploadUrls, multipartUploadId: mediaDirectUpload.multipartUploadId, record, multipart: true }; } if (!mediaDirectUpload?.id || !mediaDirectUpload.uploadUrl) { throw new Error("Failed to prepare file"); } return { data, id: mediaDirectUpload.id, uploadUrl: mediaDirectUpload.uploadUrl, headers: mediaDirectUpload.headers, record, multipart: false }; } // src/attachments/partial-file-sdk-extensions.ts function partialFileSdkExtensions(baseSdk) { const prepareAttachmentForUpload2 = prepareAttachmentForUpload.bind(baseSdk); const analyzeAttachment2 = analyzeAttachment.bind(baseSdk); return { prepareAttachmentForUpload: prepareAttachmentForUpload2, analyzeAttachment: analyzeAttachment2 }; } // src/attachments/file-sdk-extensions.ts function fileSdkExtensions(baseSdk, uploadAttachmentFn) { const partial = partialFileSdkExtensions(baseSdk); const uploadAttachment = uploadAttachmentFn.bind({ ...baseSdk, ...partial }); return { ...partial, uploadAttachment }; } // src/codegen/graphql/client.ts function getSdk(requester) { return { accessPasses: { getAccessPass(variables, options) { return requester( "whop-sdk-ts-client/sha256:daea5c9cf3e5e30ef0fd9eaad8ea852ffdbd0e0088ff3ad05aacb6a761b7c6f9", "getAccessPass", "query", variables, options ).then((res) => res.accessPass); } }, attachments: { getAttachment(variables, options) { return requester( "whop-sdk-ts-client/sha256:07f48fb0c1292fda5a8dd5f54b5d1b637635a87b6012769819ebcf7795a045ba", "getAttachment", "query", variables, options ).then((res) => res.attachment); }, processAttachment(variables, options) { return requester( "whop-sdk-ts-client/sha256:396c5803051b3c9bcedd3ce310505a4f57a6b94bc190e7142e897d9aa5036ece", "processAttachment", "mutation", { input: variables }, options ).then((res) => res.mediaAnalyzeAttachment); }, uploadMedia(variables, options) { return requester( "whop-sdk-ts-client/sha256:a3d06ed16e52126d96aae83cad3400471246f37fc275e4c8f4836c98bf8e9d59", "uploadMedia", "mutation", { input: variables }, options ).then((res) => res.mediaDirectUpload); } }, courses: { createAssessmentQuestion(variables, options) { return requester( "whop-sdk-ts-client/sha256:52902016f3a8cf2b819038945ded34a0caafd80c9a867403ca36451c39f56ac6", "createAssessmentQuestion", "mutation", { input: variables }, options ).then((res) => res.createAssessmentQuestion); }, createChapter(variables, options) { return requester( "whop-sdk-ts-client/sha256:8ebe9533278b00eded622eef765baeebf70fccedcd5d60854f8777812da20311", "createChapter", "mutation", { input: variables }, options ).then((res) => res.createChapter); }, createCourse(variables, options) { return requester( "whop-sdk-ts-client/sha256:41f957dfc0e147131265e62e4b5ae6f743256f6bf7a4e28e042a3469777e9c35", "createCourse", "mutation", { input: variables }, options ).then((res) => res.createCourse); }, createLesson(variables, options) { return requester( "whop-sdk-ts-client/sha256:33069f4d2b756d6a9a2a486d0ac6d91272c9acbd9d3774c15e12d7b39f3df6f4", "createLesson", "mutation", { input: variables }, options ).then((res) => res.createLesson); }, deleteAssessmentQuestionImage(variables, options) { return requester( "whop-sdk-ts-client/sha256:07563fb79b45fd9fbe7ef7d14923014e5f3407dae067d0393b84bd6724970aaa", "deleteAssessmentQuestionImage", "mutation", { input: variables }, options ).then((res) => res.deleteAssessmentQuestionImage); }, deleteChapter(variables, options) { return requester( "whop-sdk-ts-client/sha256:021c10ea5b5f776e229d4c2cd25578b8aec3c869c898c747d4dcb889ddad32b6", "deleteChapter", "mutation", { input: variables }, options ).then((res) => res.deleteChapter); }, deleteLessonAttachment(variables, options) { return requester( "whop-sdk-ts-client/sha256:7af840d8ddbf664a04ec3da2283e9a540f68da24adedbe7a2af9718f1c70f10c", "deleteLessonAttachment", "mutation", { input: variables }, options ).then((res) => res.deleteLessonAttachment); }, deleteLesson(variables, options) { return requester( "whop-sdk-ts-client/sha256:6be8fd89af64aec7db125bac7d67bad8530cc8f5b8ee98c879351acd59aa6fac", "deleteLesson", "mutation", { input: variables }, options ).then((res) => res.deleteLesson); }, getCourse(variables, options) { return requester( "whop-sdk-ts-client/sha256:5e81c304ac7c4c19b2d07ea7c2a32b2fd8998774bf90900a81999b9077b383a1", "getCourse", "query", variables, options ).then((res) => res.course); }, getLesson(variables, options) { return requester( "whop-sdk-ts-client/sha256:372989bc0ffb7ff3c36d1325f1af4115c06205e95378a2e344d91a857e732630", "getLesson", "query", variables, options ).then((res) => res.course); }, getUserLessonInteractions(variables, options) { return requester( "whop-sdk-ts-client/sha256:6b12c8ccabe59b65d8869029d4e4e56ddbeac7256137e5e79012a3e33aa81523", "getUserLessonInteractions", "query", variables, options ).then((res) => res.course); }, listCoursesForCompany(variables, options) { return requester( "whop-sdk-ts-client/sha256:76dd2b0b09b6083392dcce8c1df423cc6e6eb290e58bdd2d830f50ef1a4828b3", "listCoursesForCompany", "query", variables, options ).then((res) => res.company); }, listCoursesForExperience(variables, options) { return requester( "whop-sdk-ts-client/sha256:a579fee2663d841a23be014b234d89eadb097dac387722dfe9d0e87911a7598e", "listCoursesForExperience", "query", variables, options ).then((res) => res.publicExperience); }, markLessonAsCompleted(variables, options) { return requester( "whop-sdk-ts-client/sha256:941178d021bd72247401d347d5dd969036579147777e0a754f5102cddc5074c7", "markLessonAsCompleted", "mutation", { input: variables }, options ).then((res) => res.markLessonAsCompleted); }, moveCourse(variables, options) { return requester( "whop-sdk-ts-client/sha256:ce7d38029113792bf1ff544db18f000732fed4db3ebc766767a367cef5691c2b", "moveCourse", "mutation", { input: variables }, options ).then((res) => res.moveCourse); }, updateChapterOrder(variables, options) { return requester( "whop-sdk-ts-client/sha256:c749c5c4907afd39ab2d3f8c44b3e65c8c9928e0cf06f8687deaa40d144a0df6", "updateChapterOrder", "mutation", { input: variables }, options ).then((res) => res.updateChapterOrder); }, updateChapter(variables, options) { return requester( "whop-sdk-ts-client/sha256:9fda8d867b07c1b31622cb73084523577519ca35822d8ce3938fa2b07efaf6e5", "updateChapter", "mutation", { input: variables }, options ).then((res) => res.updateChapter); }, updateLessonOrder(variables, options) { return requester( "whop-sdk-ts-client/sha256:8ae83382f97b182c08bf5851e3bbed05fd8269856c00b82b5577939c00e39e43", "updateLessonOrder", "mutation", { input: variables }, options ).then((res) => res.updateLessonOrder); }, updateLesson(variables, options) { return requester( "whop-sdk-ts-client/sha256:c872c79e5469f162f4de0f64ed6decc489cc3e05d66781a2f33ae1eef4d762bd", "updateLesson", "mutation", { input: variables }, options ).then((res) => res.updateLesson); } }, experiences: { getExperience(variables, options) { return requester( "whop-sdk-ts-client/sha256:114eb7b7c8403ffbe75a0c74a26ac50b5367e183a16ba64eebf4a43d5466bb4e", "getExperience", "query", variables, options ).then((res) => res.experience); }, listUsersForExperience(variables, options) { return requester( "whop-sdk-ts-client/sha256:85c827d8660dc2a97e8b930e213b83493ae132c00988e0f03e02c5dc99559a5a", "listUsersForExperience", "query", variables, options ).then((res) => res.publicExperience); } }, forums: { listForumPostsFromForum(variables, options) { return requester( "whop-sdk-ts-client/sha256:97a7d797f3a5f6f83bf4628cc7c586d529b90e54c0a8e193493a55b4ad05df46", "listForumPostsFromForum", "query", variables, options ).then((res) => res.feedPosts); } }, messages: { listMessagesFromChat(variables, options) { return requester( "whop-sdk-ts-client/sha256:5fdbf50fe489888e5b0a98e9fe6170584bf47ab38f87d1e0b7fce8f523513894", "listMessagesFromChat", "query", variables, options ).then((res) => res.feedPosts); } }, users: { getCurrentUser(variables, options) { return requester( "whop-sdk-ts-client/sha256:9f7cc9ff353a2778e55b674cfd5737a7dcaff19be9ac13d6f79aabd5d8ef69ff", "getCurrentUser", "query", variables, options ).then((res) => res.viewer); }, getUserLedgerAccount(variables, options) { return requester( "whop-sdk-ts-client/sha256:d7eeaf0a388395edb82220877e72a7fc91d1f06a6d89f1cfa5e56bb400d2aa49", "getUserLedgerAccount", "query", variables, options ).then((res) => res.viewer); }, getUser(variables, options) { return requester( "whop-sdk-ts-client/sha256:d8022374c6b0eb0445781342a14c9bffafd776cee4e282cb76e31af8c017d33e", "getUser", "query", variables, options ).then((res) => res.publicUser); } } }; } // src/sdk/sdk-common.ts var DEFAULT_API_ORIGIN = "https://api.whop.com"; var GQLNetworkError = class extends Error { constructor(e) { const message = e instanceof Error ? e.message : typeof e === "string" ? e : "Unknown network error"; super(message); if (e instanceof Error) this.stack = e.stack; } }; var GQLRequestError = class extends Error { statusCode; constructor(statusCode, message) { super(message); this.statusCode = statusCode; } isUnauthorized() { return this.statusCode === 401; } isForbidden() { return this.statusCode === 403; } isNotFound() { return this.statusCode === 404; } isServerError() { return this.statusCode >= 500; } }; var GQLError = class extends Error { errors; constructor(errors) { super(errors[0].message); this.errors = errors; } }; async function graphqlFetch(url, operationId, operationName, operationType, variables, headersInit = {}) { try { const body = { operationId, operationType, operationName, variables }; const headers = new Headers(headersInit); headers.set("Content-Type", "application/json"); headers.set("Accept", "application/json"); const urlObject = addOperationNameToUrl( url, operationName, operationId, operationType ); const response = await fetch(urlObject, { method: "POST", body: JSON.stringify(body), headers }); if (!response.ok) { const errorMessage = await response.text(); throw new GQLRequestError(response.status, errorMessage); } const data = await response.json(); if (data.errors) { throw new GQLError(data.errors); } return data.data; } catch (e) { throw new GQLNetworkError(e); } } function addOperationNameToUrl(url, name, operationId, operationType) { const urlObject = new URL(url); let pathname = urlObject.pathname; if (pathname.endsWith("/")) { pathname = pathname.slice(0, -1); } pathname += `/${name}`; urlObject.pathname = pathname; const [clientName, opId] = operationId.split("/"); urlObject.searchParams.set("id", opId); urlObject.searchParams.set("client", clientName); urlObject.searchParams.set("type", operationType); return urlObject; } // src/websockets/client.common.ts var import_tiny_typed_emitter = require("tiny-typed-emitter"); var WhopWebsocketClientBase = class extends import_tiny_typed_emitter.TypedEmitter { websocket = null; failedConnectionAttempts = 0; status = "disconnected"; wantsToBeConnected = false; makeWebsocket() { throw new Error("Not implemented in base class"); } connect() { if (this.websocket) { this.disconnect(); } this.wantsToBeConnected = true; this.setStatus("connecting"); const websocket = this.makeWebsocket(); this.websocket = websocket; websocket.onopen = () => { this.setStatus("connected"); }; websocket.onmessage = (event) => { try { const message = JSON.parse(event.data); this.emit("message", message); if (message.appMessage) { this.emit("appMessage", message.appMessage); } } catch (error) { console.error( "[WhopWebsocketClient] Error parsing message", event.data ); } }; websocket.onerror = (event) => { console.error("[WhopWebsocketClient] Websocket error", event); this.setStatus("disconnected"); }; websocket.onclose = (event) => { this.setStatus("disconnected"); }; return () => { this.disconnect(); }; } disconnect() { if (this.websocket) { this.websocket.onopen = null; this.websocket.onmessage = null; this.websocket.onerror = null; this.websocket.onclose = null; this.websocket.close(); this.websocket = null; } this.wantsToBeConnected = false; } send(message) { if (!this.websocket) { throw new Error("Websocket not connected"); } this.websocket.send(JSON.stringify(message)); } broadcast({ message, target }) { this.send({ broadcastAppMessage: { channel: convertBroadcastTargetToProtoChannel(target), json: message } }); } setStatus(status) { if (status === this.status) return; this.status = status; if (status === "disconnected") { const backoff = this.calculateBackoff(); this.failedConnectionAttempts++; setTimeout(() => { if (this.wantsToBeConnected) { this.connect(); } }, backoff); this.emit("disconnect"); } if (status === "connected") { this.failedConnectionAttempts = 0; this.emit("connect"); } this.emit("connectionStatus", status); } calculateBackoff() { return Math.min(50 * 2 ** this.failedConnectionAttempts, 1e3 * 60); } }; function convertBroadcastTargetToProtoChannel(target) { if (target === "everyone") { return { type: "APP", id: "[app_id]" }; } if ("experienceId" in target) { return { type: "APP", id: `[app_id]_${target.experienceId}` }; } if ("customId" in target) { return { type: "APP", id: `[app_id]_c_${target.customId}` }; } throw new Error("Invalid broadcast target"); } // src/websockets/client.browser.ts var WhopWebsocketClientBrowser = class extends WhopWebsocketClientBase { options; constructor(options) { super(); this.options = options; } makeWebsocket() { const path = "/_whop/ws/v1/websockets/connect"; const searchParams = new URLSearchParams(); addChannelIds(searchParams, "join_experience", this.options.joinExperience); addChannelIds(searchParams, "join_custom", this.options.joinCustom); addChannelIds(searchParams, "join_public", this.options.joinPublic); const url = new URL(path, window.location.origin); url.protocol = url.protocol.replace("http", "ws"); url.search = searchParams.toString(); return new WebSocket(url.toString()); } }; function addChannelIds(searchParams, key, channels) { if (!channels) { return; } if (typeof channels === "string" && channels.length > 0) { searchParams.set(key, channels); return; } for (const channel of channels) { searchParams.append(key, channel); } } function makeConnectToWebsocketFunction() { return function connectToWebsocket(options) { return new WhopWebsocketClientBrowser(options); }; } // src/sdk/client-sdk-shared.ts function makeWhopClientSdk({ uploadFile: uploadFile3 }) { return function WhopClientSdk2(options) { const baseSdk = getSdk( makeRequester({ apiPath: "/_whop/public-graphql", ...options }) ); const fileSdk = fileSdkExtensions(baseSdk, uploadFile3); const websocketClient = makeConnectToWebsocketFunction(); const sdk3 = { ...baseSdk, attachments: { ...baseSdk.attachments, ...fileSdk }, websockets: { client: websocketClient } }; return sdk3; }; } function makeRequester(apiOptions) { const endpoint = getEndpoint(apiOptions); return async function fetcher(operationId, operationName, operationType, vars, options) { const headers = new Headers(options?.headers); return graphqlFetch( endpoint, operationId, operationName, operationType, vars, headers ); }; } function getEndpoint(apiOptions) { if (typeof document === "undefined" && !apiOptions.apiOrigin) { throw new Error("WhopApi.client() is only available in the browser"); } const url = new URL( apiOptions.apiPath ?? "/public-graphql", apiOptions.apiOrigin ?? window.location.origin ); return url.href; } // src/sdk/client-sdk-node.ts var uploadFile = makeUploadAttachmentFunction({ uploadPart: uploadPartImpl }); var sdk = makeWhopClientSdk({ uploadFile }); function WhopClientSdk(options) { return sdk(options); } // src/codegen/graphql/server.ts function getSdk2(requester) { return { accessPasses: { getAccessPass(variables, options) { return requester( "whop-sdk-ts-server/sha256:daea5c9cf3e5e30ef0fd9eaad8ea852ffdbd0e0088ff3ad05aacb6a761b7c6f9", "getAccessPass", "query", variables, options ).then((res) => res.accessPass); } }, access: { checkIfUserHasAccessToAccessPass(variables, options) { return requester( "whop-sdk-ts-server/sha256:a5ee1715113ab68b87dcfd5b578b6c20d1ca1fe50d8c0e2ec43e462a9b86632d", "checkIfUserHasAccessToAccessPass", "query", variables, options ).then((res) => res.hasAccessToAccessPass); }, checkIfUserHasAccessToCompany(variables, options) { return requester( "whop-sdk-ts-server/sha256:b894321dc004894f993e91f5e7451554b0ae8af7da950a5c84ac69180599edc2", "checkIfUserHasAccessToCompany", "query", variables, options ).then((res) => res.hasAccessToCompany); }, checkIfUserHasAccessToExperience(variables, options) { return requester( "whop-sdk-ts-server/sha256:b16d7fe717171fb936dfb6de679558e149f5070bbe25ade44e38af83c330ad71", "checkIfUserHasAccessToExperience", "query", variables, options ).then((res) => res.hasAccessToExperience); } }, apps: { createAppBuild(variables, options) { return requester( "whop-sdk-ts-server/sha256:221275dcd40898079c1e7bc1510b364a487581d6cdfc1a9524da74f2f82689cc", "createAppBuild", "mutation", { input: variables }, options ).then((res) => res.createAppBuild); } }, attachments: { getAttachment(variables, options) { return requester( "whop-sdk-ts-server/sha256:07f48fb0c1292fda5a8dd5f54b5d1b637635a87b6012769819ebcf7795a045ba", "getAttachment", "query", variables, options ).then((res) => res.attachment); }, processAttachment(variables, options) { return requester( "whop-sdk-ts-server/sha256:396c5803051b3c9bcedd3ce310505a4f57a6b94bc190e7142e897d9aa5036ece", "processAttachment", "mutation", { input: variables }, options ).then((res) => res.mediaAnalyzeAttachment); }, uploadMedia(variables, options) { return requester( "whop-sdk-ts-server/sha256:a3d06ed16e52126d96aae83cad3400471246f37fc275e4c8f4836c98bf8e9d59", "uploadMedia", "mutation", { input: variables }, options ).then((res) => res.mediaDirectUpload); } }, companies: { getCompanyLedgerAccount(variables, options) { return requester( "whop-sdk-ts-server/sha256:38c83c1105b29a010208830b29d38af3d87a885b9c54a3da65d6dd2749128773", "getCompanyLedgerAccount", "query", variables, options ).then((res) => res.company); }, getWaitlistEntriesForCompany(variables, options) { return requester( "whop-sdk-ts-server/sha256:5ad1e4c5932d68eda92af2d709ecf6ad0afc8fb29e1ef2bd1448f61650b637d3", "getWaitlistEntriesForCompany", "query", variables, options ).then((res) => res.company); } }, courses: { createAssessmentQuestion(variables, options) { return requester( "whop-sdk-ts-server/sha256:52902016f3a8cf2b819038945ded34a0caafd80c9a867403ca36451c39f56ac6", "createAssessmentQuestion", "mutation", { input: variables }, options ).then((res) => res.createAssessmentQuestion); }, createChapter(variables, options) { return requester( "whop-sdk-ts-server/sha256:8ebe9533278b00eded622eef765baeebf70fccedcd5d60854f8777812da20311", "createChapter", "mutation", { input: variables }, options ).then((res) => res.createChapter); }, createCourse(variables, options) { return requester( "whop-sdk-ts-server/sha256:41f957dfc0e147131265e62e4b5ae6f743256f6bf7a4e28e042a3469777e9c35", "createCourse", "mutation", { input: variables }, options ).then((res) => res.createCourse); }, createLesson(variables, options) { return requester( "whop-sdk-ts-server/sha256:33069f4d2b756d6a9a2a486d0ac6d91272c9acbd9d3774c15e12d7b39f3df6f4", "createLesson", "mutation", { input: variables }, options ).then((res) => res.createLesson); }, deleteAssessmentQuestionImage(variables, options) { return requester( "whop-sdk-ts-server/sha256:07563fb79b45fd9fbe7ef7d14923014e5f3407dae067d0393b84bd6724970aaa", "deleteAssessmentQuestionImage", "mutation", { input: variables }, options ).then((res) => res.deleteAssessmentQuestionImage); }, deleteChapter(variables, options) { return requester( "whop-sdk-ts-server/sha256:021c10ea5b5f776e229d4c2cd25578b8aec3c869c898c747d4dcb889ddad32b6", "deleteChapter", "mutation", { input: variables }, options ).then((res) => res.deleteChapter); }, deleteLessonAttachment(variables, options) { return requester( "whop-sdk-ts-server/sha256:7af840d8ddbf664a04ec3da2283e9a540f68da24adedbe7a2af9718f1c70f10c", "deleteLessonAttachment", "mutation", { input: variables }, options ).then((res) => res.deleteLessonAttachment); }, deleteLesson(variables, options) { return requester( "whop-sdk-ts-server/sha256:6be8fd89af64aec7db125bac7d67bad8530cc8f5b8ee98c879351acd59aa6fac", "deleteLesson", "mutation", { input: variables }, options ).then((res) => res.deleteLesson); }, getCourse(variables, options) { return requester( "whop-sdk-ts-server/sha256:5e81c304ac7c4c19b2d07ea7c2a32b2fd8998774bf90900a81999b9077b383a1", "getCourse", "query", variables, options ).then((res) => res.course); }, getLesson(variables, options) { return requester( "whop-sdk-ts-server/sha256:372989bc0ffb7ff3c36d1325f1af4115c06205e95378a2e344d91a857e732630", "getLesson", "query", variables, options ).then((res) => res.course); }, getUserLessonInteractions(variables, options) { return requester( "whop-sdk-ts-server/sha256:6b12c8ccabe59b65d8869029d4e4e56ddbeac7256137e5e79012a3e33aa81523", "getUserLessonInteractions", "query", variables, options ).then((res) => res.course); }, listCoursesForCompany(variables, options) { return requester( "whop-sdk-ts-server/sha256:76dd2b0b09b6083392dcce8c1df423cc6e6eb290e58bdd2d830f50ef1a4828b3", "listCoursesForCompany", "query", variables, options ).then((res) => res.company); }, listCoursesForExperience(variables, options) { return requester( "whop-sdk-ts-server/sha256:a579fee2663d841a23be014b234d89eadb097dac387722dfe9d0e87911a7598e", "listCoursesForExperience", "query", variables, options ).then((res) => res.publicExperience); }, markLessonAsCompleted(variables, options) { return requester( "whop-sdk-ts-server/sha256:941178d021bd72247401d347d5dd969036579147777e0a754f5102cddc5074c7", "markLessonAsCompleted", "mutation", { input: variables }, options ).then((res) => res.markLessonAsCompleted); }, moveCourse(variables, options) { return requester( "whop-sdk-ts-server/sha256:ce7d38029113792bf1ff544db18f000732fed4db3ebc766767a367cef5691c2b", "moveCourse", "mutation", { input: variables }, options ).then((res) => res.moveCourse); }, updateChapterOrder(variables, options) { return requester( "whop-sdk-ts-server/sha256:c749c5c4907afd39ab2d3f8c44b3e65c8c9928e0cf06f8687deaa40d144a0df6", "updateChapterOrder", "mutation", { input: variables }, options ).then((res) => res.updateChapterOrder); }, updateChapter(variables, options) { return requester( "whop-sdk-ts-server/sha256:9fda8d867b07c1b31622cb73084523577519ca35822d8ce3938fa2b07efaf6e5", "updateChapter", "mutation", { input: variables }, options ).then((res) => res.updateChapter); }, updateLessonOrder(variables, options) { return requester( "whop-sdk-ts-server/sha256:8ae83382f97b182c08bf5851e3bbed05fd8269856c00b82b5577939c00e39e43", "updateLessonOrder", "mutation", { input: variables }, options ).then((res) => res.updateLessonOrder); }, updateLesson(variables, options) { return requester( "whop-sdk-ts-server/sha256:c872c79e5469f162f4de0f64ed6decc489cc3e05d66781a2f33ae1eef4d762bd", "updateLesson", "mutation", { input: variables }, options ).then((res) => res.updateLesson); } }, experiences: { getExperience(variables, options) { return requester( "whop-sdk-ts-server/sha256:114eb7b7c8403ffbe75a0c74a26ac50b5367e183a16ba64eebf4a43d5466bb4e", "getExperience", "query", variables, options ).then((res) => res.experience); }, listAccessPassesForExperience(variables, options) { return requester( "whop-sdk-ts-server/sha256:699621f62be7675bfaf9fc49cb6d7abfe244bf691aee274cb492036f0b59bddc", "listAccessPassesForExperience", "query", variables, options ).then((res) => res.experience); }, listExperiences(variables, options) { return requester( "whop-sdk-ts-server/sha256:6ca8515118d4710204bb2e32ea020bb98de8ea1cada4929ecfe7cae606cf6e79", "listExperiences", "query", variables, options ).then((res) => res.company); }, listUsersForExperience(variables, options) { return requester( "whop-sdk-ts-server/sha256:85c827d8660dc2a97e8b930e213b83493ae132c00988e0f03e02c5dc99559a5a", "listUsersForExperience", "query", variables, options ).then((res) => res.publicExperience); } }, forums: { createForumPost(variables, options) { return requester( "whop-sdk-ts-server/sha256:e6253ed15def017eef4bc2e2f8b01ecd9cf480b5c54fffed439d0afe01a864f2", "createForumPost", "mutation", { input: variables }, options ).then((res) => res.createForumPost); }, findOrCreateForum(variables, options) { return requester( "whop-sdk-ts-server/sha256:5219219796ebdeb29023d098bd9498cf8c64b3536dc9d42cbc4e19708e0b317d", "findOrCreateForum", "mutation", { input: variables }, options ).then((res) => res.createForum); }, listForumPostsFromForum(variables, options) { return requester( "whop-sdk-ts-server/sha256:97a7d797f3a5f6f83bf4628cc7c586d529b90e54c0a8e193493a55b4ad05df46", "listForumPostsFromForum", "query", variables, options ).then((res) => res.feedPosts); } }, messages: { findOrCreateChat(variables, options) { return requester( "whop-sdk-ts-server/sha256:f69684c08f79192b7a4722a3c24a347fd0074e04e1c940517e54b52a9c27f40c", "findOrCreateChat", "mutation", { input: variables }, options ).then((res) => res.createChat); }, listDirectMessageConversations(variables, options) { return requester( "whop-sdk-ts-server/sha256:ea4457aace3d29d8c376dd9de3629cee00d4a76ff0fc9b9d51b6ffeab1cc6ead", "listDirectMessageConversations", "query", variables, options ).then((res) => res.myDmsChannelsV2); }, listMessagesFromChat(variables, options) { return requester( "whop-sdk-ts-server/sha256:5fdbf50fe489888e5b0a98e9fe6170584bf47ab38f87d1e0b7fce8f523513894", "listMessagesFromChat", "query", variables, options ).then((res) => res.feedPosts); }, sendDirectMessageToUser(variables, options) { return requester( "whop-sdk-ts-server/sha256:b1b27b67e3c776813439ace71cb979587cd16c221155a303fcf8e4c7ad8beafa", "sendDirectMessageToUser", "mutation", variables, options ).then((res) => res.sendMessage); }, sendMessageToChat(variables, options) { return requester( "whop-sdk-ts-server/sha256:a3b2e7765662a63fb57a7e61da5081b719fb75ba60560b9059ba4fe856499ac3", "sendMessageToChat", "mutation", variables, options ).then((res) => res.sendMessage); } }, notifications: { sendPushNotification(variables, options) { return requester( "whop-sdk-ts-server/sha256:6239cbdb659f0698ed81ca9533740337b4d2d44e25e22297188d7d1e1a7037d2", "sendPushNotification", "mutation", { input: variables }, options ).then((res) => res.sendNotification); } }, payments: { chargeUser(variables, options) { return requester( "whop-sdk-ts-server/sha256:2392cef9bb6e08d243f102a52c4a6a6e6bd9371e2fced2ad598b2dc14685af81", "chargeUser", "mutation", { input: variables }, options ).then((res) => res.chargeUser); }, createCheckoutSession(variables, options) { return requester( "whop-sdk-ts-server/sha256:498eba2f4b9b6b8fe4ed5f93423af054ea1c4995bf2f3258089c40b68a4919e8", "createCheckoutSession", "mutation", { input: variables }, options ).then((res) => res.createCheckoutSession); }, listReceiptsForCompany(variables, options) { return requester( "whop-sdk-ts-server/sha256:4b5163aa1e6398851da21ce465640243418d36bb26e7b1a87287cddcf677e6ca", "listReceiptsForCompany", "query", variables, options ).then((res) => res.company); }, payUser(variables, options) { return requester( "whop-sdk-ts-server/sha256:d8cbac8b275a7c41e05ab4daa01084b0e54c31c6b5375261f8aee241e5f6c794", "payUser", "mutation", { input: variables }, options ).then((res) => res.transferFunds); } }, users: { getCurrentUser(variables, options) { return requester( "whop-sdk-ts-server/sha256:9f7cc9ff353a2778e55b674cfd5737a7dcaff19be9ac13d6f79aabd5d8ef69ff", "getCurrentUser", "query", variables, options ).then((res) => res.viewer); }, getUserLedgerAccount(variables, options) { return requester( "whop-sdk-ts-server/sha256:d7eeaf0a388395edb82220877e72a7fc91d1f06a6d89f1cfa5e56bb400d2aa49", "getUserLedgerAccount", "query", variables, options ).then((res) => res.viewer); }, getUser(variables, options) { return requester( "whop-sdk-ts-server/sha256:d8022374c6b0eb0445781342a14c9bffafd776cee4e282cb76e31af8c017d33e", "getUser", "query", variables, options ).then((res) => res.publicUser); } } }; } // src/oauth/index.ts var WhopOAuth = class _WhopOAuth { constructor(appId, appApiKey, apiOrigin = "https://api.whop.com") { this.appId = appId; this.appApiKey = appApiKey; this.apiOrigin = apiOrigin; } static OAUTH_URL = "https://whop.com/oauth/"; /** * Get an authorization url to start the OAuth2 flow. * * ```ts * const { url, state } = whopOAuth.getAuthorizationUrl({ * redirectUri: "http://localhost:3000/api/oauth/callback", * scope: ["read_user"], * }) * ``` */ getAuthorizationUrl({ state = crypto.randomUUID(), redirectUri, scope = ["read_user"] }) { const oAuthUrl = new URL(_WhopOAuth.OAUTH_URL); oAuthUrl.searchParams.set("client_id", this.appId); oAuthUrl.searchParams.set("response_type", "code"); oAuthUrl.searchParams.set("scope", scope.join(" ")); oAuthUrl.searchParams.set("state", state); if (redirectUri instanceof URL) { oAuthUrl.searchParams.set("redirect_uri", redirectUri.toString()); } else { oAuthUrl.searchParams.set("redirect_uri", redirectUri); } return { url: oAuthUrl.toString(), state }; } /** * Exchange a code for a token. * * ```ts * const authResponse = await whopOAuth.exchangeCode({ * code: "1234", * redirectUri: "http://localhost:3000/api/oauth/callback", * }) * * if (!authResponse.ok) { * throw new Error(`Failed to exchange code for token. Status: ${authResponse.code}`); * } * * const { access_token } = authResponse.tokens; * ``` */ async exchangeCode({ code, redirectUri }) { const resolvedRedirectUri = redirectUri instanceof URL ? redirectUri.toString() : redirectUri; const tokensEndpoint = new URL("/api/oauth/token", this.apiOrigin); const tokensResponse = await fetch(tokensEndpoint, { method: "POST", body: JSON.stringify({ code, client_id: this.appId, client_secret: this.appApiKey, grant_type: "authorization_code", redirect_uri: resolvedRedirectUri }), headers: { "content-type": "application/json", "cache-control": "no-cache", pragma: "no-cache" }, cache: "no-store" }); if (!tokensResponse.ok) { return { ok: false, code: tokensResponse.status, raw: tokensResponse }; } const tokens = await tokensResponse.json(); return { ok: true, tokens }; } /** * Get an Auth.js provider for the Whop OAuth2 API. * * Works with any Auth.js compatible client: * - [`next-auth`](https://www.npmjs.com/package/next-auth) * - [`@auth/qwik`](https://www.npmjs.com/package/@auth/qwik) * - [`@auth/sveltekit`](https://www.npmjs.com/package/@auth/sveltekit) * - [`@auth/express`](https://www.npmjs.com/package/@auth/express) * - etc. * * ```ts * const WhopProvider = whopOAuth.authJsProvider({ * scope: ["read_user"], * }) * * export const auth = Auth({ * providers: [WhopProvider], * }); * ``` */ authJsProvider({ scope = ["read_user"] }) { return { id: "whop", name: "Whop", type: "oauth", clientId: this.appId, clientSecret: this.appApiKey, authorization: { url: _WhopOAuth.OAUTH_URL, params: { scope: scope.join(" ") } }, checks: ["state"], token: new URL("/api/oauth/token", this.apiOrigin).href, userinfo: new URL("/api/v5/me", this.apiOrigin).href, profile(profile) { return { id: profile.id, name: profile.username || profile.email, email: profile.email, image: profile.profile_pic_url }; } }; } }; // src/verify-user-token.ts var import_jose = require("jose"); var USER_TOKEN_HEADER_NAME = "x-whop-user-token"; var USER_TOKEN_VERIFICATION_KEY = '{"kty":"EC","x":"rz8a8vxvexHC0TLT91g7llOdDOsNuYiGEfic4Qhni-E","y":"zH0QblKYToexd5PEIMGXPVJS9AB5smKrW4S_TbiXrOs","crv":"P-256"}'; function getUserToken(tokenOrHeadersOrRequest) { if (typeof tokenOrHeadersOrRequest === "string") return tokenOrHeadersOrRequest; if (tokenOrHeadersOrRequest instanceof Headers) return tokenOrHeadersOrRequest.g