@uptrademedia/site-kit 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/index.js +7 -7
- package/dist/analytics/index.mjs +3 -3
- package/dist/api-QUIPJJCX.js +77 -0
- package/dist/api-QUIPJJCX.js.map +1 -0
- package/dist/api-V3BA5PMX.mjs +4 -0
- package/dist/api-V3BA5PMX.mjs.map +1 -0
- package/dist/blog/index.d.mts +2 -2
- package/dist/blog/index.d.ts +2 -2
- package/dist/blog/index.js +40 -6
- package/dist/blog/index.js.map +1 -1
- package/dist/blog/index.mjs +40 -6
- package/dist/blog/index.mjs.map +1 -1
- package/dist/blog/server.d.mts +3 -2
- package/dist/blog/server.d.ts +3 -2
- package/dist/blog/server.js +13 -6
- package/dist/blog/server.js.map +1 -1
- package/dist/blog/server.mjs +13 -6
- package/dist/blog/server.mjs.map +1 -1
- package/dist/{chunk-FKVJOT2F.mjs → chunk-42EXHJTC.mjs} +196 -7
- package/dist/chunk-42EXHJTC.mjs.map +1 -0
- package/dist/{scanner-AZV5I6US.mjs → chunk-44OMJFCG.mjs} +354 -14
- package/dist/chunk-44OMJFCG.mjs.map +1 -0
- package/dist/chunk-4TGJYNHV.js +981 -0
- package/dist/chunk-4TGJYNHV.js.map +1 -0
- package/dist/chunk-4XPGGLVP.mjs +53 -0
- package/dist/{chunk-NYKRE2FL.mjs.map → chunk-4XPGGLVP.mjs.map} +1 -1
- package/dist/{generators-TO2FKJR6.mjs → chunk-6ONUXZDO.mjs} +26 -9
- package/dist/chunk-6ONUXZDO.mjs.map +1 -0
- package/dist/chunk-CG53ASWX.mjs +729 -0
- package/dist/chunk-CG53ASWX.mjs.map +1 -0
- package/dist/{scanner-ETJAMIT7.js → chunk-DERI27QC.js} +448 -102
- package/dist/chunk-DERI27QC.js.map +1 -0
- package/dist/chunk-DYM5ML2V.mjs +1518 -0
- package/dist/chunk-DYM5ML2V.mjs.map +1 -0
- package/dist/chunk-FLZZOX44.js +1526 -0
- package/dist/chunk-FLZZOX44.js.map +1 -0
- package/dist/{chunk-7H6I3ECV.mjs → chunk-FQVGK746.mjs} +63 -3
- package/dist/chunk-FQVGK746.mjs.map +1 -0
- package/dist/{chunk-GQ6ZOU2N.mjs → chunk-JGQPAXTL.mjs} +4 -4
- package/dist/{chunk-GQ6ZOU2N.mjs.map → chunk-JGQPAXTL.mjs.map} +1 -1
- package/dist/{chunk-V3F5J6CV.js → chunk-JUEVN4Q4.js} +196 -7
- package/dist/chunk-JUEVN4Q4.js.map +1 -0
- package/dist/chunk-KKMGTT7F.mjs +968 -0
- package/dist/chunk-KKMGTT7F.mjs.map +1 -0
- package/dist/{chunk-XQJX252G.mjs → chunk-MB3WR5KJ.mjs} +28 -18
- package/dist/chunk-MB3WR5KJ.mjs.map +1 -0
- package/dist/{chunk-2IHTEKHU.mjs → chunk-QD5CN2OI.mjs} +16 -7
- package/dist/chunk-QD5CN2OI.mjs.map +1 -0
- package/dist/{chunk-SBVEYCSV.js → chunk-QQB4FO4Q.js} +7 -7
- package/dist/{chunk-SBVEYCSV.js.map → chunk-QQB4FO4Q.js.map} +1 -1
- package/dist/{generators-YZWIGHCO.js → chunk-S2GXR5HY.js} +26 -9
- package/dist/chunk-S2GXR5HY.js.map +1 -0
- package/dist/{chunk-O2OHHBUD.js → chunk-TDK7DLCH.js} +30 -20
- package/dist/chunk-TDK7DLCH.js.map +1 -0
- package/dist/{chunk-QP5NCO2E.js → chunk-VDI7KYME.js} +67 -2
- package/dist/chunk-VDI7KYME.js.map +1 -0
- package/dist/chunk-VOR53RUR.js +753 -0
- package/dist/chunk-VOR53RUR.js.map +1 -0
- package/dist/{chunk-GAJLEDRD.js → chunk-ZKJ7JKFV.js} +16 -7
- package/dist/chunk-ZKJ7JKFV.js.map +1 -0
- package/dist/chunk-ZSMWDLMK.js +63 -0
- package/dist/{chunk-EQCVQC35.js.map → chunk-ZSMWDLMK.js.map} +1 -1
- package/dist/cli/index.js +37269 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/index.mjs +37233 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/commerce/index.js +1 -1
- package/dist/commerce/index.mjs +1 -1
- package/dist/commerce/server.d.mts +12 -3
- package/dist/commerce/server.d.ts +12 -3
- package/dist/commerce/server.js +71 -70
- package/dist/commerce/server.js.map +1 -1
- package/dist/commerce/server.mjs +71 -70
- package/dist/commerce/server.mjs.map +1 -1
- package/dist/engage/index.d.mts +6 -4
- package/dist/engage/index.d.ts +6 -4
- package/dist/engage/index.js +8 -4
- package/dist/engage/index.mjs +2 -2
- package/dist/forms/index.js +1 -1
- package/dist/forms/index.mjs +1 -1
- package/dist/generators-5EU4PTVF.js +33 -0
- package/dist/generators-5EU4PTVF.js.map +1 -0
- package/dist/generators-TYPILCWD.mjs +4 -0
- package/dist/generators-TYPILCWD.mjs.map +1 -0
- package/dist/images/index.js +11 -11
- package/dist/images/index.mjs +4 -4
- package/dist/index.d.mts +154 -5
- package/dist/index.d.ts +154 -5
- package/dist/index.js +940 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +819 -7
- package/dist/index.mjs.map +1 -1
- package/dist/llms/index.d.mts +657 -0
- package/dist/llms/index.d.ts +657 -0
- package/dist/llms/index.js +101 -0
- package/dist/llms/index.js.map +1 -0
- package/dist/llms/index.mjs +4 -0
- package/dist/llms/index.mjs.map +1 -0
- package/dist/migrator-ARLHUNB3.mjs +4 -0
- package/dist/migrator-ARLHUNB3.mjs.map +1 -0
- package/dist/migrator-VZLBH3VY.js +37 -0
- package/dist/migrator-VZLBH3VY.js.map +1 -0
- package/dist/redirects/index.js +1 -1
- package/dist/redirects/index.mjs +1 -1
- package/dist/reputation/index.js +1 -1
- package/dist/reputation/index.mjs +1 -1
- package/dist/{routing-BWjUF7lp.d.ts → routing-CF91y6NO.d.ts} +1 -1
- package/dist/{routing-CgmRi9tD.d.mts → routing-CIOFpFCB.d.mts} +1 -1
- package/dist/scanner-7ZMUM2P5.mjs +4 -0
- package/dist/scanner-7ZMUM2P5.mjs.map +1 -0
- package/dist/scanner-OY7UF3WA.js +53 -0
- package/dist/scanner-OY7UF3WA.js.map +1 -0
- package/dist/seo/index.d.mts +267 -7
- package/dist/seo/index.d.ts +267 -7
- package/dist/seo/index.js +432 -24
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +400 -11
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo/server.d.mts +11 -4
- package/dist/seo/server.d.ts +11 -4
- package/dist/seo/server.js +17 -17
- package/dist/seo/server.mjs +3 -3
- package/dist/setup/client.js +1 -1
- package/dist/setup/client.mjs +1 -1
- package/dist/setup/index.js +3 -3
- package/dist/setup/index.mjs +2 -2
- package/dist/setup/server.js +3 -3
- package/dist/setup/server.mjs +2 -2
- package/dist/sitemap/index.js +2 -2
- package/dist/sitemap/index.js.map +1 -1
- package/dist/sitemap/index.mjs +2 -2
- package/dist/sitemap/index.mjs.map +1 -1
- package/dist/{types-C0pJGfbH.d.mts → types-D6FHAVWX.d.mts} +99 -3
- package/dist/{types-C0pJGfbH.d.ts → types-D6FHAVWX.d.ts} +99 -3
- package/dist/{types-BN4OwtCO.d.mts → types-DI0jnhjJ.d.mts} +2 -0
- package/dist/{types-BN4OwtCO.d.ts → types-DI0jnhjJ.d.ts} +2 -0
- package/dist/{types-BmzutFwy.d.ts → types-j8X4vUhB.d.mts} +19 -2
- package/dist/{types-BmzutFwy.d.mts → types-j8X4vUhB.d.ts} +19 -2
- package/dist/{web-vitals-BH55V7EJ.js → web-vitals-444RLW3B.js} +11 -11
- package/dist/{web-vitals-BH55V7EJ.js.map → web-vitals-444RLW3B.js.map} +1 -1
- package/dist/{web-vitals-RJYPWAR3.mjs → web-vitals-KPICZIEF.mjs} +3 -3
- package/dist/{web-vitals-RJYPWAR3.mjs.map → web-vitals-KPICZIEF.mjs.map} +1 -1
- package/package.json +9 -2
- package/dist/api-N35S3EES.js +0 -57
- package/dist/api-N35S3EES.js.map +0 -1
- package/dist/api-SYBTK7Z7.mjs +0 -4
- package/dist/api-SYBTK7Z7.mjs.map +0 -1
- package/dist/chunk-2IHTEKHU.mjs.map +0 -1
- package/dist/chunk-7H6I3ECV.mjs.map +0 -1
- package/dist/chunk-BGJLOJ7T.mjs +0 -605
- package/dist/chunk-BGJLOJ7T.mjs.map +0 -1
- package/dist/chunk-EQCVQC35.js +0 -35
- package/dist/chunk-FKVJOT2F.mjs.map +0 -1
- package/dist/chunk-GAJLEDRD.js.map +0 -1
- package/dist/chunk-NYKRE2FL.mjs +0 -31
- package/dist/chunk-O2OHHBUD.js.map +0 -1
- package/dist/chunk-QAYJV4KK.js +0 -608
- package/dist/chunk-QAYJV4KK.js.map +0 -1
- package/dist/chunk-QP5NCO2E.js.map +0 -1
- package/dist/chunk-V3F5J6CV.js.map +0 -1
- package/dist/chunk-XQJX252G.mjs.map +0 -1
- package/dist/generators-TO2FKJR6.mjs.map +0 -1
- package/dist/generators-YZWIGHCO.js.map +0 -1
- package/dist/migrator-V6KS75EA.mjs +0 -265
- package/dist/migrator-V6KS75EA.mjs.map +0 -1
- package/dist/migrator-XKM7YQCY.js +0 -272
- package/dist/migrator-XKM7YQCY.js.map +0 -1
- package/dist/scanner-AZV5I6US.mjs.map +0 -1
- package/dist/scanner-ETJAMIT7.js.map +0 -1
package/dist/commerce/index.js
CHANGED
package/dist/commerce/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { CalendarView, CheckoutForm, EventCalendar, EventEmbed, EventModal, EventTile, EventsWidget, OfferingCard, OfferingList, ProductDetail, ProductEmbed, ProductGrid, ProductPage, RegistrationForm, UpcomingEvents, createCheckoutSession, fetchCategories, fetchLatestOffering, fetchNextEvent, fetchOffering, fetchOfferings, fetchProductBySlug, fetchProducts, fetchProductsPublic, fetchServices, fetchUpcomingEvents, formatDate, formatDateRange, formatDateTime, formatPrice, formatTime, getOfferingUrl, getRelativeTimeUntil, getSpotsRemaining, isEventSoldOut, registerForEvent, useEventModal } from '../chunk-DOHML47I.mjs';
|
|
2
|
-
import '../chunk-
|
|
2
|
+
import '../chunk-4XPGGLVP.mjs';
|
|
3
3
|
//# sourceMappingURL=index.mjs.map
|
|
4
4
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -5,11 +5,13 @@ import { O as OfferingType, C as CommerceOffering } from '../types-nB206tPK.mjs'
|
|
|
5
5
|
*
|
|
6
6
|
* Helpers for server-side rendering and dynamic routes.
|
|
7
7
|
* Use in Next.js getStaticPaths, getStaticProps, or App Router.
|
|
8
|
+
*
|
|
9
|
+
* All data fetching goes through the Portal API.
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
12
|
interface ServerConfig {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
apiUrl: string;
|
|
14
|
+
apiKey: string;
|
|
13
15
|
projectId: string;
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
@@ -93,6 +95,13 @@ declare function generateOfferingMetadata(offering: CommerceOffering | null, sit
|
|
|
93
95
|
url: string;
|
|
94
96
|
};
|
|
95
97
|
} | null;
|
|
96
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Create a server config for API calls
|
|
100
|
+
*
|
|
101
|
+
* @param apiUrl - Portal API URL (e.g., 'https://api.uptrademedia.com')
|
|
102
|
+
* @param apiKey - Project API key
|
|
103
|
+
* @param projectId - Project ID
|
|
104
|
+
*/
|
|
105
|
+
declare function createServerConfig(apiUrl: string, apiKey: string, projectId: string): ServerConfig;
|
|
97
106
|
|
|
98
107
|
export { createServerConfig, generateOfferingMetadata, getEventPaths, getNextEvent, getOfferingBySlug, getOfferingPaths, getOfferings, getProductPaths, getUpcomingEvents };
|
|
@@ -5,11 +5,13 @@ import { O as OfferingType, C as CommerceOffering } from '../types-nB206tPK.js';
|
|
|
5
5
|
*
|
|
6
6
|
* Helpers for server-side rendering and dynamic routes.
|
|
7
7
|
* Use in Next.js getStaticPaths, getStaticProps, or App Router.
|
|
8
|
+
*
|
|
9
|
+
* All data fetching goes through the Portal API.
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
12
|
interface ServerConfig {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
apiUrl: string;
|
|
14
|
+
apiKey: string;
|
|
13
15
|
projectId: string;
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
@@ -93,6 +95,13 @@ declare function generateOfferingMetadata(offering: CommerceOffering | null, sit
|
|
|
93
95
|
url: string;
|
|
94
96
|
};
|
|
95
97
|
} | null;
|
|
96
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Create a server config for API calls
|
|
100
|
+
*
|
|
101
|
+
* @param apiUrl - Portal API URL (e.g., 'https://api.uptrademedia.com')
|
|
102
|
+
* @param apiKey - Project API key
|
|
103
|
+
* @param projectId - Project ID
|
|
104
|
+
*/
|
|
105
|
+
declare function createServerConfig(apiUrl: string, apiKey: string, projectId: string): ServerConfig;
|
|
97
106
|
|
|
98
107
|
export { createServerConfig, generateOfferingMetadata, getEventPaths, getNextEvent, getOfferingBySlug, getOfferingPaths, getOfferings, getProductPaths, getUpcomingEvents };
|
package/dist/commerce/server.js
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
require('../chunk-
|
|
4
|
-
var supabaseJs = require('@supabase/supabase-js');
|
|
3
|
+
require('../chunk-ZSMWDLMK.js');
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
// src/commerce/server.ts
|
|
6
|
+
async function apiFetch(config, endpoint) {
|
|
7
|
+
try {
|
|
8
|
+
const response = await fetch(`${config.apiUrl}${endpoint}`, {
|
|
9
|
+
headers: {
|
|
10
|
+
"X-API-Key": config.apiKey,
|
|
11
|
+
"X-Project-ID": config.projectId,
|
|
12
|
+
"Content-Type": "application/json"
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok) return null;
|
|
16
|
+
return response.json();
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.error("API fetch error:", error);
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
8
21
|
}
|
|
9
22
|
function transformOffering(data) {
|
|
10
23
|
return {
|
|
@@ -19,7 +32,7 @@ function transformOffering(data) {
|
|
|
19
32
|
long_description: data.long_description,
|
|
20
33
|
featured_image_url: data.featured_image_url,
|
|
21
34
|
gallery_images: data.gallery_image_urls || [],
|
|
22
|
-
price_type: data.price_type,
|
|
35
|
+
price_type: data.price_type || "fixed",
|
|
23
36
|
price: data.price,
|
|
24
37
|
compare_at_price: data.compare_at_price,
|
|
25
38
|
currency: data.currency || "USD",
|
|
@@ -49,97 +62,85 @@ function transformOffering(data) {
|
|
|
49
62
|
};
|
|
50
63
|
}
|
|
51
64
|
async function getProductPaths(config) {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
const data = await apiFetch(
|
|
66
|
+
config,
|
|
67
|
+
`/public/commerce/offerings?type=product&status=active&fields=slug`
|
|
68
|
+
);
|
|
69
|
+
if (!data?.offerings) return [];
|
|
70
|
+
return data.offerings.map((item) => ({ params: { slug: item.slug } }));
|
|
56
71
|
}
|
|
57
72
|
async function getEventPaths(config) {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
73
|
+
const data = await apiFetch(
|
|
74
|
+
config,
|
|
75
|
+
`/public/commerce/offerings?type=event&status=active&fields=slug`
|
|
76
|
+
);
|
|
77
|
+
if (!data?.offerings) return [];
|
|
78
|
+
return data.offerings.map((item) => ({ params: { slug: item.slug } }));
|
|
62
79
|
}
|
|
63
80
|
async function getOfferingPaths(config, type) {
|
|
64
|
-
|
|
65
|
-
let query = supabase.from("commerce_offerings").select("slug").eq("project_id", config.projectId).eq("status", "active");
|
|
81
|
+
let typeParam = "";
|
|
66
82
|
if (type) {
|
|
67
83
|
if (Array.isArray(type)) {
|
|
68
|
-
|
|
84
|
+
typeParam = `&type=${type.join(",")}`;
|
|
69
85
|
} else {
|
|
70
|
-
|
|
86
|
+
typeParam = `&type=${type}`;
|
|
71
87
|
}
|
|
72
88
|
}
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
89
|
+
const data = await apiFetch(
|
|
90
|
+
config,
|
|
91
|
+
`/public/commerce/offerings?status=active&fields=slug${typeParam}`
|
|
92
|
+
);
|
|
93
|
+
if (!data?.offerings) return [];
|
|
94
|
+
return data.offerings.map((item) => ({ params: { slug: item.slug } }));
|
|
76
95
|
}
|
|
77
96
|
async function getOfferingBySlug(config, slug) {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
`).eq("project_id", config.projectId).eq("slug", slug).single();
|
|
85
|
-
if (error || !data) return null;
|
|
86
|
-
return transformOffering(data);
|
|
97
|
+
const data = await apiFetch(
|
|
98
|
+
config,
|
|
99
|
+
`/public/commerce/offerings/${slug}`
|
|
100
|
+
);
|
|
101
|
+
if (!data?.offering) return null;
|
|
102
|
+
return transformOffering(data.offering);
|
|
87
103
|
}
|
|
88
104
|
async function getOfferings(config, options = {}) {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
*,
|
|
92
|
-
category:commerce_categories(id, name, slug),
|
|
93
|
-
variants:commerce_variants(*),
|
|
94
|
-
schedules:commerce_schedules(*)
|
|
95
|
-
`).eq("project_id", config.projectId).eq("status", options.status || "active").order("sort_order", { ascending: true });
|
|
105
|
+
const params = new URLSearchParams();
|
|
106
|
+
params.set("status", options.status || "active");
|
|
96
107
|
if (options.type) {
|
|
97
108
|
if (Array.isArray(options.type)) {
|
|
98
|
-
|
|
109
|
+
params.set("type", options.type.join(","));
|
|
99
110
|
} else {
|
|
100
|
-
|
|
111
|
+
params.set("type", options.type);
|
|
101
112
|
}
|
|
102
113
|
}
|
|
103
114
|
if (options.category) {
|
|
104
|
-
|
|
115
|
+
params.set("category", options.category);
|
|
105
116
|
}
|
|
106
117
|
if (options.limit) {
|
|
107
|
-
|
|
118
|
+
params.set("limit", options.limit.toString());
|
|
108
119
|
}
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
const data = await apiFetch(
|
|
121
|
+
config,
|
|
122
|
+
`/public/commerce/offerings?${params.toString()}`
|
|
123
|
+
);
|
|
124
|
+
if (!data?.offerings) return [];
|
|
125
|
+
return data.offerings.map(transformOffering);
|
|
112
126
|
}
|
|
113
127
|
async function getUpcomingEvents(config, options = {}) {
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
category:commerce_categories(id, name, slug),
|
|
119
|
-
schedules:commerce_schedules(*)
|
|
120
|
-
`).eq("project_id", config.projectId).eq("type", "event").eq("status", "active");
|
|
128
|
+
const params = new URLSearchParams();
|
|
129
|
+
params.set("type", "event");
|
|
130
|
+
params.set("status", "active");
|
|
131
|
+
params.set("upcoming", "true");
|
|
121
132
|
if (options.category) {
|
|
122
|
-
|
|
133
|
+
params.set("category", options.category);
|
|
123
134
|
}
|
|
124
|
-
const { data, error } = await query;
|
|
125
|
-
if (error || !data) return [];
|
|
126
|
-
const eventsWithSchedules = data.map((event) => {
|
|
127
|
-
const schedules = (event.schedules || []).filter((s) => new Date(s.starts_at) >= new Date(now) && s.status === "scheduled").sort((a, b) => new Date(a.starts_at).getTime() - new Date(b.starts_at).getTime());
|
|
128
|
-
return {
|
|
129
|
-
...transformOffering(event),
|
|
130
|
-
schedules,
|
|
131
|
-
next_schedule: schedules[0] || null
|
|
132
|
-
};
|
|
133
|
-
}).filter((event) => event.schedules.length > 0).sort((a, b) => {
|
|
134
|
-
const aDate = a.next_schedule?.starts_at;
|
|
135
|
-
const bDate = b.next_schedule?.starts_at;
|
|
136
|
-
if (!aDate || !bDate) return 0;
|
|
137
|
-
return new Date(aDate).getTime() - new Date(bDate).getTime();
|
|
138
|
-
});
|
|
139
135
|
if (options.limit) {
|
|
140
|
-
|
|
136
|
+
params.set("limit", options.limit.toString());
|
|
141
137
|
}
|
|
142
|
-
|
|
138
|
+
const data = await apiFetch(
|
|
139
|
+
config,
|
|
140
|
+
`/public/commerce/offerings?${params.toString()}`
|
|
141
|
+
);
|
|
142
|
+
if (!data?.offerings) return [];
|
|
143
|
+
return data.offerings.map(transformOffering);
|
|
143
144
|
}
|
|
144
145
|
async function getNextEvent(config, category) {
|
|
145
146
|
const events = await getUpcomingEvents(config, { limit: 1, category });
|
|
@@ -169,8 +170,8 @@ function generateOfferingMetadata(offering, siteUrl) {
|
|
|
169
170
|
}
|
|
170
171
|
};
|
|
171
172
|
}
|
|
172
|
-
function createServerConfig(
|
|
173
|
-
return {
|
|
173
|
+
function createServerConfig(apiUrl, apiKey, projectId) {
|
|
174
|
+
return { apiUrl, apiKey, projectId };
|
|
174
175
|
}
|
|
175
176
|
|
|
176
177
|
exports.createServerConfig = createServerConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commerce/server.ts"],"names":["createClient"],"mappings":"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","file":"server.js","sourcesContent":["/**\n * @uptrade/site-kit/commerce - Server-side utilities\n * \n * Helpers for server-side rendering and dynamic routes.\n * Use in Next.js getStaticPaths, getStaticProps, or App Router.\n */\n\nimport { createClient } from '@supabase/supabase-js'\nimport type { CommerceOffering, OfferingType } from './types'\n\ninterface ServerConfig {\n supabaseUrl: string\n supabaseKey: string\n projectId: string\n}\n\nfunction getSupabaseClient(config: ServerConfig) {\n return createClient(config.supabaseUrl, config.supabaseKey)\n}\n\nfunction transformOffering(data: any): CommerceOffering {\n return {\n id: data.id,\n project_id: data.project_id,\n type: data.type,\n status: data.status,\n name: data.name,\n slug: data.slug,\n description: data.description,\n short_description: data.short_description,\n long_description: data.long_description,\n featured_image_url: data.featured_image_url,\n gallery_images: data.gallery_image_urls || [],\n price_type: data.price_type,\n price: data.price,\n compare_at_price: data.compare_at_price,\n currency: data.currency || 'USD',\n price_is_public: data.price_is_public ?? true,\n billing_period: data.billing_period,\n track_inventory: data.track_inventory,\n inventory_count: data.inventory_count,\n allow_backorder: data.allow_backorder,\n duration_minutes: data.duration_minutes,\n capacity: data.capacity,\n location: data.location,\n is_virtual: data.is_virtual,\n virtual_meeting_url: data.virtual_meeting_url,\n requires_booking: data.requires_booking,\n booking_lead_time_hours: data.booking_lead_time_hours,\n category: data.category,\n category_id: data.category_id,\n tags: data.tags || [],\n seo_title: data.seo_title,\n seo_description: data.seo_description,\n features: data.features || [],\n specifications: data.specifications || {},\n schedules: data.schedules || [],\n variants: data.variants || [],\n created_at: data.created_at,\n updated_at: data.updated_at,\n }\n}\n\n// ============================================\n// Static Path Generators\n// ============================================\n\n/**\n * Get all product slugs for static generation\n * \n * @example Next.js Pages Router\n * export async function getStaticPaths() {\n * const paths = await getProductPaths(config)\n * return { paths, fallback: 'blocking' }\n * }\n */\nexport async function getProductPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const supabase = getSupabaseClient(config)\n \n const { data, error } = await supabase\n .from('commerce_offerings')\n .select('slug')\n .eq('project_id', config.projectId)\n .eq('type', 'product')\n .eq('status', 'active')\n \n if (error || !data) return []\n \n return data.map(item => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all event slugs for static generation\n */\nexport async function getEventPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const supabase = getSupabaseClient(config)\n \n const { data, error } = await supabase\n .from('commerce_offerings')\n .select('slug')\n .eq('project_id', config.projectId)\n .eq('type', 'event')\n .eq('status', 'active')\n \n if (error || !data) return []\n \n return data.map(item => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all offering slugs for static generation (any type)\n */\nexport async function getOfferingPaths(\n config: ServerConfig,\n type?: OfferingType | OfferingType[]\n): Promise<{ params: { slug: string } }[]> {\n const supabase = getSupabaseClient(config)\n \n let query = supabase\n .from('commerce_offerings')\n .select('slug')\n .eq('project_id', config.projectId)\n .eq('status', 'active')\n \n if (type) {\n if (Array.isArray(type)) {\n query = query.in('type', type)\n } else {\n query = query.eq('type', type)\n }\n }\n \n const { data, error } = await query\n \n if (error || !data) return []\n \n return data.map(item => ({ params: { slug: item.slug } }))\n}\n\n// ============================================\n// Data Fetchers\n// ============================================\n\n/**\n * Fetch a single offering by slug (server-side)\n * \n * @example Next.js Pages Router\n * export async function getStaticProps({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * if (!product) return { notFound: true }\n * return { props: { product }, revalidate: 60 }\n * }\n */\nexport async function getOfferingBySlug(\n config: ServerConfig,\n slug: string\n): Promise<CommerceOffering | null> {\n const supabase = getSupabaseClient(config)\n \n const { data, error } = await supabase\n .from('commerce_offerings')\n .select(`\n *,\n category:commerce_categories(id, name, slug),\n variants:commerce_variants(*),\n schedules:commerce_schedules(*)\n `)\n .eq('project_id', config.projectId)\n .eq('slug', slug)\n .single()\n \n if (error || !data) return null\n \n return transformOffering(data)\n}\n\n/**\n * Fetch all offerings of a type (server-side)\n */\nexport async function getOfferings(\n config: ServerConfig,\n options: {\n type?: OfferingType | OfferingType[]\n category?: string\n limit?: number\n status?: string\n } = {}\n): Promise<CommerceOffering[]> {\n const supabase = getSupabaseClient(config)\n \n let query = supabase\n .from('commerce_offerings')\n .select(`\n *,\n category:commerce_categories(id, name, slug),\n variants:commerce_variants(*),\n schedules:commerce_schedules(*)\n `)\n .eq('project_id', config.projectId)\n .eq('status', options.status || 'active')\n .order('sort_order', { ascending: true })\n \n if (options.type) {\n if (Array.isArray(options.type)) {\n query = query.in('type', options.type)\n } else {\n query = query.eq('type', options.type)\n }\n }\n \n if (options.category) {\n query = query.eq('category_id', options.category)\n }\n \n if (options.limit) {\n query = query.limit(options.limit)\n }\n \n const { data, error } = await query\n \n if (error || !data) return []\n \n return data.map(transformOffering)\n}\n\n/**\n * Fetch upcoming events (server-side)\n */\nexport async function getUpcomingEvents(\n config: ServerConfig,\n options: { limit?: number; category?: string } = {}\n): Promise<CommerceOffering[]> {\n const supabase = getSupabaseClient(config)\n const now = new Date().toISOString()\n \n let query = supabase\n .from('commerce_offerings')\n .select(`\n *,\n category:commerce_categories(id, name, slug),\n schedules:commerce_schedules(*)\n `)\n .eq('project_id', config.projectId)\n .eq('type', 'event')\n .eq('status', 'active')\n \n if (options.category) {\n query = query.eq('category_id', options.category)\n }\n \n const { data, error } = await query\n \n if (error || !data) return []\n \n // Filter events with upcoming schedules and sort\n const eventsWithSchedules = data\n .map(event => {\n const schedules = (event.schedules || [])\n .filter((s: any) => new Date(s.starts_at) >= new Date(now) && s.status === 'scheduled')\n .sort((a: any, b: any) => new Date(a.starts_at).getTime() - new Date(b.starts_at).getTime())\n \n return {\n ...transformOffering(event),\n schedules,\n next_schedule: schedules[0] || null,\n }\n })\n .filter(event => event.schedules.length > 0)\n .sort((a, b) => {\n const aDate = (a as any).next_schedule?.starts_at\n const bDate = (b as any).next_schedule?.starts_at\n if (!aDate || !bDate) return 0\n return new Date(aDate).getTime() - new Date(bDate).getTime()\n })\n \n if (options.limit) {\n return eventsWithSchedules.slice(0, options.limit)\n }\n \n return eventsWithSchedules\n}\n\n/**\n * Get next upcoming event (server-side)\n */\nexport async function getNextEvent(\n config: ServerConfig,\n category?: string\n): Promise<CommerceOffering | null> {\n const events = await getUpcomingEvents(config, { limit: 1, category })\n return events[0] || null\n}\n\n// ============================================\n// Metadata Helpers\n// ============================================\n\n/**\n * Generate page metadata for an offering\n * \n * @example Next.js App Router\n * export async function generateMetadata({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * return generateOfferingMetadata(product, 'https://example.com')\n * }\n */\nexport function generateOfferingMetadata(\n offering: CommerceOffering | null,\n siteUrl: string\n): {\n title: string\n description: string\n openGraph: {\n title: string\n description: string\n images: string[]\n type: string\n url: string\n }\n} | null {\n if (!offering) return null\n \n const title = offering.seo_title || offering.name\n const description = offering.seo_description || offering.short_description || offering.description || ''\n const images = offering.featured_image_url ? [offering.featured_image_url] : []\n \n const typeMap: Record<OfferingType, string> = {\n product: 'product',\n service: 'website',\n event: 'website',\n class: 'website',\n subscription: 'product',\n }\n \n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images,\n type: typeMap[offering.type] || 'website',\n url: `${siteUrl}/${offering.type}s/${offering.slug}`,\n },\n }\n}\n\n// ============================================\n// Export config builder\n// ============================================\n\nexport function createServerConfig(\n supabaseUrl: string,\n supabaseKey: string,\n projectId: string\n): ServerConfig {\n return { supabaseUrl, supabaseKey, projectId }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/commerce/server.ts"],"names":[],"mappings":";;;;;AAqBA,eAAe,QAAA,CAAY,QAAsB,QAAA,EAAqC;AACpF,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,OAAO,MAAM,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI;AAAA,MAC1D,OAAA,EAAS;AAAA,QACP,aAAa,MAAA,CAAO,MAAA;AAAA,QACpB,gBAAgB,MAAA,CAAO,SAAA;AAAA,QACvB,cAAA,EAAgB;AAAA;AAClB,KACD,CAAA;AAED,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,IAAA;AACzB,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,oBAAoB,KAAK,CAAA;AACvC,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,kBAAkB,IAAA,EAAiD;AAC1E,EAAA,OAAO;AAAA,IACL,IAAI,IAAA,CAAK,EAAA;AAAA,IACT,YAAY,IAAA,CAAK,UAAA;AAAA,IACjB,MAAM,IAAA,CAAK,IAAA;AAAA,IACX,QAAQ,IAAA,CAAK,MAAA;AAAA,IACb,MAAM,IAAA,CAAK,IAAA;AAAA,IACX,MAAM,IAAA,CAAK,IAAA;AAAA,IACX,aAAa,IAAA,CAAK,WAAA;AAAA,IAClB,mBAAmB,IAAA,CAAK,iBAAA;AAAA,IACxB,kBAAkB,IAAA,CAAK,gBAAA;AAAA,IACvB,oBAAoB,IAAA,CAAK,kBAAA;AAAA,IACzB,cAAA,EAAiB,IAAA,CAAK,kBAAA,IAAmC,EAAC;AAAA,IAC1D,UAAA,EAAa,KAAK,UAAA,IAA0D,OAAA;AAAA,IAC5E,OAAO,IAAA,CAAK,KAAA;AAAA,IACZ,kBAAkB,IAAA,CAAK,gBAAA;AAAA,IACvB,QAAA,EAAW,KAAK,QAAA,IAAuB,KAAA;AAAA,IACvC,eAAA,EAAkB,KAAK,eAAA,IAA+B,IAAA;AAAA,IACtD,gBAAgB,IAAA,CAAK,cAAA;AAAA,IACrB,iBAAiB,IAAA,CAAK,eAAA;AAAA,IACtB,iBAAiB,IAAA,CAAK,eAAA;AAAA,IACtB,iBAAiB,IAAA,CAAK,eAAA;AAAA,IACtB,kBAAkB,IAAA,CAAK,gBAAA;AAAA,IACvB,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,YAAY,IAAA,CAAK,UAAA;AAAA,IACjB,qBAAqB,IAAA,CAAK,mBAAA;AAAA,IAC1B,kBAAkB,IAAA,CAAK,gBAAA;AAAA,IACvB,yBAAyB,IAAA,CAAK,uBAAA;AAAA,IAC9B,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,aAAa,IAAA,CAAK,WAAA;AAAA,IAClB,IAAA,EAAO,IAAA,CAAK,IAAA,IAAqB,EAAC;AAAA,IAClC,WAAW,IAAA,CAAK,SAAA;AAAA,IAChB,iBAAiB,IAAA,CAAK,eAAA;AAAA,IACtB,QAAA,EAAW,IAAA,CAAK,QAAA,IAAyB,EAAC;AAAA,IAC1C,cAAA,EAAiB,IAAA,CAAK,cAAA,IAA6C,EAAC;AAAA,IACpE,SAAA,EAAY,IAAA,CAAK,SAAA,IAA+C,EAAC;AAAA,IACjE,QAAA,EAAW,IAAA,CAAK,QAAA,IAA6C,EAAC;AAAA,IAC9D,YAAY,IAAA,CAAK,UAAA;AAAA,IACjB,YAAY,IAAA,CAAK;AAAA,GACnB;AACF;AAeA,eAAsB,gBAAgB,MAAA,EAA+D;AACnG,EAAA,MAAM,OAAO,MAAM,QAAA;AAAA,IACjB,MAAA;AAAA,IACA,CAAA,iEAAA;AAAA,GACF;AAEA,EAAA,IAAI,CAAC,IAAA,EAAM,SAAA,EAAW,OAAO,EAAC;AAE9B,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,CAAC,IAAA,MAAoB,EAAE,MAAA,EAAQ,EAAE,IAAA,EAAM,IAAA,CAAK,IAAA,EAAK,EAAE,CAAE,CAAA;AACjF;AAKA,eAAsB,cAAc,MAAA,EAA+D;AACjG,EAAA,MAAM,OAAO,MAAM,QAAA;AAAA,IACjB,MAAA;AAAA,IACA,CAAA,+DAAA;AAAA,GACF;AAEA,EAAA,IAAI,CAAC,IAAA,EAAM,SAAA,EAAW,OAAO,EAAC;AAE9B,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,CAAC,IAAA,MAAoB,EAAE,MAAA,EAAQ,EAAE,IAAA,EAAM,IAAA,CAAK,IAAA,EAAK,EAAE,CAAE,CAAA;AACjF;AAKA,eAAsB,gBAAA,CACpB,QACA,IAAA,EACyC;AACzC,EAAA,IAAI,SAAA,GAAY,EAAA;AAChB,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,EAAG;AACvB,MAAA,SAAA,GAAY,CAAA,MAAA,EAAS,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AAAA,IACrC,CAAA,MAAO;AACL,MAAA,SAAA,GAAY,SAAS,IAAI,CAAA,CAAA;AAAA,IAC3B;AAAA,EACF;AAEA,EAAA,MAAM,OAAO,MAAM,QAAA;AAAA,IACjB,MAAA;AAAA,IACA,uDAAuD,SAAS,CAAA;AAAA,GAClE;AAEA,EAAA,IAAI,CAAC,IAAA,EAAM,SAAA,EAAW,OAAO,EAAC;AAE9B,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,CAAC,IAAA,MAAoB,EAAE,MAAA,EAAQ,EAAE,IAAA,EAAM,IAAA,CAAK,IAAA,EAAK,EAAE,CAAE,CAAA;AACjF;AAgBA,eAAsB,iBAAA,CACpB,QACA,IAAA,EACkC;AAClC,EAAA,MAAM,OAAO,MAAM,QAAA;AAAA,IACjB,MAAA;AAAA,IACA,8BAA8B,IAAI,CAAA;AAAA,GACpC;AAEA,EAAA,IAAI,CAAC,IAAA,EAAM,QAAA,EAAU,OAAO,IAAA;AAE5B,EAAA,OAAO,iBAAA,CAAkB,KAAK,QAAQ,CAAA;AACxC;AAKA,eAAsB,YAAA,CACpB,MAAA,EACA,OAAA,GAKI,EAAC,EACwB;AAC7B,EAAA,MAAM,MAAA,GAAS,IAAI,eAAA,EAAgB;AACnC,EAAA,MAAA,CAAO,GAAA,CAAI,QAAA,EAAU,OAAA,CAAQ,MAAA,IAAU,QAAQ,CAAA;AAE/C,EAAA,IAAI,QAAQ,IAAA,EAAM;AAChB,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAA,EAAG;AAC/B,MAAA,MAAA,CAAO,IAAI,MAAA,EAAQ,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,IAC3C,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,GAAA,CAAI,MAAA,EAAQ,OAAA,CAAQ,IAAI,CAAA;AAAA,IACjC;AAAA,EACF;AAEA,EAAA,IAAI,QAAQ,QAAA,EAAU;AACpB,IAAA,MAAA,CAAO,GAAA,CAAI,UAAA,EAAY,OAAA,CAAQ,QAAQ,CAAA;AAAA,EACzC;AAEA,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,MAAA,CAAO,GAAA,CAAI,OAAA,EAAS,OAAA,CAAQ,KAAA,CAAM,UAAU,CAAA;AAAA,EAC9C;AAEA,EAAA,MAAM,OAAO,MAAM,QAAA;AAAA,IACjB,MAAA;AAAA,IACA,CAAA,2BAAA,EAA8B,MAAA,CAAO,QAAA,EAAU,CAAA;AAAA,GACjD;AAEA,EAAA,IAAI,CAAC,IAAA,EAAM,SAAA,EAAW,OAAO,EAAC;AAE9B,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,iBAAiB,CAAA;AAC7C;AAKA,eAAsB,iBAAA,CACpB,MAAA,EACA,OAAA,GAAiD,EAAC,EACrB;AAC7B,EAAA,MAAM,MAAA,GAAS,IAAI,eAAA,EAAgB;AACnC,EAAA,MAAA,CAAO,GAAA,CAAI,QAAQ,OAAO,CAAA;AAC1B,EAAA,MAAA,CAAO,GAAA,CAAI,UAAU,QAAQ,CAAA;AAC7B,EAAA,MAAA,CAAO,GAAA,CAAI,YAAY,MAAM,CAAA;AAE7B,EAAA,IAAI,QAAQ,QAAA,EAAU;AACpB,IAAA,MAAA,CAAO,GAAA,CAAI,UAAA,EAAY,OAAA,CAAQ,QAAQ,CAAA;AAAA,EACzC;AAEA,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,MAAA,CAAO,GAAA,CAAI,OAAA,EAAS,OAAA,CAAQ,KAAA,CAAM,UAAU,CAAA;AAAA,EAC9C;AAEA,EAAA,MAAM,OAAO,MAAM,QAAA;AAAA,IACjB,MAAA;AAAA,IACA,CAAA,2BAAA,EAA8B,MAAA,CAAO,QAAA,EAAU,CAAA;AAAA,GACjD;AAEA,EAAA,IAAI,CAAC,IAAA,EAAM,SAAA,EAAW,OAAO,EAAC;AAE9B,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,iBAAiB,CAAA;AAC7C;AAKA,eAAsB,YAAA,CACpB,QACA,QAAA,EACkC;AAClC,EAAA,MAAM,MAAA,GAAS,MAAM,iBAAA,CAAkB,MAAA,EAAQ,EAAE,KAAA,EAAO,CAAA,EAAG,UAAU,CAAA;AACrE,EAAA,OAAO,MAAA,CAAO,CAAC,CAAA,IAAK,IAAA;AACtB;AAeO,SAAS,wBAAA,CACd,UACA,OAAA,EAWO;AACP,EAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AAEtB,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,SAAA,IAAa,QAAA,CAAS,IAAA;AAC7C,EAAA,MAAM,cAAc,QAAA,CAAS,eAAA,IAAmB,QAAA,CAAS,iBAAA,IAAqB,SAAS,WAAA,IAAe,EAAA;AACtG,EAAA,MAAM,SAAS,QAAA,CAAS,kBAAA,GAAqB,CAAC,QAAA,CAAS,kBAAkB,IAAI,EAAC;AAE9E,EAAA,MAAM,OAAA,GAAwC;AAAA,IAC5C,OAAA,EAAS,SAAA;AAAA,IACT,OAAA,EAAS,SAAA;AAAA,IACT,KAAA,EAAO,SAAA;AAAA,IACP,KAAA,EAAO,SAAA;AAAA,IACP,YAAA,EAAc;AAAA,GAChB;AAEA,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA,EAAW;AAAA,MACT,KAAA;AAAA,MACA,WAAA;AAAA,MACA,MAAA;AAAA,MACA,IAAA,EAAM,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA,IAAK,SAAA;AAAA,MAChC,GAAA,EAAK,GAAG,OAAO,CAAA,CAAA,EAAI,SAAS,IAAI,CAAA,EAAA,EAAK,SAAS,IAAI,CAAA;AAAA;AACpD,GACF;AACF;AAaO,SAAS,kBAAA,CACd,MAAA,EACA,MAAA,EACA,SAAA,EACc;AACd,EAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,SAAA,EAAU;AACrC","file":"server.js","sourcesContent":["/**\n * @uptrade/site-kit/commerce - Server-side utilities\n * \n * Helpers for server-side rendering and dynamic routes.\n * Use in Next.js getStaticPaths, getStaticProps, or App Router.\n * \n * All data fetching goes through the Portal API.\n */\n\nimport type { CommerceOffering, OfferingType } from './types'\n\ninterface ServerConfig {\n apiUrl: string\n apiKey: string\n projectId: string\n}\n\ninterface SlugItem {\n slug: string\n}\n\nasync function apiFetch<T>(config: ServerConfig, endpoint: string): Promise<T | null> {\n try {\n const response = await fetch(`${config.apiUrl}${endpoint}`, {\n headers: {\n 'X-API-Key': config.apiKey,\n 'X-Project-ID': config.projectId,\n 'Content-Type': 'application/json',\n },\n })\n \n if (!response.ok) return null\n return response.json()\n } catch (error) {\n console.error('API fetch error:', error)\n return null\n }\n}\n\nfunction transformOffering(data: Record<string, unknown>): CommerceOffering {\n return {\n id: data.id as string,\n project_id: data.project_id as string,\n type: data.type as OfferingType,\n status: data.status as 'draft' | 'active' | 'archived' | 'sold_out',\n name: data.name as string,\n slug: data.slug as string,\n description: data.description as string | undefined,\n short_description: data.short_description as string | undefined,\n long_description: data.long_description as string | undefined,\n featured_image_url: data.featured_image_url as string | undefined,\n gallery_images: (data.gallery_image_urls as string[]) || [],\n price_type: (data.price_type as 'fixed' | 'variable' | 'quote' | 'free') || 'fixed',\n price: data.price as number | undefined,\n compare_at_price: data.compare_at_price as number | undefined,\n currency: (data.currency as string) || 'USD',\n price_is_public: (data.price_is_public as boolean) ?? true,\n billing_period: data.billing_period as 'weekly' | 'monthly' | 'quarterly' | 'yearly' | undefined,\n track_inventory: data.track_inventory as boolean | undefined,\n inventory_count: data.inventory_count as number | undefined,\n allow_backorder: data.allow_backorder as boolean | undefined,\n duration_minutes: data.duration_minutes as number | undefined,\n capacity: data.capacity as number | undefined,\n location: data.location as string | undefined,\n is_virtual: data.is_virtual as boolean | undefined,\n virtual_meeting_url: data.virtual_meeting_url as string | undefined,\n requires_booking: data.requires_booking as boolean | undefined,\n booking_lead_time_hours: data.booking_lead_time_hours as number | undefined,\n category: data.category as CommerceOffering['category'],\n category_id: data.category_id as string | undefined,\n tags: (data.tags as string[]) || [],\n seo_title: data.seo_title as string | undefined,\n seo_description: data.seo_description as string | undefined,\n features: (data.features as string[]) || [],\n specifications: (data.specifications as Record<string, string>) || {},\n schedules: (data.schedules as CommerceOffering['schedules']) || [],\n variants: (data.variants as CommerceOffering['variants']) || [],\n created_at: data.created_at as string,\n updated_at: data.updated_at as string,\n }\n}\n\n// ============================================\n// Static Path Generators\n// ============================================\n\n/**\n * Get all product slugs for static generation\n * \n * @example Next.js Pages Router\n * export async function getStaticPaths() {\n * const paths = await getProductPaths(config)\n * return { paths, fallback: 'blocking' }\n * }\n */\nexport async function getProductPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=product&status=active&fields=slug`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all event slugs for static generation\n */\nexport async function getEventPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=event&status=active&fields=slug`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all offering slugs for static generation (any type)\n */\nexport async function getOfferingPaths(\n config: ServerConfig,\n type?: OfferingType | OfferingType[]\n): Promise<{ params: { slug: string } }[]> {\n let typeParam = ''\n if (type) {\n if (Array.isArray(type)) {\n typeParam = `&type=${type.join(',')}`\n } else {\n typeParam = `&type=${type}`\n }\n }\n \n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?status=active&fields=slug${typeParam}`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n// ============================================\n// Data Fetchers\n// ============================================\n\n/**\n * Fetch a single offering by slug (server-side)\n * \n * @example Next.js Pages Router\n * export async function getStaticProps({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * if (!product) return { notFound: true }\n * return { props: { product }, revalidate: 60 }\n * }\n */\nexport async function getOfferingBySlug(\n config: ServerConfig,\n slug: string\n): Promise<CommerceOffering | null> {\n const data = await apiFetch<{ offering: Record<string, unknown> }>(\n config,\n `/public/commerce/offerings/${slug}`\n )\n \n if (!data?.offering) return null\n \n return transformOffering(data.offering)\n}\n\n/**\n * Fetch all offerings of a type (server-side)\n */\nexport async function getOfferings(\n config: ServerConfig,\n options: {\n type?: OfferingType | OfferingType[]\n category?: string\n limit?: number\n status?: string\n } = {}\n): Promise<CommerceOffering[]> {\n const params = new URLSearchParams()\n params.set('status', options.status || 'active')\n \n if (options.type) {\n if (Array.isArray(options.type)) {\n params.set('type', options.type.join(','))\n } else {\n params.set('type', options.type)\n }\n }\n \n if (options.category) {\n params.set('category', options.category)\n }\n \n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n \n const data = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map(transformOffering)\n}\n\n/**\n * Fetch upcoming events (server-side)\n */\nexport async function getUpcomingEvents(\n config: ServerConfig,\n options: { limit?: number; category?: string } = {}\n): Promise<CommerceOffering[]> {\n const params = new URLSearchParams()\n params.set('type', 'event')\n params.set('status', 'active')\n params.set('upcoming', 'true')\n \n if (options.category) {\n params.set('category', options.category)\n }\n \n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n \n const data = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map(transformOffering)\n}\n\n/**\n * Get next upcoming event (server-side)\n */\nexport async function getNextEvent(\n config: ServerConfig,\n category?: string\n): Promise<CommerceOffering | null> {\n const events = await getUpcomingEvents(config, { limit: 1, category })\n return events[0] || null\n}\n\n// ============================================\n// Metadata Helpers\n// ============================================\n\n/**\n * Generate page metadata for an offering\n * \n * @example Next.js App Router\n * export async function generateMetadata({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * return generateOfferingMetadata(product, 'https://example.com')\n * }\n */\nexport function generateOfferingMetadata(\n offering: CommerceOffering | null,\n siteUrl: string\n): {\n title: string\n description: string\n openGraph: {\n title: string\n description: string\n images: string[]\n type: string\n url: string\n }\n} | null {\n if (!offering) return null\n \n const title = offering.seo_title || offering.name\n const description = offering.seo_description || offering.short_description || offering.description || ''\n const images = offering.featured_image_url ? [offering.featured_image_url] : []\n \n const typeMap: Record<OfferingType, string> = {\n product: 'product',\n service: 'website',\n event: 'website',\n class: 'website',\n subscription: 'product',\n }\n \n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images,\n type: typeMap[offering.type] || 'website',\n url: `${siteUrl}/${offering.type}s/${offering.slug}`,\n },\n }\n}\n\n// ============================================\n// Export config builder\n// ============================================\n\n/**\n * Create a server config for API calls\n * \n * @param apiUrl - Portal API URL (e.g., 'https://api.uptrademedia.com')\n * @param apiKey - Project API key\n * @param projectId - Project ID\n */\nexport function createServerConfig(\n apiUrl: string,\n apiKey: string,\n projectId: string\n): ServerConfig {\n return { apiUrl, apiKey, projectId }\n}\n"]}
|
package/dist/commerce/server.mjs
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
|
-
import '../chunk-
|
|
2
|
-
import { createClient } from '@supabase/supabase-js';
|
|
1
|
+
import '../chunk-4XPGGLVP.mjs';
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
// src/commerce/server.ts
|
|
4
|
+
async function apiFetch(config, endpoint) {
|
|
5
|
+
try {
|
|
6
|
+
const response = await fetch(`${config.apiUrl}${endpoint}`, {
|
|
7
|
+
headers: {
|
|
8
|
+
"X-API-Key": config.apiKey,
|
|
9
|
+
"X-Project-ID": config.projectId,
|
|
10
|
+
"Content-Type": "application/json"
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
if (!response.ok) return null;
|
|
14
|
+
return response.json();
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error("API fetch error:", error);
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
6
19
|
}
|
|
7
20
|
function transformOffering(data) {
|
|
8
21
|
return {
|
|
@@ -17,7 +30,7 @@ function transformOffering(data) {
|
|
|
17
30
|
long_description: data.long_description,
|
|
18
31
|
featured_image_url: data.featured_image_url,
|
|
19
32
|
gallery_images: data.gallery_image_urls || [],
|
|
20
|
-
price_type: data.price_type,
|
|
33
|
+
price_type: data.price_type || "fixed",
|
|
21
34
|
price: data.price,
|
|
22
35
|
compare_at_price: data.compare_at_price,
|
|
23
36
|
currency: data.currency || "USD",
|
|
@@ -47,97 +60,85 @@ function transformOffering(data) {
|
|
|
47
60
|
};
|
|
48
61
|
}
|
|
49
62
|
async function getProductPaths(config) {
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
63
|
+
const data = await apiFetch(
|
|
64
|
+
config,
|
|
65
|
+
`/public/commerce/offerings?type=product&status=active&fields=slug`
|
|
66
|
+
);
|
|
67
|
+
if (!data?.offerings) return [];
|
|
68
|
+
return data.offerings.map((item) => ({ params: { slug: item.slug } }));
|
|
54
69
|
}
|
|
55
70
|
async function getEventPaths(config) {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
71
|
+
const data = await apiFetch(
|
|
72
|
+
config,
|
|
73
|
+
`/public/commerce/offerings?type=event&status=active&fields=slug`
|
|
74
|
+
);
|
|
75
|
+
if (!data?.offerings) return [];
|
|
76
|
+
return data.offerings.map((item) => ({ params: { slug: item.slug } }));
|
|
60
77
|
}
|
|
61
78
|
async function getOfferingPaths(config, type) {
|
|
62
|
-
|
|
63
|
-
let query = supabase.from("commerce_offerings").select("slug").eq("project_id", config.projectId).eq("status", "active");
|
|
79
|
+
let typeParam = "";
|
|
64
80
|
if (type) {
|
|
65
81
|
if (Array.isArray(type)) {
|
|
66
|
-
|
|
82
|
+
typeParam = `&type=${type.join(",")}`;
|
|
67
83
|
} else {
|
|
68
|
-
|
|
84
|
+
typeParam = `&type=${type}`;
|
|
69
85
|
}
|
|
70
86
|
}
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
const data = await apiFetch(
|
|
88
|
+
config,
|
|
89
|
+
`/public/commerce/offerings?status=active&fields=slug${typeParam}`
|
|
90
|
+
);
|
|
91
|
+
if (!data?.offerings) return [];
|
|
92
|
+
return data.offerings.map((item) => ({ params: { slug: item.slug } }));
|
|
74
93
|
}
|
|
75
94
|
async function getOfferingBySlug(config, slug) {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
`).eq("project_id", config.projectId).eq("slug", slug).single();
|
|
83
|
-
if (error || !data) return null;
|
|
84
|
-
return transformOffering(data);
|
|
95
|
+
const data = await apiFetch(
|
|
96
|
+
config,
|
|
97
|
+
`/public/commerce/offerings/${slug}`
|
|
98
|
+
);
|
|
99
|
+
if (!data?.offering) return null;
|
|
100
|
+
return transformOffering(data.offering);
|
|
85
101
|
}
|
|
86
102
|
async function getOfferings(config, options = {}) {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
*,
|
|
90
|
-
category:commerce_categories(id, name, slug),
|
|
91
|
-
variants:commerce_variants(*),
|
|
92
|
-
schedules:commerce_schedules(*)
|
|
93
|
-
`).eq("project_id", config.projectId).eq("status", options.status || "active").order("sort_order", { ascending: true });
|
|
103
|
+
const params = new URLSearchParams();
|
|
104
|
+
params.set("status", options.status || "active");
|
|
94
105
|
if (options.type) {
|
|
95
106
|
if (Array.isArray(options.type)) {
|
|
96
|
-
|
|
107
|
+
params.set("type", options.type.join(","));
|
|
97
108
|
} else {
|
|
98
|
-
|
|
109
|
+
params.set("type", options.type);
|
|
99
110
|
}
|
|
100
111
|
}
|
|
101
112
|
if (options.category) {
|
|
102
|
-
|
|
113
|
+
params.set("category", options.category);
|
|
103
114
|
}
|
|
104
115
|
if (options.limit) {
|
|
105
|
-
|
|
116
|
+
params.set("limit", options.limit.toString());
|
|
106
117
|
}
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
118
|
+
const data = await apiFetch(
|
|
119
|
+
config,
|
|
120
|
+
`/public/commerce/offerings?${params.toString()}`
|
|
121
|
+
);
|
|
122
|
+
if (!data?.offerings) return [];
|
|
123
|
+
return data.offerings.map(transformOffering);
|
|
110
124
|
}
|
|
111
125
|
async function getUpcomingEvents(config, options = {}) {
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
category:commerce_categories(id, name, slug),
|
|
117
|
-
schedules:commerce_schedules(*)
|
|
118
|
-
`).eq("project_id", config.projectId).eq("type", "event").eq("status", "active");
|
|
126
|
+
const params = new URLSearchParams();
|
|
127
|
+
params.set("type", "event");
|
|
128
|
+
params.set("status", "active");
|
|
129
|
+
params.set("upcoming", "true");
|
|
119
130
|
if (options.category) {
|
|
120
|
-
|
|
131
|
+
params.set("category", options.category);
|
|
121
132
|
}
|
|
122
|
-
const { data, error } = await query;
|
|
123
|
-
if (error || !data) return [];
|
|
124
|
-
const eventsWithSchedules = data.map((event) => {
|
|
125
|
-
const schedules = (event.schedules || []).filter((s) => new Date(s.starts_at) >= new Date(now) && s.status === "scheduled").sort((a, b) => new Date(a.starts_at).getTime() - new Date(b.starts_at).getTime());
|
|
126
|
-
return {
|
|
127
|
-
...transformOffering(event),
|
|
128
|
-
schedules,
|
|
129
|
-
next_schedule: schedules[0] || null
|
|
130
|
-
};
|
|
131
|
-
}).filter((event) => event.schedules.length > 0).sort((a, b) => {
|
|
132
|
-
const aDate = a.next_schedule?.starts_at;
|
|
133
|
-
const bDate = b.next_schedule?.starts_at;
|
|
134
|
-
if (!aDate || !bDate) return 0;
|
|
135
|
-
return new Date(aDate).getTime() - new Date(bDate).getTime();
|
|
136
|
-
});
|
|
137
133
|
if (options.limit) {
|
|
138
|
-
|
|
134
|
+
params.set("limit", options.limit.toString());
|
|
139
135
|
}
|
|
140
|
-
|
|
136
|
+
const data = await apiFetch(
|
|
137
|
+
config,
|
|
138
|
+
`/public/commerce/offerings?${params.toString()}`
|
|
139
|
+
);
|
|
140
|
+
if (!data?.offerings) return [];
|
|
141
|
+
return data.offerings.map(transformOffering);
|
|
141
142
|
}
|
|
142
143
|
async function getNextEvent(config, category) {
|
|
143
144
|
const events = await getUpcomingEvents(config, { limit: 1, category });
|
|
@@ -167,8 +168,8 @@ function generateOfferingMetadata(offering, siteUrl) {
|
|
|
167
168
|
}
|
|
168
169
|
};
|
|
169
170
|
}
|
|
170
|
-
function createServerConfig(
|
|
171
|
-
return {
|
|
171
|
+
function createServerConfig(apiUrl, apiKey, projectId) {
|
|
172
|
+
return { apiUrl, apiKey, projectId };
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
export { createServerConfig, generateOfferingMetadata, getEventPaths, getNextEvent, getOfferingBySlug, getOfferingPaths, getOfferings, getProductPaths, getUpcomingEvents };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commerce/server.ts"],"names":[],"mappings":"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","file":"server.mjs","sourcesContent":["/**\n * @uptrade/site-kit/commerce - Server-side utilities\n * \n * Helpers for server-side rendering and dynamic routes.\n * Use in Next.js getStaticPaths, getStaticProps, or App Router.\n */\n\nimport { createClient } from '@supabase/supabase-js'\nimport type { CommerceOffering, OfferingType } from './types'\n\ninterface ServerConfig {\n supabaseUrl: string\n supabaseKey: string\n projectId: string\n}\n\nfunction getSupabaseClient(config: ServerConfig) {\n return createClient(config.supabaseUrl, config.supabaseKey)\n}\n\nfunction transformOffering(data: any): CommerceOffering {\n return {\n id: data.id,\n project_id: data.project_id,\n type: data.type,\n status: data.status,\n name: data.name,\n slug: data.slug,\n description: data.description,\n short_description: data.short_description,\n long_description: data.long_description,\n featured_image_url: data.featured_image_url,\n gallery_images: data.gallery_image_urls || [],\n price_type: data.price_type,\n price: data.price,\n compare_at_price: data.compare_at_price,\n currency: data.currency || 'USD',\n price_is_public: data.price_is_public ?? true,\n billing_period: data.billing_period,\n track_inventory: data.track_inventory,\n inventory_count: data.inventory_count,\n allow_backorder: data.allow_backorder,\n duration_minutes: data.duration_minutes,\n capacity: data.capacity,\n location: data.location,\n is_virtual: data.is_virtual,\n virtual_meeting_url: data.virtual_meeting_url,\n requires_booking: data.requires_booking,\n booking_lead_time_hours: data.booking_lead_time_hours,\n category: data.category,\n category_id: data.category_id,\n tags: data.tags || [],\n seo_title: data.seo_title,\n seo_description: data.seo_description,\n features: data.features || [],\n specifications: data.specifications || {},\n schedules: data.schedules || [],\n variants: data.variants || [],\n created_at: data.created_at,\n updated_at: data.updated_at,\n }\n}\n\n// ============================================\n// Static Path Generators\n// ============================================\n\n/**\n * Get all product slugs for static generation\n * \n * @example Next.js Pages Router\n * export async function getStaticPaths() {\n * const paths = await getProductPaths(config)\n * return { paths, fallback: 'blocking' }\n * }\n */\nexport async function getProductPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const supabase = getSupabaseClient(config)\n \n const { data, error } = await supabase\n .from('commerce_offerings')\n .select('slug')\n .eq('project_id', config.projectId)\n .eq('type', 'product')\n .eq('status', 'active')\n \n if (error || !data) return []\n \n return data.map(item => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all event slugs for static generation\n */\nexport async function getEventPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const supabase = getSupabaseClient(config)\n \n const { data, error } = await supabase\n .from('commerce_offerings')\n .select('slug')\n .eq('project_id', config.projectId)\n .eq('type', 'event')\n .eq('status', 'active')\n \n if (error || !data) return []\n \n return data.map(item => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all offering slugs for static generation (any type)\n */\nexport async function getOfferingPaths(\n config: ServerConfig,\n type?: OfferingType | OfferingType[]\n): Promise<{ params: { slug: string } }[]> {\n const supabase = getSupabaseClient(config)\n \n let query = supabase\n .from('commerce_offerings')\n .select('slug')\n .eq('project_id', config.projectId)\n .eq('status', 'active')\n \n if (type) {\n if (Array.isArray(type)) {\n query = query.in('type', type)\n } else {\n query = query.eq('type', type)\n }\n }\n \n const { data, error } = await query\n \n if (error || !data) return []\n \n return data.map(item => ({ params: { slug: item.slug } }))\n}\n\n// ============================================\n// Data Fetchers\n// ============================================\n\n/**\n * Fetch a single offering by slug (server-side)\n * \n * @example Next.js Pages Router\n * export async function getStaticProps({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * if (!product) return { notFound: true }\n * return { props: { product }, revalidate: 60 }\n * }\n */\nexport async function getOfferingBySlug(\n config: ServerConfig,\n slug: string\n): Promise<CommerceOffering | null> {\n const supabase = getSupabaseClient(config)\n \n const { data, error } = await supabase\n .from('commerce_offerings')\n .select(`\n *,\n category:commerce_categories(id, name, slug),\n variants:commerce_variants(*),\n schedules:commerce_schedules(*)\n `)\n .eq('project_id', config.projectId)\n .eq('slug', slug)\n .single()\n \n if (error || !data) return null\n \n return transformOffering(data)\n}\n\n/**\n * Fetch all offerings of a type (server-side)\n */\nexport async function getOfferings(\n config: ServerConfig,\n options: {\n type?: OfferingType | OfferingType[]\n category?: string\n limit?: number\n status?: string\n } = {}\n): Promise<CommerceOffering[]> {\n const supabase = getSupabaseClient(config)\n \n let query = supabase\n .from('commerce_offerings')\n .select(`\n *,\n category:commerce_categories(id, name, slug),\n variants:commerce_variants(*),\n schedules:commerce_schedules(*)\n `)\n .eq('project_id', config.projectId)\n .eq('status', options.status || 'active')\n .order('sort_order', { ascending: true })\n \n if (options.type) {\n if (Array.isArray(options.type)) {\n query = query.in('type', options.type)\n } else {\n query = query.eq('type', options.type)\n }\n }\n \n if (options.category) {\n query = query.eq('category_id', options.category)\n }\n \n if (options.limit) {\n query = query.limit(options.limit)\n }\n \n const { data, error } = await query\n \n if (error || !data) return []\n \n return data.map(transformOffering)\n}\n\n/**\n * Fetch upcoming events (server-side)\n */\nexport async function getUpcomingEvents(\n config: ServerConfig,\n options: { limit?: number; category?: string } = {}\n): Promise<CommerceOffering[]> {\n const supabase = getSupabaseClient(config)\n const now = new Date().toISOString()\n \n let query = supabase\n .from('commerce_offerings')\n .select(`\n *,\n category:commerce_categories(id, name, slug),\n schedules:commerce_schedules(*)\n `)\n .eq('project_id', config.projectId)\n .eq('type', 'event')\n .eq('status', 'active')\n \n if (options.category) {\n query = query.eq('category_id', options.category)\n }\n \n const { data, error } = await query\n \n if (error || !data) return []\n \n // Filter events with upcoming schedules and sort\n const eventsWithSchedules = data\n .map(event => {\n const schedules = (event.schedules || [])\n .filter((s: any) => new Date(s.starts_at) >= new Date(now) && s.status === 'scheduled')\n .sort((a: any, b: any) => new Date(a.starts_at).getTime() - new Date(b.starts_at).getTime())\n \n return {\n ...transformOffering(event),\n schedules,\n next_schedule: schedules[0] || null,\n }\n })\n .filter(event => event.schedules.length > 0)\n .sort((a, b) => {\n const aDate = (a as any).next_schedule?.starts_at\n const bDate = (b as any).next_schedule?.starts_at\n if (!aDate || !bDate) return 0\n return new Date(aDate).getTime() - new Date(bDate).getTime()\n })\n \n if (options.limit) {\n return eventsWithSchedules.slice(0, options.limit)\n }\n \n return eventsWithSchedules\n}\n\n/**\n * Get next upcoming event (server-side)\n */\nexport async function getNextEvent(\n config: ServerConfig,\n category?: string\n): Promise<CommerceOffering | null> {\n const events = await getUpcomingEvents(config, { limit: 1, category })\n return events[0] || null\n}\n\n// ============================================\n// Metadata Helpers\n// ============================================\n\n/**\n * Generate page metadata for an offering\n * \n * @example Next.js App Router\n * export async function generateMetadata({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * return generateOfferingMetadata(product, 'https://example.com')\n * }\n */\nexport function generateOfferingMetadata(\n offering: CommerceOffering | null,\n siteUrl: string\n): {\n title: string\n description: string\n openGraph: {\n title: string\n description: string\n images: string[]\n type: string\n url: string\n }\n} | null {\n if (!offering) return null\n \n const title = offering.seo_title || offering.name\n const description = offering.seo_description || offering.short_description || offering.description || ''\n const images = offering.featured_image_url ? [offering.featured_image_url] : []\n \n const typeMap: Record<OfferingType, string> = {\n product: 'product',\n service: 'website',\n event: 'website',\n class: 'website',\n subscription: 'product',\n }\n \n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images,\n type: typeMap[offering.type] || 'website',\n url: `${siteUrl}/${offering.type}s/${offering.slug}`,\n },\n }\n}\n\n// ============================================\n// Export config builder\n// ============================================\n\nexport function createServerConfig(\n supabaseUrl: string,\n supabaseKey: string,\n projectId: string\n): ServerConfig {\n return { supabaseUrl, supabaseKey, projectId }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/commerce/server.ts"],"names":[],"mappings":"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","file":"server.mjs","sourcesContent":["/**\n * @uptrade/site-kit/commerce - Server-side utilities\n * \n * Helpers for server-side rendering and dynamic routes.\n * Use in Next.js getStaticPaths, getStaticProps, or App Router.\n * \n * All data fetching goes through the Portal API.\n */\n\nimport type { CommerceOffering, OfferingType } from './types'\n\ninterface ServerConfig {\n apiUrl: string\n apiKey: string\n projectId: string\n}\n\ninterface SlugItem {\n slug: string\n}\n\nasync function apiFetch<T>(config: ServerConfig, endpoint: string): Promise<T | null> {\n try {\n const response = await fetch(`${config.apiUrl}${endpoint}`, {\n headers: {\n 'X-API-Key': config.apiKey,\n 'X-Project-ID': config.projectId,\n 'Content-Type': 'application/json',\n },\n })\n \n if (!response.ok) return null\n return response.json()\n } catch (error) {\n console.error('API fetch error:', error)\n return null\n }\n}\n\nfunction transformOffering(data: Record<string, unknown>): CommerceOffering {\n return {\n id: data.id as string,\n project_id: data.project_id as string,\n type: data.type as OfferingType,\n status: data.status as 'draft' | 'active' | 'archived' | 'sold_out',\n name: data.name as string,\n slug: data.slug as string,\n description: data.description as string | undefined,\n short_description: data.short_description as string | undefined,\n long_description: data.long_description as string | undefined,\n featured_image_url: data.featured_image_url as string | undefined,\n gallery_images: (data.gallery_image_urls as string[]) || [],\n price_type: (data.price_type as 'fixed' | 'variable' | 'quote' | 'free') || 'fixed',\n price: data.price as number | undefined,\n compare_at_price: data.compare_at_price as number | undefined,\n currency: (data.currency as string) || 'USD',\n price_is_public: (data.price_is_public as boolean) ?? true,\n billing_period: data.billing_period as 'weekly' | 'monthly' | 'quarterly' | 'yearly' | undefined,\n track_inventory: data.track_inventory as boolean | undefined,\n inventory_count: data.inventory_count as number | undefined,\n allow_backorder: data.allow_backorder as boolean | undefined,\n duration_minutes: data.duration_minutes as number | undefined,\n capacity: data.capacity as number | undefined,\n location: data.location as string | undefined,\n is_virtual: data.is_virtual as boolean | undefined,\n virtual_meeting_url: data.virtual_meeting_url as string | undefined,\n requires_booking: data.requires_booking as boolean | undefined,\n booking_lead_time_hours: data.booking_lead_time_hours as number | undefined,\n category: data.category as CommerceOffering['category'],\n category_id: data.category_id as string | undefined,\n tags: (data.tags as string[]) || [],\n seo_title: data.seo_title as string | undefined,\n seo_description: data.seo_description as string | undefined,\n features: (data.features as string[]) || [],\n specifications: (data.specifications as Record<string, string>) || {},\n schedules: (data.schedules as CommerceOffering['schedules']) || [],\n variants: (data.variants as CommerceOffering['variants']) || [],\n created_at: data.created_at as string,\n updated_at: data.updated_at as string,\n }\n}\n\n// ============================================\n// Static Path Generators\n// ============================================\n\n/**\n * Get all product slugs for static generation\n * \n * @example Next.js Pages Router\n * export async function getStaticPaths() {\n * const paths = await getProductPaths(config)\n * return { paths, fallback: 'blocking' }\n * }\n */\nexport async function getProductPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=product&status=active&fields=slug`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all event slugs for static generation\n */\nexport async function getEventPaths(config: ServerConfig): Promise<{ params: { slug: string } }[]> {\n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?type=event&status=active&fields=slug`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n/**\n * Get all offering slugs for static generation (any type)\n */\nexport async function getOfferingPaths(\n config: ServerConfig,\n type?: OfferingType | OfferingType[]\n): Promise<{ params: { slug: string } }[]> {\n let typeParam = ''\n if (type) {\n if (Array.isArray(type)) {\n typeParam = `&type=${type.join(',')}`\n } else {\n typeParam = `&type=${type}`\n }\n }\n \n const data = await apiFetch<{ offerings: SlugItem[] }>(\n config,\n `/public/commerce/offerings?status=active&fields=slug${typeParam}`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map((item: SlugItem) => ({ params: { slug: item.slug } }))\n}\n\n// ============================================\n// Data Fetchers\n// ============================================\n\n/**\n * Fetch a single offering by slug (server-side)\n * \n * @example Next.js Pages Router\n * export async function getStaticProps({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * if (!product) return { notFound: true }\n * return { props: { product }, revalidate: 60 }\n * }\n */\nexport async function getOfferingBySlug(\n config: ServerConfig,\n slug: string\n): Promise<CommerceOffering | null> {\n const data = await apiFetch<{ offering: Record<string, unknown> }>(\n config,\n `/public/commerce/offerings/${slug}`\n )\n \n if (!data?.offering) return null\n \n return transformOffering(data.offering)\n}\n\n/**\n * Fetch all offerings of a type (server-side)\n */\nexport async function getOfferings(\n config: ServerConfig,\n options: {\n type?: OfferingType | OfferingType[]\n category?: string\n limit?: number\n status?: string\n } = {}\n): Promise<CommerceOffering[]> {\n const params = new URLSearchParams()\n params.set('status', options.status || 'active')\n \n if (options.type) {\n if (Array.isArray(options.type)) {\n params.set('type', options.type.join(','))\n } else {\n params.set('type', options.type)\n }\n }\n \n if (options.category) {\n params.set('category', options.category)\n }\n \n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n \n const data = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map(transformOffering)\n}\n\n/**\n * Fetch upcoming events (server-side)\n */\nexport async function getUpcomingEvents(\n config: ServerConfig,\n options: { limit?: number; category?: string } = {}\n): Promise<CommerceOffering[]> {\n const params = new URLSearchParams()\n params.set('type', 'event')\n params.set('status', 'active')\n params.set('upcoming', 'true')\n \n if (options.category) {\n params.set('category', options.category)\n }\n \n if (options.limit) {\n params.set('limit', options.limit.toString())\n }\n \n const data = await apiFetch<{ offerings: Record<string, unknown>[] }>(\n config,\n `/public/commerce/offerings?${params.toString()}`\n )\n \n if (!data?.offerings) return []\n \n return data.offerings.map(transformOffering)\n}\n\n/**\n * Get next upcoming event (server-side)\n */\nexport async function getNextEvent(\n config: ServerConfig,\n category?: string\n): Promise<CommerceOffering | null> {\n const events = await getUpcomingEvents(config, { limit: 1, category })\n return events[0] || null\n}\n\n// ============================================\n// Metadata Helpers\n// ============================================\n\n/**\n * Generate page metadata for an offering\n * \n * @example Next.js App Router\n * export async function generateMetadata({ params }) {\n * const product = await getOfferingBySlug(config, params.slug)\n * return generateOfferingMetadata(product, 'https://example.com')\n * }\n */\nexport function generateOfferingMetadata(\n offering: CommerceOffering | null,\n siteUrl: string\n): {\n title: string\n description: string\n openGraph: {\n title: string\n description: string\n images: string[]\n type: string\n url: string\n }\n} | null {\n if (!offering) return null\n \n const title = offering.seo_title || offering.name\n const description = offering.seo_description || offering.short_description || offering.description || ''\n const images = offering.featured_image_url ? [offering.featured_image_url] : []\n \n const typeMap: Record<OfferingType, string> = {\n product: 'product',\n service: 'website',\n event: 'website',\n class: 'website',\n subscription: 'product',\n }\n \n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images,\n type: typeMap[offering.type] || 'website',\n url: `${siteUrl}/${offering.type}s/${offering.slug}`,\n },\n }\n}\n\n// ============================================\n// Export config builder\n// ============================================\n\n/**\n * Create a server config for API calls\n * \n * @param apiUrl - Portal API URL (e.g., 'https://api.uptrademedia.com')\n * @param apiKey - Project API key\n * @param projectId - Project ID\n */\nexport function createServerConfig(\n apiUrl: string,\n apiKey: string,\n projectId: string\n): ServerConfig {\n return { apiUrl, apiKey, projectId }\n}\n"]}
|