@whop/api
Version:
Whop API client
1,618 lines (1,594 loc) • 79.5 kB
JavaScript
"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