Scans
@@ -473,7 +476,7 @@ function ScansControl() {
{scan.name || `Scan ${index + 1}`}
@@ -693,7 +696,7 @@ function ReferencesControl() {
{total}
@@ -736,7 +739,7 @@ function ReferencesControl() {
)}
{
+ test('prefixes root-relative assets for a subpath deployment', () => {
+ expect(withEditorBasePath('/icons/select.webp', '/pascal-service')).toBe(
+ '/pascal-service/icons/select.webp',
+ )
+ })
+
+ test('does not duplicate an existing base path', () => {
+ expect(withEditorBasePath('/pascal-service/icons/select.webp', '/pascal-service')).toBe(
+ '/pascal-service/icons/select.webp',
+ )
+ })
+
+ test('leaves external assets unchanged', () => {
+ expect(withEditorBasePath('https://cdn.example/icon.webp', '/pascal-service')).toBe(
+ 'https://cdn.example/icon.webp',
+ )
+ })
+})
diff --git a/services/pascal-editor/packages/editor/src/lib/public-asset-path.ts b/services/pascal-editor/packages/editor/src/lib/public-asset-path.ts
new file mode 100644
index 000000000..948465db1
--- /dev/null
+++ b/services/pascal-editor/packages/editor/src/lib/public-asset-path.ts
@@ -0,0 +1,20 @@
+const configuredBasePath = process.env.NEXT_PUBLIC_PASCAL_BASE_PATH?.trim() ?? ''
+
+const EDITOR_BASE_PATH = configuredBasePath
+ ? `/${configuredBasePath.replace(/^\/+|\/+$/g, '')}`
+ : ''
+
+export function withEditorBasePath(pathname: string, basePath = EDITOR_BASE_PATH): string {
+ if (/^(?:[a-z]+:)?\/\//i.test(pathname) || pathname.startsWith('data:')) return pathname
+
+ const path = pathname.startsWith('/') ? pathname : `/${pathname}`
+ const normalizedBasePath = basePath ? `/${basePath.replace(/^\/+|\/+$/g, '')}` : ''
+ if (
+ !normalizedBasePath ||
+ path === normalizedBasePath ||
+ path.startsWith(`${normalizedBasePath}/`)
+ ) {
+ return path
+ }
+ return `${normalizedBasePath}${path}`
+}