@serve.zone/dcrouter-apiclient
@serve.zone/dcrouter-apiclient
@serve.zone/dcrouter-apiclient is the object-oriented TypeScript client for the dcrouter OpsServer API. It wraps /typedrequest calls in managers, builders, and resource classes for routes, certificates, API tokens, remote ingress, email, stats, config, logs, RADIUS, and gateway-client integrations.
It is the client half of dcrouter without the server: installing it does not pull the runtime, the dashboard, the database client or a native password hasher. It ships the shared contracts alongside the client under the ./interfaces subpath, so a consumer that only reads request and data types never needs @serve.zone/dcrouter either.
Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.
Install
pnpm add @serve.zone/dcrouter-apiclient
Two entry points:
import { DcRouterApiClient } from '@serve.zone/dcrouter-apiclient';
import { data, requests } from '@serve.zone/dcrouter-apiclient/interfaces';
The same client and contracts remain available as subpaths of the server package for consumers that already depend on it:
import { DcRouterApiClient } from '@serve.zone/dcrouter/apiclient';
import { data, requests } from '@serve.zone/dcrouter/interfaces';
Platform support
This package installs on Linux x64 and arm64 only. Several contract members are typed against @push.rocks/smartmta, @push.rocks/smartproxy and @push.rocks/smartnetwork, so those packages are dependencies even though the imports are type-only, and @push.rocks/smartmta declares os: ["linux"] with cpu: ["x64", "arm64"]. Installing anywhere else fails with ERR_PNPM_UNSUPPORTED_PLATFORM. @serve.zone/dcrouter carries the same constraint today, so this is not a new restriction — but it does mean the client cannot yet be installed on a macOS or Windows developer machine.
The restriction is upstream and no change here lifts it. It goes away once @push.rocks/smartproxy, @push.rocks/smartmta and @push.rocks/smartnetwork move their Rust payloads into per-platform optional packages; today each of the three ships both the amd64 and the arm64 binary in one tarball and declares no macOS or Windows build.
Quick Start
import { DcRouterApiClient } from '@serve.zone/dcrouter-apiclient';
const client = new DcRouterApiClient({
baseUrl: 'https://dcrouter.example.com',
});
await client.login('admin@example.com', 'strong-password');
const { routes, warnings } = await client.routes.list();
console.log(routes.length, warnings.length);
const route = await client.routes.build()
.setName('api-gateway')
.setMatch({ ports: 443, domains: ['api.example.com'] })
.setAction({ type: 'forward', targets: [{ host: '127.0.0.1', port: 8080 }] })
.save();
await route.toggle(true);
Authentication
The client supports persisted-admin session login and API-token authentication. Initial admin creation is a bootstrap flow exposed by the Ops dashboard and raw TypedRequest contracts; after a persisted admin exists, use that account with login().
const sessionClient = new DcRouterApiClient({
baseUrl: 'https://dcrouter.example.com',
});
await sessionClient.login('admin@example.com', 'strong-password');
const tokenClient = new DcRouterApiClient({
baseUrl: 'https://dcrouter.example.com',
apiToken: 'dcr_token_value',
});
baseUrl is normalized by removing trailing slashes. Ordinary requests are sent to ${baseUrl}/typedrequest; log streams use a dedicated TypedSocket connection. buildRequestPayload() injects the current identity and optional API token for manager methods.
Manager Map
| Manager | Purpose |
|---|---|
client.routes |
List merged routes, build/update/delete ordinary operator routes, and toggle routes. |
client.certificates |
Inspect certificate summaries and trigger certificate operations. |
client.apiTokens |
Create, list, toggle, roll, and revoke API tokens. |
client.remoteIngress |
Manage edge registrations, statuses, ports, tags, and connection tokens. |
client.emails |
Inspect received/cached email items and trigger resend flows. |
client.gatewayClients |
Manage gateway-client route, DNS, and domain integration calls. |
client.stats |
Read health, counters, summaries, and runtime status. |
client.config |
Read the current configuration view. |
client.logs |
Read recent logs or receive a live log stream. |
client.radius |
Manage RADIUS clients, VLAN mappings, and accounting sessions. |
Log Streams
Log streaming requires a dcrouter server using TypedSocket 8. Each stream owns
one connection, which is released when the stream closes or aborts. Access needs
logs:read and is revalidated on the same physical peer during streaming.
try {
const { logStream } = await client.logs.getStream({ follow: false });
try {
await logStream.opened;
const decoder = new TextDecoder();
for (;;) {
const chunk = await logStream.receive();
if (chunk === undefined) break;
console.log(JSON.parse(decoder.decode(chunk)));
}
await logStream.accept();
} catch (error) {
await logStream.abort(error);
throw error;
}
} finally {
await client.stop();
}
Use follow: true for ongoing logs and call logStream.abort() when finished,
including when no entries are arriving. Await each receive to apply backpressure.
client.logs.close() closes current streams while allowing a later session;
client.stop() permanently closes log streaming on that client instance.
Logout closes current streams and permits a later login.
Route Builder
const route = await client.routes.build()
.setName('internal-app')
.setMatch({
ports: 443,
domains: ['internal.example.com'],
})
.setAction({
type: 'forward',
targets: [{ host: '127.0.0.1', port: 3000 }],
})
.setEnabled(true)
.save();
await route.update({
action: {
type: 'forward',
targets: [{ host: '127.0.0.1', port: 3001 }],
},
});
System routes from config, email, and dns origins are designed to be toggled, not edited. Generic create/update/delete behavior is for ordinary operator-owned routes with origin api. API-origin routes carrying managed ownership metadata, including gateway-client routes and HTTP-01 Special Forwards, must be changed through their owning specialized TypedRequest workflow; client.routes does not bypass that protection.
API Tokens and Remote Ingress
const token = await client.apiTokens.build()
.setName('automation')
.setScopes(['routes:read', 'routes:write'])
.setExpiresInDays(30)
.save();
const edge = await client.remoteIngress.build()
.setName('edge-eu-1')
.setListenPorts([80, 443])
.setAutoDerivePorts(true)
.setEgress({
enabled: true,
allowedPorts: [25],
allowedHostPatterns: ['*.example.com'],
maxConcurrentStreams: 100,
})
.setTags(['production', 'eu'])
.save();
const connectionToken = await edge.getConnectionToken();
console.log(token.tokenValue, connectionToken);
RemoteIngress resources expose performance and egress fields. create() and update() accept the same fields as the builder. Egress is default-disabled; dcrouter currently accepts outbound SMTP egress on port 25 only.
What This Package Is Not
- It does not start dcrouter.
- It does not serve or bundle the Ops dashboard.
- It does not replace the raw dcrouter-local TypedRequest contracts under
@serve.zone/dcrouter-apiclient/interfaceswhen you want to talk to/typedrequestyourself.
Use @serve.zone/dcrouter for the server runtime. The canonical machine-facing gateway client route, DNS, and domain contracts used by client.gatewayClients come from @serve.zone/interfaces.
Development
This folder is published from the dcrouter monorepo through its tspublish.json, which also owns ts_interfaces and exposes it as the ./interfaces subpath. Both folders keep the build order they always had (ts_interfaces first, then ts_apiclient). See ../ts_interfaces/readme.md for the contract surface. gitzone release publishes this package in the same release as @serve.zone/dcrouter and the Docker images, at the same version and before the runtime package.
Useful source entry points:
index.tsexports the public client surface.classes.dcrouterapiclient.tsowns authentication and request dispatch.classes.route.tsowns route resources and builders.classes.remoteingress.ts,classes.apitoken.ts,classes.radius.ts, and the other manager files wrap focused API domains.
License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the license file.
Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
Company Information
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.