@nextblock-cms/ecom 0.12.12 → 0.12.14
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/index.cjs.js +1 -1
- package/index.d.ts +2 -0
- package/index.es.js +108 -106
- package/lib/components/Checkout.cjs.js +1 -1
- package/lib/components/Checkout.es.js +32 -33
- package/lib/components/CustomerProfileForm.cjs.js +1 -1
- package/lib/components/CustomerProfileForm.es.js +185 -238
- package/lib/components/FreemiusLicensePanel.cjs.js +1 -0
- package/lib/components/FreemiusLicensePanel.d.ts +6 -0
- package/lib/components/FreemiusLicensePanel.es.js +66 -0
- package/lib/components/InvoiceViewerShell.cjs.js +2 -2
- package/lib/components/InvoiceViewerShell.d.ts +3 -1
- package/lib/components/InvoiceViewerShell.es.js +13 -11
- package/lib/customer-orders.cjs.js +1 -1
- package/lib/customer-orders.d.ts +2 -0
- package/lib/customer-orders.es.js +30 -27
- package/lib/freemius-license-types.d.ts +19 -0
- package/lib/freemius-license.cjs.js +1 -0
- package/lib/freemius-license.d.ts +20 -0
- package/lib/freemius-license.es.js +41 -0
- package/lib/freemius-order-sync.cjs.js +1 -1
- package/lib/freemius-order-sync.es.js +62 -52
- package/lib/pages/cms/orders/types.d.ts +0 -1
- package/lib/pages/cms/products/actions.cjs.js +1 -1
- package/lib/pages/cms/products/actions.es.js +1 -1
- package/lib/pages/cms/products/components/CurrencyPriceFields.cjs.js +1 -1
- package/lib/pages/cms/products/components/CurrencyPriceFields.es.js +104 -62
- package/lib/product-actions.cjs.js +3 -3
- package/lib/product-actions.d.ts +2 -1
- package/lib/product-actions.es.js +45 -44
- package/lib/server-actions/customer-actions.cjs.js +1 -1
- package/lib/server-actions/customer-actions.d.ts +0 -1
- package/lib/server-actions/customer-actions.es.js +12 -13
- package/package.json +4 -4
- package/server.cjs.js +1 -1
- package/server.d.ts +1 -0
- package/server.es.js +77 -75
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs as l, jsx as e, Fragment as p } from "react/jsx-runtime";
|
|
3
|
+
import { useState as u } from "react";
|
|
4
|
+
import { KeyRound as f, Check as x, Copy as h } from "lucide-react";
|
|
5
|
+
import { Button as y } from "@nextblock-cms/ui/button";
|
|
6
|
+
import { useTranslations as g } from "@nextblock-cms/utils";
|
|
7
|
+
import { translateOrFallback as a, getInvoiceLocale as b } from "../invoice-ui.es.js";
|
|
8
|
+
import { formatInvoiceDate as N } from "../invoice.es.js";
|
|
9
|
+
function E({ license: r }) {
|
|
10
|
+
const { t, lang: s } = g(), [o, n] = u(!1);
|
|
11
|
+
if (!r)
|
|
12
|
+
return null;
|
|
13
|
+
const m = b(s), c = r.expiration ?? r.trialEndsAt, i = c ? N(c, m) : null, d = async () => {
|
|
14
|
+
if (!(!r.licenseKey || typeof navigator > "u" || !navigator.clipboard))
|
|
15
|
+
try {
|
|
16
|
+
await navigator.clipboard.writeText(r.licenseKey), n(!0), window.setTimeout(() => n(!1), 2e3);
|
|
17
|
+
} catch {
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
return /* @__PURE__ */ l("div", { className: "mb-6 rounded-2xl border border-primary/30 bg-primary/5 p-5 print:hidden", children: [
|
|
21
|
+
/* @__PURE__ */ l("div", { className: "flex items-center gap-2", children: [
|
|
22
|
+
/* @__PURE__ */ e(f, { className: "h-5 w-5 text-primary" }),
|
|
23
|
+
/* @__PURE__ */ e("h2", { className: "text-lg font-semibold", children: a(t, "ecommerce.license_panel_title", "Your license") })
|
|
24
|
+
] }),
|
|
25
|
+
r.licenseKey ? /* @__PURE__ */ l(p, { children: [
|
|
26
|
+
/* @__PURE__ */ e("p", { className: "mt-1 text-sm text-muted-foreground", children: a(
|
|
27
|
+
t,
|
|
28
|
+
"ecommerce.license_panel_help",
|
|
29
|
+
"Activate this key in your NextBlock install under Settings → Packages."
|
|
30
|
+
) }),
|
|
31
|
+
/* @__PURE__ */ l("div", { className: "mt-3 flex flex-col gap-2 sm:flex-row sm:items-center", children: [
|
|
32
|
+
/* @__PURE__ */ e("code", { className: "flex-1 overflow-x-auto rounded-lg border bg-background px-3 py-2 font-mono text-sm", children: r.licenseKey }),
|
|
33
|
+
/* @__PURE__ */ l(
|
|
34
|
+
y,
|
|
35
|
+
{
|
|
36
|
+
type: "button",
|
|
37
|
+
variant: "default",
|
|
38
|
+
onClick: d,
|
|
39
|
+
className: "shrink-0",
|
|
40
|
+
children: [
|
|
41
|
+
o ? /* @__PURE__ */ e(x, { className: "mr-2 h-4 w-4" }) : /* @__PURE__ */ e(h, { className: "mr-2 h-4 w-4" }),
|
|
42
|
+
o ? a(t, "ecommerce.license_copied", "Copied") : a(t, "ecommerce.license_copy", "Copy key")
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
] })
|
|
47
|
+
] }) : /* @__PURE__ */ e("p", { className: "mt-1 text-sm text-muted-foreground", children: a(
|
|
48
|
+
t,
|
|
49
|
+
"ecommerce.license_panel_email_fallback",
|
|
50
|
+
"Your license key was sent to your email. It will also appear here once your purchase is confirmed."
|
|
51
|
+
) }),
|
|
52
|
+
/* @__PURE__ */ l("dl", { className: "mt-4 grid gap-x-6 gap-y-1 text-xs text-muted-foreground sm:grid-cols-2", children: [
|
|
53
|
+
/* @__PURE__ */ l("div", { className: "flex justify-between gap-3 sm:block", children: [
|
|
54
|
+
/* @__PURE__ */ e("dt", { className: "font-medium", children: a(t, "ecommerce.license_number", "License #") }),
|
|
55
|
+
/* @__PURE__ */ e("dd", { className: "font-mono", children: r.licenseId })
|
|
56
|
+
] }),
|
|
57
|
+
i ? /* @__PURE__ */ l("div", { className: "flex justify-between gap-3 sm:block", children: [
|
|
58
|
+
/* @__PURE__ */ e("dt", { className: "font-medium", children: r.isCancelled ? a(t, "ecommerce.license_expires", "Expires") : r.trialEndsAt ? a(t, "ecommerce.license_trial_ends", "Trial ends") : a(t, "ecommerce.license_renews", "Renews / expires") }),
|
|
59
|
+
/* @__PURE__ */ e("dd", { children: i })
|
|
60
|
+
] }) : null
|
|
61
|
+
] })
|
|
62
|
+
] });
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
E as FreemiusLicensePanel
|
|
66
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),j=require("next/link"),v=require("lucide-react"),s=require("@nextblock-cms/ui/button"),f=require("./InvoiceDocument.cjs.js");function g({invoice:i,labels:a,locale:o,title:c,description:r,printLabel:x,headerVisual:d,action:t,loading:l=!1,loadingMessage:m,error:n,emptyMessage:u,className:p="",showHeader:h=!0,beforeInvoice:b}){return e.jsxs(e.Fragment,{children:[e.jsx("style",{children:`
|
|
2
2
|
@media print {
|
|
3
3
|
@page {
|
|
4
4
|
size: portrait;
|
|
@@ -26,4 +26,4 @@
|
|
|
26
26
|
padding: 0;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
`}),e.jsxs("div",{className:`mx-auto max-w-6xl px-4 py-10 md:px-6 print:max-w-none print:px-0 print:py-0 ${p}`,children:[h?e.jsxs("div",{className:"mb-6 flex flex-col gap-4 md:flex-row md:items-center md:justify-between print:hidden",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[d?e.jsx("div",{className:"shrink-0",children:d}):null,e.jsxs("div",{children:[e.jsx("h1",{className:"text-3xl font-bold",children:c}),r?e.jsx("p",{className:"text-sm text-muted-foreground",children:r}):null]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs(s.Button,{type:"button",variant:"outline",onClick:()=>window.print(),disabled:!i,children:[e.jsx(
|
|
29
|
+
`}),e.jsxs("div",{className:`mx-auto max-w-6xl px-4 py-10 md:px-6 print:max-w-none print:px-0 print:py-0 ${p}`,children:[h?e.jsxs("div",{className:"mb-6 flex flex-col gap-4 md:flex-row md:items-center md:justify-between print:hidden",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[d?e.jsx("div",{className:"shrink-0",children:d}):null,e.jsxs("div",{children:[e.jsx("h1",{className:"text-3xl font-bold",children:c}),r?e.jsx("p",{className:"text-sm text-muted-foreground",children:r}):null]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs(s.Button,{type:"button",variant:"outline",onClick:()=>window.print(),disabled:!i,children:[e.jsx(v.Printer,{className:"mr-2 h-4 w-4"}),x]}),t?e.jsx(s.Button,{asChild:!0,variant:t.variant||"default",children:e.jsx(j,{href:t.href,children:t.label})}):null]})]}):null,l?e.jsx("div",{className:"mb-6 flex items-center justify-center gap-3 rounded-2xl border bg-background px-5 py-4 text-sm text-muted-foreground print:hidden",children:m}):null,n?e.jsx("div",{className:"mb-6 rounded-2xl border border-amber-200 bg-amber-50 px-5 py-4 text-sm text-amber-700 print:hidden",children:n}):null,b,i?e.jsx("div",{"data-print-invoice-root":!0,children:e.jsx(f.InvoiceDocument,{data:i,labels:a,locale:o})}):!l&&!n?e.jsx("div",{className:"rounded-2xl border bg-background px-6 py-12 text-center text-muted-foreground print:hidden",children:u}):null]})]})}exports.InvoiceViewerShell=g;
|
|
@@ -21,6 +21,8 @@ interface InvoiceViewerShellProps {
|
|
|
21
21
|
emptyMessage?: string;
|
|
22
22
|
className?: string;
|
|
23
23
|
showHeader?: boolean;
|
|
24
|
+
/** Optional content rendered above the invoice (and hidden when printing). */
|
|
25
|
+
beforeInvoice?: ReactNode;
|
|
24
26
|
}
|
|
25
|
-
export declare function InvoiceViewerShell({ invoice, labels, locale, title, description, printLabel, headerVisual, action, loading, loadingMessage, error, emptyMessage, className, showHeader, }: InvoiceViewerShellProps): import("react").JSX.Element;
|
|
27
|
+
export declare function InvoiceViewerShell({ invoice, labels, locale, title, description, printLabel, headerVisual, action, loading, loadingMessage, error, emptyMessage, className, showHeader, beforeInvoice, }: InvoiceViewerShellProps): import("react").JSX.Element;
|
|
26
28
|
export {};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsxs as i, Fragment as
|
|
3
|
-
import
|
|
4
|
-
import { Printer as
|
|
2
|
+
import { jsxs as i, Fragment as v, jsx as e } from "react/jsx-runtime";
|
|
3
|
+
import g from "next/link";
|
|
4
|
+
import { Printer as y } from "lucide-react";
|
|
5
5
|
import { Button as m } from "@nextblock-cms/ui/button";
|
|
6
|
-
import { InvoiceDocument as
|
|
7
|
-
function
|
|
6
|
+
import { InvoiceDocument as w } from "./InvoiceDocument.es.js";
|
|
7
|
+
function z({
|
|
8
8
|
invoice: r,
|
|
9
9
|
labels: o,
|
|
10
10
|
locale: s,
|
|
@@ -18,9 +18,10 @@ function I({
|
|
|
18
18
|
error: n,
|
|
19
19
|
emptyMessage: u,
|
|
20
20
|
className: h = "",
|
|
21
|
-
showHeader: b = !0
|
|
21
|
+
showHeader: b = !0,
|
|
22
|
+
beforeInvoice: f
|
|
22
23
|
}) {
|
|
23
|
-
return /* @__PURE__ */ i(
|
|
24
|
+
return /* @__PURE__ */ i(v, { children: [
|
|
24
25
|
/* @__PURE__ */ e("style", { children: `
|
|
25
26
|
@media print {
|
|
26
27
|
@page {
|
|
@@ -72,18 +73,19 @@ function I({
|
|
|
72
73
|
onClick: () => window.print(),
|
|
73
74
|
disabled: !r,
|
|
74
75
|
children: [
|
|
75
|
-
/* @__PURE__ */ e(
|
|
76
|
+
/* @__PURE__ */ e(y, { className: "mr-2 h-4 w-4" }),
|
|
76
77
|
p
|
|
77
78
|
]
|
|
78
79
|
}
|
|
79
80
|
),
|
|
80
|
-
t ? /* @__PURE__ */ e(m, { asChild: !0, variant: t.variant || "default", children: /* @__PURE__ */ e(
|
|
81
|
+
t ? /* @__PURE__ */ e(m, { asChild: !0, variant: t.variant || "default", children: /* @__PURE__ */ e(g, { href: t.href, children: t.label }) }) : null
|
|
81
82
|
] })
|
|
82
83
|
] }) : null,
|
|
83
84
|
a ? /* @__PURE__ */ e("div", { className: "mb-6 flex items-center justify-center gap-3 rounded-2xl border bg-background px-5 py-4 text-sm text-muted-foreground print:hidden", children: x }) : null,
|
|
84
85
|
n ? /* @__PURE__ */ e("div", { className: "mb-6 rounded-2xl border border-amber-200 bg-amber-50 px-5 py-4 text-sm text-amber-700 print:hidden", children: n }) : null,
|
|
86
|
+
f,
|
|
85
87
|
r ? /* @__PURE__ */ e("div", { "data-print-invoice-root": !0, children: /* @__PURE__ */ e(
|
|
86
|
-
|
|
88
|
+
w,
|
|
87
89
|
{
|
|
88
90
|
data: r,
|
|
89
91
|
labels: o,
|
|
@@ -96,5 +98,5 @@ function I({
|
|
|
96
98
|
] });
|
|
97
99
|
}
|
|
98
100
|
export {
|
|
99
|
-
|
|
101
|
+
z as InvoiceViewerShell
|
|
100
102
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("@nextblock-cms/db/server"),l=require("./invoice-server.cjs.js"),g=require("./freemius-license.cjs.js"),o=["pending"];function i(e){return e??d.createClient()}async function u(e){const{data:{user:r},error:t}=await e.auth.getUser();if(t||!r)throw new Error("Unauthorized");return r}async function m(e){const r=i(e),t=await u(r),{data:n,error:s}=await r.from("orders").select("id, invoice_number, paid_at, created_at, currency, status, provider, subtotal, shipping_total, tax_total, total").eq("user_id",t.id).not("status","in",`(${o.join(",")})`).order("created_at",{ascending:!1});if(s)throw new Error(s.message);return n??[]}async function c(e,r){const t=i(r),n=await u(t),{data:s,error:a}=await t.from("orders").select("id, invoice_number, paid_at, created_at, currency, status, provider, subtotal, shipping_total, tax_total, total").eq("id",e).eq("user_id",n.id).not("status","in",`(${o.join(",")})`).maybeSingle();if(a)throw new Error(a.message);return s??null}async function _(e,r){const t=i(r),n=await c(e,t);if(!n)return null;const s=n.invoice_number?await l.getInvoicePresentationData(e,t):null,a=n.provider==="freemius"?await g.getFreemiusOrderLicense({orderId:e,client:t}):null;return{order:n,invoice:s,license:a}}exports.getCurrentCustomerOrder=c;exports.getCurrentCustomerOrderInvoice=_;exports.getCurrentCustomerOrders=m;
|
package/lib/customer-orders.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
2
|
import { InvoicePresentationData } from './invoice';
|
|
3
|
+
import { FreemiusOrderLicense } from './freemius-license-types';
|
|
3
4
|
type SupabaseLikeClient = SupabaseClient<any>;
|
|
4
5
|
export interface CustomerOrderSummary {
|
|
5
6
|
id: string;
|
|
@@ -19,5 +20,6 @@ export declare function getCurrentCustomerOrder(orderId: string, client?: Supaba
|
|
|
19
20
|
export declare function getCurrentCustomerOrderInvoice(orderId: string, client?: SupabaseLikeClient): Promise<{
|
|
20
21
|
order: CustomerOrderSummary;
|
|
21
22
|
invoice: InvoicePresentationData | null;
|
|
23
|
+
license: FreemiusOrderLicense | null;
|
|
22
24
|
} | null>;
|
|
23
25
|
export {};
|
|
@@ -1,45 +1,48 @@
|
|
|
1
|
-
import { createClient as
|
|
2
|
-
import { getInvoicePresentationData as
|
|
1
|
+
import { createClient as c } from "@nextblock-cms/db/server";
|
|
2
|
+
import { getInvoicePresentationData as d } from "./invoice-server.es.js";
|
|
3
|
+
import { getFreemiusOrderLicense as l } from "./freemius-license.es.js";
|
|
4
|
+
const s = ["pending"];
|
|
3
5
|
function o(t) {
|
|
4
|
-
return t ??
|
|
6
|
+
return t ?? c();
|
|
5
7
|
}
|
|
6
|
-
async function
|
|
8
|
+
async function u(t) {
|
|
7
9
|
const {
|
|
8
|
-
data: { user:
|
|
9
|
-
error:
|
|
10
|
+
data: { user: r },
|
|
11
|
+
error: e
|
|
10
12
|
} = await t.auth.getUser();
|
|
11
|
-
if (
|
|
13
|
+
if (e || !r)
|
|
12
14
|
throw new Error("Unauthorized");
|
|
13
|
-
return
|
|
15
|
+
return r;
|
|
14
16
|
}
|
|
15
|
-
async function
|
|
16
|
-
const
|
|
17
|
+
async function g(t) {
|
|
18
|
+
const r = o(t), e = await u(r), { data: n, error: a } = await r.from("orders").select(
|
|
17
19
|
"id, invoice_number, paid_at, created_at, currency, status, provider, subtotal, shipping_total, tax_total, total"
|
|
18
|
-
).eq("user_id",
|
|
19
|
-
if (
|
|
20
|
-
throw new Error(
|
|
21
|
-
return
|
|
20
|
+
).eq("user_id", e.id).not("status", "in", `(${s.join(",")})`).order("created_at", { ascending: !1 });
|
|
21
|
+
if (a)
|
|
22
|
+
throw new Error(a.message);
|
|
23
|
+
return n ?? [];
|
|
22
24
|
}
|
|
23
|
-
async function
|
|
24
|
-
const
|
|
25
|
+
async function m(t, r) {
|
|
26
|
+
const e = o(r), n = await u(e), { data: a, error: i } = await e.from("orders").select(
|
|
25
27
|
"id, invoice_number, paid_at, created_at, currency, status, provider, subtotal, shipping_total, tax_total, total"
|
|
26
|
-
).eq("id", t).eq("user_id",
|
|
28
|
+
).eq("id", t).eq("user_id", n.id).not("status", "in", `(${s.join(",")})`).maybeSingle();
|
|
27
29
|
if (i)
|
|
28
30
|
throw new Error(i.message);
|
|
29
|
-
return
|
|
31
|
+
return a ?? null;
|
|
30
32
|
}
|
|
31
|
-
async function
|
|
32
|
-
const
|
|
33
|
-
if (!
|
|
33
|
+
async function w(t, r) {
|
|
34
|
+
const e = o(r), n = await m(t, e);
|
|
35
|
+
if (!n)
|
|
34
36
|
return null;
|
|
35
|
-
const
|
|
37
|
+
const a = n.invoice_number ? await d(t, e) : null, i = n.provider === "freemius" ? await l({ orderId: t, client: e }) : null;
|
|
36
38
|
return {
|
|
37
|
-
order:
|
|
38
|
-
invoice:
|
|
39
|
+
order: n,
|
|
40
|
+
invoice: a,
|
|
41
|
+
license: i
|
|
39
42
|
};
|
|
40
43
|
}
|
|
41
44
|
export {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
m as getCurrentCustomerOrder,
|
|
46
|
+
w as getCurrentCustomerOrderInvoice,
|
|
47
|
+
g as getCurrentCustomerOrders
|
|
45
48
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface FreemiusOrderLicense {
|
|
2
|
+
/** Freemius license id captured on the order (always present). */
|
|
3
|
+
licenseId: string;
|
|
4
|
+
/**
|
|
5
|
+
* The activatable license key (Freemius `secret_key`), fetched on demand and
|
|
6
|
+
* never stored locally. Null when it could not be resolved (e.g. the Freemius
|
|
7
|
+
* API was unreachable or no key has been issued yet) — surface the email
|
|
8
|
+
* fallback in that case.
|
|
9
|
+
*/
|
|
10
|
+
licenseKey: string | null;
|
|
11
|
+
/** Freemius plan id the license belongs to, when known. */
|
|
12
|
+
planId: string | null;
|
|
13
|
+
/** License expiration (ISO) — for trials this is the trial end. */
|
|
14
|
+
expiration: string | null;
|
|
15
|
+
/** Trial end recorded on the order, if the order started as a trial. */
|
|
16
|
+
trialEndsAt: string | null;
|
|
17
|
+
/** Whether Freemius reports the license as cancelled. */
|
|
18
|
+
isCancelled: boolean;
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("@freemius/sdk"),l=require("./payment-config.cjs.js"),u=require("./providers/freemius.cjs.js");async function c(n,e){if(!n)return null;const r=u.resolveFreemiusCheckoutCredentials(n);return!r.apiKey||!r.secretKey||!r.publicKey?null:new t.Freemius({productId:Number(n),apiKey:r.apiKey,secretKey:r.secretKey,publicKey:r.publicKey}).api.license.retrieve(e)}async function a(n){const{data:e,error:r}=await n.client.from("orders").select("id, provider, freemius_product_id, freemius_license_id, freemius_trial_ends_at").eq("id",n.orderId).maybeSingle();if(r||!e||e.provider!=="freemius"||!e.freemius_license_id)return null;let i=null;try{await l.hydrateFreemiusEnvFromDb(),i=await c(e.freemius_product_id,String(e.freemius_license_id))}catch(s){console.error("[Freemius License] Failed to retrieve license key:",s)}return{licenseId:String(e.freemius_license_id),licenseKey:i?.secret_key??null,planId:i?.plan_id!=null?String(i.plan_id):null,expiration:i?.expiration??null,trialEndsAt:e.freemius_trial_ends_at??null,isCancelled:!!i?.is_cancelled}}exports.getFreemiusOrderLicense=a;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
import { FreemiusOrderLicense } from './freemius-license-types';
|
|
3
|
+
export type { FreemiusOrderLicense };
|
|
4
|
+
type SupabaseLikeClient = SupabaseClient<any>;
|
|
5
|
+
/**
|
|
6
|
+
* Fetches the activatable Freemius license key for an order on demand.
|
|
7
|
+
*
|
|
8
|
+
* The key is never persisted locally — it is retrieved straight from Freemius
|
|
9
|
+
* using the license id captured on the order at checkout time. Returns null for
|
|
10
|
+
* non-Freemius orders or orders that have no license yet.
|
|
11
|
+
*
|
|
12
|
+
* Authorization is the caller's responsibility: this only reads what the passed
|
|
13
|
+
* Supabase client can see, so pass an owner-scoped (RLS) client on customer
|
|
14
|
+
* surfaces and the service-role client only right after checkout, keyed by the
|
|
15
|
+
* order's own (unguessable) id.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getFreemiusOrderLicense(input: {
|
|
18
|
+
orderId: string;
|
|
19
|
+
client: SupabaseLikeClient;
|
|
20
|
+
}): Promise<FreemiusOrderLicense | null>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Freemius as s } from "@freemius/sdk";
|
|
2
|
+
import { hydrateFreemiusEnvFromDb as t } from "./payment-config.es.js";
|
|
3
|
+
import { resolveFreemiusCheckoutCredentials as u } from "./providers/freemius.es.js";
|
|
4
|
+
async function c(n, e) {
|
|
5
|
+
if (!n)
|
|
6
|
+
return null;
|
|
7
|
+
const r = u(n);
|
|
8
|
+
return !r.apiKey || !r.secretKey || !r.publicKey ? null : new s({
|
|
9
|
+
productId: Number(n),
|
|
10
|
+
apiKey: r.apiKey,
|
|
11
|
+
secretKey: r.secretKey,
|
|
12
|
+
publicKey: r.publicKey
|
|
13
|
+
}).api.license.retrieve(e);
|
|
14
|
+
}
|
|
15
|
+
async function m(n) {
|
|
16
|
+
const { data: e, error: r } = await n.client.from("orders").select(
|
|
17
|
+
"id, provider, freemius_product_id, freemius_license_id, freemius_trial_ends_at"
|
|
18
|
+
).eq("id", n.orderId).maybeSingle();
|
|
19
|
+
if (r || !e || e.provider !== "freemius" || !e.freemius_license_id)
|
|
20
|
+
return null;
|
|
21
|
+
let i = null;
|
|
22
|
+
try {
|
|
23
|
+
await t(), i = await c(
|
|
24
|
+
e.freemius_product_id,
|
|
25
|
+
String(e.freemius_license_id)
|
|
26
|
+
);
|
|
27
|
+
} catch (l) {
|
|
28
|
+
console.error("[Freemius License] Failed to retrieve license key:", l);
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
licenseId: String(e.freemius_license_id),
|
|
32
|
+
licenseKey: i?.secret_key ?? null,
|
|
33
|
+
planId: i?.plan_id != null ? String(i.plan_id) : null,
|
|
34
|
+
expiration: i?.expiration ?? null,
|
|
35
|
+
trialEndsAt: e.freemius_trial_ends_at ?? null,
|
|
36
|
+
isCancelled: !!i?.is_cancelled
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
m as getFreemiusOrderLicense
|
|
41
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("crypto"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("crypto"),A=require("@freemius/sdk"),R=require("@supabase/supabase-js"),K=require("./invoice-server.cjs.js"),j=require("./order-inventory.cjs.js"),d=require("./providers/freemius.cjs.js");function s(e){return e==null||e===""?null:String(e)}function u(e){const r=s(e);if(!r)return null;const t=r.includes("T")?r:r.replace(" ","T")+"Z",i=new Date(t);return Number.isNaN(i.getTime())?r:i.toISOString()}function x(e){if(e==null||e==="")return null;const r=Number(e);return Number.isFinite(r)?r:null}function f(...e){return e.some(r=>{const t=x(r);return t!==null&&t>0})}function l(e){return e==="pending"||e==="trial"}function y(e){return["license.cancelled","license.deleted","license.expired","subscription.cancelled","subscription.renewal.failed.last","trial.cancelled","trial.expired"].includes(e||"")}function M(e,r){return e==="license.extended"&&(r?.is_renewal===!0||r?.is_renewal===1||r?.is_renewal==="1"||r?.is_renewal==="true")}function B(e){const r=e.objects?.payment??e.data?.payment??e.data;return e.type==="payment.created"&&f(r?.gross,r?.total_gross,r?.amount,r?.initial_amount)}function b(e){const r=e?.purchase??null,t=e?.trial??null;return{freemius_product_id:s(r?.plugin_id)??s(r?.product_id)??s(r?.productId)??s(t?.plugin_id)??s(t?.product_id)??s(t?.productId),freemius_plan_id:s(r?.plan_id)??s(r?.planId),freemius_license_id:s(r?.license_id)??s(r?.licenseId)??s(t?.license_id)??s(t?.licenseId),freemius_subscription_id:s(r?.subscription_id)??s(r?.subscriptionId)??s(t?.subscription_id)??s(t?.subscriptionId),freemius_trial_id:s(t?.id),freemius_user_id:s(r?.user_id)??s(r?.userId)??s(t?.user_id)??s(t?.userId)??s(e?.user?.id),freemius_trial_ends_at:u(t?.trial_ends_at)??u(t?.trialEndsAt)??u(r?.trial_ends)??u(r?.trialEnds)}}function S(e,r="pending"){const t=e?.purchase??null,i=e?.trial??null;return r==="paid"?"paid":i&&(i.canceled_at||i.canceledAt)&&l(r)?"cancelled":i?"trial":t?(t.canceled_at||t.canceledAt)&&l(r)?"cancelled":f(t.initial_amount,t.initialAmount,t.gross,t.total_gross,t.totalGross)?"paid":t.trial_ends||t.trialEnds||t.subscription_id||t.subscriptionId?"trial":r:r}function m(e){const{event:r,currentStatus:t,purchaseData:i}=e;return t==="paid"&&y(r.type)?"paid":y(r.type)?l(t)?"cancelled":t:B(r)||M(r.type,r.data)||i&&f(i.initialAmount,i.initial_amount,i.gross,i.totalGross,i.total_gross)?"paid":i?.canceled===!0&&l(t)?"cancelled":t==="pending"&&(i?.trialEndsAt||i?.trial_ends_at||i?.trialEnds||i?.trial_ends)||(i?.subscriptionId||i?.subscription_id||r.type==="subscription.created"||r.type==="license.created")&&t==="pending"?"trial":t}function N(e,...r){const t=r.filter(i=>!!i);return e==="paid"||t.includes("paid")?"paid":t.includes("cancelled")?"cancelled":t.includes("trial")?"trial":t.includes("shipped")?"shipped":t.includes("refunded")?"refunded":e}function P(e,r){const t={freemius_last_event_type:r,freemius_last_synced_at:new Date().toISOString()};for(const[i,n]of Object.entries(e))n!=null&&n!==""&&(t[i]=n);return t}function E(){const e=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,r=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!e||!r)throw new Error("Missing Supabase Service Role environment variables");return R.createClient(e,r,{auth:{autoRefreshToken:!1,persistSession:!1}})}async function T(e,r){const{data:t,error:i}=await e.from("orders").select("id, status, provider, freemius_product_id, freemius_plan_id, freemius_license_id, freemius_subscription_id, freemius_trial_id, freemius_user_id, freemius_trial_ends_at").eq("id",r).single();if(i||!t)throw new Error(i?.message||"Order not found");return t}async function U(e,r){const{data:t,error:i}=await e.from("orders").select("id, status, provider, freemius_product_id, freemius_plan_id, freemius_license_id, freemius_subscription_id, freemius_trial_id, freemius_user_id, freemius_trial_ends_at").eq("freemius_license_id",r).order("created_at",{ascending:!1}).limit(1).maybeSingle();if(i)throw new Error(i.message);return t??null}async function h(e){const r=P(e.metadata,e.eventType),t=e.order.status,i=t==="paid"&&e.nextStatus!=="paid"?"paid":e.nextStatus;i!==t&&(r.status=i);const{error:n}=await e.client.from("orders").update(r).eq("id",e.order.id);if(n)throw new Error(n.message);return i==="paid"&&t!=="paid"&&(await K.assignInvoiceMetadata({orderId:e.order.id,client:e.client}),await j.applyOrderInventoryDeduction(e.client,e.order.id)),i}async function q(e){const r=e.client??E(),t=await T(r,e.orderId);if(t.provider!=="freemius")return{success:!1,error:"Only Freemius orders can be synced from Freemius checkout"};const i=b(e.checkoutResponse);let n=null;if(i.freemius_license_id)try{n=await F(i.freemius_product_id??t.freemius_product_id,i.freemius_license_id)}catch(O){console.error("[Freemius Checkout Sync] Failed to retrieve purchase data:",O)}const a={type:"checkout.purchaseCompleted",data:{license_id:i.freemius_license_id},objects:{}},c={...i,...v(a,n)},o=S(e.checkoutResponse,t.status),_=n?m({event:a,currentStatus:t.status,purchaseData:n}):null,k=o==="paid"?t.status:o,w=N(t.status,k,_),C=await h({client:r,order:t,nextStatus:w,metadata:c,eventType:"checkout.purchaseCompleted"});return{success:!0,orderId:t.id,status:C,metadata:c}}function g(e){return s(e.data?.license_id)??s(e.objects?.license?.id)??s(e.objects?.subscription?.license_id)??s(e.objects?.payment?.license_id)??s(e.data?.payment?.license_id)}function v(e,r){const t=e.objects?.license,i=e.objects?.subscription,n=e.objects?.trial,a=e.objects?.payment??e.data?.payment;return{freemius_product_id:s(r?.productId)??s(r?.product_id)??s(t?.plugin_id)??s(i?.plugin_id)??s(a?.plugin_id),freemius_plan_id:s(r?.planId)??s(r?.plan_id)??s(t?.plan_id),freemius_license_id:s(r?.licenseId)??s(r?.license_id)??g(e),freemius_subscription_id:s(r?.subscriptionId)??s(r?.subscription_id)??s(i?.id)??s(e.data?.subscription_id),freemius_trial_id:s(n?.id)??s(e.data?.trial_id),freemius_user_id:s(r?.userId)??s(r?.user_id)??s(e.objects?.user?.id),freemius_trial_ends_at:u(n?.trial_ends_at)??u(n?.trial_ends)??u(t?.trial_ends)??u(r?.trialEndsAt)??u(r?.trial_ends_at)}}async function F(e,r){if(!e)return null;const t=d.resolveFreemiusCheckoutCredentials(e);return!t.apiKey||!t.secretKey||!t.publicKey?null:new A.Freemius({productId:Number(e),apiKey:t.apiKey,secretKey:t.secretKey,publicKey:t.publicKey}).purchase.retrievePurchaseData(r)}async function W(e){const r=e.client??E(),t=g(e.event);if(!t)return{success:!0,ignored:!0,reason:"missing_license_id",type:e.event.type};const i=await U(r,t);if(!i)return{success:!0,ignored:!0,reason:"unknown_license_id",licenseId:t,type:e.event.type};let n=null;try{n=await F(i.freemius_product_id??e.event.objects?.license?.plugin_id,t)}catch(_){console.error("[Freemius Sync] Failed to retrieve purchase data:",_)}const a=v(e.event,n),c=m({event:e.event,currentStatus:i.status,purchaseData:n}),o=await h({client:r,order:i,nextStatus:c,metadata:a,eventType:e.event.type??null});return{success:!0,orderId:i.id,status:o,type:e.event.type}}function I(){const e=[d.readFreemiusEnvValue("FREEMIUS_SECRET_KEY"),d.readFreemiusEnvValue("FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY"),...Object.values(d.parseFreemiusCheckoutCredentialsMap()??{}).map(r=>r.secretKey??null)];return Array.from(new Set(e.filter(r=>!!r)))}function L(e,r){return r?I().some(t=>{const i=p.createHmac("sha256",t).update(e).digest("hex");try{return p.timingSafeEqual(Buffer.from(i,"hex"),Buffer.from(r,"hex"))}catch{return!1}}):!1}exports.extractFreemiusCheckoutMetadata=b;exports.getFreemiusWebhookSecretCandidates=I;exports.resolveFreemiusStatusFromCheckoutResponse=S;exports.resolveFreemiusStatusFromWebhookEvent=m;exports.syncFreemiusCheckoutOrder=q;exports.syncFreemiusOrderFromWebhookEvent=W;exports.verifyFreemiusWebhookSignature=L;
|