@nextsparkjs/core 0.1.0-beta.128 → 0.1.0-beta.129

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.
Files changed (76) hide show
  1. package/dist/components/billing/ConfirmPlanChangeModal.d.ts +29 -0
  2. package/dist/components/billing/ConfirmPlanChangeModal.d.ts.map +1 -0
  3. package/dist/components/billing/ConfirmPlanChangeModal.js +100 -0
  4. package/dist/components/billing/PricingTable.d.ts +3 -0
  5. package/dist/components/billing/PricingTable.d.ts.map +1 -1
  6. package/dist/components/billing/PricingTable.js +146 -71
  7. package/dist/components/billing/QuotaGate.d.ts +21 -0
  8. package/dist/components/billing/QuotaGate.d.ts.map +1 -0
  9. package/dist/components/billing/QuotaGate.js +33 -0
  10. package/dist/components/billing/index.d.ts +2 -0
  11. package/dist/components/billing/index.d.ts.map +1 -1
  12. package/dist/components/billing/index.js +4 -0
  13. package/dist/components/dashboard/block-editor/dynamic-form.d.ts.map +1 -1
  14. package/dist/components/dashboard/block-editor/dynamic-form.js +7 -5
  15. package/dist/contexts/SubscriptionContext.d.ts +2 -0
  16. package/dist/contexts/SubscriptionContext.d.ts.map +1 -1
  17. package/dist/contexts/SubscriptionContext.js +2 -0
  18. package/dist/hooks/index.d.ts +1 -0
  19. package/dist/hooks/index.d.ts.map +1 -1
  20. package/dist/hooks/index.js +1 -0
  21. package/dist/hooks/useQuotaCheck.d.ts +26 -0
  22. package/dist/hooks/useQuotaCheck.d.ts.map +1 -0
  23. package/dist/hooks/useQuotaCheck.js +33 -0
  24. package/dist/lib/api/entity/generic-handler.d.ts.map +1 -1
  25. package/dist/lib/api/entity/generic-handler.js +54 -6
  26. package/dist/lib/oauth/index.d.ts +1 -1
  27. package/dist/messages/de/billing.json +10 -0
  28. package/dist/messages/de/index.d.ts +9 -0
  29. package/dist/messages/de/index.d.ts.map +1 -1
  30. package/dist/messages/en/billing.json +21 -0
  31. package/dist/messages/en/index.d.ts +19 -0
  32. package/dist/messages/en/index.d.ts.map +1 -1
  33. package/dist/messages/es/billing.json +21 -0
  34. package/dist/messages/es/index.d.ts +19 -0
  35. package/dist/messages/es/index.d.ts.map +1 -1
  36. package/dist/messages/fr/billing.json +10 -0
  37. package/dist/messages/fr/index.d.ts +9 -0
  38. package/dist/messages/fr/index.d.ts.map +1 -1
  39. package/dist/messages/it/billing.json +10 -0
  40. package/dist/messages/it/index.d.ts +9 -0
  41. package/dist/messages/it/index.d.ts.map +1 -1
  42. package/dist/messages/pt/billing.json +10 -0
  43. package/dist/messages/pt/index.d.ts +9 -0
  44. package/dist/messages/pt/index.d.ts.map +1 -1
  45. package/dist/styles/classes.json +6 -2
  46. package/dist/styles/ui.css +1 -1
  47. package/dist/templates/app/api/v1/billing/cancel/route.ts +1 -1
  48. package/dist/templates/app/api/v1/billing/change-plan/route.ts +1 -1
  49. package/dist/templates/app/api/v1/billing/check-action/route.ts +7 -6
  50. package/dist/templates/app/api/v1/billing/checkout/route.ts +35 -7
  51. package/dist/templates/app/api/v1/billing/portal/route.ts +1 -1
  52. package/dist/templates/app/dashboard/settings/billing/page.tsx +9 -4
  53. package/dist/templates/app/dashboard/settings/plans/page.tsx +29 -7
  54. package/dist/templates/blocks/hero/component.tsx +6 -3
  55. package/dist/templates/blocks/hero/schema.ts +2 -1
  56. package/dist/templates/blocks/testimonials/component.tsx +2 -2
  57. package/dist/templates/blocks/testimonials/schema.ts +2 -2
  58. package/dist/templates/features/pages/blocks/hero/component.tsx +6 -3
  59. package/dist/templates/features/pages/blocks/hero/schema.ts +2 -1
  60. package/dist/types/blocks.d.ts +24 -0
  61. package/dist/types/blocks.d.ts.map +1 -1
  62. package/dist/types/blocks.js +17 -1
  63. package/package.json +2 -2
  64. package/templates/app/api/v1/billing/cancel/route.ts +1 -1
  65. package/templates/app/api/v1/billing/change-plan/route.ts +1 -1
  66. package/templates/app/api/v1/billing/check-action/route.ts +7 -6
  67. package/templates/app/api/v1/billing/checkout/route.ts +35 -7
  68. package/templates/app/api/v1/billing/portal/route.ts +1 -1
  69. package/templates/app/dashboard/settings/billing/page.tsx +9 -4
  70. package/templates/app/dashboard/settings/plans/page.tsx +29 -7
  71. package/templates/blocks/hero/component.tsx +6 -3
  72. package/templates/blocks/hero/schema.ts +2 -1
  73. package/templates/blocks/testimonials/component.tsx +2 -2
  74. package/templates/blocks/testimonials/schema.ts +2 -2
  75. package/templates/features/pages/blocks/hero/component.tsx +6 -3
  76. package/templates/features/pages/blocks/hero/schema.ts +2 -1
@@ -51,7 +51,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
51
51
 
52
52
  // 3. Permission check using MembershipService
53
53
  const membership = await MembershipService.get(authResult.user.id, teamId)
54
- const actionResult = membership.canPerformAction('billing.cancel')
54
+ const actionResult = membership.canPerformAction('team.billing.manage')
55
55
 
56
56
  if (!actionResult.allowed) {
57
57
  return NextResponse.json(
@@ -49,7 +49,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
49
49
 
50
50
  // 3. Permission check using MembershipService
51
51
  const membership = await MembershipService.get(authResult.user.id, teamId)
52
- const actionResult = membership.canPerformAction('billing.change-plan')
52
+ const actionResult = membership.canPerformAction('team.billing.manage')
53
53
 
54
54
  if (!actionResult.allowed) {
55
55
  return NextResponse.json(
@@ -11,7 +11,7 @@
11
11
 
12
12
  import { NextRequest, NextResponse } from 'next/server'
13
13
  import { authenticateRequest, createAuthError } from '@nextsparkjs/core/lib/api/auth/dual-auth'
14
- import { MembershipService } from '@nextsparkjs/core/lib/services'
14
+ import { SubscriptionService } from '@nextsparkjs/core/lib/services'
15
15
  import { z } from 'zod'
16
16
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
17
17
 
@@ -69,11 +69,12 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
69
69
  )
70
70
  }
71
71
 
72
- // 4. Check action permission using MembershipService
73
- // Note: MembershipService.get() does NOT throw for non-members
74
- // It returns TeamMembership with role: null
75
- const membership = await MembershipService.get(authResult.user.id, teamId)
76
- const result = membership.canPerformAction(action)
72
+ // 4. Check action using SubscriptionService (RBAC + features + quotas)
73
+ const result = await SubscriptionService.canPerformAction(
74
+ authResult.user.id,
75
+ teamId,
76
+ action
77
+ )
77
78
 
78
79
  return NextResponse.json({
79
80
  success: true,
@@ -69,7 +69,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
69
69
 
70
70
  // 4. Permission check using MembershipService
71
71
  const membership = await MembershipService.get(authResult.user.id, teamId)
72
- const actionResult = membership.canPerformAction('billing.checkout')
72
+ const actionResult = membership.canPerformAction('team.billing.manage')
73
73
 
74
74
  if (!actionResult.allowed) {
75
75
  return NextResponse.json(
@@ -83,16 +83,44 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
83
83
  )
84
84
  }
85
85
 
86
- // 5. Check existing subscription for customer ID
86
+ // 5. Check existing subscription
87
87
  try {
88
- const subscription = await SubscriptionService.getActive(teamId)
88
+ const subscription = await SubscriptionService.getActive(teamId, authResult.user.id)
89
89
 
90
- // Build URLs
90
+ // If already subscribed with an active provider subscription,
91
+ // use changePlan (immediate proration) instead of creating a new checkout.
92
+ // This prevents double-billing by updating the existing subscription in Stripe.
93
+ if (subscription?.externalSubscriptionId) {
94
+ const result = await SubscriptionService.changePlan(
95
+ teamId,
96
+ planSlug,
97
+ billingPeriod,
98
+ authResult.user.id
99
+ )
100
+
101
+ if (!result.success) {
102
+ return NextResponse.json(
103
+ { success: false, error: result.error },
104
+ { status: 400 }
105
+ )
106
+ }
107
+
108
+ // No redirect needed — plan changed immediately via API
109
+ return NextResponse.json({
110
+ success: true,
111
+ data: {
112
+ changed: true,
113
+ subscription: result.subscription,
114
+ warnings: result.downgradeWarnings,
115
+ }
116
+ })
117
+ }
118
+
119
+ // No existing provider subscription — create a new checkout session
91
120
  const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:5173'
92
121
  const successUrl = `${appUrl}/dashboard/settings/billing?success=true`
93
122
  const cancelUrl = `${appUrl}/dashboard/settings/billing?canceled=true`
94
123
 
95
- // Create checkout session via billing gateway
96
124
  const session = await getBillingGateway().createCheckoutSession({
97
125
  teamId,
98
126
  planSlug,
@@ -111,11 +139,11 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
111
139
  }
112
140
  })
113
141
  } catch (error) {
114
- console.error('[checkout] Error creating checkout session:', error)
142
+ console.error('[checkout] Error:', error)
115
143
  return NextResponse.json(
116
144
  {
117
145
  success: false,
118
- error: error instanceof Error ? error.message : 'Failed to create checkout session'
146
+ error: error instanceof Error ? error.message : 'Failed to process checkout'
119
147
  },
120
148
  { status: 500 }
121
149
  )
@@ -38,7 +38,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
38
38
 
39
39
  // 3. Permission check using MembershipService
40
40
  const membership = await MembershipService.get(authResult.user.id, teamId)
41
- const actionResult = membership.canPerformAction('billing.portal')
41
+ const actionResult = membership.canPerformAction('team.billing.manage')
42
42
 
43
43
  if (!actionResult.allowed) {
44
44
  return NextResponse.json(
@@ -18,6 +18,7 @@ import { sel } from '@nextsparkjs/core/selectors'
18
18
  import { useTranslations } from 'next-intl'
19
19
  import { getTemplateOrDefaultClient } from '@nextsparkjs/registries/template-registry.client'
20
20
  import { useInvoices } from '@nextsparkjs/core/hooks/useInvoices'
21
+ import { useSubscription } from '@nextsparkjs/core/hooks/useSubscription'
21
22
  import { InvoicesTable } from '@nextsparkjs/core/components/billing'
22
23
  import { usePermission } from '@nextsparkjs/core/lib/permissions/hooks'
23
24
  import type { Permission } from '@nextsparkjs/core/lib/permissions/types'
@@ -25,9 +26,11 @@ import type { Permission } from '@nextsparkjs/core/lib/permissions/types'
25
26
  function BillingPage() {
26
27
  const router = useRouter()
27
28
  const canAccessBilling = usePermission('settings.billing' as Permission)
29
+ const { planSlug, plan, isActive, isReady } = useSubscription()
28
30
  const [statusMessage, setStatusMessage] = useState('')
29
- const [invoicesLimit, setInvoicesLimit] = useState(3) // Start with 3, load 10 more each time
31
+ const [invoicesLimit, setInvoicesLimit] = useState(3)
30
32
  const t = useTranslations('settings')
33
+ const tb = useTranslations('billing')
31
34
 
32
35
  // Fetch invoices for current team (must be before early return)
33
36
  const {
@@ -107,7 +110,9 @@ function BillingPage() {
107
110
  {t('billing.currentPlan.description')}
108
111
  </CardDescription>
109
112
  </div>
110
- <Badge variant="secondary">{t('billing.currentPlan.free')}</Badge>
113
+ <Badge variant={isActive ? 'default' : 'secondary'}>
114
+ {isReady && planSlug ? tb(`plans.${planSlug}.name`) : t('billing.currentPlan.free')}
115
+ </Badge>
111
116
  </div>
112
117
  </CardHeader>
113
118
  <CardContent>
@@ -136,7 +141,7 @@ function BillingPage() {
136
141
  {t('billing.upgrade.description')}
137
142
  </p>
138
143
  </div>
139
- <Link href="/pricing">
144
+ <Link href="/dashboard/settings/plans">
140
145
  <Button
141
146
  onClick={handleUpgrade}
142
147
  data-cy={sel('settings.billing.currentPlan.upgradeButton')}
@@ -263,7 +268,7 @@ function BillingPage() {
263
268
  </p>
264
269
  </div>
265
270
  <div className="flex gap-3">
266
- <Link href="/pricing">
271
+ <Link href="/dashboard/settings/plans">
267
272
  <Button variant="outline">
268
273
  {t('billing.upgrade.viewPricing')}
269
274
  </Button>
@@ -1,10 +1,11 @@
1
1
  'use client'
2
2
 
3
- import { useCallback } from 'react'
3
+ import { useCallback, useState } from 'react'
4
4
  import { useTranslations } from 'next-intl'
5
5
  import { getTemplateOrDefaultClient } from '@nextsparkjs/registries/template-registry.client'
6
6
  import { PricingTable } from '@nextsparkjs/core/components/billing'
7
- import { useRouter } from 'next/navigation'
7
+ import { fetchWithTeam } from '@nextsparkjs/core/lib/api/entities'
8
+ import { toast } from 'sonner'
8
9
 
9
10
  /**
10
11
  * Plans Settings Page
@@ -14,12 +15,33 @@ import { useRouter } from 'next/navigation'
14
15
  */
15
16
  function PlansPage() {
16
17
  const t = useTranslations('settings')
17
- const router = useRouter()
18
+ const [loading, setLoading] = useState<string | null>(null)
18
19
 
19
- const handleSelectPlan = useCallback((planSlug: string) => {
20
- // Redirect to checkout API with selected plan
21
- router.push(`/api/v1/billing/checkout?plan=${planSlug}`)
22
- }, [router])
20
+ const handleSelectPlan = useCallback(async (planSlug: string) => {
21
+ setLoading(planSlug)
22
+ try {
23
+ const res = await fetchWithTeam('/api/v1/billing/checkout', {
24
+ method: 'POST',
25
+ headers: { 'Content-Type': 'application/json' },
26
+ body: JSON.stringify({ planSlug, billingPeriod: 'monthly' }),
27
+ })
28
+ const data = await res.json()
29
+ if (data.success && data.data?.url) {
30
+ // New subscription — redirect to provider checkout
31
+ window.location.href = data.data.url
32
+ } else if (data.success && data.data?.changed) {
33
+ // Plan changed via proration (existing subscription)
34
+ toast.success('Plan changed successfully')
35
+ window.location.reload()
36
+ } else {
37
+ toast.error(data.error || 'Failed to process plan change')
38
+ }
39
+ } catch {
40
+ toast.error('Failed to start checkout')
41
+ } finally {
42
+ setLoading(null)
43
+ }
44
+ }, [])
23
45
 
24
46
  return (
25
47
  <div className="max-w-6xl" data-cy="plans-settings-main">
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
  import { Button } from '@/core/components/ui/button'
3
3
  import { cn } from '@/core/lib/utils'
4
- import { buildSectionClasses } from '@/core/types/blocks'
4
+ import { buildSectionClasses, resolveMediaUrl } from '@/core/types/blocks'
5
5
  import type { HeroBlockProps } from './schema'
6
6
 
7
7
  /**
@@ -43,6 +43,9 @@ export function HeroBlock({
43
43
  // Handle legacy subtitle/description props for backward compatibility
44
44
  const displayContent = content || legacyProps.subtitle || legacyProps.description
45
45
 
46
+ // Resolve media ref to URL (handles both legacy string and new object format)
47
+ const backgroundImageUrl = resolveMediaUrl(backgroundImage)
48
+
46
49
  // Build section classes with background and custom className
47
50
  const sectionClasses = buildSectionClasses(
48
51
  cn(
@@ -55,11 +58,11 @@ export function HeroBlock({
55
58
  return (
56
59
  <section id={id} className={sectionClasses} data-cy="block-hero">
57
60
  {/* Background Image */}
58
- {backgroundImage && (
61
+ {backgroundImageUrl && (
59
62
  <div
60
63
  className="absolute inset-0 z-0"
61
64
  style={{
62
- backgroundImage: `url(${backgroundImage})`,
65
+ backgroundImage: `url(${backgroundImageUrl})`,
63
66
  backgroundSize: 'cover',
64
67
  backgroundPosition: 'center',
65
68
  }}
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod'
2
2
  import {
3
3
  baseBlockSchema,
4
+ mediaRefSchema,
4
5
  type BaseBlockProps,
5
6
  } from '@/core/types/blocks'
6
7
 
@@ -16,7 +17,7 @@ import {
16
17
  */
17
18
  export const heroSpecificSchema = z.object({
18
19
  // Hero-specific design fields
19
- backgroundImage: z.string().url('Must be a valid URL').optional(),
20
+ backgroundImage: mediaRefSchema.optional(),
20
21
  textColor: z.enum(['light', 'dark']).default('light'),
21
22
  })
22
23
 
@@ -2,7 +2,7 @@ import React from 'react'
2
2
  import { Quote } from 'lucide-react'
3
3
  import { Avatar, AvatarFallback, AvatarImage } from '@/core/components/ui/avatar'
4
4
  import { cn } from '@/core/lib/utils'
5
- import { buildSectionClasses } from '@/core/types/blocks'
5
+ import { buildSectionClasses, resolveMediaUrl } from '@/core/types/blocks'
6
6
  import type { TestimonialsBlockProps, TestimonialItem } from './schema'
7
7
 
8
8
  /**
@@ -77,7 +77,7 @@ export function TestimonialsBlock({
77
77
 
78
78
  <div className="flex items-center gap-3">
79
79
  <Avatar>
80
- <AvatarImage src={item.avatar} alt={item.author} />
80
+ <AvatarImage src={resolveMediaUrl(item.avatar)} alt={item.author} />
81
81
  <AvatarFallback>
82
82
  {item.author.split(' ').map((n: string) => n[0]).join('')}
83
83
  </AvatarFallback>
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod'
2
- import { baseBlockSchema } from '@/core/types/blocks'
2
+ import { baseBlockSchema, mediaRefSchema } from '@/core/types/blocks'
3
3
 
4
4
  /**
5
5
  * Testimonial Item Schema
@@ -9,7 +9,7 @@ const testimonialItemSchema = z.object({
9
9
  quote: z.string().min(1, 'Quote is required').max(500),
10
10
  author: z.string().min(1, 'Author name is required').max(100),
11
11
  role: z.string().max(100).optional(),
12
- avatar: z.string().url('Must be a valid URL').optional(),
12
+ avatar: mediaRefSchema.optional(),
13
13
  })
14
14
 
15
15
  export type TestimonialItem = z.infer<typeof testimonialItemSchema>
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
  import { Button } from '@nextsparkjs/core/components/ui/button'
3
3
  import { cn } from '@nextsparkjs/core/lib/utils'
4
- import { buildSectionClasses } from '@nextsparkjs/core/types/blocks'
4
+ import { buildSectionClasses, resolveMediaUrl } from '@nextsparkjs/core/types/blocks'
5
5
  import { sel } from '../../lib/selectors'
6
6
  import type { HeroBlockProps } from './schema'
7
7
 
@@ -45,6 +45,9 @@ export function HeroBlock({
45
45
  // Handle legacy subtitle/description props for backward compatibility
46
46
  const displayContent = content || legacyProps.subtitle || legacyProps.description
47
47
 
48
+ // Resolve media ref to URL (handles both legacy string and new object format)
49
+ const backgroundImageUrl = resolveMediaUrl(backgroundImage)
50
+
48
51
  // Alignment classes mapping
49
52
  const alignmentClasses = {
50
53
  left: 'text-left items-start',
@@ -64,11 +67,11 @@ export function HeroBlock({
64
67
  return (
65
68
  <section id={id} className={sectionClasses} data-cy={sel('blocks.hero.container')}>
66
69
  {/* Background Image */}
67
- {backgroundImage && (
70
+ {backgroundImageUrl && (
68
71
  <div
69
72
  className="absolute inset-0 z-0"
70
73
  style={{
71
- backgroundImage: `url(${backgroundImage})`,
74
+ backgroundImage: `url(${backgroundImageUrl})`,
72
75
  backgroundSize: 'cover',
73
76
  backgroundPosition: 'center',
74
77
  }}
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod'
2
2
  import {
3
3
  baseBlockSchema,
4
+ mediaRefSchema,
4
5
  type BaseBlockProps,
5
6
  } from '@nextsparkjs/core/types/blocks'
6
7
 
@@ -17,7 +18,7 @@ import {
17
18
  */
18
19
  export const heroSpecificSchema = z.object({
19
20
  // Hero-specific design fields
20
- backgroundImage: z.string().url('Must be a valid URL').optional(),
21
+ backgroundImage: mediaRefSchema.optional(),
21
22
  textColor: z.enum(['light', 'dark']).default('light'),
22
23
  alignment: z.enum(['left', 'center', 'right']).default('center'),
23
24
  })
@@ -5,6 +5,30 @@
5
5
  * Supports WordPress/Webflow-style page building with reusable blocks.
6
6
  */
7
7
  import { z } from 'zod';
8
+ /**
9
+ * Media Reference Schema
10
+ *
11
+ * Blocks can store media references in two formats:
12
+ * - Legacy: plain URL string (backward compatible)
13
+ * - New: object with mediaId + url (enables future URL re-resolution)
14
+ *
15
+ * Use `resolveMediaUrl()` in components to safely extract the URL from either format.
16
+ */
17
+ export declare const mediaRefObjectSchema: z.ZodObject<{
18
+ mediaId: z.ZodString;
19
+ url: z.ZodString;
20
+ }, z.core.$strip>;
21
+ export declare const mediaRefSchema: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
22
+ mediaId: z.ZodString;
23
+ url: z.ZodString;
24
+ }, z.core.$strip>]>;
25
+ export type MediaRef = z.infer<typeof mediaRefSchema>;
26
+ export type MediaRefObject = z.infer<typeof mediaRefObjectSchema>;
27
+ /**
28
+ * Resolve a MediaRef value to a plain URL string.
29
+ * Handles both legacy string URLs and new { mediaId, url } objects.
30
+ */
31
+ export declare function resolveMediaUrl(ref: MediaRef | null | undefined): string | undefined;
8
32
  /**
9
33
  * CTA (Call-to-Action) Schema
10
34
  * Used for buttons/links in Content tab
@@ -1 +1 @@
1
- {"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../src/types/blocks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../src/types/blocks.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,17 @@
1
1
  import { z } from "zod";
2
+ const mediaRefObjectSchema = z.object({
3
+ mediaId: z.string(),
4
+ url: z.string()
5
+ });
6
+ const mediaRefSchema = z.union([
7
+ z.string(),
8
+ mediaRefObjectSchema
9
+ ]);
10
+ function resolveMediaUrl(ref) {
11
+ if (!ref) return void 0;
12
+ if (typeof ref === "string") return ref || void 0;
13
+ return ref.url || void 0;
14
+ }
2
15
  const ctaSchema = z.object({
3
16
  text: z.string().min(1, "CTA text is required"),
4
17
  link: z.string().url("Must be a valid URL").or(z.string().startsWith("/")),
@@ -199,5 +212,8 @@ export {
199
212
  getBackgroundClasses,
200
213
  getSectionAttributes,
201
214
  isBlockConfig,
202
- isBlockInstance
215
+ isBlockInstance,
216
+ mediaRefObjectSchema,
217
+ mediaRefSchema,
218
+ resolveMediaUrl
203
219
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextsparkjs/core",
3
- "version": "0.1.0-beta.128",
3
+ "version": "0.1.0-beta.129",
4
4
  "description": "NextSpark - The complete SaaS framework for Next.js",
5
5
  "license": "MIT",
6
6
  "author": "NextSpark <hello@nextspark.dev>",
@@ -462,7 +462,7 @@
462
462
  "tailwind-merge": "^3.3.1",
463
463
  "uuid": "^13.0.0",
464
464
  "zod": "^4.1.5",
465
- "@nextsparkjs/testing": "0.1.0-beta.128"
465
+ "@nextsparkjs/testing": "0.1.0-beta.129"
466
466
  },
467
467
  "scripts": {
468
468
  "postinstall": "node scripts/postinstall.mjs || true",
@@ -51,7 +51,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
51
51
 
52
52
  // 3. Permission check using MembershipService
53
53
  const membership = await MembershipService.get(authResult.user.id, teamId)
54
- const actionResult = membership.canPerformAction('billing.cancel')
54
+ const actionResult = membership.canPerformAction('team.billing.manage')
55
55
 
56
56
  if (!actionResult.allowed) {
57
57
  return NextResponse.json(
@@ -49,7 +49,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
49
49
 
50
50
  // 3. Permission check using MembershipService
51
51
  const membership = await MembershipService.get(authResult.user.id, teamId)
52
- const actionResult = membership.canPerformAction('billing.change-plan')
52
+ const actionResult = membership.canPerformAction('team.billing.manage')
53
53
 
54
54
  if (!actionResult.allowed) {
55
55
  return NextResponse.json(
@@ -11,7 +11,7 @@
11
11
 
12
12
  import { NextRequest, NextResponse } from 'next/server'
13
13
  import { authenticateRequest, createAuthError } from '@nextsparkjs/core/lib/api/auth/dual-auth'
14
- import { MembershipService } from '@nextsparkjs/core/lib/services'
14
+ import { SubscriptionService } from '@nextsparkjs/core/lib/services'
15
15
  import { z } from 'zod'
16
16
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
17
17
 
@@ -69,11 +69,12 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
69
69
  )
70
70
  }
71
71
 
72
- // 4. Check action permission using MembershipService
73
- // Note: MembershipService.get() does NOT throw for non-members
74
- // It returns TeamMembership with role: null
75
- const membership = await MembershipService.get(authResult.user.id, teamId)
76
- const result = membership.canPerformAction(action)
72
+ // 4. Check action using SubscriptionService (RBAC + features + quotas)
73
+ const result = await SubscriptionService.canPerformAction(
74
+ authResult.user.id,
75
+ teamId,
76
+ action
77
+ )
77
78
 
78
79
  return NextResponse.json({
79
80
  success: true,
@@ -69,7 +69,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
69
69
 
70
70
  // 4. Permission check using MembershipService
71
71
  const membership = await MembershipService.get(authResult.user.id, teamId)
72
- const actionResult = membership.canPerformAction('billing.checkout')
72
+ const actionResult = membership.canPerformAction('team.billing.manage')
73
73
 
74
74
  if (!actionResult.allowed) {
75
75
  return NextResponse.json(
@@ -83,16 +83,44 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
83
83
  )
84
84
  }
85
85
 
86
- // 5. Check existing subscription for customer ID
86
+ // 5. Check existing subscription
87
87
  try {
88
- const subscription = await SubscriptionService.getActive(teamId)
88
+ const subscription = await SubscriptionService.getActive(teamId, authResult.user.id)
89
89
 
90
- // Build URLs
90
+ // If already subscribed with an active provider subscription,
91
+ // use changePlan (immediate proration) instead of creating a new checkout.
92
+ // This prevents double-billing by updating the existing subscription in Stripe.
93
+ if (subscription?.externalSubscriptionId) {
94
+ const result = await SubscriptionService.changePlan(
95
+ teamId,
96
+ planSlug,
97
+ billingPeriod,
98
+ authResult.user.id
99
+ )
100
+
101
+ if (!result.success) {
102
+ return NextResponse.json(
103
+ { success: false, error: result.error },
104
+ { status: 400 }
105
+ )
106
+ }
107
+
108
+ // No redirect needed — plan changed immediately via API
109
+ return NextResponse.json({
110
+ success: true,
111
+ data: {
112
+ changed: true,
113
+ subscription: result.subscription,
114
+ warnings: result.downgradeWarnings,
115
+ }
116
+ })
117
+ }
118
+
119
+ // No existing provider subscription — create a new checkout session
91
120
  const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:5173'
92
121
  const successUrl = `${appUrl}/dashboard/settings/billing?success=true`
93
122
  const cancelUrl = `${appUrl}/dashboard/settings/billing?canceled=true`
94
123
 
95
- // Create checkout session via billing gateway
96
124
  const session = await getBillingGateway().createCheckoutSession({
97
125
  teamId,
98
126
  planSlug,
@@ -111,11 +139,11 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
111
139
  }
112
140
  })
113
141
  } catch (error) {
114
- console.error('[checkout] Error creating checkout session:', error)
142
+ console.error('[checkout] Error:', error)
115
143
  return NextResponse.json(
116
144
  {
117
145
  success: false,
118
- error: error instanceof Error ? error.message : 'Failed to create checkout session'
146
+ error: error instanceof Error ? error.message : 'Failed to process checkout'
119
147
  },
120
148
  { status: 500 }
121
149
  )
@@ -38,7 +38,7 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
38
38
 
39
39
  // 3. Permission check using MembershipService
40
40
  const membership = await MembershipService.get(authResult.user.id, teamId)
41
- const actionResult = membership.canPerformAction('billing.portal')
41
+ const actionResult = membership.canPerformAction('team.billing.manage')
42
42
 
43
43
  if (!actionResult.allowed) {
44
44
  return NextResponse.json(