Skip to content

fix(uploader): set the manifest fallback so SPA deep links resolve - #18

Merged
vilenarios merged 4 commits into
mainfrom
fix/manifest-fallback
Aug 28, 2026
Merged

fix(uploader): set the manifest fallback so SPA deep links resolve#18
vilenarios merged 4 commits into
mainfrom
fix/manifest-fallback

Conversation

@vilenarios

Copy link
Copy Markdown
Contributor

Problem

An arweave/paths manifest serves only the paths it lists, so any single-page app deployed with this tool 404s every route that isn't a real file — the root loads, /settings doesn't.

uploadFolder built the manifest with index but never fallback:

const manifest = {
  manifest: 'arweave/paths',
  version: '0.2.0',
  ...(indexPath && { index: { path: indexPath } }),
  paths: manifestPaths,
}

The README has advertised "404 Fallback Detection: Automatically detects and sets 404.html as fallback", but the string fallback appeared nowhere outside that README — documented, never implemented. Found while deploying console.ar.io: every deep link 404'd in production.

Change

  • 404.html becomes the manifest fallback when the build emits one
  • --fallback-file <path> overrides it, so an SPA that only builds index.html can point at that instead of inventing a 404 file
  • A named file missing from the folder throws rather than silently skipping — skipping ships exactly the broken manifest this prevents
  • README now matches the code

Shape matters: fallback takes an { id } where index takes a { path }. The v0.2.0 spec differs, and a { path } here is silently ignored by gateways.

Verification

  • 6 new unit tests (tests/unit/uploader-manifest-fallback.test.ts) covering: 404.html detected; id-not-path shape; no fallback when absent (unchanged behaviour); explicit override; SPA opt-in via index.html; missing file errors
  • Full suite: 62 tests, 9 files, all passing
  • tsc --noEmit clean, pnpm build clean
  • Verified on the built CLI: --fallback-file appears in deploy --help and upload --help

vilenarios and others added 4 commits August 28, 2026 15:11
An arweave/paths manifest serves only the paths it lists, so a single-page
app deployed with this tool 404s every route that is not a real file — the
root loads and /settings does not. The manifest was built with `index` but
never `fallback`, which is the field gateways use for an unlisted path.

The README has advertised "404 Fallback Detection: Automatically detects and
sets 404.html as fallback" since before this change, but the string
`fallback` appeared nowhere outside that README: documented, never
implemented. This makes the claim true.

`404.html` is used when the build emits one, matching the convention static
hosts already follow. `--fallback-file <path>` overrides it, so an SPA whose
build only produces index.html can point at that rather than inventing a 404
file. A named file that is not in the folder is an error rather than a silent
skip — skipping would ship exactly the broken manifest this prevents.

Note the shape: `fallback` takes an `{ id }` where `index` takes a `{ path }`.
The v0.2.0 spec differs between the two, and a `{ path }` here is silently
ignored by gateways.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The check ran after every file had been uploaded and paid for, so a
mistyped --fallback-file billed the whole deploy and then threw.
path.relative yields backslashes on Windows and those strings become
arweave/paths keys verbatim, so a deploy from Windows 404s every nested
asset and never matches the dir/index.html directory-index rule.
@vilenarios
vilenarios merged commit 560a1fd into main Aug 28, 2026
7 checks passed
@vilenarios
vilenarios deleted the fix/manifest-fallback branch August 28, 2026 23:08
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.

1 participant