@puckeditor/cli 0.24.0-canary.301a0304
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/LICENSE +21 -0
- package/README.md +45 -0
- package/dist/bin.mjs +7304 -0
- package/dist/docs/api-reference/actions.md +63 -0
- package/dist/docs/api-reference/components/action-bar-action.md +35 -0
- package/dist/docs/api-reference/components/action-bar-group.md +24 -0
- package/dist/docs/api-reference/components/action-bar-label.md +25 -0
- package/dist/docs/api-reference/components/action-bar-separator.md +16 -0
- package/dist/docs/api-reference/components/action-bar.md +32 -0
- package/dist/docs/api-reference/components/auto-field.md +63 -0
- package/dist/docs/api-reference/components/drawer-item.md +75 -0
- package/dist/docs/api-reference/components/drawer.md +29 -0
- package/dist/docs/api-reference/components/drop-zone.md +232 -0
- package/dist/docs/api-reference/components/field-label.md +138 -0
- package/dist/docs/api-reference/components/inline-text-field.md +77 -0
- package/dist/docs/api-reference/components/puck-components.md +19 -0
- package/dist/docs/api-reference/components/puck-fields.md +39 -0
- package/dist/docs/api-reference/components/puck-layout.md +27 -0
- package/dist/docs/api-reference/components/puck-outline.md +19 -0
- package/dist/docs/api-reference/components/puck-preview.md +39 -0
- package/dist/docs/api-reference/components/puck.md +561 -0
- package/dist/docs/api-reference/components/render.md +94 -0
- package/dist/docs/api-reference/components/rich-text-menu-control.md +87 -0
- package/dist/docs/api-reference/components/rich-text-menu-group.md +27 -0
- package/dist/docs/api-reference/components/rich-text-menu.md +99 -0
- package/dist/docs/api-reference/components.md +32 -0
- package/dist/docs/api-reference/configuration/component-config.md +569 -0
- package/dist/docs/api-reference/configuration/config.md +108 -0
- package/dist/docs/api-reference/configuration.md +4 -0
- package/dist/docs/api-reference/data-model/app-state.md +168 -0
- package/dist/docs/api-reference/data-model/component-data.md +62 -0
- package/dist/docs/api-reference/data-model/data.md +95 -0
- package/dist/docs/api-reference/data-model/item-selector.md +34 -0
- package/dist/docs/api-reference/data-model/root-data.md +59 -0
- package/dist/docs/api-reference/data-model.md +8 -0
- package/dist/docs/api-reference/dictionary.md +172 -0
- package/dist/docs/api-reference/field-transforms.md +51 -0
- package/dist/docs/api-reference/fields/array.md +211 -0
- package/dist/docs/api-reference/fields/base.md +96 -0
- package/dist/docs/api-reference/fields/custom.md +193 -0
- package/dist/docs/api-reference/fields/external.md +413 -0
- package/dist/docs/api-reference/fields/number.md +132 -0
- package/dist/docs/api-reference/fields/object.md +78 -0
- package/dist/docs/api-reference/fields/radio.md +82 -0
- package/dist/docs/api-reference/fields/richtext.md +422 -0
- package/dist/docs/api-reference/fields/select.md +79 -0
- package/dist/docs/api-reference/fields/slot.md +302 -0
- package/dist/docs/api-reference/fields/text.md +93 -0
- package/dist/docs/api-reference/fields/textarea.md +93 -0
- package/dist/docs/api-reference/fields.md +16 -0
- package/dist/docs/api-reference/functions/migrate.md +204 -0
- package/dist/docs/api-reference/functions/register-overlay-portal.md +45 -0
- package/dist/docs/api-reference/functions/resolve-all-data.md +27 -0
- package/dist/docs/api-reference/functions/set-deep.md +55 -0
- package/dist/docs/api-reference/functions/transform-props.md +51 -0
- package/dist/docs/api-reference/functions/use-get-puck.md +24 -0
- package/dist/docs/api-reference/functions/use-puck.md +43 -0
- package/dist/docs/api-reference/functions/walk-tree.md +88 -0
- package/dist/docs/api-reference/functions.md +8 -0
- package/dist/docs/api-reference/overrides/action-bar.md +35 -0
- package/dist/docs/api-reference/overrides/component-overlay.md +41 -0
- package/dist/docs/api-reference/overrides/drawer-item.md +24 -0
- package/dist/docs/api-reference/overrides/drawer.md +19 -0
- package/dist/docs/api-reference/overrides/field-label.md +18 -0
- package/dist/docs/api-reference/overrides/field-types.md +51 -0
- package/dist/docs/api-reference/overrides/fields.md +19 -0
- package/dist/docs/api-reference/overrides/header-actions.md +24 -0
- package/dist/docs/api-reference/overrides/header.md +29 -0
- package/dist/docs/api-reference/overrides/iframe.md +32 -0
- package/dist/docs/api-reference/overrides/outline.md +19 -0
- package/dist/docs/api-reference/overrides/preview.md +19 -0
- package/dist/docs/api-reference/overrides/puck.md +19 -0
- package/dist/docs/api-reference/overrides.md +28 -0
- package/dist/docs/api-reference/permissions.md +55 -0
- package/dist/docs/api-reference/plugin.md +112 -0
- package/dist/docs/api-reference/plugins/blocks-plugin.md +57 -0
- package/dist/docs/api-reference/plugins/fields-plugin.md +68 -0
- package/dist/docs/api-reference/plugins/legacy-side-bar-plugin.md +54 -0
- package/dist/docs/api-reference/plugins/outline-plugin.md +57 -0
- package/dist/docs/api-reference/puck-api.md +278 -0
- package/dist/docs/api-reference/theming/action-bar.md +32 -0
- package/dist/docs/api-reference/theming/button.md +65 -0
- package/dist/docs/api-reference/theming/canvas.md +20 -0
- package/dist/docs/api-reference/theming/computed-values.md +194 -0
- package/dist/docs/api-reference/theming/drawer.md +34 -0
- package/dist/docs/api-reference/theming/fields.md +70 -0
- package/dist/docs/api-reference/theming/global.md +127 -0
- package/dist/docs/api-reference/theming/header.md +19 -0
- package/dist/docs/api-reference/theming/icon-button.md +28 -0
- package/dist/docs/api-reference/theming/outline.md +35 -0
- package/dist/docs/api-reference/theming/plugin-bar.md +24 -0
- package/dist/docs/api-reference/theming/sidebar.md +19 -0
- package/dist/docs/api-reference/theming/slot.md +27 -0
- package/dist/docs/cli.md +201 -0
- package/dist/docs/extending-puck/composition.md +54 -0
- package/dist/docs/extending-puck/custom-fields.md +133 -0
- package/dist/docs/extending-puck/field-transforms.md +89 -0
- package/dist/docs/extending-puck/internal-puck-api.md +96 -0
- package/dist/docs/extending-puck/plugins.md +159 -0
- package/dist/docs/extending-puck/theming.md +88 -0
- package/dist/docs/extending-puck/ui-overrides.md +134 -0
- package/dist/docs/getting-started.md +68 -0
- package/dist/docs/guides/migrations/dropzones-to-slots.md +138 -0
- package/dist/docs/index.json +466 -0
- package/dist/docs/index.md +37 -0
- package/dist/docs/integrating-puck/categories.md +92 -0
- package/dist/docs/integrating-puck/component-configuration.md +159 -0
- package/dist/docs/integrating-puck/data-migration.md +86 -0
- package/dist/docs/integrating-puck/dynamic-fields.md +86 -0
- package/dist/docs/integrating-puck/dynamic-props.md +137 -0
- package/dist/docs/integrating-puck/external-data-sources.md +149 -0
- package/dist/docs/integrating-puck/feature-toggling.md +121 -0
- package/dist/docs/integrating-puck/localization.md +228 -0
- package/dist/docs/integrating-puck/multi-column-layouts.md +226 -0
- package/dist/docs/integrating-puck/overlay-portals.md +25 -0
- package/dist/docs/integrating-puck/rich-text-editing.md +230 -0
- package/dist/docs/integrating-puck/root-configuration.md +171 -0
- package/dist/docs/integrating-puck/server-components.md +199 -0
- package/dist/docs/integrating-puck/styling.md +117 -0
- package/dist/docs/integrating-puck/viewports.md +75 -0
- package/dist/templates/astro/README.md +52 -0
- package/dist/templates/astro/_gitignore +24 -0
- package/dist/templates/astro/astro.config.mjs +14 -0
- package/dist/templates/astro/database.json +1 -0
- package/dist/templates/astro/package.json +25 -0
- package/dist/templates/astro/public/favicon.svg +9 -0
- package/dist/templates/astro/src/lib/pages.ts +21 -0
- package/dist/templates/astro/src/lib/resolve-puck-path.ts +19 -0
- package/dist/templates/astro/src/pages/[...puckPath].astro +25 -0
- package/dist/templates/astro/src/pages/api/pages.ts +18 -0
- package/dist/templates/astro/src/puck/editor.tsx +32 -0
- package/dist/templates/astro/src/puck/pages.ts +15 -0
- package/dist/templates/astro/src/puck/render.tsx +9 -0
- package/dist/templates/astro/src/puck.config.tsx +23 -0
- package/dist/templates/astro/tsconfig.json +14 -0
- package/dist/templates/astro-ai/README.md +64 -0
- package/dist/templates/astro-ai/_gitignore +24 -0
- package/dist/templates/astro-ai/astro.config.mjs +21 -0
- package/dist/templates/astro-ai/database.json +1 -0
- package/dist/templates/astro-ai/package.json +27 -0
- package/dist/templates/astro-ai/public/favicon.svg +9 -0
- package/dist/templates/astro-ai/src/lib/pages.ts +21 -0
- package/dist/templates/astro-ai/src/lib/resolve-puck-path.ts +19 -0
- package/dist/templates/astro-ai/src/pages/[...puckPath].astro +25 -0
- package/dist/templates/astro-ai/src/pages/api/pages.ts +18 -0
- package/dist/templates/astro-ai/src/pages/api/puck/[...all].ts +36 -0
- package/dist/templates/astro-ai/src/puck/editor.tsx +53 -0
- package/dist/templates/astro-ai/src/puck/pages.ts +15 -0
- package/dist/templates/astro-ai/src/puck/render.tsx +10 -0
- package/dist/templates/astro-ai/src/puck.config.tsx +23 -0
- package/dist/templates/astro-ai/tsconfig.json +14 -0
- package/dist/templates/express/README.md +66 -0
- package/dist/templates/express/_gitignore +16 -0
- package/dist/templates/express/database.json +1 -0
- package/dist/templates/express/package.json +20 -0
- package/dist/templates/express/src/index.ts +15 -0
- package/dist/templates/express/src/puck/pages.ts +39 -0
- package/dist/templates/express/tsconfig.json +12 -0
- package/dist/templates/express-ai/README.md +81 -0
- package/dist/templates/express-ai/_gitignore +16 -0
- package/dist/templates/express-ai/database.json +1 -0
- package/dist/templates/express-ai/package.json +22 -0
- package/dist/templates/express-ai/src/index.ts +17 -0
- package/dist/templates/express-ai/src/puck/cloud.ts +71 -0
- package/dist/templates/express-ai/src/puck/pages.ts +39 -0
- package/dist/templates/express-ai/tsconfig.json +12 -0
- package/dist/templates/hono/README.md +66 -0
- package/dist/templates/hono/_gitignore +32 -0
- package/dist/templates/hono/database.json +1 -0
- package/dist/templates/hono/package.json +20 -0
- package/dist/templates/hono/src/index.ts +21 -0
- package/dist/templates/hono/src/puck/pages.ts +32 -0
- package/dist/templates/hono/tsconfig.json +13 -0
- package/dist/templates/hono-ai/README.md +81 -0
- package/dist/templates/hono-ai/_gitignore +32 -0
- package/dist/templates/hono-ai/database.json +1 -0
- package/dist/templates/hono-ai/package.json +22 -0
- package/dist/templates/hono-ai/src/index.ts +23 -0
- package/dist/templates/hono-ai/src/puck/cloud.ts +30 -0
- package/dist/templates/hono-ai/src/puck/pages.ts +32 -0
- package/dist/templates/hono-ai/tsconfig.json +13 -0
- package/dist/templates/manifest.json +4 -0
- package/dist/templates/next/README.md +112 -0
- package/dist/templates/next/_gitignore +35 -0
- package/dist/templates/next/app/[...puckPath]/client.tsx +9 -0
- package/dist/templates/next/app/[...puckPath]/page.tsx +49 -0
- package/dist/templates/next/app/favicon.ico +0 -0
- package/dist/templates/next/app/layout.tsx +13 -0
- package/dist/templates/next/app/page.tsx +1 -0
- package/dist/templates/next/app/puck/[...puckPath]/client.tsx +20 -0
- package/dist/templates/next/app/puck/[...puckPath]/page.tsx +55 -0
- package/dist/templates/next/app/puck/api/route.ts +25 -0
- package/dist/templates/next/app/puck/page.tsx +3 -0
- package/dist/templates/next/app/styles.css +3 -0
- package/dist/templates/next/database.json +1 -0
- package/dist/templates/next/lib/get-page.ts +11 -0
- package/dist/templates/next/next.config.js +3 -0
- package/dist/templates/next/package.json +25 -0
- package/dist/templates/next/proxy.ts +27 -0
- package/dist/templates/next/puck.config.tsx +25 -0
- package/dist/templates/next/tsconfig/base.json +20 -0
- package/dist/templates/next/tsconfig/nextjs.json +21 -0
- package/dist/templates/next/tsconfig.json +8 -0
- package/dist/templates/next-ai/README.md +169 -0
- package/dist/templates/next-ai/_gitignore +35 -0
- package/dist/templates/next-ai/app/[...puckPath]/client.tsx +12 -0
- package/dist/templates/next-ai/app/[...puckPath]/page.tsx +49 -0
- package/dist/templates/next-ai/app/api/pages/route.ts +26 -0
- package/dist/templates/next-ai/app/api/puck/[...all]/route.ts +31 -0
- package/dist/templates/next-ai/app/layout.tsx +13 -0
- package/dist/templates/next-ai/app/page.tsx +1 -0
- package/dist/templates/next-ai/app/puck/[...puckPath]/client.tsx +38 -0
- package/dist/templates/next-ai/app/puck/[...puckPath]/page.tsx +57 -0
- package/dist/templates/next-ai/app/puck/page.tsx +3 -0
- package/dist/templates/next-ai/app/styles.css +3 -0
- package/dist/templates/next-ai/database.json +1 -0
- package/dist/templates/next-ai/lib/get-page.ts +11 -0
- package/dist/templates/next-ai/next.config.js +3 -0
- package/dist/templates/next-ai/package.json +27 -0
- package/dist/templates/next-ai/proxy.ts +27 -0
- package/dist/templates/next-ai/public/favicon.ico +0 -0
- package/dist/templates/next-ai/puck.config.tsx +25 -0
- package/dist/templates/next-ai/tsconfig/base.json +20 -0
- package/dist/templates/next-ai/tsconfig/nextjs.json +21 -0
- package/dist/templates/next-ai/tsconfig.json +8 -0
- package/dist/templates/react-router/README.md +113 -0
- package/dist/templates/react-router/_gitignore +6 -0
- package/dist/templates/react-router/app/components/puck-render.tsx +8 -0
- package/dist/templates/react-router/app/lib/pages.server.ts +29 -0
- package/dist/templates/react-router/app/lib/resolve-puck-path.server.ts +19 -0
- package/dist/templates/react-router/app/root.tsx +65 -0
- package/dist/templates/react-router/app/routes/_index.tsx +31 -0
- package/dist/templates/react-router/app/routes/puck-splat.tsx +95 -0
- package/dist/templates/react-router/app/routes.ts +7 -0
- package/dist/templates/react-router/database.json +1 -0
- package/dist/templates/react-router/package.json +33 -0
- package/dist/templates/react-router/public/favicon.ico +0 -0
- package/dist/templates/react-router/puck.config.tsx +23 -0
- package/dist/templates/react-router/react-router.config.ts +7 -0
- package/dist/templates/react-router/tsconfig.json +29 -0
- package/dist/templates/react-router/vite.config.ts +10 -0
- package/dist/templates/react-router-ai/README.md +172 -0
- package/dist/templates/react-router-ai/_gitignore +6 -0
- package/dist/templates/react-router-ai/app/components/puck-render.tsx +11 -0
- package/dist/templates/react-router-ai/app/lib/pages.server.ts +29 -0
- package/dist/templates/react-router-ai/app/lib/resolve-puck-path.server.ts +19 -0
- package/dist/templates/react-router-ai/app/root.tsx +65 -0
- package/dist/templates/react-router-ai/app/routes/_index.tsx +31 -0
- package/dist/templates/react-router-ai/app/routes/api.puck.ts +34 -0
- package/dist/templates/react-router-ai/app/routes/puck-splat.tsx +119 -0
- package/dist/templates/react-router-ai/app/routes.ts +8 -0
- package/dist/templates/react-router-ai/database.json +1 -0
- package/dist/templates/react-router-ai/package.json +35 -0
- package/dist/templates/react-router-ai/public/favicon.ico +0 -0
- package/dist/templates/react-router-ai/puck.config.tsx +25 -0
- package/dist/templates/react-router-ai/react-router.config.ts +7 -0
- package/dist/templates/react-router-ai/tsconfig.json +29 -0
- package/dist/templates/react-router-ai/vite.config.ts +10 -0
- package/dist/templates/tanstack-start/README.md +113 -0
- package/dist/templates/tanstack-start/_gitignore +12 -0
- package/dist/templates/tanstack-start/database.json +1 -0
- package/dist/templates/tanstack-start/package.json +26 -0
- package/dist/templates/tanstack-start/puck.config.tsx +23 -0
- package/dist/templates/tanstack-start/src/components/puck-render.tsx +8 -0
- package/dist/templates/tanstack-start/src/lib/pages.server.ts +26 -0
- package/dist/templates/tanstack-start/src/lib/pages.ts +39 -0
- package/dist/templates/tanstack-start/src/lib/resolve-puck-path.ts +19 -0
- package/dist/templates/tanstack-start/src/routeTree.gen.ts +86 -0
- package/dist/templates/tanstack-start/src/router.tsx +19 -0
- package/dist/templates/tanstack-start/src/routes/$.tsx +41 -0
- package/dist/templates/tanstack-start/src/routes/__root.tsx +42 -0
- package/dist/templates/tanstack-start/src/routes/index.tsx +18 -0
- package/dist/templates/tanstack-start/src/styles.css +13 -0
- package/dist/templates/tanstack-start/tsconfig.json +24 -0
- package/dist/templates/tanstack-start/vite.config.ts +15 -0
- package/dist/templates/tanstack-start-ai/README.md +171 -0
- package/dist/templates/tanstack-start-ai/_gitignore +12 -0
- package/dist/templates/tanstack-start-ai/database.json +1 -0
- package/dist/templates/tanstack-start-ai/package.json +28 -0
- package/dist/templates/tanstack-start-ai/puck.config.tsx +23 -0
- package/dist/templates/tanstack-start-ai/src/components/puck-render.tsx +11 -0
- package/dist/templates/tanstack-start-ai/src/lib/pages.server.ts +26 -0
- package/dist/templates/tanstack-start-ai/src/lib/pages.ts +39 -0
- package/dist/templates/tanstack-start-ai/src/lib/resolve-puck-path.ts +19 -0
- package/dist/templates/tanstack-start-ai/src/routeTree.gen.ts +104 -0
- package/dist/templates/tanstack-start-ai/src/router.tsx +19 -0
- package/dist/templates/tanstack-start-ai/src/routes/$.tsx +73 -0
- package/dist/templates/tanstack-start-ai/src/routes/__root.tsx +42 -0
- package/dist/templates/tanstack-start-ai/src/routes/api/puck/$.ts +39 -0
- package/dist/templates/tanstack-start-ai/src/routes/index.tsx +18 -0
- package/dist/templates/tanstack-start-ai/src/styles.css +13 -0
- package/dist/templates/tanstack-start-ai/tsconfig.json +24 -0
- package/dist/templates/tanstack-start-ai/vite.config.ts +15 -0
- package/dist/templates/vinext/README.md +112 -0
- package/dist/templates/vinext/_gitignore +33 -0
- package/dist/templates/vinext/app/[...puckPath]/client.tsx +9 -0
- package/dist/templates/vinext/app/[...puckPath]/page.tsx +49 -0
- package/dist/templates/vinext/app/favicon.ico +0 -0
- package/dist/templates/vinext/app/layout.tsx +13 -0
- package/dist/templates/vinext/app/page.tsx +1 -0
- package/dist/templates/vinext/app/puck/[...puckPath]/client.tsx +20 -0
- package/dist/templates/vinext/app/puck/[...puckPath]/page.tsx +55 -0
- package/dist/templates/vinext/app/puck/api/route.ts +25 -0
- package/dist/templates/vinext/app/puck/page.tsx +3 -0
- package/dist/templates/vinext/app/styles.css +3 -0
- package/dist/templates/vinext/database.json +1 -0
- package/dist/templates/vinext/lib/get-page.ts +11 -0
- package/dist/templates/vinext/package.json +30 -0
- package/dist/templates/vinext/proxy.ts +27 -0
- package/dist/templates/vinext/puck.config.tsx +25 -0
- package/dist/templates/vinext/tsconfig.json +30 -0
- package/dist/templates/vinext/vite.config.ts +6 -0
- package/dist/templates/vinext-ai/README.md +169 -0
- package/dist/templates/vinext-ai/_gitignore +33 -0
- package/dist/templates/vinext-ai/app/[...puckPath]/client.tsx +12 -0
- package/dist/templates/vinext-ai/app/[...puckPath]/page.tsx +49 -0
- package/dist/templates/vinext-ai/app/api/pages/route.ts +26 -0
- package/dist/templates/vinext-ai/app/api/puck/[...all]/route.ts +31 -0
- package/dist/templates/vinext-ai/app/layout.tsx +13 -0
- package/dist/templates/vinext-ai/app/page.tsx +1 -0
- package/dist/templates/vinext-ai/app/puck/[...puckPath]/client.tsx +38 -0
- package/dist/templates/vinext-ai/app/puck/[...puckPath]/page.tsx +57 -0
- package/dist/templates/vinext-ai/app/puck/page.tsx +3 -0
- package/dist/templates/vinext-ai/app/styles.css +3 -0
- package/dist/templates/vinext-ai/database.json +1 -0
- package/dist/templates/vinext-ai/lib/get-page.ts +11 -0
- package/dist/templates/vinext-ai/package.json +32 -0
- package/dist/templates/vinext-ai/proxy.ts +27 -0
- package/dist/templates/vinext-ai/public/favicon.ico +0 -0
- package/dist/templates/vinext-ai/puck.config.tsx +25 -0
- package/dist/templates/vinext-ai/tsconfig.json +30 -0
- package/dist/templates/vinext-ai/vite.config.ts +9 -0
- package/dist/templates/vite/README.md +56 -0
- package/dist/templates/vite/_gitignore +24 -0
- package/dist/templates/vite/database.json +1 -0
- package/dist/templates/vite/index.html +12 -0
- package/dist/templates/vite/package.json +29 -0
- package/dist/templates/vite/server/index.ts +13 -0
- package/dist/templates/vite/server/prod.ts +18 -0
- package/dist/templates/vite/server/puck/pages.ts +32 -0
- package/dist/templates/vite/src/App.tsx +11 -0
- package/dist/templates/vite/src/main.tsx +12 -0
- package/dist/templates/vite/src/puck/editor.tsx +28 -0
- package/dist/templates/vite/src/puck/page.tsx +27 -0
- package/dist/templates/vite/src/puck/pages.ts +15 -0
- package/dist/templates/vite/src/puck/root.tsx +27 -0
- package/dist/templates/vite/src/puck.config.tsx +23 -0
- package/dist/templates/vite/tsconfig.app.json +26 -0
- package/dist/templates/vite/tsconfig.json +7 -0
- package/dist/templates/vite/tsconfig.node.json +23 -0
- package/dist/templates/vite/vite.config.ts +14 -0
- package/dist/templates/vite-ai/README.md +67 -0
- package/dist/templates/vite-ai/_gitignore +24 -0
- package/dist/templates/vite-ai/database.json +1 -0
- package/dist/templates/vite-ai/index.html +12 -0
- package/dist/templates/vite-ai/package.json +31 -0
- package/dist/templates/vite-ai/server/index.ts +15 -0
- package/dist/templates/vite-ai/server/prod.ts +18 -0
- package/dist/templates/vite-ai/server/puck/cloud.ts +30 -0
- package/dist/templates/vite-ai/server/puck/pages.ts +32 -0
- package/dist/templates/vite-ai/src/App.tsx +11 -0
- package/dist/templates/vite-ai/src/main.tsx +12 -0
- package/dist/templates/vite-ai/src/puck/editor.tsx +49 -0
- package/dist/templates/vite-ai/src/puck/page.tsx +28 -0
- package/dist/templates/vite-ai/src/puck/pages.ts +15 -0
- package/dist/templates/vite-ai/src/puck/root.tsx +27 -0
- package/dist/templates/vite-ai/src/puck.config.tsx +23 -0
- package/dist/templates/vite-ai/tsconfig.app.json +26 -0
- package/dist/templates/vite-ai/tsconfig.json +7 -0
- package/dist/templates/vite-ai/tsconfig.node.json +23 -0
- package/dist/templates/vite-ai/vite.config.ts +14 -0
- package/package.json +51 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Handles all requests for Puck AI
|
|
2
|
+
// Learn more: https://puckeditor.com/docs/ai/getting-started
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import type { APIRoute } from "astro";
|
|
5
|
+
import type { PuckCloudOptions } from "@puckeditor/cloud-client";
|
|
6
|
+
import { puckHandler } from "@puckeditor/cloud-client";
|
|
7
|
+
|
|
8
|
+
export const prerender = false;
|
|
9
|
+
|
|
10
|
+
// Astro doesn't put .env files in process.env, where puckHandler reads
|
|
11
|
+
// PUCK_API_KEY. Production servers read it from their environment.
|
|
12
|
+
if (import.meta.env.DEV && fs.existsSync(".env.local"))
|
|
13
|
+
process.loadEnvFile(".env.local");
|
|
14
|
+
|
|
15
|
+
const options: PuckCloudOptions = {
|
|
16
|
+
ai: {
|
|
17
|
+
// Replace with your business context
|
|
18
|
+
context: "We are Google. You create Google landing pages.",
|
|
19
|
+
designMode: {
|
|
20
|
+
// Allow AI to generate new components using "design mode"
|
|
21
|
+
// Learn more: https://puckeditor.com/docs/ai/design-mode
|
|
22
|
+
allowed: true,
|
|
23
|
+
// Constrain component generation, replace with your own instructions
|
|
24
|
+
instructions: `
|
|
25
|
+
#### Color Palette
|
|
26
|
+
|
|
27
|
+
Always use the following colors:
|
|
28
|
+
|
|
29
|
+
* Primary: \`#1976d2\`
|
|
30
|
+
* Secondary: \`#9c27b0\`
|
|
31
|
+
`,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const ALL: APIRoute = ({ request }) => puckHandler(request, options);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from "react";
|
|
2
|
+
import type { Data } from "@puckeditor/core";
|
|
3
|
+
import { Puck, blocksPlugin, outlinePlugin } from "@puckeditor/core";
|
|
4
|
+
import { createAiPlugin, withDynamicConfig } from "@puckeditor/plugin-ai";
|
|
5
|
+
import "@puckeditor/core/puck.css";
|
|
6
|
+
import "@puckeditor/plugin-ai/styles.css";
|
|
7
|
+
|
|
8
|
+
import { config } from "../puck.config";
|
|
9
|
+
import { loadPage, savePage } from "./pages";
|
|
10
|
+
|
|
11
|
+
const aiPlugin = createAiPlugin({
|
|
12
|
+
// Allow users to switch between design and assembly mode.
|
|
13
|
+
// Read more: https://puckeditor.com/docs/ai/design-mode
|
|
14
|
+
designMode: {
|
|
15
|
+
visible: true,
|
|
16
|
+
},
|
|
17
|
+
// Select design mode by default.
|
|
18
|
+
defaultMode: "design",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Place the ai plugin in the first position in the side nav.
|
|
22
|
+
const plugins = [aiPlugin, blocksPlugin(), outlinePlugin()];
|
|
23
|
+
|
|
24
|
+
// Empty shell for new pages
|
|
25
|
+
const emptyPage: Data = { content: [], root: { props: { title: "" } } };
|
|
26
|
+
|
|
27
|
+
// e.g. /edit?path=/about, where there are no server routes for each page
|
|
28
|
+
const pathFromQuery = () =>
|
|
29
|
+
new URLSearchParams(window.location.search).get("path") ?? "/";
|
|
30
|
+
|
|
31
|
+
export default function Editor({ path = pathFromQuery() }: { path?: string }) {
|
|
32
|
+
const [data, setData] = useState<Data | null>(null);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
loadPage(path).then((page) => setData(page ?? emptyPage));
|
|
36
|
+
}, [path]);
|
|
37
|
+
|
|
38
|
+
const configWithDesignedComponents = useMemo(
|
|
39
|
+
() => (data ? withDynamicConfig(config, data) : config),
|
|
40
|
+
[data]
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (!data) return null;
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Puck
|
|
47
|
+
plugins={plugins}
|
|
48
|
+
config={configWithDesignedComponents}
|
|
49
|
+
data={data}
|
|
50
|
+
onPublish={(data) => savePage(path, data)}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Data } from "@puckeditor/core";
|
|
2
|
+
|
|
3
|
+
// Loads and saves pages with the pages API in server/puck/pages.ts
|
|
4
|
+
export const loadPage = async (path: string): Promise<Data | null> => {
|
|
5
|
+
const response = await fetch(`/api/pages?path=${encodeURIComponent(path)}`);
|
|
6
|
+
return response.ok ? response.json() : null;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const savePage = async (path: string, data: Data) => {
|
|
10
|
+
await fetch("/api/pages", {
|
|
11
|
+
method: "POST",
|
|
12
|
+
headers: { "Content-Type": "application/json" },
|
|
13
|
+
body: JSON.stringify({ path, data }),
|
|
14
|
+
});
|
|
15
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Data } from "@puckeditor/core";
|
|
2
|
+
import { Render } from "@puckeditor/core";
|
|
3
|
+
import { withDynamicConfig } from "@puckeditor/plugin-ai";
|
|
4
|
+
|
|
5
|
+
import { config } from "../puck.config";
|
|
6
|
+
|
|
7
|
+
// Rendered on the server, without shipping the editor to the browser
|
|
8
|
+
export default function PuckRender({ data }: { data: Data }) {
|
|
9
|
+
return <Render config={withDynamicConfig(config, data)} data={data} />;
|
|
10
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Config } from "@puckeditor/core";
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
HeadingBlock: { title: string };
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const config: Config<Props> = {
|
|
8
|
+
components: {
|
|
9
|
+
HeadingBlock: {
|
|
10
|
+
fields: {
|
|
11
|
+
title: { type: "text" },
|
|
12
|
+
},
|
|
13
|
+
defaultProps: {
|
|
14
|
+
title: "Heading",
|
|
15
|
+
},
|
|
16
|
+
render: ({ title }) => (
|
|
17
|
+
<div style={{ padding: 64 }}>
|
|
18
|
+
<h1>{title}</h1>
|
|
19
|
+
</div>
|
|
20
|
+
),
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Puck + Express recipe
|
|
2
|
+
|
|
3
|
+
[Puck](https://puckeditor.com) is the open-source visual editor for React.
|
|
4
|
+
|
|
5
|
+
This recipe is a [Express](https://expressjs.com) server that stores Puck pages. It has no editor of its own: point a Puck editor in your React app at it.
|
|
6
|
+
|
|
7
|
+
## The APIs
|
|
8
|
+
|
|
9
|
+
| Route | Purpose |
|
|
10
|
+
| ---------------------------- | ------------------------------------------------- |
|
|
11
|
+
| `GET /api/pages?path=/about` | Returns the saved page data for a path, or a 404. |
|
|
12
|
+
| `POST /api/pages` | Saves `{ "path": "/about", "data": { ... } }`. |
|
|
13
|
+
|
|
14
|
+
## Run the recipe
|
|
15
|
+
|
|
16
|
+
### 1. Start the server
|
|
17
|
+
|
|
18
|
+
Run:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm run dev
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Once the server is running, [http://localhost:3000/api/pages?path=/](http://localhost:3000/api/pages?path=/) returns the home page's data.
|
|
25
|
+
|
|
26
|
+
### 2. Connect an editor
|
|
27
|
+
|
|
28
|
+
Load and save pages from your editor with the pages API:
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
<Puck
|
|
32
|
+
config={config}
|
|
33
|
+
data={await(await fetch("/api/pages?path=/")).json()}
|
|
34
|
+
onPublish={(data) =>
|
|
35
|
+
fetch("/api/pages", {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: { "Content-Type": "application/json" },
|
|
38
|
+
body: JSON.stringify({ path: "/", data }),
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
/>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If your editor runs on another origin, proxy `/api` to this server in development (for example with Vite's [`server.proxy`](https://vite.dev/config/server-options#server-proxy)), or enable CORS.
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
| File | Purpose |
|
|
49
|
+
| ------------------- | ----------------------------------------------------------------------------------- |
|
|
50
|
+
| `src/index.ts` | Creates the Express app and mounts the Puck routes with `app.use(puckPages);`. |
|
|
51
|
+
| `src/puck/pages.ts` | Reads and writes page data in `database.json`. Replace this with your own database. |
|
|
52
|
+
| `database.json` | Acts as a local database. Replace this with your own database solution. |
|
|
53
|
+
|
|
54
|
+
## Before deploying to production
|
|
55
|
+
|
|
56
|
+
Before deploying this recipe, make sure to:
|
|
57
|
+
|
|
58
|
+
- **Protect the APIs.** The pages API is public by default. Add authentication, authorization to protect page data.
|
|
59
|
+
- **Use a real database.** Replace `database.json` and `src/puck/pages.ts`. Local files are not reliable across server instances or serverless deployments.
|
|
60
|
+
|
|
61
|
+
## Learn more
|
|
62
|
+
|
|
63
|
+
- [Puck documentation](https://puckeditor.com/docs)
|
|
64
|
+
- [Integrating Puck](https://puckeditor.com/docs/integrating-puck/component-configuration)
|
|
65
|
+
- [Express](https://expressjs.com)
|
|
66
|
+
- [Puck Discord](https://discord.gg/D9e4E3MQVZ)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"/":{"content":[{"type":"HeadingBlock","props":{"title":"Edit this page by adding /edit to the end of the URL","id":"HeadingBlock-1694032984497"}}],"root":{"props": {"title":""}}}}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "express-recipe",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "tsx watch src/index.ts",
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"start": "node dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"express": "^5.2.1"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/express": "^5.0.3",
|
|
16
|
+
"@types/node": "^22.10.2",
|
|
17
|
+
"tsx": "^4.23.0",
|
|
18
|
+
"typescript": "^5.9.3"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { puckPages } from "./puck/pages.js";
|
|
3
|
+
|
|
4
|
+
const app = express();
|
|
5
|
+
app.use(express.json());
|
|
6
|
+
|
|
7
|
+
app.get("/", (_req, res) => {
|
|
8
|
+
res.send("Hello Express!");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
app.use(puckPages);
|
|
12
|
+
|
|
13
|
+
app.listen(3000, () => {
|
|
14
|
+
console.log("Server is running on http://localhost:3000");
|
|
15
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Loads and saves Puck pages for the editor
|
|
2
|
+
// Learn more: https://puckeditor.com/docs/cli
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import express from "express";
|
|
5
|
+
|
|
6
|
+
// Replace this with your own database
|
|
7
|
+
const databasePath = "database.json";
|
|
8
|
+
|
|
9
|
+
const readPages = async (): Promise<Record<string, unknown>> => {
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(await fs.readFile(databasePath, "utf-8"));
|
|
12
|
+
} catch {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const puckPages = express.Router();
|
|
18
|
+
|
|
19
|
+
puckPages.get("/api/pages", async (req, res) => {
|
|
20
|
+
const pages = await readPages();
|
|
21
|
+
const page = pages[typeof req.query.path === "string" ? req.query.path : "/"];
|
|
22
|
+
|
|
23
|
+
if (page) res.json(page);
|
|
24
|
+
else res.status(404).json({ error: "Not found" });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
puckPages.post(
|
|
28
|
+
"/api/pages",
|
|
29
|
+
express.json({ limit: "10mb" }),
|
|
30
|
+
async (req, res) => {
|
|
31
|
+
const { path, data } = req.body;
|
|
32
|
+
const pages = await readPages();
|
|
33
|
+
|
|
34
|
+
pages[path] = data;
|
|
35
|
+
await fs.writeFile(databasePath, JSON.stringify(pages));
|
|
36
|
+
|
|
37
|
+
res.json({ status: "ok" });
|
|
38
|
+
}
|
|
39
|
+
);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Puck AI + Express recipe
|
|
2
|
+
|
|
3
|
+
[Puck](https://puckeditor.com) is the open-source visual editor for React.
|
|
4
|
+
|
|
5
|
+
This recipe is a [Express](https://expressjs.com) server that stores Puck pages and serves Puck AI. It has no editor of its own: point a Puck editor in your React app at it, and add the Puck AI plugin to that editor.
|
|
6
|
+
|
|
7
|
+
## The APIs
|
|
8
|
+
|
|
9
|
+
| Route | Purpose |
|
|
10
|
+
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
11
|
+
| `GET /api/pages?path=/about` | Returns the saved page data for a path, or a 404. |
|
|
12
|
+
| `POST /api/pages` | Saves `{ "path": "/about", "data": { ... } }`. |
|
|
13
|
+
| `/api/puck/*` | Forwards requests from the Puck AI plugin to Puck Cloud using [`puckHandler`](https://puckeditor.com/docs/api-reference/ai/cloud-client/puck-handler). |
|
|
14
|
+
|
|
15
|
+
## Run the recipe
|
|
16
|
+
|
|
17
|
+
### 1. Add a Puck API key
|
|
18
|
+
|
|
19
|
+
Start by creating an account, [generating an API key](https://cloud.puckeditor.com/api-keys), and adding it to an `.env.local` file:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
PUCK_API_KEY=your-api-key
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. Start the server
|
|
26
|
+
|
|
27
|
+
Run:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
npm run dev
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Once the server is running, [http://localhost:3000/api/pages?path=/](http://localhost:3000/api/pages?path=/) returns the home page's data.
|
|
34
|
+
|
|
35
|
+
### 3. Connect an editor
|
|
36
|
+
|
|
37
|
+
Load and save pages from your editor with the pages API:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
<Puck
|
|
41
|
+
config={config}
|
|
42
|
+
data={await(await fetch("/api/pages?path=/")).json()}
|
|
43
|
+
onPublish={(data) =>
|
|
44
|
+
fetch("/api/pages", {
|
|
45
|
+
method: "POST",
|
|
46
|
+
headers: { "Content-Type": "application/json" },
|
|
47
|
+
body: JSON.stringify({ path: "/", data }),
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
/>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If your editor runs on another origin, proxy `/api` to this server in development (for example with Vite's [`server.proxy`](https://vite.dev/config/server-options#server-proxy)), or enable CORS.
|
|
54
|
+
|
|
55
|
+
The [Puck AI plugin](https://puckeditor.com/docs/api-reference/ai/ai-plugin/installation) calls `/api/puck` on the editor's origin by default. Pass `host` to `createAiPlugin` to call this server directly instead.
|
|
56
|
+
|
|
57
|
+
## How it works
|
|
58
|
+
|
|
59
|
+
| File | Purpose |
|
|
60
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
61
|
+
| `src/index.ts` | Creates the Express app and mounts the Puck routes with `app.use(puckPages);` and `app.use(puckCloud);`. |
|
|
62
|
+
| `src/puck/pages.ts` | Reads and writes page data in `database.json`. Replace this with your own database. |
|
|
63
|
+
| `src/puck/cloud.ts` | Handles requests from the AI plugin and configures AI generation. |
|
|
64
|
+
| `database.json` | Acts as a local database. Replace this with your own database solution. |
|
|
65
|
+
|
|
66
|
+
## Before deploying to production
|
|
67
|
+
|
|
68
|
+
Before deploying this recipe, make sure to:
|
|
69
|
+
|
|
70
|
+
- **Protect the APIs.** The pages API and `/api/puck` route are public by default. Add authentication, authorization, and rate limits to protect page data and AI usage.
|
|
71
|
+
- **Set your business context.** Replace the example Google context in `src/puck/cloud.ts` with clear information about your product, audience, and content rules.
|
|
72
|
+
- **Set `PUCK_API_KEY` in production.** `npm start` runs Node without `.env.local`, so set it in the environment wherever the server runs.
|
|
73
|
+
- **Use a real database.** Replace `database.json` and `src/puck/pages.ts`. Local files are not reliable across server instances or serverless deployments.
|
|
74
|
+
|
|
75
|
+
## Learn more
|
|
76
|
+
|
|
77
|
+
- [Puck documentation](https://puckeditor.com/docs)
|
|
78
|
+
- [Integrating Puck](https://puckeditor.com/docs/integrating-puck/component-configuration)
|
|
79
|
+
- [Puck AI documentation](https://puckeditor.com/docs/ai/overview)
|
|
80
|
+
- [Express](https://expressjs.com)
|
|
81
|
+
- [Puck Discord](https://discord.gg/D9e4E3MQVZ)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"/":{"content":[{"type":"HeadingBlock","props":{"title":"Edit this page by adding /edit to the end of the URL","id":"HeadingBlock-1694032984497"}}],"root":{"props": {"title":""}}}}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "express-ai-recipe",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "tsx watch --env-file-if-exists=.env.local src/index.ts",
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"start": "node dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@puckeditor/cloud-client": "^0",
|
|
13
|
+
"express": "^5.2.1",
|
|
14
|
+
"react": "^19.2.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/express": "^5.0.3",
|
|
18
|
+
"@types/node": "^22.10.2",
|
|
19
|
+
"tsx": "^4.23.0",
|
|
20
|
+
"typescript": "^5.9.3"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { puckPages } from "./puck/pages.js";
|
|
3
|
+
import { puckCloud } from "./puck/cloud.js";
|
|
4
|
+
|
|
5
|
+
const app = express();
|
|
6
|
+
app.use(express.json());
|
|
7
|
+
|
|
8
|
+
app.get("/", (_req, res) => {
|
|
9
|
+
res.send("Hello Express!");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
app.use(puckPages);
|
|
13
|
+
app.use(puckCloud);
|
|
14
|
+
|
|
15
|
+
app.listen(3000, () => {
|
|
16
|
+
console.log("Server is running on http://localhost:3000");
|
|
17
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Handles all requests for Puck AI
|
|
2
|
+
// Learn more: https://puckeditor.com/docs/ai/getting-started
|
|
3
|
+
import { Readable } from "node:stream";
|
|
4
|
+
import express from "express";
|
|
5
|
+
import type { Request, Response } from "express";
|
|
6
|
+
import type { PuckCloudOptions } from "@puckeditor/cloud-client";
|
|
7
|
+
import { puckHandler } from "@puckeditor/cloud-client";
|
|
8
|
+
|
|
9
|
+
const options: PuckCloudOptions = {
|
|
10
|
+
ai: {
|
|
11
|
+
// Replace with your business context
|
|
12
|
+
context: "We are Google. You create Google landing pages.",
|
|
13
|
+
designMode: {
|
|
14
|
+
// Allow AI to generate new components using "design mode"
|
|
15
|
+
// Learn more: https://puckeditor.com/docs/ai/design-mode
|
|
16
|
+
allowed: true,
|
|
17
|
+
// Constrain component generation, replace with your own instructions
|
|
18
|
+
instructions: `
|
|
19
|
+
#### Color Palette
|
|
20
|
+
|
|
21
|
+
Always use the following colors:
|
|
22
|
+
|
|
23
|
+
* Primary: \`#1976d2\`
|
|
24
|
+
* Secondary: \`#9c27b0\`
|
|
25
|
+
`,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// puckHandler takes a web Request, so convert Express's request to one
|
|
31
|
+
const toWebRequest = (req: Request) => {
|
|
32
|
+
const headers = new Headers();
|
|
33
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
34
|
+
if (Array.isArray(value)) value.forEach((v) => headers.append(key, v));
|
|
35
|
+
else if (value !== undefined) headers.set(key, value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let body: BodyInit | undefined;
|
|
39
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
40
|
+
if (req.readableEnded) {
|
|
41
|
+
// A body parser like express.json() already read the body
|
|
42
|
+
body = JSON.stringify(req.body ?? {});
|
|
43
|
+
headers.delete("content-length");
|
|
44
|
+
} else {
|
|
45
|
+
body = Readable.toWeb(req) as ReadableStream;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return new globalThis.Request(
|
|
50
|
+
new URL(req.originalUrl, `${req.protocol}://${req.get("host")}`),
|
|
51
|
+
{ method: req.method, headers, body, duplex: "half" } as RequestInit
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// ...and stream the web Response back through Express
|
|
56
|
+
const sendWebResponse = (res: Response, response: globalThis.Response) => {
|
|
57
|
+
res.status(response.status);
|
|
58
|
+
response.headers.forEach((value, key) => res.setHeader(key, value));
|
|
59
|
+
if (!response.body) return res.end();
|
|
60
|
+
Readable.fromWeb(response.body as any).pipe(res);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const puckCloud = express.Router();
|
|
64
|
+
|
|
65
|
+
puckCloud.use("/api/puck", async (req, res, next) => {
|
|
66
|
+
try {
|
|
67
|
+
sendWebResponse(res, await puckHandler(toWebRequest(req), options));
|
|
68
|
+
} catch (error) {
|
|
69
|
+
next(error);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Loads and saves Puck pages for the editor
|
|
2
|
+
// Learn more: https://puckeditor.com/docs/cli
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import express from "express";
|
|
5
|
+
|
|
6
|
+
// Replace this with your own database
|
|
7
|
+
const databasePath = "database.json";
|
|
8
|
+
|
|
9
|
+
const readPages = async (): Promise<Record<string, unknown>> => {
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(await fs.readFile(databasePath, "utf-8"));
|
|
12
|
+
} catch {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const puckPages = express.Router();
|
|
18
|
+
|
|
19
|
+
puckPages.get("/api/pages", async (req, res) => {
|
|
20
|
+
const pages = await readPages();
|
|
21
|
+
const page = pages[typeof req.query.path === "string" ? req.query.path : "/"];
|
|
22
|
+
|
|
23
|
+
if (page) res.json(page);
|
|
24
|
+
else res.status(404).json({ error: "Not found" });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
puckPages.post(
|
|
28
|
+
"/api/pages",
|
|
29
|
+
express.json({ limit: "10mb" }),
|
|
30
|
+
async (req, res) => {
|
|
31
|
+
const { path, data } = req.body;
|
|
32
|
+
const pages = await readPages();
|
|
33
|
+
|
|
34
|
+
pages[path] = data;
|
|
35
|
+
await fs.writeFile(databasePath, JSON.stringify(pages));
|
|
36
|
+
|
|
37
|
+
res.json({ status: "ok" });
|
|
38
|
+
}
|
|
39
|
+
);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Puck + Hono recipe
|
|
2
|
+
|
|
3
|
+
[Puck](https://puckeditor.com) is the open-source visual editor for React.
|
|
4
|
+
|
|
5
|
+
This recipe is a [Hono](https://hono.dev) server that stores Puck pages. It has no editor of its own: point a Puck editor in your React app at it.
|
|
6
|
+
|
|
7
|
+
## The APIs
|
|
8
|
+
|
|
9
|
+
| Route | Purpose |
|
|
10
|
+
| ---------------------------- | ------------------------------------------------- |
|
|
11
|
+
| `GET /api/pages?path=/about` | Returns the saved page data for a path, or a 404. |
|
|
12
|
+
| `POST /api/pages` | Saves `{ "path": "/about", "data": { ... } }`. |
|
|
13
|
+
|
|
14
|
+
## Run the recipe
|
|
15
|
+
|
|
16
|
+
### 1. Start the server
|
|
17
|
+
|
|
18
|
+
Run:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm run dev
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Once the server is running, [http://localhost:3000/api/pages?path=/](http://localhost:3000/api/pages?path=/) returns the home page's data.
|
|
25
|
+
|
|
26
|
+
### 2. Connect an editor
|
|
27
|
+
|
|
28
|
+
Load and save pages from your editor with the pages API:
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
<Puck
|
|
32
|
+
config={config}
|
|
33
|
+
data={await(await fetch("/api/pages?path=/")).json()}
|
|
34
|
+
onPublish={(data) =>
|
|
35
|
+
fetch("/api/pages", {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: { "Content-Type": "application/json" },
|
|
38
|
+
body: JSON.stringify({ path: "/", data }),
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
/>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If your editor runs on another origin, proxy `/api` to this server in development (for example with Vite's [`server.proxy`](https://vite.dev/config/server-options#server-proxy)), or enable CORS.
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
| File | Purpose |
|
|
49
|
+
| ------------------- | ----------------------------------------------------------------------------------- |
|
|
50
|
+
| `src/index.ts` | Creates the Hono app and mounts the Puck routes with `app.route("/", puckPages);`. |
|
|
51
|
+
| `src/puck/pages.ts` | Reads and writes page data in `database.json`. Replace this with your own database. |
|
|
52
|
+
| `database.json` | Acts as a local database. Replace this with your own database solution. |
|
|
53
|
+
|
|
54
|
+
## Before deploying to production
|
|
55
|
+
|
|
56
|
+
Before deploying this recipe, make sure to:
|
|
57
|
+
|
|
58
|
+
- **Protect the APIs.** The pages API is public by default. Add authentication, authorization to protect page data.
|
|
59
|
+
- **Use a real database.** Replace `database.json` and `src/puck/pages.ts`. Local files are not reliable across server instances or serverless deployments.
|
|
60
|
+
|
|
61
|
+
## Learn more
|
|
62
|
+
|
|
63
|
+
- [Puck documentation](https://puckeditor.com/docs)
|
|
64
|
+
- [Integrating Puck](https://puckeditor.com/docs/integrating-puck/component-configuration)
|
|
65
|
+
- [Hono](https://hono.dev)
|
|
66
|
+
- [Puck Discord](https://discord.gg/D9e4E3MQVZ)
|