@nextblock-cms/ecom 0.22.0 → 0.22.2
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 +1 -1
- package/index.es.js +31 -31
- package/lib/components/Checkout.cjs +1 -1
- package/lib/components/Checkout.es.js +2 -1
- package/lib/coupon-server.cjs +1 -1
- package/lib/coupon-server.d.ts +65 -1
- package/lib/coupon-server.es.js +151 -91
- package/lib/coupons.cjs +1 -1
- package/lib/coupons.d.ts +13 -0
- package/lib/coupons.es.js +5 -4
- package/lib/order-access-token.cjs +1 -0
- package/lib/order-access-token.d.ts +2 -0
- package/lib/order-access-token.es.js +18 -0
- package/lib/pages/cms/orders/actions.cjs +3 -3
- package/lib/pages/cms/orders/actions.es.js +48 -26
- package/lib/pages/cms/orders/export-actions.cjs +1 -1
- package/lib/pages/cms/orders/export-actions.d.ts +42 -1
- package/lib/pages/cms/orders/export-actions.es.js +18 -16
- package/lib/pages/cms/orders/server-actions.cjs +1 -1
- package/lib/pages/cms/orders/server-actions.es.js +25 -15
- package/lib/pages/cms/products/actions.cjs +4 -4
- package/lib/pages/cms/products/actions.es.js +44 -41
- package/lib/pages/cms/products/inventory/actions.cjs +2 -2
- package/lib/pages/cms/products/inventory/actions.es.js +23 -23
- package/lib/pages/cms/products/server-actions.cjs +1 -1
- package/lib/pages/cms/products/server-actions.es.js +109 -108
- package/lib/pages/cms/shipping/server-actions.cjs +1 -1
- package/lib/pages/cms/shipping/server-actions.es.js +27 -26
- package/lib/payment-config.cjs +1 -1
- package/lib/payment-config.d.ts +4 -2
- package/lib/payment-config.es.js +73 -72
- package/lib/product-actions.cjs +1 -1
- package/lib/product-actions.es.js +6 -6
- package/lib/providers/checkout-items.cjs +1 -0
- package/lib/providers/checkout-items.d.ts +30 -0
- package/lib/providers/checkout-items.es.js +43 -0
- package/lib/providers/freemius.cjs +1 -1
- package/lib/providers/freemius.d.ts +1 -1
- package/lib/providers/freemius.es.js +166 -144
- package/lib/providers/stripe.cjs +1 -1
- package/lib/providers/stripe.d.ts +1 -1
- package/lib/providers/stripe.es.js +191 -146
- package/lib/server-actions/coupon-actions.cjs +1 -1
- package/lib/server-actions/coupon-actions.d.ts +11 -12
- package/lib/server-actions/coupon-actions.es.js +19 -11
- package/lib/server-actions/require-ecom-role.cjs +1 -0
- package/lib/server-actions/require-ecom-role.d.ts +5825 -0
- package/lib/server-actions/require-ecom-role.es.js +24 -0
- package/lib/server-actions/shipping-actions.cjs +1 -1
- package/lib/server-actions/shipping-actions.es.js +4 -4
- package/lib/server-actions/tax-actions.cjs +1 -1
- package/lib/server-actions/tax-actions.es.js +22 -18
- package/lib/shipping/checkout-shipping-method.cjs +7 -0
- package/lib/shipping/checkout-shipping-method.d.ts +115 -0
- package/lib/shipping/checkout-shipping-method.es.js +167 -0
- package/lib/shipping/resolver.cjs +1 -7
- package/lib/shipping/resolver.d.ts +7 -12
- package/lib/shipping/resolver.es.js +13 -38
- package/package.json +4 -4
- package/server.cjs +1 -1
- package/server.d.ts +1 -0
- package/server.es.js +49 -48
package/lib/payment-config.es.js
CHANGED
|
@@ -1,121 +1,122 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getEcomActorRole as e, requireEcomAdmin as t } from "./server-actions/require-ecom-role.es.js";
|
|
2
|
+
import { createClient as n, encryptWithEnvKey as r, getSecretEnvelopeStatus as i, getServiceRoleSupabaseClient as a, isSandboxEnvironment as o, resolveConfigValue as s, tryDecryptWithEnvKey as c } from "@nextblock-cms/db/server";
|
|
2
3
|
//#region src/lib/payment-config.ts
|
|
3
|
-
var
|
|
4
|
-
function
|
|
4
|
+
var l = "payment_secret", u = "payment_public", d = 6e4, f = null;
|
|
5
|
+
function p(e) {
|
|
5
6
|
return e && typeof e == "object" && !Array.isArray(e) ? e : {};
|
|
6
7
|
}
|
|
7
|
-
async function
|
|
8
|
+
async function m(e = !1) {
|
|
8
9
|
let t = Date.now();
|
|
9
|
-
if (!e &&
|
|
10
|
-
secret:
|
|
11
|
-
public:
|
|
10
|
+
if (!e && f && t - f.at < d) return {
|
|
11
|
+
secret: f.secret,
|
|
12
|
+
public: f.public
|
|
12
13
|
};
|
|
13
|
-
let n = {},
|
|
14
|
+
let n = {}, r = {};
|
|
14
15
|
try {
|
|
15
|
-
let e =
|
|
16
|
-
n =
|
|
16
|
+
let e = a(), [{ data: t }, { data: i }] = await Promise.all([e.from("site_settings").select("value").eq("key", l).maybeSingle(), e.from("site_settings").select("value").eq("key", u).maybeSingle()]);
|
|
17
|
+
n = p(t?.value), r = p(i?.value);
|
|
17
18
|
} catch {}
|
|
18
|
-
return
|
|
19
|
+
return f = {
|
|
19
20
|
at: t,
|
|
20
21
|
secret: n,
|
|
21
|
-
public:
|
|
22
|
+
public: r
|
|
22
23
|
}, {
|
|
23
24
|
secret: n,
|
|
24
|
-
public:
|
|
25
|
+
public: r
|
|
25
26
|
};
|
|
26
27
|
}
|
|
27
|
-
function
|
|
28
|
-
|
|
28
|
+
function h() {
|
|
29
|
+
f = null;
|
|
29
30
|
}
|
|
30
|
-
function
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
|
-
async function h() {
|
|
34
|
-
let { secret: e } = await f();
|
|
35
|
-
return a(m(e, "stripeSecretKey"), "STRIPE_SECRET_KEY");
|
|
36
|
-
}
|
|
37
|
-
async function g() {
|
|
38
|
-
let { secret: e } = await f();
|
|
39
|
-
return a(m(e, "stripeWebhookSecret"), "STRIPE_WEBHOOK_SECRET");
|
|
31
|
+
function g(e, t) {
|
|
32
|
+
return c(e[t]);
|
|
40
33
|
}
|
|
41
34
|
async function _() {
|
|
42
|
-
let {
|
|
43
|
-
return
|
|
35
|
+
let { secret: e } = await m();
|
|
36
|
+
return s(g(e, "stripeSecretKey"), "STRIPE_SECRET_KEY");
|
|
44
37
|
}
|
|
45
38
|
async function v() {
|
|
39
|
+
let { secret: e } = await m();
|
|
40
|
+
return s(g(e, "stripeWebhookSecret"), "STRIPE_WEBHOOK_SECRET");
|
|
41
|
+
}
|
|
42
|
+
async function y() {
|
|
43
|
+
let { public: e } = await m(), t = p(e.stripe).publishableKey;
|
|
44
|
+
return s(typeof t == "string" ? t : null, "NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY");
|
|
45
|
+
}
|
|
46
|
+
async function b() {
|
|
46
47
|
try {
|
|
47
|
-
let { secret: e, public: t } = await
|
|
48
|
+
let { secret: e, public: t } = await m(), n = p(t.freemius), r = (e, t) => {
|
|
48
49
|
t && t.trim() && (process.env[e] = t.trim());
|
|
49
50
|
};
|
|
50
|
-
r("FREEMIUS_SECRET_KEY",
|
|
51
|
+
r("FREEMIUS_SECRET_KEY", g(e, "freemiusSecretKey")), r("FREEMIUS_API_KEY", g(e, "freemiusApiKey")), r("FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY", g(e, "freemiusSandboxSecretKey")), r("FREEMIUS_PUBLIC_KEY", typeof n.publicKey == "string" ? n.publicKey : null), r("FREEMIUS_PRODUCT_ID", typeof n.productId == "string" ? n.productId : null), r("FREEMIUS_DEVELOPER_ID", typeof n.developerId == "string" ? n.developerId : null);
|
|
51
52
|
} catch (e) {
|
|
52
53
|
console.warn("[payment-config] Could not hydrate Freemius credentials from the database:", e);
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
|
-
async function
|
|
56
|
-
let { secret: e, public: t } = await
|
|
57
|
-
|
|
58
|
-
let
|
|
59
|
-
return
|
|
56
|
+
async function x() {
|
|
57
|
+
let { secret: e, public: t } = await m(), n = p(t.freemius), r = p(t.stripe), i = [];
|
|
58
|
+
s(g(e, "stripeSecretKey"), "STRIPE_SECRET_KEY") || i.push("Secret key"), s(typeof r.publishableKey == "string" ? r.publishableKey : null, "NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY") || i.push("Publishable key"), s(g(e, "stripeWebhookSecret"), "STRIPE_WEBHOOK_SECRET") || i.push("Webhook secret");
|
|
59
|
+
let a = [];
|
|
60
|
+
return s(typeof n.publicKey == "string" ? n.publicKey : null, "FREEMIUS_PUBLIC_KEY") || a.push("Public key"), s(g(e, "freemiusSecretKey"), "FREEMIUS_SECRET_KEY") || a.push("Secret key"), {
|
|
60
61
|
stripe: {
|
|
61
62
|
hasKeys: i.length === 0,
|
|
62
63
|
missing: i
|
|
63
64
|
},
|
|
64
65
|
freemius: {
|
|
65
|
-
hasKeys:
|
|
66
|
-
missing:
|
|
66
|
+
hasKeys: a.length === 0,
|
|
67
|
+
missing: a
|
|
67
68
|
}
|
|
68
69
|
};
|
|
69
70
|
}
|
|
70
|
-
async function
|
|
71
|
-
let t = e(), [{ data: r }, { data:
|
|
71
|
+
async function S() {
|
|
72
|
+
let t = await e() === "ADMIN" ? a() : n(), [{ data: r }, { data: o }] = await Promise.all([t.from("site_settings").select("value").eq("key", l).maybeSingle(), t.from("site_settings").select("value").eq("key", u).maybeSingle()]), s = p(r?.value), c = p(o?.value), d = p(c.stripe), f = p(c.freemius), m = (e) => typeof e == "string" ? e : "";
|
|
72
73
|
return {
|
|
73
74
|
stripe: {
|
|
74
|
-
publishableKey:
|
|
75
|
-
hasSecretKey:
|
|
76
|
-
hasWebhookSecret:
|
|
75
|
+
publishableKey: m(d.publishableKey),
|
|
76
|
+
hasSecretKey: i(s.stripeSecretKey).hasStoredValue,
|
|
77
|
+
hasWebhookSecret: i(s.stripeWebhookSecret).hasStoredValue
|
|
77
78
|
},
|
|
78
79
|
freemius: {
|
|
79
|
-
developerId: f
|
|
80
|
-
publicKey: f
|
|
81
|
-
productId: f
|
|
82
|
-
hasSecretKey:
|
|
83
|
-
hasApiKey:
|
|
80
|
+
developerId: m(f.developerId),
|
|
81
|
+
publicKey: m(f.publicKey),
|
|
82
|
+
productId: m(f.productId),
|
|
83
|
+
hasSecretKey: i(s.freemiusSecretKey).hasStoredValue,
|
|
84
|
+
hasApiKey: i(s.freemiusApiKey).hasStoredValue
|
|
84
85
|
},
|
|
85
|
-
envFallbackActive: !(
|
|
86
|
+
envFallbackActive: !(s.stripeSecretKey || !process.env.STRIPE_SECRET_KEY)
|
|
86
87
|
};
|
|
87
88
|
}
|
|
88
|
-
async function
|
|
89
|
-
let
|
|
90
|
-
stripe: { publishableKey:
|
|
89
|
+
async function C(e) {
|
|
90
|
+
let n = await t(), i = {
|
|
91
|
+
stripe: { publishableKey: e.stripe.publishableKey.trim() },
|
|
91
92
|
freemius: {
|
|
92
|
-
developerId:
|
|
93
|
-
publicKey:
|
|
94
|
-
productId:
|
|
93
|
+
developerId: e.freemius.developerId.trim(),
|
|
94
|
+
publicKey: e.freemius.publicKey.trim(),
|
|
95
|
+
productId: e.freemius.productId.trim(),
|
|
95
96
|
sandboxEnabled: !1
|
|
96
97
|
}
|
|
97
|
-
}, { error:
|
|
98
|
-
key:
|
|
99
|
-
value:
|
|
98
|
+
}, { error: a } = await n.from("site_settings").upsert({
|
|
99
|
+
key: u,
|
|
100
|
+
value: i
|
|
100
101
|
});
|
|
101
|
-
if (
|
|
102
|
-
let
|
|
103
|
-
["stripeSecretKey",
|
|
104
|
-
["stripeWebhookSecret",
|
|
105
|
-
["freemiusSecretKey",
|
|
106
|
-
["freemiusApiKey",
|
|
102
|
+
if (a) throw console.error("Error saving payment_public settings:", a.message), Error("Failed to save payment settings.");
|
|
103
|
+
let s = [
|
|
104
|
+
["stripeSecretKey", e.stripe.secretKey],
|
|
105
|
+
["stripeWebhookSecret", e.stripe.webhookSecret],
|
|
106
|
+
["freemiusSecretKey", e.freemius.secretKey],
|
|
107
|
+
["freemiusApiKey", e.freemius.apiKey]
|
|
107
108
|
];
|
|
108
|
-
if (
|
|
109
|
-
if (
|
|
110
|
-
let { data: e } = await
|
|
111
|
-
for (let [e,
|
|
112
|
-
let { error:
|
|
113
|
-
key:
|
|
114
|
-
value:
|
|
109
|
+
if (s.some(([, e]) => e && e.trim())) {
|
|
110
|
+
if (o()) throw Error("The sandbox cannot store live payment credentials.");
|
|
111
|
+
let { data: e } = await n.from("site_settings").select("value").eq("key", l).maybeSingle(), t = { ...p(e?.value) };
|
|
112
|
+
for (let [e, n] of s) n && n.trim() && (t[e] = r(n.trim()));
|
|
113
|
+
let { error: i } = await n.from("site_settings").upsert({
|
|
114
|
+
key: l,
|
|
115
|
+
value: t
|
|
115
116
|
});
|
|
116
|
-
if (
|
|
117
|
+
if (i) throw console.error("Error saving payment_secret settings:", i.message), Error("Failed to save payment credentials.");
|
|
117
118
|
}
|
|
118
|
-
|
|
119
|
+
h();
|
|
119
120
|
}
|
|
120
121
|
//#endregion
|
|
121
|
-
export {
|
|
122
|
+
export { h as clearPaymentConfigCache, x as getPaymentConfigStatus, S as getPaymentCredentialsView, b as hydrateFreemiusEnvFromDb, y as resolveStripePublishableKey, _ as resolveStripeSecretKey, v as resolveStripeWebhookSecret, C as savePaymentCredentials };
|
package/lib/product-actions.cjs
CHANGED
|
@@ -167,7 +167,7 @@ const e=require("./shared-inventory.cjs");let t=require("@nextblock-cms/utils"),
|
|
|
167
167
|
description_translations
|
|
168
168
|
)
|
|
169
169
|
)
|
|
170
|
-
`).eq(`slug`,t);if(i)return{data:null,error:i};if(!r||r.length===0)return{data:null,error:{message:`Product not found`,code:`PGRST116`}};let a=null;return n&&(a=r.find(e=>(Array.isArray(e.languages)?e.languages[0]:e.languages)?.code===n)),a||=r.find(e=>(Array.isArray(e.languages)?e.languages[0]:e.languages)?.is_default),a||=r.find(e=>(Array.isArray(e.languages)?e.languages[0]:e.languages)?.code===`en`),a||=r[0],{data:a,error:null}}async function m(t,n){let{data:r,error:i}=await t.rpc(`upsert_product_with_variants`,{product_payload:s(n)});if(i||!r)throw i||Error(`Failed to create product`);if(n.product_media&&n.product_media.length>0){let e=n.product_media.map((e,t)=>({product_id:r,media_id:e.media_id,sort_order:t}));await t.from(`product_media`).insert(e)}else n.media_id&&await t.from(`product_media`).insert({product_id:r,media_id:n.media_id,sort_order:0});await l(t,r,n.is_taxable),await c(t,r,n),await u(t,r,n),await e.syncSharedInventoryForSavedProduct(r,n),n.category_ids!==void 0&&await y(t,r,n.category_ids);let{data:a}=await t.from(`products`).select(`*`).eq(`id`,r).single();return a}async function h(t,r,i){let{data:a}=await t.from(`product_media`).select(`media_id`).eq(`product_id`,r),o=a?.map(e=>e.media_id)||[],{data:d,error:f}=await t.rpc(`upsert_product_with_variants`,{product_payload:s(i,r)});if(f||!d)throw f||Error(`Failed to update product`);if(i.product_media){if(await t.from(`product_media`).delete().eq(`product_id`,r),i.product_media.length>0){let e=i.product_media.map((e,t)=>({product_id:r,media_id:e.media_id,sort_order:t}));await t.from(`product_media`).insert(e)}}else i.media_id&&(await t.from(`product_media`).delete().eq(`product_id`,r),await t.from(`product_media`).insert({product_id:r,media_id:i.media_id,sort_order:0}));await l(t,d,i.is_taxable),await c(t,d,i),await u(t,d,i);let p=i.product_media?i.product_media.map(e=>e.media_id):i.media_id?[i.media_id]:[],m=i.explicitly_removed_media_ids||[],h=o.filter(e=>!p.includes(e)),g=Array.from(new Set([...h,...m]));if(g.length>0)for(let e of g){let{count:r}=await t.from(`product_media`).select(`*`,{count:`exact`,head:!0}).eq(`media_id`,e);if(r&&r>0)continue;let{count:i}=await t.from(`posts`).select(`*`,{count:`exact`,head:!0}).eq(`feature_image_id`,e);if(i&&i>0)continue;let{count:a}=await t.from(`logos`).select(`*`,{count:`exact`,head:!0}).eq(`media_id`,e);if(a&&a>0)continue;let{count:o}=await t.from(`product_variants`).select(`*`,{count:`exact`,head:!0}).eq(`main_media_id`,e);if(o&&o>0)continue;let{data:s}=await t.from(`media`).
|
|
170
|
+
`).eq(`slug`,t);if(i)return{data:null,error:i};if(!r||r.length===0)return{data:null,error:{message:`Product not found`,code:`PGRST116`}};let a=null;return n&&(a=r.find(e=>(Array.isArray(e.languages)?e.languages[0]:e.languages)?.code===n)),a||=r.find(e=>(Array.isArray(e.languages)?e.languages[0]:e.languages)?.is_default),a||=r.find(e=>(Array.isArray(e.languages)?e.languages[0]:e.languages)?.code===`en`),a||=r[0],{data:a,error:null}}async function m(t,n){let{data:r,error:i}=await t.rpc(`upsert_product_with_variants`,{product_payload:s(n)});if(i||!r)throw i||Error(`Failed to create product`);if(n.product_media&&n.product_media.length>0){let e=n.product_media.map((e,t)=>({product_id:r,media_id:e.media_id,sort_order:t}));await t.from(`product_media`).insert(e)}else n.media_id&&await t.from(`product_media`).insert({product_id:r,media_id:n.media_id,sort_order:0});await l(t,r,n.is_taxable),await c(t,r,n),await u(t,r,n),await e.syncSharedInventoryForSavedProduct(r,n),n.category_ids!==void 0&&await y(t,r,n.category_ids);let{data:a}=await t.from(`products`).select(`*`).eq(`id`,r).single();return a}async function h(t,r,i){let{data:a}=await t.from(`product_media`).select(`media_id`).eq(`product_id`,r),o=a?.map(e=>e.media_id)||[],{data:d,error:f}=await t.rpc(`upsert_product_with_variants`,{product_payload:s(i,r)});if(f||!d)throw f||Error(`Failed to update product`);if(i.product_media){if(await t.from(`product_media`).delete().eq(`product_id`,r),i.product_media.length>0){let e=i.product_media.map((e,t)=>({product_id:r,media_id:e.media_id,sort_order:t}));await t.from(`product_media`).insert(e)}}else i.media_id&&(await t.from(`product_media`).delete().eq(`product_id`,r),await t.from(`product_media`).insert({product_id:r,media_id:i.media_id,sort_order:0}));await l(t,d,i.is_taxable),await c(t,d,i),await u(t,d,i);let p=i.product_media?i.product_media.map(e=>e.media_id):i.media_id?[i.media_id]:[],m=i.explicitly_removed_media_ids||[],h=o.filter(e=>!p.includes(e)),g=Array.from(new Set([...h,...m]));if(g.length>0)for(let e of g){let{count:r}=await t.from(`product_media`).select(`*`,{count:`exact`,head:!0}).eq(`media_id`,e);if(r&&r>0)continue;let{count:i}=await t.from(`posts`).select(`*`,{count:`exact`,head:!0}).eq(`feature_image_id`,e);if(i&&i>0)continue;let{count:a}=await t.from(`logos`).select(`*`,{count:`exact`,head:!0}).eq(`media_id`,e);if(a&&a>0)continue;let{count:o}=await t.from(`product_variants`).select(`*`,{count:`exact`,head:!0}).eq(`main_media_id`,e);if(o&&o>0)continue;let{data:s}=await t.from(`media`).delete().eq(`id`,e).select(`object_key, variants`),c=s&&s.length>0?s[0]:null;if(c){let e=[];c.object_key&&e.push(c.object_key),c.variants&&Array.isArray(c.variants)&&c.variants.forEach(t=>{t?.objectKey&&e.push(t.objectKey)}),e.length>0&&await(0,n.deleteMediaFiles)(e)}}await e.syncSharedInventoryForSavedProduct(d,i),i.category_ids!==void 0&&await y(t,r,i.category_ids);let{data:_}=await t.from(`products`).select(`*`).eq(`id`,d).single();return _}async function g(e,t){let{error:n}=await e.from(`products`).delete().eq(`id`,t);if(n)throw n;return!0}async function _(e,t,n){let{data:r,error:i}=await e.from(`products`).select(`*`).eq(`id`,n).single();if(i||!r)throw Error(i?.message||`Source product not found`);let{data:a,error:o}=await e.from(`products`).select(`language_id`).eq(`id`,t).single();if(o||!a)throw Error(o?.message||`Target product not found`);let{error:s}=await e.from(`products`).update({title:r.title,short_description:r.short_description,description_json:r.description_json}).eq(`id`,t);if(s)throw s;let{data:c,error:l}=await e.from(`blocks`).select(`*`).eq(`product_id`,n).order(`order`,{ascending:!0});if(l)throw l;if(await e.from(`blocks`).delete().eq(`product_id`,t),c&&c.length>0){let n=c.map(e=>{let{id:n,created_at:r,updated_at:i,...o}=e;return{...o,product_id:t,language_id:a.language_id}}),{error:r}=await e.from(`blocks`).insert(n);if(r)throw r}await e.from(`product_drafts`).delete().eq(`product_id`,t),await e.from(`product_media`).delete().eq(`product_id`,t);let{data:u}=await e.from(`product_media`).select(`media_id, sort_order`).eq(`product_id`,n);if(u&&u.length>0){let n=u.map(e=>({product_id:t,media_id:e.media_id,sort_order:e.sort_order}));await e.from(`product_media`).insert(n)}return{success:!0}}async function v(e,n,r,i=[],a=[]){let{data:o}=await e.from(`languages`).select(`id`).eq(`code`,r).single();if(!o)return{data:[],error:`Language not found`};let s=[];n.length>0&&s.push(`translation_group_id.in.(${n.join(`,`)})`),i.length>0&&s.push(`sku.in.(${i.map(e=>`"${e}"`).join(`,`)})`),a.length>0&&s.push(`id.in.(${a.join(`,`)})`);let c=e.from(`products`).select(`
|
|
171
171
|
id,
|
|
172
172
|
title,
|
|
173
173
|
sku,
|
|
@@ -214,12 +214,12 @@ async function h(t, r, i) {
|
|
|
214
214
|
head: !0
|
|
215
215
|
}).eq("main_media_id", e);
|
|
216
216
|
if (o && o > 0) continue;
|
|
217
|
-
let { data: s } = await t.from("media").
|
|
218
|
-
if (
|
|
219
|
-
let
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}),
|
|
217
|
+
let { data: s } = await t.from("media").delete().eq("id", e).select("object_key, variants"), c = s && s.length > 0 ? s[0] : null;
|
|
218
|
+
if (c) {
|
|
219
|
+
let e = [];
|
|
220
|
+
c.object_key && e.push(c.object_key), c.variants && Array.isArray(c.variants) && c.variants.forEach((t) => {
|
|
221
|
+
t?.objectKey && e.push(t.objectKey);
|
|
222
|
+
}), e.length > 0 && await n(e);
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
await e(d, i), i.category_ids !== void 0 && await y(t, r, i.category_ids);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require("../coupons.cjs");var t=1e4;function n(e){return typeof e==`number`&&Number.isSafeInteger(e)&&e>0&&e<=1e4}function r(){return{error:`Your checkout items could not be processed.`,errorKey:`ecommerce.checkout_invalid_items`,errorStatus:400}}function i(t){let i={ok:!1,error:r()};if(!Array.isArray(t)||t.length===0)return i;let a=new Map;for(let r of t){if(!r||typeof r!=`object`||Array.isArray(r))return i;let t=r;if(typeof t.product_id!=`string`||!t.product_id.trim()||t.variant_id!==void 0&&t.variant_id!==null&&typeof t.variant_id!=`string`||!n(t.quantity))return i;let o=e.getCartLineCouponKey(t),s=a.get(o);if(s){let e=s.quantity+t.quantity;if(!n(e))return i;a.set(o,{...s,quantity:e});continue}a.set(o,{...t})}return{ok:!0,items:[...a.values()]}}exports.MAX_CHECKOUT_LINE_QUANTITY=t,exports.createInvalidCheckoutItemsError=r,exports.isValidCheckoutQuantity=n,exports.normalizeCheckoutItems=i;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CheckoutErrorPayload } from '../inventory-settings';
|
|
2
|
+
import { CartItem } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Upper bound for one cart line after duplicates are merged. Inventory tracking bounds the
|
|
5
|
+
* quantity by stock when it is on; when it is off this is the only ceiling, and it keeps
|
|
6
|
+
* `unit_amount * quantity` far from both Stripe's per-line maximum and integer overflow.
|
|
7
|
+
* `apps/nextblock/app/api/checkout/route.ts` mirrors the value in its request schema.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MAX_CHECKOUT_LINE_QUANTITY = 10000;
|
|
10
|
+
export declare function isValidCheckoutQuantity(value: unknown): value is number;
|
|
11
|
+
export declare function createInvalidCheckoutItemsError(): CheckoutErrorPayload;
|
|
12
|
+
export type CheckoutItemsNormalization = {
|
|
13
|
+
ok: true;
|
|
14
|
+
items: CartItem[];
|
|
15
|
+
} | {
|
|
16
|
+
ok: false;
|
|
17
|
+
error: CheckoutErrorPayload;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Validates and merges the cart lines a checkout submitted.
|
|
21
|
+
*
|
|
22
|
+
* Every quantity must be a positive integer no greater than MAX_CHECKOUT_LINE_QUANTITY: the
|
|
23
|
+
* providers multiply it into the subtotal, store it on `order_items`, and the paid-order
|
|
24
|
+
* inventory deduction subtracts the SUM of a product's lines from stock, so a negative line
|
|
25
|
+
* used to deflate the stored total below the Stripe charge and ADD phantom stock on payment.
|
|
26
|
+
*
|
|
27
|
+
* Lines for the same product + variant are merged into one (quantities summed) so a product
|
|
28
|
+
* is priced, discounted and recorded exactly once, whatever shape the request arrived in.
|
|
29
|
+
*/
|
|
30
|
+
export declare function normalizeCheckoutItems(items: unknown): CheckoutItemsNormalization;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { getCartLineCouponKey as e } from "../coupons.es.js";
|
|
2
|
+
//#region src/lib/providers/checkout-items.ts
|
|
3
|
+
var t = 1e4;
|
|
4
|
+
function n(e) {
|
|
5
|
+
return typeof e == "number" && Number.isSafeInteger(e) && e > 0 && e <= 1e4;
|
|
6
|
+
}
|
|
7
|
+
function r() {
|
|
8
|
+
return {
|
|
9
|
+
error: "Your checkout items could not be processed.",
|
|
10
|
+
errorKey: "ecommerce.checkout_invalid_items",
|
|
11
|
+
errorStatus: 400
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function i(t) {
|
|
15
|
+
let i = {
|
|
16
|
+
ok: !1,
|
|
17
|
+
error: r()
|
|
18
|
+
};
|
|
19
|
+
if (!Array.isArray(t) || t.length === 0) return i;
|
|
20
|
+
let a = /* @__PURE__ */ new Map();
|
|
21
|
+
for (let r of t) {
|
|
22
|
+
if (!r || typeof r != "object" || Array.isArray(r)) return i;
|
|
23
|
+
let t = r;
|
|
24
|
+
if (typeof t.product_id != "string" || !t.product_id.trim() || t.variant_id !== void 0 && t.variant_id !== null && typeof t.variant_id != "string" || !n(t.quantity)) return i;
|
|
25
|
+
let o = e(t), s = a.get(o);
|
|
26
|
+
if (s) {
|
|
27
|
+
let e = s.quantity + t.quantity;
|
|
28
|
+
if (!n(e)) return i;
|
|
29
|
+
a.set(o, {
|
|
30
|
+
...s,
|
|
31
|
+
quantity: e
|
|
32
|
+
});
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
a.set(o, { ...t });
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
ok: !0,
|
|
39
|
+
items: [...a.values()]
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { t as MAX_CHECKOUT_LINE_QUANTITY, r as createInvalidCheckoutItemsError, n as isValidCheckoutQuantity, i as normalizeCheckoutItems };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../currency.cjs"),n=require("../coupon-server.cjs"),r=require("../customer.cjs"),i=require("../customer-addresses.cjs"),a=require("../payment-config.cjs");let o=require("@supabase/supabase-js"),s=require("crypto");s=e.__toESM(s,1);let c=require("@freemius/sdk");function l(e){let t=process.env[e];if(!t)return null;let n=t.trim();return n.startsWith(`"`)&&n.endsWith(`"`)||n.startsWith(`'`)&&n.endsWith(`'`)?n.slice(1,-1).trim():n}function u(e){let t=e?.trim();if(!t)return{firstName:null,lastName:null};let[n,...r]=t.split(/\s+/);return{firstName:n||null,lastName:r.length>0?r.join(` `):null}}function d(e){if(e==null||e===``)return 0;let t=Number(e);return!Number.isFinite(t)||t<=0?0:Math.round(t)}function f(e){return e===!0||e===1||e===`1`||e===`true`}function p(e,t){let n=e?.[t];return Array.isArray(n)?n:n&&typeof n==`object`?[n]:[]}function m(e,t){for(let n of t){let t=p(e,n);if(t.length>0)return t}return Array.isArray(e)?e:[]}function h(e){if(e==null||e===``)return null;let t=Number(e);return Number.isFinite(t)?t:null}function g(e){return e===null?0:e>5e3?(console.warn(`[Freemius Sync] Suspiciously high price detected: ${e}. Assuming it is already in cents.`),Math.round(e)):Math.round(e*100)}function _(e){let t=Number(e);return!Number.isFinite(t)||t<1?1:Math.round(t)}function v(){let e=l(`FREEMIUS_CHECKOUT_PRODUCTS_JSON`);if(!e)return null;try{let t=JSON.parse(e);return t&&typeof t==`object`?t:null}catch(e){return console.error(`[Freemius Checkout] Failed to parse FREEMIUS_CHECKOUT_PRODUCTS_JSON:`,e),null}}function y(e){let t=v(),n=String(e),r=t?.[n],i=l(`FREEMIUS_PRODUCT_ID`),a=l(`FREEMIUS_ECOMMERCE_SANDBOX_PUBLIC_KEY`),o=l(`FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY`);return r?.publicKey?{publicKey:r.publicKey,secretKey:r.secretKey??null,apiKey:r.apiKey??null,source:`product-map`}:process.env.FREEMIUS_SANDBOX_ENABLED===`true`&&i&&i===n&&a?{publicKey:a,secretKey:o,apiKey:l(`FREEMIUS_API_KEY`),source:`single-product-sandbox-env`}:i&&i===n&&l(`FREEMIUS_PUBLIC_KEY`)?{publicKey:l(`FREEMIUS_PUBLIC_KEY`),secretKey:l(`FREEMIUS_SECRET_KEY`),apiKey:l(`FREEMIUS_API_KEY`),source:`single-product-env`}:{publicKey:l(`FREEMIUS_PUBLIC_KEY`),secretKey:l(`FREEMIUS_SECRET_KEY`),apiKey:l(`FREEMIUS_API_KEY`),source:`legacy-env`}}async function b(e){if(!e.apiKey)throw Error(`Missing Freemius API key for SDK sandbox generation.`);return new c.Freemius({productId:Number(e.productId),apiKey:e.apiKey,secretKey:e.secretKey,publicKey:e.publicKey}).checkout.getSandboxParams()}var x=class{getProviderName(){return`Freemius`}async createCheckoutSession({items:e,customerEmail:c,customerPhone:f,userId:p,billingAddress:m,shippingAddress:h,currencyCode:g,couponCode:_,couponContextItems:v}){let x=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,S=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!x||!S)return{error:`Missing Supabase credentials for checkout (Service Key required).`,url:null};let C=(0,o.createClient)(x,S);if(!e||e.length===0)return{error:`Cart is empty`,url:null};if(e.length!==1)return{error:`Freemius items must be checked out one at a time.`,url:null};let{data:w,error:T}=await C.from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}),E=w??[];if(T||E.length===0)return{error:`Failed to resolve store currencies`,url:null};let D=t.getDefaultCurrency(E),O=E.find(e=>e.code===(g||``).toUpperCase())??D,k=e[0],{data:A,error:j}=await C.from(`products`).select(`id, title, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, freemius_plan_id, freemius_product_id, trial_period_days, trial_requires_payment_method`).eq(`id`,k.product_id).single();if(j||!A)return{error:`Product not found`,url:null};let M=A.freemius_plan_id,N=A.freemius_product_id;if(!M||!N)return{error:`Product is not configured for Freemius checkout (missing Plan ID or Product ID)`,url:null};let P=t.resolveEffectivePriceForCurrency({prices:A.prices||{},salePrices:A.sale_prices||{},fallbackPrice:A.price,fallbackSalePrice:A.sale_price,saleStartAt:A.sale_start_at,saleEndAt:A.sale_end_at,scheduledPrice:A.scheduled_price,scheduledPrices:A.scheduled_prices||{},scheduledPriceAt:A.scheduled_price_at,currencyCode:O.code,currencies:E}),F=P.sale_price??P.price,I=t.isSaleWindowActive({saleStartAt:A.sale_start_at,saleEndAt:A.sale_end_at}),L=F*k.quantity,R=null,z=0;if(_){let t=await n.getCouponQuote({client:C,code:_,items:v&&v.length>0?v:e,currencyCode:O.code});if(!t.success)return{error:t.error,errorKey:t.errorKey,errorStatus:400,url:null};R=t.quote,z=Math.min(L,R.lineDiscounts.filter(e=>e.product_id===A.id).reduce((e,t)=>e+t.discount,0))}let B=d(A.trial_period_days),V=B>0?k.trial_preference?k.trial_preference:A.trial_requires_payment_method?`paid`:`free`:null,H=`pending`,U=u(m?.recipient_name??null),{data:W,error:G}=await C.from(`orders`).insert({status:H,total:Math.max(0,L-z),currency:O.code,exchange_rate_at_purchase:O.exchange_rate,subtotal:L,discount_total:z,coupon_id:R?.couponId??null,coupon_code:R?.code??null,discount_details:R?{code:R.code,discount_type:R.discountType,discount_amount:R.discountAmount,provider:`freemius`,provider_discounts:R.providerDiscounts,line_discounts:R.lineDiscounts,final_amount_owned_by:`freemius`}:null,provider:`freemius`,freemius_product_id:String(N),freemius_plan_id:String(M),user_id:p||null,customer_details:r.normalizeOrderCustomerDetails({email:c,phone:f,name:m?.recipient_name,billing:m,shipping:h})}).select(`id`).single();if(G||!W)return console.error(`Failed to create pending order:`,G),{error:`Failed to initiate order`,url:null};let{error:K}=await C.from(`order_items`).insert([{order_id:W.id,product_id:A.id,quantity:k.quantity,price_at_purchase:F}]);if(K&&console.error(`Failed to insert order items:`,K),p)try{await i.upsertDefaultUserAddresses({userId:p,billingAddress:m,shippingAddress:h,client:C}),await i.fillMissingUserProfileCheckoutDetails({userId:p,fullName:m?.recipient_name??h?.recipient_name??null,phone:f,client:C})}catch(e){console.error(`Failed to sync checkout profile defaults before checkout:`,e)}R&&await n.recordCouponRedemption({client:C,quote:R,orderId:W.id,provider:`freemius`,discountTotal:z,userId:p,customerEmail:c,metadata:{currency:O.code,subtotal:L,final_amount_owned_by:`freemius`}}),await a.hydrateFreemiusEnvFromDb();let q=process.env.FREEMIUS_SANDBOX_ENABLED===`true`,J=y(N),Y=J.publicKey,X=J.secretKey,Z=J.apiKey;if(!Y||q&&!X)return console.error(`Freemius checkout blocked: missing credentials (PUBLIC_KEY or SECRET_KEY) in CMS → Payments or environment.`),{error:`This store is not able to take payments right now. Please contact the seller to complete your purchase.`,errorKey:`ecommerce.checkout_payments_unavailable`,errorStatus:503,url:null};if(q&&J.source===`legacy-env`){let e=l(`FREEMIUS_PRODUCT_ID`),t=!!l(`FREEMIUS_ECOMMERCE_SANDBOX_PUBLIC_KEY`),n=!!l(`FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY`);console.warn(`[Freemius Checkout] Sandbox is enabled for product ${N}, but no product-scoped checkout credentials were selected. Falling back to legacy FREEMIUS_PUBLIC_KEY/FREEMIUS_SECRET_KEY may open live checkout instead of sandbox.`,{configuredProductId:e,productIdsMatch:e===String(N),hasSandboxOverridePublicKey:t,hasSandboxOverrideSecretKey:n,hasCheckoutProductsJson:!!l(`FREEMIUS_CHECKOUT_PRODUCTS_JSON`)})}let Q=!1;if(q&&X&&Y)try{Q=await b({productId:N,publicKey:Y,secretKey:X,apiKey:Z})}catch(e){console.warn(`Freemius Checkout - SDK sandbox generation failed. Falling back to manual token generation.`,e,{credentialSource:J.source,hasApiKey:!!Z});let t=Math.floor(Date.now()/1e3).toString(),n=`${t}${N}${X}${Y}checkout`;Q={ctx:t,token:s.default.createHash(`md5`).update(n).digest(`hex`)}}let $=new URL(`https://checkout.freemius.com/app/${N}/plan/${M}/`);if(q&&X&&Y?($.searchParams.append(`sandbox`,Q.token),$.searchParams.append(`s_ctx_ts`,Q.ctx)):q&&$.searchParams.append(`sandbox`,`true`),c&&$.searchParams.append(`user_email`,c),U.firstName&&$.searchParams.append(`user_firstname`,U.firstName),U.lastName&&$.searchParams.append(`user_lastname`,U.lastName),$.searchParams.append(`currency`,O.code.toLowerCase()),k.billing_cycle&&$.searchParams.append(`billing_cycle`,k.billing_cycle),V&&$.searchParams.append(`trial`,V),R)$.searchParams.append(`coupon`,R.code);else if(I){let{data:e}=await C.from(`product_freemius_sale_coupons`).select(`freemius_coupon_code, is_active, starts_at, ends_at, sync_status`).eq(`product_id`,A.id).maybeSingle();e?.is_active&&e.sync_status===`synced`&&e.freemius_coupon_code&&t.isSaleWindowActive({saleStartAt:e.starts_at,saleEndAt:e.ends_at})&&$.searchParams.append(`coupon`,e.freemius_coupon_code)}return{url:$.toString(),customProps:{provider:`freemius`,plugin_id:N,plan_id:M,public_key:Y,user_email:c,user_firstname:U.firstName,user_lastname:U.lastName,credential_source:J.source,sandbox:Q,billing_cycle:k.billing_cycle,trial:V,trial_period_days:B,trial_requires_payment_method:A.trial_requires_payment_method,initial_order_status:H,coupon:R?.code??null,order_id:W.id}}}};async function S(e,t,n,r){let i=new Date().toUTCString().replace(`GMT`,`+0000`),a=`GET\n\n\n${i}\n${e}`,o=s.default.createHmac(`sha256`,r).update(a).digest(`hex`),c=`FS ${t}:${n}:${Buffer.from(o).toString(`base64`).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=/g,``)}`,l=await fetch(`https://api.freemius.com${e}`,{headers:{Authorization:c,Date:i,Accept:`application/json`}});if(!l.ok){let t=await l.text();throw console.error(`[Freemius API] [ERROR] ${e} returned ${l.status}: ${t}`),Error(`Freemius API failed on ${e}: ${l.status} - ${t}`)}return l.json()}async function C(){let e=l(`FREEMIUS_DEVELOPER_ID`),t=l(`FREEMIUS_PUBLIC_KEY`),n=l(`FREEMIUS_SECRET_KEY`),r=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,i=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!e||!t||!n||!r||!i)throw Error(`Missing necessary environment variables for Freemius Sync.`);let a=(0,o.createClient)(r,i,{auth:{autoRefreshToken:!1,persistSession:!1}}),s=r=>S(r,e,t,n);try{console.log(`[Freemius Sync] Fetching all plugins for developer ${e}...`);let t=m(await s(`/v1/developers/${e}/plugins.json`),[`plugins`,`plugin`]);console.log(`[Freemius Sync] Found ${t.length} plugins. Syncing plans...`);let n=0,{data:r}=await a.from(`languages`).select(`id`).eq(`code`,`en`).single(),i=r?.id;if(!i)throw Error(`English language not found in database. Cannot sync products.`);for(let r of t){let t=r.id?.toString();if(!t){console.warn(`[Freemius Sync] Skipping plugin without an id:`,r);continue}let o=await T(a,e,t,r.title||r.name||`Freemius Product ${t}`,s,i);n+=o}return{success:!0,count:n}}catch(e){throw console.error(`[Freemius Sync] Global Error:`,e),e}}async function w(e){let t=l(`FREEMIUS_DEVELOPER_ID`),n=l(`FREEMIUS_PUBLIC_KEY`),r=l(`FREEMIUS_SECRET_KEY`),i=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,a=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!t||!n||!r||!i||!a)throw Error(`Missing environment variables for Freemius Sync.`);let s=(0,o.createClient)(i,a),c=e=>S(e,t,n,r),{data:u}=await s.from(`languages`).select(`id`).eq(`code`,`en`).single(),d=u?.id;if(!d)throw Error(`English language not found in database. Cannot sync products.`);let f=await c(`/v1/developers/${t}/plugins/${e}.json`),p=f.plugin??f;return{success:!0,count:await T(s,t,e,p.title||p.name||`Freemius Product ${e}`,c,d)}}async function T(e,t,n,r,i,a){console.log(`[Freemius Sync] Fetching plans for plugin: ${r} (${n})...`);let o=0;try{let s=m(await i(`/v1/developers/${t}/plugins/${n}/plans.json`),[`plans`,`plan`]);console.log(`[Freemius Sync] Received ${s.length} plans for plugin ${n}.`);for(let c of s){let s=c.id?.toString();if(!s){console.warn(`[Freemius Sync] Skipping plan without an id:`,c);continue}let l=c.name||c.title||s,u=c.title||l;console.log(`[Freemius Sync] Processing plan: ${u} (${s})...`);let p=c;if(p.trial_period===void 0||p.is_require_subscription===void 0)try{let e=await i(`/v1/developers/${t}/plugins/${n}/plans/${s}.json`),r=e.plan??e;p={...p,...r}}catch(e){console.warn(`[Freemius Sync] Could not fetch trial details for plan ${s}:`,e instanceof Error?e.message:e)}let v=d(p.trial_period),y=v>0&&f(p.is_require_subscription),b=0,x=[];try{if(x=m(await i(`/v1/developers/${t}/plugins/${n}/plans/${s}/pricing.json`),[`pricing`,`prices`,`pricings`]),x.length>0){let e=x[0];b=g(h(e.annual_price)??h(e.monthly_price)??h(e.lifetime_price))}console.log(`[Freemius Sync] Plan: ${u} -> Resolved Price (cents): ${b}`)}catch(e){console.warn(`[Freemius Sync] Could not fetch pricing for plan ${s}:`,e instanceof Error?e.message:e)}let S=`${r}-${u}`.toLowerCase().replace(/[^\w\s-]/g,``).replace(/[\s_]+/g,`-`).replace(/^-+|-+$/g,``),C={title:`${r} - ${u}`,slug:S,short_description:c.description||``,price:b,product_type:`digital`,payment_provider:`freemius`,freemius_plan_id:s,freemius_product_id:n,trial_period_days:v,trial_requires_payment_method:y,status:`active`,stock:999,sku:`FM-${n}-${s}`,language_id:a},{data:w,error:T}=await e.from(`products`).upsert(C,{onConflict:`language_id, sku`}).select();if(T||!w||w.length===0){console.error(`[Freemius Sync] Error upserting product ${C.sku}:`,T);continue}let E=w[0].id,{data:D,error:O}=await e.from(`freemius_plans`).select(`id`).eq(`product_id`,E).eq(`name`,l).maybeSingle();O&&console.warn(`[Freemius Sync] Could not check existing local plan for ${C.sku}:`,O.message||O);let k=``;if(D){k=D.id;let{error:t}=await e.from(`freemius_plans`).update({title:u,updated_at:new Date().toISOString()}).eq(`id`,k);t&&console.warn(`[Freemius Sync] Could not update local plan ${k}:`,t.message||t)}else{let{data:t,error:n}=await e.from(`freemius_plans`).insert({product_id:E,name:l,title:u}).select(`id`).single();n&&console.warn(`[Freemius Sync] Could not insert local plan for ${C.sku}:`,n.message||n),t&&(k=t.id)}if(k&&x.length>0)for(let t of x){let n=_(t.licenses??t.license_quota??t.quota),{data:r,error:i}=await e.from(`freemius_pricing`).select(`id`).eq(`plan_id`,k).eq(`license_quota`,n).maybeSingle();i&&console.warn(`[Freemius Sync] Could not check pricing for plan ${k}, quota ${n}:`,i.message||i);let a={api_monthly_price:h(t.monthly_price),api_annual_price:h(t.annual_price),api_lifetime_price:h(t.lifetime_price),updated_at:new Date().toISOString()};if(r){let{error:t}=await e.from(`freemius_pricing`).update(a).eq(`id`,r.id);t&&console.warn(`[Freemius Sync] Could not update pricing ${r.id}:`,t.message||t)}else{let{error:t}=await e.from(`freemius_pricing`).insert({plan_id:k,license_quota:n,...a});t&&console.warn(`[Freemius Sync] Could not insert pricing for plan ${k}, quota ${n}:`,t.message||t)}}console.log(`[Freemius Sync] Successfully fully synced product ${C.sku}.`),o++}}catch(e){console.error(`[Freemius Sync] Failed sync for plugin ${n}:`,e.message)}return o}exports.FreemiusProvider=x,exports.parseFreemiusCheckoutCredentialsMap=v,exports.readFreemiusEnvValue=l,exports.resolveFreemiusCheckoutCredentials=y,exports.syncFreemiusProductsToSupabase=C,exports.syncSingleFreemiusProduct=w;
|
|
1
|
+
const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../currency.cjs"),n=require("../coupon-server.cjs"),r=require("../customer.cjs"),i=require("../customer-addresses.cjs"),a=require("../payment-config.cjs"),o=require("../order-access-token.cjs"),s=require("./checkout-items.cjs");let c=require("@supabase/supabase-js"),l=require("crypto");l=e.__toESM(l,1);let u=require("@freemius/sdk");function d(e){let t=process.env[e];if(!t)return null;let n=t.trim();return n.startsWith(`"`)&&n.endsWith(`"`)||n.startsWith(`'`)&&n.endsWith(`'`)?n.slice(1,-1).trim():n}function f(e){let t=e?.trim();if(!t)return{firstName:null,lastName:null};let[n,...r]=t.split(/\s+/);return{firstName:n||null,lastName:r.length>0?r.join(` `):null}}function p(e){if(e==null||e===``)return 0;let t=Number(e);return!Number.isFinite(t)||t<=0?0:Math.round(t)}function m(e){return e===!0||e===1||e===`1`||e===`true`}function h(e,t){let n=e?.[t];return Array.isArray(n)?n:n&&typeof n==`object`?[n]:[]}function g(e,t){for(let n of t){let t=h(e,n);if(t.length>0)return t}return Array.isArray(e)?e:[]}function _(e){if(e==null||e===``)return null;let t=Number(e);return Number.isFinite(t)?t:null}function ee(e){return e===null?0:e>5e3?(console.warn(`[Freemius Sync] Suspiciously high price detected: ${e}. Assuming it is already in cents.`),Math.round(e)):Math.round(e*100)}function v(e){let t=Number(e);return!Number.isFinite(t)||t<1?1:Math.round(t)}function y(){let e=d(`FREEMIUS_CHECKOUT_PRODUCTS_JSON`);if(!e)return null;try{let t=JSON.parse(e);return t&&typeof t==`object`?t:null}catch(e){return console.error(`[Freemius Checkout] Failed to parse FREEMIUS_CHECKOUT_PRODUCTS_JSON:`,e),null}}function b(e){let t=y(),n=String(e),r=t?.[n],i=d(`FREEMIUS_PRODUCT_ID`),a=d(`FREEMIUS_ECOMMERCE_SANDBOX_PUBLIC_KEY`),o=d(`FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY`);return r?.publicKey?{publicKey:r.publicKey,secretKey:r.secretKey??null,apiKey:r.apiKey??null,source:`product-map`}:process.env.FREEMIUS_SANDBOX_ENABLED===`true`&&i&&i===n&&a?{publicKey:a,secretKey:o,apiKey:d(`FREEMIUS_API_KEY`),source:`single-product-sandbox-env`}:i&&i===n&&d(`FREEMIUS_PUBLIC_KEY`)?{publicKey:d(`FREEMIUS_PUBLIC_KEY`),secretKey:d(`FREEMIUS_SECRET_KEY`),apiKey:d(`FREEMIUS_API_KEY`),source:`single-product-env`}:{publicKey:d(`FREEMIUS_PUBLIC_KEY`),secretKey:d(`FREEMIUS_SECRET_KEY`),apiKey:d(`FREEMIUS_API_KEY`),source:`legacy-env`}}async function x(e){if(!e.apiKey)throw Error(`Missing Freemius API key for SDK sandbox generation.`);return new u.Freemius({productId:Number(e.productId),apiKey:e.apiKey,secretKey:e.secretKey,publicKey:e.publicKey}).checkout.getSandboxParams()}var S=class{getProviderName(){return`Freemius`}async createCheckoutSession({items:e,customerEmail:u,customerPhone:m,userId:h,billingAddress:g,shippingAddress:_,currencyCode:ee,couponCode:v,couponContextItems:y}){let S=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,C=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!S||!C)return{error:`Missing Supabase credentials for checkout (Service Key required).`,url:null};let w=(0,c.createClient)(S,C);if(!e||e.length===0)return{error:`Cart is empty`,url:null};if(e.length!==1)return{error:`Freemius items must be checked out one at a time.`,url:null};let T=s.normalizeCheckoutItems(e);if(!T.ok)return{url:null,...T.error};let E=T.items;if(y&&y.length>0){let e=s.normalizeCheckoutItems(y);if(!e.ok)return{url:null,...e.error};E=e.items}let{data:D,error:O}=await w.from(`currencies`).select(`code, symbol, exchange_rate, is_default, is_active, auto_sync_product_prices, auto_update_exchange_rate, exchange_rate_source, exchange_rate_updated_at, rounding_mode, rounding_increment, rounding_charm_amount`).eq(`is_active`,!0).order(`code`,{ascending:!0}),k=D??[];if(O||k.length===0)return{error:`Failed to resolve store currencies`,url:null};let te=t.getDefaultCurrency(k),A=k.find(e=>e.code===(ee||``).toUpperCase())??te,j=T.items[0],{data:M,error:ne}=await w.from(`products`).select(`id, title, price, prices, sale_price, sale_prices, sale_start_at, sale_end_at, scheduled_price, scheduled_prices, scheduled_price_at, freemius_plan_id, freemius_product_id, trial_period_days, trial_requires_payment_method`).eq(`id`,j.product_id).single();if(ne||!M)return{error:`Product not found`,url:null};let N=M.freemius_plan_id,P=M.freemius_product_id;if(!N||!P)return{error:`Product is not configured for Freemius checkout (missing Plan ID or Product ID)`,url:null};let F=t.resolveEffectivePriceForCurrency({prices:M.prices||{},salePrices:M.sale_prices||{},fallbackPrice:M.price,fallbackSalePrice:M.sale_price,saleStartAt:M.sale_start_at,saleEndAt:M.sale_end_at,scheduledPrice:M.scheduled_price,scheduledPrices:M.scheduled_prices||{},scheduledPriceAt:M.scheduled_price_at,currencyCode:A.code,currencies:k}),I=F.sale_price??F.price,re=t.isSaleWindowActive({saleStartAt:M.sale_start_at,saleEndAt:M.sale_end_at}),L=I*j.quantity,R=null,z=0;if(v){let e=await n.getCouponQuote({client:w,code:v,items:E,currencyCode:A.code});if(!e.success)return{error:e.error,errorKey:e.errorKey,errorStatus:400,url:null};R=e.quote,z=Math.min(L,R.lineDiscounts.filter(e=>e.product_id===M.id).reduce((e,t)=>e+t.discount,0))}let B=p(M.trial_period_days),V=B>0?j.trial_preference?j.trial_preference:M.trial_requires_payment_method?`paid`:`free`:null,H=`pending`,U=f(g?.recipient_name??null),{data:W,error:G}=await w.from(`orders`).insert({status:H,total:Math.max(0,L-z),currency:A.code,exchange_rate_at_purchase:A.exchange_rate,subtotal:L,discount_total:z,coupon_id:R?.couponId??null,coupon_code:R?.code??null,discount_details:R?{code:R.code,discount_type:R.discountType,discount_amount:R.discountAmount,provider:`freemius`,provider_discounts:R.providerDiscounts,line_discounts:R.lineDiscounts,final_amount_owned_by:`freemius`}:null,provider:`freemius`,freemius_product_id:String(P),freemius_plan_id:String(N),user_id:h||null,customer_details:r.normalizeOrderCustomerDetails({email:u,phone:m,name:g?.recipient_name,billing:g,shipping:_})}).select(`id`).single();if(G||!W)return console.error(`Failed to create pending order:`,G),{error:`Failed to initiate order`,url:null};let{error:K}=await w.from(`order_items`).insert([{order_id:W.id,product_id:M.id,quantity:j.quantity,price_at_purchase:I}]);if(K&&console.error(`Failed to insert order items:`,K),h)try{await i.upsertDefaultUserAddresses({userId:h,billingAddress:g,shippingAddress:_,client:w}),await i.fillMissingUserProfileCheckoutDetails({userId:h,fullName:g?.recipient_name??_?.recipient_name??null,phone:m,client:w})}catch(e){console.error(`Failed to sync checkout profile defaults before checkout:`,e)}if(R&&!(await n.recordCouponRedemption({client:w,quote:R,orderId:W.id,provider:`freemius`,discountTotal:z,userId:h,customerEmail:u,metadata:{currency:A.code,subtotal:L,final_amount_owned_by:`freemius`}})).success)return await w.from(`orders`).update({status:`failed`}).eq(`id`,W.id),{url:null,error:`Coupon is no longer available.`,errorKey:`ecommerce.coupon_invalid`};await a.hydrateFreemiusEnvFromDb();let q=process.env.FREEMIUS_SANDBOX_ENABLED===`true`,J=b(P),Y=J.publicKey,X=J.secretKey,Z=J.apiKey;if(!Y||q&&!X)return console.error(`Freemius checkout blocked: missing credentials (PUBLIC_KEY or SECRET_KEY) in CMS → Payments or environment.`),{error:`This store is not able to take payments right now. Please contact the seller to complete your purchase.`,errorKey:`ecommerce.checkout_payments_unavailable`,errorStatus:503,url:null};if(q&&J.source===`legacy-env`){let e=d(`FREEMIUS_PRODUCT_ID`),t=!!d(`FREEMIUS_ECOMMERCE_SANDBOX_PUBLIC_KEY`),n=!!d(`FREEMIUS_ECOMMERCE_SANDBOX_SECRET_KEY`);console.warn(`[Freemius Checkout] Sandbox is enabled for product ${P}, but no product-scoped checkout credentials were selected. Falling back to legacy FREEMIUS_PUBLIC_KEY/FREEMIUS_SECRET_KEY may open live checkout instead of sandbox.`,{configuredProductId:e,productIdsMatch:e===String(P),hasSandboxOverridePublicKey:t,hasSandboxOverrideSecretKey:n,hasCheckoutProductsJson:!!d(`FREEMIUS_CHECKOUT_PRODUCTS_JSON`)})}let Q=!1;if(q&&X&&Y)try{Q=await x({productId:P,publicKey:Y,secretKey:X,apiKey:Z})}catch(e){console.warn(`Freemius Checkout - SDK sandbox generation failed. Falling back to manual token generation.`,e,{credentialSource:J.source,hasApiKey:!!Z});let t=Math.floor(Date.now()/1e3).toString(),n=`${t}${P}${X}${Y}checkout`;Q={ctx:t,token:l.default.createHash(`md5`).update(n).digest(`hex`)}}let $=new URL(`https://checkout.freemius.com/app/${P}/plan/${N}/`);if(q&&X&&Y?($.searchParams.append(`sandbox`,Q.token),$.searchParams.append(`s_ctx_ts`,Q.ctx)):q&&$.searchParams.append(`sandbox`,`true`),u&&$.searchParams.append(`user_email`,u),U.firstName&&$.searchParams.append(`user_firstname`,U.firstName),U.lastName&&$.searchParams.append(`user_lastname`,U.lastName),$.searchParams.append(`currency`,A.code.toLowerCase()),j.billing_cycle&&$.searchParams.append(`billing_cycle`,j.billing_cycle),V&&$.searchParams.append(`trial`,V),R)$.searchParams.append(`coupon`,R.code);else if(re){let{data:e}=await w.from(`product_freemius_sale_coupons`).select(`freemius_coupon_code, is_active, starts_at, ends_at, sync_status`).eq(`product_id`,M.id).maybeSingle();e?.is_active&&e.sync_status===`synced`&&e.freemius_coupon_code&&t.isSaleWindowActive({saleStartAt:e.starts_at,saleEndAt:e.ends_at})&&$.searchParams.append(`coupon`,e.freemius_coupon_code)}return{url:$.toString(),customProps:{provider:`freemius`,plugin_id:P,plan_id:N,public_key:Y,user_email:u,user_firstname:U.firstName,user_lastname:U.lastName,credential_source:J.source,sandbox:Q,billing_cycle:j.billing_cycle,trial:V,trial_period_days:B,trial_requires_payment_method:M.trial_requires_payment_method,initial_order_status:H,coupon:R?.code??null,order_id:W.id,success_token:o.mintOrderAccessToken(W.id)}}}};async function C(e,t,n,r){let i=new Date().toUTCString().replace(`GMT`,`+0000`),a=`GET\n\n\n${i}\n${e}`,o=l.default.createHmac(`sha256`,r).update(a).digest(`hex`),s=`FS ${t}:${n}:${Buffer.from(o).toString(`base64`).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=/g,``)}`,c=await fetch(`https://api.freemius.com${e}`,{headers:{Authorization:s,Date:i,Accept:`application/json`}});if(!c.ok){let t=await c.text();throw console.error(`[Freemius API] [ERROR] ${e} returned ${c.status}: ${t}`),Error(`Freemius API failed on ${e}: ${c.status} - ${t}`)}return c.json()}async function w(){let e=d(`FREEMIUS_DEVELOPER_ID`),t=d(`FREEMIUS_PUBLIC_KEY`),n=d(`FREEMIUS_SECRET_KEY`),r=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,i=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!e||!t||!n||!r||!i)throw Error(`Missing necessary environment variables for Freemius Sync.`);let a=(0,c.createClient)(r,i,{auth:{autoRefreshToken:!1,persistSession:!1}}),o=r=>C(r,e,t,n);try{console.log(`[Freemius Sync] Fetching all plugins for developer ${e}...`);let t=g(await o(`/v1/developers/${e}/plugins.json`),[`plugins`,`plugin`]);console.log(`[Freemius Sync] Found ${t.length} plugins. Syncing plans...`);let n=0,{data:r}=await a.from(`languages`).select(`id`).eq(`code`,`en`).single(),i=r?.id;if(!i)throw Error(`English language not found in database. Cannot sync products.`);for(let r of t){let t=r.id?.toString();if(!t){console.warn(`[Freemius Sync] Skipping plugin without an id:`,r);continue}let s=await E(a,e,t,r.title||r.name||`Freemius Product ${t}`,o,i);n+=s}return{success:!0,count:n}}catch(e){throw console.error(`[Freemius Sync] Global Error:`,e),e}}async function T(e){let t=d(`FREEMIUS_DEVELOPER_ID`),n=d(`FREEMIUS_PUBLIC_KEY`),r=d(`FREEMIUS_SECRET_KEY`),i=process.env.NEXT_PUBLIC_SUPABASE_URL||process.env.SUPABASE_URL,a=process.env.SUPABASE_SERVICE_ROLE_KEY||process.env.SUPABASE_SECRET_KEY;if(!t||!n||!r||!i||!a)throw Error(`Missing environment variables for Freemius Sync.`);let o=(0,c.createClient)(i,a),s=e=>C(e,t,n,r),{data:l}=await o.from(`languages`).select(`id`).eq(`code`,`en`).single(),u=l?.id;if(!u)throw Error(`English language not found in database. Cannot sync products.`);let f=await s(`/v1/developers/${t}/plugins/${e}.json`),p=f.plugin??f;return{success:!0,count:await E(o,t,e,p.title||p.name||`Freemius Product ${e}`,s,u)}}async function E(e,t,n,r,i,a){console.log(`[Freemius Sync] Fetching plans for plugin: ${r} (${n})...`);let o=0;try{let s=g(await i(`/v1/developers/${t}/plugins/${n}/plans.json`),[`plans`,`plan`]);console.log(`[Freemius Sync] Received ${s.length} plans for plugin ${n}.`);for(let c of s){let s=c.id?.toString();if(!s){console.warn(`[Freemius Sync] Skipping plan without an id:`,c);continue}let l=c.name||c.title||s,u=c.title||l;console.log(`[Freemius Sync] Processing plan: ${u} (${s})...`);let d=c;if(d.trial_period===void 0||d.is_require_subscription===void 0)try{let e=await i(`/v1/developers/${t}/plugins/${n}/plans/${s}.json`),r=e.plan??e;d={...d,...r}}catch(e){console.warn(`[Freemius Sync] Could not fetch trial details for plan ${s}:`,e instanceof Error?e.message:e)}let f=p(d.trial_period),h=f>0&&m(d.is_require_subscription),y=0,b=[];try{if(b=g(await i(`/v1/developers/${t}/plugins/${n}/plans/${s}/pricing.json`),[`pricing`,`prices`,`pricings`]),b.length>0){let e=b[0];y=ee(_(e.annual_price)??_(e.monthly_price)??_(e.lifetime_price))}console.log(`[Freemius Sync] Plan: ${u} -> Resolved Price (cents): ${y}`)}catch(e){console.warn(`[Freemius Sync] Could not fetch pricing for plan ${s}:`,e instanceof Error?e.message:e)}let x=`${r}-${u}`.toLowerCase().replace(/[^\w\s-]/g,``).replace(/[\s_]+/g,`-`).replace(/^-+|-+$/g,``),S={title:`${r} - ${u}`,slug:x,short_description:c.description||``,price:y,product_type:`digital`,payment_provider:`freemius`,freemius_plan_id:s,freemius_product_id:n,trial_period_days:f,trial_requires_payment_method:h,status:`active`,stock:999,sku:`FM-${n}-${s}`,language_id:a},{data:C,error:w}=await e.from(`products`).upsert(S,{onConflict:`language_id, sku`}).select();if(w||!C||C.length===0){console.error(`[Freemius Sync] Error upserting product ${S.sku}:`,w);continue}let T=C[0].id,{data:E,error:D}=await e.from(`freemius_plans`).select(`id`).eq(`product_id`,T).eq(`name`,l).maybeSingle();D&&console.warn(`[Freemius Sync] Could not check existing local plan for ${S.sku}:`,D.message||D);let O=``;if(E){O=E.id;let{error:t}=await e.from(`freemius_plans`).update({title:u,updated_at:new Date().toISOString()}).eq(`id`,O);t&&console.warn(`[Freemius Sync] Could not update local plan ${O}:`,t.message||t)}else{let{data:t,error:n}=await e.from(`freemius_plans`).insert({product_id:T,name:l,title:u}).select(`id`).single();n&&console.warn(`[Freemius Sync] Could not insert local plan for ${S.sku}:`,n.message||n),t&&(O=t.id)}if(O&&b.length>0)for(let t of b){let n=v(t.licenses??t.license_quota??t.quota),{data:r,error:i}=await e.from(`freemius_pricing`).select(`id`).eq(`plan_id`,O).eq(`license_quota`,n).maybeSingle();i&&console.warn(`[Freemius Sync] Could not check pricing for plan ${O}, quota ${n}:`,i.message||i);let a={api_monthly_price:_(t.monthly_price),api_annual_price:_(t.annual_price),api_lifetime_price:_(t.lifetime_price),updated_at:new Date().toISOString()};if(r){let{error:t}=await e.from(`freemius_pricing`).update(a).eq(`id`,r.id);t&&console.warn(`[Freemius Sync] Could not update pricing ${r.id}:`,t.message||t)}else{let{error:t}=await e.from(`freemius_pricing`).insert({plan_id:O,license_quota:n,...a});t&&console.warn(`[Freemius Sync] Could not insert pricing for plan ${O}, quota ${n}:`,t.message||t)}}console.log(`[Freemius Sync] Successfully fully synced product ${S.sku}.`),o++}}catch(e){console.error(`[Freemius Sync] Failed sync for plugin ${n}:`,e.message)}return o}exports.FreemiusProvider=S,exports.parseFreemiusCheckoutCredentialsMap=y,exports.readFreemiusEnvValue=d,exports.resolveFreemiusCheckoutCredentials=b,exports.syncFreemiusProductsToSupabase=w,exports.syncSingleFreemiusProduct=T;
|
|
@@ -30,7 +30,7 @@ export declare function resolveFreemiusCheckoutCredentials(productId: string | n
|
|
|
30
30
|
};
|
|
31
31
|
export declare class FreemiusProvider implements PaymentProvider {
|
|
32
32
|
getProviderName(): string;
|
|
33
|
-
createCheckoutSession({ items: cartItems, customerEmail, customerPhone, userId, billingAddress, shippingAddress, currencyCode, couponCode, couponContextItems, }: CheckoutSessionInput): Promise<{
|
|
33
|
+
createCheckoutSession({ items: cartItems, customerEmail, customerPhone, userId, billingAddress, shippingAddress, currencyCode, couponCode, couponContextItems: submittedCouponContextItems, }: CheckoutSessionInput): Promise<{
|
|
34
34
|
url: string | null;
|
|
35
35
|
error?: string;
|
|
36
36
|
errorKey?: string;
|