Agent skill

Fastly Compute Well Known Spa Fallback

by divinevideo in divinevideo/divine-mobile

Fix .well-known files (apple-app-site-association, assetlinks.json) being served as HTML by the @fastly/compute-js-static-publish SPA fallback instead of JSON.

MPL-2.0Auto-check passedMobile

Install Fastly Compute Well Known Spa Fallback

skills CLI
$ npx skills add divinevideo/divine-mobile --skill fastly-compute-well-known-spa-fallback -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install divinevideo/divine-mobile fastly-compute-well-known-spa-fallback --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/divinevideo/divine-mobile.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/fastly-compute-well-known-spa-fallback .claude/skills/fastly-compute-well-known-spa-fallback && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
fastly-compute-well-known-spa-fallback
GitHub stars
266
Token cost
~2.5k tokens
SKILL.md length
471 words
Files
1
Skills in repo
103
Repo updated
First seen
Licence
MPL-2.0

At a glance

Fix .well-known files (apple-app-site-association, assetlinks.json) being served as HTML by the @fastly/compute-js-static-publish SPA fallback instead of JSON.

  • Works in 3 steps: Ensure Files Are Published → Intercept .well-known Paths Before SPA… → Apply the Same Fix in Subdomain Handlers
  • IOS Universal Links
  • SKILL.md covers Problem, Non-Obvious Root Causes, Solution and Verification, plus 4 more sections
  • Calls curl and npm

What it does

Fastly Compute Well Known Spa Fallback is an agent skill from divinevideo/divine-mobile. Fix .well-known files (apple-app-site-association, assetlinks.json) being served as HTML by the @fastly/compute-js-static-publish SPA fallback instead of JSON. Use when: (1) iOS Universal Links or Android App Links are broken because the verification files return text/html instead of application/json, (2) PublisherServer with spaFile config intercepts /.well-known/ paths and returns index.html (200, text/html) instead of 404 for missing files, (3) apple-app-site-association (no file extension) gets wrong content…

Its SKILL.md is about 2.5k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Mobile, covering Android development. It works with Android and iOS. The licence is MPL-2.0.

When your agent uses it

  • IOS Universal Links
  • Android App Links are broken because the verification files return text/html instead of application/json
  • PublisherServer with spaFile config intercepts /.well-known/ paths and returns index.html (200
  • Text/html) instead of 404 for missing files

Example prompts

  • “/fastly-compute-well-known-spa-fallback”

Workflow steps

3 steps, taken from the step headings in SKILL.md.

  1. Ensure Files Are Published
  2. Intercept .well-known Paths Before SPA Fallback
  3. Apply the Same Fix in Subdomain Handlers

What it can do on your machine

Read from SKILL.md and the folder at commit c3d6f7e. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • curl
    • npm

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • developer.apple.com
    • developer.android.com
    • npmjs.com
    • fastly.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Fastly Compute Well Known Spa Fallback loads about 2.5k tokens when it runs. Until then it costs about 163 tokens; SKILL.md has 471 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~163
When it runs · the whole SKILL.md, loaded when a task matches
~2.5k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from divinevideo/divine-mobile at commit c3d6f7e, republished under its MPL-2.0 licence (© divinevideo). 471 words, ~2,536 tokens.

Download SKILL.mdSave it as .claude/skills/fastly-compute-well-known-spa-fallback/SKILL.md (or your agent's skills folder).
name
fastly-compute-well-known-spa-fallback
description
Fix .well-known files (apple-app-site-association, assetlinks.json) being served as HTML by the @fastly/compute-js-static-publish SPA fallback instead of JSON. Use when: (1) iOS Universal Links or Android App Links are broken because the verification files return text/html instead of application/json, (2) PublisherServer with spaFile config intercepts /.well-known/ paths and returns index.html (200, text/html) instead of 404 for missing files, (3) apple-app-site-association (no file extension) gets wrong content type even when correctly stored in KV. Covers both apex domain and subdomain handler patterns.
author
Claude Code
version
1.0.0
date
2026-02-23

Fastly Compute: .well-known Files Intercepted by SPA Fallback

Problem

When using @fastly/compute-js-static-publish with SPA fallback configured (spaFile: "/index.html"), the PublisherServer.serveRequest() returns index.html with status 200 and Content-Type text/html for ANY path not found in the KV store. This includes /.well-known/apple-app-site-association and /.well-known/assetlinks.json, which iOS and Android require to be served as application/json.

Symptoms:

  • iOS Universal Links don't work (Apple's verification fetches .well-known/apple-app-site-association and gets HTML)
  • Android App Links don't work (Google's verifier fetches .well-known/assetlinks.json and gets HTML)
  • curl -I https://yourdomain.com/.well-known/apple-app-site-association shows Content-Type: text/html
  • The files ARE published to KV (confirmed by npm run fastly:publish) but still return HTML

Non-Obvious Root Causes

  1. SPA fallback returns 200, not 404: The publisher's SPA mode returns index.html with HTTP 200 for missing paths. You cannot distinguish "file served" from "fallback served" by status code alone - you must inspect the Content-Type.

  2. apple-app-site-association has no file extension: The static publisher infers MIME type from file extension. With no extension, it cannot detect application/json, so even when the file IS published to KV, it may get application/octet-stream or be served incorrectly.

  3. includeWellKnown: true in publish-content.config.js is necessary but not sufficient: It ensures the files are uploaded to KV, but doesn't prevent the SPA fallback from intercepting the requests, and doesn't fix the content-type for extension-less files.

  4. Both apex domain and subdomain handlers need the fix: If your Compute handler has separate code paths for subdomains vs apex, both paths must intercept .well-known/ requests before reaching the SPA fallback.

Solution

Step 1: Ensure Files Are Published

In publish-content.config.js, confirm includeWellKnown: true is set:

javascript
// publish-content.config.js
module.exports = {
  // ...
  includeWellKnown: true,   // Must be true to include /.well-known/ files
  // ...
};

Then publish static content:

bash
npm run fastly:publish
Show full SKILL.md (208 more words)Show less
Step 2: Intercept .well-known Paths Before SPA Fallback

In your Compute entry point (compute-js/src/index.js), add a .well-known handler BEFORE any call to publisherServer.serveRequest(request) that has SPA fallback enabled.

Critical guard: Check that the publisher response is NOT text/html - if it is, the SPA fallback fired (file not in KV), so return 404 instead of the HTML.

javascript
// In your main handleRequest function, BEFORE the final publisherServer.serveRequest() call:

// Handle .well-known requests (must come before SPA fallback)
if (url.pathname.startsWith('/.well-known/')) {
  // Handle NIP-05 or other dynamic .well-known endpoints first
  if (url.pathname === '/.well-known/nostr.json') {
    return handleNip05(url);  // Your custom handler
  }

  // For all other .well-known files: fetch from static publisher
  const wkResponse = await publisherServer.serveRequest(request);

  // CRITICAL: Guard against SPA fallback. The publisher returns index.html (text/html)
  // for files not in KV. We must detect this and return 404 instead.
  if (
    wkResponse != null &&
    wkResponse.status === 200 &&
    !wkResponse.headers.get('Content-Type')?.includes('text/html')
  ) {
    const headers = new Headers(wkResponse.headers);

    // Explicitly set correct content type.
    // apple-app-site-association has no extension, so the publisher may not detect JSON.
    const isJsonFile =
      url.pathname.endsWith('.json') ||
      url.pathname.endsWith('/apple-app-site-association') ||
      url.pathname === '/.well-known/apple-app-site-association';

    headers.set(
      'Content-Type',
      isJsonFile ? 'application/json' : (headers.get('Content-Type') || 'application/octet-stream')
    );
    headers.set('Cache-Control', 'public, max-age=3600');
    headers.append('Vary', 'X-Original-Host');  // If using multi-service routing

    return new Response(wkResponse.body, { status: 200, headers });
  }

  // File not in KV (or publisher returned SPA fallback) - return proper 404
  return new Response('Not Found', { status: 404 });
}
Step 3: Apply the Same Fix in Subdomain Handlers

If you have separate handling for subdomain requests, add the same guard there too. Subdomain paths hit a different code branch before reaching the apex domain handler:

javascript
if (subdomain) {
  if (url.pathname.startsWith('/.well-known/')) {
    if (url.pathname === '/.well-known/nostr.json') {
      return handleSubdomainNip05(subdomain);
    }

    // Same pattern: intercept, guard against SPA fallback, force JSON content type
    const wkResponse = await publisherServer.serveRequest(request);
    if (
      wkResponse != null &&
      wkResponse.status === 200 &&
      !wkResponse.headers.get('Content-Type')?.includes('text/html')
    ) {
      const headers = new Headers(wkResponse.headers);
      const contentType =
        url.pathname.endsWith('.json') || url.pathname.endsWith('/apple-app-site-association')
          ? 'application/json'
          : headers.get('Content-Type') || 'application/octet-stream';
      headers.set('Content-Type', contentType);
      headers.set('Cache-Control', 'public, max-age=3600');
      return new Response(wkResponse.body, { status: 200, headers });
    }
    return new Response('Not Found', { status: 404 });
  }

  // ... rest of subdomain handling
}

Verification

bash
# Should return application/json, NOT text/html
curl -sI https://yourdomain.com/.well-known/apple-app-site-association | grep -i content-type

# Should return JSON body
curl -s https://yourdomain.com/.well-known/apple-app-site-association | head -c 100

# Android assetlinks.json
curl -sI https://yourdomain.com/.well-known/assetlinks.json | grep -i content-type

# Verify the SPA fallback guard works (path that does NOT exist in KV)
curl -sI https://yourdomain.com/.well-known/nonexistent-file
# Should return 404, not 200

Complete Working Example

From compute-js/src/index.js in divine-web:

javascript
// 4. Handle .well-known requests
if (url.pathname.startsWith('/.well-known/')) {
  // 4a. NIP-05 from KV store
  if (url.pathname === '/.well-known/nostr.json') {
    return await handleNip05(url);
  }

  // 4b. Serve other .well-known files (apple-app-site-association, assetlinks.json)
  // These must be served as JSON, not the SPA fallback.
  // apple-app-site-association has no file extension, so the static publisher
  // cannot detect its content type - we handle it explicitly here.
  const wkResponse = await publisherServer.serveRequest(request);
  // Guard: if publisher returns text/html, it's the SPA fallback, not the real file
  if (wkResponse != null && wkResponse.status === 200 && !wkResponse.headers.get('Content-Type')?.includes('text/html')) {
    const headers = new Headers(wkResponse.headers);
    // Ensure correct content type for app association files
    const contentType = url.pathname.endsWith('.json') || url.pathname.endsWith('/apple-app-site-association')
      ? 'application/json'
      : headers.get('Content-Type') || 'application/octet-stream';
    headers.set('Content-Type', contentType);
    headers.set('Cache-Control', 'public, max-age=3600');
    headers.append('Vary', 'X-Original-Host');
    return new Response(wkResponse.body, {
      status: 200,
      headers,
    });
  }
  // File not found in KV - return 404 instead of SPA fallback
  return new Response('Not Found', { status: 404 });
}

Deployment Checklist

After making code changes:

bash
# 1. Publish static content first (uploads .well-known files to KV)
npm run fastly:publish

# 2. Deploy the edge worker code (with the .well-known interception logic)
npm run fastly:deploy

# NOTE: Order matters if files weren't in KV before. If you deploy code first,
# it will correctly return 404 for missing files. Then publish uploads the files.
# Either order works - the guard handles both cases.

Notes

  • This pattern applies to any Fastly Compute service using @fastly/compute-js-static-publish with spaFile configured.
  • The SPA fallback is intentional for client-side routing, but it breaks any path that needs a real 404 (like .well-known verification files).
  • The content-type detection by file extension is a fundamental limitation of static publishing - extension-less files always need explicit handling.
  • If you serve multiple domains (apex + subdomains), each code path that can call publisherServer.serveRequest() needs the .well-known interception guard.
  • After fastly:publish, allow up to 2-3 minutes for KV propagation before testing.

References

© divinevideo, MPL-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/fastly-compute-well-known-spa-fallback of divinevideo/divine-mobile.

Open the folder on GitHubat commit c3d6f7e

Compare with similar skills

Fastly Compute Well Known Spa Fallback next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Fastly Compute Well Known Spa Fallback compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Fastly Compute Well Known Spa Fallback this skilldivinevideo/divine-mobile266—~2.5kAutomated safety check: PassMPL-2.0
Expo Brownfield Integrationmweinbach/agent-coworker1562 repos~900Automated safety check: NotesCustom licence
Jetpack Composedarriousliu/PiPixiv263—~1.5kAutomated safety check: PassApache-2.0
Simulator Audio E2Ehyochan/react-native-nitro-sound961—~1.1kAutomated safety check: PassMIT
Android Maps Ktxgooglemaps/android-maps-ktx360—~897Automated safety check: PassApache-2.0
Expo UIarcboxlabs/linkcode155—~1.2kAutomated safety check: PassMIT

Similar skills

  • Expo Brownfield Integration

    mweinbach/agent-coworker

    Helps add Expo and React Native to an existing native iOS or Android app, and choose between a prebuilt AAR or XCFramework and a fully integrated build.

    156 GitHub starsUsed in 2 repos~900 tokens
    MobileAuto-check: notes
  • Jetpack Compose

    darriousliu/PiPixiv

    Jetpack Compose expert skill for Android UI development. An agent skill from darriousliu/PiPixiv.

    263 GitHub stars~1.5k tokensUpdated 2 days ago
    MobileAuto-check passed
  • Simulator Audio E2E

    hyochan/react-native-nitro-sound

    Build and run repeatable react-native-nitro-sound recorder/player regression tests on an iOS Simulator or Android emulator, with explicit virtual-device selection, microphone permission, Maestro…

    961 GitHub stars~1.1k tokensUpdated 11 days ago
    MobileAuto-check passed
  • Android Maps Ktx

    googlemaps/android-maps-ktx

    Provides idiomatic Kotlin extension (KTX) patterns, reactive Flow event streams, and multi-subscriber shareIn rules for Google Maps SDK for Android and its Utility Library.

    360 GitHub stars~897 tokensUpdated 3 days ago
    MobileAuto-check passed
  • Expo UI

    arcboxlabs/linkcode

    Framework (OSS). An agent skill from arcboxlabs/linkcode.

    155 GitHub stars~1.2k tokensUpdated 13 days ago
    MobileAuto-check passed
  • Ksafe

    ioannisa/KSafe

    Required before any reply that touches KSafe (by ksafe(...), ksafe.get/put, :ksafe-compose, :ksafe-biometrics), even a 'can KSafe do X?' question or a one-line change that looks like plain Kotlin.

    338 GitHub stars~17k tokensUpdated 7 days ago
    MobileAuto-check passed

More from divinevideo/divine-mobile

All 103 skills in this repo
  • Fix ArgoCD ExternalSecret deployment failing with "namespace X is not permitted in project Y".

    266 GitHub stars~931 tokensUpdated today
    Auto-check passed
  • Art Direct

    divinevideo/divine-mobile

    Art direction for any content — reads text, PDF, Word, HTML, PPT, then proposes 2-3 creative directions with photography style, mood, and visual language.

    266 GitHub stars~4.8k tokensUpdated today
    Auto-check passed
  • Async Await Null Race Condition

    divinevideo/divine-mobile

    Fix "Null check operator used on a null value" errors when an object is set to null during an async await.

    266 GitHub stars~881 tokensUpdated today
    Auto-check passed
  • AWS V4 Signing Custom Headers Gcs

    divinevideo/divine-mobile

    Add custom metadata headers (x-amz-meta-) to AWS v4 signed requests for GCS S3-compatible API.

    266 GitHub stars~1k tokensUpdated today
    Auto-check passed
  • Bash Herestring Newline Secrets

    divinevideo/divine-mobile

    Fix password/secret authentication failures caused by trailing newlines when creating Google Cloud secrets (or similar) with bash here-strings.

    266 GitHub stars~791 tokensUpdated today
    Auto-check passed
  • Fix silent video/media processing failures caused by URL extraction code that filters on file extensions (.mp4, .webm, .webp).

    266 GitHub stars~1.1k tokensUpdated today
    Auto-check passed

Works with

Categories

Questions about Fastly Compute Well Known Spa Fallback

What does Fastly Compute Well Known Spa Fallback do?

Fix .well-known files (apple-app-site-association, assetlinks.json) being served as HTML by the @fastly/compute-js-static-publish SPA fallback instead of JSON. Fastly Compute Well Known Spa Fallback is an agent skill from divinevideo/divine-mobile.json) being served as HTML by the @fastly/compute-js-static-publish SPA fallback instead of JSON.

When should I use Fastly Compute Well Known Spa Fallback?

Fastly Compute Well Known Spa Fallback fits situations like: IOS Universal Links; android App Links are broken because the verification files return text/html instead of application/json; publisherServer with spaFile config intercepts /.well-known/ paths and returns index.html (200; text/html) instead of 404 for missing files.

How do I install Fastly Compute Well Known Spa Fallback in Claude Code?

Run `npx skills add divinevideo/divine-mobile --skill fastly-compute-well-known-spa-fallback -a claude-code`. Or copy the skill folder (.agents/skills/fastly-compute-well-known-spa-fallback in divinevideo/divine-mobile) into .claude/skills/fastly-compute-well-known-spa-fallback in your project. Claude Code loads it when a task matches its description.

How do I install Fastly Compute Well Known Spa Fallback in Codex?

Run `npx skills add divinevideo/divine-mobile --skill fastly-compute-well-known-spa-fallback -a codex`. Or copy the skill folder (.agents/skills/fastly-compute-well-known-spa-fallback in divinevideo/divine-mobile) into .agents/skills/fastly-compute-well-known-spa-fallback in your project. Codex loads it when a task matches its description.

Can I use Fastly Compute Well Known Spa Fallback in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add divinevideo/divine-mobile --skill fastly-compute-well-known-spa-fallback -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/fastly-compute-well-known-spa-fallback, .gemini/skills/fastly-compute-well-known-spa-fallback, .github/skills/fastly-compute-well-known-spa-fallback and .opencode/skills/fastly-compute-well-known-spa-fallback in your project.

What does Fastly Compute Well Known Spa Fallback need to run?

Going by SKILL.md and its folder, Fastly Compute Well Known Spa Fallback needs the command-line tools its instructions call (curl and npm).

Does Fastly Compute Well Known Spa Fallback access the network?

SKILL.md names 4 domains. As links in the text: developer.apple.com, developer.android.com, npmjs.com and fastly.com. This is read from the text; nothing was executed.

Is Fastly Compute Well Known Spa Fallback safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Fastly Compute Well Known Spa Fallback use?

Fastly Compute Well Known Spa Fallback is published under the MPL-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Fastly Compute Well Known Spa Fallback use?

About 2.5k tokens (SKILL.md is roughly 10k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Fastly Compute Well Known Spa Fallback?

Skills that share tags, products or a category with Fastly Compute Well Known Spa Fallback: Expo Brownfield Integration (mweinbach/agent-coworker, 156 stars), Jetpack Compose (darriousliu/PiPixiv, 263 stars), Simulator Audio E2E (hyochan/react-native-nitro-sound, 961 stars) and Android Maps Ktx (googlemaps/android-maps-ktx, 360 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Fastly Compute Well Known Spa Fallback?

divinevideo (a GitHub organization) maintains it in divinevideo/divine-mobile, which has 266 GitHub stars. The repository holds 103 skills in this directory. The repository was last updated on October 10, 2026.

Source: divinevideo/divine-mobile on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.