SDK
Package: @dip/sdk. The client wraps the protocol packages. It is the recommended entry point for applications.
The complete example is examples/sdk-quickstart.mjs.
Create a client
import { DipClient } from "@dip/sdk";
const client = new DipClient({
trustRoots: [
/* public keys: issuer, engine, evidence, approvers */
],
engine: { keyId: "engine-1", privateKey }, // signs decisions
evidenceSigner: { keyId: "evidence-1", privateKey }, // signs evidence
connectors: new Map([["payment.create", connector]]), // operation → connector
now: () => new Date(), // injected clock
maxDecisionAgeSeconds: 300, // optional
executionTimeoutMs: 5000, // optional
eventLog, // optional: durable journal
});trustRoots is the only source of trust. Nothing in a declaration, request or bundle can add a key.
For durable state, use DipClient.open(config) with an eventLog. It replays the journal and refuses to start if the stored evidence chain does not verify.
Authority
const declaration = client.createAuthorityDeclaration({
/* fields: see docs/spec/03 */
});
client.publishAuthority(signAuthority(declaration, issuerPrivateKey));
client.revokeAuthority(
signRevocation({ authorityId, version, revokedAt, signingKeyId }, issuerPrivateKey),
);
client.getAuthority(authorityId, version);
client.latestAuthorityVersion(authorityId);Publication fails for a bad signature, an unknown or revoked key, a tampered body, or a version that is already published or skips a number.
Authorize
const request = client.normalizeRequest(rawRequest); // canonical body + digest; rejects ambiguous input
const { result, decision } = client.authorize(request);
// result is exactly "ALLOW" or "DENY". Nothing else is returned.authorize never executes anything. Reason codes are in decision.body.reasonCodes.
Approvals
Approvals have their own states (PENDING, APPROVED, REJECTED, EXPIRED, REVOKED). These are not authorization results.
client.requestApproval({ approvalId, organizationId, requestDigest, authorityRef, policyRef,
approverKeyId, requestedAt, expiresAt });
client.approve(signApprovalDecision({ approvalId, action: "APPROVE", approverKeyId, decidedAt }, approverPrivateKey));
client.reject(...); // action REJECT
client.revokeApproval(...); // action REVOKE
client.approvalStatus(approvalId);After an approval, call authorize again. Only the new decision permits execution.
Execute and record
const attempt = await client.execute(request, decision);
// attempt.state: SUCCEEDED, FAILED, TIMED_OUT, REFUSED or DUPLICATE
client.record({ normalized: request, decision, attempt }); // evidence for every attemptexecute re-checks the authority and any approval at execution time. A refused attempt is still recorded as evidence.
Verify
client.verifyLedger(expectedHead); // this client's ledger
client.verifyBundle(bundle); // an exported bundle, against this client's trust rootsexpectedHead is a head recorded outside the system. Without it, a truncated tail cannot be detected.
Read evidence
client.ledgerSize();
client.ledgerHead();
client.ledgerLines(); // canonical lines, in order
client.findEvidence(evidenceId);
client.evidenceAt(index);Errors
Errors are DipError instances with a stable code (see spec 16). Match on code, not on the message.
import { DipError } from "@dip/sdk";
try {
client.publishAuthority(input);
} catch (err) {
if (err instanceof DipError && err.code === "AUTHORITY_SIGNATURE_INVALID") {
/* … */
}
}Stability
The SDK follows the protocol version (1.0). Breaking changes require a new protocol version and an entry in CHANGELOG.md.