@nextsparkjs/core 0.1.0-beta.131 → 0.1.0-beta.133

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.
@@ -4,6 +4,7 @@ export interface BuilderEditorViewProps {
4
4
  entityConfig: ClientEntityConfig;
5
5
  id?: string;
6
6
  mode: 'create' | 'edit';
7
+ onEntityFieldChange?: (field: string, value: unknown) => void;
7
8
  }
8
- export declare function BuilderEditorView({ entitySlug, entityConfig, id, mode }: BuilderEditorViewProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function BuilderEditorView({ entitySlug, entityConfig, id, mode, onEntityFieldChange: onEntityFieldChangeProp }: BuilderEditorViewProps): import("react/jsx-runtime").JSX.Element;
9
10
  //# sourceMappingURL=builder-editor-view.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"builder-editor-view.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/builder-editor-view.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AAwCxF,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;IAChC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAA;CACxB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,sBAAsB,2CA+rB/F"}
1
+ {"version":3,"file":"builder-editor-view.d.ts","sourceRoot":"","sources":["../../../../src/components/dashboard/block-editor/builder-editor-view.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAA;AAwCxF,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,kBAAkB,CAAA;IAChC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAA;IACvB,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC9D;AAED,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,EAAE,sBAAsB,2CAgsB7I"}
@@ -41,7 +41,7 @@ function buildApiHeaders(includeContentType = false) {
41
41
  function slugify(text) {
42
42
  return text.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9\s-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-");
43
43
  }
44
- function BuilderEditorView({ entitySlug, entityConfig, id, mode }) {
44
+ function BuilderEditorView({ entitySlug, entityConfig, id, mode, onEntityFieldChange: onEntityFieldChangeProp }) {
45
45
  var _a;
46
46
  const router = useRouter();
47
47
  const t = useTranslations("admin.builder");
@@ -311,7 +311,8 @@ function BuilderEditorView({ entitySlug, entityConfig, id, mode }) {
311
311
  }, []);
312
312
  const handleEntityFieldChange = useCallback((field, value) => {
313
313
  setEntityFields((prev) => ({ ...prev, [field]: value }));
314
- }, []);
314
+ onEntityFieldChangeProp == null ? void 0 : onEntityFieldChangeProp(field, value);
315
+ }, [onEntityFieldChangeProp]);
315
316
  const handleLeftSidebarToggle = useCallback((value) => {
316
317
  if (!value || value === leftSidebarMode) {
317
318
  setLeftSidebarMode("none");
@@ -2,7 +2,12 @@
2
2
  * PageRenderer Component
3
3
  *
4
4
  * Renders pages from the Page Builder by iterating over blocks
5
- * and dynamically loading block components from the registry.
5
+ * and directly loading block components from the SSR registry.
6
+ *
7
+ * Uses direct imports (BLOCK_COMPONENTS_SSR) instead of React.lazy
8
+ * so that all HTML is visible in the initial server response without JS.
9
+ * React.lazy puts content inside hidden <template> tags that require
10
+ * client-side JS to reveal — breaking no-JS rendering and hurting SEO.
6
11
  *
7
12
  * @module core/components/public/pageBuilder
8
13
  */
@@ -1 +1 @@
1
- {"version":3,"file":"PageRenderer.d.ts","sourceRoot":"","sources":["../../../../src/components/public/pageBuilder/PageRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAmD1D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAA;QACV,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,EAAE,aAAa,EAAE,CAAA;QACvB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;CACF;AAED,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE,iBAAiB,2CA+BvD"}
1
+ {"version":3,"file":"PageRenderer.d.ts","sourceRoot":"","sources":["../../../../src/components/public/pageBuilder/PageRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAkC1D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAA;QACV,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,EAAE,aAAa,EAAE,CAAA;QACvB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;CACF;AAED,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE,iBAAiB,2CA+BvD"}
@@ -1,13 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { Suspense } from "react";
3
- import { getBlockComponent, normalizeBlockProps } from "../../../lib/blocks/loader.js";
4
- function BlockSkeleton() {
5
- return /* @__PURE__ */ jsx("div", { className: "w-full py-12 px-4 animate-pulse", children: /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto", children: [
6
- /* @__PURE__ */ jsx("div", { className: "h-8 bg-muted rounded w-3/4 mb-4" }),
7
- /* @__PURE__ */ jsx("div", { className: "h-4 bg-muted rounded w-full mb-2" }),
8
- /* @__PURE__ */ jsx("div", { className: "h-4 bg-muted rounded w-5/6" })
9
- ] }) });
10
- }
2
+ import { getBlockComponentSSR, normalizeBlockProps } from "../../../lib/blocks/loader.js";
11
3
  function BlockError({ blockSlug }) {
12
4
  return /* @__PURE__ */ jsx("div", { className: "w-full py-12 px-4 bg-destructive/10 border border-destructive/20 rounded", children: /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto text-center", children: [
13
5
  /* @__PURE__ */ jsxs("p", { className: "text-destructive", children: [
@@ -18,13 +10,13 @@ function BlockError({ blockSlug }) {
18
10
  ] }) });
19
11
  }
20
12
  function BlockRenderer({ block }) {
21
- const BlockComponent = getBlockComponent(block.blockSlug);
13
+ const BlockComponent = getBlockComponentSSR(block.blockSlug);
22
14
  if (!BlockComponent) {
23
15
  console.warn(`Block component not found for slug: ${block.blockSlug}`);
24
16
  return /* @__PURE__ */ jsx(BlockError, { blockSlug: block.blockSlug });
25
17
  }
26
18
  const normalizedProps = normalizeBlockProps(block.props);
27
- return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(BlockSkeleton, {}), children: /* @__PURE__ */ jsx(BlockComponent, { ...normalizedProps }) });
19
+ return /* @__PURE__ */ jsx(BlockComponent, { ...normalizedProps });
28
20
  }
29
21
  function PageRenderer({ page }) {
30
22
  const blocks = Array.isArray(page.blocks) ? page.blocks : [];
@@ -22,6 +22,15 @@ export declare function getBlockComponents(): Record<string, BlockComponent>;
22
22
  * @returns The block component or undefined if not found
23
23
  */
24
24
  export declare function getBlockComponent(slug: string): BlockComponent | undefined;
25
+ /**
26
+ * Get all SSR block components (direct imports, no React.lazy)
27
+ * Use for public page rendering where no-JS SSR is required
28
+ */
29
+ export declare function getBlockComponentsSSR(): Record<string, BlockComponent>;
30
+ /**
31
+ * Get a specific SSR block component by slug (direct import, no React.lazy)
32
+ */
33
+ export declare function getBlockComponentSSR(slug: string): BlockComponent | undefined;
25
34
  /**
26
35
  * Check if a block exists in the registry
27
36
  *
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/lib/blocks/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAIrC,KAAK,cAAc,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;AAExC;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE1E;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgD3F"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/lib/blocks/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAIrC,KAAK,cAAc,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;AAExC;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE1E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAEtE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE7E;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgD3F"}
@@ -1,10 +1,16 @@
1
- import { BLOCK_COMPONENTS } from "@nextsparkjs/registries/block-registry";
1
+ import { BLOCK_COMPONENTS, BLOCK_COMPONENTS_SSR } from "@nextsparkjs/registries/block-registry";
2
2
  function getBlockComponents() {
3
3
  return BLOCK_COMPONENTS;
4
4
  }
5
5
  function getBlockComponent(slug) {
6
6
  return BLOCK_COMPONENTS[slug];
7
7
  }
8
+ function getBlockComponentsSSR() {
9
+ return BLOCK_COMPONENTS_SSR;
10
+ }
11
+ function getBlockComponentSSR(slug) {
12
+ return BLOCK_COMPONENTS_SSR[slug];
13
+ }
8
14
  function hasBlock(slug) {
9
15
  return slug in BLOCK_COMPONENTS;
10
16
  }
@@ -48,7 +54,9 @@ function normalizeBlockProps(props) {
48
54
  }
49
55
  export {
50
56
  getBlockComponent,
57
+ getBlockComponentSSR,
51
58
  getBlockComponents,
59
+ getBlockComponentsSSR,
52
60
  hasBlock,
53
61
  normalizeBlockProps
54
62
  };
@@ -1,5 +1,5 @@
1
1
  {
2
- "generated": "2026-03-31T21:30:22.374Z",
2
+ "generated": "2026-04-06T20:21:52.643Z",
3
3
  "totalClasses": 1078,
4
4
  "classes": [
5
5
  "!text-2xl",
@@ -68,7 +68,7 @@ function AcceptInvitePage() {
68
68
  }
69
69
 
70
70
  // Check email match
71
- if (user.email.toLowerCase() !== data.data.email.toLowerCase()) {
71
+ if ((user.email ?? '').toLowerCase() !== data.data.email.toLowerCase()) {
72
72
  setStatus('email_mismatch')
73
73
  setErrorMessage(`This invitation was sent to ${data.data.email}, but you are logged in as ${user.email}`)
74
74
  return
@@ -22,7 +22,15 @@ import { query, queryOne } from '@nextsparkjs/core/lib/db'
22
22
  import { getBillingGateway } from '@nextsparkjs/core/lib/billing/gateways/factory'
23
23
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
24
24
  import type { PolarWebhookExtensions } from '@nextsparkjs/core/lib/billing/polar-webhook'
25
- import { polarWebhookExtensions } from '@/lib/billing/polar-webhook-extensions'
25
+
26
+ async function loadExtensions(): Promise<PolarWebhookExtensions> {
27
+ try {
28
+ const mod = await import('@/lib/billing/polar-webhook-extensions')
29
+ return mod.polarWebhookExtensions
30
+ } catch {
31
+ return {}
32
+ }
33
+ }
26
34
 
27
35
  async function handlePolarWebhook(request: NextRequest) {
28
36
  // 1. Get raw body and ALL headers (Polar needs full headers for verification)
@@ -86,7 +94,7 @@ async function handlePolarWebhook(request: NextRequest) {
86
94
  break
87
95
 
88
96
  case 'order.paid':
89
- await handleOrderPaid(event.data, eventId, polarWebhookExtensions)
97
+ await handleOrderPaid(event.data, eventId, await loadExtensions())
90
98
  break
91
99
 
92
100
  default:
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Handles Stripe subscription lifecycle events.
5
5
  * To add one-time payment handling (credit packs, LTD, upsells),
6
- * override lib/billing/stripe-webhook-extensions.ts in your project.
6
+ * create lib/billing/stripe-webhook-extensions.ts in your project.
7
7
  *
8
8
  * Rate limiting: 500 requests/hour per IP (tier: webhook).
9
9
  * Stripe signature verification is the primary security layer;
@@ -14,12 +14,21 @@
14
14
 
15
15
  import { NextRequest } from 'next/server'
16
16
  import { handleStripeWebhook } from '@nextsparkjs/core/lib/billing/stripe-webhook'
17
- import { stripeWebhookExtensions } from '@/lib/billing/stripe-webhook-extensions'
18
17
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
19
18
 
19
+ async function loadExtensions() {
20
+ try {
21
+ const mod = await import('@/lib/billing/stripe-webhook-extensions')
22
+ return mod.stripeWebhookExtensions
23
+ } catch {
24
+ return {}
25
+ }
26
+ }
27
+
20
28
  export const POST = withRateLimitTier(
21
29
  async (request: NextRequest) => {
22
- return handleStripeWebhook(request, stripeWebhookExtensions)
30
+ const extensions = await loadExtensions()
31
+ return handleStripeWebhook(request, extensions)
23
32
  },
24
33
  'webhook'
25
34
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextsparkjs/core",
3
- "version": "0.1.0-beta.131",
3
+ "version": "0.1.0-beta.133",
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.131"
465
+ "@nextsparkjs/testing": "0.1.0-beta.133"
466
466
  },
467
467
  "scripts": {
468
468
  "postinstall": "node scripts/postinstall.mjs || true",
@@ -47,6 +47,13 @@ export const BLOCK_CATEGORIES: string[] = []
47
47
 
48
48
  export const BLOCK_COMPONENTS: Record<string, React.LazyExoticComponent<React.ComponentType<unknown>>> = {}
49
49
 
50
+ /**
51
+ * Direct-imported block components for SSR rendering
52
+ * No React.lazy, no Suspense — HTML is fully visible without JS
53
+ */
54
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
+ export const BLOCK_COMPONENTS_SSR: Record<string, React.ComponentType<any>> = {}
56
+
50
57
  export const BLOCK_METADATA = {
51
58
  totalBlocks: 0,
52
59
  categories: [],
@@ -59,6 +66,8 @@ export const BLOCK_METADATA = {
59
66
 
60
67
  // Import field definitions and examples (if they exist)
61
68
  const imports = []
69
+ // Direct component imports for SSR (no React.lazy)
70
+ const ssrImports = []
62
71
 
63
72
  blocks.forEach(block => {
64
73
  const slugVar = block.slug.replace(/-/g, '_')
@@ -66,6 +75,9 @@ export const BLOCK_METADATA = {
66
75
  // Always import field definitions
67
76
  imports.push(`import { fieldDefinitions as ${slugVar}_fields } from '${block.paths.fields}'`)
68
77
 
78
+ // Direct component import for SSR rendering
79
+ ssrImports.push(`import { default as ${slugVar}_component } from '${block.paths.component}'`)
80
+
69
81
  // Conditionally import examples if they exist
70
82
  if (block.hasExamples) {
71
83
  imports.push(`import { examples as ${slugVar}_examples } from '${block.paths.examples}'`)
@@ -73,6 +85,7 @@ export const BLOCK_METADATA = {
73
85
  })
74
86
 
75
87
  const fieldImports = imports.join('\n')
88
+ const ssrComponentImports = ssrImports.join('\n')
76
89
 
77
90
  const registryEntries = blocks.map(block => {
78
91
  const slugVar = block.slug.replace(/-/g, '_')
@@ -124,6 +137,9 @@ import type { BlockConfig, BlockCategory } from '${convertCorePath('@/core/types
124
137
 
125
138
  ${fieldImports}
126
139
 
140
+ // Direct component imports for SSR (no React.lazy, no Suspense needed)
141
+ ${ssrComponentImports}
142
+
127
143
  export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
128
144
  ${registryEntries}
129
145
  }
@@ -141,6 +157,19 @@ ${blocks.map(block => {
141
157
  }).join(',\n')}
142
158
  }
143
159
 
160
+ /**
161
+ * Direct-imported block components for SSR rendering
162
+ * No React.lazy, no Suspense — HTML is fully visible without JS.
163
+ * Use with SSRPageRenderer for public pages where SEO and no-JS rendering matter.
164
+ */
165
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
166
+ export const BLOCK_COMPONENTS_SSR: Record<string, React.ComponentType<any>> = {
167
+ ${blocks.map(block => {
168
+ const slugVar = block.slug.replace(/-/g, '_')
169
+ return ` '${block.slug}': ${slugVar}_component`
170
+ }).join(',\n')}
171
+ }
172
+
144
173
  /**
145
174
  * Block registry metadata
146
175
  */
@@ -133,7 +133,7 @@ export interface PluginRegistryEntry {
133
133
  hasAssets: boolean
134
134
  }
135
135
 
136
- export const PLUGIN_REGISTRY = {
136
+ export const PLUGIN_REGISTRY: Record<string, PluginRegistryEntry> = {
137
137
  ${registryEntries}
138
138
  }
139
139
 
@@ -68,7 +68,7 @@ function AcceptInvitePage() {
68
68
  }
69
69
 
70
70
  // Check email match
71
- if (user.email.toLowerCase() !== data.data.email.toLowerCase()) {
71
+ if ((user.email ?? '').toLowerCase() !== data.data.email.toLowerCase()) {
72
72
  setStatus('email_mismatch')
73
73
  setErrorMessage(`This invitation was sent to ${data.data.email}, but you are logged in as ${user.email}`)
74
74
  return
@@ -22,7 +22,15 @@ import { query, queryOne } from '@nextsparkjs/core/lib/db'
22
22
  import { getBillingGateway } from '@nextsparkjs/core/lib/billing/gateways/factory'
23
23
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
24
24
  import type { PolarWebhookExtensions } from '@nextsparkjs/core/lib/billing/polar-webhook'
25
- import { polarWebhookExtensions } from '@/lib/billing/polar-webhook-extensions'
25
+
26
+ async function loadExtensions(): Promise<PolarWebhookExtensions> {
27
+ try {
28
+ const mod = await import('@/lib/billing/polar-webhook-extensions')
29
+ return mod.polarWebhookExtensions
30
+ } catch {
31
+ return {}
32
+ }
33
+ }
26
34
 
27
35
  async function handlePolarWebhook(request: NextRequest) {
28
36
  // 1. Get raw body and ALL headers (Polar needs full headers for verification)
@@ -86,7 +94,7 @@ async function handlePolarWebhook(request: NextRequest) {
86
94
  break
87
95
 
88
96
  case 'order.paid':
89
- await handleOrderPaid(event.data, eventId, polarWebhookExtensions)
97
+ await handleOrderPaid(event.data, eventId, await loadExtensions())
90
98
  break
91
99
 
92
100
  default:
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Handles Stripe subscription lifecycle events.
5
5
  * To add one-time payment handling (credit packs, LTD, upsells),
6
- * override lib/billing/stripe-webhook-extensions.ts in your project.
6
+ * create lib/billing/stripe-webhook-extensions.ts in your project.
7
7
  *
8
8
  * Rate limiting: 500 requests/hour per IP (tier: webhook).
9
9
  * Stripe signature verification is the primary security layer;
@@ -14,12 +14,21 @@
14
14
 
15
15
  import { NextRequest } from 'next/server'
16
16
  import { handleStripeWebhook } from '@nextsparkjs/core/lib/billing/stripe-webhook'
17
- import { stripeWebhookExtensions } from '@/lib/billing/stripe-webhook-extensions'
18
17
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
19
18
 
19
+ async function loadExtensions() {
20
+ try {
21
+ const mod = await import('@/lib/billing/stripe-webhook-extensions')
22
+ return mod.stripeWebhookExtensions
23
+ } catch {
24
+ return {}
25
+ }
26
+ }
27
+
20
28
  export const POST = withRateLimitTier(
21
29
  async (request: NextRequest) => {
22
- return handleStripeWebhook(request, stripeWebhookExtensions)
30
+ const extensions = await loadExtensions()
31
+ return handleStripeWebhook(request, extensions)
23
32
  },
24
33
  'webhook'
25
34
  )
@@ -6,6 +6,8 @@ export const BLOCK_REGISTRY: Record<string, any> = {}
6
6
 
7
7
  export const BLOCK_COMPONENTS: Record<string, any> = {}
8
8
 
9
+ export const BLOCK_COMPONENTS_SSR: Record<string, any> = {}
10
+
9
11
  export const BLOCK_METADATA = {
10
12
  generated: new Date().toISOString(),
11
13
  totalBlocks: 0,