|
| 1 | +--- |
| 2 | +title: Standalone service worker (@eggjs/service-worker[-runtime]) |
| 3 | +type: package |
| 4 | +summary: Fetch-semantics standalone runtime — HTTP controllers and MCP tools served from a tegg module without an egg application |
| 5 | +source_files: |
| 6 | + - tegg/standalone/service-worker-runtime/src |
| 7 | + - tegg/standalone/service-worker/src |
| 8 | + - examples/helloworld-service-worker |
| 9 | +updated_at: 2026-07-05 |
| 10 | +status: active |
| 11 | +--- |
| 12 | + |
| 13 | +Two packages provide the standalone service worker runtime on top of the |
| 14 | +module-plugin mechanism (declarative `@InnerObjectProto` / |
| 15 | +`@XxxLifecycleProto` hooks, see the module-plugin pages): |
| 16 | + |
| 17 | +- `@eggjs/service-worker-runtime` — protocol-agnostic: `@Runner()` entry |
| 18 | + dispatching events to `@EventHandlerProto('<type>')` handlers, event |
| 19 | + injection into ContextProtos, `BackgroundTaskHelper` re-export |
| 20 | + (ctx-destroy draining). |
| 21 | +- `@eggjs/service-worker` — the fetch protocol: `FetchEventHandler`, |
| 22 | + `FetchRouter` + fetch parameter binding (no `@Cookies`), MCP stateless |
| 23 | + streamable HTTP under `/mcp[/name]/stream`, `ServiceWorkerApp` facade with |
| 24 | + `serve()` (node:http bridge) and embedded `handleEvent()`. |
| 25 | + |
| 26 | +Key mechanics and constraints: |
| 27 | + |
| 28 | +- **Controller reuse**: metadata from `@eggjs/controller-decorator`, |
| 29 | + registration runtime from `@eggjs/controller-plugin` (shared with |
| 30 | + `@eggjs/controller-plugin`); only param binding and transports are |
| 31 | + fetch-specific. |
| 32 | +- **MCP SDK >= 1.29 stateless transports are single-shot** (reuse throws), so |
| 33 | + each MCP request builds a fresh `MCPServerHelper` + web-standard transport |
| 34 | + from register records collected at boot. The service worker uses |
| 35 | + `WebStandardStreamableHTTPServerTransport` (Request in, Response out) — no |
| 36 | + node req/res bridging. Auth is an `mcpAuthHandler` extension point |
| 37 | + (default: allow). |
| 38 | +- **Streaming lifecycle**: `FetchEventHandler` routes every response body |
| 39 | + through a passthrough and registers the drain as a background task, so ctx |
| 40 | + destroy waits (bounded by `config.backgroundTask.timeout`) until the client |
| 41 | + consumes the stream. |
| 42 | +- **Unified errors**: framework failures reply `{ code, message }` JSON |
| 43 | + (`NOT_FOUND` / `INTERNAL_SERVER_ERROR`); `ctx.responseHeaders` merge onto |
| 44 | + the final response. |
| 45 | +- **frameworkDeps scan excludes `test/**`\*\*: the framework packages are |
| 46 | + themselves modules; without the exclusion their test fixtures load as |
| 47 | + business modules (duplicate controller names) in workspace layouts. |
| 48 | +- Per-app state is all inner objects in the app's TeggScope bag — two |
| 49 | + concurrent `ServiceWorkerApp`s are isolated (`test/MultiApp.test.ts`). |
| 50 | + |
| 51 | +Example: `examples/helloworld-service-worker` (entry `main.ts` lives outside |
| 52 | +the scanned `app/` module dir on purpose — the scan imports every module |
| 53 | +file, and importing an entry that boots the app recurses). |
0 commit comments