@sourceregistry/sveltekit-service-manager
v1.1.2
Published
A minimal, production-oriented service gateway for SvelteKit.
Maintainers
Readme
🔧 @sourceregistry/sveltekit-service-manager
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.
Why this exists
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.
Features
- 🚪 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
Project structure
├── src
│ ├── lib
│ │ ├── client # Client-side service caller
│ │ └── server
│ │ └── helpers
│ └── routes
│ └── api
│ └── v1
│ └── services
│ └── [service_name]
│ └── [...catch]
│ └── +server.ts
├── static
└── tests
└── servicesInstallation
npm i @sourceregistry/sveltekit-service-managerIn this repository you may see
$lib/server/index.js. In production always import from the package.
Gateway setup
Example gateway route
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/*Multiple gateways (public / internal)
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');Defining a service
Router-based service (recommended)
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/helloHot Module Reloading (HMR)
When loading a service with:
ServiceManager.Load(service, import.meta)The following happens automatically during Vite HMR:
cleanup()is called (if defined)- Router routes are fully reset
- Service is unregistered
- Updated module is reloaded
- Routes are re-registered
This prevents:
- duplicate routes
- stale handlers
- memory leaks
Middleware guards
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
)
};Internal service calls (no HTTP)
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.
Client-side usage
The client helper provides a typed, ergonomic way to call public services.
Basic usage
import {Service} from "@sourceregistry/sveltekit-service-manager";
const ping = Service('ping');
const result = await ping.call('/health');With route helpers
ping.route('/health'); // "/api/v1/services/ping/health"POST with JSON body
await ping.call('/echo', { message: 'hello' });Client error handling
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
}
}Custom entrypoint or fetch
Service('ping', {
entryPoint: '/api/v1/services',
executor: fetch
});Supports dynamic [param] resolution using Page.params.
Express / Node middleware integration
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)
};Exports
Server
ServiceManagerServiceRouter/RouterService(internal call)ActionmiddlewareServer(WebHTTPServer)Proxy(WebProxyServer)json,text,html,file,fail,error
Client
ServiceServiceErrorPublicServices
Testing
npm testTests live in tests/services.
License
Apache 2.0 see LICENSE
