@nextsparkjs/core 0.1.0-beta.4 → 0.1.0-beta.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.
Files changed (31) hide show
  1. package/dist/components/entities/wrappers/EntityDetailWrapper.d.ts.map +1 -1
  2. package/dist/components/entities/wrappers/EntityDetailWrapper.js +23 -72
  3. package/dist/components/public/index.d.ts +10 -0
  4. package/dist/components/public/index.d.ts.map +1 -0
  5. package/dist/components/public/index.js +2 -0
  6. package/dist/components/public/pageBuilder/PageRenderer.d.ts +20 -0
  7. package/dist/components/public/pageBuilder/PageRenderer.d.ts.map +1 -0
  8. package/dist/components/public/pageBuilder/PageRenderer.js +41 -0
  9. package/dist/components/public/pageBuilder/index.d.ts +10 -0
  10. package/dist/components/public/pageBuilder/index.d.ts.map +1 -0
  11. package/dist/components/public/pageBuilder/index.js +4 -0
  12. package/dist/lib/email/factory.d.ts.map +1 -1
  13. package/dist/lib/email/factory.js +2 -1
  14. package/dist/lib/entities/queries.d.ts +1 -1
  15. package/dist/lib/entities/queries.d.ts.map +1 -1
  16. package/dist/lib/entities/queries.js +2 -2
  17. package/dist/messages/es/index.d.ts +23 -0
  18. package/dist/messages/es/index.d.ts.map +1 -1
  19. package/dist/messages/es/teams.json +27 -1
  20. package/dist/styles/classes.json +1 -1
  21. package/dist/templates/app/(public)/[...slug]/page.tsx +1 -1
  22. package/package.json +9 -1
  23. package/scripts/build/registry/post-build/page-generator.mjs +5 -3
  24. package/scripts/build/registry/post-build/route-cleanup.mjs +16 -7
  25. package/scripts/build/registry/watch.mjs +1 -1
  26. package/scripts/build/registry.mjs +6 -2
  27. package/templates/app/(public)/[...slug]/page.tsx +1 -1
  28. package/dist/templates/app/components/page-renderer.d.ts.map +0 -1
  29. package/dist/templates/app/components/page-renderer.tsx +0 -89
  30. package/templates/app/components/page-renderer.d.ts.map +0 -1
  31. package/templates/app/components/page-renderer.tsx +0 -89
@@ -1 +1 @@
1
- {"version":3,"file":"EntityDetailWrapper.d.ts","sourceRoot":"","sources":["../../../../src/components/entities/wrappers/EntityDetailWrapper.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAoD,MAAM,OAAO,CAAA;AAYxE,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAA;CAChE;AAED,wBAAgB,mBAAmB,CAAC,EAClC,UAAU,EACV,EAAE,EACF,gBAAqB,EACrB,OAAO,EACP,SAAS,EACT,oBAAyB,GAC1B,EAAE,wBAAwB,2CA8d1B"}
1
+ {"version":3,"file":"EntityDetailWrapper.d.ts","sourceRoot":"","sources":["../../../../src/components/entities/wrappers/EntityDetailWrapper.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAoD,MAAM,OAAO,CAAA;AAYxE,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAA;CAChE;AAED,wBAAgB,mBAAmB,CAAC,EAClC,UAAU,EACV,EAAE,EACF,gBAAqB,EACrB,OAAO,EACP,SAAS,EACT,oBAAyB,GAC1B,EAAE,wBAAwB,2CA4a1B"}
@@ -1,10 +1,8 @@
1
1
  "use client";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { jsx } from "react/jsx-runtime";
3
3
  import React, { useState, useEffect, useCallback, useMemo } from "react";
4
4
  import { EntityDetail } from "../EntityDetail";
5
5
  import { Alert, AlertDescription } from "../../ui/alert";
6
- import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../../ui/dialog";
7
- import { Button } from "../../ui/button";
8
6
  import { SkeletonEntityDetail } from "../../ui/skeleton-detail";
9
7
  import { useEntityConfig } from "../../../hooks/useEntityConfig";
10
8
  import { useRouter } from "next/navigation";
@@ -25,8 +23,6 @@ function EntityDetailWrapper({
25
23
  const [isLoadingData, setIsLoadingData] = useState(false);
26
24
  const [dataError, setDataError] = useState(null);
27
25
  const hasChildEntities = childEntityNames.length > 0;
28
- const [parentDeleteConfirmation, setParentDeleteConfirmation] = useState(false);
29
- const [isDeletingParent, setIsDeletingParent] = useState(false);
30
26
  const customSections = useMemo(() => {
31
27
  const sections = [];
32
28
  if (entityType === "teams") {
@@ -153,26 +149,15 @@ function EntityDetailWrapper({
153
149
  router.push(`/dashboard/${entityConfig == null ? void 0 : entityConfig.slug}/${id}/edit`);
154
150
  }, [router, entityConfig, id]);
155
151
  const handleDelete = useCallback(async () => {
156
- setParentDeleteConfirmation(true);
157
- return new Promise(() => {
158
- });
159
- }, []);
160
- const handleConfirmParentDelete = useCallback(async () => {
161
- setParentDeleteConfirmation(false);
162
- setIsDeletingParent(true);
163
152
  try {
164
153
  await deleteEntityData(entityType, id);
165
154
  router.push(`/dashboard/${(entityConfig == null ? void 0 : entityConfig.slug) || entityType}`);
166
155
  } catch (error) {
167
156
  console.error("Error deleting entity:", error);
168
157
  onError == null ? void 0 : onError(error instanceof Error ? error : new Error("Error deleting entity"));
169
- } finally {
170
- setIsDeletingParent(false);
158
+ throw error;
171
159
  }
172
160
  }, [entityType, id, router, entityConfig, onError]);
173
- const handleCancelParentDelete = useCallback(() => {
174
- setParentDeleteConfirmation(false);
175
- }, []);
176
161
  const handleRefresh = useCallback(async () => {
177
162
  if (!entityConfig || !id) return;
178
163
  try {
@@ -320,61 +305,27 @@ function EntityDetailWrapper({
320
305
  if (!data) {
321
306
  return /* @__PURE__ */ jsx(Alert, { children: /* @__PURE__ */ jsx(AlertDescription, { children: "No se encontraron datos para esta entidad." }) });
322
307
  }
323
- return /* @__PURE__ */ jsxs(Fragment, { children: [
324
- /* @__PURE__ */ jsx(
325
- EntityDetail,
326
- {
327
- entityConfig,
328
- data,
329
- childData,
330
- childEntityNames,
331
- isLoading: isLoadingData,
332
- error: dataError,
333
- onEdit: handleEdit,
334
- onDelete: handleDelete,
335
- onChildAdd: handleChildAdd,
336
- onChildEdit: handleChildEdit,
337
- onChildDelete: handleChildDelete,
338
- onRefresh: handleRefresh,
339
- enableActions: true,
340
- className,
341
- customFormComponents,
342
- customSections
343
- }
344
- ),
345
- /* @__PURE__ */ jsx(Dialog, { open: parentDeleteConfirmation, onOpenChange: (open) => !open && handleCancelParentDelete(), children: /* @__PURE__ */ jsxs(DialogContent, { children: [
346
- /* @__PURE__ */ jsxs(DialogHeader, { children: [
347
- /* @__PURE__ */ jsx(DialogTitle, { children: "Confirmar Eliminaci\xF3n" }),
348
- /* @__PURE__ */ jsxs(DialogDescription, { children: [
349
- "\xBFEst\xE1s seguro de que quieres eliminar este ",
350
- entityConfig == null ? void 0 : entityConfig.names.singular.toLowerCase(),
351
- "? Esta acci\xF3n eliminar\xE1 permanentemente toda la informaci\xF3n y no se puede deshacer."
352
- ] })
353
- ] }),
354
- /* @__PURE__ */ jsxs(DialogFooter, { children: [
355
- /* @__PURE__ */ jsx(
356
- Button,
357
- {
358
- variant: "outline",
359
- onClick: handleCancelParentDelete,
360
- disabled: isDeletingParent,
361
- "data-cy": "cancel-delete",
362
- children: "Cancelar"
363
- }
364
- ),
365
- /* @__PURE__ */ jsx(
366
- Button,
367
- {
368
- variant: "destructive",
369
- onClick: handleConfirmParentDelete,
370
- disabled: isDeletingParent,
371
- "data-cy": "confirm-delete",
372
- children: isDeletingParent ? "Eliminando..." : "Eliminar"
373
- }
374
- )
375
- ] })
376
- ] }) })
377
- ] });
308
+ return /* @__PURE__ */ jsx(
309
+ EntityDetail,
310
+ {
311
+ entityConfig,
312
+ data,
313
+ childData,
314
+ childEntityNames,
315
+ isLoading: isLoadingData,
316
+ error: dataError,
317
+ onEdit: handleEdit,
318
+ onDelete: handleDelete,
319
+ onChildAdd: handleChildAdd,
320
+ onChildEdit: handleChildEdit,
321
+ onChildDelete: handleChildDelete,
322
+ onRefresh: handleRefresh,
323
+ enableActions: true,
324
+ className,
325
+ customFormComponents,
326
+ customSections
327
+ }
328
+ );
378
329
  }
379
330
  export {
380
331
  EntityDetailWrapper
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Public Components
3
+ *
4
+ * Components for rendering content on public-facing pages.
5
+ *
6
+ * @module core/components/public
7
+ */
8
+ export * from './pageBuilder';
9
+ export * from './entities';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/public/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA"}
@@ -0,0 +1,2 @@
1
+ export * from "./pageBuilder";
2
+ export * from "./entities";
@@ -0,0 +1,20 @@
1
+ /**
2
+ * PageRenderer Component
3
+ *
4
+ * Renders pages from the Page Builder by iterating over blocks
5
+ * and dynamically loading block components from the registry.
6
+ *
7
+ * @module core/components/public/pageBuilder
8
+ */
9
+ import type { BlockInstance } from '../../../types/blocks';
10
+ export interface PageRendererProps {
11
+ page: {
12
+ id: string;
13
+ title: string;
14
+ slug: string;
15
+ blocks: BlockInstance[];
16
+ locale: string;
17
+ };
18
+ }
19
+ export declare function PageRenderer({ page }: PageRendererProps): import("react/jsx-runtime").JSX.Element;
20
+ //# sourceMappingURL=PageRenderer.d.ts.map
@@ -0,0 +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,2CA0BvD"}
@@ -0,0 +1,41 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Suspense } from "react";
3
+ import { getBlockComponent, normalizeBlockProps } from "../../../lib/blocks/loader";
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
+ }
11
+ function BlockError({ blockSlug }) {
12
+ 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
+ /* @__PURE__ */ jsxs("p", { className: "text-destructive", children: [
14
+ "Failed to load block: ",
15
+ /* @__PURE__ */ jsx("code", { className: "font-mono", children: blockSlug })
16
+ ] }),
17
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-2", children: "This block may not be available or there was an error rendering it." })
18
+ ] }) });
19
+ }
20
+ function BlockRenderer({ block }) {
21
+ const BlockComponent = getBlockComponent(block.blockSlug);
22
+ if (!BlockComponent) {
23
+ console.warn(`Block component not found for slug: ${block.blockSlug}`);
24
+ return /* @__PURE__ */ jsx(BlockError, { blockSlug: block.blockSlug });
25
+ }
26
+ const normalizedProps = normalizeBlockProps(block.props);
27
+ return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(BlockSkeleton, {}), children: /* @__PURE__ */ jsx(BlockComponent, { ...normalizedProps }) });
28
+ }
29
+ function PageRenderer({ page }) {
30
+ const blocks = Array.isArray(page.blocks) ? page.blocks : [];
31
+ if (blocks.length === 0) {
32
+ return /* @__PURE__ */ jsx("div", { className: "min-h-screen flex items-center justify-center bg-muted/10", children: /* @__PURE__ */ jsxs("div", { className: "text-center max-w-md mx-auto px-4", children: [
33
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold mb-2", children: page.title }),
34
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "This page does not have any content yet." })
35
+ ] }) });
36
+ }
37
+ return /* @__PURE__ */ jsx("div", { className: "min-h-screen", "data-page-id": page.id, "data-page-slug": page.slug, children: blocks.map((block) => /* @__PURE__ */ jsx("div", { "data-block-id": block.id, "data-block-slug": block.blockSlug, children: /* @__PURE__ */ jsx(BlockRenderer, { block }) }, block.id)) });
38
+ }
39
+ export {
40
+ PageRenderer
41
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Page Builder Public Components
3
+ *
4
+ * Components for rendering page builder content on public-facing pages.
5
+ *
6
+ * @module core/components/public/pageBuilder
7
+ */
8
+ export { PageRenderer } from './PageRenderer';
9
+ export type { PageRendererProps } from './PageRenderer';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/public/pageBuilder/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1,4 @@
1
+ import { PageRenderer } from "./PageRenderer";
2
+ export {
3
+ PageRenderer
4
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/lib/email/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAI7C,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAE9D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE;QACf,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;KAC9C,CAAC;CACH;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA8B;IAErD,MAAM,CAAC,MAAM,CAAC,OAAO,GAAE,mBAAwB,GAAG,aAAa;IAiD/D,MAAM,CAAC,WAAW,IAAI,aAAa;IAOnC,MAAM,CAAC,KAAK,IAAI,IAAI;CAGrB"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/lib/email/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAI7C,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAE9D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE;QACf,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;KAC9C,CAAC;CACH;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA8B;IAErD,MAAM,CAAC,MAAM,CAAC,OAAO,GAAE,mBAAwB,GAAG,aAAa;IAoD/D,MAAM,CAAC,WAAW,IAAI,aAAa;IAOnC,MAAM,CAAC,KAAK,IAAI,IAAI;CAGrB"}
@@ -3,8 +3,9 @@ import { ConsoleProvider } from "./providers/console";
3
3
  class EmailFactory {
4
4
  static instance = null;
5
5
  static create(options = {}) {
6
+ const envProvider = process.env.EMAIL_PROVIDER;
6
7
  const {
7
- provider = "auto",
8
+ provider = envProvider || "auto",
8
9
  resendApiKey = process.env.RESEND_API_KEY,
9
10
  defaultFrom,
10
11
  consoleOptions
@@ -99,7 +99,7 @@ export declare function getEntityOwner(entityName: string): EntityOwner | null;
99
99
  /**
100
100
  * Get entity by slug
101
101
  */
102
- export declare function getEntityBySlug(slug: string): EntityConfig | ChildEntityDefinition | undefined;
102
+ export declare function getEntityBySlug(slug: string): EntityConfig | undefined;
103
103
  /**
104
104
  * Get entity metadata (totals, counts, etc.)
105
105
  */
@@ -1 +1 @@
1
- {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../../src/lib/entities/queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAElE;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,YAAY,GAAG,qBAAqB,CAAA;IAC5C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE;QACd,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,MAAM,CAAA;KAClB,CAAA;IACD,YAAY,CAAC,EAAE;QACb,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;IACD,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,SAAS,CAAC,EAAE,GAAG,CAAA;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAA;IACxB,IAAI,EAAE,MAAM,CAAA;CACb;AAwBD;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,CAAC,YAAY,GAAG,qBAAqB,CAAC,EAAE,CAEhF;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,qBAAqB,GAAG,SAAS,CAExF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAE/E;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,mBAAmB,EAAE,CAEvD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAE1E;AAED,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC;IAC3E,UAAU,EAAE,cAAc,EAAE,CAAA;CAC7B;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,cAAc,EAAE,CAMhD;AAUD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAEvE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEnE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAEvF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAI3E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAIzE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAWrE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,qBAAqB,GAAG,SAAS,CAG9F;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,sBAAsB,GAAG,IAAI,CAIzE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAEvE"}
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../../src/lib/entities/queries.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAElE;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,YAAY,GAAG,qBAAqB,CAAA;IAC5C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE;QACd,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,MAAM,CAAA;KAClB,CAAA;IACD,YAAY,CAAC,EAAE;QACb,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;IACD,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,SAAS,CAAC,EAAE,GAAG,CAAA;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAA;IACxB,IAAI,EAAE,MAAM,CAAA;CACb;AAwBD;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,CAAC,YAAY,GAAG,qBAAqB,CAAC,EAAE,CAEhF;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,qBAAqB,GAAG,SAAS,CAExF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAE/E;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,mBAAmB,EAAE,CAEvD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAE1E;AAED,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC;IAC3E,UAAU,EAAE,cAAc,EAAE,CAAA;CAC7B;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,cAAc,EAAE,CAMhD;AAUD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAEvE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEnE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAEvF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAI3E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAIzE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAWrE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAItE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,sBAAsB,GAAG,IAAI,CAIzE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAEvE"}
@@ -80,8 +80,8 @@ function getEntityOwner(entityName) {
80
80
  return null;
81
81
  }
82
82
  function getEntityBySlug(slug) {
83
- var _a;
84
- return (_a = Object.values(getRegistry()).find((entry) => entry.config.slug === slug)) == null ? void 0 : _a.config;
83
+ const entry = Object.values(getRegistry()).find((entry2) => "slug" in entry2.config && entry2.config.slug === slug);
84
+ return entry == null ? void 0 : entry.config;
85
85
  }
86
86
  function getEntityRegistryMetadata() {
87
87
  getRegistry();
@@ -1759,6 +1759,18 @@ declare const _default: {
1759
1759
  readonly teams: {
1760
1760
  title: string;
1761
1761
  description: string;
1762
+ entity: {
1763
+ description: string;
1764
+ plural: string;
1765
+ };
1766
+ fields: {
1767
+ name: string;
1768
+ slug: string;
1769
+ description: string;
1770
+ email: string;
1771
+ role: string;
1772
+ joinedAt: string;
1773
+ };
1762
1774
  types: {
1763
1775
  personal: string;
1764
1776
  work: string;
@@ -1785,6 +1797,8 @@ declare const _default: {
1785
1797
  invite: string;
1786
1798
  removeMember: string;
1787
1799
  changeRole: string;
1800
+ makeRole: string;
1801
+ cancel: string;
1788
1802
  };
1789
1803
  switcher: {
1790
1804
  switchTeam: string;
@@ -1832,11 +1846,17 @@ declare const _default: {
1832
1846
  invitations: {
1833
1847
  title: string;
1834
1848
  description: string;
1849
+ pending: string;
1835
1850
  empty: string;
1836
1851
  sent: string;
1837
1852
  expires: string;
1853
+ expiresAt: string;
1854
+ invitedBy: string;
1838
1855
  resend: string;
1839
1856
  cancel: string;
1857
+ cancelTitle: string;
1858
+ cancelDescription: string;
1859
+ cancelConfirm: string;
1840
1860
  cancelSuccess: string;
1841
1861
  cancelError: string;
1842
1862
  };
@@ -1868,6 +1888,9 @@ declare const _default: {
1868
1888
  billing: string;
1869
1889
  danger: string;
1870
1890
  };
1891
+ messages: {
1892
+ loading: string;
1893
+ };
1871
1894
  errors: {
1872
1895
  notFound: string;
1873
1896
  notMember: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/messages/es/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBA,wBAmBU"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/messages/es/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBA,wBAmBU"}
@@ -2,6 +2,20 @@
2
2
  "title": "Equipos",
3
3
  "description": "Administra tus equipos y colaboraciones",
4
4
 
5
+ "entity": {
6
+ "description": "Gestiona tus equipos, miembros e invitaciones",
7
+ "plural": "Equipos"
8
+ },
9
+
10
+ "fields": {
11
+ "name": "Nombre",
12
+ "slug": "URL",
13
+ "description": "Descripción",
14
+ "email": "Correo electrónico",
15
+ "role": "Rol",
16
+ "joinedAt": "Fecha de ingreso"
17
+ },
18
+
5
19
  "types": {
6
20
  "personal": "Personal",
7
21
  "work": "Equipo de Trabajo"
@@ -30,7 +44,9 @@
30
44
  "manage": "Gestionar Equipo",
31
45
  "invite": "Invitar Miembro",
32
46
  "removeMember": "Eliminar Miembro",
33
- "changeRole": "Cambiar Rol"
47
+ "changeRole": "Cambiar Rol",
48
+ "makeRole": "Hacer {role}",
49
+ "cancel": "Cancelar"
34
50
  },
35
51
 
36
52
  "switcher": {
@@ -84,11 +100,17 @@
84
100
  "invitations": {
85
101
  "title": "Invitaciones Pendientes",
86
102
  "description": "Invitaciones esperando respuesta",
103
+ "pending": "Pendiente",
87
104
  "empty": "Sin invitaciones pendientes",
88
105
  "sent": "Enviada {date}",
89
106
  "expires": "Expira {date}",
107
+ "expiresAt": "Expira",
108
+ "invitedBy": "Invitado por",
90
109
  "resend": "Reenviar",
91
110
  "cancel": "Cancelar Invitacion",
111
+ "cancelTitle": "Cancelar Invitacion",
112
+ "cancelDescription": "¿Estas seguro de que deseas cancelar esta invitacion?",
113
+ "cancelConfirm": "Si, Cancelar",
92
114
  "cancelSuccess": "Invitacion cancelada",
93
115
  "cancelError": "Error al cancelar la invitacion"
94
116
  },
@@ -124,6 +146,10 @@
124
146
  "danger": "Zona de Peligro"
125
147
  },
126
148
 
149
+ "messages": {
150
+ "loading": "Cargando..."
151
+ },
152
+
127
153
  "errors": {
128
154
  "notFound": "Equipo no encontrado",
129
155
  "notMember": "No eres miembro de este equipo",
@@ -1,5 +1,5 @@
1
1
  {
2
- "generated": "2026-01-06T01:15:14.655Z",
2
+ "generated": "2026-01-06T22:36:13.387Z",
3
3
  "totalClasses": 999,
4
4
  "classes": [
5
5
  "''",
@@ -15,7 +15,7 @@
15
15
 
16
16
  import { notFound } from 'next/navigation'
17
17
  import { query } from '@nextsparkjs/core/lib/db'
18
- import { PageRenderer } from '@/app/components/page-renderer'
18
+ import { PageRenderer } from '@nextsparkjs/core/components/public/pageBuilder'
19
19
  import {
20
20
  matchPathToEntity,
21
21
  getEntityBasePath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextsparkjs/core",
3
- "version": "0.1.0-beta.4",
3
+ "version": "0.1.0-beta.6",
4
4
  "description": "NextSpark - The complete SaaS framework for Next.js",
5
5
  "license": "MIT",
6
6
  "author": "NextSpark <hello@nextspark.dev>",
@@ -154,6 +154,14 @@
154
154
  "types": "./dist/components/public/entities/index.d.ts",
155
155
  "import": "./dist/components/public/entities/index.js"
156
156
  },
157
+ "./components/public/pageBuilder": {
158
+ "types": "./dist/components/public/pageBuilder/index.d.ts",
159
+ "import": "./dist/components/public/pageBuilder/index.js"
160
+ },
161
+ "./components/public": {
162
+ "types": "./dist/components/public/index.d.ts",
163
+ "import": "./dist/components/public/index.js"
164
+ },
157
165
  "./components/superadmin/filters": {
158
166
  "types": "./dist/components/superadmin/filters/index.d.ts",
159
167
  "import": "./dist/components/superadmin/filters/index.js"
@@ -16,8 +16,8 @@ import { cleanupOrphanedTemplates } from './route-cleanup.mjs'
16
16
 
17
17
  const __filename = fileURLToPath(import.meta.url)
18
18
  const __dirname = dirname(__filename)
19
- // Default rootDir for backwards compatibility (will be overridden by config)
20
- let rootDir = join(__dirname, '../../../../../..')
19
+ // Default rootDir - use cwd() for NPM compatibility (will be overridden by config.projectRoot if provided)
20
+ let rootDir = process.cwd()
21
21
 
22
22
  /**
23
23
  * Convert string to PascalCase
@@ -348,7 +348,9 @@ export async function generateMissingPages(templates, config = null) {
348
348
  const templatesDir = join(rootDir, 'app', '(templates)')
349
349
 
350
350
  // First, clean up orphaned files before generating new ones
351
- await cleanupOrphanedTemplates(templates)
351
+ // Note: This is also called in registry.mjs before generateMissingPages,
352
+ // but we keep it here for standalone usage of this function
353
+ await cleanupOrphanedTemplates(templates, config)
352
354
 
353
355
  if (templates.length === 0) {
354
356
  return
@@ -15,13 +15,13 @@ import { log, verbose } from '../../../utils/index.mjs'
15
15
 
16
16
  const __filename = fileURLToPath(import.meta.url)
17
17
  const __dirname = dirname(__filename)
18
- // Path from packages/core/scripts/build/registry/post-build/ to project root (6 levels up)
19
- const rootDir = join(__dirname, '../../../../../..')
20
18
 
21
19
  /**
22
20
  * Clean up old generated route files
21
+ * @param {object} CONFIG - Configuration object from getConfig()
23
22
  */
24
- export async function cleanupOldRouteFiles() {
23
+ export async function cleanupOldRouteFiles(CONFIG) {
24
+ const rootDir = CONFIG?.projectRoot || process.cwd()
25
25
  const appApiDir = join(rootDir, 'app', 'api', 'v1', 'plugin')
26
26
 
27
27
  try {
@@ -56,8 +56,11 @@ export async function cleanupOldRouteFiles() {
56
56
  /**
57
57
  * Clean up orphaned template files that no longer have corresponding templates
58
58
  * Removes files from app/(templates)/ when their source templates are deleted
59
+ * @param {object[]} activeTemplates - List of active templates from discovery
60
+ * @param {object} CONFIG - Configuration object from getConfig()
59
61
  */
60
- export async function cleanupOrphanedTemplates(activeTemplates) {
62
+ export async function cleanupOrphanedTemplates(activeTemplates, CONFIG) {
63
+ const rootDir = CONFIG?.projectRoot || process.cwd()
61
64
  const templatesDir = join(rootDir, 'app', '(templates)')
62
65
  if (!existsSync(templatesDir)) {
63
66
  return
@@ -136,8 +139,11 @@ export async function cleanupOrphanedTemplates(activeTemplates) {
136
139
  /**
137
140
  * Map template file path to generated app template path
138
141
  * contents/themes/content-buddy/templates/(public)/pricing/page.tsx → app/(templates)/(public)/pricing/page.tsx
142
+ * @param {string} templateFilePath - Full path to the template file
143
+ * @param {object} CONFIG - Configuration object from getConfig()
139
144
  */
140
- export function mapTemplateToAppPath(templateFilePath) {
145
+ export function mapTemplateToAppPath(templateFilePath, CONFIG) {
146
+ const rootDir = CONFIG?.projectRoot || process.cwd()
141
147
  // Extract the part after /templates/
142
148
  const templatesMatch = templateFilePath.match(/\/themes\/[^\/]+\/templates\/(.+)$/)
143
149
  if (!templatesMatch) {
@@ -150,9 +156,12 @@ export function mapTemplateToAppPath(templateFilePath) {
150
156
 
151
157
  /**
152
158
  * Clean up generated template files when original templates are deleted
159
+ * @param {string} templateFilePath - Full path to the template file
160
+ * @param {object} CONFIG - Configuration object from getConfig()
153
161
  */
154
- export async function cleanupDeletedTemplate(templateFilePath) {
155
- const appTemplatePath = mapTemplateToAppPath(templateFilePath)
162
+ export async function cleanupDeletedTemplate(templateFilePath, CONFIG) {
163
+ const rootDir = CONFIG?.projectRoot || process.cwd()
164
+ const appTemplatePath = mapTemplateToAppPath(templateFilePath, CONFIG)
156
165
  if (!appTemplatePath || !existsSync(appTemplatePath)) {
157
166
  return
158
167
  }
@@ -101,7 +101,7 @@ export async function watchContents(buildRegistries) {
101
101
  // File was deleted (was tracked but no longer exists)
102
102
  if (wasTracked && !currentlyExists) {
103
103
  log(`Template deleted: ${filename}`, 'info')
104
- await cleanupDeletedTemplate(fullTemplatePath)
104
+ await cleanupDeletedTemplate(fullTemplatePath, CONFIG)
105
105
  templateFileTracker.delete(filename)
106
106
  }
107
107
  // File was added (exists but wasn't tracked)
@@ -68,7 +68,8 @@ import {
68
68
  displayTreeStructure,
69
69
  generateTestEntitiesJson,
70
70
  generateTestBlocksJson,
71
- cleanupOldRouteFiles
71
+ cleanupOldRouteFiles,
72
+ cleanupOrphanedTemplates
72
73
  } from './registry/post-build/index.mjs'
73
74
  import { watchContents } from './registry/watch.mjs'
74
75
 
@@ -198,7 +199,10 @@ export async function buildRegistries(projectRoot = null) {
198
199
  displayTreeStructure(plugins, entities, themes)
199
200
 
200
201
  // Clean up old generated route files first
201
- await cleanupOldRouteFiles()
202
+ await cleanupOldRouteFiles(CONFIG)
203
+
204
+ // Clean up orphaned template files from previous theme builds
205
+ await cleanupOrphanedTemplates(templates, CONFIG)
202
206
 
203
207
  // Hoist plugin dependencies to root workspace for proper resolution
204
208
  // Generate all registry files (use aggregated entities for entity registry + blocks)
@@ -15,7 +15,7 @@
15
15
 
16
16
  import { notFound } from 'next/navigation'
17
17
  import { query } from '@nextsparkjs/core/lib/db'
18
- import { PageRenderer } from '@/app/components/page-renderer'
18
+ import { PageRenderer } from '@nextsparkjs/core/components/public/pageBuilder'
19
19
  import {
20
20
  matchPathToEntity,
21
21
  getEntityBasePath,
@@ -1 +0,0 @@
1
- {"version":3,"file":"page-renderer.d.ts","sourceRoot":"","sources":["page-renderer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAmDxD,UAAU,iBAAiB;IACzB,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,+BA0BvD"}
@@ -1,89 +0,0 @@
1
- import { Suspense } from 'react'
2
- import type { BlockInstance } from '@nextsparkjs/core/types/blocks'
3
- import { getBlockComponent, normalizeBlockProps } from '@nextsparkjs/core/lib/blocks/loader'
4
-
5
- // Loading skeleton for blocks
6
- function BlockSkeleton() {
7
- return (
8
- <div className="w-full py-12 px-4 animate-pulse">
9
- <div className="max-w-7xl mx-auto">
10
- <div className="h-8 bg-muted rounded w-3/4 mb-4" />
11
- <div className="h-4 bg-muted rounded w-full mb-2" />
12
- <div className="h-4 bg-muted rounded w-5/6" />
13
- </div>
14
- </div>
15
- )
16
- }
17
-
18
- // Error boundary for individual blocks
19
- function BlockError({ blockSlug }: { blockSlug: string }) {
20
- return (
21
- <div className="w-full py-12 px-4 bg-destructive/10 border border-destructive/20 rounded">
22
- <div className="max-w-7xl mx-auto text-center">
23
- <p className="text-destructive">
24
- Failed to load block: <code className="font-mono">{blockSlug}</code>
25
- </p>
26
- <p className="text-sm text-muted-foreground mt-2">
27
- This block may not be available or there was an error rendering it.
28
- </p>
29
- </div>
30
- </div>
31
- )
32
- }
33
-
34
- // Individual block renderer with error boundary
35
- function BlockRenderer({ block }: { block: BlockInstance }) {
36
- const BlockComponent = getBlockComponent(block.blockSlug)
37
-
38
- if (!BlockComponent) {
39
- console.warn(`Block component not found for slug: ${block.blockSlug}`)
40
- return <BlockError blockSlug={block.blockSlug} />
41
- }
42
-
43
- // Normalize props to convert dot-notation to nested objects
44
- const normalizedProps = normalizeBlockProps(block.props)
45
-
46
- return (
47
- <Suspense fallback={<BlockSkeleton />}>
48
- <BlockComponent {...normalizedProps} />
49
- </Suspense>
50
- )
51
- }
52
-
53
- interface PageRendererProps {
54
- page: {
55
- id: string
56
- title: string
57
- slug: string
58
- blocks: BlockInstance[]
59
- locale: string
60
- }
61
- }
62
-
63
- export function PageRenderer({ page }: PageRendererProps) {
64
- // Ensure blocks is an array
65
- const blocks = Array.isArray(page.blocks) ? page.blocks : []
66
-
67
- if (blocks.length === 0) {
68
- return (
69
- <div className="min-h-screen flex items-center justify-center bg-muted/10">
70
- <div className="text-center max-w-md mx-auto px-4">
71
- <h1 className="text-2xl font-bold mb-2">{page.title}</h1>
72
- <p className="text-muted-foreground">
73
- This page does not have any content yet.
74
- </p>
75
- </div>
76
- </div>
77
- )
78
- }
79
-
80
- return (
81
- <div className="min-h-screen" data-page-id={page.id} data-page-slug={page.slug}>
82
- {blocks.map((block) => (
83
- <div key={block.id} data-block-id={block.id} data-block-slug={block.blockSlug}>
84
- <BlockRenderer block={block} />
85
- </div>
86
- ))}
87
- </div>
88
- )
89
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"page-renderer.d.ts","sourceRoot":"","sources":["page-renderer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAmDxD,UAAU,iBAAiB;IACzB,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,+BA0BvD"}
@@ -1,89 +0,0 @@
1
- import { Suspense } from 'react'
2
- import type { BlockInstance } from '@nextsparkjs/core/types/blocks'
3
- import { getBlockComponent, normalizeBlockProps } from '@nextsparkjs/core/lib/blocks/loader'
4
-
5
- // Loading skeleton for blocks
6
- function BlockSkeleton() {
7
- return (
8
- <div className="w-full py-12 px-4 animate-pulse">
9
- <div className="max-w-7xl mx-auto">
10
- <div className="h-8 bg-muted rounded w-3/4 mb-4" />
11
- <div className="h-4 bg-muted rounded w-full mb-2" />
12
- <div className="h-4 bg-muted rounded w-5/6" />
13
- </div>
14
- </div>
15
- )
16
- }
17
-
18
- // Error boundary for individual blocks
19
- function BlockError({ blockSlug }: { blockSlug: string }) {
20
- return (
21
- <div className="w-full py-12 px-4 bg-destructive/10 border border-destructive/20 rounded">
22
- <div className="max-w-7xl mx-auto text-center">
23
- <p className="text-destructive">
24
- Failed to load block: <code className="font-mono">{blockSlug}</code>
25
- </p>
26
- <p className="text-sm text-muted-foreground mt-2">
27
- This block may not be available or there was an error rendering it.
28
- </p>
29
- </div>
30
- </div>
31
- )
32
- }
33
-
34
- // Individual block renderer with error boundary
35
- function BlockRenderer({ block }: { block: BlockInstance }) {
36
- const BlockComponent = getBlockComponent(block.blockSlug)
37
-
38
- if (!BlockComponent) {
39
- console.warn(`Block component not found for slug: ${block.blockSlug}`)
40
- return <BlockError blockSlug={block.blockSlug} />
41
- }
42
-
43
- // Normalize props to convert dot-notation to nested objects
44
- const normalizedProps = normalizeBlockProps(block.props)
45
-
46
- return (
47
- <Suspense fallback={<BlockSkeleton />}>
48
- <BlockComponent {...normalizedProps} />
49
- </Suspense>
50
- )
51
- }
52
-
53
- interface PageRendererProps {
54
- page: {
55
- id: string
56
- title: string
57
- slug: string
58
- blocks: BlockInstance[]
59
- locale: string
60
- }
61
- }
62
-
63
- export function PageRenderer({ page }: PageRendererProps) {
64
- // Ensure blocks is an array
65
- const blocks = Array.isArray(page.blocks) ? page.blocks : []
66
-
67
- if (blocks.length === 0) {
68
- return (
69
- <div className="min-h-screen flex items-center justify-center bg-muted/10">
70
- <div className="text-center max-w-md mx-auto px-4">
71
- <h1 className="text-2xl font-bold mb-2">{page.title}</h1>
72
- <p className="text-muted-foreground">
73
- This page does not have any content yet.
74
- </p>
75
- </div>
76
- </div>
77
- )
78
- }
79
-
80
- return (
81
- <div className="min-h-screen" data-page-id={page.id} data-page-slug={page.slug}>
82
- {blocks.map((block) => (
83
- <div key={block.id} data-block-id={block.id} data-block-slug={block.blockSlug}>
84
- <BlockRenderer block={block} />
85
- </div>
86
- ))}
87
- </div>
88
- )
89
- }