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,75 +0,0 @@
|
|
|
1
|
-
import { readFile, stat } from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { NextResponse } from "next/server";
|
|
4
|
-
import { resolveWorkspaceForAgent } from "@/lib/workspace-context";
|
|
5
|
-
import { safeWorkspacePath } from "@/lib/workspaces";
|
|
6
|
-
|
|
7
|
-
const MIME_MAP: Record<string, string> = {
|
|
8
|
-
jpg: "image/jpeg",
|
|
9
|
-
jpeg: "image/jpeg",
|
|
10
|
-
png: "image/png",
|
|
11
|
-
gif: "image/gif",
|
|
12
|
-
webp: "image/webp",
|
|
13
|
-
svg: "image/svg+xml",
|
|
14
|
-
avif: "image/avif",
|
|
15
|
-
ico: "image/x-icon",
|
|
16
|
-
bmp: "image/bmp",
|
|
17
|
-
pdf: "application/pdf",
|
|
18
|
-
txt: "text/plain; charset=utf-8",
|
|
19
|
-
md: "text/markdown; charset=utf-8",
|
|
20
|
-
mp4: "video/mp4",
|
|
21
|
-
webm: "video/webm",
|
|
22
|
-
mov: "video/quicktime",
|
|
23
|
-
m4v: "video/mp4",
|
|
24
|
-
mp3: "audio/mpeg",
|
|
25
|
-
wav: "audio/wav",
|
|
26
|
-
ogg: "audio/ogg",
|
|
27
|
-
m4a: "audio/mp4",
|
|
28
|
-
aac: "audio/aac",
|
|
29
|
-
ipynb: "application/json",
|
|
30
|
-
json: "application/json",
|
|
31
|
-
js: "text/javascript",
|
|
32
|
-
ts: "text/plain",
|
|
33
|
-
css: "text/css",
|
|
34
|
-
html: "text/html",
|
|
35
|
-
mmd: "text/plain",
|
|
36
|
-
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
37
|
-
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
38
|
-
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export async function GET(
|
|
42
|
-
request: Request,
|
|
43
|
-
{ params }: { params: Promise<{ path: string[] }> },
|
|
44
|
-
) {
|
|
45
|
-
const wsx = await resolveWorkspaceForAgent(request);
|
|
46
|
-
if (!wsx.ok) return NextResponse.json({ error: wsx.code }, { status: wsx.status });
|
|
47
|
-
const { rootDir } = wsx;
|
|
48
|
-
|
|
49
|
-
const segments = (await params).path;
|
|
50
|
-
const rel = segments.join("/");
|
|
51
|
-
|
|
52
|
-
// Path traversal guard
|
|
53
|
-
const resolved = safeWorkspacePath(rootDir, rel);
|
|
54
|
-
if (!resolved) {
|
|
55
|
-
return NextResponse.json({ error: "Invalid path" }, { status: 400 });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
const info = await stat(resolved);
|
|
60
|
-
if (info.isDirectory())
|
|
61
|
-
return NextResponse.json({ error: "Not a file" }, { status: 400 });
|
|
62
|
-
|
|
63
|
-
const ext = path.extname(resolved).slice(1).toLowerCase();
|
|
64
|
-
const contentType = MIME_MAP[ext] ?? "application/octet-stream";
|
|
65
|
-
const buffer = await readFile(resolved);
|
|
66
|
-
return new Response(buffer, {
|
|
67
|
-
headers: {
|
|
68
|
-
"Content-Type": contentType,
|
|
69
|
-
"Cache-Control": "private, max-age=60",
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
} catch {
|
|
73
|
-
return NextResponse.json({ error: "File not found" }, { status: 404 });
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GET /api/owner/init
|
|
3
|
-
*
|
|
4
|
-
* Legacy bootstrap endpoint. Now redirects to /signin (Better Auth).
|
|
5
|
-
* Kept for back-compat — any agent or UI calling this will be redirected.
|
|
6
|
-
*/
|
|
7
|
-
import { NextResponse } from "next/server";
|
|
8
|
-
|
|
9
|
-
export const runtime = "nodejs";
|
|
10
|
-
|
|
11
|
-
export function GET(req: Request): NextResponse {
|
|
12
|
-
const url = new URL("/signin", req.url);
|
|
13
|
-
return NextResponse.redirect(url, { status: 308 });
|
|
14
|
-
}
|
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { checkOrigin } from "@/lib/auth/csrf";
|
|
3
|
-
import { requireUser } from "@/lib/auth/server";
|
|
4
|
-
import { getWorkspace } from "@/lib/workspaces";
|
|
5
|
-
import { safeAbsPath } from "@/lib/proof/raw-fs";
|
|
6
|
-
import { checkAndConsume } from "@/lib/proof/rate-limit";
|
|
7
|
-
import {
|
|
8
|
-
getShareByToken,
|
|
9
|
-
verifyPassword,
|
|
10
|
-
revokeShare,
|
|
11
|
-
isExpired,
|
|
12
|
-
incrementViewCount,
|
|
13
|
-
} from "@/lib/shared-docs/db";
|
|
14
|
-
|
|
15
|
-
const MAX_DISPLAY_SIZE = 1 * 1024 * 1024; // 1MB
|
|
16
|
-
|
|
17
|
-
// ── Shared helper: read file content for a resolved share ────────────────────
|
|
18
|
-
|
|
19
|
-
async function resolveContent(
|
|
20
|
-
token: string,
|
|
21
|
-
): Promise<
|
|
22
|
-
| { ok: true; content: string; filename: string; viewCount: number }
|
|
23
|
-
| { ok: false; response: NextResponse }
|
|
24
|
-
> {
|
|
25
|
-
const share = getShareByToken(token);
|
|
26
|
-
if (!share) {
|
|
27
|
-
return {
|
|
28
|
-
ok: false,
|
|
29
|
-
response: NextResponse.json(
|
|
30
|
-
{ error: "not_found", message: "Share link not found" },
|
|
31
|
-
{ status: 404 },
|
|
32
|
-
),
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (share.isRevoked) {
|
|
37
|
-
return {
|
|
38
|
-
ok: false,
|
|
39
|
-
response: NextResponse.json(
|
|
40
|
-
{ error: "revoked", message: "Share link has been revoked" },
|
|
41
|
-
{ status: 410 },
|
|
42
|
-
),
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (isExpired(share)) {
|
|
47
|
-
return {
|
|
48
|
-
ok: false,
|
|
49
|
-
response: NextResponse.json(
|
|
50
|
-
{ error: "expired", message: "Share link has expired" },
|
|
51
|
-
{ status: 410 },
|
|
52
|
-
),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const ws = await getWorkspace(share.workspaceId);
|
|
57
|
-
if (!ws) {
|
|
58
|
-
return {
|
|
59
|
-
ok: false,
|
|
60
|
-
response: NextResponse.json(
|
|
61
|
-
{ error: "workspace_gone", message: "Workspace no longer exists" },
|
|
62
|
-
{ status: 410 },
|
|
63
|
-
),
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const absPath = await safeAbsPath(ws.rootDir, share.filePath);
|
|
68
|
-
if (!absPath) {
|
|
69
|
-
return {
|
|
70
|
-
ok: false,
|
|
71
|
-
response: NextResponse.json(
|
|
72
|
-
{ error: "path_invalid", message: "Invalid file path" },
|
|
73
|
-
{ status: 400 },
|
|
74
|
-
),
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const { readFile, stat } = await import("node:fs/promises");
|
|
79
|
-
try {
|
|
80
|
-
const info = await stat(absPath);
|
|
81
|
-
if (info.size > MAX_DISPLAY_SIZE) {
|
|
82
|
-
return {
|
|
83
|
-
ok: false,
|
|
84
|
-
response: NextResponse.json(
|
|
85
|
-
{ error: "too_large", message: "File too large to share (max 1MB)" },
|
|
86
|
-
{ status: 413 },
|
|
87
|
-
),
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
} catch {
|
|
91
|
-
return {
|
|
92
|
-
ok: false,
|
|
93
|
-
response: NextResponse.json(
|
|
94
|
-
{ error: "file_gone", message: "File no longer exists" },
|
|
95
|
-
{ status: 410 },
|
|
96
|
-
),
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
let content: string;
|
|
101
|
-
try {
|
|
102
|
-
const buffer = await readFile(absPath);
|
|
103
|
-
content = buffer.toString("utf-8");
|
|
104
|
-
} catch (err: unknown) {
|
|
105
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
106
|
-
console.error("[share] readFile(%s) %s", absPath, detail);
|
|
107
|
-
return {
|
|
108
|
-
ok: false,
|
|
109
|
-
response: NextResponse.json(
|
|
110
|
-
{ error: "read_error", message: "Failed to read file" },
|
|
111
|
-
{ status: 500 },
|
|
112
|
-
),
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
incrementViewCount(token);
|
|
117
|
-
const filename = share.filePath.split("/").pop() ?? share.filePath;
|
|
118
|
-
|
|
119
|
-
return { ok: true, content, filename, viewCount: share.viewCount + 1 };
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// ── GET: Resolve a share link (public) ───────────────────────────────────────
|
|
123
|
-
|
|
124
|
-
export async function GET(
|
|
125
|
-
request: Request,
|
|
126
|
-
{ params }: { params: Promise<{ token: string }> },
|
|
127
|
-
) {
|
|
128
|
-
const { token } = await params;
|
|
129
|
-
|
|
130
|
-
const rl = checkAndConsume(`share:${token}`, 1);
|
|
131
|
-
if (!rl.ok) {
|
|
132
|
-
return NextResponse.json(
|
|
133
|
-
{ error: "rate_limited", message: "Too many requests" },
|
|
134
|
-
{
|
|
135
|
-
status: 429,
|
|
136
|
-
headers: { "Retry-After": String(Math.ceil(rl.retryAfterMs / 1000)) },
|
|
137
|
-
},
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const share = getShareByToken(token);
|
|
142
|
-
if (!share) {
|
|
143
|
-
return NextResponse.json(
|
|
144
|
-
{ error: "not_found", message: "Share link not found" },
|
|
145
|
-
{ status: 404 },
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (share.isRevoked) {
|
|
150
|
-
return NextResponse.json(
|
|
151
|
-
{ error: "revoked", message: "Share link has been revoked" },
|
|
152
|
-
{ status: 410 },
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (isExpired(share)) {
|
|
157
|
-
return NextResponse.json(
|
|
158
|
-
{ error: "expired", message: "Share link has expired" },
|
|
159
|
-
{ status: 410 },
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Password-protected: tell client to POST to /unlock instead
|
|
164
|
-
if (share.passwordHash) {
|
|
165
|
-
return NextResponse.json(
|
|
166
|
-
{ protected: true, message: "This document is password-protected" },
|
|
167
|
-
{ status: 401 },
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const result = await resolveContent(token);
|
|
172
|
-
if (!result.ok) return result.response;
|
|
173
|
-
|
|
174
|
-
return NextResponse.json({
|
|
175
|
-
content: result.content,
|
|
176
|
-
filename: result.filename,
|
|
177
|
-
viewCount: result.viewCount,
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// ── POST: Unlock a password-protected share ───────────────────────────────────
|
|
182
|
-
|
|
183
|
-
export async function POST(
|
|
184
|
-
request: Request,
|
|
185
|
-
{ params }: { params: Promise<{ token: string }> },
|
|
186
|
-
) {
|
|
187
|
-
const { token } = await params;
|
|
188
|
-
|
|
189
|
-
const share = getShareByToken(token);
|
|
190
|
-
if (!share) {
|
|
191
|
-
return NextResponse.json({ error: "not_found" }, { status: 404 });
|
|
192
|
-
}
|
|
193
|
-
if (share.isRevoked) {
|
|
194
|
-
return NextResponse.json({ error: "revoked" }, { status: 410 });
|
|
195
|
-
}
|
|
196
|
-
if (isExpired(share)) {
|
|
197
|
-
return NextResponse.json({ error: "expired" }, { status: 410 });
|
|
198
|
-
}
|
|
199
|
-
if (!share.passwordHash) {
|
|
200
|
-
return NextResponse.json({ error: "not_protected" }, { status: 400 });
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Rate limit password attempts
|
|
204
|
-
const rl = checkAndConsume(`share-pwd:${token}`, 1);
|
|
205
|
-
if (!rl.ok) {
|
|
206
|
-
return NextResponse.json(
|
|
207
|
-
{ error: "rate_limited", message: "Too many attempts. Try again later." },
|
|
208
|
-
{
|
|
209
|
-
status: 429,
|
|
210
|
-
headers: { "Retry-After": String(Math.ceil(rl.retryAfterMs / 1000)) },
|
|
211
|
-
},
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const body: { password?: string } = await request.json();
|
|
216
|
-
if (!body.password || typeof body.password !== "string") {
|
|
217
|
-
return NextResponse.json({ error: "missing_password" }, { status: 400 });
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (!verifyPassword(body.password, share.passwordHash)) {
|
|
221
|
-
return NextResponse.json(
|
|
222
|
-
{ error: "wrong_password", message: "Incorrect password" },
|
|
223
|
-
{ status: 403 },
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const result = await resolveContent(token);
|
|
228
|
-
if (!result.ok) return result.response;
|
|
229
|
-
|
|
230
|
-
return NextResponse.json({
|
|
231
|
-
content: result.content,
|
|
232
|
-
filename: result.filename,
|
|
233
|
-
viewCount: result.viewCount,
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// ── DELETE: Revoke a share link (auth required) ───────────────────────────────
|
|
238
|
-
|
|
239
|
-
export async function DELETE(
|
|
240
|
-
request: Request,
|
|
241
|
-
{ params }: { params: Promise<{ token: string }> },
|
|
242
|
-
) {
|
|
243
|
-
const { token } = await params;
|
|
244
|
-
|
|
245
|
-
const csrf = checkOrigin(request);
|
|
246
|
-
if (csrf) return csrf;
|
|
247
|
-
|
|
248
|
-
const auth = await requireUser(request);
|
|
249
|
-
if (!auth.ok) {
|
|
250
|
-
return NextResponse.json({ error: "UNAUTHORIZED" }, { status: 401 });
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const share = getShareByToken(token);
|
|
254
|
-
if (!share) {
|
|
255
|
-
return NextResponse.json({ error: "not_found" }, { status: 404 });
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
if (share.createdBy !== auth.user.id) {
|
|
259
|
-
const { isAdmin } = await import("@/lib/auth/admin");
|
|
260
|
-
const admin = await isAdmin(auth.user.id, auth.user.email);
|
|
261
|
-
if (!admin) {
|
|
262
|
-
return NextResponse.json({ error: "FORBIDDEN" }, { status: 403 });
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
revokeShare(share.id);
|
|
267
|
-
|
|
268
|
-
return NextResponse.json({ ok: true });
|
|
269
|
-
}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import { checkOrigin } from "@/lib/auth/csrf";
|
|
3
|
-
import { requireUser } from "@/lib/auth/server";
|
|
4
|
-
import { resolveWorkspaceForUser } from "@/lib/workspace-context";
|
|
5
|
-
import { safeAbsPath } from "@/lib/proof/raw-fs";
|
|
6
|
-
import {
|
|
7
|
-
createShare,
|
|
8
|
-
listSharesForFile,
|
|
9
|
-
} from "@/lib/shared-docs/db";
|
|
10
|
-
|
|
11
|
-
// ── POST: Create a share link ─────────────────────────────────────────────────
|
|
12
|
-
|
|
13
|
-
export async function POST(request: Request) {
|
|
14
|
-
const csrf = checkOrigin(request);
|
|
15
|
-
if (csrf) return csrf;
|
|
16
|
-
|
|
17
|
-
// Must be signed in
|
|
18
|
-
const auth = await requireUser(request);
|
|
19
|
-
if (!auth.ok) {
|
|
20
|
-
return NextResponse.json({ error: "UNAUTHORIZED" }, { status: 401 });
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const ctx = await resolveWorkspaceForUser(request);
|
|
24
|
-
if (!ctx.ok) {
|
|
25
|
-
return NextResponse.json({ error: ctx.code }, { status: ctx.status });
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const body: {
|
|
29
|
-
path?: string;
|
|
30
|
-
password?: string;
|
|
31
|
-
expiresAt?: string;
|
|
32
|
-
} = await request.json();
|
|
33
|
-
|
|
34
|
-
const relPath = body.path;
|
|
35
|
-
if (!relPath || typeof relPath !== "string") {
|
|
36
|
-
return NextResponse.json({ error: "Missing path" }, { status: 400 });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Verify the file exists and belongs to this workspace
|
|
40
|
-
const absPath = await safeAbsPath(ctx.rootDir, relPath);
|
|
41
|
-
if (!absPath) {
|
|
42
|
-
return NextResponse.json({ error: "Invalid path" }, { status: 400 });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const { stat } = await import("node:fs/promises");
|
|
46
|
-
try {
|
|
47
|
-
await stat(absPath);
|
|
48
|
-
} catch {
|
|
49
|
-
return NextResponse.json({ error: "File not found" }, { status: 404 });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Validate optional params
|
|
53
|
-
if (body.password !== undefined && typeof body.password !== "string") {
|
|
54
|
-
return NextResponse.json({ error: "Invalid password" }, { status: 400 });
|
|
55
|
-
}
|
|
56
|
-
if (
|
|
57
|
-
body.expiresAt !== undefined &&
|
|
58
|
-
body.expiresAt !== null &&
|
|
59
|
-
typeof body.expiresAt !== "string"
|
|
60
|
-
) {
|
|
61
|
-
return NextResponse.json({ error: "Invalid expiresAt" }, { status: 400 });
|
|
62
|
-
}
|
|
63
|
-
// Reject invalid or already-expired dates
|
|
64
|
-
if (body.expiresAt) {
|
|
65
|
-
const d = new Date(body.expiresAt);
|
|
66
|
-
if (isNaN(d.getTime())) {
|
|
67
|
-
return NextResponse.json({ error: "Invalid date" }, { status: 400 });
|
|
68
|
-
}
|
|
69
|
-
if (d.getTime() < Date.now()) {
|
|
70
|
-
return NextResponse.json({ error: "Date is in the past" }, { status: 400 });
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const share = createShare({
|
|
75
|
-
workspaceId: ctx.ws.id,
|
|
76
|
-
filePath: relPath,
|
|
77
|
-
password: body.password && body.password.length > 0 ? body.password : undefined,
|
|
78
|
-
expiresAt: body.expiresAt || undefined,
|
|
79
|
-
createdBy: auth.user.id,
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
return NextResponse.json({
|
|
83
|
-
token: share.token,
|
|
84
|
-
url: `/s/${share.token}`,
|
|
85
|
-
hasPassword: !!share.passwordHash,
|
|
86
|
-
expiresAt: share.expiresAt,
|
|
87
|
-
createdAt: share.createdAt,
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// ── GET: List share links for a file ──────────────────────────────────────────
|
|
92
|
-
|
|
93
|
-
export async function GET(request: Request) {
|
|
94
|
-
const csrf = checkOrigin(request);
|
|
95
|
-
if (csrf) return csrf;
|
|
96
|
-
|
|
97
|
-
const auth = await requireUser(request);
|
|
98
|
-
if (!auth.ok) {
|
|
99
|
-
return NextResponse.json({ error: "UNAUTHORIZED" }, { status: 401 });
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const ctx = await resolveWorkspaceForUser(request);
|
|
103
|
-
if (!ctx.ok) {
|
|
104
|
-
return NextResponse.json({ error: ctx.code }, { status: ctx.status });
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const { searchParams } = new URL(request.url);
|
|
108
|
-
const relPath = searchParams.get("path");
|
|
109
|
-
if (!relPath) {
|
|
110
|
-
return NextResponse.json({ error: "Missing path" }, { status: 400 });
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const shares = listSharesForFile(ctx.ws.id, relPath);
|
|
114
|
-
|
|
115
|
-
return NextResponse.json({
|
|
116
|
-
shares: shares.map((s) => ({
|
|
117
|
-
id: s.id,
|
|
118
|
-
token: s.token,
|
|
119
|
-
url: `/s/${s.token}`,
|
|
120
|
-
hasPassword: !!s.passwordHash,
|
|
121
|
-
expiresAt: s.expiresAt,
|
|
122
|
-
createdAt: s.createdAt,
|
|
123
|
-
viewCount: s.viewCount,
|
|
124
|
-
isExpired: s.expiresAt ? new Date(s.expiresAt) < new Date() : false,
|
|
125
|
-
})),
|
|
126
|
-
});
|
|
127
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Admin management API.
|
|
3
|
-
*
|
|
4
|
-
* GET /api/system/admins — any signed-in user (returns isAdmin flag, admin list,
|
|
5
|
-
* and user roster if caller is admin).
|
|
6
|
-
* POST { userId } — admin-only: promote user to admin.
|
|
7
|
-
* DELETE { userId } — admin-only: demote user; refuses to remove last admin.
|
|
8
|
-
*
|
|
9
|
-
* Bootstrap: first authenticated request triggers ensureBootstrapAdmin so the
|
|
10
|
-
* first user to sign in becomes admin when no WIKI_ADMIN_EMAILS is set.
|
|
11
|
-
*/
|
|
12
|
-
import { NextResponse } from "next/server";
|
|
13
|
-
import Database from "better-sqlite3";
|
|
14
|
-
import path from "node:path";
|
|
15
|
-
import os from "node:os";
|
|
16
|
-
import { mkdirSync } from "node:fs";
|
|
17
|
-
import { checkOrigin } from "@/lib/auth/csrf";
|
|
18
|
-
import { requireUser } from "@/lib/auth/server";
|
|
19
|
-
import {
|
|
20
|
-
isAdmin,
|
|
21
|
-
listAdmins,
|
|
22
|
-
addAdmin,
|
|
23
|
-
removeAdmin,
|
|
24
|
-
requireAdmin,
|
|
25
|
-
ensureBootstrapAdmin,
|
|
26
|
-
} from "@/lib/auth/admin";
|
|
27
|
-
|
|
28
|
-
export const runtime = "nodejs";
|
|
29
|
-
|
|
30
|
-
interface UserRow {
|
|
31
|
-
id: string;
|
|
32
|
-
email: string;
|
|
33
|
-
name: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function queryAllUsers(): UserRow[] {
|
|
37
|
-
try {
|
|
38
|
-
const dir = path.join(process.env.HOME ?? os.homedir(), ".wiki-viewer");
|
|
39
|
-
mkdirSync(dir, { recursive: true });
|
|
40
|
-
const db = new Database(path.join(dir, "auth.db"));
|
|
41
|
-
db.pragma("journal_mode = WAL");
|
|
42
|
-
return db.prepare("SELECT id, email, name FROM user").all() as UserRow[];
|
|
43
|
-
} catch {
|
|
44
|
-
return [];
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export async function GET(request: Request) {
|
|
49
|
-
const auth = await requireUser(request);
|
|
50
|
-
if (!auth.ok) return NextResponse.json({ error: "UNAUTHORIZED" }, { status: 401 });
|
|
51
|
-
|
|
52
|
-
// Bootstrap: first authenticated user becomes admin if no admin set yet.
|
|
53
|
-
await ensureBootstrapAdmin(auth.user.id);
|
|
54
|
-
|
|
55
|
-
const admin = await isAdmin(auth.user.id, auth.user.email);
|
|
56
|
-
const admins = await listAdmins();
|
|
57
|
-
const users = admin ? queryAllUsers() : [];
|
|
58
|
-
|
|
59
|
-
return NextResponse.json({ admins, isAdmin: admin, users });
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export async function POST(request: Request) {
|
|
63
|
-
const csrf = checkOrigin(request);
|
|
64
|
-
if (csrf) return csrf;
|
|
65
|
-
|
|
66
|
-
const authResult = await requireAdmin(request);
|
|
67
|
-
if (!authResult.ok)
|
|
68
|
-
return NextResponse.json({ error: authResult.code }, { status: authResult.status });
|
|
69
|
-
|
|
70
|
-
const body: { userId?: string } = await request.json();
|
|
71
|
-
if (!body.userId?.trim())
|
|
72
|
-
return NextResponse.json({ error: "Missing userId" }, { status: 400 });
|
|
73
|
-
|
|
74
|
-
await addAdmin(body.userId.trim());
|
|
75
|
-
const admins = await listAdmins();
|
|
76
|
-
return NextResponse.json({ ok: true, admins });
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export async function DELETE(request: Request) {
|
|
80
|
-
const csrf = checkOrigin(request);
|
|
81
|
-
if (csrf) return csrf;
|
|
82
|
-
|
|
83
|
-
const authResult = await requireAdmin(request);
|
|
84
|
-
if (!authResult.ok)
|
|
85
|
-
return NextResponse.json({ error: authResult.code }, { status: authResult.status });
|
|
86
|
-
|
|
87
|
-
const body: { userId?: string } = await request.json();
|
|
88
|
-
if (!body.userId?.trim())
|
|
89
|
-
return NextResponse.json({ error: "Missing userId" }, { status: 400 });
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
await removeAdmin(body.userId.trim());
|
|
93
|
-
} catch (e) {
|
|
94
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
95
|
-
if (msg.startsWith("LAST_ADMIN")) {
|
|
96
|
-
return NextResponse.json({ error: "LAST_ADMIN", message: msg }, { status: 409 });
|
|
97
|
-
}
|
|
98
|
-
throw e;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const admins = await listAdmins();
|
|
102
|
-
return NextResponse.json({ ok: true, admins });
|
|
103
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GET /api/system/auth-config — public, unauthenticated.
|
|
3
|
-
*
|
|
4
|
-
* The sign-in page renders before any session exists, so it needs a public way
|
|
5
|
-
* to learn which auth methods are available: whether email/password is enabled
|
|
6
|
-
* and whether a social provider (Google) is configured. No secrets are exposed,
|
|
7
|
-
* only booleans describing which UI to show.
|
|
8
|
-
*/
|
|
9
|
-
import { NextResponse } from "next/server";
|
|
10
|
-
import { passwordAuthEnabled } from "@/lib/auth/server";
|
|
11
|
-
|
|
12
|
-
export const runtime = "nodejs";
|
|
13
|
-
|
|
14
|
-
export function GET() {
|
|
15
|
-
const google = Boolean(
|
|
16
|
-
process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET,
|
|
17
|
-
);
|
|
18
|
-
return NextResponse.json({
|
|
19
|
-
passwordAuth: passwordAuthEnabled,
|
|
20
|
-
google,
|
|
21
|
-
});
|
|
22
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GET /api/system/auth-settings — read the effective signup allowlist.
|
|
3
|
-
* PUT /api/system/auth-settings — update the allowlist in config.json.
|
|
4
|
-
*
|
|
5
|
-
* Single-tenant local app: any authenticated user may read/edit. The effective
|
|
6
|
-
* list resolves config first, env as fallback (see getAllowlist). `source`
|
|
7
|
-
* tells the UI where the active values came from so it can warn that editing
|
|
8
|
-
* here overrides the env vars.
|
|
9
|
-
*/
|
|
10
|
-
import { NextResponse } from "next/server";
|
|
11
|
-
import { checkOrigin } from "@/lib/auth/csrf";
|
|
12
|
-
import { requireUser } from "@/lib/auth/server";
|
|
13
|
-
import { getAllowlist } from "@/lib/auth/allowlist";
|
|
14
|
-
import { readConfig, writeConfig } from "@/lib/config";
|
|
15
|
-
|
|
16
|
-
export const runtime = "nodejs";
|
|
17
|
-
|
|
18
|
-
export async function GET(request: Request) {
|
|
19
|
-
const auth = await requireUser(request);
|
|
20
|
-
if (!auth.ok)
|
|
21
|
-
return NextResponse.json({ error: "UNAUTHORIZED" }, { status: 401 });
|
|
22
|
-
|
|
23
|
-
const config = await readConfig();
|
|
24
|
-
const effective = await getAllowlist();
|
|
25
|
-
const usingConfig =
|
|
26
|
-
(config.allowedEmails?.length ?? 0) > 0 ||
|
|
27
|
-
(config.allowedDomains?.length ?? 0) > 0;
|
|
28
|
-
|
|
29
|
-
return NextResponse.json({
|
|
30
|
-
allowedEmails: effective.emails,
|
|
31
|
-
allowedDomains: effective.domains,
|
|
32
|
-
source: usingConfig ? "config" : "env",
|
|
33
|
-
envFallbackActive: !usingConfig,
|
|
34
|
-
rateLimit: Number(process.env.AGENT_RATE_LIMIT) || 60,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function normalizeList(value: unknown): string[] {
|
|
39
|
-
if (!Array.isArray(value)) return [];
|
|
40
|
-
return value
|
|
41
|
-
.filter((v): v is string => typeof v === "string")
|
|
42
|
-
.map((s) => s.trim().toLowerCase())
|
|
43
|
-
.filter(Boolean);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export async function PUT(request: Request) {
|
|
47
|
-
const csrf = checkOrigin(request);
|
|
48
|
-
if (csrf) return csrf;
|
|
49
|
-
const auth = await requireUser(request);
|
|
50
|
-
if (!auth.ok)
|
|
51
|
-
return NextResponse.json({ error: "UNAUTHORIZED" }, { status: 401 });
|
|
52
|
-
|
|
53
|
-
let body: { allowedEmails?: unknown; allowedDomains?: unknown };
|
|
54
|
-
try {
|
|
55
|
-
body = await request.json();
|
|
56
|
-
} catch {
|
|
57
|
-
return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const allowedEmails = normalizeList(body.allowedEmails);
|
|
61
|
-
const allowedDomains = normalizeList(body.allowedDomains);
|
|
62
|
-
|
|
63
|
-
// Reject obviously malformed email entries (must contain a single @ with text
|
|
64
|
-
// on both sides). Domains are looser but must not contain @ or spaces.
|
|
65
|
-
const badEmail = allowedEmails.find((e) => !/^[^@\s]+@[^@\s]+$/.test(e));
|
|
66
|
-
if (badEmail)
|
|
67
|
-
return NextResponse.json(
|
|
68
|
-
{ error: `Invalid email entry: ${badEmail}` },
|
|
69
|
-
{ status: 400 },
|
|
70
|
-
);
|
|
71
|
-
const badDomain = allowedDomains.find((d) => /[@\s]/.test(d));
|
|
72
|
-
if (badDomain)
|
|
73
|
-
return NextResponse.json(
|
|
74
|
-
{ error: `Invalid domain entry: ${badDomain}` },
|
|
75
|
-
{ status: 400 },
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
await writeConfig({ allowedEmails, allowedDomains });
|
|
79
|
-
|
|
80
|
-
return NextResponse.json({
|
|
81
|
-
ok: true,
|
|
82
|
-
allowedEmails,
|
|
83
|
-
allowedDomains,
|
|
84
|
-
source: allowedEmails.length || allowedDomains.length ? "config" : "env",
|
|
85
|
-
});
|
|
86
|
-
}
|