From 83689699325685052e53a2e65cb47e991530c11f Mon Sep 17 00:00:00 2001 From: Wael Nasreddine Date: Thu, 25 Dec 2025 22:06:30 -0800 Subject: [PATCH 1/2] implement the second part of the sharejs --- apps/server/src/services/export/zip.ts | 8 ++++++++ apps/server/src/share/content_renderer.ts | 12 +++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/server/src/services/export/zip.ts b/apps/server/src/services/export/zip.ts index 53e0eb540..4a9f14041 100644 --- a/apps/server/src/services/export/zip.ts +++ b/apps/server/src/services/export/zip.ts @@ -295,6 +295,14 @@ async function exportToZip(taskContext: TaskContext<"export">, branch: BBranch, return url ? `href="${url}"` : match; }); + if (format === "share") { + content = content.replace(/src="[^"]*api\/notes\/([a-zA-Z0-9_]+)\/download"/g, (match, targetNoteId) => { + const url = getNoteTargetUrl(targetNoteId, noteMeta); + + return url ? `src="${url}"` : match; + }); + } + return content; function findAttachment(targetAttachmentId: string) { diff --git a/apps/server/src/share/content_renderer.ts b/apps/server/src/share/content_renderer.ts index 897f10394..1316af4ce 100644 --- a/apps/server/src/share/content_renderer.ts +++ b/apps/server/src/share/content_renderer.ts @@ -73,6 +73,14 @@ export function renderNoteForExport(note: BNote, parentBranch: BBranch, basePath note: parentBranch.getNote() }; + // Determine JS to load. + const jsToLoad: string[] = [ + `${basePath}assets/scripts.js` + ]; + for (const jsRelation of note.getRelations("shareJs")) { + jsToLoad.push(`api/notes/${jsRelation.value}/download`); + } + return renderNoteContentInternal(note, { subRoot, rootNoteId: parentBranch.noteId, @@ -80,9 +88,7 @@ export function renderNoteForExport(note: BNote, parentBranch: BBranch, basePath `${basePath}assets/styles.css`, `${basePath}assets/scripts.css`, ], - jsToLoad: [ - `${basePath}assets/scripts.js` - ], + jsToLoad, logoUrl: `${basePath}icon-color.svg`, faviconUrl: `${basePath}favicon.ico`, ancestors, From 3d1f6c4f91b2c0d936c95535e5be50e6b44f53c2 Mon Sep 17 00:00:00 2001 From: Wael Nasreddine Date: Thu, 25 Dec 2025 22:54:14 -0800 Subject: [PATCH 2/2] be loosy and honor startsWith application/javascript --- apps/server/src/services/export/zip/share_theme.ts | 3 +-- apps/server/src/share/content_renderer.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/server/src/services/export/zip/share_theme.ts b/apps/server/src/services/export/zip/share_theme.ts index 7775b52d6..2f1784c13 100644 --- a/apps/server/src/services/export/zip/share_theme.ts +++ b/apps/server/src/services/export/zip/share_theme.ts @@ -116,8 +116,7 @@ export default class ShareThemeExportProvider extends ZipExportProvider { return null; } - // TODO: Should we allow mime to also include backend, i.e loosely check that it starts with application/javascript and ignore the rest? - if (type === "code" && mime === "application/javascript;env=frontend"){ + if (mime.startsWith("application/javascript")) { return "js"; } diff --git a/apps/server/src/share/content_renderer.ts b/apps/server/src/share/content_renderer.ts index 1316af4ce..7a92d2728 100644 --- a/apps/server/src/share/content_renderer.ts +++ b/apps/server/src/share/content_renderer.ts @@ -155,7 +155,7 @@ interface RenderArgs { } function renderNoteContentInternal(note: SNote | BNote, renderArgs: RenderArgs) { - if (renderArgs.isStatic && note.type == "code" && note.mime === "application/javascript;env=frontend") { + if (renderArgs.isStatic && note.mime.startsWith("application/javascript")) { if (note.isProtected) { // TODO: how to handle this case here? throw new Error(`note ${note.noteId} is protected and cannot be exported`);