sveltekit-service-manager - v1.1.0
    Preparing search index...

    sveltekit-service-manager - v1.1.0

    πŸ”§ @sourceregistry/sveltekit-service-manager

    npm version License CI Codecov

    A minimal, production-oriented service gateway for SvelteKit.

    This library provides a structured way to expose backend services through versioned gateway routes while keeping services modular, testable, and HMR-safe.


    SvelteKit routes are powerful, but for larger backends you often want:

    • a single gateway (/api/v1/services/...)
    • modular services with their own routers and lifecycle
    • internal calls without HTTP
    • safe hot reload during development
    • optional Express / Node middleware reuse
    • a typed client to call services from the browser

    This project solves that without introducing a full framework.


    • πŸšͺ Versioned service gateways (/api/v1/services/<service>/<path…>)
    • πŸ” Per-gateway allowlists
    • πŸ” Clean Vite HMR (cleanup + route reset + re-register)
    • 🧭 Fast, typed service-relative router
    • 🧠 Internal service calls (no HTTP hop)
    • πŸ›‘οΈ Middleware guards
    • πŸ”Œ Express / Node middleware compatibility (Fetch adapter)
    • 🌐 Typed client-side service caller

    β”œβ”€β”€ src
    β”‚   β”œβ”€β”€ lib
    β”‚   β”‚   β”œβ”€β”€ client          # Client-side service caller
    β”‚   β”‚   └── server
    β”‚   β”‚       └── helpers
    β”‚   └── routes
    β”‚       └── api
    β”‚           └── v1
    β”‚               └── services
    β”‚                   └── [service_name]
    β”‚                       └── [...catch]
    β”‚                           └── +server.ts
    β”œβ”€β”€ static
    └── tests
        └── services
    

    npm i @sourceregistry/sveltekit-service-manager
    

    In this repository you may see $lib/server/index.js. In production always import from the package.


    src/routes/api/v1/services/[service_name]/[...catch]/+server.ts

    import { ServiceManager } from '@sourceregistry/sveltekit-service-manager';

    const { endpoint, access } = ServiceManager.Base(undefined, {
    accessKey: 'api:v1'
    });

    export const { GET, POST, PUT, DELETE, PATCH, HEAD } = endpoint;

    // Allow only selected services through this gateway
    access('ping', 'users');

    This exposes:

    /api/v1/services/ping/*
    /api/v1/services/users/*

    Each gateway gets its own allowlist, isolated even across HMR:

    // Public API
    ServiceManager.Base(undefined, { accessKey: 'public' }).access('ping');

    // Internal API
    ServiceManager.Base(undefined, { accessKey: 'internal' }).access('admin', 'metrics');

    import { Router, Action, ServiceManager } from '@sourceregistry/sveltekit-service-manager';

    const router = Router()
    .GET('/health', () => Action.success(200, { ok: true }))
    .GET('/echo/[msg]', ({ params }) =>
    Action.success(200, { msg: params.msg })
    );

    export const service = {
    name: 'ping',
    route: router
    };

    export default ServiceManager
    .Load(service, import.meta)
    .finally(() => console.log('[Service]', `[${service.name}]`, 'Loaded'));

    Accessible via:

    /api/v1/services/ping/health
    /api/v1/services/ping/echo/hello

    When loading a service with:

    ServiceManager.Load(service, import.meta)
    

    The following happens automatically during Vite HMR:

    1. cleanup() is called (if defined)
    2. Router routes are fully reset
    3. Service is unregistered
    4. Updated module is reloaded
    5. Routes are re-registered

    This prevents:

    • duplicate routes
    • stale handlers
    • memory leaks

    Compose guards and pass combined state to handlers:

    import { middleware, Action } from '@sourceregistry/sveltekit-service-manager';

    const requireAuth = async ({ cookies }) => {
    const token = cookies.get('token');
    if (!token) throw Action.error(401, { message: 'Unauthorized' } as any);
    return { token };
    };

    export const service = {
    name: 'users',
    route: middleware(
    async ({ guard }) => Action.success(200, { token: guard.token }),
    requireAuth
    )
    };

    If a service defines local, you can call it directly:

    import { Service } from '@sourceregistry/sveltekit-service-manager';

    const value = Service('ping');

    This is fully typed via App.Services.


    The client helper provides a typed, ergonomic way to call public services.

    import { Service } from '$lib/client';

    const ping = Service('ping');

    const result = await ping.call('/health');
    ping.route('/health'); // "/api/v1/services/ping/health"
    

    POST with JSON body

    await ping.call('/echo', { message: 'hello' });
    

    Errors throw a ServiceError:

    try {
    await ping.call('/fail');
    } catch (e) {
    if (e instanceof ServiceError) {
    console.error(e.code); // HTTP status
    console.error(e.data); // parsed JSON or text
    }
    }

    Service('ping', {
    entryPoint: '/api/v1/services',
    executor: fetch
    });

    Supports dynamic [param] resolution using Page.params.


    You can run Express (or similar) inside a service:

    import express from 'express';
    import { Proxy } from '@sourceregistry/sveltekit-service-manager';

    const app = express();
    app.get('/hello', (_req, res) => res.json({ hello: 'world' }));

    const proxy = new Proxy(app);

    export const service = {
    name: 'express-demo',
    route: (event) => proxy.handle(event)
    };

    • ServiceManager
    • ServiceRouter / Router
    • Service (internal call)
    • Action
    • middleware
    • Server (WebHTTPServer)
    • Proxy (WebProxyServer)
    • json, text, html, file, fail, error
    • Service
    • ServiceError
    • PublicServices

    npm test
    

    Tests live in tests/services.


    Apache 2.0 see LICENSE