* feat(web): ingest GET /share?url=&text=&title= deep links
Native companions that cannot POST via Web Share Target can open the
same session picker by synthesizing the IndexedDB transfer client-side.
When id is present, the existing SW path still wins.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): preserve share deep-link whitespace; scrub content beside id
Keep GET content strings verbatim when non-empty (match POST form-data).
When id is present with leftover url/text/title, replace to ?id= only so
payload does not linger in the address bar. Query-param contract stays —
fragments would break shipped native companions.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): ingest /share deep links via URL fragment, not query
Shared url/text/title must not appear on the HTTP request line — hub
Hono logger (and any access log) records path+query. Native companions
open /share#url=&text=&title=; the client reads the fragment, scrubs it,
and continues with the existing ?id= picker path. Query validateSearch
keeps only id/error (Web Share Target redirect).
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): keep /share hash ingest across StrictMode remount
Capture the fragment in useState and reuse a single putShareTransfer
promise so the first effect's scrub + cleanup cancel does not lose the
deep-link under React.StrictMode.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(web): fetch companion fileUrl into /share transfer files
Native shares cannot put binaries in the hash fragment. Companions host a
one-shot CORS URL and pass fileUrl/fileName/fileType; the share page fetches
bytes into the same IndexedDB files[] as Web Share Target POST.
* fix(web): cap share fileUrl fetch at the composer upload ceiling
Stream fileUrl downloads with Content-Length and body size checks matching
MAX_UPLOAD_BYTES so a crafted deep link cannot buffer unbounded bytes into
IndexedDB. Align native deep-link docs on the fileUrl hand-off vs POST.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): cast streamed fileUrl chunks to BlobPart for tsc
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(web): in-app PWA update prompt when new service worker is available (closes#938)
User-controlled reload with a persistent banner, visibility-triggered SW
checks, and an expandable rationale. Switches registerType to prompt.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): align vite.config with soup layers for clean driver merge
Keeps registerType prompt while matching garden IWER stubs and PWA
share_target shape expected by feat/pwa-share-target in the manifest.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Revert "fix(web): align vite.config with soup layers for clean driver merge"
This reverts commit 6f0915b0884d029a2413d8819a4dfe81d7c4e595.
* fix(web): make PWA reload apply waiting service worker updates
Handle SKIP_WAITING in injectManifest sw.ts and reload via controllerchange
with a timed fallback when vite-plugin-pwa prompt mode does not navigate.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): satisfy setTimeout mock typing in PWA reload tests
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): register PWA service worker before auth gates
Mount PwaUpdateProvider at app root and show the update banner on login
and error screens so registerSW runs for logged-out users too.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): offset PWA update banner below top status banners
Reserve top-12 when syncing or reconnecting so the reload prompt stays
visible above SyncingBanner and ReconnectingBanner.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): offset PWA update banner below voice error banner
Use PwaUpdateBannerWithStatusOffset inside VoiceProvider so voice errors
share the same top-12 reservation as sync and reconnect banners.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Use relative paths with .md extension for docs/guide/*.md files and
relative paths in README.md to support both GitHub rendering and
VitePress website (which has base: '/docs/'). Fixes#36
- Initialize VitePress documentation site with config, index, and guides
- Add guides for quick-start, installation, PWA, how-it-works, FAQ, and why HAPI
- Update .gitignore to exclude VitePress cache directory
- Update logo.svg with actual icon from web/public/icon.svg
- Simplify README.md with link to full installation guide
- Remove redundant WHY_NOT_HAPPY.md (content migrated to why-hapi guide)