Publishing Your Extension

Once your extension works locally, publish it so others can install it in Glyph.

Build

npm run build

This creates optimized, minified bundles in dist/:

dist/
├── my-source.js       # Minified extension bundle (~680KB with cheerio)
├── index.json          # Repository metadata

Build Validation

The build script automatically validates each extension:

  • info object has all required fields (id, name, version, baseUrl, icon, language)
  • Required methods exist (searchNovels, fetchNovelDetails, fetchChapterContent)
  • Bundle evaluates without runtime errors

If validation fails, the build shows which checks didn’t pass.

Hosting

Host the dist/ folder on any static HTTPS host. The app fetches index.json to discover available sources.

  1. Push your repo to GitHub
  2. Go to Settings → Pages → Deploy from branch (select main, folder /dist)
  3. Your URL: https://username.github.io/repo-name/dist/index.json

Other Hosts

Netlify, Vercel, Cloudflare Pages, or any static file server.

Important: HTTPS is required. HTTP is only allowed for localhost during development.

Installing in Glyph

Users install your extension by:

  1. Settings → Extensions → +
  2. Enter your repo URL (e.g. https://username.github.io/repo-name)
  3. Tap FetchInstall

The app auto-appends /dist/index.json if the URL doesn’t end in .json.

Share a one-tap install link:

glyph://add-repo?url=https://username.github.io/repo-name/dist/index.json

The dev server prints this link automatically when you start it.

Versioning

Bump the version field in your createSource() call:

export default createSource({
  id: 'my-source',
  version: '1.0.1', // ← bump this
  // ...
})

When users refresh their extensions in Glyph (Settings → Extensions → Refresh), the app detects the version change and downloads the new bundle.

index.json Format

The build generates an index.json with this structure:

{
  "name": "My Extensions",
  "author": "your-name",
  "sources": [
    {
      "id": "my-source",
      "name": "My Source",
      "version": "1.0.1",
      "language": "en",
      "icon": "https://example.com/icon.png",
      "bundleUrl": "https://username.github.io/repo/dist/my-source.js"
    }
  ]
}

Development Workflow

Dev Server

npm run dev

Starts a local server that:

  • Watches for file changes and rebuilds automatically
  • Validates extensions on every build
  • Serves at http://localhost:PORT
  • Prints a deep link for easy testing in Glyph

Testing

npm test              # Unit tests (fast, mocked HTTP)
npm run test:integration  # Integration tests (real HTTP, slower)

Unit tests use mocked HTTP responses:

import { mockRequest, clearMocks } from '@glyph/sdk/testing'

beforeEach(() => clearMocks())

it('searches novels', async () => {
  mockRequest('https://example.com/search?q=test&page=1', {
    body: '<html>...</html>',
  })

  const result = await source.searchNovels('test', 1)
  expect(result.items).toHaveLength(3)
})

Mock Options

mockRequest(
  url,
  {
    status: 200, // HTTP status (default: 200)
    body: '<html>...</html>', // Response body (required)
    headers: {}, // Response headers (optional)
  },
  {
    glob: false, // Enable pattern matching (default: false)
  },
)

With glob matching:

mockRequest(
  'https://example.com/book/*',
  {
    body: '<html>...</html>',
  },
  { glob: true },
)