whop-kit 0.1.3 → 0.2.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/analytics/index.d.ts +22 -0
- package/dist/analytics/index.js +3 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/chunk-5INLS5FZ.js +32 -0
- package/dist/chunk-5INLS5FZ.js.map +1 -0
- package/dist/chunk-7W3CHSHP.js +45 -0
- package/dist/chunk-7W3CHSHP.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/dist/webhooks/index.d.ts +49 -0
- package/dist/webhooks/index.js +4 -0
- package/dist/webhooks/index.js.map +1 -0
- package/package.json +9 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type AnalyticsProvider = "posthog" | "google" | "plausible";
|
|
2
|
+
interface AnalyticsConfig {
|
|
3
|
+
provider: AnalyticsProvider;
|
|
4
|
+
id: string;
|
|
5
|
+
}
|
|
6
|
+
/** Validation patterns for analytics IDs to prevent XSS injection */
|
|
7
|
+
declare const ANALYTICS_ID_PATTERNS: Record<string, RegExp>;
|
|
8
|
+
/**
|
|
9
|
+
* Validate an analytics ID against its provider's expected format.
|
|
10
|
+
*/
|
|
11
|
+
declare function isValidAnalyticsId(provider: AnalyticsProvider, id: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Generate the analytics script HTML for a provider.
|
|
14
|
+
* Returns null if the ID fails format validation (XSS prevention).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const script = getAnalyticsScript({ provider: "posthog", id: "phc_xxxxx" });
|
|
18
|
+
* // Inject into <head>: <Fragment set:html={script} />
|
|
19
|
+
*/
|
|
20
|
+
declare function getAnalyticsScript(config: AnalyticsConfig): string | null;
|
|
21
|
+
|
|
22
|
+
export { ANALYTICS_ID_PATTERNS, type AnalyticsConfig, type AnalyticsProvider, getAnalyticsScript, isValidAnalyticsId };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// src/analytics/index.ts
|
|
2
|
+
var ANALYTICS_ID_PATTERNS = {
|
|
3
|
+
google: /^G-[A-Z0-9]+$/i,
|
|
4
|
+
posthog: /^phc_[a-zA-Z0-9]+$/,
|
|
5
|
+
plausible: /^[a-zA-Z0-9._-]+$/
|
|
6
|
+
};
|
|
7
|
+
function isValidAnalyticsId(provider, id) {
|
|
8
|
+
const pattern = ANALYTICS_ID_PATTERNS[provider];
|
|
9
|
+
return pattern ? pattern.test(id) : false;
|
|
10
|
+
}
|
|
11
|
+
function getAnalyticsScript(config) {
|
|
12
|
+
if (!isValidAnalyticsId(config.provider, config.id)) {
|
|
13
|
+
console.warn(
|
|
14
|
+
`[whop-kit] Invalid ${config.provider} analytics ID format: ${config.id}`
|
|
15
|
+
);
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
switch (config.provider) {
|
|
19
|
+
case "google":
|
|
20
|
+
return `<script async src="https://www.googletagmanager.com/gtag/js?id=${config.id}"></script><script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('js',new Date());gtag('config','${config.id}')</script>`;
|
|
21
|
+
case "posthog":
|
|
22
|
+
return `<script>!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init capture register register_once register_for_session unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group setPersonProperties resetPersonProperties setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags startSessionRecording stopSessionRecording sessionRecordingStarted loadToolbar get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSurvey getSurvey getActiveMatchingSurveys renderSurvey canRenderSurvey".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);posthog.init('${config.id}',{api_host:'https://us.i.posthog.com',person_profiles:'identified_only'})</script>`;
|
|
23
|
+
case "plausible":
|
|
24
|
+
return `<script defer data-domain="${config.id}" src="https://plausible.io/js/script.js"></script>`;
|
|
25
|
+
default:
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { ANALYTICS_ID_PATTERNS, getAnalyticsScript, isValidAnalyticsId };
|
|
31
|
+
//# sourceMappingURL=chunk-5INLS5FZ.js.map
|
|
32
|
+
//# sourceMappingURL=chunk-5INLS5FZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/analytics/index.ts"],"names":[],"mappings":";AAeO,IAAM,qBAAA,GAAgD;AAAA,EAC3D,MAAA,EAAQ,gBAAA;AAAA,EACR,OAAA,EAAS,oBAAA;AAAA,EACT,SAAA,EAAW;AACb;AAKO,SAAS,kBAAA,CACd,UACA,EAAA,EACS;AACT,EAAA,MAAM,OAAA,GAAU,sBAAsB,QAAQ,CAAA;AAC9C,EAAA,OAAO,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,GAAI,KAAA;AACtC;AAUO,SAAS,mBAAmB,MAAA,EAAwC;AACzE,EAAA,IAAI,CAAC,kBAAA,CAAmB,MAAA,CAAO,QAAA,EAAU,MAAA,CAAO,EAAE,CAAA,EAAG;AACnD,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,CAAA,mBAAA,EAAsB,MAAA,CAAO,QAAQ,CAAA,sBAAA,EAAyB,OAAO,EAAE,CAAA;AAAA,KACzE;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,QAAQ,OAAO,QAAA;AAAU,IACvB,KAAK,QAAA;AACH,MAAA,OAAO,CAAA,+DAAA,EAAkE,MAAA,CAAO,EAAE,CAAA,wIAAA,EAA2I,OAAO,EAAE,CAAA,WAAA,CAAA;AAAA,IAExO,KAAK,SAAA;AACH,MAAA,OAAO,CAAA,y1CAAA,EAA41C,OAAO,EAAE,CAAA,mFAAA,CAAA;AAAA,IAE92C,KAAK,WAAA;AACH,MAAA,OAAO,CAAA,2BAAA,EAA8B,OAAO,EAAE,CAAA,mDAAA,CAAA;AAAA,IAEhD;AACE,MAAA,OAAO,IAAA;AAAA;AAEb","file":"chunk-5INLS5FZ.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Analytics — script generation for common providers\n// ---------------------------------------------------------------------------\n// Returns HTML script tags as strings. Framework-agnostic — inject\n// into your <head> however your framework supports it.\n// ---------------------------------------------------------------------------\n\nexport type AnalyticsProvider = \"posthog\" | \"google\" | \"plausible\";\n\nexport interface AnalyticsConfig {\n provider: AnalyticsProvider;\n id: string;\n}\n\n/** Validation patterns for analytics IDs to prevent XSS injection */\nexport const ANALYTICS_ID_PATTERNS: Record<string, RegExp> = {\n google: /^G-[A-Z0-9]+$/i,\n posthog: /^phc_[a-zA-Z0-9]+$/,\n plausible: /^[a-zA-Z0-9._-]+$/,\n};\n\n/**\n * Validate an analytics ID against its provider's expected format.\n */\nexport function isValidAnalyticsId(\n provider: AnalyticsProvider,\n id: string,\n): boolean {\n const pattern = ANALYTICS_ID_PATTERNS[provider];\n return pattern ? pattern.test(id) : false;\n}\n\n/**\n * Generate the analytics script HTML for a provider.\n * Returns null if the ID fails format validation (XSS prevention).\n *\n * @example\n * const script = getAnalyticsScript({ provider: \"posthog\", id: \"phc_xxxxx\" });\n * // Inject into <head>: <Fragment set:html={script} />\n */\nexport function getAnalyticsScript(config: AnalyticsConfig): string | null {\n if (!isValidAnalyticsId(config.provider, config.id)) {\n console.warn(\n `[whop-kit] Invalid ${config.provider} analytics ID format: ${config.id}`,\n );\n return null;\n }\n\n switch (config.provider) {\n case \"google\":\n return `<script async src=\"https://www.googletagmanager.com/gtag/js?id=${config.id}\"></script><script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('js',new Date());gtag('config','${config.id}')</script>`;\n\n case \"posthog\":\n return `<script>!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(\".\");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement(\"script\")).type=\"text/javascript\",p.async=!0,p.src=s.api_host+\"/static/array.js\",(r=t.getElementsByTagName(\"script\")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a=\"posthog\",u.people=u.people||[],u.toString=function(t){var e=\"posthog\";return\"posthog\"!==a&&(e+=\".\"+a),t||(e+=\" (stub)\"),e},u.people.toString=function(){return u.toString(1)+\".people (stub)\"},o=\"init capture register register_once register_for_session unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group setPersonProperties resetPersonProperties setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags startSessionRecording stopSessionRecording sessionRecordingStarted loadToolbar get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSurvey getSurvey getActiveMatchingSurveys renderSurvey canRenderSurvey\".split(\" \"),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);posthog.init('${config.id}',{api_host:'https://us.i.posthog.com',person_profiles:'identified_only'})</script>`;\n\n case \"plausible\":\n return `<script defer data-domain=\"${config.id}\" src=\"https://plausible.io/js/script.js\"></script>`;\n\n default:\n return null;\n }\n}\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { verifyWebhookSignature } from './chunk-EYK3S5U2.js';
|
|
2
|
+
|
|
3
|
+
// src/webhooks/index.ts
|
|
4
|
+
function createWebhookHandler(options) {
|
|
5
|
+
const {
|
|
6
|
+
secret,
|
|
7
|
+
on,
|
|
8
|
+
maxPayloadSize = 1e6,
|
|
9
|
+
onUnhandled = (type) => console.log(`[whop-kit] Unhandled webhook event: ${type}`),
|
|
10
|
+
onError = (type, err) => console.error(`[whop-kit] Webhook error processing ${type}:`, err)
|
|
11
|
+
} = options;
|
|
12
|
+
return async (body, headers, contentLength) => {
|
|
13
|
+
if (contentLength !== void 0 && contentLength > maxPayloadSize) {
|
|
14
|
+
return { status: 413, body: { error: "Payload too large" } };
|
|
15
|
+
}
|
|
16
|
+
const isValid = await verifyWebhookSignature(body, headers, secret);
|
|
17
|
+
if (!isValid) {
|
|
18
|
+
return { status: 401, body: { error: "Invalid signature" } };
|
|
19
|
+
}
|
|
20
|
+
let event;
|
|
21
|
+
try {
|
|
22
|
+
event = JSON.parse(body);
|
|
23
|
+
} catch {
|
|
24
|
+
return { status: 400, body: { error: "Invalid JSON" } };
|
|
25
|
+
}
|
|
26
|
+
const eventType = event.type;
|
|
27
|
+
console.log(`[whop-kit] Webhook received: ${eventType}`);
|
|
28
|
+
const handler = on[eventType];
|
|
29
|
+
if (!handler) {
|
|
30
|
+
onUnhandled(eventType, event.data);
|
|
31
|
+
return { status: 200, body: { received: true } };
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
await handler(event.data, event);
|
|
35
|
+
return { status: 200, body: { received: true } };
|
|
36
|
+
} catch (err) {
|
|
37
|
+
onError(eventType, err);
|
|
38
|
+
return { status: 500, body: { error: "processing_failed" } };
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { createWebhookHandler };
|
|
44
|
+
//# sourceMappingURL=chunk-7W3CHSHP.js.map
|
|
45
|
+
//# sourceMappingURL=chunk-7W3CHSHP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/webhooks/index.ts"],"names":[],"mappings":";;;AAqEO,SAAS,qBACd,OAAA,EAC2F;AAC3F,EAAA,MAAM;AAAA,IACJ,MAAA;AAAA,IACA,EAAA;AAAA,IACA,cAAA,GAAiB,GAAA;AAAA,IACjB,cAAc,CAAC,IAAA,KAAS,QAAQ,GAAA,CAAI,CAAA,oCAAA,EAAuC,IAAI,CAAA,CAAE,CAAA;AAAA,IACjF,OAAA,GAAU,CAAC,IAAA,EAAM,GAAA,KAAQ,QAAQ,KAAA,CAAM,CAAA,oCAAA,EAAuC,IAAI,CAAA,CAAA,CAAA,EAAK,GAAG;AAAA,GAC5F,GAAI,OAAA;AAEJ,EAAA,OAAO,OAAO,IAAA,EAAM,OAAA,EAAS,aAAA,KAAkB;AAE7C,IAAA,IAAI,aAAA,KAAkB,MAAA,IAAa,aAAA,GAAgB,cAAA,EAAgB;AACjE,MAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,MAAM,EAAE,KAAA,EAAO,qBAAoB,EAAE;AAAA,IAC7D;AAGA,IAAA,MAAM,OAAA,GAAU,MAAM,sBAAA,CAAuB,IAAA,EAAM,SAAS,MAAM,CAAA;AAClE,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,MAAM,EAAE,KAAA,EAAO,qBAAoB,EAAE;AAAA,IAC7D;AAGA,IAAA,IAAI,KAAA;AACJ,IAAA,IAAI;AACF,MAAA,KAAA,GAAQ,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,IACzB,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,MAAM,EAAE,KAAA,EAAO,gBAAe,EAAE;AAAA,IACxD;AAEA,IAAA,MAAM,YAAY,KAAA,CAAM,IAAA;AACxB,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,6BAAA,EAAgC,SAAS,CAAA,CAAE,CAAA;AAGvD,IAAA,MAAM,OAAA,GAAU,GAAG,SAAS,CAAA;AAC5B,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,WAAA,CAAY,SAAA,EAAW,MAAM,IAAI,CAAA;AACjC,MAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,MAAM,EAAE,QAAA,EAAU,MAAK,EAAE;AAAA,IACjD;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,CAAQ,KAAA,CAAM,IAAA,EAAM,KAAK,CAAA;AAC/B,MAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,MAAM,EAAE,QAAA,EAAU,MAAK,EAAE;AAAA,IACjD,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,CAAQ,WAAW,GAAG,CAAA;AAGtB,MAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAK,MAAM,EAAE,KAAA,EAAO,qBAAoB,EAAE;AAAA,IAC7D;AAAA,EACF,CAAA;AACF","file":"chunk-7W3CHSHP.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Webhook handler — declarative event routing with signature verification\n// ---------------------------------------------------------------------------\n// Bundles signature verification + JSON parsing + event routing + error\n// handling into a single call. Templates just register callbacks.\n// ---------------------------------------------------------------------------\n\nimport { verifyWebhookSignature } from \"../whop/index.js\";\nimport type { WebhookHeaders } from \"../whop/index.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Raw webhook event from Whop */\nexport interface WebhookEvent {\n type: string;\n data: Record<string, unknown>;\n}\n\n/** Result returned by the webhook handler */\nexport interface WebhookResult {\n status: number;\n body: Record<string, unknown>;\n}\n\n/** Event handler callback */\nexport type EventHandler = (\n data: Record<string, unknown>,\n event: WebhookEvent,\n) => void | Promise<void>;\n\nexport interface WebhookHandlerOptions {\n /** Your webhook signing secret */\n secret: string;\n /** Map of event type → handler function */\n on: Record<string, EventHandler>;\n /** Max payload size in bytes. Defaults to 1MB. */\n maxPayloadSize?: number;\n /** Called for unhandled event types. Defaults to console.log. */\n onUnhandled?: (eventType: string, data: Record<string, unknown>) => void;\n /** Called when an event handler throws. Defaults to console.error. */\n onError?: (eventType: string, error: unknown) => void;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a webhook handler that verifies signatures and routes events.\n *\n * @example\n * const handle = createWebhookHandler({\n * secret: process.env.WHOP_WEBHOOK_SECRET,\n * on: {\n * membership_activated: async (data) => {\n * await subs.activateMembership(data.user_id, \"pro\", data.id);\n * },\n * membership_deactivated: async (data) => {\n * await subs.deactivateMembership(data.user_id);\n * },\n * },\n * });\n *\n * // In your route handler:\n * const result = await handle(rawBody, headers);\n * return new Response(JSON.stringify(result.body), { status: result.status });\n */\nexport function createWebhookHandler(\n options: WebhookHandlerOptions,\n): (body: string, headers: WebhookHeaders, contentLength?: number) => Promise<WebhookResult> {\n const {\n secret,\n on,\n maxPayloadSize = 1_000_000,\n onUnhandled = (type) => console.log(`[whop-kit] Unhandled webhook event: ${type}`),\n onError = (type, err) => console.error(`[whop-kit] Webhook error processing ${type}:`, err),\n } = options;\n\n return async (body, headers, contentLength) => {\n // Guard against oversized payloads\n if (contentLength !== undefined && contentLength > maxPayloadSize) {\n return { status: 413, body: { error: \"Payload too large\" } };\n }\n\n // Verify signature\n const isValid = await verifyWebhookSignature(body, headers, secret);\n if (!isValid) {\n return { status: 401, body: { error: \"Invalid signature\" } };\n }\n\n // Parse JSON\n let event: WebhookEvent;\n try {\n event = JSON.parse(body);\n } catch {\n return { status: 400, body: { error: \"Invalid JSON\" } };\n }\n\n const eventType = event.type;\n console.log(`[whop-kit] Webhook received: ${eventType}`);\n\n // Route to handler\n const handler = on[eventType];\n if (!handler) {\n onUnhandled(eventType, event.data);\n return { status: 200, body: { received: true } };\n }\n\n try {\n await handler(event.data, event);\n return { status: 200, body: { received: true } };\n } catch (err) {\n onError(eventType, err);\n // Return 500 so Whop retries — the event was authenticated\n // but processing failed (likely a DB error)\n return { status: 500, body: { error: \"processing_failed\" } };\n }\n };\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,3 +5,5 @@ export { ConfigManager, ConfigManagerOptions, ConfigStore, createConfigManager }
|
|
|
5
5
|
export { DbAdapter, SubscriptionDetails, SubscriptionDetailsResult, SubscriptionHelpers, SubscriptionStatus, UserRecord, createSubscriptionHelpers } from './subscriptions/index.js';
|
|
6
6
|
export { EmailConfig, EmailProvider, SendEmailOptions, SendEmailResult, emailWrapper, escapeHtml, sendEmail } from './email/index.js';
|
|
7
7
|
export { cn, formatDate, monthlyEquivalent } from './utils/index.js';
|
|
8
|
+
export { ANALYTICS_ID_PATTERNS, AnalyticsConfig, AnalyticsProvider, getAnalyticsScript, isValidAnalyticsId } from './analytics/index.js';
|
|
9
|
+
export { EventHandler, WebhookEvent, WebhookHandlerOptions, WebhookResult, createWebhookHandler } from './webhooks/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
export { createWebhookHandler } from './chunk-7W3CHSHP.js';
|
|
2
|
+
export { buildAuthorizationUrl, checkWhopAccess, exchangeCodeForTokens, fetchWhopPlanDetails, getEffectivePrice, getWhopUser, randomString, sha256, uncancelMembership, verifyWebhookSignature } from './chunk-EYK3S5U2.js';
|
|
3
|
+
export { ANALYTICS_ID_PATTERNS, getAnalyticsScript, isValidAnalyticsId } from './chunk-5INLS5FZ.js';
|
|
1
4
|
export { clearSessionCookie, createSessionToken, encodeSecret, generateSecret, getSessionFromCookie, setSessionCookie, verifySessionToken } from './chunk-GXQLG4HV.js';
|
|
2
5
|
export { createConfigManager } from './chunk-PLZUFPEG.js';
|
|
3
6
|
export { definePlans } from './chunk-ZQ44KZRC.js';
|
|
4
7
|
export { emailWrapper, escapeHtml, sendEmail } from './chunk-KQQGVBBH.js';
|
|
5
8
|
export { createSubscriptionHelpers } from './chunk-NS32METI.js';
|
|
6
9
|
export { cn, formatDate, monthlyEquivalent } from './chunk-BLQ7T7NQ.js';
|
|
7
|
-
export { buildAuthorizationUrl, checkWhopAccess, exchangeCodeForTokens, fetchWhopPlanDetails, getEffectivePrice, getWhopUser, randomString, sha256, uncancelMembership, verifyWebhookSignature } from './chunk-EYK3S5U2.js';
|
|
8
10
|
//# sourceMappingURL=index.js.map
|
|
9
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { WebhookHeaders } from '../whop/index.js';
|
|
2
|
+
|
|
3
|
+
/** Raw webhook event from Whop */
|
|
4
|
+
interface WebhookEvent {
|
|
5
|
+
type: string;
|
|
6
|
+
data: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
/** Result returned by the webhook handler */
|
|
9
|
+
interface WebhookResult {
|
|
10
|
+
status: number;
|
|
11
|
+
body: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
/** Event handler callback */
|
|
14
|
+
type EventHandler = (data: Record<string, unknown>, event: WebhookEvent) => void | Promise<void>;
|
|
15
|
+
interface WebhookHandlerOptions {
|
|
16
|
+
/** Your webhook signing secret */
|
|
17
|
+
secret: string;
|
|
18
|
+
/** Map of event type → handler function */
|
|
19
|
+
on: Record<string, EventHandler>;
|
|
20
|
+
/** Max payload size in bytes. Defaults to 1MB. */
|
|
21
|
+
maxPayloadSize?: number;
|
|
22
|
+
/** Called for unhandled event types. Defaults to console.log. */
|
|
23
|
+
onUnhandled?: (eventType: string, data: Record<string, unknown>) => void;
|
|
24
|
+
/** Called when an event handler throws. Defaults to console.error. */
|
|
25
|
+
onError?: (eventType: string, error: unknown) => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a webhook handler that verifies signatures and routes events.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* const handle = createWebhookHandler({
|
|
32
|
+
* secret: process.env.WHOP_WEBHOOK_SECRET,
|
|
33
|
+
* on: {
|
|
34
|
+
* membership_activated: async (data) => {
|
|
35
|
+
* await subs.activateMembership(data.user_id, "pro", data.id);
|
|
36
|
+
* },
|
|
37
|
+
* membership_deactivated: async (data) => {
|
|
38
|
+
* await subs.deactivateMembership(data.user_id);
|
|
39
|
+
* },
|
|
40
|
+
* },
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* // In your route handler:
|
|
44
|
+
* const result = await handle(rawBody, headers);
|
|
45
|
+
* return new Response(JSON.stringify(result.body), { status: result.status });
|
|
46
|
+
*/
|
|
47
|
+
declare function createWebhookHandler(options: WebhookHandlerOptions): (body: string, headers: WebhookHeaders, contentLength?: number) => Promise<WebhookResult>;
|
|
48
|
+
|
|
49
|
+
export { type EventHandler, type WebhookEvent, type WebhookHandlerOptions, type WebhookResult, createWebhookHandler };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "whop-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Framework-agnostic toolkit for building apps with Whop authentication, payments, and memberships",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,6 +41,14 @@
|
|
|
41
41
|
"./utils": {
|
|
42
42
|
"import": "./dist/utils/index.js",
|
|
43
43
|
"types": "./dist/utils/index.d.ts"
|
|
44
|
+
},
|
|
45
|
+
"./analytics": {
|
|
46
|
+
"import": "./dist/analytics/index.js",
|
|
47
|
+
"types": "./dist/analytics/index.d.ts"
|
|
48
|
+
},
|
|
49
|
+
"./webhooks": {
|
|
50
|
+
"import": "./dist/webhooks/index.js",
|
|
51
|
+
"types": "./dist/webhooks/index.d.ts"
|
|
44
52
|
}
|
|
45
53
|
},
|
|
46
54
|
"files": [
|