Server only
Creator server runtime
@silicon-jungle/inkwell-sdk/serverDefine one game backend with your own world, rooms, queues, timers and application rules.
Exact source · npm package · Reference version 0.0.8
API at a glance
defineBackend<Protocol>({ start?, connect?, disconnect?, messages?, binaryEvents?, binaryMessages?, actions?, fetch?, shutdown? })context.connections / context.region / context.fetchcontext.broadcastReliable(name, payload, { except? }?): Promise<void>context.broadcastUnreliable(name, payload, { except? }?): numbercontext.database / storage / leaderboards / achievements / stats / chat / presenceconnection.id / connection.identityconnection.sendReliable(), sendUnreliable(), close()connection.binaryEvents / sendBinaryReliable(name, bytes) / sendBinaryUnreliable(name, bytes)new BackendActionFailure(code, publicMessage)createBackendServer(definition, services) / new BackendServer(definition, services)server.start(), accept(peer), receive(peerId, bytes, delivery), remove(peerId), handleFetch(request, identity), shutdown()server.connections / server.connectionCount
The hosted runtime invokes your definition. createBackendServer, BackendServer and BackendPeer are lower-level adapters for tests or custom runtimes; implementing an adapter does not provision hosted infrastructure.
connection.id identifies a transport connection. identity.playerId identifies the player within this game; signed-in identity survives sessions and builds. Multiple connections may belong to one player.
Broadcast except values are connection IDs, not player IDs. Unreliable broadcast returns how many connections admitted the send, not acknowledgements.
Validate every client payload and authorize every world or inventory operation. Throw BackendActionFailure for an intentional public action error; unexpected handler errors are concealed.
Save durable state during normal operation. Shutdown is not guaranteed on crashes, and in-memory state or local files do not survive as durable account saves.
Set binaryEvents: true to support negotiation, then handle raw byte payloads in binaryMessages. Do not send binary before connection.binaryEvents is true. The reliable action inkwell.binary.negotiate is reserved; binary support does not validate your application schema or make datagrams reliable.
All exported symbols
BackendActionFailureBackendChatBackendContextBackendDefinitionBackendIdentityBackendPeerBackendRuntimeServicesBackendServerServerConnectioncreateBackendServerdefineBackend
Exact TypeScript API
Generated from the SDK source, including input options, return values, public types and overloads. Relative imports below are links between SDK source modules, not additional package subpaths. Only the entrypoints listed in the reference index are supported import paths.
import type { AnyBackendProtocol, BackendProtocol } from "./backend.js";
import { type Delivery } from "./wire.js";
import type { InkwellDatabase, InkwellObjectStorage } from "./storage.js";
import type { createServerLeaderboards } from "./leaderboards.js";
import type { createServerAchievements } from "./achievements.js";
import type { createServerStats } from "./stats.js";
import type { createServerPresence } from "./presence.js";
import type { createServerChat } from "./chat.js";
export type BackendChat = Omit<ReturnType<typeof createServerChat>, "connect">;
export type BackendIdentity = Readonly<{
playerId: string;
username: string | null;
displayName: string;
avatarUrl: string | null;
isGuest: boolean;
}>;
export type BackendRuntimeServices = Readonly<{
presence: ReturnType<typeof createServerPresence>;
chat: BackendChat;
achievements: ReturnType<typeof createServerAchievements>;
stats: ReturnType<typeof createServerStats>;
leaderboards: ReturnType<typeof createServerLeaderboards>;
database: InkwellDatabase;
storage: InkwellObjectStorage;
fetch: typeof fetch;
region: string;
}>;
export type BackendPeer = {
id: string;
identity: BackendIdentity;
sendReliable(frame: Uint8Array): Promise<void>;
sendUnreliable(frame: Uint8Array): boolean;
close(code?: number, reason?: string): void;
};
type EventName<T> = Extract<keyof T, string>;
type ActionInput<T> = T extends {
input: infer Input;
} ? Input : never;
type ActionOutput<T> = T extends {
output: infer Output;
} ? Output : never;
export declare class BackendActionFailure extends Error {
readonly code: string;
constructor(code: string, message: string);
}
export declare class ServerConnection<Protocol extends BackendProtocol = AnyBackendProtocol> {
private readonly peer;
constructor(peer: BackendPeer);
get binaryEvents(): boolean;
sendBinaryReliable(name: string, payload: Uint8Array): Promise<void>;
sendBinaryUnreliable(name: string, payload: Uint8Array): boolean;
get id(): string;
get identity(): Readonly<{
playerId: string;
username: string | null;
displayName: string;
avatarUrl: string | null;
isGuest: boolean;
}>;
sendReliable<Name extends EventName<Protocol["serverEvents"]>>(name: Name, payload: Protocol["serverEvents"][Name]): Promise<void>;
sendUnreliable<Name extends EventName<Protocol["serverEvents"]>>(name: Name, payload: Protocol["serverEvents"][Name]): boolean;
close(code?: number, reason?: string): void;
}
export type BackendContext<Protocol extends BackendProtocol = AnyBackendProtocol> = Readonly<{
presence: ReturnType<typeof createServerPresence>;
chat: BackendChat;
achievements: ReturnType<typeof createServerAchievements>;
stats: ReturnType<typeof createServerStats>;
leaderboards: ReturnType<typeof createServerLeaderboards>;
database: InkwellDatabase;
storage: InkwellObjectStorage;
fetch: typeof fetch;
region: string;
connections: readonly ServerConnection<Protocol>[];
broadcastReliable<Name extends EventName<Protocol["serverEvents"]>>(name: Name, payload: Protocol["serverEvents"][Name], options?: {
except?: string | readonly string[];
}): Promise<void>;
broadcastUnreliable<Name extends EventName<Protocol["serverEvents"]>>(name: Name, payload: Protocol["serverEvents"][Name], options?: {
except?: string | readonly string[];
}): number;
}>;
export type BackendDefinition<Protocol extends BackendProtocol = AnyBackendProtocol> = Readonly<{
__inkwellBackend: 1;
binaryEvents?: boolean;
binaryMessages?: Record<string, (payload: Uint8Array, connection: ServerConnection<Protocol>, context: BackendContext<Protocol>, delivery: Delivery) => void | Promise<void>>;
start?: (context: BackendContext<Protocol>) => void | Promise<void>;
connect?: (connection: ServerConnection<Protocol>, context: BackendContext<Protocol>) => void | Promise<void>;
disconnect?: (connection: ServerConnection<Protocol>, context: BackendContext<Protocol>) => void | Promise<void>;
messages?: {
[Name in EventName<Protocol["clientEvents"]>]?: (payload: Protocol["clientEvents"][Name], connection: ServerConnection<Protocol>, context: BackendContext<Protocol>, delivery: Delivery) => void | Promise<void>;
};
actions?: {
[Name in EventName<Protocol["actions"]>]?: (payload: ActionInput<Protocol["actions"][Name]>, connection: ServerConnection<Protocol>, context: BackendContext<Protocol>) => ActionOutput<Protocol["actions"][Name]> | Promise<ActionOutput<Protocol["actions"][Name]>>;
};
fetch?: (request: Request, context: BackendContext<Protocol>, identity: BackendIdentity) => Response | Promise<Response>;
shutdown?: (context: BackendContext<Protocol>) => void | Promise<void>;
}>;
type BackendDefinitionInput<Protocol extends BackendProtocol> = Omit<BackendDefinition<Protocol>, "__inkwellBackend">;
export declare function defineBackend<Protocol extends BackendProtocol = AnyBackendProtocol>(definition: BackendDefinitionInput<Protocol>): BackendDefinition<Protocol>;
export declare class BackendServer<Protocol extends BackendProtocol = AnyBackendProtocol> {
private readonly definition;
private readonly connectionsById;
private readonly peersById;
private readonly activeActions;
private readonly context;
private startPromise;
private shuttingDown;
constructor(definition: BackendDefinition<Protocol>, services: BackendRuntimeServices);
get connections(): ServerConnection<Protocol>[];
get connectionCount(): number;
start(): Promise<void>;
accept(peer: BackendPeer): Promise<ServerConnection<Protocol> | null>;
receive(peerId: string, bytes: Uint8Array, delivery: Delivery): Promise<void>;
remove(peerId: string): Promise<void>;
handleFetch(request: Request, identity: BackendIdentity): Promise<Response>;
shutdown(): Promise<void>;
private broadcastReliable;
private broadcastUnreliable;
private sendActionError;
}
export declare function createBackendServer<Protocol extends BackendProtocol = AnyBackendProtocol>(definition: BackendDefinition<Protocol>, services: BackendRuntimeServices): BackendServer<Protocol>;
export {};
Supporting internal type declarations
These clarify types referenced by the generated signatures; do not import these internal paths directly.
game-services.d.ts
export declare class GameServiceError extends Error {
readonly status: number;
readonly code: string;
constructor(message: string, status?: number, code?: string);
}
export type GameServiceRequest = <T>(service: string, request: Record<string, unknown>) => Promise<T>;
export declare const requestGameService: GameServiceRequest;
/** Server-only adapter. Credentials must never be bundled into browser games. */
export declare function createGameServiceRequest(options: {
baseUrl: string;
token: string;
fetch?: typeof fetch;
}): GameServiceRequest;
protocol.d.ts
export declare const SDK_SOURCE: "inkwell-sdk";
export declare const SDK_VERSION: 1;
export type InkwellMessageType = "ready" | "loading.progress" | "loading.error" | "session.complete" | "analytics.track" | "assets.progress" | "player.get" | "presence.get" | "performance.sample" | "backend.connect" | "backend.fetch";
export type InkwellMessage = {
source: typeof SDK_SOURCE;
version: typeof SDK_VERSION;
type: InkwellMessageType;
payload?: Record<string, unknown>;
sentAt: number;
};
export declare function parentOrigin(): string | null;
export declare function requestId(): string;
export declare function emit(type: InkwellMessageType, payload?: Record<string, unknown>): boolean;