Skip to content

Introduce Canvas App#1610

Open
paustint wants to merge 10 commits intomainfrom
feat/canvas-app
Open

Introduce Canvas App#1610
paustint wants to merge 10 commits intomainfrom
feat/canvas-app

Conversation

@paustint
Copy link
Copy Markdown
Contributor

@paustint paustint commented Mar 25, 2026

Introduce a managed package for Jetstream deployed as a Managed Package using a Canvas App.

@socket-security
Copy link
Copy Markdown

socket-security bot commented Mar 28, 2026

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm @lwc/template-compiler is 91.0% likely obfuscated

Confidence: 0.91

Location: Package overview

From: ?npm/@salesforce/sfdx-lwc-jest@7.1.2npm/@lwc/template-compiler@8.20.4

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@lwc/template-compiler@8.20.4. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@paustint paustint marked this pull request as ready for review March 28, 2026 23:39
Copilot AI review requested due to automatic review settings March 28, 2026 23:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 introduces an initial “Canvas App” (Salesforce Canvas / managed package) delivery path alongside the existing web app, desktop app, and browser extension flows, including environment detection, embedded-mode UI behavior, and Canvas-specific OAuth + routing.

Changes:

  • Add a new jetstream-canvas Nx/Vite application and a Canvas-aware client routing/axios adapter layer.
  • Extend shared UI + jobs + download + permissions/ability logic to support isCanvasApp() / single-org embedded mode behaviors.
  • Add Salesforce managed-package (SFDX) assets + docs + CI workflow, and add API /canvas/* routes for serving the Canvas app and handling OAuth callbacks.

Reviewed changes

Copilot reviewed 125 out of 137 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
yarn.lock Bumps @testing-library/react lock entry.
package.json Adds canvas build scripts + includes jetstream-canvas in CI build; bumps @testing-library/react.
libs/ui/src/lib/layout/Header.tsx Renames isChromeExtension prop to isEmbeddedApp and updates conditional rendering.
libs/ui/src/lib/file-download-modal/options/FileDownloadGoogle.tsx Treats Canvas app as “external Google picker” environment.
libs/ui/src/lib/file-download-modal/RecordDownloadModal.tsx Allows Google download/upload flow in Canvas app.
libs/ui/src/lib/file-download-modal/FileFauxDownloadModal.tsx Allows Google download/upload flow in Canvas app.
libs/ui/src/lib/file-download-modal/FileDownloadModal.tsx Allows Google download/upload flow in Canvas app.
libs/shared/utils/src/lib/utils.ts Adds urlSearchParamsToJson helper.
libs/shared/ui-utils/src/lib/shared-canvas-helpers.ts Adds isCanvasApp() helper.
libs/shared/ui-utils/src/lib/hooks/useDriveExternalPicker.ts Adds BroadcastChannel fallback and treats Canvas as popup-based picker flow.
libs/shared/ui-utils/src/index.ts Re-exports new canvas helpers.
libs/shared/ui-core/src/state-management/load-records.state.ts Gives Canvas app “unlimited” API limits similar to desktop/extension.
libs/shared/ui-core/src/jobs/Jobs.tsx Uses external Google token store in Canvas app.
libs/shared/ui-core/src/jobs/JobWorker.ts Treats Canvas app like extension for non-streaming bulk downloads.
libs/shared/ui-core/src/app/HeaderNavbar.tsx Adds embedded-mode prop, fullscreen link handling for Canvas, and selected-org usage.
libs/shared/ui-app-state/src/lib/ui-app-state.ts Adds Canvas-specific appInfo/serverUrl handling and single-org mode behavior.
libs/shared/data/src/lib/client-data.ts Adds Canvas-specific preference getters/setters passing org context.
libs/features/platform-event-monitor/src/usePlatformEvent.ts Adds subscribe/unsubscribe override hooks for non-CometD environments (Canvas).
libs/features/platform-event-monitor/src/index.ts Re-exports override-related types.
libs/features/platform-event-monitor/src/PlatformEventMonitor.tsx Accepts override fns and renames internal “chromeExtension” state.
libs/features/load-records/src/steps/SelectObjectAndFile.tsx Enables Google picker + unlimited file size in Canvas app.
libs/features/load-records-multi-object/src/LoadRecordsMultiObject.tsx Enables Google picker support in Canvas app.
libs/features/deploy/src/view-or-compare-metadata/ViewOrCompareMetadataSidebar.tsx Renames extension-only flag to generic single-org mode flag.
libs/features/deploy/src/view-or-compare-metadata/ViewOrCompareMetadataModalFooter.tsx Renames extension-only flag to generic single-org mode flag.
libs/features/deploy/src/view-or-compare-metadata/ViewOrCompareMetadataModal.tsx Treats Canvas app as single-org mode for UI labels/behavior.
libs/features/deploy/src/DeployMetadataDeploymentTable.tsx Treats Canvas app as single-org mode for button copy.
libs/features/deploy/src/DeployMetadataDeployment.tsx Hides “deploy to different org” in single-org (extension/canvas) mode.
libs/auth/salesforce-oauth/src/lib/salesforce-oauth.ts Adds Canvas OAuth init/callback with signed state payload.
libs/auth/acl/src/lib/acl.ts Adds isCanvasApp to ability derivation and “web app” classification.
custom-typings/index.d.ts Declares global __IS_CANVAS_APP__.
apps/landing/pages/web-extension/google-picker/index.tsx Switches to shared “external picker” state hook.
apps/landing/pages/oauth-link/index.tsx Refactors postMessage handling and minor JSX spacing tweak.
apps/landing/pages/canvas-auth/index.tsx Adds Canvas OAuth “close window / return to app” landing page.
apps/landing/hooks/external-google-picker.hooks.ts Generalizes picker hook for extension/canvas + adds BroadcastChannel fallback.
apps/jetstream-web-extension/src/utils/api-client.ts Fixes double await.
apps/jetstream-web-extension/src/pages/app/App.tsx Uses isEmbeddedApp prop instead of isChromeExtension.
apps/jetstream-web-extension/src/controllers/sf-misc.web-ext.controller.ts Fixes HTTP error threshold (>= 300).
apps/jetstream-desktop/src/controllers/sf-misc.desktop.controller.ts Fixes HTTP error threshold (>= 300).
apps/jetstream-canvas/vite.plugins.ts Adds Vite plugin utilities for base href and file replacement.
apps/jetstream-canvas/vite.config.mts Adds Vite config for Canvas app build/dev/test.
apps/jetstream-canvas/tsconfig.spec.json Adds spec TS config for Canvas app.
apps/jetstream-canvas/tsconfig.json Adds base TS config for Canvas app.
apps/jetstream-canvas/tsconfig.app.json Adds app TS config for Canvas app.
apps/jetstream-canvas/src/utils/zip.ts Adds ZIP streaming/creation utilities for Canvas downloads.
apps/jetstream-canvas/src/utils/canvas.utils.ts Builds a SalesforceOrgUi from Canvas signed request context.
apps/jetstream-canvas/src/utils/canvas.types.ts Adds Canvas org/api-connection type.
apps/jetstream-canvas/src/utils/canvas-axios-adapter.ts Adds axios adapter that routes requests to in-app Canvas controllers.
apps/jetstream-canvas/src/utils/api-client.ts Adds Canvas API client using Canvas SDK ajax bridge + org initialization.
apps/jetstream-canvas/src/main.tsx Boots Canvas app, installs axios adapter, validates iframe context, initializes Canvas SDK.
apps/jetstream-canvas/src/main.scss Adds Canvas app styling overrides.
apps/jetstream-canvas/src/environments/environment.ts Adds Canvas dev environment config.
apps/jetstream-canvas/src/environments/environment.staging.ts Adds Canvas staging environment config.
apps/jetstream-canvas/src/environments/environment.prod.ts Adds Canvas prod environment config.
apps/jetstream-canvas/src/controllers/user.canvas.controller.ts Adds (placeholder) feedback route wiring.
apps/jetstream-canvas/src/controllers/sf-record.canvas.controller.ts Adds record APIs (binary upload, CRUD ops) for Canvas adapter routing.
apps/jetstream-canvas/src/controllers/sf-query.canvas.controller.ts Adds describe/query/queryMore routes for Canvas adapter routing.
apps/jetstream-canvas/src/controllers/sf-misc.canvas.controller.ts Adds misc routes (downloads, manual requests) for Canvas adapter routing.
apps/jetstream-canvas/src/controllers/sf-metadata-tooling.canvas.controller.ts Adds metadata tooling endpoints for Canvas adapter routing.
apps/jetstream-canvas/src/controllers/sf-bulk-query-20-api.canvas.controller.ts Adds Bulk Query 2.0 endpoints for Canvas adapter routing.
apps/jetstream-canvas/src/controllers/sf-bulk-api.canvas.controller.ts Adds Bulk API endpoints for Canvas adapter routing.
apps/jetstream-canvas/src/controllers/route.utils.ts Adds lightweight route creation/validation and response helpers for Canvas adapter routing.
apps/jetstream-canvas/src/controllers/preferences.canvas.controller.ts Implements preference read/write via custom setting in Salesforce.
apps/jetstream-canvas/src/controllers/jetstream-data-sync.canvas.controller.ts Adds placeholder data-sync routes.
apps/jetstream-canvas/src/controllers/canvas.routes.ts Registers the Canvas app’s internal “API” routes.
apps/jetstream-canvas/src/assets/.gitkeep Keeps assets directory in repo.
apps/jetstream-canvas/src/app/core/monaco-loader.ts Configures Monaco loader paths and custom configuration.
apps/jetstream-canvas/src/app/core/config.ts Adds Canvas router config/basename.
apps/jetstream-canvas/src/app/core/Login.tsx Adds Canvas-specific auth/authorize UX and OAuth popup flow.
apps/jetstream-canvas/src/app/core/LazyLoad.tsx Adds lazy-with-preload helper (ported).
apps/jetstream-canvas/src/app/core/AppInitializer.tsx Initializes org state, DB, and Canvas preference sync.
apps/jetstream-canvas/src/app/app.tsx Wires core providers, embedded header, and routes for Canvas app.
apps/jetstream-canvas/src/app/AppRoutes.tsx Defines Canvas app route tree and platform-event overrides using Canvas SDK streaming.
apps/jetstream-canvas/project.json Adds Nx targets for build/serve/test for Canvas app.
apps/jetstream-canvas/index.html Adds Canvas app HTML template with injected Canvas SDK + signed request.
apps/jetstream-canvas/eslint.config.cjs Adds eslint config for Canvas app project.
apps/docs/sidebars.ts Adds managed-package doc page to docs sidebar.
apps/docs/docs/getting-started/managed-package/managed-package.mdx Adds documentation for managed package / Canvas app usage.
apps/api/src/main.ts Registers /canvas route with CSP frame-ancestors and router.
apps/api/src/app/routes/index.ts Exports new canvasRoutes.
apps/api/src/app/routes/canvas.routes.ts Adds API routes to serve Canvas app + static assets.
apps/api/src/app/controllers/sf-misc.controller.ts Fixes HTTP error threshold (>= 300).
apps/api/src/app/controllers/sf-bulk-api.controller.ts Fixes validator params for bulk zip upload.
apps/api/src/app/controllers/canvas.controller.ts Implements Canvas signed_request verification + user-approval OAuth flow + HTML injection.
apps-sfdx/sfdx-project.json Adds SFDX project config for managed package assets and replacements.
apps-sfdx/scripts/soql/.gitkeep Adds placeholder scripts folder.
apps-sfdx/scripts/sfdx/create-scratch-org.mjs Adds scratch org creation/deploy helper script.
apps-sfdx/scripts/apex/.gitkeep Adds placeholder apex scripts folder.
apps-sfdx/package.json Adds SFDX project scripts/deps for lint/test/scratch org tasks.
apps-sfdx/jest.config.js Adds Jest config for LWC tests.
apps-sfdx/eslint.config.js Adds ESLint flat config for SFDX Aura/LWC + Jest mocks.
apps-sfdx/config/project-scratch-def.json Adds default scratch org definition for Canvas package.
apps-sfdx/config/project-scratch-def-professional.json Adds Professional scratch org definition.
apps-sfdx/canvas-app/untracked/main/default/extlClntAppGlobalOauthSets/Jetstream_Canvas_glbloauth.ecaGlblOauth-meta.xml Adds global OAuth settings metadata (untracked).
apps-sfdx/canvas-app/untracked/main/default/.gitkeep Keeps untracked metadata folder.
apps-sfdx/canvas-app/unpackaged/main/default/.gitkeep Keeps unpackaged metadata folder.
apps-sfdx/canvas-app/jetstream/main/default/tabs/JetstreamAppTab.tab-meta.xml Adds Jetstream custom tab.
apps-sfdx/canvas-app/jetstream/main/default/permissionsets/Jetstream.permissionset-meta.xml Adds permission set for Canvas app + custom setting fields.
apps-sfdx/canvas-app/jetstream/main/default/pages/JetstreamPage.page-meta.xml Adds VF page metadata.
apps-sfdx/canvas-app/jetstream/main/default/pages/JetstreamPage.page Adds VF page embedding the Canvas app with resizing script.
apps-sfdx/canvas-app/jetstream/main/default/objects/UserPreferences__c/fields/WhereClauseOpsIndented__c.field-meta.xml Adds preferences custom setting field.
apps-sfdx/canvas-app/jetstream/main/default/objects/UserPreferences__c/fields/SubqueryParensOnOwnLine__c.field-meta.xml Adds preferences custom setting field.
apps-sfdx/canvas-app/jetstream/main/default/objects/UserPreferences__c/fields/SkipFrontdoorLogin__c.field-meta.xml Adds preferences custom setting field.
apps-sfdx/canvas-app/jetstream/main/default/objects/UserPreferences__c/fields/RecordSyncEnabled__c.field-meta.xml Adds preferences custom setting field.
apps-sfdx/canvas-app/jetstream/main/default/objects/UserPreferences__c/fields/NumIndent__c.field-meta.xml Adds preferences custom setting field.
apps-sfdx/canvas-app/jetstream/main/default/objects/UserPreferences__c/fields/NewLineAfterKeywords__c.field-meta.xml Adds preferences custom setting field.
apps-sfdx/canvas-app/jetstream/main/default/objects/UserPreferences__c/fields/FieldMaxLineLength__c.field-meta.xml Adds preferences custom setting field.
apps-sfdx/canvas-app/jetstream/main/default/objects/UserPreferences__c/UserPreferences__c.object-meta.xml Adds hierarchy custom setting for user preferences.
apps-sfdx/canvas-app/jetstream/main/default/extlClntAppPolicies/Jetstream_Canvas_plcy.ecaPlcy-meta.xml Adds external client app policies metadata.
apps-sfdx/canvas-app/jetstream/main/default/extlClntAppOauthSettings/Jetstream_Canvas_oauth.ecaOauth-meta.xml Adds external client app OAuth settings metadata.
apps-sfdx/canvas-app/jetstream/main/default/extlClntAppOauthPolicies/Jetstream_Canvas_oauthPlcy.ecaOauthPlcy-meta.xml Adds external client app OAuth policies metadata.
apps-sfdx/canvas-app/jetstream/main/default/extlClntAppCanvasSettings/Jetstream_Canvas_canvasSettings.ecaCanvas-meta.xml Adds external client app Canvas settings metadata.
apps-sfdx/canvas-app/jetstream/main/default/externalClientApps/Jetstream_Canvas_Dev.eca-meta.xml Adds external client app definition metadata.
apps-sfdx/canvas-app/jetstream/main/default/contentassets/jetstreamiconpro128.asset-meta.xml Adds content asset metadata for branding.
apps-sfdx/canvas-app/jetstream/main/default/classes/UserPreferencesTest.cls-meta.xml Adds Apex test metadata for preferences.
apps-sfdx/canvas-app/jetstream/main/default/classes/UserPreferencesTest.cls Adds Apex tests for preference custom setting behavior.
apps-sfdx/canvas-app/jetstream/main/default/classes/JetstreamPageControllerTest.cls-meta.xml Adds Apex test metadata for page controller.
apps-sfdx/canvas-app/jetstream/main/default/classes/JetstreamPageControllerTest.cls Adds Apex tests for fullscreen parameter logic.
apps-sfdx/canvas-app/jetstream/main/default/classes/JetstreamPageController.cls-meta.xml Adds Apex class metadata for page controller.
apps-sfdx/canvas-app/jetstream/main/default/classes/JetstreamPageController.cls Adds page controller providing isFullScreen canvas parameters.
apps-sfdx/canvas-app/jetstream/main/default/applications/Jetstream.app-meta.xml Adds Lightning app definition for Jetstream.
apps-sfdx/canvas-app/jetstream/main/default/appMenus/AppSwitcher.appMenu-meta.xml Adds app menu metadata entries.
apps-sfdx/README.md Adds minimal SFDX readme.
apps-sfdx/.vscode/settings.json Adds SFDX workspace VS Code settings.
apps-sfdx/.prettierrc Adds Prettier config for SFDX assets (Apex/XML).
apps-sfdx/.prettierignore Adds ignore rules for SFDX workspace.
apps-sfdx/.gitignore Adds SFDX-specific ignores.
apps-sfdx/.forceignore Adds Salesforce source tracking ignore rules.
.vscode/settings.json Excludes SFDX folders from search/watcher.
.vscode/launch.json Adds Apex Replay Debugger launch configuration.
.github/workflows/sfdx-ci.yml Adds CI workflow to deploy to scratch org and run Apex tests.
.github/workflows/release.yml Fixes Rollbar env var name for deploy creation step.
Comments suppressed due to low confidence (2)

apps/landing/hooks/external-google-picker.hooks.ts:98

  • This hook logs nonce/origin and picker result params via console.log/console.warn. These values can include sensitive auth artifacts and are likely to leak in production (browser logs, support screenshots, etc.). Please remove these logs or guard them behind an explicit dev/debug flag.
    apps/landing/hooks/external-google-picker.hooks.ts:61
  • isTrustedOrigin currently allows any https:// origin. Because openerOrigin is read from query params, an attacker can open this page with their own openerOrigin and receive Google picker results (tokens / file metadata) via postMessage. Please restrict allowed origins to a known allowlist (e.g., your app domains + *.force.com / *.salesforce.com + extension origins) and treat openerOrigin as untrusted input.

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

@paustint paustint changed the title feat: wip - canvas app Introduce Canvas App Mar 29, 2026
@paustint paustint requested a review from Copilot March 29, 2026 00:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 125 out of 137 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

apps/landing/hooks/external-google-picker.hooks.ts:62

  • openerOrigin is taken directly from query params, and isTrustedOrigin() currently allows any https:// origin. That means any arbitrary website can open this page, set openerOrigin to itself, and receive Google Picker results via postMessage (the nonce does not prevent this because the attacker controls the nonce too). Please restrict openerOrigin to a tight allowlist (e.g., known Jetstream origins and extension origins) and/or derive the target origin from a trusted source instead of URL params.
    apps/landing/hooks/external-google-picker.hooks.ts:76
  • This introduces a number of console.log/console.warn statements that will run in production for every picker completion. This can leak details to logs and adds noise for users. Consider removing these, gating behind a debug flag, or routing through the existing logger with an environment-controlled log level.

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

@paustint paustint force-pushed the feat/canvas-app branch 4 times, most recently from b278f6a to 21ade01 Compare April 3, 2026 03:35
@paustint paustint requested a review from Copilot April 3, 2026 03:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 128 out of 141 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (2)

apps/landing/hooks/external-google-picker.hooks.ts:61

  • isTrustedOrigin currently returns true for any https:// origin derived from a query param (openerOrigin/targetOrigin). This allows any arbitrary HTTPS site to open this picker page and receive the Google picker result (including access token) via postMessage, which is a token exfiltration risk. Restrict allowed origins to a hardcoded allowlist (e.g., Jetstream domains and extension origins) and/or derive the target origin from a server-signed value rather than trusting a URL param.
    apps/landing/hooks/external-google-picker.hooks.ts:72
  • The debug console.log/console.warn statements in sendResultToOpener log params and nonce, which can include sensitive data like accessToken/picker selections. Please remove these logs or gate them behind a non-production/debug flag to avoid leaking tokens in browser consoles and log collection tooling.

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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 128 out of 141 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

apps/landing/hooks/external-google-picker.hooks.ts:61

  • isTrustedOrigin() currently treats any https:// origin as trusted, but openerOrigin is sourced directly from query params. This effectively allows any third-party website to use this page as an OAuth+Google Picker relay using Jetstream’s Google client configuration (quota/abuse risk) and receive results via postMessage. Recommend restricting openerOrigin to an explicit allow-list (Jetstream web origins + extension origins), and/or deriving the allowed target origin from a server-issued/signed nonce instead of trusting a URL param.
    apps/landing/hooks/external-google-picker.hooks.ts:98
  • There are multiple unconditional console.log/console.warn statements in sendResultToOpener. These will ship to production and may leak implementation details into user consoles; they also add noise when this page is used frequently. Consider removing them or gating behind a debug flag / NODE_ENV !== 'production', and prefer the app logger if you need telemetry.

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

paustint added 3 commits April 3, 2026 07:23
Add API and core application logic for a new distribution method for canvas apps
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 131 out of 144 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

apps/landing/hooks/external-google-picker.hooks.ts:61

  • isTrustedOrigin currently treats any https:// origin as trusted. Because this page can return Google OAuth results/tokens to window.opener via postMessage, allowing arbitrary HTTPS origins enables token exfiltration if this page is opened by an attacker-controlled site. Restrict the allowed origins to a small allow-list (e.g., Jetstream-owned domains and extension schemes), or validate openerOrigin against a server-signed value rather than accepting it from query params.
    apps/landing/hooks/external-google-picker.hooks.ts:72
  • sendResultToOpener logs params (and related context) to the console. In this flow params can include sensitive values such as googleAccessToken / expiry and file identifiers. Please remove these logs or ensure they are behind a non-production debug flag with explicit redaction of tokens/PII.

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

Comment on lines +12 to +14
export function escapeJsonForScript(json: string): string {
return json.replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/\//g, '\\u002f').replace(/'/g, '\\u0027');
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

escapeJsonForScript escapes <, >, /, and ', but does not escape Unicode line/paragraph separators (U+2028/U+2029). Those characters can terminate a JavaScript string literal when embedding JSON inside <script> (even when wrapped in quotes), causing script parse errors and potentially enabling injection in edge cases. Consider escaping \u2028 and \u2029 (and optionally \u0000.. control chars) before embedding.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +17
// The fullscreen VF page passes { isFullScreen: true } via the apex:canvasApp parameters attribute
const isFullscreen = z.coerce.boolean().default(true).parse(sr.context?.environment?.parameters?.isFullScreen);

Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

z.coerce.boolean().default(true) will coerce undefined to false, so the .default(true) will never apply when isFullScreen is missing. This makes isFullscreen default to false unexpectedly and hides the fullscreen-specific behavior. Prefer parsing with an explicit optional default before coercion (e.g., treat undefined as true), or use a preprocess that preserves undefined so the default can apply.

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +85
let parsedBody: unknown = undefined;

if (req.request.method !== 'GET' && !skipBodyParsing) {
const contentType = req.request.headers.get('content-type') ?? '';
if (contentType.startsWith('application/json')) {
try {
parsedBody = await req.request.json();
} catch {
// headers may not have been correct, just ignore and continue
}
} else if (contentType.startsWith('application/zip')) {
parsedBody = await req.request.arrayBuffer();
} else {
parsedBody = await req.request.text();
}
}

try {
const data = {
params: params ? params.parse(req.params) : undefined,
body: body && parsedBody !== undefined ? body.parse(parsedBody) : undefined,
query: query ? query.parse(queryParams) : undefined,
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

createRoute only parses/validates the request body when parsedBody !== undefined. If a route declares a body schema but the request has no body (or JSON parsing fails), data.body becomes undefined instead of triggering schema validation, which can lead to downstream runtime errors and inconsistent 400 handling. Consider always running body.parse(parsedBody) when a body schema is provided (even if parsedBody is undefined), and/or throw a clear error when body parsing fails for application/json requests.

Copilot uses AI. Check for mistakes.
Sign up for free to 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.

3 participants