@simplysm/service-server
v13.0.69
Published
심플리즘 패키지 - 서비스 모듈 (server)
Readme
@simplysm/service-server
A Fastify-based HTTP/WebSocket server package. Provides server features needed for full-stack applications, including RPC-style service invocation, JWT authentication, file upload, static file serving, and real-time events.
Used together with @simplysm/service-client to configure WebSocket/HTTP communication between client and server.
Installation
npm install @simplysm/service-server
# or
pnpm add @simplysm/service-serverMain Modules
Core Functions and Classes
createServiceServer- Factory function for creating aServiceServerinstanceServiceServer- Main server class. Creates a Fastify instance and configures routes/pluginsdefineService- Defines a service with a name and factory functionServiceContext- Context object passed to service factory functionscreateServiceContext- Factory function that creates aServiceContext(exported for advanced use)runServiceMethod- Dispatches a service method call with auth checks and executionServiceDefinition- Type describing a registered service (name + factory + authPermissions)ServiceMethods- Type utility that extracts method signatures from aServiceDefinition
Authentication
auth- Wrapper that sets authentication requirements at service or method levelgetServiceAuthPermissions- Reads auth permissions from anauth()-wrapped functionsignJwt- Generate a JWT token (HS256, 12-hour expiration)verifyJwt- Verify and decode a JWT tokendecodeJwt- Decode a JWT token without verification (synchronous)AuthTokenPayload- JWT payload interface (includesroles,data)
Transport Layer - WebSocket
WebSocketHandler- Interface for managing multiple WebSocket connections, routing messages, and broadcasting eventscreateWebSocketHandler- Factory function that creates aWebSocketHandlerinstanceServiceSocket- Interface wrapping a single WebSocket connection. Manages ping/pong, protocol encoding/decoding, event listener managementcreateServiceSocket- Factory function that creates aServiceSocketinstance
Transport Layer - HTTP
handleHttpRequest- Handles service method calls via HTTP at/api/:service/:methodhandleUpload- Handles multipart file upload at/upload(auth required)handleStaticFile- Serves static files fromrootPath/www/. Prevents path traversal and blocks hidden files
Protocol
ProtocolWrapper- Interface for message encoding/decoding. Messages over 30KB are processed in worker threadscreateProtocolWrapper- Factory function that creates aProtocolWrapperinstance
Built-in Services
OrmService- DB connection/transaction/query execution (WebSocket only, auth required)OrmServiceType- Type alias forOrmServicemethod signatures (for client-side type sharing)AutoUpdateService- App auto-update (provides latest version query and download path)AutoUpdateServiceType- Type alias forAutoUpdateServicemethod signatures (for client-side type sharing)
Utilities
getConfig- JSON config file loading with caching and real-time file watching
Legacy
handleV1Connection- V1 protocol client compatibility handling (supports auto-update only)
Usage
Basic Server Configuration
import { createServiceServer } from "@simplysm/service-server";
const server = createServiceServer({
port: 8080,
rootPath: "/app/data",
services: [MyService],
});
// Start server
await server.listen();
// Receive events
server.on("ready", () => {
console.log("Server ready");
});
server.on("close", () => {
console.log("Server closed");
});
// Close server
await server.close();Server Options
See ServiceServerOptions for detailed configuration options including SSL, authentication, and directory structure.
Custom Services
Services are defined using the defineService function. Service methods are called via RPC from the client.
import { defineService } from "@simplysm/service-server";
export const MyService = defineService("My", (ctx) => ({
hello: async (name: string): Promise<string> => {
return `Hello, ${name}!`;
},
getServerTime: async (): Promise<Date> => {
return new Date();
},
}));
// Export type for client-side type sharing
export type MyServiceMethods = import("@simplysm/service-server").ServiceMethods<typeof MyService>;ServiceContext
The ctx parameter provides access to server resources:
ctx.server- ServiceServer instancectx.socket- ServiceSocket instance (WebSocket only, undefined for HTTP)ctx.http- HTTP request/reply objects (HTTP only, undefined for WebSocket)ctx.authInfo- Authentication info (set via JWT token)ctx.clientName- Client identifierctx.clientPath- Resolved per-client directory path (rootPath/www/{clientName})ctx.getConfig(section)- Get server config by section name
Authentication
Use the auth() wrapper to set authentication requirements at service or method level:
import { defineService, auth } from "@simplysm/service-server";
interface UserAuthInfo {
userId: number;
role: string;
}
// Service-level auth: all methods require authentication
export const UserService = defineService("User", auth((ctx) => ({
getProfile: async (): Promise<unknown> => {
const userId = (ctx.authInfo as UserAuthInfo)?.userId;
// ...
},
deleteUser: auth(["admin"], async (targetId: number): Promise<void> => {
// Only users with admin role can call
}),
})));
export type UserServiceMethods = import("@simplysm/service-server").ServiceMethods<typeof UserService>;Auth Patterns
Method-level auth only:
export const MyService = defineService("My", (ctx) => ({
publicMethod: async (): Promise<void> => {
// No auth required
},
protectedMethod: auth(async (): Promise<void> => {
// Auth required
}),
adminMethod: auth(["admin"], async (): Promise<void> => {
// Auth + admin role required
}),
}));Service-level auth with method override:
// All methods require authentication by default
export const SecureService = defineService("Secure", auth((ctx) => ({
normalMethod: async (): Promise<void> => {
// Auth required (inherited from service level)
},
adminMethod: auth(["admin"], async (): Promise<void> => {
// Auth + admin role required
}),
})));See Authentication for JWT token management and permission handling.
HTTP/WebSocket Communication
Service methods can be called via HTTP or WebSocket:
GET /api/My/hello?json=["World"]
POST /api/My/helloSee HTTP API Call and ServiceSocket for transport layer details.
File Upload
Upload files via multipart request to the /upload endpoint:
const formData = new FormData();
formData.append("file", file);
const response = await fetch("/upload", {
method: "POST",
headers: { Authorization: `Bearer ${token}` },
body: formData,
});See File Upload for more details.
Event Publishing
Publish real-time events to connected WebSocket clients:
import { defineEvent } from "@simplysm/service-common";
export const OrderUpdatedEvent = defineEvent<
{ orderId: number },
{ status: string }
>("OrderUpdatedEvent");
await server.emitEvent(
OrderUpdatedEvent,
(info) => info.orderId === 123,
{ status: "completed" },
);See Real-time Event Publishing for more details.
Built-in Services
The package provides several built-in services:
OrmService- Database operations (MySQL, MSSQL, PostgreSQL)AutoUpdateService- Client app auto-updates
Register them like any other service:
import { createServiceServer, OrmService } from "@simplysm/service-server";
const server = createServiceServer({
port: 8080,
rootPath: "/app/data",
auth: { jwtSecret: "secret" },
services: [OrmService],
});Security
- Helmet:
@fastify/helmetplugin automatically sets security headers like CSP, HSTS - CORS:
@fastify/corsplugin configures CORS - Path Traversal Prevention: Static file handler and client name validation block
..,/,\characters - Hidden File Blocking: Files starting with
.return a 403 response - Directory Trailing Slash Redirect: Directory requests without a trailing slash are redirected to the same path with a trailing slash (standard web server behavior)
- Graceful Shutdown: Detects
SIGINT/SIGTERMsignals to safely close WebSocket connections and server (10-second timeout)
See Security for more details.
License
Apache-2.0
