Skip to content

Note sharing: publish notes to zennotes.org#62

Open
adibhanna wants to merge 1 commit into
mainfrom
feat/note-sharing
Open

Note sharing: publish notes to zennotes.org#62
adibhanna wants to merge 1 commit into
mainfrom
feat/note-sharing

Conversation

@adibhanna

Copy link
Copy Markdown
Contributor

Summary

Share a note from the app and get a public URL anyone can read. Pairs with ZenNotes/website PR (server side: Sanctum auth, shares API, public pages).

  • Vim-first: :share publishes (or updates an existing share), :unshare takes it down, :sharelink copies the URL — plus command palette entries, note context-menu items, and a status-bar SHARED chip whose popover shows live view count / last publish and carries copy / open / update / stop-sharing actions
  • Account connect: browser handoff via the existing zennotes:// deep link with a state nonce; one-time code paste fallback in Settings → Sharing; token in the OS keychain (existing secret-store); server URL overridable for self-hosters
  • Share state in frontmatter: share_id/share_url written with surgical byte-preserving edits (no gray-matter reserialization) so shares survive rename/move/vault sync
  • TikZ: pre-rendered to SVG in the main process at publish time, keyed sha1(raw fence body) — contract pinned by tikz-hash.test.ts
  • New apps/share-viewer workspace: renders public pages with the real app-core Preview pipeline behind a window.zen shim (TikZ substituted by hash + DOMPurify-sanitized, assets resolved via the payload map, wikilinks/tags/checkboxes neutralized, light/dark by OS preference). npm run sync -w @zennotes/share-viewer copies the bundle into the website repo
  • Resilience: PUT-404 → fresh create when a share was revoked from the web dashboard; missing assets don't sink a publish

Test plan

  • 58 new vitest tests: frontmatter byte-preservation (CRLF/BOM), payload extraction (tikz fences, image/embed refs, svg filtering), share client (FormData shape, ref ordering, PUT-vs-POST, error mapping), connect state machine (nonce validation, single-use), deep-link auth parsing, tikz hash contract
  • npm run typecheck + npm run test:run green across the monorepo
  • Manual E2E against zennotes.test: connect via browser + manual code, publish/update/unshare round-trips, public page fidelity (KaTeX, mermaid, TikZ, images), PUT-404 fallback

Publish the active note to the ZenNotes website and get a public URL
anyone can read. Account-based via a browser connect handoff: the site
mints a one-time code, hands it back through the existing zennotes://
deep link (manual paste fallback in Settings), and the app exchanges it
for an API token stored in the OS keychain.

- :share publishes or updates, :unshare takes down, :sharelink copies
  the public URL; command-palette + note context-menu equivalents
- share_id/share_url live in the note's YAML frontmatter via surgical
  byte-preserving edits, so shares survive rename/move/vault sync
- TikZ pre-rendered to SVG in the main process (browsers can't run
  node-tikzjax); hash contract sha1(raw fence body) shared with viewer
- assets upload as ordered multipart parts zipped with payload
  asset_refs; SVG assets excluded (script-bearing when served raw)
- new apps/share-viewer workspace: renders shared pages with the real
  app-core Preview pipeline behind a window.zen shim — pixel parity,
  lazy mermaid/jsxgraph/function-plot chunks; scripts/sync-viewer.mjs
  copies the bundle into the website repo
- status-bar SHARED chip opens a popover with live view count, copy
  link, open in browser, update, and stop sharing
- PUT-404 falls back to a fresh create when a share was revoked from
  the web dashboard
async function saveAccountFile(deps: ShareAccountDeps, next: ShareAccountFile): Promise<void> {
cachedAccount = next
await fs.mkdir(path.dirname(accountFilePath(deps)), { recursive: true })
await fs.writeFile(accountFilePath(deps), JSON.stringify(next, null, 2), 'utf8')
private async send(path: string, init: RequestInit): Promise<Response> {
let response: Response
try {
response = await fetch(`${this.baseUrl}${path}`, init)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants