Skip to content

Feat/snippet usage instructions - #224

Open
JemimahEkong wants to merge 2 commits into
SudiptaPaul-31:mainfrom
JemimahEkong:feat/snippet-usage-instructions
Open

JemimahEkong wants to merge 2 commits into
SudiptaPaul-31:mainfrom
JemimahEkong:feat/snippet-usage-instructions

Conversation

@JemimahEkong

Copy link
Copy Markdown
Contributor

Summary

Adds a Usage Instructions panel to the snippet details view. It gives authors a structured place to document how a snippet works and how to use it.

Closes #214

What's included

Sections: Overview, Prerequisites, Setup Instructions, an Input Example and an Output Example (each a separate code block with its own language label), and Notes.

Markdown: headings, paragraphs, ordered and unordered lists, fenced code blocks, inline code, bold and italic text, and links.

Where it appears:

  • The snippet details modal, above the source code.
  • The snippet edit form, for existing snippets. New snippets show a hint to add instructions after saving.

Editing:

  • Who can edit: only the owner, or a collaborator who has edit permission (canEdit).
  • Editor: Write and Preview tabs; Save, Cancel and Delete (with a confirmation step).
  • States: empty, loading, validation (per field), error with Retry, and "Saved {time}".

API

/api/snippets/[id]/usage

Method Purpose Responses
GET Can the caller edit? {canEdit} 200, 404
PUT Create or replace the instructions 200, 400 {error, fields}, 401, 403, 404, 500
DELETE Remove the instructions 200, 401, 403, 404, 500

Reads need no new endpoint. usage_instructions is a column, so GET /api/snippets/[id] already returns it under the existing visibility rules.

Storage

  • Migration: scripts/migrations/005_add_snippet_usage_instructions.sql adds the nullable usage_instructions JSONB column.
  • updated_at: saving does not change it. That way SnippetForm's If-Unmodified-Since conflict check doesn't fire on a later code edit.
  • Malformed rows: they render as "no instructions" and do not crash the panel.

Security

  • Authentication: writes require a verified JWT and a live session (verifyAuthentication).
  • No header-based auth: the unauthenticated x-wallet-address header is not accepted. A test checks that a spoofed header naming the owner gets a 401.
  • Validation: the server and the editor use the same zod schema. It rejects unknown keys, enforces 5,000-character limits, rejects control characters, and limits example languages to [A-Za-z0-9+#._-].
  • Rendering:
    • lib/safe-markdown.tsx builds React elements only and never uses dangerouslySetInnerHTML.
    • Raw HTML such as <script> or <img onerror> is shown as text.
    • Links are limited to absolute http(s) and mailto URLs, with rel="noopener noreferrer nofollow ugc". javascript:, data: and relative links are shown as plain text.
    • Code is only displayed, never executed.

Accessibility and responsiveness

  • Structure: the panel is a labelled section region with an h3. Author headings are offset to h4 and below, so the page outline stays correct. Each section has an aria-label.
  • Editor controls: the tabs use tablist/tab roles. Every field has a label. Errors are linked through aria-invalid and aria-describedby. Loading uses role="status" and errors use role="alert".
  • Small screens: code blocks scroll horizontally, and the examples stack into one column. The modal width and padding are adjusted.

Tests

97 new tests, all passing:

File Tests Covers
lib/usage-instructions.test.ts 20 Validation, normalisation, persistence round trip, defensive parsing
lib/safe-markdown.test.tsx 26 Rendering, and XSS payloads: no on* attributes, attribute whitelist, unsafe links
app/api/snippets/[id]/usage/route.test.ts 23 Create, edit, delete, owner vs collaborator vs stranger, spoofed header, validation, 404, 500
components/__tests__/UsageInstructionsPanel.test.tsx 28 Empty, create, edit, delete, preview, validation, 401/403/network errors, loading and retry, a11y roles and labels

Mutation checks:

  • Re-enabling x-wallet-address trust makes the spoofed-header test fail.
  • Allowing javascript: links makes 3 renderer tests fail.

Also fixed (separate commit)

fix(ui): restore Button component corrupted in #189. Commit 12b814f left components/ui/button.tsx unparseable, so every suite that imports Button failed to load. This restores the last working version. As a side effect, ForkSnippetModal tests pass again.

Results compared with main

Run locally:

Check main This branch
pnpm lint 57 problems (8 errors) 57 problems (8 errors), unchanged; new files are clean
tsc --noEmit 57 errors 50 errors; none in touched files
Jest suites 12 failed 11 failed
Jest tests 30 failed / 528 31 failed, 599 passed / 630

The one "new" failure is WalletConnect signAction › should successfully prompt freighter… in validiation/frontend-signature.test.tsx. Before this branch, that suite could not load because of the broken button.tsx, so the failure was hidden rather than introduced. It may also be affected by the local wallet-kit stub (see the notes below).

JemimahEkong and others added 2 commits October 19, 2026 20:48
Commit 12b814f left components/ui/button.tsx unparseable (unterminated
'button string, @lib/utils alias, variants not nested under `variant`,
typos such as srink-0 / ring-ing / 9over / has-;[svg]). Every test suite
that imports Button failed to load. Restore the last working version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvL6Yz2Zfg7spM1F9DXXtz
Adds a "Usage Instructions" panel to the snippet details view with
Overview, Prerequisites, Setup, Input/Output examples and Notes.

- usage_instructions JSONB column (migration 005); saving does not bump
  updated_at so SnippetForm's conflict check is unaffected
- PUT/DELETE /api/snippets/[id]/usage: verified JWT + live session,
  owner or "edit" collaborator only; x-wallet-address is not trusted
- zod schema shared by client and server (size limits, strict keys,
  control-character and language checks, field-level errors)
- SafeMarkdown renderer: React elements only, no dangerouslySetInnerHTML,
  links limited to http(s)/mailto with rel=noopener noreferrer nofollow ugc;
  code is displayed, never executed
- Editor with Write/Preview tabs, labelled fields, aria-invalid errors,
  loading/empty/error/retry states; also available from the edit form
- Tests for model, renderer (XSS), route (auth/validation/persistence)
  and panel (create/edit/delete/empty/a11y/errors)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LvL6Yz2Zfg7spM1F9DXXtz
@vercel

vercel Bot commented Oct 19, 2026

Copy link
Copy Markdown

@JemimahEkong is attempting to deploy a commit to the Sudipta 's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Oct 19, 2026

Copy link
Copy Markdown

@JemimahEkong Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

This branch has not been deployed

No deployments
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.

Implement Snippet Usage Instructions Panel

1 participant