Overview
The Effect entry has the same route tree and transport as the promise client. Calls return Effect<A, Dalp instead of Promise<A>, where Code is the union of error codes that operation can return. Interrupting a fibre aborts a request that uses the client-provided signal.
import { createDalpEffectClient } from "@settlemint/dalp-sdk/effect";
import * as Effect from "effect/Effect";
const dalp = createDalpEffectClient({
baseUrl: process.env.DALP_API_URL!,
apiKey: process.env.DALP_API_KEY!,
runtime: "server",
});
const program = Effect.gen(function* () {
const tokens = yield* dalp.api.token.list({ page: { limit: 50 } });
return tokens.data;
});
const rows = await Effect.runPromise(program);effect is an optional peer dependency, and this entry supports Effect 4. Install the latest Effect 4 release only if you use this entry.
npm install effect@4Why it is a separate entry
The root package does not import Effect. Import @settlemint/ when your application uses Effect.
The failure channel
Every call fails with one type, DalpRequestError<Code>, carrying the platform's error contract. Let the compiler infer the type from the call so Code stays the operation's own codes:
const program = dalp.api.token
.list({ page: { limit: 50 } })
.pipe(Effect.retry({ times: 3, while: (error) => error.retryable }));A bare DalpRequestError types code as the union of every published API and SDK error code (DalpApiErrorCode), never plain string. Each route's own call narrows it further to the error codes that route declares. A failure that never reaches a declared response, such as a network error, carries an SDK code like sdk. that the route's type does not list, so branch on error.retryable for those and keep the operation's inferred error type instead of annotating a bare DalpRequestError.
Branch on error.id for domain handling and on error.retryable for retry policy. Success responses are checked at runtime as well as typed: a body that does not match the route's schema fails with sdk. instead of arriving as a value the type promises.
Interruption
Interrupting a fibre aborts the request. The abort controller is wired to the fibre rather than handed to you, so a cancelled fibre does not leave a socket open:
import * as Fiber from "effect/Fiber";
const program = Effect.gen(function* () {
const fiber = yield* Effect.forkChild(dalp.api.token.list({ page: { limit: 50 } }));
yield* Effect.sleep("2 seconds");
yield* Fiber.interrupt(fiber); // the HTTP request is aborted
});If you pass your own signal, manage its cancellation yourself.
Composition
Concurrency, retry, and timeout are Effect's, not the SDK's:
const program = Effect.gen(function* () {
const [tokens, users] = yield* Effect.all(
[dalp.api.token.list({ page: { limit: 50 } }), dalp.api.party.users.list({ page: { limit: 50 } })],
{
concurrency: 2,
}
);
return { tokens: tokens.data, users: users.data };
});dalp.api.token
.list({ page: { limit: 50 } })
.pipe(
Effect.timeout("5 seconds"),
Effect.retry({ times: 3, while: (error) => error._tag === "TimeoutError" || error.retryable })
);An Effect.timeout around a call interrupts it, which aborts the request. That composes correctly with settlement: a queue-backed write interrupted mid-wait stops waiting, and the instruction it submitted stays live on the platform exactly as it would if the platform's own wait had run out and answered with a 202 handle. Interrupting the wait is not cancelling the transaction.
Route ids
Dispatch by id, for code that builds its own command surface:
const program = dalp.execute("token/list", { page: { limit: 50 } });An unknown id fails with a DalpRequestError in the error channel rather than throwing, so the failure stays in the type system with every other failure.
What is the same
The Effect client matches the promise client in the flat argument split, the response envelope, settlement, the acting-context headers and the per-call options, and the pages on the promise surface document each of them once.
The Effect client differs in what the call hands back and in what it leaves out: it exposes only api and execute, with no conditionalRequests handle and no sendParts, streamParts or downloadParts. An Effect program that switches organisation or participant therefore builds a new client rather than clearing held tags.
A streaming route returns an effect that succeeds at once with the async iterable of frames. The request opens on the first iteration, so a refusal or a stream failure is thrown as a DalpApiError while you iterate, not in the effect's error channel. Break out of the loop, or abort a signal you pass, to close the stream.
Next
Command-line access to the same routes: CLI.