From 61de033e329f575caed847cfbdfff917ba451d88 Mon Sep 17 00:00:00 2001 From: amitdhiman5086 Date: Wed, 18 Feb 2026 16:50:32 +0530 Subject: [PATCH 1/6] feat: add Next.js revalidation --- .../(builder)/api/actions/publish-changes.ts | 49 +++++++++++++++++++ frameworks/nextjs/app/(builder)/api/route.ts | 4 +- src/actions/builder/chai-action-interface.ts | 1 + .../builder/chai-builder-actions-handler.ts | 6 +-- src/actions/builder/publish-changes.ts | 20 +++++--- src/actions/export.ts | 1 + 6 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 frameworks/nextjs/app/(builder)/api/actions/publish-changes.ts diff --git a/frameworks/nextjs/app/(builder)/api/actions/publish-changes.ts b/frameworks/nextjs/app/(builder)/api/actions/publish-changes.ts new file mode 100644 index 000000000..0b1cf19f2 --- /dev/null +++ b/frameworks/nextjs/app/(builder)/api/actions/publish-changes.ts @@ -0,0 +1,49 @@ + +import { PublishChangesAction } from "@chaibuilder/sdk/actions"; +import { revalidatePath, revalidateTag } from "next/cache"; + +export class NextJsPublishChangesAction extends PublishChangesAction { + async execute(data: any) { + const response = await super.execute(data); + const { tags, paths } = response; + + // Handle tags revalidation + if (tags && tags.length > 0) { + await Promise.all(tags.map((tag:string) => revalidateTag(tag, "max"))); + } + + // Handle paths revalidation and regeneration + if (paths && paths.length > 0) { + await Promise.all(paths.map((path:string) => revalidatePath(path))); + + // Trigger immediate regeneration of the pages + const hostname = this.context?.hostname; + if (hostname) { + const protocol = hostname.includes("localhost") ? "http" : "https"; + const origin = `${protocol}://${hostname}`; + + await Promise.allSettled( + paths.map(async (path:string) => { + if (!path || !path.startsWith("/")) return; + try { + const url = `${origin}${path}`; + await fetch(url, { + method: "GET", + headers: { + "x-isr-regeneration": "true", + }, + }); + console.log(`Triggered regeneration for ${path}`); + } catch (err) { + console.error(`Failed to trigger regeneration for ${path}`, err); + } + }) + ); + } else { + console.warn("Hostname not found in context. Skipping page regeneration."); + } + } + + return response; + } +} diff --git a/frameworks/nextjs/app/(builder)/api/route.ts b/frameworks/nextjs/app/(builder)/api/route.ts index 25cc5bf35..e851385c5 100644 --- a/frameworks/nextjs/app/(builder)/api/route.ts +++ b/frameworks/nextjs/app/(builder)/api/route.ts @@ -2,6 +2,7 @@ import { getSupabaseAdmin } from "@/app/supabase-admin"; import { registerPageTypes } from "@/page-types"; import { ChaiActionsRegistry, initChaiBuilderActionHandler } from "@chaibuilder/sdk/actions"; import { SupabaseAuthActions, SupabaseStorageActions } from "@chaibuilder/sdk/actions/supabase"; +import { NextJsPublishChangesAction } from "./actions/publish-changes"; import { NextRequest, NextResponse } from "next/server"; registerPageTypes(); @@ -16,6 +17,7 @@ export async function POST(req: NextRequest) { const supabase = getSupabaseAdmin(); ChaiActionsRegistry.registerActions(SupabaseAuthActions(supabase)); ChaiActionsRegistry.registerActions(SupabaseStorageActions(supabase)); + ChaiActionsRegistry.register("PUBLISH_CHANGES", new NextJsPublishChangesAction()); try { // Get authorization header let authorization = req.headers.get("authorization") || ""; @@ -31,7 +33,7 @@ export async function POST(req: NextRequest) { } const userId = supabaseUser.data.user?.id || ""; - const actionHandler = initChaiBuilderActionHandler({ apiKey, userId }); + const actionHandler = initChaiBuilderActionHandler({ apiKey, userId, hostname: req.nextUrl.host }); const response = await actionHandler(body); // Handle streaming responses if (response?._streamingResponse && response?._streamResult) { diff --git a/src/actions/builder/chai-action-interface.ts b/src/actions/builder/chai-action-interface.ts index c150c83ea..11f67aef5 100644 --- a/src/actions/builder/chai-action-interface.ts +++ b/src/actions/builder/chai-action-interface.ts @@ -5,6 +5,7 @@ export interface ChaiActionContext { appId: string; userId?: string; + hostname?: string; } /** diff --git a/src/actions/builder/chai-builder-actions-handler.ts b/src/actions/builder/chai-builder-actions-handler.ts index 78ec9a990..21f368a73 100644 --- a/src/actions/builder/chai-builder-actions-handler.ts +++ b/src/actions/builder/chai-builder-actions-handler.ts @@ -2,9 +2,9 @@ import { ActionError } from "./action-error"; import { getChaiAction } from "./actions-registery"; import { ChaiBaseAction } from "./base-action"; -export const initChaiBuilderActionHandler = (params: { apiKey: string; userId: string }) => { +export const initChaiBuilderActionHandler = (params: { apiKey: string; userId: string; hostname?: string }) => { return async (actionData: { action: string; data?: unknown }) => { - const { apiKey, userId } = params; + const { apiKey, userId, hostname } = params; try { const requestBody = actionData; const { action, data } = requestBody; @@ -29,7 +29,7 @@ export const initChaiBuilderActionHandler = (params: { apiKey: string; userId: s } // If action is registered in the new system, use it // Set the context on the action handler - actionHandler.setContext({ appId: apiKey, userId }); + actionHandler.setContext({ appId: apiKey, userId, hostname }); // Execute the action return await actionHandler.execute(data); // } diff --git a/src/actions/builder/publish-changes.ts b/src/actions/builder/publish-changes.ts index bcd9a599a..c1b17f297 100644 --- a/src/actions/builder/publish-changes.ts +++ b/src/actions/builder/publish-changes.ts @@ -15,6 +15,7 @@ type PublishChangesActionData = { type PublishChangesActionResponse = { tags: string[]; + paths: string[]; }; /** @@ -85,7 +86,9 @@ export class PublishChangesAction extends ChaiBaseAction r.tags))); + const paths = uniq(flattenDeep(responses.map((r) => r.paths))); + return { tags, paths }; } catch (error) { return this.handleExecutionError(error); } @@ -103,7 +106,7 @@ export class PublishChangesAction extends ChaiBaseAction { + private async publishTheme(): Promise<{ tags: string[]; paths: string[] }> { const app = await this.cloneApp(); // Delete existing online app @@ -127,13 +130,13 @@ export class PublishChangesAction extends ChaiBaseAction { + private async publishDesignToken(): Promise<{ tags: string[]; paths: string[] }> { const app = await this.cloneApp(); // Delete existing online app @@ -157,7 +160,7 @@ export class PublishChangesAction extends ChaiBaseAction { + private async publishPage(id: string): Promise<{ tags: string[]; paths: string[] }> { const page = await this.clonePage(id); await this.addOnlinePage(page); const tags = [`page-${page.primaryPage ?? page.id}`]; + const paths: string[] = []; if (isEmpty(page.slug)) { tags.push(...(await this.getPartialBlockUsage(page.primaryPage ?? page.id))); + } else { + paths.push(`${page.slug}`); } - return tags; + return { tags, paths }; } /** diff --git a/src/actions/export.ts b/src/actions/export.ts index 8bbfa1a6b..5b4490bd3 100644 --- a/src/actions/export.ts +++ b/src/actions/export.ts @@ -2,6 +2,7 @@ import ChaiActionsRegistry from "./builder/actions-registery"; import { getAskAiSystemPrompt } from "./classes/system-prompt"; export { initChaiBuilderActionHandler } from "./builder/chai-builder-actions-handler"; +export { PublishChangesAction } from "./builder/publish-changes"; export { db, safeQuery, schema } from "./db"; export { LANGUAGES } from "./LANGUAGES"; export { ChaiActionsRegistry, getAskAiSystemPrompt }; From b70781c8e3eecd008d65ff411b69d8e685de6818 Mon Sep 17 00:00:00 2001 From: amitdhiman5086 Date: Thu, 19 Feb 2026 10:42:40 +0530 Subject: [PATCH 2/6] feat: added Next.js publish changes action to handle cache revalidation and page regeneration --- frameworks/nextjs/app/(builder)/api/route.ts | 2 +- .../nextjs/app/(public)/[[...slug]]/page.tsx | 2 +- frameworks/nextjs/package/actions.ts | 1 + .../nextjs/package/nextjs-publish-changes.ts | 53 +++++++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 frameworks/nextjs/package/nextjs-publish-changes.ts diff --git a/frameworks/nextjs/app/(builder)/api/route.ts b/frameworks/nextjs/app/(builder)/api/route.ts index e851385c5..a6a8e365c 100644 --- a/frameworks/nextjs/app/(builder)/api/route.ts +++ b/frameworks/nextjs/app/(builder)/api/route.ts @@ -2,7 +2,7 @@ import { getSupabaseAdmin } from "@/app/supabase-admin"; import { registerPageTypes } from "@/page-types"; import { ChaiActionsRegistry, initChaiBuilderActionHandler } from "@chaibuilder/sdk/actions"; import { SupabaseAuthActions, SupabaseStorageActions } from "@chaibuilder/sdk/actions/supabase"; -import { NextJsPublishChangesAction } from "./actions/publish-changes"; +import { NextJsPublishChangesAction } from "@/package/actions"; import { NextRequest, NextResponse } from "next/server"; registerPageTypes(); diff --git a/frameworks/nextjs/app/(public)/[[...slug]]/page.tsx b/frameworks/nextjs/app/(public)/[[...slug]]/page.tsx index 7588ab408..27f08c788 100644 --- a/frameworks/nextjs/app/(public)/[[...slug]]/page.tsx +++ b/frameworks/nextjs/app/(public)/[[...slug]]/page.tsx @@ -45,7 +45,7 @@ export default async function Page({ params }: { params: Promise<{ slug: string[ pageLang: page.lang, }; return ( - + diff --git a/frameworks/nextjs/package/actions.ts b/frameworks/nextjs/package/actions.ts index b85919a86..78a0ce370 100644 --- a/frameworks/nextjs/package/actions.ts +++ b/frameworks/nextjs/package/actions.ts @@ -1 +1,2 @@ export * from "@chaibuilder/sdk/actions"; +export { NextJsPublishChangesAction } from "./nextjs-publish-changes"; \ No newline at end of file diff --git a/frameworks/nextjs/package/nextjs-publish-changes.ts b/frameworks/nextjs/package/nextjs-publish-changes.ts new file mode 100644 index 000000000..80fdcc0d3 --- /dev/null +++ b/frameworks/nextjs/package/nextjs-publish-changes.ts @@ -0,0 +1,53 @@ +import { PublishChangesAction } from "@chaibuilder/sdk/actions"; +import { revalidatePath, revalidateTag } from "next/cache"; + +export class NextJsPublishChangesAction extends PublishChangesAction { + async execute(data: any) { + const response = await super.execute(data); + const { tags, paths } = response; + + // Handle tags revalidation + if (tags && tags.length > 0) { + await Promise.all(tags.map((tag: string) => revalidateTag(tag, "max"))); + } + + // Handle paths revalidation and regeneration + if (paths && paths.length > 0) { + await Promise.all(paths.map((path: string) => revalidatePath(path))); + + // Trigger immediate regeneration of the pages + const hostname = this.context?.hostname; + if (hostname) { + const protocol = hostname.includes("localhost") ? "http" : "https"; + const origin = `${protocol}://${hostname}`; + + await Promise.allSettled( + paths.map(async (path: string) => { + if (!path || !path.startsWith("/")) return; + try { + const url = `${origin}${path}`; + await fetch(url, { + method: "GET", + headers: { + "x-isr-regeneration": "true", + }, + }); + console.log(`Triggered regeneration for ${path}`); + } catch (err) { + console.error( + `Failed to trigger regeneration for ${path}`, + err + ); + } + }) + ); + } else { + console.warn( + "Hostname not found in context. Skipping page regeneration." + ); + } + } + + return response; + } +} From a4ff5bfb1771b1eddb46fc52ba4d42927a40e805 Mon Sep 17 00:00:00 2001 From: amitdhiman5086 Date: Thu, 19 Feb 2026 10:54:53 +0530 Subject: [PATCH 3/6] feat: removed unsued file --- .../(builder)/api/actions/publish-changes.ts | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 frameworks/nextjs/app/(builder)/api/actions/publish-changes.ts diff --git a/frameworks/nextjs/app/(builder)/api/actions/publish-changes.ts b/frameworks/nextjs/app/(builder)/api/actions/publish-changes.ts deleted file mode 100644 index 0b1cf19f2..000000000 --- a/frameworks/nextjs/app/(builder)/api/actions/publish-changes.ts +++ /dev/null @@ -1,49 +0,0 @@ - -import { PublishChangesAction } from "@chaibuilder/sdk/actions"; -import { revalidatePath, revalidateTag } from "next/cache"; - -export class NextJsPublishChangesAction extends PublishChangesAction { - async execute(data: any) { - const response = await super.execute(data); - const { tags, paths } = response; - - // Handle tags revalidation - if (tags && tags.length > 0) { - await Promise.all(tags.map((tag:string) => revalidateTag(tag, "max"))); - } - - // Handle paths revalidation and regeneration - if (paths && paths.length > 0) { - await Promise.all(paths.map((path:string) => revalidatePath(path))); - - // Trigger immediate regeneration of the pages - const hostname = this.context?.hostname; - if (hostname) { - const protocol = hostname.includes("localhost") ? "http" : "https"; - const origin = `${protocol}://${hostname}`; - - await Promise.allSettled( - paths.map(async (path:string) => { - if (!path || !path.startsWith("/")) return; - try { - const url = `${origin}${path}`; - await fetch(url, { - method: "GET", - headers: { - "x-isr-regeneration": "true", - }, - }); - console.log(`Triggered regeneration for ${path}`); - } catch (err) { - console.error(`Failed to trigger regeneration for ${path}`, err); - } - }) - ); - } else { - console.warn("Hostname not found in context. Skipping page regeneration."); - } - } - - return response; - } -} From d8ec0c689992d762ff1358a8fc56283f51efd2dc Mon Sep 17 00:00:00 2001 From: amitdhiman5086 Date: Thu, 19 Feb 2026 16:44:01 +0530 Subject: [PATCH 4/6] fix: added updateTag for revalidation --- frameworks/nextjs/app/(builder)/api/route.ts | 40 ++------------ .../nextjs/app/(builder)/editor/editor.tsx | 2 + frameworks/nextjs/package/actions.ts | 39 +++++++++++++- .../nextjs/package/nextjs-publish-changes.ts | 53 ------------------- frameworks/nextjs/package/update-pages.ts | 7 +++ src/pages/chaibuilder-pages.tsx | 1 + src/pages/hooks/pages/mutations.ts | 10 ++-- src/types/common.ts | 1 + 8 files changed, 59 insertions(+), 94 deletions(-) delete mode 100644 frameworks/nextjs/package/nextjs-publish-changes.ts create mode 100644 frameworks/nextjs/package/update-pages.ts diff --git a/frameworks/nextjs/app/(builder)/api/route.ts b/frameworks/nextjs/app/(builder)/api/route.ts index a6a8e365c..324abc08e 100644 --- a/frameworks/nextjs/app/(builder)/api/route.ts +++ b/frameworks/nextjs/app/(builder)/api/route.ts @@ -1,8 +1,8 @@ import { getSupabaseAdmin } from "@/app/supabase-admin"; import { registerPageTypes } from "@/page-types"; -import { ChaiActionsRegistry, initChaiBuilderActionHandler } from "@chaibuilder/sdk/actions"; +import { ChaiActionsRegistry } from "@chaibuilder/sdk/actions"; import { SupabaseAuthActions, SupabaseStorageActions } from "@chaibuilder/sdk/actions/supabase"; -import { NextJsPublishChangesAction } from "@/package/actions"; +import { initChaiBuilderNextJSActionHandler } from "@/package/actions"; import { NextRequest, NextResponse } from "next/server"; registerPageTypes(); @@ -17,7 +17,6 @@ export async function POST(req: NextRequest) { const supabase = getSupabaseAdmin(); ChaiActionsRegistry.registerActions(SupabaseAuthActions(supabase)); ChaiActionsRegistry.registerActions(SupabaseStorageActions(supabase)); - ChaiActionsRegistry.register("PUBLISH_CHANGES", new NextJsPublishChangesAction()); try { // Get authorization header let authorization = req.headers.get("authorization") || ""; @@ -33,39 +32,8 @@ export async function POST(req: NextRequest) { } const userId = supabaseUser.data.user?.id || ""; - const actionHandler = initChaiBuilderActionHandler({ apiKey, userId, hostname: req.nextUrl.host }); - const response = await actionHandler(body); - // Handle streaming responses - if (response?._streamingResponse && response?._streamResult) { - const result = response._streamResult; - - if (!result?.textStream) { - return NextResponse.json({ error: "No streaming response available" }, { status: 500 }); - } - - // Create a ReadableStream for streaming response - const stream = new ReadableStream({ - async start(controller) { - const encoder = new TextEncoder(); - try { - for await (const chunk of result.textStream) { - if (chunk) { - controller.enqueue(encoder.encode(chunk)); - } - } - controller.close(); - } catch (error) { - controller.error(error); - } - }, - }); - - return new Response(stream, { - headers: { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "no-cache" }, - }); - } - - return NextResponse.json(response, { status: response.status || 200 }); + const actionHandler = initChaiBuilderNextJSActionHandler({ apiKey, userId }); + return await actionHandler(body); } catch (error) { console.error("Error handling POST request", { message: error instanceof Error ? error.message : String(error), diff --git a/frameworks/nextjs/app/(builder)/editor/editor.tsx b/frameworks/nextjs/app/(builder)/editor/editor.tsx index 5e7aac83c..b8d749875 100644 --- a/frameworks/nextjs/app/(builder)/editor/editor.tsx +++ b/frameworks/nextjs/app/(builder)/editor/editor.tsx @@ -9,6 +9,7 @@ import "@chaibuilder/sdk/styles"; import dynamic from "next/dynamic"; import { useCallback, useEffect, useState } from "react"; import { LoginScreen } from "./login"; +import { updatePages } from "@/package/update-pages"; const ChaiWebsiteBuilder = dynamic(() => import("@chaibuilder/sdk/pages").then((mod) => mod.ChaiWebsiteBuilder), { ssr: false, }); @@ -116,6 +117,7 @@ export default function Editor() { designTokens: true, ai: true, }} + onPublish={updatePages} currentUser={user} autoSave autoSaveActionsCount={5} diff --git a/frameworks/nextjs/package/actions.ts b/frameworks/nextjs/package/actions.ts index 78a0ce370..db153b1cd 100644 --- a/frameworks/nextjs/package/actions.ts +++ b/frameworks/nextjs/package/actions.ts @@ -1,2 +1,39 @@ +import { initChaiBuilderActionHandler } from "@chaibuilder/sdk/actions"; +import { NextResponse } from "next/server"; export * from "@chaibuilder/sdk/actions"; -export { NextJsPublishChangesAction } from "./nextjs-publish-changes"; \ No newline at end of file +export function initChaiBuilderNextJSActionHandler({ apiKey, userId }: { apiKey: string, userId: string }) { + return async function (body: any) { + const actionHandler = initChaiBuilderActionHandler({ apiKey, userId }) + const response: any = await actionHandler(body) + if (response?._streamingResponse && response?._streamResult) { + const result = response._streamResult; + + if (!result?.textStream) { + return NextResponse.json({ error: "No streaming response available" }, { status: 500 }); + } + + // Create a ReadableStream for streaming response + const stream = new ReadableStream({ + async start(controller) { + const encoder = new TextEncoder(); + try { + for await (const chunk of result.textStream) { + if (chunk) { + controller.enqueue(encoder.encode(chunk)); + } + } + controller.close(); + } catch (error) { + controller.error(error); + } + }, + }); + + return new Response(stream, { + headers: { "Content-Type": "text/plain; charset=utf-8", "Cache-Control": "no-cache" }, + }); + } + + return NextResponse.json(response, { status: response.status || 200 }); + } +} \ No newline at end of file diff --git a/frameworks/nextjs/package/nextjs-publish-changes.ts b/frameworks/nextjs/package/nextjs-publish-changes.ts deleted file mode 100644 index 80fdcc0d3..000000000 --- a/frameworks/nextjs/package/nextjs-publish-changes.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { PublishChangesAction } from "@chaibuilder/sdk/actions"; -import { revalidatePath, revalidateTag } from "next/cache"; - -export class NextJsPublishChangesAction extends PublishChangesAction { - async execute(data: any) { - const response = await super.execute(data); - const { tags, paths } = response; - - // Handle tags revalidation - if (tags && tags.length > 0) { - await Promise.all(tags.map((tag: string) => revalidateTag(tag, "max"))); - } - - // Handle paths revalidation and regeneration - if (paths && paths.length > 0) { - await Promise.all(paths.map((path: string) => revalidatePath(path))); - - // Trigger immediate regeneration of the pages - const hostname = this.context?.hostname; - if (hostname) { - const protocol = hostname.includes("localhost") ? "http" : "https"; - const origin = `${protocol}://${hostname}`; - - await Promise.allSettled( - paths.map(async (path: string) => { - if (!path || !path.startsWith("/")) return; - try { - const url = `${origin}${path}`; - await fetch(url, { - method: "GET", - headers: { - "x-isr-regeneration": "true", - }, - }); - console.log(`Triggered regeneration for ${path}`); - } catch (err) { - console.error( - `Failed to trigger regeneration for ${path}`, - err - ); - } - }) - ); - } else { - console.warn( - "Hostname not found in context. Skipping page regeneration." - ); - } - } - - return response; - } -} diff --git a/frameworks/nextjs/package/update-pages.ts b/frameworks/nextjs/package/update-pages.ts new file mode 100644 index 000000000..2f3e77b15 --- /dev/null +++ b/frameworks/nextjs/package/update-pages.ts @@ -0,0 +1,7 @@ +"use server" + +import { updateTag } from "next/cache"; + +export async function updatePages(tags: string[]) { + await Promise.all(tags.map((tag: string) => updateTag(tag))); +} \ No newline at end of file diff --git a/src/pages/chaibuilder-pages.tsx b/src/pages/chaibuilder-pages.tsx index 6f44c2ee5..6fc5f9c9a 100644 --- a/src/pages/chaibuilder-pages.tsx +++ b/src/pages/chaibuilder-pages.tsx @@ -280,6 +280,7 @@ const ChaiWebsiteBuilder = (props: ChaiWebsiteBuilderProps) => { "getLoggedInUser", "flags", "currentUser", + "onPublish" ]), ); setTimeout(() => { diff --git a/src/pages/hooks/pages/mutations.ts b/src/pages/hooks/pages/mutations.ts index 48b6e06a3..200c3cd10 100644 --- a/src/pages/hooks/pages/mutations.ts +++ b/src/pages/hooks/pages/mutations.ts @@ -3,12 +3,12 @@ import { useSavePage } from "@/hooks/use-save-page"; import { ACTIONS } from "@/pages/constants/ACTIONS"; import { ERRORS } from "@/pages/constants/ERRORS"; import { useCurrentActivePage } from "@/pages/hooks/pages/use-current-page"; -import { useApiUrl } from "@/pages/hooks/project/use-builder-prop"; +import { useApiUrl, usePagesProp } from "@/pages/hooks/project/use-builder-prop"; import { usePageTypes } from "@/pages/hooks/project/use-page-types"; import { useRevisionsEnabled } from "@/pages/hooks/use-revisions-enabled"; import { useFetch } from "@/pages/hooks/utils/use-fetch"; import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { find, get } from "lodash-es"; +import { find, get, noop } from "lodash-es"; import { toast } from "sonner"; export const useCreatePage = () => { @@ -186,6 +186,7 @@ export const usePublishPages = () => { const { savePageAsync } = useSavePage(); const revisionsEnabled = useRevisionsEnabled(); const { handleQuerySync } = useQuerySync(); + const onPublish = usePagesProp('onPublish', noop) return useMutation({ mutationFn: async ({ ids }: { ids: string[] }) => { @@ -196,16 +197,17 @@ export const usePublishPages = () => { data: { ids, revisions: revisionsEnabled }, }); }, - onSuccess: (_data, { ids }) => { + onSuccess: (data, { ids }) => { // Invalidate pages query to reflect cleared changes and updated online status handleQuerySync({ type: "PUBLISH_CHANGES", data: { ids }, sync: true, }); + onPublish(data.tags) }, onError: (error) => { - console.log("##", error); + console.log(error); toast.error("Failed to publish pages."); }, }); diff --git a/src/types/common.ts b/src/types/common.ts index da13f1473..9beb8ff32 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -56,6 +56,7 @@ export type ChaiWebsiteBuilderProps = { currentUser: LoggedInUser | null; websocket?: any; realtimeAdapter?: RealtimeAdapter; + onPublish?: (tags: string[]) => void } & Pick< ChaiBuilderEditorProps, | "onError" From 5a6b78c722cdeef36f79bd53bf0e2343e6ab06db Mon Sep 17 00:00:00 2001 From: amitdhiman5086 Date: Thu, 19 Feb 2026 16:58:32 +0530 Subject: [PATCH 5/6] refactor: remove `paths` from publish changes action and `hostname` from action context --- src/actions/builder/chai-action-interface.ts | 1 - .../builder/chai-builder-actions-handler.ts | 6 +++--- src/actions/builder/publish-changes.ts | 20 +++++++------------ src/actions/export.ts | 1 - 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/actions/builder/chai-action-interface.ts b/src/actions/builder/chai-action-interface.ts index 11f67aef5..c150c83ea 100644 --- a/src/actions/builder/chai-action-interface.ts +++ b/src/actions/builder/chai-action-interface.ts @@ -5,7 +5,6 @@ export interface ChaiActionContext { appId: string; userId?: string; - hostname?: string; } /** diff --git a/src/actions/builder/chai-builder-actions-handler.ts b/src/actions/builder/chai-builder-actions-handler.ts index 21f368a73..958aef5ac 100644 --- a/src/actions/builder/chai-builder-actions-handler.ts +++ b/src/actions/builder/chai-builder-actions-handler.ts @@ -2,9 +2,9 @@ import { ActionError } from "./action-error"; import { getChaiAction } from "./actions-registery"; import { ChaiBaseAction } from "./base-action"; -export const initChaiBuilderActionHandler = (params: { apiKey: string; userId: string; hostname?: string }) => { +export const initChaiBuilderActionHandler = (params: { apiKey: string; userId: string; }) => { return async (actionData: { action: string; data?: unknown }) => { - const { apiKey, userId, hostname } = params; + const { apiKey, userId } = params; try { const requestBody = actionData; const { action, data } = requestBody; @@ -29,7 +29,7 @@ export const initChaiBuilderActionHandler = (params: { apiKey: string; userId: s } // If action is registered in the new system, use it // Set the context on the action handler - actionHandler.setContext({ appId: apiKey, userId, hostname }); + actionHandler.setContext({ appId: apiKey, userId }); // Execute the action return await actionHandler.execute(data); // } diff --git a/src/actions/builder/publish-changes.ts b/src/actions/builder/publish-changes.ts index c1b17f297..bcd9a599a 100644 --- a/src/actions/builder/publish-changes.ts +++ b/src/actions/builder/publish-changes.ts @@ -15,7 +15,6 @@ type PublishChangesActionData = { type PublishChangesActionResponse = { tags: string[]; - paths: string[]; }; /** @@ -86,9 +85,7 @@ export class PublishChangesAction extends ChaiBaseAction r.tags))); - const paths = uniq(flattenDeep(responses.map((r) => r.paths))); - return { tags, paths }; + return { tags: uniq(flattenDeep(responses)) }; } catch (error) { return this.handleExecutionError(error); } @@ -106,7 +103,7 @@ export class PublishChangesAction extends ChaiBaseAction { + private async publishTheme(): Promise { const app = await this.cloneApp(); // Delete existing online app @@ -130,13 +127,13 @@ export class PublishChangesAction extends ChaiBaseAction { + private async publishDesignToken(): Promise { const app = await this.cloneApp(); // Delete existing online app @@ -160,7 +157,7 @@ export class PublishChangesAction extends ChaiBaseAction { + private async publishPage(id: string): Promise { const page = await this.clonePage(id); await this.addOnlinePage(page); const tags = [`page-${page.primaryPage ?? page.id}`]; - const paths: string[] = []; if (isEmpty(page.slug)) { tags.push(...(await this.getPartialBlockUsage(page.primaryPage ?? page.id))); - } else { - paths.push(`${page.slug}`); } - return { tags, paths }; + return tags; } /** diff --git a/src/actions/export.ts b/src/actions/export.ts index 5b4490bd3..8bbfa1a6b 100644 --- a/src/actions/export.ts +++ b/src/actions/export.ts @@ -2,7 +2,6 @@ import ChaiActionsRegistry from "./builder/actions-registery"; import { getAskAiSystemPrompt } from "./classes/system-prompt"; export { initChaiBuilderActionHandler } from "./builder/chai-builder-actions-handler"; -export { PublishChangesAction } from "./builder/publish-changes"; export { db, safeQuery, schema } from "./db"; export { LANGUAGES } from "./LANGUAGES"; export { ChaiActionsRegistry, getAskAiSystemPrompt }; From cf98e6d76fb3e545cb1a2f79aabfb0cbb477f31f Mon Sep 17 00:00:00 2001 From: amitdhiman5086 Date: Thu, 19 Feb 2026 17:06:06 +0530 Subject: [PATCH 6/6] refactor: centralize `updatePages` export in `actions.ts` and update its import path --- frameworks/nextjs/app/(builder)/editor/editor.tsx | 2 +- frameworks/nextjs/package/actions.ts | 3 +++ src/actions/builder/chai-builder-actions-handler.ts | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/frameworks/nextjs/app/(builder)/editor/editor.tsx b/frameworks/nextjs/app/(builder)/editor/editor.tsx index b8d749875..b191d7a3c 100644 --- a/frameworks/nextjs/app/(builder)/editor/editor.tsx +++ b/frameworks/nextjs/app/(builder)/editor/editor.tsx @@ -9,7 +9,7 @@ import "@chaibuilder/sdk/styles"; import dynamic from "next/dynamic"; import { useCallback, useEffect, useState } from "react"; import { LoginScreen } from "./login"; -import { updatePages } from "@/package/update-pages"; +import { updatePages } from "@/package/actions"; const ChaiWebsiteBuilder = dynamic(() => import("@chaibuilder/sdk/pages").then((mod) => mod.ChaiWebsiteBuilder), { ssr: false, }); diff --git a/frameworks/nextjs/package/actions.ts b/frameworks/nextjs/package/actions.ts index db153b1cd..0c016c939 100644 --- a/frameworks/nextjs/package/actions.ts +++ b/frameworks/nextjs/package/actions.ts @@ -1,6 +1,9 @@ import { initChaiBuilderActionHandler } from "@chaibuilder/sdk/actions"; import { NextResponse } from "next/server"; +import { updatePages } from "./update-pages"; + export * from "@chaibuilder/sdk/actions"; +export { updatePages }; export function initChaiBuilderNextJSActionHandler({ apiKey, userId }: { apiKey: string, userId: string }) { return async function (body: any) { const actionHandler = initChaiBuilderActionHandler({ apiKey, userId }) diff --git a/src/actions/builder/chai-builder-actions-handler.ts b/src/actions/builder/chai-builder-actions-handler.ts index 958aef5ac..78ec9a990 100644 --- a/src/actions/builder/chai-builder-actions-handler.ts +++ b/src/actions/builder/chai-builder-actions-handler.ts @@ -2,7 +2,7 @@ import { ActionError } from "./action-error"; import { getChaiAction } from "./actions-registery"; import { ChaiBaseAction } from "./base-action"; -export const initChaiBuilderActionHandler = (params: { apiKey: string; userId: string; }) => { +export const initChaiBuilderActionHandler = (params: { apiKey: string; userId: string }) => { return async (actionData: { action: string; data?: unknown }) => { const { apiKey, userId } = params; try {