@rovela-ai/sdk 0.19.4 → 0.19.6
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/admin/components/AdminPageHeader.d.ts.map +1 -1
- package/dist/admin/components/AdminPageHeader.js +9 -2
- package/dist/admin/components/AdminPageHeader.js.map +1 -1
- package/dist/admin/components/AdminUserMenu.d.ts.map +1 -1
- package/dist/admin/components/AdminUserMenu.js +2 -1
- package/dist/admin/components/AdminUserMenu.js.map +1 -1
- package/dist/admin/components/CustomerDetails.d.ts.map +1 -1
- package/dist/admin/components/CustomerDetails.js +2 -1
- package/dist/admin/components/CustomerDetails.js.map +1 -1
- package/dist/admin/components/EmailsManager.d.ts.map +1 -1
- package/dist/admin/components/EmailsManager.js +2 -1
- package/dist/admin/components/EmailsManager.js.map +1 -1
- package/dist/admin/components/LowStockAlert.d.ts.map +1 -1
- package/dist/admin/components/LowStockAlert.js +3 -2
- package/dist/admin/components/LowStockAlert.js.map +1 -1
- package/dist/admin/components/OrderDetails.d.ts.map +1 -1
- package/dist/admin/components/OrderDetails.js +2 -1
- package/dist/admin/components/OrderDetails.js.map +1 -1
- package/dist/admin/components/ProductTable.d.ts.map +1 -1
- package/dist/admin/components/ProductTable.js +4 -3
- package/dist/admin/components/ProductTable.js.map +1 -1
- package/dist/admin/components/RecentOrders.d.ts.map +1 -1
- package/dist/admin/components/RecentOrders.js +2 -1
- package/dist/admin/components/RecentOrders.js.map +1 -1
- package/dist/admin/components/SEOPreview.d.ts +2 -8
- package/dist/admin/components/SEOPreview.d.ts.map +1 -1
- package/dist/admin/components/SEOPreview.js +32 -5
- package/dist/admin/components/SEOPreview.js.map +1 -1
- package/dist/admin/components/SecondaryMetricsRow.d.ts.map +1 -1
- package/dist/admin/components/SecondaryMetricsRow.js +3 -2
- package/dist/admin/components/SecondaryMetricsRow.js.map +1 -1
- package/dist/admin/components/StatsCards.d.ts.map +1 -1
- package/dist/admin/components/StatsCards.js +2 -1
- package/dist/admin/components/StatsCards.js.map +1 -1
- package/docs/changelog/README.md +53 -0
- package/docs/changelog/epoch-01-chrome-consent.md +63 -0
- package/docs/changelog/epoch-02-platform-commerce.md +108 -0
- package/docs/changelog/epoch-03-i18n-files.md +72 -0
- package/docs/changelog/epoch-04-emails.md +65 -0
- package/docs/changelog/epoch-05-admin-experience.md +98 -0
- package/docs/changelog/epoch-06-mobile-integrity.md +92 -0
- package/docs/design/admin-ledger-visual-universe.html +1961 -0
- package/docs/design/admin-sidebar-and-band.html +542 -0
- package/package.json +3 -1
- package/templates/store-template/.claude/skills/add-section/SKILL.md +438 -0
- package/templates/store-template/.claude/skills/build-feature/SKILL.md +201 -0
- package/templates/store-template/.claude/skills/customize-theme/SKILL.md +167 -0
- package/templates/store-template/.claude/skills/debug-errors/SKILL.md +68 -0
- package/templates/store-template/.claude/skills/frontend-design/SKILL.md +176 -0
- package/templates/store-template/.claude/skills/generate-images/SKILL.md +115 -0
- package/templates/store-template/.claude/skills/manage-products/SKILL.md +187 -0
- package/templates/store-template/.claude/skills/override-sdk-component/SKILL.md +154 -0
- package/templates/store-template/.env.example +50 -0
- package/templates/store-template/.mcp.json +8 -0
- package/templates/store-template/.rovela/blueprint.example.json +190 -0
- package/templates/store-template/CLAUDE.md +14 -0
- package/templates/store-template/app/LayoutContent.tsx +106 -0
- package/templates/store-template/app/[...path]/page.tsx +79 -0
- package/templates/store-template/app/account/addresses/page.tsx +45 -0
- package/templates/store-template/app/account/layout.tsx +17 -0
- package/templates/store-template/app/account/orders/[id]/invoice/page.tsx +277 -0
- package/templates/store-template/app/account/orders/[id]/page.tsx +725 -0
- package/templates/store-template/app/account/orders/page.tsx +153 -0
- package/templates/store-template/app/account/page.tsx +184 -0
- package/templates/store-template/app/account/profile/page.tsx +434 -0
- package/templates/store-template/app/admin/(dashboard)/account/page.tsx +16 -0
- package/templates/store-template/app/admin/(dashboard)/analytics/events/page.tsx +14 -0
- package/templates/store-template/app/admin/(dashboard)/analytics/layout.tsx +48 -0
- package/templates/store-template/app/admin/(dashboard)/analytics/page.tsx +15 -0
- package/templates/store-template/app/admin/(dashboard)/analytics/visitors/page.tsx +14 -0
- package/templates/store-template/app/admin/(dashboard)/categories/[id]/page.tsx +38 -0
- package/templates/store-template/app/admin/(dashboard)/categories/new/page.tsx +35 -0
- package/templates/store-template/app/admin/(dashboard)/categories/page.tsx +223 -0
- package/templates/store-template/app/admin/(dashboard)/customers/[id]/page.tsx +26 -0
- package/templates/store-template/app/admin/(dashboard)/customers/page.tsx +33 -0
- package/templates/store-template/app/admin/(dashboard)/discounts/page.tsx +16 -0
- package/templates/store-template/app/admin/(dashboard)/emails/page.tsx +16 -0
- package/templates/store-template/app/admin/(dashboard)/files/page.tsx +16 -0
- package/templates/store-template/app/admin/(dashboard)/layout.tsx +44 -0
- package/templates/store-template/app/admin/(dashboard)/loading.tsx +88 -0
- package/templates/store-template/app/admin/(dashboard)/locations/page.tsx +16 -0
- package/templates/store-template/app/admin/(dashboard)/orders/[id]/page.tsx +66 -0
- package/templates/store-template/app/admin/(dashboard)/orders/page.tsx +26 -0
- package/templates/store-template/app/admin/(dashboard)/page.tsx +146 -0
- package/templates/store-template/app/admin/(dashboard)/payments/page.tsx +15 -0
- package/templates/store-template/app/admin/(dashboard)/products/[id]/page.tsx +38 -0
- package/templates/store-template/app/admin/(dashboard)/products/new/page.tsx +35 -0
- package/templates/store-template/app/admin/(dashboard)/products/page.tsx +31 -0
- package/templates/store-template/app/admin/(dashboard)/settings/page.tsx +46 -0
- package/templates/store-template/app/admin/(dashboard)/shipping/page.tsx +15 -0
- package/templates/store-template/app/admin/(dashboard)/tax/page.tsx +15 -0
- package/templates/store-template/app/admin/(dashboard)/users/[id]/page.tsx +114 -0
- package/templates/store-template/app/admin/(dashboard)/users/page.tsx +16 -0
- package/templates/store-template/app/admin/accept-invite/page.tsx +36 -0
- package/templates/store-template/app/admin/forgot-password/page.tsx +13 -0
- package/templates/store-template/app/admin/layout.tsx +47 -0
- package/templates/store-template/app/admin/login/page.tsx +528 -0
- package/templates/store-template/app/admin/reset-password/page.tsx +36 -0
- package/templates/store-template/app/api/account/addresses/[id]/route.ts +10 -0
- package/templates/store-template/app/api/account/addresses/route.ts +10 -0
- package/templates/store-template/app/api/account/change-password/route.ts +107 -0
- package/templates/store-template/app/api/account/orders/[id]/refund/route.ts +11 -0
- package/templates/store-template/app/api/account/orders/[id]/return/route.ts +14 -0
- package/templates/store-template/app/api/account/orders/[id]/route.ts +42 -0
- package/templates/store-template/app/api/account/orders/route.ts +29 -0
- package/templates/store-template/app/api/account/profile/route.ts +165 -0
- package/templates/store-template/app/api/admin/accept-invite/route.ts +11 -0
- package/templates/store-template/app/api/admin/analytics/events/route.ts +9 -0
- package/templates/store-template/app/api/admin/analytics/route.ts +10 -0
- package/templates/store-template/app/api/admin/analytics/visitors/route.ts +9 -0
- package/templates/store-template/app/api/admin/branding/favicon/route.ts +9 -0
- package/templates/store-template/app/api/admin/branding/logo/route.ts +9 -0
- package/templates/store-template/app/api/admin/categories/[id]/route.ts +9 -0
- package/templates/store-template/app/api/admin/categories/route.ts +9 -0
- package/templates/store-template/app/api/admin/check/route.ts +10 -0
- package/templates/store-template/app/api/admin/customer-groups/[id]/route.ts +10 -0
- package/templates/store-template/app/api/admin/customer-groups/route.ts +10 -0
- package/templates/store-template/app/api/admin/customers/[id]/addresses/[addressId]/route.ts +15 -0
- package/templates/store-template/app/api/admin/customers/[id]/addresses/route.ts +15 -0
- package/templates/store-template/app/api/admin/customers/[id]/route.ts +11 -0
- package/templates/store-template/app/api/admin/customers/bulk/route.ts +8 -0
- package/templates/store-template/app/api/admin/customers/route.ts +9 -0
- package/templates/store-template/app/api/admin/discounts/[id]/route.ts +11 -0
- package/templates/store-template/app/api/admin/discounts/route.ts +10 -0
- package/templates/store-template/app/api/admin/emails/preview/route.ts +4 -0
- package/templates/store-template/app/api/admin/emails/route.ts +5 -0
- package/templates/store-template/app/api/admin/emails/test/route.ts +4 -0
- package/templates/store-template/app/api/admin/files/route.ts +8 -0
- package/templates/store-template/app/api/admin/forgot-password/route.ts +7 -0
- package/templates/store-template/app/api/admin/linked-customer/route.ts +11 -0
- package/templates/store-template/app/api/admin/locations/[id]/route.ts +10 -0
- package/templates/store-template/app/api/admin/locations/route.ts +10 -0
- package/templates/store-template/app/api/admin/me/password/route.ts +13 -0
- package/templates/store-template/app/api/admin/me/route.ts +11 -0
- package/templates/store-template/app/api/admin/orders/[id]/refund/route.ts +7 -0
- package/templates/store-template/app/api/admin/orders/[id]/return/approve/route.ts +7 -0
- package/templates/store-template/app/api/admin/orders/[id]/return/reject/route.ts +7 -0
- package/templates/store-template/app/api/admin/orders/[id]/route.ts +9 -0
- package/templates/store-template/app/api/admin/orders/[id]/ship-with-shippo/route.ts +6 -0
- package/templates/store-template/app/api/admin/orders/[id]/shippo-rates/route.ts +6 -0
- package/templates/store-template/app/api/admin/orders/bulk/route.ts +8 -0
- package/templates/store-template/app/api/admin/orders/route.ts +9 -0
- package/templates/store-template/app/api/admin/payment-methods/[id]/route.ts +10 -0
- package/templates/store-template/app/api/admin/payment-methods/route.ts +10 -0
- package/templates/store-template/app/api/admin/products/[id]/route.ts +9 -0
- package/templates/store-template/app/api/admin/products/bulk/route.ts +9 -0
- package/templates/store-template/app/api/admin/products/route.ts +9 -0
- package/templates/store-template/app/api/admin/products/stats/route.ts +10 -0
- package/templates/store-template/app/api/admin/reset-password/route.ts +10 -0
- package/templates/store-template/app/api/admin/settings/route.ts +11 -0
- package/templates/store-template/app/api/admin/setup/route.ts +10 -0
- package/templates/store-template/app/api/admin/setup-guide/manual-mark/route.ts +13 -0
- package/templates/store-template/app/api/admin/setup-guide/route.ts +10 -0
- package/templates/store-template/app/api/admin/shipping/carriers/[id]/route.ts +9 -0
- package/templates/store-template/app/api/admin/shipping/carriers/route.ts +9 -0
- package/templates/store-template/app/api/admin/shipping/rates/[id]/route.ts +9 -0
- package/templates/store-template/app/api/admin/shipping/rates/route.ts +9 -0
- package/templates/store-template/app/api/admin/shipping/shippo/api-key/route.ts +1 -0
- package/templates/store-template/app/api/admin/shipping/shippo/validate/route.ts +1 -0
- package/templates/store-template/app/api/admin/shipping/zones/[id]/route.ts +9 -0
- package/templates/store-template/app/api/admin/shipping/zones/route.ts +9 -0
- package/templates/store-template/app/api/admin/stats/route.ts +9 -0
- package/templates/store-template/app/api/admin/stripe-status/route.ts +1 -0
- package/templates/store-template/app/api/admin/tax-zones/[id]/route.ts +7 -0
- package/templates/store-template/app/api/admin/tax-zones/route.ts +7 -0
- package/templates/store-template/app/api/admin/users/[id]/route.ts +14 -0
- package/templates/store-template/app/api/admin/users/route.ts +12 -0
- package/templates/store-template/app/api/admin-auth/[...nextauth]/route.ts +17 -0
- package/templates/store-template/app/api/analytics/track/route.ts +12 -0
- package/templates/store-template/app/api/auth/[...nextauth]/route.ts +19 -0
- package/templates/store-template/app/api/auth/forgot-password/route.ts +9 -0
- package/templates/store-template/app/api/auth/register/route.ts +9 -0
- package/templates/store-template/app/api/auth/resend-verification/route.ts +9 -0
- package/templates/store-template/app/api/auth/reset-password/route.ts +10 -0
- package/templates/store-template/app/api/auth/verify-email/route.ts +10 -0
- package/templates/store-template/app/api/categories/route.ts +10 -0
- package/templates/store-template/app/api/checkout/countries/route.ts +7 -0
- package/templates/store-template/app/api/checkout/discount/route.ts +9 -0
- package/templates/store-template/app/api/checkout/manual/route.ts +10 -0
- package/templates/store-template/app/api/checkout/payment-methods/route.ts +8 -0
- package/templates/store-template/app/api/checkout/pickup-locations/route.ts +8 -0
- package/templates/store-template/app/api/checkout/route.ts +10 -0
- package/templates/store-template/app/api/checkout/shipping/route.ts +21 -0
- package/templates/store-template/app/api/checkout/status/route.ts +10 -0
- package/templates/store-template/app/api/contact/route.ts +164 -0
- package/templates/store-template/app/api/media/presign/route.ts +7 -0
- package/templates/store-template/app/api/media/route.ts +7 -0
- package/templates/store-template/app/api/products/[slug]/route.ts +10 -0
- package/templates/store-template/app/api/products/route.ts +10 -0
- package/templates/store-template/app/api/store/settings/route.ts +12 -0
- package/templates/store-template/app/api/webhooks/stripe/route.ts +63 -0
- package/templates/store-template/app/auth/forgot-password/page.tsx +38 -0
- package/templates/store-template/app/auth/layout.tsx +17 -0
- package/templates/store-template/app/auth/reset-password/page.tsx +81 -0
- package/templates/store-template/app/auth/signin/page.tsx +62 -0
- package/templates/store-template/app/auth/signup/page.tsx +38 -0
- package/templates/store-template/app/auth/verify-email/page.tsx +185 -0
- package/templates/store-template/app/cart/page.tsx +137 -0
- package/templates/store-template/app/checkout/page.tsx +88 -0
- package/templates/store-template/app/checkout/success/page.tsx +50 -0
- package/templates/store-template/app/contact/layout.tsx +24 -0
- package/templates/store-template/app/contact/page.tsx +321 -0
- package/templates/store-template/app/faq/page.tsx +153 -0
- package/templates/store-template/app/globals.css +99 -0
- package/templates/store-template/app/layout.tsx +269 -0
- package/templates/store-template/app/not-found.tsx +35 -0
- package/templates/store-template/app/page.tsx +23 -0
- package/templates/store-template/app/privacy/page.tsx +281 -0
- package/templates/store-template/app/products/[slug]/ProductDetailClient.tsx +179 -0
- package/templates/store-template/app/products/[slug]/page.tsx +149 -0
- package/templates/store-template/app/products/layout.tsx +26 -0
- package/templates/store-template/app/products/page.tsx +102 -0
- package/templates/store-template/app/robots.ts +25 -0
- package/templates/store-template/app/sitemap.ts +76 -0
- package/templates/store-template/app/terms/page.tsx +313 -0
- package/templates/store-template/components/PathSyncBridge.tsx +61 -0
- package/templates/store-template/components/Providers.tsx +37 -0
- package/templates/store-template/components/layout/Footer.tsx +150 -0
- package/templates/store-template/components/layout/Header.tsx +162 -0
- package/templates/store-template/components/sections/.gitkeep +7 -0
- package/templates/store-template/components/sections/CTA.tsx +51 -0
- package/templates/store-template/components/sections/Features.tsx +91 -0
- package/templates/store-template/components/sections/Hero.tsx +85 -0
- package/templates/store-template/eslint.config.mjs +18 -0
- package/templates/store-template/lib/store-config.ts +77 -0
- package/templates/store-template/lib/store-policy.ts +68 -0
- package/templates/store-template/lib/utils.ts +21 -0
- package/templates/store-template/next-env.d.ts +6 -0
- package/templates/store-template/next.config.js +105 -0
- package/templates/store-template/package.json +32 -0
- package/templates/store-template/postcss.config.js +6 -0
- package/templates/store-template/proxy.ts +150 -0
- package/templates/store-template/public/rovela-logo.png +0 -0
- package/templates/store-template/tailwind.config.ts +74 -0
- package/templates/store-template/tsconfig.json +41 -0
- package/templates/store-template/types/next-auth.d.ts +32 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Single Payment Method API Route
|
|
3
|
+
*
|
|
4
|
+
* PUT /api/admin/payment-methods/[id] - Update a method
|
|
5
|
+
* DELETE /api/admin/payment-methods/[id] - Delete a method (order history keeps its label)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { updatePaymentMethodHandler, deletePaymentMethodHandler } from '@rovela-ai/sdk/admin/api'
|
|
9
|
+
|
|
10
|
+
export { updatePaymentMethodHandler as PUT, deletePaymentMethodHandler as DELETE }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Payment Methods API Route
|
|
3
|
+
*
|
|
4
|
+
* GET /api/admin/payment-methods - List all methods
|
|
5
|
+
* POST /api/admin/payment-methods - Create a manual method
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getPaymentMethods, createPaymentMethodHandler } from '@rovela-ai/sdk/admin/api'
|
|
9
|
+
|
|
10
|
+
export { getPaymentMethods as GET, createPaymentMethodHandler as POST }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Products Metrics API Route
|
|
3
|
+
*
|
|
4
|
+
* GET /api/admin/products/stats
|
|
5
|
+
*
|
|
6
|
+
* Returns: { data: { activeCount, outOfStockCount, bestSeller } }
|
|
7
|
+
* - bestSeller is over the last 30 days, by units sold; null when no sales.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { GET } from '@rovela-ai/sdk/admin/api/products-stats'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Reset Password API Route
|
|
3
|
+
*
|
|
4
|
+
* Thin re-export of the SDK handler.
|
|
5
|
+
*
|
|
6
|
+
* - GET ?token=X → non-destructive token validation (used by the UI on mount)
|
|
7
|
+
* - POST { token, password } → consume the token and update the admin's password
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { GET, POST } from '@rovela-ai/sdk/admin/api/reset-password'
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Settings API Route
|
|
3
|
+
*
|
|
4
|
+
* GET /api/admin/settings - Get store settings (with lazy init from blueprint)
|
|
5
|
+
* PUT /api/admin/settings - Update store settings
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getSettings, updateSettings } from '@rovela-ai/sdk/admin/api'
|
|
9
|
+
|
|
10
|
+
export const GET = getSettings
|
|
11
|
+
export const PUT = updateSettings
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Setup Guide Manual-Mark API Route
|
|
3
|
+
*
|
|
4
|
+
* POST /api/admin/setup-guide/manual-mark
|
|
5
|
+
*
|
|
6
|
+
* Body: { key: 'taxNoneNeeded' | 'legalPagesReviewed' | 'firstProductTouched'
|
|
7
|
+
* | 'logoUploaded' | 'dismiss' | 'reopen', value: boolean }
|
|
8
|
+
*
|
|
9
|
+
* Allowlisted-key writeback to `store_settings.onboarding` JSONB. Auth gate
|
|
10
|
+
* `settings.write`. See SDK §32.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export { markSetupTask as POST } from '@rovela-ai/sdk/admin/api'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Setup Guide API Route
|
|
3
|
+
*
|
|
4
|
+
* GET /api/admin/setup-guide
|
|
5
|
+
*
|
|
6
|
+
* Returns the 9 setup-guide tasks + per-tier progress for the dashboard
|
|
7
|
+
* card. Auth gate `settings.read`. See SDK §32 for the full spec.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { getSetupGuide as GET } from '@rovela-ai/sdk/admin/api'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Single Shipping Carrier API Route
|
|
3
|
+
*
|
|
4
|
+
* GET/PUT/DELETE /api/admin/shipping/carriers/[id]
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { getShippingCarrier, updateShippingCarrier, deleteShippingCarrier } from '@rovela-ai/sdk/admin/api'
|
|
8
|
+
|
|
9
|
+
export { getShippingCarrier as GET, updateShippingCarrier as PUT, deleteShippingCarrier as DELETE }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Shipping Carriers API Route
|
|
3
|
+
*
|
|
4
|
+
* GET/POST /api/admin/shipping/carriers - List/Create shipping carriers
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { getShippingCarriers, createShippingCarrier } from '@rovela-ai/sdk/admin/api'
|
|
8
|
+
|
|
9
|
+
export { getShippingCarriers as GET, createShippingCarrier as POST }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { saveShippoApiKey as POST, deleteShippoApiKey as DELETE } from '@rovela-ai/sdk/admin/api'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { validateShippoApiKey as POST } from '@rovela-ai/sdk/admin/api'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Single Shipping Zone API Route
|
|
3
|
+
*
|
|
4
|
+
* GET/PUT/DELETE /api/admin/shipping/zones/[id]
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { getShippingZone, updateShippingZone, deleteShippingZone } from '@rovela-ai/sdk/admin/api'
|
|
8
|
+
|
|
9
|
+
export { getShippingZone as GET, updateShippingZone as PUT, deleteShippingZone as DELETE }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Shipping Zones API Route
|
|
3
|
+
*
|
|
4
|
+
* GET/POST /api/admin/shipping/zones - List/Create shipping zones
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { getShippingZones, createShippingZone } from '@rovela-ai/sdk/admin/api'
|
|
8
|
+
|
|
9
|
+
export { getShippingZones as GET, createShippingZone as POST }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getStripeStatus as GET } from '@rovela-ai/sdk/admin/api'
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Users API Route — detail + actions
|
|
3
|
+
*
|
|
4
|
+
* Thin re-export of the SDK handlers:
|
|
5
|
+
* GET — detail (users.read)
|
|
6
|
+
* PATCH — { action: 'deactivate' | 'reactivate' } (users.write)
|
|
7
|
+
* DELETE — hard delete (users.delete, owner only)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
getUser as GET,
|
|
12
|
+
PATCH,
|
|
13
|
+
DELETE,
|
|
14
|
+
} from '@rovela-ai/sdk/admin/api/users'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Users API Route — list + invite
|
|
3
|
+
*
|
|
4
|
+
* Thin re-export of the SDK handlers:
|
|
5
|
+
* GET — list all admins (users.read)
|
|
6
|
+
* POST — invite a new admin (users.write; Phase 3)
|
|
7
|
+
*
|
|
8
|
+
* The SDK enforces all permissions and invariants; this file just mounts
|
|
9
|
+
* the handlers at the expected path.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export { GET, POST } from '@rovela-ai/sdk/admin/api/users'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store Admin Authentication Route
|
|
3
|
+
*
|
|
4
|
+
* Dedicated NextAuth endpoint for admin sign-in/sign-out/session. Writes
|
|
5
|
+
* its own cookie (`__Secure-rovela.admin.session-token`), completely
|
|
6
|
+
* separate from the storefront customer session cookie. Both can coexist
|
|
7
|
+
* in the same browser.
|
|
8
|
+
*
|
|
9
|
+
* Customer authentication lives at /api/auth/[...nextauth].
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import NextAuth from 'next-auth'
|
|
13
|
+
import { createAdminAuthOptions } from '@rovela-ai/sdk/admin'
|
|
14
|
+
|
|
15
|
+
const handler = NextAuth(createAdminAuthOptions())
|
|
16
|
+
|
|
17
|
+
export { handler as GET, handler as POST }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/analytics/track
|
|
3
|
+
*
|
|
4
|
+
* Storefront analytics event ingest. Public endpoint — events are pseudonymous
|
|
5
|
+
* (visitor_id is a random UUID, no PII). The SDK handler validates the event,
|
|
6
|
+
* filters bots + admin sessions, derives device/country, and inserts to the
|
|
7
|
+
* store's own Neon branch.
|
|
8
|
+
*
|
|
9
|
+
* See CLAUDE.md §46.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export { POST } from '@rovela-ai/sdk/analytics/api/track'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storefront Customer Authentication Route
|
|
3
|
+
*
|
|
4
|
+
* Handles customer sign-in/sign-up/session for the storefront.
|
|
5
|
+
* Uses the 'credentials' provider and writes the customer session cookie
|
|
6
|
+
* (`__Secure-rovela.customer.session-token`).
|
|
7
|
+
*
|
|
8
|
+
* Admin authentication lives at a SEPARATE endpoint:
|
|
9
|
+
* /api/admin-auth/[...nextauth]
|
|
10
|
+
* with its own cookie (`__Secure-rovela.admin.session-token`), so an admin
|
|
11
|
+
* and a customer session can coexist in the same browser.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import NextAuth from 'next-auth'
|
|
15
|
+
import { createCustomerAuthOptions } from '@rovela-ai/sdk/auth'
|
|
16
|
+
|
|
17
|
+
const handler = NextAuth(createCustomerAuthOptions())
|
|
18
|
+
|
|
19
|
+
export { handler as GET, handler as POST }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reset Password Route
|
|
3
|
+
*
|
|
4
|
+
* GET/POST /api/auth/reset-password - Validate token / Reset password
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { GET as getHandler, POST as postHandler } from '@rovela-ai/sdk/auth/api/reset-password'
|
|
8
|
+
|
|
9
|
+
export const GET = getHandler
|
|
10
|
+
export const POST = postHandler
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email Verification Route
|
|
3
|
+
*
|
|
4
|
+
* GET/POST /api/auth/verify-email - Verify customer email
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { GET as getHandler, POST as postHandler } from '@rovela-ai/sdk/auth/api/verify-email'
|
|
8
|
+
|
|
9
|
+
export const GET = getHandler
|
|
10
|
+
export const POST = postHandler
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkout Discount Preview API Route
|
|
3
|
+
*
|
|
4
|
+
* POST /api/checkout/discount - Validate a discount code against the current
|
|
5
|
+
* cart (and surface automatic promotions) before placing the order. Runs the
|
|
6
|
+
* same server-side pricing pipeline as order creation.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export { POST } from '@rovela-ai/sdk/checkout/api/discount'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manual Checkout API Route
|
|
3
|
+
*
|
|
4
|
+
* POST /api/checkout/manual - Place an order with a manual payment method
|
|
5
|
+
* (cash on delivery, wire transfer…). Order is created as 'pending'; the
|
|
6
|
+
* merchant marks it paid from the admin. All amounts are recomputed
|
|
7
|
+
* server-side from the database.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { POST } from '@rovela-ai/sdk/checkout/api/manual'
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkout Pickup Locations API Route (public)
|
|
3
|
+
*
|
|
4
|
+
* GET /api/checkout/pickup-locations - Pickup-enabled store locations for the
|
|
5
|
+
* checkout's "Pick up in store" selector. Empty list = toggle hidden.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { GET } from '@rovela-ai/sdk/checkout/api/pickup-locations'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shipping calculation API route
|
|
3
|
+
*
|
|
4
|
+
* POST /api/checkout/shipping
|
|
5
|
+
* Calculates available shipping options based on address and cart items.
|
|
6
|
+
* Supports both manual (zone-based) and Shippo (carrier API) modes.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const response = await fetch('/api/checkout/shipping', {
|
|
11
|
+
* method: 'POST',
|
|
12
|
+
* headers: { 'Content-Type': 'application/json' },
|
|
13
|
+
* body: JSON.stringify({
|
|
14
|
+
* address: { firstName, lastName, line1, city, state, postalCode, country },
|
|
15
|
+
* items: [{ price: 2999, quantity: 2 }]
|
|
16
|
+
* })
|
|
17
|
+
* })
|
|
18
|
+
* const { options, flatOptions, mode } = await response.json()
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export { ShippingPOST as POST } from '@rovela-ai/sdk/checkout/api'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkout Status Route
|
|
3
|
+
*
|
|
4
|
+
* GET /api/checkout/status - Check if payments are configured
|
|
5
|
+
*
|
|
6
|
+
* Used by CheckoutButton component to verify the store can accept payments
|
|
7
|
+
* before showing the checkout button.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { GET } from '@rovela-ai/sdk/checkout/api/payment-status'
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contact Form API Route
|
|
3
|
+
*
|
|
4
|
+
* POST /api/contact - Send contact form message to store owner
|
|
5
|
+
*
|
|
6
|
+
* Uses SDK email system to send formatted emails.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { NextRequest, NextResponse } from 'next/server'
|
|
10
|
+
import {
|
|
11
|
+
sendEmail,
|
|
12
|
+
baseLayout,
|
|
13
|
+
getEmailConfig,
|
|
14
|
+
getSupportEmail,
|
|
15
|
+
escapeHtml,
|
|
16
|
+
} from '@rovela-ai/sdk/emails'
|
|
17
|
+
|
|
18
|
+
// =============================================================================
|
|
19
|
+
// Types
|
|
20
|
+
// =============================================================================
|
|
21
|
+
|
|
22
|
+
interface ContactFormData {
|
|
23
|
+
name: string
|
|
24
|
+
email: string
|
|
25
|
+
subject: string
|
|
26
|
+
message: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// =============================================================================
|
|
30
|
+
// Validation
|
|
31
|
+
// =============================================================================
|
|
32
|
+
|
|
33
|
+
function validateContactForm(data: unknown): {
|
|
34
|
+
valid: boolean
|
|
35
|
+
error?: string
|
|
36
|
+
data?: ContactFormData
|
|
37
|
+
} {
|
|
38
|
+
if (!data || typeof data !== 'object') {
|
|
39
|
+
return { valid: false, error: 'Invalid request body' }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const { name, email, subject, message } = data as Record<string, unknown>
|
|
43
|
+
|
|
44
|
+
if (typeof name !== 'string' || name.trim().length < 2) {
|
|
45
|
+
return { valid: false, error: 'Name must be at least 2 characters' }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (typeof email !== 'string' || !email.includes('@') || email.length < 5) {
|
|
49
|
+
return { valid: false, error: 'Please provide a valid email address' }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (typeof subject !== 'string' || subject.trim().length < 5) {
|
|
53
|
+
return { valid: false, error: 'Subject must be at least 5 characters' }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (typeof message !== 'string' || message.trim().length < 10) {
|
|
57
|
+
return { valid: false, error: 'Message must be at least 10 characters' }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
valid: true,
|
|
62
|
+
data: {
|
|
63
|
+
name: name.trim(),
|
|
64
|
+
email: email.trim().toLowerCase(),
|
|
65
|
+
subject: subject.trim(),
|
|
66
|
+
message: message.trim(),
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// =============================================================================
|
|
72
|
+
// POST Handler
|
|
73
|
+
// =============================================================================
|
|
74
|
+
|
|
75
|
+
export async function POST(request: NextRequest) {
|
|
76
|
+
try {
|
|
77
|
+
// Parse request body
|
|
78
|
+
const body = await request.json()
|
|
79
|
+
|
|
80
|
+
// Validate form data
|
|
81
|
+
const validation = validateContactForm(body)
|
|
82
|
+
if (!validation.valid || !validation.data) {
|
|
83
|
+
return NextResponse.json(
|
|
84
|
+
{ success: false, error: validation.error },
|
|
85
|
+
{ status: 400 }
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const { name, email, subject, message } = validation.data
|
|
90
|
+
|
|
91
|
+
// Get email configuration
|
|
92
|
+
const config = await getEmailConfig()
|
|
93
|
+
|
|
94
|
+
// Determine recipient - store owner or support email
|
|
95
|
+
const recipientEmail =
|
|
96
|
+
process.env.STORE_OWNER_EMAIL || (await getSupportEmail())
|
|
97
|
+
|
|
98
|
+
// Build email content
|
|
99
|
+
const emailContent = `
|
|
100
|
+
<h1 style="margin: 0 0 24px 0; font-family: 'Plus Jakarta Sans', system-ui, sans-serif; font-size: 30px; font-weight: 700; color: #0A0A0A; text-align: center; line-height: 1.1;">New Contact Form Message</h1>
|
|
101
|
+
<p style="margin: 0 0 16px 0; font-family: 'Plus Jakarta Sans', system-ui, sans-serif; font-size: 16px; font-weight: 400; line-height: 1.625; color: #78716C;">You've received a new message from your store's contact form.</p>
|
|
102
|
+
|
|
103
|
+
<table style="width: 100%; border-collapse: collapse; margin: 24px 0;">
|
|
104
|
+
<tr>
|
|
105
|
+
<td style="padding: 12px 0; border-bottom: 1px solid #E8DFD3; font-weight: 600; width: 100px;">From:</td>
|
|
106
|
+
<td style="padding: 12px 0; border-bottom: 1px solid #E8DFD3;">${escapeHtml(name)}</td>
|
|
107
|
+
</tr>
|
|
108
|
+
<tr>
|
|
109
|
+
<td style="padding: 12px 0; border-bottom: 1px solid #E8DFD3; font-weight: 600;">Email:</td>
|
|
110
|
+
<td style="padding: 12px 0; border-bottom: 1px solid #E8DFD3;">
|
|
111
|
+
<a href="mailto:${escapeHtml(email)}" style="color: #0CAF7D; text-decoration: none;">${escapeHtml(email)}</a>
|
|
112
|
+
</td>
|
|
113
|
+
</tr>
|
|
114
|
+
<tr>
|
|
115
|
+
<td style="padding: 12px 0; border-bottom: 1px solid #E8DFD3; font-weight: 600;">Subject:</td>
|
|
116
|
+
<td style="padding: 12px 0; border-bottom: 1px solid #E8DFD3;">${escapeHtml(subject)}</td>
|
|
117
|
+
</tr>
|
|
118
|
+
</table>
|
|
119
|
+
|
|
120
|
+
<h2 style="margin: 24px 0 16px 0; font-family: 'Plus Jakarta Sans', system-ui, sans-serif; font-size: 20px; font-weight: 600; color: #0A0A0A;">Message</h2>
|
|
121
|
+
<div style="background-color: #F7F7F7; border-radius: 8px; padding: 20px; margin-top: 16px;">
|
|
122
|
+
<p style="margin: 0; white-space: pre-wrap; line-height: 1.6;">${escapeHtml(message)}</p>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<p style="margin: 24px 0 0 0; font-family: 'Plus Jakarta Sans', system-ui, sans-serif; font-size: 14px; font-weight: 400; line-height: 1.625; color: #78716C;"><em>You can reply directly to this email to respond to ${escapeHtml(name)}.</em></p>
|
|
126
|
+
`
|
|
127
|
+
|
|
128
|
+
// Render with base layout
|
|
129
|
+
const html = baseLayout({
|
|
130
|
+
config,
|
|
131
|
+
title: `Contact: ${subject}`,
|
|
132
|
+
content: emailContent,
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// Send email with reply-to set to customer's email
|
|
136
|
+
const result = await sendEmail({
|
|
137
|
+
to: recipientEmail,
|
|
138
|
+
subject: `[${config.storeName}] Contact: ${subject}`,
|
|
139
|
+
html,
|
|
140
|
+
replyTo: email,
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
if (!result.success) {
|
|
144
|
+
console.error('[Contact API] Email send failed:', result.error)
|
|
145
|
+
return NextResponse.json(
|
|
146
|
+
{ success: false, error: 'Failed to send message. Please try again.' },
|
|
147
|
+
{ status: 500 }
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
console.log('[Contact API] Message sent successfully to:', recipientEmail)
|
|
152
|
+
|
|
153
|
+
return NextResponse.json({
|
|
154
|
+
success: true,
|
|
155
|
+
message: 'Message sent successfully',
|
|
156
|
+
})
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error('[Contact API] Error:', error)
|
|
159
|
+
return NextResponse.json(
|
|
160
|
+
{ success: false, error: 'An unexpected error occurred' },
|
|
161
|
+
{ status: 500 }
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
}
|