first commit
Some checks failed
Deploy Production / deploy (push) Has been cancelled

This commit is contained in:
Frank John Begornia
2026-01-12 22:16:36 +08:00
commit 3ba0b250ed
44 changed files with 18635 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
import Stripe from "stripe";
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig();
const stripeSecretKey = config.stripeSecretKey;
if (!stripeSecretKey) {
throw createError({
statusCode: 500,
statusMessage: "Stripe secret key not configured",
});
}
const stripe = new Stripe(stripeSecretKey, {
apiVersion: "2025-10-29.clover",
});
const body = await readBody<{
designId: string;
templateId?: string;
designName?: string;
amount: number;
currency?: string;
successUrl: string;
cancelUrl: string;
customerEmail?: string;
}>(event);
if (
!body?.designId ||
!body?.amount ||
!body?.successUrl ||
!body?.cancelUrl
) {
throw createError({
statusCode: 400,
statusMessage: "Missing required fields",
});
}
const { currency = "usd" } = body;
const session = await stripe.checkout.sessions.create({
mode: "payment",
payment_method_types: ["card"],
billing_address_collection: "auto",
customer_email: body.customerEmail,
shipping_address_collection: { allowed_countries: ["US", "CA"] },
line_items: [
{
quantity: 1,
price_data: {
currency,
unit_amount: Math.round(body.amount * 100),
product_data: {
name: body.designName ?? `Slipmat design ${body.designId}`,
metadata: {
designId: body.designId,
...(body.templateId ? { templateId: body.templateId } : {}),
},
},
},
},
],
metadata: {
designId: body.designId,
...(body.templateId ? { templateId: body.templateId } : {}),
},
success_url: body.successUrl,
cancel_url: body.cancelUrl,
});
return { id: session.id, url: session.url };
});

View File

@@ -0,0 +1,62 @@
import Stripe from 'stripe'
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig()
const stripeSecretKey = config.stripeSecretKey
if (!stripeSecretKey) {
throw createError({ statusCode: 500, statusMessage: 'Stripe secret key not configured' })
}
const params = event.context.params as { sessionId?: string }
const sessionId = params?.sessionId
if (!sessionId) {
throw createError({ statusCode: 400, statusMessage: 'Missing session id' })
}
const stripe = new Stripe(stripeSecretKey, {
apiVersion: '2025-10-29.clover',
})
try {
const session = await stripe.checkout.sessions.retrieve(sessionId, {
expand: ['payment_intent', 'customer'],
})
const customerDetails = session.customer_details ?? null
return {
id: session.id,
paymentStatus: session.payment_status,
amountTotal: session.amount_total,
currency: session.currency,
customerEmail: customerDetails?.email ?? session.customer_email ?? null,
customerName: customerDetails?.name ?? null,
createdAt: session.created ? new Date(session.created * 1000).toISOString() : null,
metadata: session.metadata ?? {},
customerDetails: customerDetails
? {
name: customerDetails.name ?? null,
email: customerDetails.email ?? null,
phone: customerDetails.phone ?? null,
address: customerDetails.address
? {
line1: customerDetails.address.line1 ?? null,
line2: customerDetails.address.line2 ?? null,
city: customerDetails.address.city ?? null,
state: customerDetails.address.state ?? null,
postalCode: customerDetails.address.postal_code ?? null,
country: customerDetails.address.country ?? null,
}
: null,
}
: null,
}
} catch (error: any) {
throw createError({
statusCode: error?.statusCode ?? 500,
statusMessage: error?.message ?? 'Unable to retrieve checkout session',
})
}
})

View File

@@ -0,0 +1,63 @@
export default defineEventHandler(async (event) => {
const body = await readBody<{
designId: string;
templateId: string;
ownerEmail?: string | null;
ownerId?: string | null;
previewUrl?: string | null;
productionUrl?: string | null;
canvasJson: unknown;
metadata?: Record<string, unknown>;
}>(event);
if (!body?.designId || !body?.templateId || body.canvasJson === undefined) {
throw createError({
statusCode: 400,
statusMessage: "Missing required design fields",
});
}
const config = useRuntimeConfig();
const backendUrl = config.public?.backendUrl;
if (!backendUrl) {
throw createError({
statusCode: 500,
statusMessage: "Backend URL not configured",
});
}
// Extract the authorization token from the incoming request
const authHeader = getHeader(event, "authorization");
const payload = {
designId: body.designId,
templateId: body.templateId,
ownerEmail: body.ownerEmail ?? null,
ownerId: body.ownerId ?? null,
previewUrl: body.previewUrl ?? null,
productionUrl: body.productionUrl ?? null,
canvasJson: body.canvasJson,
metadata: body.metadata ?? {},
};
try {
const result = await $fetch("/designs", {
baseURL: backendUrl,
method: "POST",
headers: authHeader ? { Authorization: authHeader } : {},
body: payload,
});
return {
ok: true,
result,
};
} catch (err) {
console.error("[designs] Failed to forward design payload", err);
throw createError({
statusCode: 502,
statusMessage: (err as Error)?.message ?? "Failed to persist design",
});
}
});

View File

@@ -0,0 +1,30 @@
export default defineEventHandler(async (event) => {
const params = event.context.params as { designId?: string }
const designId = params?.designId
if (!designId) {
throw createError({ statusCode: 400, statusMessage: "Missing design id" })
}
const config = useRuntimeConfig()
const backendUrl = config.public?.backendUrl
if (!backendUrl) {
throw createError({ statusCode: 500, statusMessage: "Backend URL not configured" })
}
try {
const design = await $fetch(`/designs/${encodeURIComponent(designId)}`, {
baseURL: backendUrl,
method: "GET",
})
return design
} catch (err) {
console.error(`[designs] Failed to fetch design ${designId}`, err)
throw createError({
statusCode: 502,
statusMessage: (err as Error)?.message ?? "Failed to load design",
})
}
})

43
server/api/orders.get.ts Normal file
View File

@@ -0,0 +1,43 @@
export default defineEventHandler(async (event) => {
const config = useRuntimeConfig();
const backendUrl = config.public?.backendUrl;
if (!backendUrl) {
throw createError({ statusCode: 500, statusMessage: "Backend URL not configured" });
}
const query = getQuery(event);
const customerEmail = typeof query.customerEmail === "string" ? query.customerEmail : null;
if (!customerEmail) {
throw createError({ statusCode: 400, statusMessage: "Missing customerEmail" });
}
try {
const result = await $fetch("/transactions", {
baseURL: backendUrl,
method: "GET",
query: { customerEmail },
});
if (Array.isArray(result)) {
return result;
}
if (result && Array.isArray((result as any).data)) {
return (result as any).data;
}
if (result && Array.isArray((result as any).orders)) {
return (result as any).orders;
}
return result;
} catch (err) {
console.error("[orders] Failed to fetch order history", err);
throw createError({
statusCode: 502,
statusMessage: (err as Error)?.message ?? "Failed to load order history",
});
}
});

View File

@@ -0,0 +1,73 @@
export default defineEventHandler(async (event) => {
const body = await readBody<{
stripeSessionId: string;
designId: string;
templateId?: string;
amount: number | string;
currency: string;
customerEmail?: string;
customerDetails?: {
name?: string | null;
email?: string | null;
phone?: string | null;
address?: {
line1?: string | null;
line2?: string | null;
city?: string | null;
state?: string | null;
postalCode?: string | null;
country?: string | null;
} | null;
};
}>(event);
if (!body?.stripeSessionId || !body?.designId) {
throw createError({
statusCode: 400,
statusMessage: "Missing required fields",
});
}
const config = useRuntimeConfig();
const backendUrl = config.public?.backendUrl;
if (!backendUrl) {
throw createError({
statusCode: 500,
statusMessage: "Backend URL not configured",
});
}
const record = {
stripeSessionId: body.stripeSessionId,
designId: body.designId,
templateId: body.templateId ?? null,
amount: body.amount.toString(),
currency: body.currency,
customerEmail: body.customerEmail ?? null,
customerDetails: body.customerDetails ?? null,
};
console.log("[transactions] Forwarding record to backend:", record);
try {
const backendResult = await $fetch("/transactions", {
baseURL: backendUrl,
method: "POST",
body: record,
});
return {
ok: true,
receivedAt: new Date().toISOString(),
backendResult,
};
} catch (err) {
console.error("[transactions] Failed to forward to backend", err);
throw createError({
statusCode: 502,
statusMessage:
(err as Error)?.message ?? "Failed to save transaction to backend",
});
}
});