Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
eb0b10a
basic setup
benlife5 Feb 3, 2026
275f7fb
Automated update to THIRD-PARTY-NOTICES from github action's 3rd part…
github-actions[bot] Feb 3, 2026
30dda3d
docs: auto-generate component documentation
github-actions[bot] Feb 3, 2026
fb7860c
revert starter changes
benlife5 Feb 4, 2026
22b3b76
add local dev server
benlife5 Feb 4, 2026
26d8cec
Update component screenshots for visual-editor
github-actions[bot] Feb 4, 2026
106c7ed
package updates
benlife5 Feb 4, 2026
42f2f92
docs: auto-generate component documentation
github-actions[bot] Feb 4, 2026
173f569
rabbit updates
benlife5 Feb 4, 2026
1d26405
Update component screenshots for visual-editor
github-actions[bot] Feb 4, 2026
2475e4d
Update component screenshots for visual-editor
github-actions[bot] Feb 4, 2026
c5b3b55
streaming + error handling
benlife5 Feb 4, 2026
9151037
more css updates; memoize plugin
benlife5 Feb 4, 2026
f63755b
Update component screenshots for visual-editor
github-actions[bot] Feb 4, 2026
ccc8a43
Update component screenshots for visual-editor
github-actions[bot] Feb 4, 2026
4a40a1e
fn name
benlife5 Feb 5, 2026
435f86e
Update component screenshots for visual-editor
github-actions[bot] Feb 5, 2026
a0b7fb2
rework as cloudflare worker with hono backend
benlife5 Feb 5, 2026
54b304a
docs: auto-generate component documentation
github-actions[bot] Feb 5, 2026
bdc34c4
dev:ai script
benlife5 Feb 5, 2026
f18c61e
remove old ai attempt
benlife5 Feb 5, 2026
7a0a106
robot comments
benlife5 Feb 5, 2026
59e39a2
fix css; rename files; fix error message
benlife5 Feb 6, 2026
cb30e0e
upgrade to puck ai 0.6.0
benlife5 Feb 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/autogenerate-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
id: commit_docs
uses: EndBug/add-and-commit@v9
with:
add: '["packages/visual-editor/src/docs/components.md", "packages/visual-editor/src/docs/ai/components.d.ts"]'
add: '["packages/visual-editor/src/docs/components.md"]'
message: "docs: auto-generate component documentation"
push: true
default_author: github_actions
Expand Down
12 changes: 12 additions & 0 deletions packages/puck-ai-backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# wrangler project

.dev.vars*
!.dev.vars.example
.env*
!.env.example
.wrangler/

worker-configuration.d.ts

# IDE
.vscode/**
22 changes: 22 additions & 0 deletions packages/puck-ai-backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "puck-ai-backend",
"version": "0.0.0",
"author": "sumo@yext.com",
"private": true,
"packageManager": "pnpm@9.12.3",
"scripts": {
"deploy": "wrangler deploy",
"dev": "wrangler dev",
"start": "wrangler dev",
"cf-typegen": "wrangler types"
},
"devDependencies": {
"@types/node": "^25.2.1",
"typescript": "^5.5.2",
"wrangler": "^4.63.0"
},
"dependencies": {
"@puckeditor/cloud-client": "0.6.0",
"hono": "^4.6.12"
}
}
53 changes: 53 additions & 0 deletions packages/puck-ai-backend/src/cors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { MiddlewareHandler } from "hono";

const isLocalHost = (host: string) =>
host === "localhost" || host === "127.0.0.1" || host === "0.0.0.0";

const isAllowedOrigin = (origin: string, isLocalServer: boolean) => {
try {
const url = new URL(origin);
const host = url.hostname.toLowerCase();
if (host.endsWith(".preview.pagescdn.com")) {
return true;
}
if (isLocalServer && isLocalHost(host)) {
return true;
}
return false;
} catch {
return false;
}
};

export const corsForPuck: MiddlewareHandler = async (c, next) => {
const origin = c.req.header("Origin");
const hostHeader = c.req.header("Host") ?? "";
const requestHost = hostHeader.split(":")[0].toLowerCase();
const isLocalServer = isLocalHost(requestHost);
const allowed = origin ? isAllowedOrigin(origin, isLocalServer) : false;

if (c.req.method === "OPTIONS") {
if (allowed && origin) {
c.header("Access-Control-Allow-Origin", origin);
c.header("Vary", "Origin");
c.header("Access-Control-Allow-Methods", "POST, OPTIONS");
const requestedHeaders = c.req.header("Access-Control-Request-Headers");
if (requestedHeaders) {
c.header("Access-Control-Allow-Headers", requestedHeaders);
}
}
return c.body(null, 204);
}

await next();

if (allowed && origin) {
c.res.headers.set("Access-Control-Allow-Origin", origin);
c.res.headers.set("Vary", "Origin");
c.res.headers.set("Access-Control-Allow-Methods", "POST, OPTIONS");
const requestedHeaders = c.req.header("Access-Control-Request-Headers");
if (requestedHeaders) {
c.res.headers.set("Access-Control-Allow-Headers", requestedHeaders);
}
}
};
12 changes: 12 additions & 0 deletions packages/puck-ai-backend/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Hono } from "hono";
import { corsForPuck } from "./cors";
import { puckRouter } from "./puckRouter";

const app = new Hono();

app.get("/", (c) => c.text("Yext Pages Puck AI Backend is running."));

app.use("/api/puck/*", corsForPuck);
app.post("/api/puck/:route", puckRouter);

export default app;
87 changes: 87 additions & 0 deletions packages/puck-ai-backend/src/puckRouter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { puckHandler, ChatParams } from "@puckeditor/cloud-client";
import type { Context } from "hono";

type CustomChatParams = ChatParams & { systemPrompt: string };

const parseBody = async (c: Context): Promise<CustomChatParams | undefined> => {
const contentType = c.req.header("content-type") ?? "";
if (contentType.includes("application/json")) {
try {
return await c.req.json();
} catch {
return;
}
}
if (
contentType.includes("application/x-www-form-urlencoded") ||
contentType.includes("multipart/form-data")
) {
try {
const parsedBody = await c.req.parseBody();
if (typeof parsedBody === "object" && "chatId" in parsedBody) {
return parsedBody as unknown as CustomChatParams;
}
return;
} catch {
return;
}
}
return;
};

/** Accept the request from the editor, forward it to Puck, and stream the response. */
export const puckRouter = async (c: Context) => {
try {
const puckApiKey = c.env.PUCK_API_KEY;
if (!puckApiKey) {
return c.json({ success: false, error: "Missing PUCK_API_KEY" }, 500);
}

const origin = c.req.header("Origin");
if (!origin) {
return c.json({ success: false, error: "Missing Origin header" }, 400);
}
const pathname = `/api/puck/${c.req.param("route") ?? ""}`.replace(
/\/+$/,
"",
);
const url = new URL(pathname, origin);

const body = await parseBody(c);

if (!body) {
return c.json({ success: false, error: "Invalid request body" }, 400);
}

const puckRequest = new Request(url, {
method: "POST",
body: JSON.stringify(body),
headers: { "content-type": "application/json" },
});

const puckResponse = await puckHandler(puckRequest, {
ai: { context: body.systemPrompt },
apiKey: puckApiKey,
});

const isServerSideEvents = (
puckResponse.headers.get("content-type") ?? ""
).includes("text/event-stream");
if (!isServerSideEvents) {
return puckResponse;
}

const headers = new Headers(puckResponse.headers);
headers.set("Cache-Control", "no-cache");
headers.set("Connection", "keep-alive");

return new Response(puckResponse.body, {
status: puckResponse.status,
statusText: puckResponse.statusText,
headers,
});
} catch (error) {
console.error(error);
return c.json({ success: false, error: "Failed to process request" }, 500);
}
};
20 changes: 20 additions & 0 deletions packages/puck-ai-backend/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es2024",
"lib": ["es2024"],
"jsx": "react-jsx",
"module": "es2022",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"allowJs": true,
"checkJs": false,
"noEmit": true,
"isolatedModules": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"types": ["./worker-configuration.d.ts", "node"]
},
"include": ["worker-configuration.d.ts", "src/**/*.ts"]
}
14 changes: 14 additions & 0 deletions packages/puck-ai-backend/wrangler.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* For more details on how to configure Wrangler, refer to:
* https://developers.cloudflare.com/workers/wrangler/configuration/
*/
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "puck-ai-backend",
"main": "src/index.ts",
"compatibility_date": "2025-09-27",
"observability": {
"enabled": true,
},
"compatibility_flags": ["nodejs_compat"],
}
5 changes: 2 additions & 3 deletions packages/visual-editor/THIRD-PARTY-NOTICES
Original file line number Diff line number Diff line change
Expand Up @@ -1161,12 +1161,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

-----------

The following npm packages may be included in this product:
The following npm package may be included in this product:

- @puckeditor/core@0.21.1
- next-themes@0.3.0

These packages each contain the following license:
This package contains the following license:

MIT

Expand Down
12 changes: 9 additions & 3 deletions packages/visual-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
"import": "./dist/visual-editor.js",
"default": "./dist/visual-editor.js"
},
"./tailwind": {
"types": "./dist/tailwind.d.ts",
"import": "./dist/tailwind.js",
"default": "./dist/tailwind.js"
},
"./plugin": {
"import": "./dist/plugin/plugin.js",
"default": "./dist/plugin/plugin.js"
Expand All @@ -42,7 +47,7 @@
"autofix": "pnpm run lint && pnpm run prettier",
"prepare": "pnpm build",
"generate-notices": "generate-license-file --input package.json --output ./THIRD-PARTY-NOTICES --overwrite",
"generate-component-docs": "api-extractor run --local ; node generate-docs.mjs ; tsx scripts/generateComponentTypeDefinitions.ts",
"generate-component-docs": "api-extractor run --local ; node generate-docs.mjs",
"docs:dev": "vitepress dev .",
"docs:build": "vitepress build .",
"docs:preview": "vitepress preview .",
Expand All @@ -62,7 +67,6 @@
"@microsoft/api-documenter": "^7.26.29",
"@microsoft/api-extractor": "^7.52.8",
"@microsoft/api-extractor-model": "^7.30.6",
"@puckeditor/core": "0.21.1",
"@radix-ui/react-accordion": "^1.2.3",
"@radix-ui/react-alert-dialog": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.13",
Expand Down Expand Up @@ -163,6 +167,8 @@
"@yext/search-ui-react": "^2.0.2",
"mapbox-gl": "^2.9.2",
"react": "^17.0.2 || ^18.2.0",
"react-dom": "^17.0.2 || ^18.2.0"
"react-dom": "^17.0.2 || ^18.2.0",
"@puckeditor/core": "0.21.1",
"@puckeditor/plugin-ai": "0.6.0"
}
}
Loading
Loading