wiki-viewer 1.14.1 → 1.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/internal/span/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/share/[token]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/share/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/reveal/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/set-root/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/refresh/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/upload/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/backlinks/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/download/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/file/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/folder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-branches/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-checkout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-diff/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-file-info/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-history/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-pull/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/move/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/new-file/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/outlinks/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/page/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/slugs/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/upload/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/watch/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware-manifest.json +1 -1
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/package.json +1 -1
- package/bin/postbuild.js +21 -0
- package/package.json +1 -1
- package/.next/standalone/.github/workflows/publish.yml +0 -37
- package/.next/standalone/.handoffs/archive/handoff-20260612-113332.md +0 -98
- package/.next/standalone/.handoffs/archive/handoff-20260612-141032.md +0 -73
- package/.next/standalone/.pi/ownership.json +0 -3
- package/.next/standalone/AGENTS.md +0 -114
- package/.next/standalone/DESIGN.md +0 -521
- package/.next/standalone/README.md +0 -821
- package/.next/standalone/TODO.md +0 -20
- package/.next/standalone/agents/bootstrap-prompt.md +0 -14
- package/.next/standalone/agents/wiki-viewer-skill/SKILL.md +0 -456
- package/.next/standalone/bin/postbuild.js +0 -78
- package/.next/standalone/bin/wiki-viewer.js +0 -922
- package/.next/standalone/certificates/localhost-key.pem +0 -28
- package/.next/standalone/certificates/localhost.pem +0 -24
- package/.next/standalone/docs/agent-collab-plan.md +0 -1615
- package/.next/standalone/docs/agent-collab-v2-plan.md +0 -771
- package/.next/standalone/docs/agent-fs-plan.md +0 -232
- package/.next/standalone/docs/editorial-skin-spec.md +0 -242
- package/.next/standalone/docs/file-vs-collab-authority.md +0 -124
- package/.next/standalone/docs/mobile-readiness-spec.md +0 -229
- package/.next/standalone/docs/workspacing-plan.md +0 -364
- package/.next/standalone/packages/wiki-viewer-mcp/README.md +0 -195
- package/.next/standalone/packages/wiki-viewer-mcp/bench-e2e.mjs +0 -166
- package/.next/standalone/packages/wiki-viewer-mcp/bench-latency.mjs +0 -87
- package/.next/standalone/packages/wiki-viewer-mcp/bench-payload.mjs +0 -45
- package/.next/standalone/packages/wiki-viewer-mcp/dist/http-client.js +0 -331
- package/.next/standalone/packages/wiki-viewer-mcp/dist/index.js +0 -531
- package/.next/standalone/packages/wiki-viewer-mcp/dist/register.js +0 -94
- package/.next/standalone/packages/wiki-viewer-mcp/dist/state-cache.js +0 -28
- package/.next/standalone/packages/wiki-viewer-mcp/package-lock.json +0 -1716
- package/.next/standalone/packages/wiki-viewer-mcp/package.json +0 -41
- package/.next/standalone/packages/wiki-viewer-mcp/src/http-client.ts +0 -459
- package/.next/standalone/packages/wiki-viewer-mcp/src/index.ts +0 -638
- package/.next/standalone/packages/wiki-viewer-mcp/src/register.ts +0 -144
- package/.next/standalone/packages/wiki-viewer-mcp/src/state-cache.ts +0 -55
- package/.next/standalone/packages/wiki-viewer-mcp/tsconfig.json +0 -19
- package/.next/standalone/pnpm-lock.yaml +0 -6697
- package/.next/standalone/pnpm-workspace.yaml +0 -8
- package/.next/standalone/postcss.config.mjs +0 -2
- package/.next/standalone/src/app/api/agent/activity/route.ts +0 -59
- package/.next/standalone/src/app/api/agent/admin/agents/[agentId]/revoke/route.ts +0 -40
- package/.next/standalone/src/app/api/agent/admin/agents/route.ts +0 -33
- package/.next/standalone/src/app/api/agent/admin/registrations/[regId]/approve/route.ts +0 -83
- package/.next/standalone/src/app/api/agent/admin/registrations/[regId]/deny/route.ts +0 -36
- package/.next/standalone/src/app/api/agent/admin/registrations/route.ts +0 -27
- package/.next/standalone/src/app/api/agent/events/[...path]/route.ts +0 -148
- package/.next/standalone/src/app/api/agent/files/[...path]/route.ts +0 -219
- package/.next/standalone/src/app/api/agent/fs/file/[...path]/route.ts +0 -446
- package/.next/standalone/src/app/api/agent/fs/ls/[[...path]]/route.ts +0 -152
- package/.next/standalone/src/app/api/agent/fs/move/route.ts +0 -130
- package/.next/standalone/src/app/api/agent/fs/search/route.ts +0 -272
- package/.next/standalone/src/app/api/agent/internal/span/route.ts +0 -121
- package/.next/standalone/src/app/api/agent/register/[regId]/route.ts +0 -50
- package/.next/standalone/src/app/api/agent/register/route.ts +0 -118
- package/.next/standalone/src/app/api/agent/settings/route.ts +0 -34
- package/.next/standalone/src/app/api/agent/settings/token/regenerate/route.ts +0 -20
- package/.next/standalone/src/app/api/agent/sidecar/[...path]/route.ts +0 -53
- package/.next/standalone/src/app/api/agents/install/route.ts +0 -143
- package/.next/standalone/src/app/api/agents/skill/route.ts +0 -20
- package/.next/standalone/src/app/api/agents/skill.tar.gz/route.ts +0 -87
- package/.next/standalone/src/app/api/app-proxy/[...path]/route.ts +0 -247
- package/.next/standalone/src/app/api/assets/[...path]/route.ts +0 -75
- package/.next/standalone/src/app/api/auth/[...all]/route.ts +0 -7
- package/.next/standalone/src/app/api/owner/init/route.ts +0 -14
- package/.next/standalone/src/app/api/share/[token]/route.ts +0 -269
- package/.next/standalone/src/app/api/share/route.ts +0 -127
- package/.next/standalone/src/app/api/system/admins/route.ts +0 -103
- package/.next/standalone/src/app/api/system/auth-config/route.ts +0 -22
- package/.next/standalone/src/app/api/system/auth-settings/route.ts +0 -86
- package/.next/standalone/src/app/api/system/browse/route.ts +0 -82
- package/.next/standalone/src/app/api/system/clear-root/route.ts +0 -16
- package/.next/standalone/src/app/api/system/config/route.ts +0 -14
- package/.next/standalone/src/app/api/system/pins/route.ts +0 -38
- package/.next/standalone/src/app/api/system/reveal/route.ts +0 -36
- package/.next/standalone/src/app/api/system/root-status/route.ts +0 -13
- package/.next/standalone/src/app/api/system/set-root/route.ts +0 -53
- package/.next/standalone/src/app/api/system/users/route.ts +0 -120
- package/.next/standalone/src/app/api/system/workspaces/[id]/open/route.ts +0 -34
- package/.next/standalone/src/app/api/system/workspaces/[id]/refresh/route.ts +0 -32
- package/.next/standalone/src/app/api/system/workspaces/[id]/route.ts +0 -78
- package/.next/standalone/src/app/api/system/workspaces/route.ts +0 -128
- package/.next/standalone/src/app/api/upload/[...path]/route.ts +0 -85
- package/.next/standalone/src/app/api/wiki/app/route.ts +0 -60
- package/.next/standalone/src/app/api/wiki/backlinks/route.ts +0 -29
- package/.next/standalone/src/app/api/wiki/content/route.ts +0 -159
- package/.next/standalone/src/app/api/wiki/download/route.ts +0 -100
- package/.next/standalone/src/app/api/wiki/file/route.ts +0 -57
- package/.next/standalone/src/app/api/wiki/folder/route.ts +0 -34
- package/.next/standalone/src/app/api/wiki/git-branches/route.ts +0 -32
- package/.next/standalone/src/app/api/wiki/git-checkout/route.ts +0 -45
- package/.next/standalone/src/app/api/wiki/git-diff/route.ts +0 -33
- package/.next/standalone/src/app/api/wiki/git-file-info/route.ts +0 -27
- package/.next/standalone/src/app/api/wiki/git-history/route.ts +0 -27
- package/.next/standalone/src/app/api/wiki/git-pull/route.ts +0 -48
- package/.next/standalone/src/app/api/wiki/move/route.ts +0 -61
- package/.next/standalone/src/app/api/wiki/new-file/route.ts +0 -56
- package/.next/standalone/src/app/api/wiki/outlinks/route.ts +0 -76
- package/.next/standalone/src/app/api/wiki/page/route.ts +0 -92
- package/.next/standalone/src/app/api/wiki/presence/route.ts +0 -56
- package/.next/standalone/src/app/api/wiki/route.ts +0 -116
- package/.next/standalone/src/app/api/wiki/search/route.ts +0 -44
- package/.next/standalone/src/app/api/wiki/slugs/route.ts +0 -54
- package/.next/standalone/src/app/api/wiki/upload/route.ts +0 -95
- package/.next/standalone/src/app/api/wiki/watch/route.ts +0 -67
- package/.next/standalone/src/app/globals.css +0 -1249
- package/.next/standalone/src/app/icon.svg +0 -11
- package/.next/standalone/src/app/layout.tsx +0 -78
- package/.next/standalone/src/app/manifest.ts +0 -30
- package/.next/standalone/src/app/page.tsx +0 -3260
- package/.next/standalone/src/app/s/[token]/page.tsx +0 -357
- package/.next/standalone/src/app/signin/page.tsx +0 -16
- package/.next/standalone/src/app/signin/signin-form.tsx +0 -238
- package/.next/standalone/src/components/ai-panel/activity-row.tsx +0 -284
- package/.next/standalone/src/components/ai-panel/ai-panel.tsx +0 -311
- package/.next/standalone/src/components/ai-panel/token-section.tsx +0 -313
- package/.next/standalone/src/components/auth-settings-sheet.tsx +0 -474
- package/.next/standalone/src/components/confirm-dialog.tsx +0 -56
- package/.next/standalone/src/components/dir-picker.tsx +0 -606
- package/.next/standalone/src/components/editor/backlinks-panel.tsx +0 -139
- package/.next/standalone/src/components/editor/bubble-menu.tsx +0 -346
- package/.next/standalone/src/components/editor/callout-extension.ts +0 -36
- package/.next/standalone/src/components/editor/comment-pip.tsx +0 -56
- package/.next/standalone/src/components/editor/comment-thread.tsx +0 -254
- package/.next/standalone/src/components/editor/csv-viewer.tsx +0 -379
- package/.next/standalone/src/components/editor/document-outline.tsx +0 -230
- package/.next/standalone/src/components/editor/editor-toolbar.tsx +0 -564
- package/.next/standalone/src/components/editor/editor.tsx +0 -1327
- package/.next/standalone/src/components/editor/extensions/drag-handle.ts +0 -325
- package/.next/standalone/src/components/editor/extensions/heading-anchors.ts +0 -55
- package/.next/standalone/src/components/editor/extensions/proof-span.ts +0 -60
- package/.next/standalone/src/components/editor/extensions/resizable-image.tsx +0 -159
- package/.next/standalone/src/components/editor/extensions.ts +0 -150
- package/.next/standalone/src/components/editor/file-fallback-viewer.tsx +0 -75
- package/.next/standalone/src/components/editor/folder-index.tsx +0 -236
- package/.next/standalone/src/components/editor/google-doc-viewer.tsx +0 -73
- package/.next/standalone/src/components/editor/image-viewer.tsx +0 -57
- package/.next/standalone/src/components/editor/large-file-gate.tsx +0 -108
- package/.next/standalone/src/components/editor/link-popover.tsx +0 -111
- package/.next/standalone/src/components/editor/media-popover.tsx +0 -212
- package/.next/standalone/src/components/editor/media-viewer.tsx +0 -70
- package/.next/standalone/src/components/editor/mermaid-viewer.tsx +0 -286
- package/.next/standalone/src/components/editor/node-app-viewer.tsx +0 -328
- package/.next/standalone/src/components/editor/notebook-viewer.tsx +0 -371
- package/.next/standalone/src/components/editor/office/docx-viewer.tsx +0 -93
- package/.next/standalone/src/components/editor/office/office-chrome.tsx +0 -83
- package/.next/standalone/src/components/editor/office/pptx-viewer.tsx +0 -104
- package/.next/standalone/src/components/editor/office/xlsx-viewer.tsx +0 -192
- package/.next/standalone/src/components/editor/pdf-viewer.tsx +0 -32
- package/.next/standalone/src/components/editor/proof-span-popover.tsx +0 -162
- package/.next/standalone/src/components/editor/slash-commands.tsx +0 -629
- package/.next/standalone/src/components/editor/source-viewer.tsx +0 -289
- package/.next/standalone/src/components/editor/suggest-edit-popover.tsx +0 -229
- package/.next/standalone/src/components/editor/suggestion-card.tsx +0 -206
- package/.next/standalone/src/components/editor/table-menu.tsx +0 -232
- package/.next/standalone/src/components/editor/view-mode-comment-button.tsx +0 -77
- package/.next/standalone/src/components/editor/website-viewer.tsx +0 -75
- package/.next/standalone/src/components/editor/wiki-link-create-dialog.tsx +0 -189
- package/.next/standalone/src/components/editor/wiki-link-decorator.ts +0 -79
- package/.next/standalone/src/components/editor/wiki-link-extension.ts +0 -120
- package/.next/standalone/src/components/editor/wiki-link-picker.tsx +0 -250
- package/.next/standalone/src/components/layout/viewer-toolbar.tsx +0 -54
- package/.next/standalone/src/components/search/search-command-dialog.tsx +0 -246
- package/.next/standalone/src/components/search/sidebar-search-box.tsx +0 -121
- package/.next/standalone/src/components/search/snippet-text.tsx +0 -48
- package/.next/standalone/src/components/share-dialog.tsx +0 -307
- package/.next/standalone/src/components/theme-provider.tsx +0 -16
- package/.next/standalone/src/components/theme-toggle.tsx +0 -24
- package/.next/standalone/src/components/ui/badge.tsx +0 -35
- package/.next/standalone/src/components/ui/button.tsx +0 -56
- package/.next/standalone/src/components/ui/card.tsx +0 -63
- package/.next/standalone/src/components/ui/collapsible.tsx +0 -9
- package/.next/standalone/src/components/ui/command.tsx +0 -151
- package/.next/standalone/src/components/ui/context-menu.tsx +0 -191
- package/.next/standalone/src/components/ui/dialog.tsx +0 -119
- package/.next/standalone/src/components/ui/dropdown-menu.tsx +0 -194
- package/.next/standalone/src/components/ui/input.tsx +0 -22
- package/.next/standalone/src/components/ui/label.tsx +0 -25
- package/.next/standalone/src/components/ui/popover.tsx +0 -33
- package/.next/standalone/src/components/ui/scroll-area.tsx +0 -47
- package/.next/standalone/src/components/ui/select.tsx +0 -156
- package/.next/standalone/src/components/ui/separator.tsx +0 -30
- package/.next/standalone/src/components/ui/sheet.tsx +0 -140
- package/.next/standalone/src/components/ui/skeleton.tsx +0 -15
- package/.next/standalone/src/components/ui/switch.tsx +0 -28
- package/.next/standalone/src/components/ui/tabs.tsx +0 -54
- package/.next/standalone/src/components/ui/textarea.tsx +0 -21
- package/.next/standalone/src/components/ui/tip.tsx +0 -23
- package/.next/standalone/src/components/ui/toggle-group.tsx +0 -41
- package/.next/standalone/src/components/ui/tooltip.tsx +0 -27
- package/.next/standalone/src/components/view-width-toggle.tsx +0 -70
- package/.next/standalone/src/components/wiki/frontmatter-header.tsx +0 -164
- package/.next/standalone/src/hooks/use-is-mobile.ts +0 -14
- package/.next/standalone/src/lib/app-runner.ts +0 -272
- package/.next/standalone/src/lib/auth/admin.ts +0 -120
- package/.next/standalone/src/lib/auth/allowlist.ts +0 -50
- package/.next/standalone/src/lib/auth/client.ts +0 -4
- package/.next/standalone/src/lib/auth/csrf.ts +0 -68
- package/.next/standalone/src/lib/auth/server.ts +0 -215
- package/.next/standalone/src/lib/cabinets/tree.ts +0 -75
- package/.next/standalone/src/lib/config.ts +0 -114
- package/.next/standalone/src/lib/embeds/detect.ts +0 -142
- package/.next/standalone/src/lib/git-secrets.ts +0 -65
- package/.next/standalone/src/lib/git.ts +0 -503
- package/.next/standalone/src/lib/google/detect.ts +0 -107
- package/.next/standalone/src/lib/markdown/parse-frontmatter.ts +0 -104
- package/.next/standalone/src/lib/markdown/remark-wikilinks.ts +0 -100
- package/.next/standalone/src/lib/markdown/sanitize-schema.ts +0 -106
- package/.next/standalone/src/lib/markdown/to-html.ts +0 -282
- package/.next/standalone/src/lib/markdown/to-markdown.ts +0 -252
- package/.next/standalone/src/lib/proof/activity-shared.ts +0 -31
- package/.next/standalone/src/lib/proof/activity.ts +0 -74
- package/.next/standalone/src/lib/proof/audit.ts +0 -88
- package/.next/standalone/src/lib/proof/auth.ts +0 -143
- package/.next/standalone/src/lib/proof/block-refs.ts +0 -133
- package/.next/standalone/src/lib/proof/blocks.ts +0 -73
- package/.next/standalone/src/lib/proof/client-auth.ts +0 -23
- package/.next/standalone/src/lib/proof/collab-state.ts +0 -81
- package/.next/standalone/src/lib/proof/event-bus.ts +0 -47
- package/.next/standalone/src/lib/proof/file-lock.ts +0 -43
- package/.next/standalone/src/lib/proof/glob.ts +0 -51
- package/.next/standalone/src/lib/proof/idempotency.ts +0 -37
- package/.next/standalone/src/lib/proof/lease.ts +0 -117
- package/.next/standalone/src/lib/proof/mutex.ts +0 -36
- package/.next/standalone/src/lib/proof/ops-applier.ts +0 -727
- package/.next/standalone/src/lib/proof/owner-auth.ts +0 -2
- package/.next/standalone/src/lib/proof/pending.ts +0 -97
- package/.next/standalone/src/lib/proof/proof-span.ts +0 -141
- package/.next/standalone/src/lib/proof/rate-limit.ts +0 -53
- package/.next/standalone/src/lib/proof/raw-fs.ts +0 -197
- package/.next/standalone/src/lib/proof/register-rate-limit.ts +0 -53
- package/.next/standalone/src/lib/proof/registry.ts +0 -195
- package/.next/standalone/src/lib/proof/sidecar.ts +0 -103
- package/.next/standalone/src/lib/proof/suggest-capture.ts +0 -69
- package/.next/standalone/src/lib/proof/types.ts +0 -182
- package/.next/standalone/src/lib/proof-config.ts +0 -14
- package/.next/standalone/src/lib/root-dir.ts +0 -35
- package/.next/standalone/src/lib/search/indexable-exts.ts +0 -25
- package/.next/standalone/src/lib/search/indexer.ts +0 -634
- package/.next/standalone/src/lib/search/sanitize.ts +0 -35
- package/.next/standalone/src/lib/search/search-db.ts +0 -57
- package/.next/standalone/src/lib/search/watcher-pool.ts +0 -79
- package/.next/standalone/src/lib/shared-docs/db.ts +0 -177
- package/.next/standalone/src/lib/toast.ts +0 -9
- package/.next/standalone/src/lib/utils.ts +0 -6
- package/.next/standalone/src/lib/wiki-helpers.ts +0 -36
- package/.next/standalone/src/lib/workspace-client.ts +0 -82
- package/.next/standalone/src/lib/workspace-context.ts +0 -173
- package/.next/standalone/src/lib/workspaces.ts +0 -400
- package/.next/standalone/src/middleware.ts +0 -44
- package/.next/standalone/src/stores/ai-panel-store.ts +0 -79
- package/.next/standalone/src/stores/editor-store.ts +0 -439
- package/.next/standalone/src/stores/pin-store.ts +0 -56
- package/.next/standalone/src/stores/proof-store.ts +0 -124
- package/.next/standalone/src/stores/recent-store.ts +0 -51
- package/.next/standalone/src/stores/search-store.ts +0 -104
- package/.next/standalone/src/stores/show-hidden-store.ts +0 -26
- package/.next/standalone/src/stores/sidebar-width-store.ts +0 -39
- package/.next/standalone/src/stores/skin-store.ts +0 -42
- package/.next/standalone/src/stores/tree-store.ts +0 -52
- package/.next/standalone/src/stores/view-width-store.ts +0 -101
- package/.next/standalone/src/stores/wiki-slugs-store.ts +0 -75
- package/.next/standalone/src/tests/proof/activity-aggregator.test.ts +0 -146
- package/.next/standalone/src/tests/proof/admin-create-user.test.ts +0 -43
- package/.next/standalone/src/tests/proof/agent-fs.test.ts +0 -973
- package/.next/standalone/src/tests/proof/agent-ownership.test.ts +0 -140
- package/.next/standalone/src/tests/proof/agent-workspace-scope.test.ts +0 -134
- package/.next/standalone/src/tests/proof/agents-install.test.ts +0 -110
- package/.next/standalone/src/tests/proof/bench-write.ts +0 -179
- package/.next/standalone/src/tests/proof/better-auth.test.ts +0 -68
- package/.next/standalone/src/tests/proof/block-refs.test.ts +0 -108
- package/.next/standalone/src/tests/proof/blocks.test.ts +0 -92
- package/.next/standalone/src/tests/proof/collab-state.test.ts +0 -501
- package/.next/standalone/src/tests/proof/comments-ops.test.ts +0 -177
- package/.next/standalone/src/tests/proof/editor-roundtrip.test.ts +0 -85
- package/.next/standalone/src/tests/proof/external-edit.test.ts +0 -58
- package/.next/standalone/src/tests/proof/file-lock.test.ts +0 -80
- package/.next/standalone/src/tests/proof/git-branches-checkout.test.ts +0 -136
- package/.next/standalone/src/tests/proof/git-read-features.test.ts +0 -473
- package/.next/standalone/src/tests/proof/git-secrets.test.ts +0 -138
- package/.next/standalone/src/tests/proof/git-sparse.test.ts +0 -257
- package/.next/standalone/src/tests/proof/git-workspace.test.ts +0 -135
- package/.next/standalone/src/tests/proof/git.test.ts +0 -243
- package/.next/standalone/src/tests/proof/glob.test.ts +0 -82
- package/.next/standalone/src/tests/proof/helpers/auth-session.ts +0 -27
- package/.next/standalone/src/tests/proof/markdown-to-html.test.ts +0 -46
- package/.next/standalone/src/tests/proof/ops-applier.test.ts +0 -368
- package/.next/standalone/src/tests/proof/owner-init.test.ts +0 -2
- package/.next/standalone/src/tests/proof/parse-frontmatter.test.ts +0 -60
- package/.next/standalone/src/tests/proof/preload.ts +0 -21
- package/.next/standalone/src/tests/proof/proof-span.test.ts +0 -98
- package/.next/standalone/src/tests/proof/rate-limit.test.ts +0 -54
- package/.next/standalone/src/tests/proof/readonly-enforcement.test.ts +0 -161
- package/.next/standalone/src/tests/proof/reconcile-sidecar.test.ts +0 -195
- package/.next/standalone/src/tests/proof/registration-flow.test.ts +0 -330
- package/.next/standalone/src/tests/proof/registry.test.ts +0 -169
- package/.next/standalone/src/tests/proof/routes.test.ts +0 -516
- package/.next/standalone/src/tests/proof/search-index.test.ts +0 -376
- package/.next/standalone/src/tests/proof/sidecar-lifecycle.test.ts +0 -177
- package/.next/standalone/src/tests/proof/sidecar-trim.test.ts +0 -58
- package/.next/standalone/src/tests/proof/suggestion-ops.test.ts +0 -280
- package/.next/standalone/src/tests/proof/wiki-content-put.test.ts +0 -140
- package/.next/standalone/src/tests/proof/wiki-routes-auth.test.ts +0 -208
- package/.next/standalone/src/tests/proof/workspace-isolation.test.ts +0 -87
- package/.next/standalone/src/tests/proof/workspaces-api.test.ts +0 -227
- package/.next/standalone/src/types/index.ts +0 -47
- package/.next/standalone/tailwind.config.ts +0 -191
- package/.next/standalone/tsconfig.json +0 -41
- package/.next/standalone/tsconfig.tsbuildinfo +0 -1
- /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → rRyvFORvJoc5OWbCR2A_P}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → rRyvFORvJoc5OWbCR2A_P}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → rRyvFORvJoc5OWbCR2A_P}/_ssgManifest.js +0 -0
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import type { Link, Parent, PhrasingContent, Root, Text } from "mdast";
|
|
2
|
-
import type { Plugin } from "unified";
|
|
3
|
-
|
|
4
|
-
const WIKILINK_RE = /\[\[([a-z0-9-]+)(?:\|([^\]#|]+)|#([a-z0-9-]+))?\]\]/g;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Remark plugin that converts [[slug]], [[slug|alias]], and [[slug#anchor]]
|
|
8
|
-
* occurrences in text nodes into link nodes targeting `#wiki:slug` (with
|
|
9
|
-
* `#anchor` appended when present). The link's data attributes carry the
|
|
10
|
-
* slug, optional alias, and optional anchor so renderers can branch on
|
|
11
|
-
* wiki-links specifically.
|
|
12
|
-
*/
|
|
13
|
-
const remarkWikilinks: Plugin<[], Root> = () => {
|
|
14
|
-
return (tree) => {
|
|
15
|
-
visit(tree, (node, index, parent) => {
|
|
16
|
-
if (!parent || index === undefined) return;
|
|
17
|
-
if (node.type !== "text") return;
|
|
18
|
-
const text = (node as Text).value;
|
|
19
|
-
if (!text?.includes("[[")) return;
|
|
20
|
-
|
|
21
|
-
const replacements: PhrasingContent[] = [];
|
|
22
|
-
let lastIndex = 0;
|
|
23
|
-
WIKILINK_RE.lastIndex = 0;
|
|
24
|
-
let match: RegExpExecArray | null = WIKILINK_RE.exec(text);
|
|
25
|
-
while (match !== null) {
|
|
26
|
-
const [full, slug, alias, anchor] = match;
|
|
27
|
-
if (match.index > lastIndex) {
|
|
28
|
-
replacements.push({
|
|
29
|
-
type: "text",
|
|
30
|
-
value: text.slice(lastIndex, match.index),
|
|
31
|
-
} as Text);
|
|
32
|
-
}
|
|
33
|
-
const visible = alias ?? (anchor ? `${slug}#${anchor}` : slug);
|
|
34
|
-
const url = anchor ? `#wiki:${slug}#${anchor}` : `#wiki:${slug}`;
|
|
35
|
-
const link: Link = {
|
|
36
|
-
type: "link",
|
|
37
|
-
url,
|
|
38
|
-
title: null,
|
|
39
|
-
children: [{ type: "text", value: visible } as Text],
|
|
40
|
-
data: {
|
|
41
|
-
hProperties: {
|
|
42
|
-
"data-wiki-link": "true",
|
|
43
|
-
"data-slug": slug,
|
|
44
|
-
...(alias ? { "data-alias": alias } : {}),
|
|
45
|
-
...(anchor ? { "data-anchor": anchor } : {}),
|
|
46
|
-
className: ["wiki-link"],
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
replacements.push(link);
|
|
51
|
-
lastIndex = match.index + full.length;
|
|
52
|
-
match = WIKILINK_RE.exec(text);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (replacements.length === 0) return;
|
|
56
|
-
if (lastIndex < text.length) {
|
|
57
|
-
replacements.push({
|
|
58
|
-
type: "text",
|
|
59
|
-
value: text.slice(lastIndex),
|
|
60
|
-
} as Text);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
(parent as Parent).children.splice(index, 1, ...replacements);
|
|
64
|
-
return index + replacements.length;
|
|
65
|
-
});
|
|
66
|
-
};
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
type Visitor = (
|
|
70
|
-
node: Root | PhrasingContent | Parent,
|
|
71
|
-
index: number | undefined,
|
|
72
|
-
parent: Parent | null,
|
|
73
|
-
) => number | undefined;
|
|
74
|
-
|
|
75
|
-
function visit(
|
|
76
|
-
node: Root | Parent,
|
|
77
|
-
fn: Visitor,
|
|
78
|
-
parent: Parent | null = null,
|
|
79
|
-
): void {
|
|
80
|
-
if ("children" in node && Array.isArray(node.children)) {
|
|
81
|
-
let i = 0;
|
|
82
|
-
while (i < node.children.length) {
|
|
83
|
-
const child = node.children[i];
|
|
84
|
-
const next = fn(child as PhrasingContent, i, node);
|
|
85
|
-
if (typeof next === "number") {
|
|
86
|
-
i = next;
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
if (child && typeof child === "object" && "children" in child) {
|
|
90
|
-
visit(child as Parent, fn, node);
|
|
91
|
-
}
|
|
92
|
-
i += 1;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (parent === null) {
|
|
96
|
-
fn(node, undefined, null);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export default remarkWikilinks;
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { defaultSchema } from "rehype-sanitize";
|
|
2
|
-
import type { Options as SanitizeOptions } from "rehype-sanitize";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Sanitize schema for the read-only markdown preview.
|
|
6
|
-
*
|
|
7
|
-
* The base `defaultSchema` from rehype-sanitize strips most attributes and
|
|
8
|
-
* many elements. Wiki content legitimately embeds raw HTML: tables, task-list
|
|
9
|
-
* checkboxes, and video/embed iframes produced by the shared pipeline.
|
|
10
|
-
* Extend the schema so that markup renders instead of being escaped to literal
|
|
11
|
-
* text, while still removing scripts, event handlers, and other dangerous
|
|
12
|
-
* vectors that defaultSchema blocks.
|
|
13
|
-
*/
|
|
14
|
-
const tableTags = ["table", "thead", "tbody", "tfoot", "tr", "th", "td", "colgroup", "col"];
|
|
15
|
-
|
|
16
|
-
export const previewSanitizeSchema: SanitizeOptions = {
|
|
17
|
-
...defaultSchema,
|
|
18
|
-
tagNames: Array.from(
|
|
19
|
-
new Set([
|
|
20
|
-
...(defaultSchema.tagNames ?? []),
|
|
21
|
-
...tableTags,
|
|
22
|
-
// Task-list structure emitted by fixTaskListHtml.
|
|
23
|
-
"label",
|
|
24
|
-
// Embed wrapper divs and iframes from upgradeProviderVideos.
|
|
25
|
-
"iframe",
|
|
26
|
-
"video",
|
|
27
|
-
]),
|
|
28
|
-
),
|
|
29
|
-
attributes: {
|
|
30
|
-
...defaultSchema.attributes,
|
|
31
|
-
// Allow layout attributes on table elements.
|
|
32
|
-
table: [...(defaultSchema.attributes?.table ?? []), "className", "style"],
|
|
33
|
-
th: [
|
|
34
|
-
...(defaultSchema.attributes?.th ?? []),
|
|
35
|
-
"colSpan",
|
|
36
|
-
"rowSpan",
|
|
37
|
-
"style",
|
|
38
|
-
"className",
|
|
39
|
-
],
|
|
40
|
-
td: [
|
|
41
|
-
...(defaultSchema.attributes?.td ?? []),
|
|
42
|
-
"colSpan",
|
|
43
|
-
"rowSpan",
|
|
44
|
-
"style",
|
|
45
|
-
"className",
|
|
46
|
-
],
|
|
47
|
-
col: ["span", "style", "className"],
|
|
48
|
-
colgroup: ["span", "style", "className"],
|
|
49
|
-
tr: ["style", "className"],
|
|
50
|
-
// Preserve wiki-link data attributes used by the delegated click handler.
|
|
51
|
-
// rehype-sanitize uses hast property names (camelCase) in the attributes map.
|
|
52
|
-
// Plain string = allow any value; tuple [name, val1, val2] = allow only those values.
|
|
53
|
-
a: [
|
|
54
|
-
...(defaultSchema.attributes?.a ?? []),
|
|
55
|
-
"className",
|
|
56
|
-
["dataWikiLink", "true"],
|
|
57
|
-
"dataSlug",
|
|
58
|
-
"dataAlias",
|
|
59
|
-
"dataAnchor",
|
|
60
|
-
["dataBroken", "true"],
|
|
61
|
-
["dataPdfLink", "true"],
|
|
62
|
-
],
|
|
63
|
-
// Task-list input/label.
|
|
64
|
-
input: ["type", "checked", "disabled"],
|
|
65
|
-
label: ["className"],
|
|
66
|
-
// Embed iframes - allow all attrs used by upgradeProviderVideos.
|
|
67
|
-
iframe: [
|
|
68
|
-
"src",
|
|
69
|
-
"allow",
|
|
70
|
-
"allowFullScreen",
|
|
71
|
-
"frameBorder",
|
|
72
|
-
"loading",
|
|
73
|
-
"referrerPolicy",
|
|
74
|
-
"dataEmbedProvider",
|
|
75
|
-
],
|
|
76
|
-
// Embed wrapper divs.
|
|
77
|
-
div: [
|
|
78
|
-
...(defaultSchema.attributes?.div ?? []),
|
|
79
|
-
"className",
|
|
80
|
-
["dataEmbed", "true"],
|
|
81
|
-
"dataProvider",
|
|
82
|
-
"dataSrc",
|
|
83
|
-
"dataOriginalUrl",
|
|
84
|
-
"dataAspectRatio",
|
|
85
|
-
],
|
|
86
|
-
// Task-list list items.
|
|
87
|
-
li: [
|
|
88
|
-
...(defaultSchema.attributes?.li ?? []),
|
|
89
|
-
"className",
|
|
90
|
-
"dataType",
|
|
91
|
-
"dataChecked",
|
|
92
|
-
],
|
|
93
|
-
ul: [
|
|
94
|
-
...(defaultSchema.attributes?.ul ?? []),
|
|
95
|
-
"className",
|
|
96
|
-
"dataType",
|
|
97
|
-
],
|
|
98
|
-
// Allow class names + id on all elements for styling.
|
|
99
|
-
"*": [...(defaultSchema.attributes?.["*"] ?? []), "className", "id"],
|
|
100
|
-
},
|
|
101
|
-
// Allow https iframe src (for embed providers). http excluded intentionally.
|
|
102
|
-
protocols: {
|
|
103
|
-
...defaultSchema.protocols,
|
|
104
|
-
src: [...(defaultSchema.protocols?.src ?? []), "https"],
|
|
105
|
-
},
|
|
106
|
-
};
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
import rehypeParse from "rehype-parse";
|
|
2
|
-
import rehypeRaw from "rehype-raw";
|
|
3
|
-
import rehypeSanitize from "rehype-sanitize";
|
|
4
|
-
import rehypeStringify from "rehype-stringify";
|
|
5
|
-
import remarkGfm from "remark-gfm";
|
|
6
|
-
import remarkParse from "remark-parse";
|
|
7
|
-
import remarkRehype from "remark-rehype";
|
|
8
|
-
import { unified } from "unified";
|
|
9
|
-
import { detectEmbed } from "@/lib/embeds/detect";
|
|
10
|
-
import { previewSanitizeSchema } from "@/lib/markdown/sanitize-schema";
|
|
11
|
-
|
|
12
|
-
// Canonical wiki-link regex (llm-wiki-pm ground truth).
|
|
13
|
-
// Groups: 1=slug 2=alias 3=anchor
|
|
14
|
-
const WIKI_LINK_RE = /\[\[([^\]|#]+)(?:\|([^\]]*)|#([^\]]*))?\]\]/g;
|
|
15
|
-
const SLUG_VALID_RE = /^[a-z0-9-]+$/;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Pre-process markdown to convert wiki-links to HTML anchors
|
|
19
|
-
* before the remark pipeline (which treats [[ as plain text).
|
|
20
|
-
*
|
|
21
|
-
* Handles three forms:
|
|
22
|
-
* [[slug]] - bare
|
|
23
|
-
* [[slug|alias]] - aliased
|
|
24
|
-
* [[slug#anchor]] - anchored
|
|
25
|
-
*
|
|
26
|
-
* Slugs that fail ^[a-z0-9-]+$ validation are left as plain text.
|
|
27
|
-
*/
|
|
28
|
-
function convertWikiLinks(markdown: string): string {
|
|
29
|
-
return markdown.replace(
|
|
30
|
-
WIKI_LINK_RE,
|
|
31
|
-
(
|
|
32
|
-
_match: string,
|
|
33
|
-
rawSlug: string,
|
|
34
|
-
alias: string | undefined,
|
|
35
|
-
anchor: string | undefined,
|
|
36
|
-
): string => {
|
|
37
|
-
const slug = rawSlug.trim();
|
|
38
|
-
if (!SLUG_VALID_RE.test(slug)) return _match;
|
|
39
|
-
const visibleText = alias ?? (anchor ? `${slug}#${anchor}` : slug);
|
|
40
|
-
const href = anchor ? `#wiki:${slug}#${anchor}` : `#wiki:${slug}`;
|
|
41
|
-
const aliasAttr = alias !== undefined ? ` data-alias="${alias}"` : "";
|
|
42
|
-
const anchorAttr = anchor !== undefined ? ` data-anchor="${anchor}"` : "";
|
|
43
|
-
return `<a data-wiki-link="true" data-slug="${slug}"${aliasAttr}${anchorAttr} href="${href}" class="wiki-link">${visibleText}</a>`;
|
|
44
|
-
},
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Post-process HTML to fix task list structure for Tiptap compatibility.
|
|
50
|
-
* remark-gfm outputs: <li><input type="checkbox" ...> text</li>
|
|
51
|
-
* Tiptap expects: <li data-type="taskItem" data-checked="..."><label><input ...></label><div><p>text</p></div></li>
|
|
52
|
-
* And the parent <ul> needs class="task-list" and data-type="taskList".
|
|
53
|
-
*/
|
|
54
|
-
function fixTaskListHtml(html: string): string {
|
|
55
|
-
// Convert task list <ul> with contains-task-list class
|
|
56
|
-
html = html.replace(
|
|
57
|
-
/<ul class="contains-task-list">/g,
|
|
58
|
-
'<ul data-type="taskList" class="task-list">',
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
// Convert each task list item to Tiptap's expected structure
|
|
62
|
-
html = html.replace(
|
|
63
|
-
/<li class="task-list-item">\s*<input type="checkbox"([^>]*)>\s*([\s\S]*?)(?=<\/li>)/g,
|
|
64
|
-
(_match, attrs: string, content: string) => {
|
|
65
|
-
const checked = attrs.includes("checked");
|
|
66
|
-
const cleanContent = content.trim();
|
|
67
|
-
return `<li data-type="taskItem" data-checked="${checked}"><label><input type="checkbox"${checked ? " checked" : ""}></label><div><p>${cleanContent}</p></div>`;
|
|
68
|
-
},
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
return html;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Upgrade broken `<video src="https://youtu.be/...">` (or any non-file video URL
|
|
76
|
-
* that points at a known embed provider) into a real iframe embed block.
|
|
77
|
-
*
|
|
78
|
-
* This heals content written before we had proper embed support, and also any
|
|
79
|
-
* time the TipTap schema round-trip collapsed an iframe into a video tag.
|
|
80
|
-
*/
|
|
81
|
-
function upgradeProviderVideos(html: string): string {
|
|
82
|
-
return html.replace(
|
|
83
|
-
/<video\b([^>]*)\bsrc="([^"]+)"([^>]*)><\/video>/gi,
|
|
84
|
-
(match, _before: string, src: string, _after: string) => {
|
|
85
|
-
const detected = detectEmbed(src);
|
|
86
|
-
if (!detected || detected.provider === "video") return match;
|
|
87
|
-
|
|
88
|
-
const aspect = detected.aspectRatio
|
|
89
|
-
? ` data-aspect-ratio="${detected.aspectRatio}"`
|
|
90
|
-
: "";
|
|
91
|
-
return (
|
|
92
|
-
`<div data-embed="true" data-provider="${detected.provider}"` +
|
|
93
|
-
` data-src="${detected.embedUrl}"` +
|
|
94
|
-
` data-original-url="${detected.originalUrl}"${aspect}>` +
|
|
95
|
-
`<iframe src="${detected.embedUrl}"` +
|
|
96
|
-
` data-embed-provider="${detected.provider}"` +
|
|
97
|
-
` allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen"` +
|
|
98
|
-
` allowfullscreen loading="lazy" frameborder="0"></iframe>` +
|
|
99
|
-
`</div>`
|
|
100
|
-
);
|
|
101
|
-
},
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Rewrite relative URLs (./file.pdf, ./image.png) to /api/assets/{pagePath}/file
|
|
107
|
-
* and convert PDF links to inline embedded viewers.
|
|
108
|
-
* Applies to href, src, and data-src attributes (the last is used by embed blocks).
|
|
109
|
-
*/
|
|
110
|
-
function resolveRelativeUrls(html: string, pagePath: string): string {
|
|
111
|
-
const dirPath = pagePath;
|
|
112
|
-
|
|
113
|
-
html = html.replace(
|
|
114
|
-
/href="\.\/([^"]+)"/g,
|
|
115
|
-
(_match, file: string) => `href="/api/assets/${dirPath}/${file}"`,
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
html = html.replace(
|
|
119
|
-
/src="\.\/([^"]+)"/g,
|
|
120
|
-
(_match, file: string) => `src="/api/assets/${dirPath}/${file}"`,
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
html = html.replace(
|
|
124
|
-
/data-src="\.\/([^"]+)"/g,
|
|
125
|
-
(_match, file: string) => `data-src="/api/assets/${dirPath}/${file}"`,
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
// Mark PDF links with a data attribute so the editor can handle them
|
|
129
|
-
html = html.replace(
|
|
130
|
-
/<a([^>]*?)href="(\/api\/assets\/[^"]+\.pdf)"([^>]*?)>/gi,
|
|
131
|
-
(_match, before: string, url: string, after: string) => {
|
|
132
|
-
return `<a${before}href="${url}"${after} data-pdf-link="true">`;
|
|
133
|
-
},
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
return html;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Unified's plugin resolution + processor freeze runs on every `unified()`
|
|
140
|
-
// call. Reuse single frozen pipelines across every page render so
|
|
141
|
-
// navigation doesn't pay that cost on the hot path.
|
|
142
|
-
|
|
143
|
-
// Base pipeline: produces HTML with raw nodes passed through as-is.
|
|
144
|
-
// Used for both editor and (pre-sanitize) viewer passes.
|
|
145
|
-
const processor = unified()
|
|
146
|
-
.use(remarkParse)
|
|
147
|
-
.use(remarkGfm)
|
|
148
|
-
.use(remarkRehype, { allowDangerousHtml: true })
|
|
149
|
-
.use(rehypeStringify, { allowDangerousHtml: true })
|
|
150
|
-
.freeze();
|
|
151
|
-
|
|
152
|
-
// Sanitize-only pipeline: takes a fully assembled HTML string, parses it back
|
|
153
|
-
// into hast (rehype-parse as a fragment), expands any raw nodes (rehype-raw),
|
|
154
|
-
// then strips unsafe nodes (rehype-sanitize). Runs LAST so all string
|
|
155
|
-
// post-processing is covered by sanitize.
|
|
156
|
-
const sanitizerOnly = unified()
|
|
157
|
-
.use(rehypeParse, { fragment: true })
|
|
158
|
-
.use(rehypeRaw)
|
|
159
|
-
.use(rehypeSanitize, previewSanitizeSchema)
|
|
160
|
-
.use(rehypeStringify)
|
|
161
|
-
.freeze();
|
|
162
|
-
|
|
163
|
-
// Render cache: the remark→rehype pipeline is the heaviest synchronous work on
|
|
164
|
-
// the open path. Keying rendered HTML by (content, options) makes re-opening a
|
|
165
|
-
// doc — or returning to it — parse-free. Bounded LRU so it can't grow unbounded.
|
|
166
|
-
const RENDER_CACHE_MAX = 50;
|
|
167
|
-
// Skip caching very large outputs to bound memory (still parsed, just not retained).
|
|
168
|
-
const RENDER_CACHE_MAX_HTML = 256 * 1024;
|
|
169
|
-
const renderCache = new Map<string, string>();
|
|
170
|
-
|
|
171
|
-
/** Cheap, stable 53-bit string hash (cyrb53) — no crypto, no allocations per char. */
|
|
172
|
-
function hashStr(s: string): string {
|
|
173
|
-
let h1 = 0xdeadbeef ^ s.length;
|
|
174
|
-
let h2 = 0x41c6ce57 ^ s.length;
|
|
175
|
-
for (let i = 0; i < s.length; i++) {
|
|
176
|
-
const ch = s.charCodeAt(i);
|
|
177
|
-
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
178
|
-
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
179
|
-
}
|
|
180
|
-
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
|
181
|
-
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
182
|
-
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export interface MarkdownToHtmlOptions {
|
|
186
|
-
/** File path used to resolve relative URLs (./image.png etc.). */
|
|
187
|
-
pagePath?: string;
|
|
188
|
-
/** Run rehype-sanitize on output. Use true for read-only viewer. Default false. */
|
|
189
|
-
sanitize?: boolean;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function normalizeOpts(
|
|
193
|
-
optsOrPagePath?: string | MarkdownToHtmlOptions,
|
|
194
|
-
): MarkdownToHtmlOptions {
|
|
195
|
-
return typeof optsOrPagePath === "string"
|
|
196
|
-
? { pagePath: optsOrPagePath }
|
|
197
|
-
: (optsOrPagePath ?? {});
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/** Stable cache key for a (markdown, options) render. Shared by sync + worker paths. */
|
|
201
|
-
export function renderCacheKeyFor(
|
|
202
|
-
markdown: string,
|
|
203
|
-
optsOrPagePath?: string | MarkdownToHtmlOptions,
|
|
204
|
-
): string {
|
|
205
|
-
const opts = normalizeOpts(optsOrPagePath);
|
|
206
|
-
return `${opts.sanitize ? 1 : 0}:${opts.pagePath ?? ""}:${markdown.length}:${hashStr(markdown)}`;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/** Look up a previously rendered result (LRU-refreshed). */
|
|
210
|
-
export function renderCacheGet(key: string): string | undefined {
|
|
211
|
-
const cached = renderCache.get(key);
|
|
212
|
-
if (cached === undefined) return undefined;
|
|
213
|
-
renderCache.delete(key);
|
|
214
|
-
renderCache.set(key, cached);
|
|
215
|
-
return cached;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/** Store a rendered result, evicting the oldest entry past the cap. */
|
|
219
|
-
export function renderCacheStore(key: string, html: string): void {
|
|
220
|
-
if (html.length > RENDER_CACHE_MAX_HTML) return;
|
|
221
|
-
renderCache.set(key, html);
|
|
222
|
-
if (renderCache.size > RENDER_CACHE_MAX) {
|
|
223
|
-
const oldest = renderCache.keys().next().value;
|
|
224
|
-
if (oldest !== undefined) renderCache.delete(oldest);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Pure markdown→HTML transform with NO cache. Safe to run in a Web Worker
|
|
230
|
-
* (string-only post-processing, no DOM). The cache lives on the main thread so
|
|
231
|
-
* cache hits never pay a worker round-trip.
|
|
232
|
-
*/
|
|
233
|
-
export async function renderMarkdownUncached(
|
|
234
|
-
markdown: string,
|
|
235
|
-
optsOrPagePath?: string | MarkdownToHtmlOptions,
|
|
236
|
-
): Promise<string> {
|
|
237
|
-
const opts = normalizeOpts(optsOrPagePath);
|
|
238
|
-
|
|
239
|
-
// Pre-process wiki-links before remark (which would treat [[ as text)
|
|
240
|
-
const preprocessed = convertWikiLinks(markdown);
|
|
241
|
-
|
|
242
|
-
// Always use the base pipeline first.
|
|
243
|
-
const result = await processor.process(preprocessed);
|
|
244
|
-
let html = String(result);
|
|
245
|
-
|
|
246
|
-
// Post-process task lists for Tiptap compatibility.
|
|
247
|
-
html = fixTaskListHtml(html);
|
|
248
|
-
|
|
249
|
-
// Heal <video src="youtube-url"> into real iframe embeds.
|
|
250
|
-
// Must run before sanitize so <video src> attr is still present.
|
|
251
|
-
html = upgradeProviderVideos(html);
|
|
252
|
-
|
|
253
|
-
// Resolve relative URLs if page path is provided.
|
|
254
|
-
// Must run before sanitize so interpolated paths are covered.
|
|
255
|
-
if (opts.pagePath) {
|
|
256
|
-
html = resolveRelativeUrls(html, opts.pagePath);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Sanitize last, after all string post-processing, so no injected
|
|
260
|
-
// content escapes the sanitizer.
|
|
261
|
-
if (opts.sanitize) {
|
|
262
|
-
html = String(await sanitizerOnly.process(html));
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return html;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
export async function markdownToHtml(
|
|
269
|
-
markdown: string,
|
|
270
|
-
optsOrPagePath?: string | MarkdownToHtmlOptions,
|
|
271
|
-
): Promise<string> {
|
|
272
|
-
const opts = normalizeOpts(optsOrPagePath);
|
|
273
|
-
|
|
274
|
-
// Parse-free fast path: identical (content, options) was rendered before.
|
|
275
|
-
const cacheKey = renderCacheKeyFor(markdown, opts);
|
|
276
|
-
const cached = renderCacheGet(cacheKey);
|
|
277
|
-
if (cached !== undefined) return cached;
|
|
278
|
-
|
|
279
|
-
const html = await renderMarkdownUncached(markdown, opts);
|
|
280
|
-
renderCacheStore(cacheKey, html);
|
|
281
|
-
return html;
|
|
282
|
-
}
|