Skip to content

pwa(capture): make WorldScript an OS share target and offline research/idea inbox #484

Description

@qnbs

Parent

Part of #478 — PWA first-class excellence/hardening.

Product opportunity

WorldScript's manifest already declares a Web Share Target, but a manifest declaration alone is not a polished writing workflow. A PWA can become a lightweight system-level capture destination on supported mobile/desktop environments: share a URL, selected text, research snippet or compatible file into WorldScript and continue writing later — including offline.

For a writing application this can be a meaningful PWA differentiator because the browser/OS share sheet is available across many other apps without requiring a native WorldScript integration for each source.

Core concept: Capture Inbox

Incoming shares should never be injected directly into the current manuscript. Route them into an explicit local inbox:

OS/browser share sheet
        ↓
Web Share Target
        ↓
strict parse + normalize
        ↓
local Capture Inbox
        ↓
user chooses destination
  note / research / character / scene / codex / discard

This separates capture from commit to project authority.

Input classes

Start with the manifest's current GET parameters:

  • title;
  • text;
  • URL.

Evaluate POST/multipart file sharing only after threat/size handling is designed. Candidate later types:

  • plain text/Markdown;
  • images;
  • PDFs or documents as untrusted attachments for later import/extraction;
  • WorldScript project/export packages.

Do not broaden accepted MIME types without a real workflow and parser.

Offline-first behavior

A key differentiator is capture when the user has no network.

If the installed PWA/app shell and local storage are available:

  • accept and persist the share locally;
  • show “Captured — organize later”;
  • no cloud AI call is required;
  • optional enrichment/summarization waits until a selected local/cloud backend is available and user requests it.

Never lose an accepted share merely because navigation or network fails immediately afterward.

Capture record

Persist a bounded, versioned record containing only what the user shared plus necessary metadata:

id
createdAt
sourceKind
sharedTitle?
sharedText?
sharedUrl?
attachmentRefs?
status = inbox / assigned / discarded
assignedProjectId?

Do not automatically fetch the shared URL in the background. That leaks browsing intent and introduces security/privacy complexity.

Organize workflow

From the inbox allow:

  • append as research note;
  • create project note;
  • attach to scene/character/location/world entry;
  • create a new idea/project seed;
  • copy selected content to manuscript at user-chosen location;
  • optionally run local AI classification/summarization;
  • discard.

All destructive/transformative actions should be explicit and undoable where practical.

Outbound Web Share

Complement inbound capture with navigator.share() where supported:

  • share a selected synopsis/logline/excerpt;
  • share an export link/file only after explicit user action;
  • never share manuscript content by default;
  • fall back to copy/download when unsupported.

Protocol/deep-link relationship

The manifest also declares web+worldscript. Unify external entry points under one validated routing layer:

share target
protocol handler
shortcuts
launch handler
file handler (#481)

Every external payload is untrusted. Parse into a typed ExternalLaunchIntent before any navigation/state mutation.

Security / abuse resistance

  • bound query/body lengths;
  • reject malformed/oversized payloads;
  • sanitize display text but preserve user data safely;
  • do not execute shared HTML/scripts;
  • do not auto-fetch URLs;
  • prevent javascript/data/file scheme abuse;
  • validate protocol-handler routes against an allowlist;
  • never allow external launch payloads to trigger AI provider calls, file writes, plugin installs, destructive actions or project replacement without user confirmation;
  • no sensitive payload telemetry.

Privacy

Capture stays local unless the user explicitly chooses a cloud-dependent action. UI must make this clear.

If local AI is used for classification, identify the local backend. If cloud AI is selected, request/reflect normal provider consent/routing semantics rather than treating capture as exempt.

Mobile UX

Optimize for a 5-second capture flow:

  • app launches quickly;
  • large editor need not fully initialize before durable capture if architecture permits;
  • immediate acknowledgement;
  • optional destination quick-pick;
  • defer expensive indexing/AI.

This is a place where PWA startup/code-splitting can materially exceed a heavyweight desktop workflow.

Tests

  • share title/text/url individually and combined;
  • cold installed-PWA launch from share;
  • warm existing-window share;
  • offline share;
  • malformed/oversized share;
  • dangerous URL schemes;
  • multiple rapid shares;
  • app update/version skew with pending inbox;
  • inbox survives relaunch;
  • assignment to project is transactional;
  • unsupported share-target browser fallback;
  • outbound share fallback.

Acceptance criteria

  • Current manifest share target is backed by a real tested Capture Inbox workflow.
  • Accepted shares survive offline/relaunch.
  • Incoming content is never silently inserted into a manuscript.
  • External launch intents share one typed validation boundary.
  • URLs are not auto-fetched merely because they were shared.
  • No external payload can trigger destructive/privileged actions without confirmation.
  • Capture path is fast and does not require AI/editor initialization.
  • Local/cloud enrichment remains explicit and truthful.
  • Mobile installed-PWA and fallback browser behavior are tested.

Non-goals

  • web scraping shared URLs by default;
  • silently feeding captured content to AI;
  • replacing project import validation;
  • accepting every possible MIME type;
  • turning the share target into an unauthenticated command interface.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions