Fix/publish api manifest - #11142

Closed
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest
Closed

Fix/publish api manifest#11142
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest

Conversation

@yosiwizman

Copy link
Copy Markdown

No description provided.

Yosi Wizmanand others added 10 commits January 5, 2026 14:08
- Update package name and description
- Update page title and meta description
- Update UI placeholder text and header logo
- Update AI system prompt identity
- Update favicon and icons
- Update README with attribution
- Update GitHub issue templates
- Add .gitattributes for LF enforcement
Co-Authored-By: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
* ci: add staging deployment workflow and update README
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-Authored-By: Warp <agent@warp.dev>
* docs: update README with production status and release process
- Change staging to production status
- Add live URL designation
- Add release process documentation
- Document safeguards
Co-Authored-By: Warp <agent@warp.dev>
---------
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add public/_headers with COOP/COEP headers for Cloudflare Pages
- Update entry.server.tsx to use credentialless COEP
- Add COOP/COEP headers to Cloudflare Pages function
- Add COOP/COEP headers to Vite dev server
- Add crossOriginIsolated verification warning in root.tsx
- Document cross-origin isolation in README
Headers:
- Cross-Origin-Opener-Policy: same-origin
- Cross-Origin-Embedder-Policy: credentialless
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add publish.ts store for state management
- Add api.publish.ts API endpoint for Cloudflare Pages deployment
- Add PublishButton.client.tsx UI component
- Update README with publish feature documentation
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-Authored-By: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
CopilotAI review requested due to automatic review settings January 6, 2026 01:35

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR rebrands "Bolt" to "X Builder" and implements an MVP publish feature that deploys projects to Cloudflare Pages via the Direct Upload API. The changes include cross-origin isolation headers (COOP/COEP) required for WebContainers, CI/CD workflows for automated deployment, and comprehensive documentation updates.

Key changes:

  • Complete rebrand from "Bolt" to "X Builder" across all user-facing text and branding assets
  • New publish API endpoint (/api/publish) for deploying to Cloudflare Pages
  • Cross-origin isolation headers configured across all entry points to enable SharedArrayBuffer support
  • GitHub Actions workflows for CI and staging deployment

Reviewed changes

Copilot reviewed 21 out of 23 changed files in this pull request and generated 12 comments.

Show a summary per file
FileDescription
wrangler.tomlUpdates worker name from "bolt" to "x-builder"
vite.config.tsAdds COOP/COEP headers to development server
public/favicon.svgUpdates branding from lightning bolt to "X" logo
public/_headersAdds COOP/COEP headers for Cloudflare Pages
package.jsonUpdates project metadata and adds smoke test script
icons/logo.svgUpdates branding to match new favicon
functions/[[path]].tsWraps Remix handler to inject COOP/COEP headers
app/routes/api.publish.tsNew API endpoint for Cloudflare Pages deployment
app/routes/_index.tsxUpdates page title and meta description
app/root.tsxAdds crossOriginIsolated verification check
app/lib/stores/publish.tsNew state management for publish functionality
app/lib/.server/llm/prompts.tsUpdates AI assistant name in system prompt
app/entry.server.tsxChanges COEP from require-corp to credentialless
app/components/workbench/PublishButton.client.tsxNew UI component for publishing projects
app/components/sidebar/Menu.client.tsxRemoves unused IconButton import
app/components/header/Header.tsxReplaces logo with text branding
app/components/chat/BaseChat.tsxUpdates chat placeholder text
README.mdComplete rewrite with X Builder documentation
.github/workflows/deploy-staging.ymlNew deployment workflow for Cloudflare Pages
.github/workflows/ci.ymlNew CI workflow for linting and testing
.github/ISSUE_TEMPLATE/config.ymlUpdates issue template links
.github/ISSUE_TEMPLATE/bug_report.ymlUpdates references to X Builder
.gitattributesNew file enforcing LF line endings

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* - A "manifest" field containing JSON object mapping file paths to empty strings
* - Individual file fields where field name is the file path and value is file content
*/
export async function action({ context, request }: ActionFunctionArgs) {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The publish API endpoint has no authentication or rate limiting. Any user can publish unlimited projects to your Cloudflare account, potentially incurring costs or resource exhaustion. Consider adding authentication checks or rate limiting.

Copilot uses AI. Check for mistakes.
}

try {
const { files, projectName = 'x-builder-preview' } = await request.json<PublishRequest>();

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The projectName parameter lacks validation. Malicious values could potentially be used in path traversal or injection attacks when used in the API URL. Consider validating that it matches Cloudflare's project naming requirements (alphanumeric and hyphens only, specific length limits).

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +40
if (!files || Object.keys(files).length === 0) {
return json({ error: 'No files provided for publishing' }, { status: 400 });
}

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no validation on file sizes or total payload size. A user could upload extremely large files, potentially causing memory issues or exceeding Cloudflare's size limits. Consider adding reasonable size limits and validation.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +13
# Only deploy after CI passes
needs: []

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "Only deploy after CI passes" but the needs array is empty. If there's a CI job that should run before deployment, it should be referenced here (e.g., needs: [ci]). Otherwise, deployments will run without waiting for CI validation.

Suggested change
# Only deploy after CI passes
needs: []

Copilot uses AI. Check for mistakes.
Comment threadpackage.json
Comment on lines +20 to +21
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script 'smoke:publish' references 'scripts/smoke-test-publish.ts' but this file does not exist in the repository. This script will fail when executed.

Suggested change
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"
"preview": "pnpm run build && pnpm run start"

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +79
for (const [filePath, content] of Object.entries(files)) {
// normalize path to include leading slash (required by CF Pages)
const normalizedPath = filePath.startsWith('/') ? filePath : `/${filePath}`;

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File paths from the request are not validated for malicious content. A user could potentially include paths like '../../../etc/passwd' or other path traversal attempts. Consider validating that paths don't contain '..' segments and are within expected boundaries.

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
const response = await handler(context);

// clone response to modify headers
const newResponse = new Response(response.body, response);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a new Response with response.body may fail if the response body has already been consumed or is not readable. Consider using response.clone() before creating the new response to avoid potential stream consumption issues.

Suggested change
constnewResponse=newResponse(response.body,response);
constnewResponse=response.clone();

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
/**
* Wrap handler to add COOP/COEP headers for crossOriginIsolated.
*/
export const onRequest: PagesFunction = async (context) => {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type PagesFunction is used but not imported. This will cause a TypeScript error. Import it from '@cloudflare/workers-types' or use the appropriate type definition.

Copilot uses AI. Check for mistakes.
// project might already exist (409), which is fine
if (!projectResponse.ok && projectResponse.status !== 409) {
const errorData = await projectResponse.json();
console.error('Failed to create project:', errorData);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the project creation fails (non-409 status), the error is logged but execution continues. This could lead to deployment attempts on non-existent projects. Consider returning an error response or at least validating the project exists before attempting deployment.

Suggested change
console.error('Failed to create project:',errorData);
console.error('Failed to create project:',errorData);
returnjson(
{
error: 'Failed to create project before deployment.',
details: errorData,
},
{status: projectResponse.status||502},
);

Copilot uses AI. Check for mistakes.
deploymentId: deployResult.result?.id,
});
} catch (error) {
console.error('Publish error:', error);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generic catch block doesn't differentiate between JSON parsing errors from request.json() and other errors. If the request body is malformed JSON, a more specific error message would be helpful (e.g., 'Invalid request body').

Suggested change
console.error('Publish error:',error);
console.error('Publish error:',error);
if(errorinstanceofSyntaxError){
// Likely caused by malformed JSON in the request body
returnjson({error: 'Invalid request body'},{status: 400});
}

Copilot uses AI. Check for mistakes.
@yosiwizman
yosiwizman deleted the fix/publish-api-manifest branch January 6, 2026 01:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@yosiwizman
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Fix/publish api manifest - #11142

Closed
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest
Closed

Fix/publish api manifest#11142
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest

Conversation

@yosiwizman

Copy link
Copy Markdown

No description provided.

Yosi Wizmanand others added 10 commits January 5, 2026 14:08
- Update package name and description
- Update page title and meta description
- Update UI placeholder text and header logo
- Update AI system prompt identity
- Update favicon and icons
- Update README with attribution
- Update GitHub issue templates
- Add .gitattributes for LF enforcement
Co-Authored-By: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
* ci: add staging deployment workflow and update README
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-Authored-By: Warp <agent@warp.dev>
* docs: update README with production status and release process
- Change staging to production status
- Add live URL designation
- Add release process documentation
- Document safeguards
Co-Authored-By: Warp <agent@warp.dev>
---------
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add public/_headers with COOP/COEP headers for Cloudflare Pages
- Update entry.server.tsx to use credentialless COEP
- Add COOP/COEP headers to Cloudflare Pages function
- Add COOP/COEP headers to Vite dev server
- Add crossOriginIsolated verification warning in root.tsx
- Document cross-origin isolation in README
Headers:
- Cross-Origin-Opener-Policy: same-origin
- Cross-Origin-Embedder-Policy: credentialless
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add publish.ts store for state management
- Add api.publish.ts API endpoint for Cloudflare Pages deployment
- Add PublishButton.client.tsx UI component
- Update README with publish feature documentation
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-Authored-By: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
CopilotAI review requested due to automatic review settings January 6, 2026 01:35

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR rebrands "Bolt" to "X Builder" and implements an MVP publish feature that deploys projects to Cloudflare Pages via the Direct Upload API. The changes include cross-origin isolation headers (COOP/COEP) required for WebContainers, CI/CD workflows for automated deployment, and comprehensive documentation updates.

Key changes:

  • Complete rebrand from "Bolt" to "X Builder" across all user-facing text and branding assets
  • New publish API endpoint (/api/publish) for deploying to Cloudflare Pages
  • Cross-origin isolation headers configured across all entry points to enable SharedArrayBuffer support
  • GitHub Actions workflows for CI and staging deployment

Reviewed changes

Copilot reviewed 21 out of 23 changed files in this pull request and generated 12 comments.

Show a summary per file
FileDescription
wrangler.tomlUpdates worker name from "bolt" to "x-builder"
vite.config.tsAdds COOP/COEP headers to development server
public/favicon.svgUpdates branding from lightning bolt to "X" logo
public/_headersAdds COOP/COEP headers for Cloudflare Pages
package.jsonUpdates project metadata and adds smoke test script
icons/logo.svgUpdates branding to match new favicon
functions/[[path]].tsWraps Remix handler to inject COOP/COEP headers
app/routes/api.publish.tsNew API endpoint for Cloudflare Pages deployment
app/routes/_index.tsxUpdates page title and meta description
app/root.tsxAdds crossOriginIsolated verification check
app/lib/stores/publish.tsNew state management for publish functionality
app/lib/.server/llm/prompts.tsUpdates AI assistant name in system prompt
app/entry.server.tsxChanges COEP from require-corp to credentialless
app/components/workbench/PublishButton.client.tsxNew UI component for publishing projects
app/components/sidebar/Menu.client.tsxRemoves unused IconButton import
app/components/header/Header.tsxReplaces logo with text branding
app/components/chat/BaseChat.tsxUpdates chat placeholder text
README.mdComplete rewrite with X Builder documentation
.github/workflows/deploy-staging.ymlNew deployment workflow for Cloudflare Pages
.github/workflows/ci.ymlNew CI workflow for linting and testing
.github/ISSUE_TEMPLATE/config.ymlUpdates issue template links
.github/ISSUE_TEMPLATE/bug_report.ymlUpdates references to X Builder
.gitattributesNew file enforcing LF line endings

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* - A "manifest" field containing JSON object mapping file paths to empty strings
* - Individual file fields where field name is the file path and value is file content
*/
export async function action({ context, request }: ActionFunctionArgs) {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The publish API endpoint has no authentication or rate limiting. Any user can publish unlimited projects to your Cloudflare account, potentially incurring costs or resource exhaustion. Consider adding authentication checks or rate limiting.

Copilot uses AI. Check for mistakes.
}

try {
const { files, projectName = 'x-builder-preview' } = await request.json<PublishRequest>();

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The projectName parameter lacks validation. Malicious values could potentially be used in path traversal or injection attacks when used in the API URL. Consider validating that it matches Cloudflare's project naming requirements (alphanumeric and hyphens only, specific length limits).

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +40
if (!files || Object.keys(files).length === 0) {
return json({ error: 'No files provided for publishing' }, { status: 400 });
}

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no validation on file sizes or total payload size. A user could upload extremely large files, potentially causing memory issues or exceeding Cloudflare's size limits. Consider adding reasonable size limits and validation.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +13
# Only deploy after CI passes
needs: []

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "Only deploy after CI passes" but the needs array is empty. If there's a CI job that should run before deployment, it should be referenced here (e.g., needs: [ci]). Otherwise, deployments will run without waiting for CI validation.

Suggested change
# Only deploy after CI passes
needs: []

Copilot uses AI. Check for mistakes.
Comment threadpackage.json
Comment on lines +20 to +21
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script 'smoke:publish' references 'scripts/smoke-test-publish.ts' but this file does not exist in the repository. This script will fail when executed.

Suggested change
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"
"preview": "pnpm run build && pnpm run start"

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +79
for (const [filePath, content] of Object.entries(files)) {
// normalize path to include leading slash (required by CF Pages)
const normalizedPath = filePath.startsWith('/') ? filePath : `/${filePath}`;

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File paths from the request are not validated for malicious content. A user could potentially include paths like '../../../etc/passwd' or other path traversal attempts. Consider validating that paths don't contain '..' segments and are within expected boundaries.

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
const response = await handler(context);

// clone response to modify headers
const newResponse = new Response(response.body, response);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a new Response with response.body may fail if the response body has already been consumed or is not readable. Consider using response.clone() before creating the new response to avoid potential stream consumption issues.

Suggested change
constnewResponse=newResponse(response.body,response);
constnewResponse=response.clone();

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
/**
* Wrap handler to add COOP/COEP headers for crossOriginIsolated.
*/
export const onRequest: PagesFunction = async (context) => {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type PagesFunction is used but not imported. This will cause a TypeScript error. Import it from '@cloudflare/workers-types' or use the appropriate type definition.

Copilot uses AI. Check for mistakes.
// project might already exist (409), which is fine
if (!projectResponse.ok && projectResponse.status !== 409) {
const errorData = await projectResponse.json();
console.error('Failed to create project:', errorData);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the project creation fails (non-409 status), the error is logged but execution continues. This could lead to deployment attempts on non-existent projects. Consider returning an error response or at least validating the project exists before attempting deployment.

Suggested change
console.error('Failed to create project:',errorData);
console.error('Failed to create project:',errorData);
returnjson(
{
error: 'Failed to create project before deployment.',
details: errorData,
},
{status: projectResponse.status||502},
);

Copilot uses AI. Check for mistakes.
deploymentId: deployResult.result?.id,
});
} catch (error) {
console.error('Publish error:', error);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generic catch block doesn't differentiate between JSON parsing errors from request.json() and other errors. If the request body is malformed JSON, a more specific error message would be helpful (e.g., 'Invalid request body').

Suggested change
console.error('Publish error:',error);
console.error('Publish error:',error);
if(errorinstanceofSyntaxError){
// Likely caused by malformed JSON in the request body
returnjson({error: 'Invalid request body'},{status: 400});
}

Copilot uses AI. Check for mistakes.
@yosiwizman
yosiwizman deleted the fix/publish-api-manifest branch January 6, 2026 01:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@yosiwizman
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix/publish api manifest - #11142

Closed
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest
Closed

Fix/publish api manifest#11142
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest

Conversation

@yosiwizman

Copy link
Copy Markdown

No description provided.

Yosi Wizmanand others added 10 commits January 5, 2026 14:08
- Update package name and description
- Update page title and meta description
- Update UI placeholder text and header logo
- Update AI system prompt identity
- Update favicon and icons
- Update README with attribution
- Update GitHub issue templates
- Add .gitattributes for LF enforcement
Co-Authored-By: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
* ci: add staging deployment workflow and update README
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-Authored-By: Warp <agent@warp.dev>
* docs: update README with production status and release process
- Change staging to production status
- Add live URL designation
- Add release process documentation
- Document safeguards
Co-Authored-By: Warp <agent@warp.dev>
---------
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add public/_headers with COOP/COEP headers for Cloudflare Pages
- Update entry.server.tsx to use credentialless COEP
- Add COOP/COEP headers to Cloudflare Pages function
- Add COOP/COEP headers to Vite dev server
- Add crossOriginIsolated verification warning in root.tsx
- Document cross-origin isolation in README
Headers:
- Cross-Origin-Opener-Policy: same-origin
- Cross-Origin-Embedder-Policy: credentialless
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add publish.ts store for state management
- Add api.publish.ts API endpoint for Cloudflare Pages deployment
- Add PublishButton.client.tsx UI component
- Update README with publish feature documentation
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-Authored-By: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
CopilotAI review requested due to automatic review settings January 6, 2026 01:35

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR rebrands "Bolt" to "X Builder" and implements an MVP publish feature that deploys projects to Cloudflare Pages via the Direct Upload API. The changes include cross-origin isolation headers (COOP/COEP) required for WebContainers, CI/CD workflows for automated deployment, and comprehensive documentation updates.

Key changes:

  • Complete rebrand from "Bolt" to "X Builder" across all user-facing text and branding assets
  • New publish API endpoint (/api/publish) for deploying to Cloudflare Pages
  • Cross-origin isolation headers configured across all entry points to enable SharedArrayBuffer support
  • GitHub Actions workflows for CI and staging deployment

Reviewed changes

Copilot reviewed 21 out of 23 changed files in this pull request and generated 12 comments.

Show a summary per file
FileDescription
wrangler.tomlUpdates worker name from "bolt" to "x-builder"
vite.config.tsAdds COOP/COEP headers to development server
public/favicon.svgUpdates branding from lightning bolt to "X" logo
public/_headersAdds COOP/COEP headers for Cloudflare Pages
package.jsonUpdates project metadata and adds smoke test script
icons/logo.svgUpdates branding to match new favicon
functions/[[path]].tsWraps Remix handler to inject COOP/COEP headers
app/routes/api.publish.tsNew API endpoint for Cloudflare Pages deployment
app/routes/_index.tsxUpdates page title and meta description
app/root.tsxAdds crossOriginIsolated verification check
app/lib/stores/publish.tsNew state management for publish functionality
app/lib/.server/llm/prompts.tsUpdates AI assistant name in system prompt
app/entry.server.tsxChanges COEP from require-corp to credentialless
app/components/workbench/PublishButton.client.tsxNew UI component for publishing projects
app/components/sidebar/Menu.client.tsxRemoves unused IconButton import
app/components/header/Header.tsxReplaces logo with text branding
app/components/chat/BaseChat.tsxUpdates chat placeholder text
README.mdComplete rewrite with X Builder documentation
.github/workflows/deploy-staging.ymlNew deployment workflow for Cloudflare Pages
.github/workflows/ci.ymlNew CI workflow for linting and testing
.github/ISSUE_TEMPLATE/config.ymlUpdates issue template links
.github/ISSUE_TEMPLATE/bug_report.ymlUpdates references to X Builder
.gitattributesNew file enforcing LF line endings

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* - A "manifest" field containing JSON object mapping file paths to empty strings
* - Individual file fields where field name is the file path and value is file content
*/
export async function action({ context, request }: ActionFunctionArgs) {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The publish API endpoint has no authentication or rate limiting. Any user can publish unlimited projects to your Cloudflare account, potentially incurring costs or resource exhaustion. Consider adding authentication checks or rate limiting.

Copilot uses AI. Check for mistakes.
}

try {
const { files, projectName = 'x-builder-preview' } = await request.json<PublishRequest>();

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The projectName parameter lacks validation. Malicious values could potentially be used in path traversal or injection attacks when used in the API URL. Consider validating that it matches Cloudflare's project naming requirements (alphanumeric and hyphens only, specific length limits).

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +40
if (!files || Object.keys(files).length === 0) {
return json({ error: 'No files provided for publishing' }, { status: 400 });
}

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no validation on file sizes or total payload size. A user could upload extremely large files, potentially causing memory issues or exceeding Cloudflare's size limits. Consider adding reasonable size limits and validation.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +13
# Only deploy after CI passes
needs: []

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "Only deploy after CI passes" but the needs array is empty. If there's a CI job that should run before deployment, it should be referenced here (e.g., needs: [ci]). Otherwise, deployments will run without waiting for CI validation.

Suggested change
# Only deploy after CI passes
needs: []

Copilot uses AI. Check for mistakes.
Comment threadpackage.json
Comment on lines +20 to +21
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script 'smoke:publish' references 'scripts/smoke-test-publish.ts' but this file does not exist in the repository. This script will fail when executed.

Suggested change
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"
"preview": "pnpm run build && pnpm run start"

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +79
for (const [filePath, content] of Object.entries(files)) {
// normalize path to include leading slash (required by CF Pages)
const normalizedPath = filePath.startsWith('/') ? filePath : `/${filePath}`;

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File paths from the request are not validated for malicious content. A user could potentially include paths like '../../../etc/passwd' or other path traversal attempts. Consider validating that paths don't contain '..' segments and are within expected boundaries.

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
const response = await handler(context);

// clone response to modify headers
const newResponse = new Response(response.body, response);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a new Response with response.body may fail if the response body has already been consumed or is not readable. Consider using response.clone() before creating the new response to avoid potential stream consumption issues.

Suggested change
constnewResponse=newResponse(response.body,response);
constnewResponse=response.clone();

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
/**
* Wrap handler to add COOP/COEP headers for crossOriginIsolated.
*/
export const onRequest: PagesFunction = async (context) => {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type PagesFunction is used but not imported. This will cause a TypeScript error. Import it from '@cloudflare/workers-types' or use the appropriate type definition.

Copilot uses AI. Check for mistakes.
// project might already exist (409), which is fine
if (!projectResponse.ok && projectResponse.status !== 409) {
const errorData = await projectResponse.json();
console.error('Failed to create project:', errorData);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the project creation fails (non-409 status), the error is logged but execution continues. This could lead to deployment attempts on non-existent projects. Consider returning an error response or at least validating the project exists before attempting deployment.

Suggested change
console.error('Failed to create project:',errorData);
console.error('Failed to create project:',errorData);
returnjson(
{
error: 'Failed to create project before deployment.',
details: errorData,
},
{status: projectResponse.status||502},
);

Copilot uses AI. Check for mistakes.
deploymentId: deployResult.result?.id,
});
} catch (error) {
console.error('Publish error:', error);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generic catch block doesn't differentiate between JSON parsing errors from request.json() and other errors. If the request body is malformed JSON, a more specific error message would be helpful (e.g., 'Invalid request body').

Suggested change
console.error('Publish error:',error);
console.error('Publish error:',error);
if(errorinstanceofSyntaxError){
// Likely caused by malformed JSON in the request body
returnjson({error: 'Invalid request body'},{status: 400});
}

Copilot uses AI. Check for mistakes.
@yosiwizman
yosiwizman deleted the fix/publish-api-manifest branch January 6, 2026 01:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@yosiwizman
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix/publish api manifest - #11142

Closed
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest
Closed

Fix/publish api manifest#11142
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest

Conversation

@yosiwizman

Copy link
Copy Markdown

No description provided.

Yosi Wizmanand others added 10 commits January 5, 2026 14:08
- Update package name and description
- Update page title and meta description
- Update UI placeholder text and header logo
- Update AI system prompt identity
- Update favicon and icons
- Update README with attribution
- Update GitHub issue templates
- Add .gitattributes for LF enforcement
Co-Authored-By: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
* ci: add staging deployment workflow and update README
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-Authored-By: Warp <agent@warp.dev>
* docs: update README with production status and release process
- Change staging to production status
- Add live URL designation
- Add release process documentation
- Document safeguards
Co-Authored-By: Warp <agent@warp.dev>
---------
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add public/_headers with COOP/COEP headers for Cloudflare Pages
- Update entry.server.tsx to use credentialless COEP
- Add COOP/COEP headers to Cloudflare Pages function
- Add COOP/COEP headers to Vite dev server
- Add crossOriginIsolated verification warning in root.tsx
- Document cross-origin isolation in README
Headers:
- Cross-Origin-Opener-Policy: same-origin
- Cross-Origin-Embedder-Policy: credentialless
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add publish.ts store for state management
- Add api.publish.ts API endpoint for Cloudflare Pages deployment
- Add PublishButton.client.tsx UI component
- Update README with publish feature documentation
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-Authored-By: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
CopilotAI review requested due to automatic review settings January 6, 2026 01:35

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR rebrands "Bolt" to "X Builder" and implements an MVP publish feature that deploys projects to Cloudflare Pages via the Direct Upload API. The changes include cross-origin isolation headers (COOP/COEP) required for WebContainers, CI/CD workflows for automated deployment, and comprehensive documentation updates.

Key changes:

  • Complete rebrand from "Bolt" to "X Builder" across all user-facing text and branding assets
  • New publish API endpoint (/api/publish) for deploying to Cloudflare Pages
  • Cross-origin isolation headers configured across all entry points to enable SharedArrayBuffer support
  • GitHub Actions workflows for CI and staging deployment

Reviewed changes

Copilot reviewed 21 out of 23 changed files in this pull request and generated 12 comments.

Show a summary per file
FileDescription
wrangler.tomlUpdates worker name from "bolt" to "x-builder"
vite.config.tsAdds COOP/COEP headers to development server
public/favicon.svgUpdates branding from lightning bolt to "X" logo
public/_headersAdds COOP/COEP headers for Cloudflare Pages
package.jsonUpdates project metadata and adds smoke test script
icons/logo.svgUpdates branding to match new favicon
functions/[[path]].tsWraps Remix handler to inject COOP/COEP headers
app/routes/api.publish.tsNew API endpoint for Cloudflare Pages deployment
app/routes/_index.tsxUpdates page title and meta description
app/root.tsxAdds crossOriginIsolated verification check
app/lib/stores/publish.tsNew state management for publish functionality
app/lib/.server/llm/prompts.tsUpdates AI assistant name in system prompt
app/entry.server.tsxChanges COEP from require-corp to credentialless
app/components/workbench/PublishButton.client.tsxNew UI component for publishing projects
app/components/sidebar/Menu.client.tsxRemoves unused IconButton import
app/components/header/Header.tsxReplaces logo with text branding
app/components/chat/BaseChat.tsxUpdates chat placeholder text
README.mdComplete rewrite with X Builder documentation
.github/workflows/deploy-staging.ymlNew deployment workflow for Cloudflare Pages
.github/workflows/ci.ymlNew CI workflow for linting and testing
.github/ISSUE_TEMPLATE/config.ymlUpdates issue template links
.github/ISSUE_TEMPLATE/bug_report.ymlUpdates references to X Builder
.gitattributesNew file enforcing LF line endings

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* - A "manifest" field containing JSON object mapping file paths to empty strings
* - Individual file fields where field name is the file path and value is file content
*/
export async function action({ context, request }: ActionFunctionArgs) {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The publish API endpoint has no authentication or rate limiting. Any user can publish unlimited projects to your Cloudflare account, potentially incurring costs or resource exhaustion. Consider adding authentication checks or rate limiting.

Copilot uses AI. Check for mistakes.
}

try {
const { files, projectName = 'x-builder-preview' } = await request.json<PublishRequest>();

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The projectName parameter lacks validation. Malicious values could potentially be used in path traversal or injection attacks when used in the API URL. Consider validating that it matches Cloudflare's project naming requirements (alphanumeric and hyphens only, specific length limits).

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +40
if (!files || Object.keys(files).length === 0) {
return json({ error: 'No files provided for publishing' }, { status: 400 });
}

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no validation on file sizes or total payload size. A user could upload extremely large files, potentially causing memory issues or exceeding Cloudflare's size limits. Consider adding reasonable size limits and validation.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +13
# Only deploy after CI passes
needs: []

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "Only deploy after CI passes" but the needs array is empty. If there's a CI job that should run before deployment, it should be referenced here (e.g., needs: [ci]). Otherwise, deployments will run without waiting for CI validation.

Suggested change
# Only deploy after CI passes
needs: []

Copilot uses AI. Check for mistakes.
Comment threadpackage.json
Comment on lines +20 to +21
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script 'smoke:publish' references 'scripts/smoke-test-publish.ts' but this file does not exist in the repository. This script will fail when executed.

Suggested change
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"
"preview": "pnpm run build && pnpm run start"

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +79
for (const [filePath, content] of Object.entries(files)) {
// normalize path to include leading slash (required by CF Pages)
const normalizedPath = filePath.startsWith('/') ? filePath : `/${filePath}`;

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File paths from the request are not validated for malicious content. A user could potentially include paths like '../../../etc/passwd' or other path traversal attempts. Consider validating that paths don't contain '..' segments and are within expected boundaries.

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
const response = await handler(context);

// clone response to modify headers
const newResponse = new Response(response.body, response);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a new Response with response.body may fail if the response body has already been consumed or is not readable. Consider using response.clone() before creating the new response to avoid potential stream consumption issues.

Suggested change
constnewResponse=newResponse(response.body,response);
constnewResponse=response.clone();

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
/**
* Wrap handler to add COOP/COEP headers for crossOriginIsolated.
*/
export const onRequest: PagesFunction = async (context) => {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type PagesFunction is used but not imported. This will cause a TypeScript error. Import it from '@cloudflare/workers-types' or use the appropriate type definition.

Copilot uses AI. Check for mistakes.
// project might already exist (409), which is fine
if (!projectResponse.ok && projectResponse.status !== 409) {
const errorData = await projectResponse.json();
console.error('Failed to create project:', errorData);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the project creation fails (non-409 status), the error is logged but execution continues. This could lead to deployment attempts on non-existent projects. Consider returning an error response or at least validating the project exists before attempting deployment.

Suggested change
console.error('Failed to create project:',errorData);
console.error('Failed to create project:',errorData);
returnjson(
{
error: 'Failed to create project before deployment.',
details: errorData,
},
{status: projectResponse.status||502},
);

Copilot uses AI. Check for mistakes.
deploymentId: deployResult.result?.id,
});
} catch (error) {
console.error('Publish error:', error);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generic catch block doesn't differentiate between JSON parsing errors from request.json() and other errors. If the request body is malformed JSON, a more specific error message would be helpful (e.g., 'Invalid request body').

Suggested change
console.error('Publish error:',error);
console.error('Publish error:',error);
if(errorinstanceofSyntaxError){
// Likely caused by malformed JSON in the request body
returnjson({error: 'Invalid request body'},{status: 400});
}

Copilot uses AI. Check for mistakes.
@yosiwizman
yosiwizman deleted the fix/publish-api-manifest branch January 6, 2026 01:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@yosiwizman
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Fix/publish api manifest - #11142

Closed
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest
Closed

Fix/publish api manifest#11142
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest

Conversation

@yosiwizman

Copy link
Copy Markdown

No description provided.

Yosi Wizmanand others added 10 commits January 5, 2026 14:08
- Update package name and description
- Update page title and meta description
- Update UI placeholder text and header logo
- Update AI system prompt identity
- Update favicon and icons
- Update README with attribution
- Update GitHub issue templates
- Add .gitattributes for LF enforcement
Co-Authored-By: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
* ci: add staging deployment workflow and update README
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-Authored-By: Warp <agent@warp.dev>
* docs: update README with production status and release process
- Change staging to production status
- Add live URL designation
- Add release process documentation
- Document safeguards
Co-Authored-By: Warp <agent@warp.dev>
---------
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add public/_headers with COOP/COEP headers for Cloudflare Pages
- Update entry.server.tsx to use credentialless COEP
- Add COOP/COEP headers to Cloudflare Pages function
- Add COOP/COEP headers to Vite dev server
- Add crossOriginIsolated verification warning in root.tsx
- Document cross-origin isolation in README
Headers:
- Cross-Origin-Opener-Policy: same-origin
- Cross-Origin-Embedder-Policy: credentialless
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add publish.ts store for state management
- Add api.publish.ts API endpoint for Cloudflare Pages deployment
- Add PublishButton.client.tsx UI component
- Update README with publish feature documentation
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-Authored-By: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
CopilotAI review requested due to automatic review settings January 6, 2026 01:35

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR rebrands "Bolt" to "X Builder" and implements an MVP publish feature that deploys projects to Cloudflare Pages via the Direct Upload API. The changes include cross-origin isolation headers (COOP/COEP) required for WebContainers, CI/CD workflows for automated deployment, and comprehensive documentation updates.

Key changes:

  • Complete rebrand from "Bolt" to "X Builder" across all user-facing text and branding assets
  • New publish API endpoint (/api/publish) for deploying to Cloudflare Pages
  • Cross-origin isolation headers configured across all entry points to enable SharedArrayBuffer support
  • GitHub Actions workflows for CI and staging deployment

Reviewed changes

Copilot reviewed 21 out of 23 changed files in this pull request and generated 12 comments.

Show a summary per file
FileDescription
wrangler.tomlUpdates worker name from "bolt" to "x-builder"
vite.config.tsAdds COOP/COEP headers to development server
public/favicon.svgUpdates branding from lightning bolt to "X" logo
public/_headersAdds COOP/COEP headers for Cloudflare Pages
package.jsonUpdates project metadata and adds smoke test script
icons/logo.svgUpdates branding to match new favicon
functions/[[path]].tsWraps Remix handler to inject COOP/COEP headers
app/routes/api.publish.tsNew API endpoint for Cloudflare Pages deployment
app/routes/_index.tsxUpdates page title and meta description
app/root.tsxAdds crossOriginIsolated verification check
app/lib/stores/publish.tsNew state management for publish functionality
app/lib/.server/llm/prompts.tsUpdates AI assistant name in system prompt
app/entry.server.tsxChanges COEP from require-corp to credentialless
app/components/workbench/PublishButton.client.tsxNew UI component for publishing projects
app/components/sidebar/Menu.client.tsxRemoves unused IconButton import
app/components/header/Header.tsxReplaces logo with text branding
app/components/chat/BaseChat.tsxUpdates chat placeholder text
README.mdComplete rewrite with X Builder documentation
.github/workflows/deploy-staging.ymlNew deployment workflow for Cloudflare Pages
.github/workflows/ci.ymlNew CI workflow for linting and testing
.github/ISSUE_TEMPLATE/config.ymlUpdates issue template links
.github/ISSUE_TEMPLATE/bug_report.ymlUpdates references to X Builder
.gitattributesNew file enforcing LF line endings

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* - A "manifest" field containing JSON object mapping file paths to empty strings
* - Individual file fields where field name is the file path and value is file content
*/
export async function action({ context, request }: ActionFunctionArgs) {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The publish API endpoint has no authentication or rate limiting. Any user can publish unlimited projects to your Cloudflare account, potentially incurring costs or resource exhaustion. Consider adding authentication checks or rate limiting.

Copilot uses AI. Check for mistakes.
}

try {
const { files, projectName = 'x-builder-preview' } = await request.json<PublishRequest>();

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The projectName parameter lacks validation. Malicious values could potentially be used in path traversal or injection attacks when used in the API URL. Consider validating that it matches Cloudflare's project naming requirements (alphanumeric and hyphens only, specific length limits).

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +40
if (!files || Object.keys(files).length === 0) {
return json({ error: 'No files provided for publishing' }, { status: 400 });
}

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no validation on file sizes or total payload size. A user could upload extremely large files, potentially causing memory issues or exceeding Cloudflare's size limits. Consider adding reasonable size limits and validation.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +13
# Only deploy after CI passes
needs: []

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "Only deploy after CI passes" but the needs array is empty. If there's a CI job that should run before deployment, it should be referenced here (e.g., needs: [ci]). Otherwise, deployments will run without waiting for CI validation.

Suggested change
# Only deploy after CI passes
needs: []

Copilot uses AI. Check for mistakes.
Comment threadpackage.json
Comment on lines +20 to +21
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script 'smoke:publish' references 'scripts/smoke-test-publish.ts' but this file does not exist in the repository. This script will fail when executed.

Suggested change
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"
"preview": "pnpm run build && pnpm run start"

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +79
for (const [filePath, content] of Object.entries(files)) {
// normalize path to include leading slash (required by CF Pages)
const normalizedPath = filePath.startsWith('/') ? filePath : `/${filePath}`;

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File paths from the request are not validated for malicious content. A user could potentially include paths like '../../../etc/passwd' or other path traversal attempts. Consider validating that paths don't contain '..' segments and are within expected boundaries.

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
const response = await handler(context);

// clone response to modify headers
const newResponse = new Response(response.body, response);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a new Response with response.body may fail if the response body has already been consumed or is not readable. Consider using response.clone() before creating the new response to avoid potential stream consumption issues.

Suggested change
constnewResponse=newResponse(response.body,response);
constnewResponse=response.clone();

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
/**
* Wrap handler to add COOP/COEP headers for crossOriginIsolated.
*/
export const onRequest: PagesFunction = async (context) => {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type PagesFunction is used but not imported. This will cause a TypeScript error. Import it from '@cloudflare/workers-types' or use the appropriate type definition.

Copilot uses AI. Check for mistakes.
// project might already exist (409), which is fine
if (!projectResponse.ok && projectResponse.status !== 409) {
const errorData = await projectResponse.json();
console.error('Failed to create project:', errorData);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the project creation fails (non-409 status), the error is logged but execution continues. This could lead to deployment attempts on non-existent projects. Consider returning an error response or at least validating the project exists before attempting deployment.

Suggested change
console.error('Failed to create project:',errorData);
console.error('Failed to create project:',errorData);
returnjson(
{
error: 'Failed to create project before deployment.',
details: errorData,
},
{status: projectResponse.status||502},
);

Copilot uses AI. Check for mistakes.
deploymentId: deployResult.result?.id,
});
} catch (error) {
console.error('Publish error:', error);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generic catch block doesn't differentiate between JSON parsing errors from request.json() and other errors. If the request body is malformed JSON, a more specific error message would be helpful (e.g., 'Invalid request body').

Suggested change
console.error('Publish error:',error);
console.error('Publish error:',error);
if(errorinstanceofSyntaxError){
// Likely caused by malformed JSON in the request body
returnjson({error: 'Invalid request body'},{status: 400});
}

Copilot uses AI. Check for mistakes.
@yosiwizman
yosiwizman deleted the fix/publish-api-manifest branch January 6, 2026 01:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@yosiwizman
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix/publish api manifest - #11142

Closed
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest
Closed

Fix/publish api manifest#11142
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest

Conversation

@yosiwizman

Copy link
Copy Markdown

No description provided.

Yosi Wizmanand others added 10 commits January 5, 2026 14:08
- Update package name and description
- Update page title and meta description
- Update UI placeholder text and header logo
- Update AI system prompt identity
- Update favicon and icons
- Update README with attribution
- Update GitHub issue templates
- Add .gitattributes for LF enforcement
Co-Authored-By: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
* ci: add staging deployment workflow and update README
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-Authored-By: Warp <agent@warp.dev>
* docs: update README with production status and release process
- Change staging to production status
- Add live URL designation
- Add release process documentation
- Document safeguards
Co-Authored-By: Warp <agent@warp.dev>
---------
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add public/_headers with COOP/COEP headers for Cloudflare Pages
- Update entry.server.tsx to use credentialless COEP
- Add COOP/COEP headers to Cloudflare Pages function
- Add COOP/COEP headers to Vite dev server
- Add crossOriginIsolated verification warning in root.tsx
- Document cross-origin isolation in README
Headers:
- Cross-Origin-Opener-Policy: same-origin
- Cross-Origin-Embedder-Policy: credentialless
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add publish.ts store for state management
- Add api.publish.ts API endpoint for Cloudflare Pages deployment
- Add PublishButton.client.tsx UI component
- Update README with publish feature documentation
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-Authored-By: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
CopilotAI review requested due to automatic review settings January 6, 2026 01:35

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR rebrands "Bolt" to "X Builder" and implements an MVP publish feature that deploys projects to Cloudflare Pages via the Direct Upload API. The changes include cross-origin isolation headers (COOP/COEP) required for WebContainers, CI/CD workflows for automated deployment, and comprehensive documentation updates.

Key changes:

  • Complete rebrand from "Bolt" to "X Builder" across all user-facing text and branding assets
  • New publish API endpoint (/api/publish) for deploying to Cloudflare Pages
  • Cross-origin isolation headers configured across all entry points to enable SharedArrayBuffer support
  • GitHub Actions workflows for CI and staging deployment

Reviewed changes

Copilot reviewed 21 out of 23 changed files in this pull request and generated 12 comments.

Show a summary per file
FileDescription
wrangler.tomlUpdates worker name from "bolt" to "x-builder"
vite.config.tsAdds COOP/COEP headers to development server
public/favicon.svgUpdates branding from lightning bolt to "X" logo
public/_headersAdds COOP/COEP headers for Cloudflare Pages
package.jsonUpdates project metadata and adds smoke test script
icons/logo.svgUpdates branding to match new favicon
functions/[[path]].tsWraps Remix handler to inject COOP/COEP headers
app/routes/api.publish.tsNew API endpoint for Cloudflare Pages deployment
app/routes/_index.tsxUpdates page title and meta description
app/root.tsxAdds crossOriginIsolated verification check
app/lib/stores/publish.tsNew state management for publish functionality
app/lib/.server/llm/prompts.tsUpdates AI assistant name in system prompt
app/entry.server.tsxChanges COEP from require-corp to credentialless
app/components/workbench/PublishButton.client.tsxNew UI component for publishing projects
app/components/sidebar/Menu.client.tsxRemoves unused IconButton import
app/components/header/Header.tsxReplaces logo with text branding
app/components/chat/BaseChat.tsxUpdates chat placeholder text
README.mdComplete rewrite with X Builder documentation
.github/workflows/deploy-staging.ymlNew deployment workflow for Cloudflare Pages
.github/workflows/ci.ymlNew CI workflow for linting and testing
.github/ISSUE_TEMPLATE/config.ymlUpdates issue template links
.github/ISSUE_TEMPLATE/bug_report.ymlUpdates references to X Builder
.gitattributesNew file enforcing LF line endings

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* - A "manifest" field containing JSON object mapping file paths to empty strings
* - Individual file fields where field name is the file path and value is file content
*/
export async function action({ context, request }: ActionFunctionArgs) {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The publish API endpoint has no authentication or rate limiting. Any user can publish unlimited projects to your Cloudflare account, potentially incurring costs or resource exhaustion. Consider adding authentication checks or rate limiting.

Copilot uses AI. Check for mistakes.
}

try {
const { files, projectName = 'x-builder-preview' } = await request.json<PublishRequest>();

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The projectName parameter lacks validation. Malicious values could potentially be used in path traversal or injection attacks when used in the API URL. Consider validating that it matches Cloudflare's project naming requirements (alphanumeric and hyphens only, specific length limits).

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +40
if (!files || Object.keys(files).length === 0) {
return json({ error: 'No files provided for publishing' }, { status: 400 });
}

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no validation on file sizes or total payload size. A user could upload extremely large files, potentially causing memory issues or exceeding Cloudflare's size limits. Consider adding reasonable size limits and validation.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +13
# Only deploy after CI passes
needs: []

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "Only deploy after CI passes" but the needs array is empty. If there's a CI job that should run before deployment, it should be referenced here (e.g., needs: [ci]). Otherwise, deployments will run without waiting for CI validation.

Suggested change
# Only deploy after CI passes
needs: []

Copilot uses AI. Check for mistakes.
Comment threadpackage.json
Comment on lines +20 to +21
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script 'smoke:publish' references 'scripts/smoke-test-publish.ts' but this file does not exist in the repository. This script will fail when executed.

Suggested change
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"
"preview": "pnpm run build && pnpm run start"

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +79
for (const [filePath, content] of Object.entries(files)) {
// normalize path to include leading slash (required by CF Pages)
const normalizedPath = filePath.startsWith('/') ? filePath : `/${filePath}`;

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File paths from the request are not validated for malicious content. A user could potentially include paths like '../../../etc/passwd' or other path traversal attempts. Consider validating that paths don't contain '..' segments and are within expected boundaries.

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
const response = await handler(context);

// clone response to modify headers
const newResponse = new Response(response.body, response);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a new Response with response.body may fail if the response body has already been consumed or is not readable. Consider using response.clone() before creating the new response to avoid potential stream consumption issues.

Suggested change
constnewResponse=newResponse(response.body,response);
constnewResponse=response.clone();

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
/**
* Wrap handler to add COOP/COEP headers for crossOriginIsolated.
*/
export const onRequest: PagesFunction = async (context) => {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type PagesFunction is used but not imported. This will cause a TypeScript error. Import it from '@cloudflare/workers-types' or use the appropriate type definition.

Copilot uses AI. Check for mistakes.
// project might already exist (409), which is fine
if (!projectResponse.ok && projectResponse.status !== 409) {
const errorData = await projectResponse.json();
console.error('Failed to create project:', errorData);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the project creation fails (non-409 status), the error is logged but execution continues. This could lead to deployment attempts on non-existent projects. Consider returning an error response or at least validating the project exists before attempting deployment.

Suggested change
console.error('Failed to create project:',errorData);
console.error('Failed to create project:',errorData);
returnjson(
{
error: 'Failed to create project before deployment.',
details: errorData,
},
{status: projectResponse.status||502},
);

Copilot uses AI. Check for mistakes.
deploymentId: deployResult.result?.id,
});
} catch (error) {
console.error('Publish error:', error);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generic catch block doesn't differentiate between JSON parsing errors from request.json() and other errors. If the request body is malformed JSON, a more specific error message would be helpful (e.g., 'Invalid request body').

Suggested change
console.error('Publish error:',error);
console.error('Publish error:',error);
if(errorinstanceofSyntaxError){
// Likely caused by malformed JSON in the request body
returnjson({error: 'Invalid request body'},{status: 400});
}

Copilot uses AI. Check for mistakes.
@yosiwizman
yosiwizman deleted the fix/publish-api-manifest branch January 6, 2026 01:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@yosiwizman
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix/publish api manifest - #11142

Closed
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest
Closed

Fix/publish api manifest#11142
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest

Conversation

@yosiwizman

Copy link
Copy Markdown

No description provided.

Yosi Wizmanand others added 10 commits January 5, 2026 14:08
- Update package name and description
- Update page title and meta description
- Update UI placeholder text and header logo
- Update AI system prompt identity
- Update favicon and icons
- Update README with attribution
- Update GitHub issue templates
- Add .gitattributes for LF enforcement
Co-Authored-By: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
* ci: add staging deployment workflow and update README
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-Authored-By: Warp <agent@warp.dev>
* docs: update README with production status and release process
- Change staging to production status
- Add live URL designation
- Add release process documentation
- Document safeguards
Co-Authored-By: Warp <agent@warp.dev>
---------
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add public/_headers with COOP/COEP headers for Cloudflare Pages
- Update entry.server.tsx to use credentialless COEP
- Add COOP/COEP headers to Cloudflare Pages function
- Add COOP/COEP headers to Vite dev server
- Add crossOriginIsolated verification warning in root.tsx
- Document cross-origin isolation in README
Headers:
- Cross-Origin-Opener-Policy: same-origin
- Cross-Origin-Embedder-Policy: credentialless
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add publish.ts store for state management
- Add api.publish.ts API endpoint for Cloudflare Pages deployment
- Add PublishButton.client.tsx UI component
- Update README with publish feature documentation
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-Authored-By: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
CopilotAI review requested due to automatic review settings January 6, 2026 01:35

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR rebrands "Bolt" to "X Builder" and implements an MVP publish feature that deploys projects to Cloudflare Pages via the Direct Upload API. The changes include cross-origin isolation headers (COOP/COEP) required for WebContainers, CI/CD workflows for automated deployment, and comprehensive documentation updates.

Key changes:

  • Complete rebrand from "Bolt" to "X Builder" across all user-facing text and branding assets
  • New publish API endpoint (/api/publish) for deploying to Cloudflare Pages
  • Cross-origin isolation headers configured across all entry points to enable SharedArrayBuffer support
  • GitHub Actions workflows for CI and staging deployment

Reviewed changes

Copilot reviewed 21 out of 23 changed files in this pull request and generated 12 comments.

Show a summary per file
FileDescription
wrangler.tomlUpdates worker name from "bolt" to "x-builder"
vite.config.tsAdds COOP/COEP headers to development server
public/favicon.svgUpdates branding from lightning bolt to "X" logo
public/_headersAdds COOP/COEP headers for Cloudflare Pages
package.jsonUpdates project metadata and adds smoke test script
icons/logo.svgUpdates branding to match new favicon
functions/[[path]].tsWraps Remix handler to inject COOP/COEP headers
app/routes/api.publish.tsNew API endpoint for Cloudflare Pages deployment
app/routes/_index.tsxUpdates page title and meta description
app/root.tsxAdds crossOriginIsolated verification check
app/lib/stores/publish.tsNew state management for publish functionality
app/lib/.server/llm/prompts.tsUpdates AI assistant name in system prompt
app/entry.server.tsxChanges COEP from require-corp to credentialless
app/components/workbench/PublishButton.client.tsxNew UI component for publishing projects
app/components/sidebar/Menu.client.tsxRemoves unused IconButton import
app/components/header/Header.tsxReplaces logo with text branding
app/components/chat/BaseChat.tsxUpdates chat placeholder text
README.mdComplete rewrite with X Builder documentation
.github/workflows/deploy-staging.ymlNew deployment workflow for Cloudflare Pages
.github/workflows/ci.ymlNew CI workflow for linting and testing
.github/ISSUE_TEMPLATE/config.ymlUpdates issue template links
.github/ISSUE_TEMPLATE/bug_report.ymlUpdates references to X Builder
.gitattributesNew file enforcing LF line endings

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* - A "manifest" field containing JSON object mapping file paths to empty strings
* - Individual file fields where field name is the file path and value is file content
*/
export async function action({ context, request }: ActionFunctionArgs) {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The publish API endpoint has no authentication or rate limiting. Any user can publish unlimited projects to your Cloudflare account, potentially incurring costs or resource exhaustion. Consider adding authentication checks or rate limiting.

Copilot uses AI. Check for mistakes.
}

try {
const { files, projectName = 'x-builder-preview' } = await request.json<PublishRequest>();

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The projectName parameter lacks validation. Malicious values could potentially be used in path traversal or injection attacks when used in the API URL. Consider validating that it matches Cloudflare's project naming requirements (alphanumeric and hyphens only, specific length limits).

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +40
if (!files || Object.keys(files).length === 0) {
return json({ error: 'No files provided for publishing' }, { status: 400 });
}

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no validation on file sizes or total payload size. A user could upload extremely large files, potentially causing memory issues or exceeding Cloudflare's size limits. Consider adding reasonable size limits and validation.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +13
# Only deploy after CI passes
needs: []

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "Only deploy after CI passes" but the needs array is empty. If there's a CI job that should run before deployment, it should be referenced here (e.g., needs: [ci]). Otherwise, deployments will run without waiting for CI validation.

Suggested change
# Only deploy after CI passes
needs: []

Copilot uses AI. Check for mistakes.
Comment threadpackage.json
Comment on lines +20 to +21
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script 'smoke:publish' references 'scripts/smoke-test-publish.ts' but this file does not exist in the repository. This script will fail when executed.

Suggested change
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"
"preview": "pnpm run build && pnpm run start"

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +79
for (const [filePath, content] of Object.entries(files)) {
// normalize path to include leading slash (required by CF Pages)
const normalizedPath = filePath.startsWith('/') ? filePath : `/${filePath}`;

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File paths from the request are not validated for malicious content. A user could potentially include paths like '../../../etc/passwd' or other path traversal attempts. Consider validating that paths don't contain '..' segments and are within expected boundaries.

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
const response = await handler(context);

// clone response to modify headers
const newResponse = new Response(response.body, response);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a new Response with response.body may fail if the response body has already been consumed or is not readable. Consider using response.clone() before creating the new response to avoid potential stream consumption issues.

Suggested change
constnewResponse=newResponse(response.body,response);
constnewResponse=response.clone();

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
/**
* Wrap handler to add COOP/COEP headers for crossOriginIsolated.
*/
export const onRequest: PagesFunction = async (context) => {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type PagesFunction is used but not imported. This will cause a TypeScript error. Import it from '@cloudflare/workers-types' or use the appropriate type definition.

Copilot uses AI. Check for mistakes.
// project might already exist (409), which is fine
if (!projectResponse.ok && projectResponse.status !== 409) {
const errorData = await projectResponse.json();
console.error('Failed to create project:', errorData);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the project creation fails (non-409 status), the error is logged but execution continues. This could lead to deployment attempts on non-existent projects. Consider returning an error response or at least validating the project exists before attempting deployment.

Suggested change
console.error('Failed to create project:',errorData);
console.error('Failed to create project:',errorData);
returnjson(
{
error: 'Failed to create project before deployment.',
details: errorData,
},
{status: projectResponse.status||502},
);

Copilot uses AI. Check for mistakes.
deploymentId: deployResult.result?.id,
});
} catch (error) {
console.error('Publish error:', error);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generic catch block doesn't differentiate between JSON parsing errors from request.json() and other errors. If the request body is malformed JSON, a more specific error message would be helpful (e.g., 'Invalid request body').

Suggested change
console.error('Publish error:',error);
console.error('Publish error:',error);
if(errorinstanceofSyntaxError){
// Likely caused by malformed JSON in the request body
returnjson({error: 'Invalid request body'},{status: 400});
}

Copilot uses AI. Check for mistakes.
@yosiwizman
yosiwizman deleted the fix/publish-api-manifest branch January 6, 2026 01:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@yosiwizman
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Fix/publish api manifest - #11142

Closed
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest
Closed

Fix/publish api manifest#11142
yosiwizman wants to merge 11 commits into
stackblitz:mainfrom
yosiwizman:fix/publish-api-manifest

Conversation

@yosiwizman

Copy link
Copy Markdown

No description provided.

Yosi Wizmanand others added 10 commits January 5, 2026 14:08
- Update package name and description
- Update page title and meta description
- Update UI placeholder text and header logo
- Update AI system prompt identity
- Update favicon and icons
- Update README with attribution
- Update GitHub issue templates
- Add .gitattributes for LF enforcement
Co-Authored-By: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
* ci: add staging deployment workflow and update README
- Add deploy-staging.yml for Cloudflare Pages deployment
- Add CI status badge to README
- Add staging URL and deployment documentation
- Add development setup instructions
Co-Authored-By: Warp <agent@warp.dev>
* docs: update README with production status and release process
- Change staging to production status
- Add live URL designation
- Add release process documentation
- Document safeguards
Co-Authored-By: Warp <agent@warp.dev>
---------
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add public/_headers with COOP/COEP headers for Cloudflare Pages
- Update entry.server.tsx to use credentialless COEP
- Add COOP/COEP headers to Cloudflare Pages function
- Add COOP/COEP headers to Vite dev server
- Add crossOriginIsolated verification warning in root.tsx
- Document cross-origin isolation in README
Headers:
- Cross-Origin-Opener-Policy: same-origin
- Cross-Origin-Embedder-Policy: credentialless
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Add publish.ts store for state management
- Add api.publish.ts API endpoint for Cloudflare Pages deployment
- Add PublishButton.client.tsx UI component
- Update README with publish feature documentation
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-Authored-By: Warp <agent@warp.dev>
- Use empty strings as manifest values (per CF API spec)
- Use file paths with leading slash as FormData field names
- Add getContentType helper for proper MIME types
- Remove unused hashContent function
Co-authored-by: Yosi Wizman <yosi@example.com>
Co-authored-by: Warp <agent@warp.dev>
Co-Authored-By: Warp <agent@warp.dev>
CopilotAI review requested due to automatic review settings January 6, 2026 01:35

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR rebrands "Bolt" to "X Builder" and implements an MVP publish feature that deploys projects to Cloudflare Pages via the Direct Upload API. The changes include cross-origin isolation headers (COOP/COEP) required for WebContainers, CI/CD workflows for automated deployment, and comprehensive documentation updates.

Key changes:

  • Complete rebrand from "Bolt" to "X Builder" across all user-facing text and branding assets
  • New publish API endpoint (/api/publish) for deploying to Cloudflare Pages
  • Cross-origin isolation headers configured across all entry points to enable SharedArrayBuffer support
  • GitHub Actions workflows for CI and staging deployment

Reviewed changes

Copilot reviewed 21 out of 23 changed files in this pull request and generated 12 comments.

Show a summary per file
FileDescription
wrangler.tomlUpdates worker name from "bolt" to "x-builder"
vite.config.tsAdds COOP/COEP headers to development server
public/favicon.svgUpdates branding from lightning bolt to "X" logo
public/_headersAdds COOP/COEP headers for Cloudflare Pages
package.jsonUpdates project metadata and adds smoke test script
icons/logo.svgUpdates branding to match new favicon
functions/[[path]].tsWraps Remix handler to inject COOP/COEP headers
app/routes/api.publish.tsNew API endpoint for Cloudflare Pages deployment
app/routes/_index.tsxUpdates page title and meta description
app/root.tsxAdds crossOriginIsolated verification check
app/lib/stores/publish.tsNew state management for publish functionality
app/lib/.server/llm/prompts.tsUpdates AI assistant name in system prompt
app/entry.server.tsxChanges COEP from require-corp to credentialless
app/components/workbench/PublishButton.client.tsxNew UI component for publishing projects
app/components/sidebar/Menu.client.tsxRemoves unused IconButton import
app/components/header/Header.tsxReplaces logo with text branding
app/components/chat/BaseChat.tsxUpdates chat placeholder text
README.mdComplete rewrite with X Builder documentation
.github/workflows/deploy-staging.ymlNew deployment workflow for Cloudflare Pages
.github/workflows/ci.ymlNew CI workflow for linting and testing
.github/ISSUE_TEMPLATE/config.ymlUpdates issue template links
.github/ISSUE_TEMPLATE/bug_report.ymlUpdates references to X Builder
.gitattributesNew file enforcing LF line endings

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* - A "manifest" field containing JSON object mapping file paths to empty strings
* - Individual file fields where field name is the file path and value is file content
*/
export async function action({ context, request }: ActionFunctionArgs) {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The publish API endpoint has no authentication or rate limiting. Any user can publish unlimited projects to your Cloudflare account, potentially incurring costs or resource exhaustion. Consider adding authentication checks or rate limiting.

Copilot uses AI. Check for mistakes.
}

try {
const { files, projectName = 'x-builder-preview' } = await request.json<PublishRequest>();

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The projectName parameter lacks validation. Malicious values could potentially be used in path traversal or injection attacks when used in the API URL. Consider validating that it matches Cloudflare's project naming requirements (alphanumeric and hyphens only, specific length limits).

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +40
if (!files || Object.keys(files).length === 0) {
return json({ error: 'No files provided for publishing' }, { status: 400 });
}

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no validation on file sizes or total payload size. A user could upload extremely large files, potentially causing memory issues or exceeding Cloudflare's size limits. Consider adding reasonable size limits and validation.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +13
# Only deploy after CI passes
needs: []

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "Only deploy after CI passes" but the needs array is empty. If there's a CI job that should run before deployment, it should be referenced here (e.g., needs: [ci]). Otherwise, deployments will run without waiting for CI validation.

Suggested change
# Only deploy after CI passes
needs: []

Copilot uses AI. Check for mistakes.
Comment threadpackage.json
Comment on lines +20 to +21
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script 'smoke:publish' references 'scripts/smoke-test-publish.ts' but this file does not exist in the repository. This script will fail when executed.

Suggested change
"preview": "pnpm run build && pnpm run start",
"smoke:publish": "tsx scripts/smoke-test-publish.ts"
"preview": "pnpm run build && pnpm run start"

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +79
for (const [filePath, content] of Object.entries(files)) {
// normalize path to include leading slash (required by CF Pages)
const normalizedPath = filePath.startsWith('/') ? filePath : `/${filePath}`;

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File paths from the request are not validated for malicious content. A user could potentially include paths like '../../../etc/passwd' or other path traversal attempts. Consider validating that paths don't contain '..' segments and are within expected boundaries.

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
const response = await handler(context);

// clone response to modify headers
const newResponse = new Response(response.body, response);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating a new Response with response.body may fail if the response body has already been consumed or is not readable. Consider using response.clone() before creating the new response to avoid potential stream consumption issues.

Suggested change
constnewResponse=newResponse(response.body,response);
constnewResponse=response.clone();

Copilot uses AI. Check for mistakes.
Comment threadfunctions/[[path]].ts
/**
* Wrap handler to add COOP/COEP headers for crossOriginIsolated.
*/
export const onRequest: PagesFunction = async (context) => {

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type PagesFunction is used but not imported. This will cause a TypeScript error. Import it from '@cloudflare/workers-types' or use the appropriate type definition.

Copilot uses AI. Check for mistakes.
// project might already exist (409), which is fine
if (!projectResponse.ok && projectResponse.status !== 409) {
const errorData = await projectResponse.json();
console.error('Failed to create project:', errorData);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the project creation fails (non-409 status), the error is logged but execution continues. This could lead to deployment attempts on non-existent projects. Consider returning an error response or at least validating the project exists before attempting deployment.

Suggested change
console.error('Failed to create project:',errorData);
console.error('Failed to create project:',errorData);
returnjson(
{
error: 'Failed to create project before deployment.',
details: errorData,
},
{status: projectResponse.status||502},
);

Copilot uses AI. Check for mistakes.
deploymentId: deployResult.result?.id,
});
} catch (error) {
console.error('Publish error:', error);

CopilotAIJan 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generic catch block doesn't differentiate between JSON parsing errors from request.json() and other errors. If the request body is malformed JSON, a more specific error message would be helpful (e.g., 'Invalid request body').

Suggested change
console.error('Publish error:',error);
console.error('Publish error:',error);
if(errorinstanceofSyntaxError){
// Likely caused by malformed JSON in the request body
returnjson({error: 'Invalid request body'},{status: 400});
}

Copilot uses AI. Check for mistakes.
@yosiwizman
yosiwizman deleted the fix/publish-api-manifest branch January 6, 2026 01:43
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@yosiwizman