paddle-checkout-accelerator 2.1.0 → 2.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/bin/paddle-checkout-accelerator.js +247 -0
- package/dist/index.cjs +1150 -0
- package/dist/index.d.cts +290 -0
- package/dist/index.d.ts +290 -0
- package/dist/index.js +1079 -0
- package/package.json +14 -7
- package/recipes/nextjs/app/billing.ts +1 -1
- package/dist/package/index.d.ts +0 -28
- package/dist/package/index.js +0 -28
- package/dist/src/components/paddle/BillingHistory.d.ts +0 -1
- package/dist/src/components/paddle/BillingHistory.js +0 -17
- package/dist/src/components/paddle/CustomerPortal.d.ts +0 -1
- package/dist/src/components/paddle/CustomerPortal.js +0 -5
- package/dist/src/components/paddle/CustomerPortalButton.d.ts +0 -1
- package/dist/src/components/paddle/CustomerPortalButton.js +0 -31
- package/dist/src/components/paddle/InlineCheckout.d.ts +0 -5
- package/dist/src/components/paddle/InlineCheckout.js +0 -13
- package/dist/src/components/paddle/PricingTable.d.ts +0 -1
- package/dist/src/components/paddle/PricingTable.js +0 -27
- package/dist/src/components/paddle/SubscriptionCard.d.ts +0 -6
- package/dist/src/components/paddle/SubscriptionCard.js +0 -5
- package/dist/src/components/paddle/TrialBanner.d.ts +0 -5
- package/dist/src/components/paddle/TrialBanner.js +0 -5
- package/dist/src/components/paddle/UpgradeModal.d.ts +0 -11
- package/dist/src/components/paddle/UpgradeModal.js +0 -35
- package/dist/src/components/paddle/UsageMeter.d.ts +0 -6
- package/dist/src/components/paddle/UsageMeter.js +0 -8
- package/dist/src/components/paddle/gates/SubscriptionGate.d.ts +0 -7
- package/dist/src/components/paddle/gates/SubscriptionGate.js +0 -8
- package/dist/src/lib/billing/adapters/index.d.ts +0 -3
- package/dist/src/lib/billing/adapters/index.js +0 -3
- package/dist/src/lib/billing/adapters/memory.d.ts +0 -2
- package/dist/src/lib/billing/adapters/memory.js +0 -41
- package/dist/src/lib/billing/adapters/prisma/index.d.ts +0 -28
- package/dist/src/lib/billing/adapters/prisma/index.js +0 -80
- package/dist/src/lib/billing/adapters/types.d.ts +0 -13
- package/dist/src/lib/billing/adapters/types.js +0 -1
- package/dist/src/lib/billing/configure.d.ts +0 -6
- package/dist/src/lib/billing/configure.js +0 -13
- package/dist/src/lib/billing/customer-repair.d.ts +0 -4
- package/dist/src/lib/billing/customer-repair.js +0 -19
- package/dist/src/lib/billing/demo-seed.d.ts +0 -1
- package/dist/src/lib/billing/demo-seed.js +0 -13
- package/dist/src/lib/billing/entitlements.d.ts +0 -3
- package/dist/src/lib/billing/entitlements.js +0 -16
- package/dist/src/lib/billing/events.d.ts +0 -12
- package/dist/src/lib/billing/events.js +0 -20
- package/dist/src/lib/billing/plans.d.ts +0 -9
- package/dist/src/lib/billing/plans.js +0 -41
- package/dist/src/lib/billing/protection.d.ts +0 -6
- package/dist/src/lib/billing/protection.js +0 -16
- package/dist/src/lib/billing/refresh.d.ts +0 -1
- package/dist/src/lib/billing/refresh.js +0 -32
- package/dist/src/lib/billing/subscriptions.d.ts +0 -16
- package/dist/src/lib/billing/subscriptions.js +0 -36
- package/dist/src/lib/billing/teams.d.ts +0 -42
- package/dist/src/lib/billing/teams.js +0 -104
- package/dist/src/lib/billing/usage.d.ts +0 -17
- package/dist/src/lib/billing/usage.js +0 -40
- package/dist/src/lib/billing/webhook-sync.d.ts +0 -26
- package/dist/src/lib/billing/webhook-sync.js +0 -39
- package/dist/src/lib/paddle/api.d.ts +0 -1
- package/dist/src/lib/paddle/api.js +0 -21
- package/dist/src/lib/paddle/client.d.ts +0 -1
- package/dist/src/lib/paddle/client.js +0 -13
- package/dist/src/lib/paddle/customers.d.ts +0 -15
- package/dist/src/lib/paddle/customers.js +0 -14
- package/dist/src/lib/paddle/events.d.ts +0 -10
- package/dist/src/lib/paddle/events.js +0 -11
- package/dist/src/lib/paddle/hooks.d.ts +0 -4
- package/dist/src/lib/paddle/hooks.js +0 -11
- package/dist/src/lib/paddle/portal.d.ts +0 -8
- package/dist/src/lib/paddle/portal.js +0 -28
- package/dist/src/lib/paddle/subscriptions.d.ts +0 -20
- package/dist/src/lib/paddle/subscriptions.js +0 -10
- package/dist/src/lib/paddle/types.d.ts +0 -8
- package/dist/src/lib/paddle/types.js +0 -1
- package/dist/src/lib/paddle/webhook.d.ts +0 -1
- package/dist/src/lib/paddle/webhook.js +0 -8
- package/dist/src/lib/utils.d.ts +0 -2
- package/dist/src/lib/utils.js +0 -5
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paddle-checkout-accelerator",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "next dev",
|
|
6
6
|
"build": "next build",
|
|
7
7
|
"start": "next start",
|
|
8
8
|
"lint": "eslint",
|
|
9
9
|
"test": "vitest run",
|
|
10
|
-
"build:package": "
|
|
10
|
+
"build:package": "tsup",
|
|
11
11
|
"prepack": "npm run build:package"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
@@ -37,23 +37,30 @@
|
|
|
37
37
|
"eslint": "^9",
|
|
38
38
|
"eslint-config-next": "16.2.9",
|
|
39
39
|
"tailwindcss": "^4",
|
|
40
|
+
"tsup": "^8.5.1",
|
|
40
41
|
"typescript": "^5",
|
|
41
42
|
"vitest": "^4.1.8"
|
|
42
43
|
},
|
|
43
44
|
"type": "module",
|
|
44
|
-
"main": "./dist/
|
|
45
|
-
"types": "./dist/
|
|
45
|
+
"main": "./dist/index.cjs",
|
|
46
|
+
"types": "./dist/index.d.ts",
|
|
46
47
|
"exports": {
|
|
47
48
|
".": {
|
|
48
|
-
"types": "./dist/
|
|
49
|
-
"import": "./dist/
|
|
49
|
+
"types": "./dist/index.d.ts",
|
|
50
|
+
"import": "./dist/index.js",
|
|
51
|
+
"require": "./dist/index.cjs"
|
|
50
52
|
}
|
|
51
53
|
},
|
|
52
54
|
"files": [
|
|
53
55
|
"dist",
|
|
56
|
+
"bin",
|
|
54
57
|
"README.md",
|
|
55
58
|
"LICENSE",
|
|
56
59
|
"docs",
|
|
57
60
|
"recipes"
|
|
58
|
-
]
|
|
61
|
+
],
|
|
62
|
+
"module": "./dist/index.js",
|
|
63
|
+
"bin": {
|
|
64
|
+
"paddle-checkout-accelerator": "./bin/paddle-checkout-accelerator.js"
|
|
65
|
+
}
|
|
59
66
|
}
|
package/dist/package/index.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export * from "../src/components/paddle/UpgradeModal";
|
|
2
|
-
export * from "../src/components/paddle/UsageMeter";
|
|
3
|
-
export * from "../src/components/paddle/TrialBanner";
|
|
4
|
-
export * from "../src/components/paddle/BillingHistory";
|
|
5
|
-
export * from "../src/components/paddle/CustomerPortalButton";
|
|
6
|
-
export * from "../src/components/paddle/SubscriptionCard";
|
|
7
|
-
export * from "../src/components/paddle/gates/SubscriptionGate";
|
|
8
|
-
export * from "../src/lib/paddle/hooks";
|
|
9
|
-
export * from "../src/lib/paddle/client";
|
|
10
|
-
export * from "../src/lib/paddle/types";
|
|
11
|
-
export * from "../src/lib/paddle/webhook";
|
|
12
|
-
export * from "../src/lib/billing/plans";
|
|
13
|
-
export * from "../src/lib/billing/subscriptions";
|
|
14
|
-
export * from "../src/lib/billing/entitlements";
|
|
15
|
-
export * from "../src/lib/billing/usage";
|
|
16
|
-
export * from "../src/lib/billing/webhook-sync";
|
|
17
|
-
export * from "../src/lib/billing/adapters";
|
|
18
|
-
export * from "../src/lib/billing/protection";
|
|
19
|
-
export * from "../src/lib/billing/demo-seed";
|
|
20
|
-
export * from "../src/lib/paddle/portal";
|
|
21
|
-
export * from "../src/lib/paddle/api";
|
|
22
|
-
export * from "../src/lib/paddle/subscriptions";
|
|
23
|
-
export * from "../src/lib/billing/refresh";
|
|
24
|
-
export * from "../src/lib/paddle/customers";
|
|
25
|
-
export * from "../src/lib/billing/customer-repair";
|
|
26
|
-
export * from "../src/lib/billing/teams";
|
|
27
|
-
export * from "../src/lib/billing/events";
|
|
28
|
-
export * from "../src/lib/billing/configure";
|
package/dist/package/index.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export * from "../src/components/paddle/UpgradeModal";
|
|
2
|
-
export * from "../src/components/paddle/UsageMeter";
|
|
3
|
-
export * from "../src/components/paddle/TrialBanner";
|
|
4
|
-
export * from "../src/components/paddle/BillingHistory";
|
|
5
|
-
export * from "../src/components/paddle/CustomerPortalButton";
|
|
6
|
-
export * from "../src/components/paddle/SubscriptionCard";
|
|
7
|
-
export * from "../src/components/paddle/gates/SubscriptionGate";
|
|
8
|
-
export * from "../src/lib/paddle/hooks";
|
|
9
|
-
export * from "../src/lib/paddle/client";
|
|
10
|
-
export * from "../src/lib/paddle/types";
|
|
11
|
-
export * from "../src/lib/paddle/webhook";
|
|
12
|
-
export * from "../src/lib/billing/plans";
|
|
13
|
-
export * from "../src/lib/billing/subscriptions";
|
|
14
|
-
export * from "../src/lib/billing/entitlements";
|
|
15
|
-
export * from "../src/lib/billing/usage";
|
|
16
|
-
export * from "../src/lib/billing/webhook-sync";
|
|
17
|
-
export * from "../src/lib/billing/adapters";
|
|
18
|
-
export * from "../src/lib/billing/protection";
|
|
19
|
-
export * from "../src/lib/billing/demo-seed";
|
|
20
|
-
export * from "../src/lib/paddle/portal";
|
|
21
|
-
export * from "../src/lib/paddle/api";
|
|
22
|
-
export * from "../src/lib/paddle/subscriptions";
|
|
23
|
-
export * from "../src/lib/billing/refresh";
|
|
24
|
-
export * from "../src/lib/paddle/customers";
|
|
25
|
-
export * from "../src/lib/billing/customer-repair";
|
|
26
|
-
export * from "../src/lib/billing/teams";
|
|
27
|
-
export * from "../src/lib/billing/events";
|
|
28
|
-
export * from "../src/lib/billing/configure";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function BillingHistory(): import("react").JSX.Element;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
const invoices = [
|
|
4
|
-
{
|
|
5
|
-
id: "INV-001",
|
|
6
|
-
amount: "$79",
|
|
7
|
-
status: "Paid",
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
id: "INV-002",
|
|
11
|
-
amount: "$79",
|
|
12
|
-
status: "Paid",
|
|
13
|
-
},
|
|
14
|
-
];
|
|
15
|
-
export function BillingHistory() {
|
|
16
|
-
return (_jsx("div", { className: "rounded-xl border", children: invoices.map((invoice) => (_jsxs("div", { className: "flex justify-between border-b p-4", children: [_jsx("div", { children: invoice.id }), _jsx("div", { children: invoice.amount }), _jsx("div", { children: invoice.status })] }, invoice.id))) }));
|
|
17
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function CustomerPortal(): import("react").JSX.Element;
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
export default function CustomerPortal() {
|
|
4
|
-
return (_jsxs("div", { className: "rounded-3xl border p-8", children: [_jsx("h2", { className: "text-3xl font-bold", children: "Customer Portal" }), _jsxs("div", { className: "mt-8 space-y-4", children: [_jsx("div", { className: "rounded-xl border p-4", children: "Current Plan: Pro" }), _jsx("div", { className: "rounded-xl border p-4", children: "Status: Active" }), _jsx("div", { className: "rounded-xl border p-4", children: "Renewal Date: July 1, 2026" }), _jsx("button", { className: "rounded-xl bg-black px-5 py-3 text-white", children: "Manage Subscription" })] })] }));
|
|
5
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function CustomerPortalButton(): import("react").JSX.Element;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
export function CustomerPortalButton() {
|
|
5
|
-
const [loading, setLoading] = useState(false);
|
|
6
|
-
const [error, setError] = useState(null);
|
|
7
|
-
async function launchPortal() {
|
|
8
|
-
try {
|
|
9
|
-
setLoading(true);
|
|
10
|
-
setError(null);
|
|
11
|
-
const response = await fetch("/api/paddle/portal-session", { method: "POST" });
|
|
12
|
-
const data = (await response.json());
|
|
13
|
-
if (!response.ok || !data.success || !data.url) {
|
|
14
|
-
throw new Error(data.error ??
|
|
15
|
-
"Unable to open billing portal");
|
|
16
|
-
}
|
|
17
|
-
window.location.href = data.url;
|
|
18
|
-
}
|
|
19
|
-
catch (err) {
|
|
20
|
-
setError(err instanceof Error
|
|
21
|
-
? err.message
|
|
22
|
-
: "Unable to open billing portal");
|
|
23
|
-
}
|
|
24
|
-
finally {
|
|
25
|
-
setLoading(false);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return (_jsxs("div", { className: "space-y-3", children: [_jsx("button", { onClick: launchPortal, disabled: loading, className: "rounded-xl bg-black px-4 py-3 text-white disabled:opacity-60", children: loading
|
|
29
|
-
? "Opening Billing..."
|
|
30
|
-
: "Manage Billing" }), error && (_jsx("div", { className: "rounded-xl border border-red-200 bg-red-50 p-3 text-sm text-red-700", children: error }))] }));
|
|
31
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useState } from "react";
|
|
4
|
-
export default function InlineCheckout({ priceId, }) {
|
|
5
|
-
const [loading, setLoading] = useState(true);
|
|
6
|
-
useEffect(() => {
|
|
7
|
-
const timer = setTimeout(() => {
|
|
8
|
-
setLoading(false);
|
|
9
|
-
}, 1500);
|
|
10
|
-
return () => clearTimeout(timer);
|
|
11
|
-
}, []);
|
|
12
|
-
return (_jsx("div", { className: "rounded-3xl border bg-white p-6", children: loading ? (_jsxs("div", { className: "space-y-4 animate-pulse", children: [_jsx("div", { className: "h-10 rounded bg-gray-100" }), _jsx("div", { className: "h-10 rounded bg-gray-100" }), _jsx("div", { className: "h-40 rounded bg-gray-100" })] })) : (_jsxs("div", { children: [_jsx("div", { className: "mb-4 text-sm text-gray-500", children: "Paddle Inline Checkout" }), _jsx("div", { id: "paddle-inline-checkout", "data-price-id": priceId, className: "min-h-[500px] rounded-xl border" })] })) }));
|
|
13
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function PricingTable(): import("react").JSX.Element;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Check } from "lucide-react";
|
|
4
|
-
const plans = [
|
|
5
|
-
{
|
|
6
|
-
name: "Starter",
|
|
7
|
-
price: "$29",
|
|
8
|
-
features: [
|
|
9
|
-
"1 Project",
|
|
10
|
-
"Lifetime Updates",
|
|
11
|
-
"Source Code"
|
|
12
|
-
]
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
name: "Pro",
|
|
16
|
-
price: "$79",
|
|
17
|
-
featured: true,
|
|
18
|
-
features: [
|
|
19
|
-
"Unlimited Projects",
|
|
20
|
-
"Premium Components",
|
|
21
|
-
"Priority Support"
|
|
22
|
-
]
|
|
23
|
-
}
|
|
24
|
-
];
|
|
25
|
-
export default function PricingTable() {
|
|
26
|
-
return (_jsx("div", { className: "grid gap-8 md:grid-cols-2", children: plans.map((plan) => (_jsxs("div", { className: `rounded-3xl border p-8 ${plan.featured ? "ring-2 ring-black" : ""}`, children: [_jsx("h3", { className: "text-2xl font-bold", children: plan.name }), _jsx("div", { className: "mt-6 text-5xl font-bold", children: plan.price }), _jsx("ul", { className: "mt-8 space-y-4", children: plan.features.map((feature) => (_jsxs("li", { className: "flex gap-3", children: [_jsx(Check, { size: 18 }), feature] }, feature))) }), _jsx("button", { className: "mt-8 w-full rounded-xl bg-black py-3 text-white", children: "Buy Now" })] }, plan.name))) }));
|
|
27
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
export function SubscriptionCard({ plan, status, }) {
|
|
4
|
-
return (_jsxs("div", { className: "rounded-2xl border p-6", children: [_jsx("div", { className: "text-sm text-gray-500", children: "Current Plan" }), _jsx("div", { className: "mt-2 text-3xl font-bold", children: plan }), _jsxs("div", { className: "mt-4", children: ["Status: ", status] })] }));
|
|
5
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
export function TrialBanner({ daysRemaining, }) {
|
|
4
|
-
return (_jsxs("div", { className: "rounded-xl border border-yellow-300 bg-yellow-50 p-4", children: ["Trial expires in", " ", _jsxs("strong", { children: [daysRemaining, " days"] }), "."] }));
|
|
5
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
interface UpgradeModalProps {
|
|
2
|
-
open: boolean;
|
|
3
|
-
onClose: () => void;
|
|
4
|
-
currentPlan: string;
|
|
5
|
-
targetPlan: string;
|
|
6
|
-
targetPriceId: string;
|
|
7
|
-
yearlySavings?: string;
|
|
8
|
-
onUpgradeSuccess?: (data: unknown) => void;
|
|
9
|
-
}
|
|
10
|
-
export declare function UpgradeModal({ open, onClose, currentPlan, targetPlan, targetPriceId, yearlySavings, onUpgradeSuccess, }: UpgradeModalProps): import("react").JSX.Element | null;
|
|
11
|
-
export {};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import { ArrowRight, Check, Loader2, X, } from "lucide-react";
|
|
5
|
-
import { openCheckout } from "@/lib/paddle/hooks";
|
|
6
|
-
export function UpgradeModal({ open, onClose, currentPlan, targetPlan, targetPriceId, yearlySavings, onUpgradeSuccess, }) {
|
|
7
|
-
const [loading, setLoading] = useState(false);
|
|
8
|
-
const [error, setError] = useState(null);
|
|
9
|
-
if (!open)
|
|
10
|
-
return null;
|
|
11
|
-
async function handleUpgrade() {
|
|
12
|
-
try {
|
|
13
|
-
setLoading(true);
|
|
14
|
-
setError(null);
|
|
15
|
-
await openCheckout([
|
|
16
|
-
{
|
|
17
|
-
priceId: targetPriceId,
|
|
18
|
-
quantity: 1,
|
|
19
|
-
},
|
|
20
|
-
]);
|
|
21
|
-
onUpgradeSuccess?.({
|
|
22
|
-
targetPlan,
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
catch (err) {
|
|
26
|
-
setError(err instanceof Error
|
|
27
|
-
? err.message
|
|
28
|
-
: "Unable to launch checkout");
|
|
29
|
-
}
|
|
30
|
-
finally {
|
|
31
|
-
setLoading(false);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4", children: _jsxs("div", { className: "w-full max-w-lg rounded-3xl border bg-white shadow-2xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b p-6", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-xl font-semibold", children: "Upgrade Plan" }), _jsx("p", { className: "mt-1 text-sm text-slate-500", children: "Unlock additional features" })] }), _jsx("button", { onClick: onClose, className: "rounded-lg p-2 hover:bg-slate-100", children: _jsx(X, { size: 18 }) })] }), _jsxs("div", { className: "p-6", children: [_jsx("div", { className: "rounded-2xl border p-5", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm text-slate-500", children: "Current" }), _jsx("div", { className: "mt-1 font-semibold", children: currentPlan })] }), _jsx(ArrowRight, { className: "text-slate-400", size: 20 }), _jsxs("div", { className: "text-right", children: [_jsx("div", { className: "text-sm text-slate-500", children: "Upgrade To" }), _jsx("div", { className: "mt-1 font-semibold", children: targetPlan })] })] }) }), _jsx("div", { className: "mt-6 rounded-2xl bg-slate-50 p-5", children: _jsxs("ul", { className: "space-y-3", children: [_jsxs("li", { className: "flex items-center gap-3", children: [_jsx(Check, { size: 16 }), "Unlimited projects"] }), _jsxs("li", { className: "flex items-center gap-3", children: [_jsx(Check, { size: 16 }), "Advanced billing"] }), _jsxs("li", { className: "flex items-center gap-3", children: [_jsx(Check, { size: 16 }), "Priority support"] }), _jsxs("li", { className: "flex items-center gap-3", children: [_jsx(Check, { size: 16 }), "Team access"] })] }) }), yearlySavings && (_jsxs("div", { className: "mt-4 rounded-xl border border-emerald-200 bg-emerald-50 p-3 text-sm", children: ["Save ", yearlySavings] })), error && (_jsx("div", { className: "mt-4 rounded-xl border border-red-200 bg-red-50 p-3 text-sm text-red-700", children: error })), _jsx("button", { onClick: handleUpgrade, disabled: loading, className: "mt-6 flex w-full items-center justify-center gap-2 rounded-2xl bg-black px-5 py-4 text-white transition hover:opacity-90 disabled:opacity-50", children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 18, className: "animate-spin" }), "Launching Checkout..."] })) : (_jsxs(_Fragment, { children: ["Upgrade Now", _jsx(ArrowRight, { size: 18 })] })) })] })] }) }));
|
|
35
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
export function UsageMeter({ current, limit, }) {
|
|
4
|
-
const percentage = Math.min(100, (current / limit) * 100);
|
|
5
|
-
return (_jsxs("div", { className: "rounded-xl border p-5", children: [_jsxs("div", { className: "flex justify-between", children: [_jsx("span", { children: "Usage" }), _jsxs("span", { children: [current, "/", limit] })] }), _jsx("div", { className: "mt-3 h-3 rounded-full bg-gray-100", children: _jsx("div", { className: "h-3 rounded-full bg-black", style: {
|
|
6
|
-
width: `${percentage}%`,
|
|
7
|
-
} }) })] }));
|
|
8
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
interface SubscriptionGateProps {
|
|
2
|
-
active: boolean;
|
|
3
|
-
children: React.ReactNode;
|
|
4
|
-
fallback?: React.ReactNode;
|
|
5
|
-
}
|
|
6
|
-
export declare function SubscriptionGate({ active, children, fallback, }: SubscriptionGateProps): string | number | bigint | boolean | import("react").JSX.Element | Iterable<import("react").ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode> | null | undefined>;
|
|
7
|
-
export {};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
export function SubscriptionGate({ active, children, fallback, }) {
|
|
4
|
-
if (!active) {
|
|
5
|
-
return (fallback ?? (_jsx("div", { className: "rounded-xl border p-6", children: "Upgrade required." })));
|
|
6
|
-
}
|
|
7
|
-
return _jsx(_Fragment, { children: children });
|
|
8
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
const subscriptions = new Map();
|
|
2
|
-
const usage = new Map();
|
|
3
|
-
const teams = new Map();
|
|
4
|
-
const billingEvents = new Map();
|
|
5
|
-
function usageKey(userId, key, period) {
|
|
6
|
-
return `${userId}:${key}:${period}`;
|
|
7
|
-
}
|
|
8
|
-
export const memoryBillingAdapter = {
|
|
9
|
-
async getSubscription(userId) {
|
|
10
|
-
return subscriptions.get(userId) ?? null;
|
|
11
|
-
},
|
|
12
|
-
async upsertSubscription(record) {
|
|
13
|
-
subscriptions.set(record.userId, record);
|
|
14
|
-
return record;
|
|
15
|
-
},
|
|
16
|
-
async getUsage(userId, key, period) {
|
|
17
|
-
return (usage.get(usageKey(userId, key, period)) ?? 0);
|
|
18
|
-
},
|
|
19
|
-
async incrementUsage(userId, key, period, amount) {
|
|
20
|
-
const id = usageKey(userId, key, period);
|
|
21
|
-
const next = (usage.get(id) ?? 0) + amount;
|
|
22
|
-
usage.set(id, next);
|
|
23
|
-
return next;
|
|
24
|
-
},
|
|
25
|
-
async getTeam(teamId) {
|
|
26
|
-
return teams.get(teamId) ?? null;
|
|
27
|
-
},
|
|
28
|
-
async upsertTeam(team) {
|
|
29
|
-
teams.set(team.teamId, team);
|
|
30
|
-
return team;
|
|
31
|
-
},
|
|
32
|
-
async recordBillingEvent(event) {
|
|
33
|
-
const current = billingEvents.get(event.userId) ?? [];
|
|
34
|
-
current.unshift(event);
|
|
35
|
-
billingEvents.set(event.userId, current);
|
|
36
|
-
return event;
|
|
37
|
-
},
|
|
38
|
-
async getBillingEvents(userId) {
|
|
39
|
-
return (billingEvents.get(userId) ?? []);
|
|
40
|
-
},
|
|
41
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { BillingAdapter } from "../types";
|
|
2
|
-
import type { SubscriptionRecord } from "../../subscriptions";
|
|
3
|
-
import type { TeamRecord } from "../../teams";
|
|
4
|
-
import type { BillingEvent } from "../../events";
|
|
5
|
-
type PrismaLike = {
|
|
6
|
-
subscription: {
|
|
7
|
-
findUnique(args: unknown): Promise<SubscriptionRecord | null>;
|
|
8
|
-
upsert(args: unknown): Promise<SubscriptionRecord>;
|
|
9
|
-
};
|
|
10
|
-
usageEvent: {
|
|
11
|
-
findUnique(args: unknown): Promise<{
|
|
12
|
-
count: number;
|
|
13
|
-
} | null>;
|
|
14
|
-
upsert(args: unknown): Promise<{
|
|
15
|
-
count: number;
|
|
16
|
-
}>;
|
|
17
|
-
};
|
|
18
|
-
team: {
|
|
19
|
-
findUnique(args: unknown): Promise<TeamRecord | null>;
|
|
20
|
-
upsert(args: unknown): Promise<TeamRecord>;
|
|
21
|
-
};
|
|
22
|
-
billingEvent: {
|
|
23
|
-
create(args: unknown): Promise<BillingEvent>;
|
|
24
|
-
findMany(args: unknown): Promise<BillingEvent[]>;
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
export declare function createPrismaBillingAdapter(prisma: PrismaLike): BillingAdapter;
|
|
28
|
-
export {};
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
export function createPrismaBillingAdapter(prisma) {
|
|
2
|
-
return {
|
|
3
|
-
async getSubscription(userId) {
|
|
4
|
-
return prisma.subscription.findUnique({
|
|
5
|
-
where: { userId },
|
|
6
|
-
});
|
|
7
|
-
},
|
|
8
|
-
async upsertSubscription(record) {
|
|
9
|
-
return prisma.subscription.upsert({
|
|
10
|
-
where: {
|
|
11
|
-
userId: record.userId,
|
|
12
|
-
},
|
|
13
|
-
create: record,
|
|
14
|
-
update: record,
|
|
15
|
-
});
|
|
16
|
-
},
|
|
17
|
-
async getUsage(userId, key, period) {
|
|
18
|
-
const usage = await prisma.usageEvent.findUnique({
|
|
19
|
-
where: {
|
|
20
|
-
userId_key_period: {
|
|
21
|
-
userId,
|
|
22
|
-
key,
|
|
23
|
-
period,
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
return usage?.count ?? 0;
|
|
28
|
-
},
|
|
29
|
-
async incrementUsage(userId, key, period, amount) {
|
|
30
|
-
const usage = await prisma.usageEvent.upsert({
|
|
31
|
-
where: {
|
|
32
|
-
userId_key_period: {
|
|
33
|
-
userId,
|
|
34
|
-
key,
|
|
35
|
-
period,
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
create: {
|
|
39
|
-
userId,
|
|
40
|
-
key,
|
|
41
|
-
period,
|
|
42
|
-
count: amount,
|
|
43
|
-
},
|
|
44
|
-
update: {
|
|
45
|
-
count: {
|
|
46
|
-
increment: amount,
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
return usage.count;
|
|
51
|
-
},
|
|
52
|
-
async getTeam(teamId) {
|
|
53
|
-
return prisma.team.findUnique({
|
|
54
|
-
where: { teamId },
|
|
55
|
-
});
|
|
56
|
-
},
|
|
57
|
-
async upsertTeam(team) {
|
|
58
|
-
return prisma.team.upsert({
|
|
59
|
-
where: {
|
|
60
|
-
teamId: team.teamId,
|
|
61
|
-
},
|
|
62
|
-
create: team,
|
|
63
|
-
update: team,
|
|
64
|
-
});
|
|
65
|
-
},
|
|
66
|
-
async recordBillingEvent(event) {
|
|
67
|
-
return prisma.billingEvent.create({
|
|
68
|
-
data: event,
|
|
69
|
-
});
|
|
70
|
-
},
|
|
71
|
-
async getBillingEvents(userId) {
|
|
72
|
-
return prisma.billingEvent.findMany({
|
|
73
|
-
where: { userId },
|
|
74
|
-
orderBy: {
|
|
75
|
-
createdAt: "desc",
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { SubscriptionRecord } from "../subscriptions";
|
|
2
|
-
import type { TeamRecord } from "../teams";
|
|
3
|
-
import type { BillingEvent } from "../events";
|
|
4
|
-
export interface BillingAdapter {
|
|
5
|
-
getSubscription(userId: string): Promise<SubscriptionRecord | null>;
|
|
6
|
-
upsertSubscription(record: SubscriptionRecord): Promise<SubscriptionRecord>;
|
|
7
|
-
getUsage(userId: string, key: string, period: string): Promise<number>;
|
|
8
|
-
incrementUsage(userId: string, key: string, period: string, amount: number): Promise<number>;
|
|
9
|
-
getTeam?(teamId: string): Promise<TeamRecord | null>;
|
|
10
|
-
upsertTeam?(team: TeamRecord): Promise<TeamRecord>;
|
|
11
|
-
recordBillingEvent?(event: BillingEvent): Promise<BillingEvent>;
|
|
12
|
-
getBillingEvents?(userId: string): Promise<BillingEvent[]>;
|
|
13
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { setBillingAdapter } from "./subscriptions";
|
|
2
|
-
import { setUsageAdapter } from "./usage";
|
|
3
|
-
import { setTeamAdapter } from "./teams";
|
|
4
|
-
import { setBillingEventAdapter } from "./events";
|
|
5
|
-
export function configureBilling({ adapter, }) {
|
|
6
|
-
setBillingAdapter(adapter);
|
|
7
|
-
setUsageAdapter(adapter);
|
|
8
|
-
setTeamAdapter(adapter);
|
|
9
|
-
setBillingEventAdapter(adapter);
|
|
10
|
-
return {
|
|
11
|
-
adapterConfigured: true,
|
|
12
|
-
};
|
|
13
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { findFirstPaddleCustomerByEmail } from "@/lib/paddle/customers";
|
|
2
|
-
import { fetchPaddleSubscriptionsForCustomer } from "@/lib/paddle/subscriptions";
|
|
3
|
-
import { refreshSubscriptionFromPaddle } from "./refresh";
|
|
4
|
-
export async function repairSubscriptionByEmail(email) {
|
|
5
|
-
const customer = await findFirstPaddleCustomerByEmail(email);
|
|
6
|
-
if (!customer) {
|
|
7
|
-
throw new Error("No Paddle customer found for email");
|
|
8
|
-
}
|
|
9
|
-
const subscriptions = await fetchPaddleSubscriptionsForCustomer(customer.id);
|
|
10
|
-
const activeSubscription = subscriptions.data?.find((sub) => ["active", "trialing", "past_due"].includes(sub.status));
|
|
11
|
-
if (!activeSubscription) {
|
|
12
|
-
throw new Error("No active Paddle subscription found for customer");
|
|
13
|
-
}
|
|
14
|
-
const repaired = await refreshSubscriptionFromPaddle(activeSubscription.id);
|
|
15
|
-
return {
|
|
16
|
-
customer,
|
|
17
|
-
subscription: repaired,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function seedDemoBilling(): Promise<void>;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { upsertSubscription } from "./subscriptions";
|
|
2
|
-
let seeded = false;
|
|
3
|
-
export async function seedDemoBilling() {
|
|
4
|
-
if (seeded) {
|
|
5
|
-
return;
|
|
6
|
-
}
|
|
7
|
-
await upsertSubscription({
|
|
8
|
-
userId: "demo-user-1",
|
|
9
|
-
plan: "pro",
|
|
10
|
-
status: "active",
|
|
11
|
-
});
|
|
12
|
-
seeded = true;
|
|
13
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { plans } from "./plans";
|
|
2
|
-
import { getSubscription, isSubscriptionActive } from "./subscriptions";
|
|
3
|
-
export async function hasFeature(userId, feature) {
|
|
4
|
-
const subscription = await getSubscription(userId);
|
|
5
|
-
if (!isSubscriptionActive(subscription)) {
|
|
6
|
-
return false;
|
|
7
|
-
}
|
|
8
|
-
return plans[subscription.plan].features.includes(feature);
|
|
9
|
-
}
|
|
10
|
-
export async function requireFeature(userId, feature) {
|
|
11
|
-
const allowed = await hasFeature(userId, feature);
|
|
12
|
-
if (!allowed) {
|
|
13
|
-
throw new Error(`Feature not available: ${feature}`);
|
|
14
|
-
}
|
|
15
|
-
return true;
|
|
16
|
-
}
|