npm package: @skybolt/server-adapter
Description: Skybolt server adapter for Node.js/Bun - High-performance asset caching for multi-page applications
Author: Jens Roland
Latest version: 3.5.0

# @skybolt/server-adapter

Skybolt server adapter for Node.js and Bun. High-performance asset caching for multi-page applications.

## Installation

```bash
npm install @skybolt/server-adapter
# or
pnpm add @skybolt/server-adapter
# or
bun add @skybolt/server-adapter
```

## Quick Start

```javascript
import { Skybolt } from '@skybolt/server-adapter'

// Create instance with render map path and request cookies
const skybolt = new Skybolt(
  './dist/.skybolt/render-map.json',
  req.cookies  // Your framework's cookies object
)

// Generate HTML
const html = `
<!DOCTYPE html>
<html>
<head>
  ${skybolt.css('src/css/main.css')}
  ${skybolt.launchScript()}
</head>
<body>
  <h1>Hello Skybolt!</h1>
  ${skybolt.script('src/js/app.js')}
</body>
</html>
`
```

## How It Works

**First visit:** Assets are inlined directly in the HTML. The Skybolt client script caches them in the browser's Cache API and registers a Service Worker.

**Repeat visits:** The server outputs standard `<link>` and `<script>` tags. The Service Worker intercepts these requests and serves assets from cache (~5ms response time). **Zero network requests.**

**After rebuilds:** Content hashes change, causing a cache miss. Assets are re-inlined and the cache is updated automatically.

## API

### `new Skybolt(renderMapPath, cookies?, cdnUrl?)`

Create a new Skybolt instance.

- `renderMapPath` (string) - Path to the `render-map.json` file generated by `@skybolt/vite-plugin`
- `cookies` (object | null) - Request cookies object from your framework
- `cdnUrl` (string | null) - Optional CDN base URL to prefix asset URLs

### `skybolt.css(entry, options?)`

Render a CSS asset.

```javascript
// Blocking CSS (in <head>)
skybolt.css('src/css/main.css')

// Non-blocking CSS (async loading)
skybolt.css('src/css/main.css', { async: true })
```

**Options:**

- `async` (boolean, default: `false`) - Load CSS asynchronously

### `skybolt.script(entry, options?)`

Render a JavaScript asset.

```javascript
// ES module (default)
skybolt.script('src/js/app.js')

// Classic script
skybolt.script('src/js/legacy.js', { module: false })
```

**Options:**

- `module` (boolean, default: `true`) - Use `type="module"` for ES modules

### `skybolt.preload(entry, options?)`

Render a preload link for early resource fetching.

```javascript
skybolt.preload('src/fonts/Inter.woff2', {
  as: 'font',
  type: 'font/woff2',
  crossorigin: 'anonymous'
})
```

**Options:**

- `as` (string) - Resource type (`'font'`, `'image'`, `'script'`, `'style'`)
- `type` (string) - MIME type
- `crossorigin` (string) - Crossorigin attribute
- `fetchpriority` (string) - `'high'`, `'low'`, or `'auto'`

### `skybolt.launchScript()`

Render the Skybolt client launcher. **Include this once per page.**

```javascript
// In <head> or before </body>
skybolt.launchScript()
```

### `skybolt.getAssetUrl(entry)`

Get the URL for an asset (for manual use).

```javascript
const url = skybolt.getAssetUrl('src/images/hero.webp')
// => '/assets/hero-Abc123.webp'
```

### `skybolt.getAssetHash(entry)`

Get the content hash for an asset.

```javascript
const hash = skybolt.getAssetHash('src/css/main.css')
// => 'Pw3rT8vL'
```

### `skybolt.isCached(entry)`

Check if the client has an asset cached.

```javascript
if (skybolt.isCached('src/css/main.css')) {
  // Client has current version cached
}
```

## Framework Examples

### Express

```javascript
import express from 'express'
import cookieParser from 'cookie-parser'
import { Skybolt } from '@skybolt/server-adapter'

const app = express()
app.use(cookieParser())
app.use(express.static('dist'))

app.get('/', (req, res) => {
  const skybolt = new Skybolt('./dist/.skybolt/render-map.json', req.cookies)

  res.send(`
    <!DOCTYPE html>
    <html>
    <head>
      ${skybolt.css('src/css/main.css')}
      ${skybolt.launchScript()}
    </head>
    <body>
      <h1>Express + Skybolt</h1>
      ${skybolt.script('src/js/app.js')}
    </body>
    </html>
  `)
})

app.listen(8080)
```

### Hono (Bun)

```javascript
import { Hono } from 'hono'
import { getCookie } from 'hono/cookie'
import { serveStatic } from 'hono/bun'
import { Skybolt } from '@skybolt/server-adapter'

const app = new Hono()
app.use('/*', serveStatic({ root: './dist' }))

app.get('/', (c) => {
  const cookies = { sb_digest: getCookie(c, 'sb_digest') }

  const skybolt = new Skybolt('./dist/.skybolt/render-map.json', cookies)

  return c.html(`
    <!DOCTYPE html>
    <html>
    <head>
      ${skybolt.css('src/css/main.css')}
      ${skybolt.launchScript()}
    </head>
    <body>
      <h1>Hono + Skybolt</h1>
      ${skybolt.script('src/js/app.js')}
    </body>
    </html>
  `)
})

export default app
```

### Fastify

```javascript
import Fastify from 'fastify'
import fastifyCookie from '@fastify/cookie'
import fastifyStatic from '@fastify/static'
import { Skybolt } from '@skybolt/server-adapter'

const fastify = Fastify()
await fastify.register(fastifyCookie)
await fastify.register(fastifyStatic, { root: './dist' })

fastify.get('/', (req, reply) => {
  const skybolt = new Skybolt('./dist/.skybolt/render-map.json', req.cookies)

  reply.type('text/html').send(`
    <!DOCTYPE html>
    <html>
    <head>
      ${skybolt.css('src/css/main.css')}
      ${skybolt.launchScript()}
    </head>
    <body>
      <h1>Fastify + Skybolt</h1>
      ${skybolt.script('src/js/app.js')}
    </body>
    </html>
  `)
})

await fastify.listen({ port: 8080 })
```

## CDN Support

Prefix asset URLs with a CDN base URL:

```javascript
const skybolt = new Skybolt(
  './dist/.skybolt/render-map.json',
  req.cookies,
  'https://cdn.example.com'
)

// URLs become: https://cdn.example.com/assets/main-Abc123.css
```

## TypeScript

Full TypeScript support is included:

```typescript
import { Skybolt, type RenderMap, type Asset } from '@skybolt/server-adapter'

const skybolt = new Skybolt('./dist/.skybolt/render-map.json', req.cookies)
```

## Requirements

- Node.js 18+ or Bun
- Assets built with `@skybolt/vite-plugin`

## License

MIT