Services API
Generated public TypeScript reference for @relkit/services.
Common APIs
For configuration and examples, read define, migration, service.
For a complete workflow, follow upload product images.
Frontend usage
Call a public service operation shows the client side of this capability.
Public imports
@relkit/services— 45 exports
All exported APIs
Names link to their complete contracts. Re-exports share their original contract; legacy exports keep their separate identity. Examples link to the API’s inline sample, a maintained repository usage, or the shared module walkthrough.
define-service.ts
defineService
Define a service synchronously for authoring and preserve member identity.
Throws
TypeError for malformed local input, or the original identity/ID error.
Example
import { defineFunction } from "@relkit/functions";
import { z } from "@relkit/schema";
import { defineService } from "@relkit/services";
const lookup = defineFunction({
input: z.string(),
output: z.string(),
handler: (id) => id,
});
const orders = defineService({ id: "orders", functions: { lookup } });
Signature
declare const defineService: DefineService;
Since v0.1.0
Backend and frontend example
Backend — these maintained files define the operation used by the frontend below.
/** Declares the orders service boundary without acquiring native clients. */
import { defineService } from "@relkit/app/services";
import createOrder from "./functions/create-order.function.js";
import deleteOrder from "./functions/delete-order.function.js";
import getOrder from "./functions/get-order.function.js";
import searchOrders from "./functions/search-orders.function.js";
import updateOrder from "./functions/update-order.function.js";
import authorizeOrder from "./functions/authorize-order.function.js";
import streamOrderReport from "./functions/stream-order-report.function.js";
import cleanupOrders from "./jobs/cleanup-orders.job.js";
import exportOrders from "./jobs/export-orders.job.js";
import cleanupOrdersTask from "./tasks/cleanup-orders.task.js";
import exportOrdersTask from "./tasks/export-orders.task.js";
export default defineService({
functions: {
createOrder,
deleteOrder,
getOrder,
searchOrders,
updateOrder,
authorizeOrder,
streamOrderReport,
},
tasks: { cleanupOrdersTask, exportOrdersTask },
jobs: { cleanupOrders, exportOrders },
});
/**
* Maps order HTTP operations to public service members with the existing request
* and rate-limit policies. The rate-limit reference addresses the declared cache
* by its stable identity without importing a private service implementation.
*/
import { defineServiceRoutes, http } from "@relkit/app/routes";
import { z } from "@relkit/app/schema";
import orders from "../../services/orders/service.js";
export const { GET, POST } = defineServiceRoutes(orders, {
GET: "searchOrders",
POST: {
member: "createOrder",
request: http.input({
orderId: http.header("idempotency-key"),
customerEmail: http.header("x-customer-email"),
sku: http.body("sku"),
quantity: http.body("quantity"),
}),
rateLimit: {
limit: 20,
windowMs: 60_000,
key: http.header("x-customer-email"),
store: {
ref: { kind: "cache", id: "orders.rate-limits" },
key: z.string(),
value: z.number().int().nonnegative(),
},
},
successStatus: 201,
},
});
Frontend
After frontend setup and pulling this backend’s contract,
render this component under RelkitClientProvider. Each exported service-route method produces
its own typed operation: GET /orders reads the search count, while POST /orders creates an order.
"use client";
/** Calls both commerce service-route methods using their generated domain inputs inside the frontend provider. */
import { useRelkitClient, useRoute, useRouteMutation } from "@relkit/client/react";
/** Reads the Orders search count and submits one explicit creation without replaying a failed write.
* @returns Typed query results, creation feedback, and an action available after identity is ready. */
export function Orders() {
const { status } = useRelkitClient();
const orders = useRoute("GET /orders", { input: { status: "pending" } });
const create = useRouteMutation("POST /orders");
return (
<section>
{orders.isPending && <p role="status">Loading orders…</p>}
{orders.data && <p>{orders.data.count} orders</p>}
{orders.isError && <p role="alert">{orders.error.message}</p>}
<button
disabled={status !== "ready" || !create.isIdle}
onClick={() =>
create.mutate({
orderId: crypto.randomUUID(),
customerEmail: "reader@example.com",
sku: "book",
quantity: 1,
})
}
>
Create an order
</button>
{create.isPending && <p role="status">Creating…</p>}
{create.isSuccess && <p>Created: {create.data.orderId}</p>}
{create.isError && (
<p role="alert">{create.error.message}. Check the outcome before retrying.</p>
)}
</section>
);
}
status, count, and the creation input come from the selected functions’ schemas. RPC receives
orderId and customerEmail as input fields even though REST maps them from headers. A service’s
public member alone is not a browser endpoint: the client-exposed route supplies that boundary.
Reference: useRoute, useRouteMutation.
See request mapping for the REST side and
mutations for submission and recovery behavior.
defineServiceEffect
Define a service without cloning its member descriptors.
Example
Effect.runSync(defineServiceEffect({ id: "orders", functions: { lookup } }));
Signature
declare const defineServiceEffect: <
const Id extends string,
const Functions extends ServiceFunctionMap = Readonly<Record<never, never>>,
const Events extends ServiceEventMap = Readonly<Record<never, never>>,
const Tasks extends ServiceTaskMap = Readonly<Record<never, never>>,
const Jobs extends ServiceJobMap = Readonly<Record<never, never>>,
>(
options: DefineServiceOptions<Id, Functions, Events, Tasks, Jobs>,
) => Effect.Effect<
ServiceDescriptor<Id, Functions, Events, Tasks, Jobs>,
ServiceValidationError,
never
>;
define-service.types.ts
DefineService (interface)
Generic synchronous service factory preserving member inference.
Throws
TypeError for malformed local input, or the original identity/ID error.
Example
const orders = defineService({ id: "orders", functions: { lookup } });
Signature
export interface DefineService {
<
const Id extends string,
const Functions extends ServiceFunctionMap = Readonly<Record<never, never>>,
const Events extends ServiceEventMap = Readonly<Record<never, never>>,
const Tasks extends ServiceTaskMap = Readonly<Record<never, never>>,
const Jobs extends ServiceJobMap = Readonly<Record<never, never>>,
>(
options: DefineServiceOptions<Id, Functions, Events, Tasks, Jobs>,
): ServiceDescriptor<Id, Functions, Events, Tasks, Jobs>;
}
DefineServiceOptions (interface)
Metadata and optional descriptor members accepted by defineService.
Example
const options: DefineServiceOptions<"orders"> = { id: "orders" };
Signature
export interface DefineServiceOptions<
Id extends string,
Functions extends ServiceFunctionMap = Readonly<Record<never, never>>,
Events extends ServiceEventMap = Readonly<Record<never, never>>,
Tasks extends ServiceTaskMap = Readonly<Record<never, never>>,
Jobs extends ServiceJobMap = Readonly<Record<never, never>>,
> extends DescriptorMetadata {
readonly id?: Id;
readonly functions?: Functions;
readonly events?: Events;
readonly tasks?: Tasks;
readonly jobs?: Jobs;
}
ServiceDescriptor (type alias)
Frozen service descriptor with identity-preserving public members.
Example
type Orders = ServiceDescriptor<"orders", { lookup: typeof lookup }>;
Signature
type ServiceDescriptor<
Id extends string,
Functions extends ServiceFunctionMap = Readonly<Record<never, never>>,
Events extends ServiceEventMap = Readonly<Record<never, never>>,
Tasks extends ServiceTaskMap = Readonly<Record<never, never>>,
Jobs extends ServiceJobMap = Readonly<Record<never, never>>,
> = DescriptorBase<"service", Id> &
PublicMembers<Functions, Events, Tasks, Jobs> & {
readonly [serviceTypes]: ServiceTypeMembers<Functions, Events, Tasks, Jobs>;
};
ServiceDescriptorAny (type alias)
Service descriptor with an unspecified ID and member set.
Example
function inspect(service: ServiceDescriptorAny) {
return service.id;
}
Signature
type ServiceDescriptorAny = DescriptorBase<"service", string>;
ServiceEventMap (type alias)
Named event members on a service.
Example
type Events = ServiceEventMap;
Signature
type ServiceEventMap = Readonly<Record<string, EventDescriptorAny>>;
ServiceEvents (type alias)
Extracts the event members recorded in a service type.
Example
type Events = ServiceEvents<typeof orders>;
Signature
type ServiceEvents<Service> = Service extends {
readonly [serviceTypes]: { readonly events: infer Events };
}
? Events
: never;
ServiceFunctionMap (type alias)
Named function members on a service.
Example
type Functions = ServiceFunctionMap;
Signature
type ServiceFunctionMap = Readonly<Record<string, FunctionRefAny>>;
ServiceFunctions (type alias)
Extracts the function members recorded in a service type.
Example
type Functions = ServiceFunctions<typeof orders>;
Signature
type ServiceFunctions<Service> = Service extends {
readonly [serviceTypes]: { readonly functions: infer Functions };
}
? Functions
: never;
ServiceJobMap (type alias)
Named job members on a service.
Example
type Jobs = ServiceJobMap;
Signature
type ServiceJobMap = Readonly<Record<string, JobDescriptorAny>>;
ServiceJobs (type alias)
Extracts the job members recorded in a service type.
Example
type Jobs = ServiceJobs<typeof orders>;
Signature
type ServiceJobs<Service> = Service extends {
readonly [serviceTypes]: { readonly jobs: infer Jobs };
}
? Jobs
: never;
ServiceTaskMap (type alias)
Named task members on a service.
Example
type Tasks = ServiceTaskMap;
Signature
type ServiceTaskMap = Readonly<Record<string, TaskDescriptorAny>>;
ServiceTasks (type alias)
Extracts the task members recorded in a service type.
Example
type Tasks = ServiceTasks<typeof orders>;
Signature
type ServiceTasks<Service> = Service extends {
readonly [serviceTypes]: { readonly tasks: infer Tasks };
}
? Tasks
: never;
descriptor-guards.ts
assertServiceDescriptor
Require a valid service descriptor synchronously.
Throws
TypeError when invalid.
Example
assertServiceDescriptor(candidate);
Signature
declare const assertServiceDescriptor: (value: unknown) => asserts value is ServiceDescriptorAny;
assertServiceDescriptorEffect
Require a valid service descriptor in Effect.
Example
Effect.runSync(assertServiceDescriptorEffect(candidate));
Signature
declare const assertServiceDescriptorEffect: (
value: unknown,
) => Effect.Effect<ServiceDescriptorAny, ServiceValidationError, never>;
freezeServiceDescriptor
Validate and freeze a descriptor synchronously.
Throws
TypeError when the descriptor is invalid.
Example
freezeServiceDescriptor(service);
Signature
declare const freezeServiceDescriptor: <T extends ServiceDescriptorAny>(value: T) => T;
freezeServiceDescriptorEffect
Validate and recursively freeze a descriptor in Effect.
Example
Effect.runSync(freezeServiceDescriptorEffect(service));
Signature
declare const freezeServiceDescriptorEffect: <T extends ServiceDescriptorAny>(
value: T,
) => Effect.Effect<T, ServiceValidationError, never>;
isServiceDescriptor
Check a service descriptor synchronously.
Example
isServiceDescriptor(candidate);
Signature
declare const isServiceDescriptor: (value: unknown) => value is ServiceDescriptorAny;
isServiceDescriptorEffect
Check a service descriptor and every public member in Effect.
Example
Effect.runSync(isServiceDescriptorEffect(candidate));
Signature
declare const isServiceDescriptorEffect: (value: unknown) => Effect.Effect<boolean, never, never>;
serviceMemberEntries
Enumerate public descriptor members synchronously.
Example
serviceMemberEntries(service);
Signature
declare const serviceMemberEntries: (service: ServiceDescriptorAny) => [string, unknown][];
serviceMemberEntriesEffect
Enumerate public descriptor members in Effect.
Example
Effect.runSync(serviceMemberEntriesEffect(service));
Signature
declare const serviceMemberEntriesEffect: (
service: ServiceDescriptorAny,
) => Effect.Effect<Array<[string, unknown]>, never, never>;
function-guards.ts
isFunctionDescriptor
Check a function member synchronously.
Example
isFunctionDescriptor(candidate);
Signature
declare const isFunctionDescriptor: (value: unknown) => value is FunctionRefAny;
isFunctionDescriptorEffect
Check a function member’s descriptor contract in Effect.
Example
Effect.runSync(isFunctionDescriptorEffect(candidate));
Signature
declare const isFunctionDescriptorEffect: (value: unknown) => Effect.Effect<boolean, never, never>;
guards.ts
Public guard relay.
“./descriptor-guards.js” (namespace export)
Re-exports all named exports from the “./descriptor-guards.js” module.
Signature
export * from "./descriptor-guards.js";
“./function-guards.js” (namespace export)
Re-exports all named exports from the “./function-guards.js” module.
Signature
export * from "./function-guards.js";
“./member-name.js” (namespace export)
Re-exports all named exports from the “./member-name.js” module.
Signature
export * from "./member-name.js";
“./reference-guards.js” (namespace export)
Re-exports all named exports from the “./reference-guards.js” module.
Signature
export * from "./reference-guards.js";
index.ts
“./define-service.js” (namespace export)
Re-exports all named exports from the “./define-service.js” module.
Signature
export * from "./define-service.js";
“./guards.js” (namespace export)
Re-exports all named exports from the “./guards.js” module.
Signature
export * from "./guards.js";
“./service-context.js” (namespace export)
Re-exports all named exports from the “./service-context.js” module.
Signature
export * from "./service-context.js";
“./service-error.js” (namespace export)
Re-exports all named exports from the “./service-error.js” module.
Signature
export * from "./service-error.js";
“./service-observability.js” (namespace export)
Re-exports all named exports from the “./service-observability.js” module.
Signature
export * from "./service-observability.js";
“./types.js” (namespace export)
Re-exports all named exports from the “./types.js” module.
Signature
export * from "./types.js";
member-name.ts
RESERVED_SERVICE_MEMBER_NAMES
Compatibility alias for the reserved member list.
Signature
declare const RESERVED_SERVICE_MEMBER_NAMES: readonly [
"kind",
"id",
"ref",
"functions",
"events",
"tasks",
"jobs",
"capability",
"title",
"description",
"tags",
"handler",
"constructor",
"prototype",
"__proto__",
];
SERVICE_RESERVED_MEMBER_NAMES
Names disallowed as service members because they collide with descriptor metadata.
Signature
declare const SERVICE_RESERVED_MEMBER_NAMES: readonly [
"kind",
"id",
"ref",
"functions",
"events",
"tasks",
"jobs",
"capability",
"title",
"description",
"tags",
"handler",
"constructor",
"prototype",
"__proto__",
];
assertServiceMemberName
Assert a canonical, nonreserved member name synchronously.
Throws
TypeError for invalid names.
Example
assertServiceMemberName("lookup");
Signature
declare const assertServiceMemberName: (value: unknown) => asserts value is string;
assertServiceMemberNameEffect
Validate one member name with a tagged Effect failure.
Example
Effect.runSync(assertServiceMemberNameEffect("lookup"));
Signature
declare const assertServiceMemberNameEffect: (
value: unknown,
) => Effect.Effect<string, ServiceValidationError, never>;
isReservedServiceMemberName
Check a candidate against the reserved member list.
Example
isReservedServiceMemberName(" id ");
Signature
declare const isReservedServiceMemberName: (value: unknown) => boolean;
isReservedServiceMemberNameEffect
Check whether a candidate is a reserved member name in Effect.
Example
Effect.runSync(isReservedServiceMemberNameEffect("id"));
Signature
declare const isReservedServiceMemberNameEffect: (
value: unknown,
) => Effect.Effect<boolean, never, never>;
normalizeServiceMemberName
Normalize a service member name synchronously.
Throws
TypeError for non-string or empty input.
Example
normalizeServiceMemberName(" lookup ");
Signature
declare const normalizeServiceMemberName: (value: unknown) => string;
normalizeServiceMemberNameEffect
Normalize a service member name inside Effect.
Example
Effect.runSync(normalizeServiceMemberNameEffect("lookup"));
Signature
declare const normalizeServiceMemberNameEffect: (
value: unknown,
) => Effect.Effect<string, ServiceValidationError, never>;
reference-guards.ts
assertServiceRef
Require a service reference synchronously.
Throws
TypeError when invalid.
Example
assertServiceRef(candidate);
Signature
declare const assertServiceRef: (value: unknown) => asserts value is ServiceRefAny;
assertServiceRefEffect
Require a service reference in Effect.
Example
Effect.runSync(assertServiceRefEffect(candidate));
Signature
declare const assertServiceRefEffect: (
value: unknown,
) => Effect.Effect<ServiceRefAny, ServiceValidationError, never>;
isServiceRef
Check a service reference synchronously.
Example
isServiceRef({ ref: createRef("service", "orders") });
Signature
declare const isServiceRef: (value: unknown) => value is ServiceRefAny;
isServiceRefEffect
Check a service reference in Effect.
Example
Effect.runSync(isServiceRefEffect({ ref: createRef("service", "orders") }));
Signature
declare const isServiceRefEffect: (value: unknown) => Effect.Effect<boolean, never, never>;
reference-guards.types.ts
ServiceRef (interface)
A stable reference to one service descriptor.
Example
const ref: ServiceRef<"orders"> = { ref: createRef("service", "orders") };
Signature
export interface ServiceRef<Id extends string = string> {
readonly ref: Ref<"service", Id>;
}
ServiceRefAny (type alias)
Any service reference regardless of its stable ID.
Example
function inspect(value: ServiceRefAny) {
return value.ref.id;
}
Signature
type ServiceRefAny = ServiceRef;
service-context.ts
freezeServiceContextValue
Copy and freeze a plain service context graph synchronously.
Throws
When a proxy or getter prevents graph inspection.
Example
freezeServiceContextValue({ enabled: true }, new WeakMap());
Signature
declare const freezeServiceContextValue: (value: unknown, seen: WeakMap<object, object>) => unknown;
freezeServiceContextValueEffect
Copy and freeze a plain service context graph, preserving cycles and identity.
Example
Effect.runSync(freezeServiceContextValueEffect({ enabled: true }, new WeakMap()));
Signature
declare const freezeServiceContextValueEffect: (
value: unknown,
seen: WeakMap<object, object>,
) => Effect.Effect<unknown, never, never>;
service-error.ts
ServiceValidationError (class)
Expected malformed service input or dependency rejection in an Effect operation.
Example
Effect.catchTag(defineServiceEffect(input), "ServiceValidationError", () => Effect.void);
Signature
declare class ServiceValidationError
service-members.ts
assertUniqueServiceMembersEffect
Reject member names appearing in more than one category.
Example
Effect.runSync(assertUniqueServiceMembersEffect({ lookup }, {}));
Signature
declare const assertUniqueServiceMembersEffect: (
...args: Array<any>
) => Effect.Effect<undefined, ServiceValidationError, never>;
copyServiceMembersEffect
Copy and validate one category of service members in insertion order.
Example
Effect.runSync(copyServiceMembersEffect({ lookup }, isFunctionDescriptorEffect, "function"));
Signature
declare const copyServiceMembersEffect: <T>(
value: Readonly<Record<string, T>> | undefined,
validate: ServiceMemberValidator<T>,
kind: ServiceMemberKind,
) => Effect.Effect<Record<string, T>, ServiceValidationError, never>;
service-members.types.ts
ServiceMemberKind (type alias)
Kinds accepted by service authoring.
Example
const kind: ServiceMemberKind = "function";
Signature
type ServiceMemberKind = "function" | "event" | "task" | "job";
ServiceMemberValidator (type alias)
Predicate for one member category during Effect validation.
Example
const valid: ServiceMemberValidator<number> = (value) => Effect.succeed(typeof value === "number");
Signature
type ServiceMemberValidator<T> = (value: unknown) => Effect.Effect<boolean>;
service-observability.ts
ServiceTelemetry (class)
Substitutable telemetry for all service operations.
Example
Effect.provide(isServiceRefEffect(value), ServiceTelemetryLive);
Signature
declare class ServiceTelemetry
ServiceTelemetryLive
Live span, call, duration, and failure instrumentation.
Example
Effect.provide(isServiceRefEffect(value), ServiceTelemetryLive);
Signature
declare const ServiceTelemetryLive: Layer.Layer<ServiceTelemetry, never, never>;
observeService
Observe one service operation using an injected or live observer.
Example
observeService("ref.is", Effect.succeed(true));
Signature
declare const observeService: <A, E, R>(
operation: ServiceOperation,
effect: Effect.Effect<A, E, R>,
) => Effect.Effect<A, E, R>;
runServiceSync
Run a dependency-free Effect for a synchronous compatibility caller.
Throws
TypeError for local validation, an original dependency error, or a defect.
Example
runServiceSync(Effect.succeed(1));
Signature
declare const runServiceSync: <A, E>(effect: Effect.Effect<A, E>) => A;
service-observability.types.ts
ServiceOperation (type alias)
Fixed service operation labels keep telemetry dimensions bounded.
Example
const operation: ServiceOperation = "descriptor.is";
Signature
type ServiceOperation =
| "define"
| "members.copy"
| "members.unique"
| "member.normalize"
| "member.is-reserved"
| "member.assert"
| "ref.is"
| "ref.assert"
| "descriptor.is"
| "descriptor.assert"
| "descriptor.freeze"
| "descriptor.entries"
| "function.is"
| "context.freeze";
ServiceTelemetryService (interface)
Injectable observation boundary for service operations.
Example
const telemetry: ServiceTelemetryService = { observe: (_, effect) => effect };
Signature
export interface ServiceTelemetryService {
/** Observe one operation while preserving its channels.
* @param operation - Fixed operation label.
* @param effect - Operation to measure.
* @returns The observed Effect with unchanged success and error channels.
* @example telemetry.observe("ref.is", Effect.succeed(true));
*/
readonly observe: <A, E, R>(
operation: ServiceOperation,
effect: Effect.Effect<A, E, R>,
) => Effect.Effect<A, E, R>;
}
types.ts
Public declaration relay retained for package source compatibility.
“./define-service.types.js” (namespace export)
Re-exports all named exports from the “./define-service.types.js” module.
Signature
export * from "./define-service.types.js";
“./reference-guards.types.js” (namespace export)
Re-exports all named exports from the “./reference-guards.types.js” module.
Signature
export * from "./reference-guards.types.js";