@mnd8t/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Glencorse Ltd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # @mnd8t/sdk
2
+
3
+ A typed TypeScript client for the [mnd8t](https://mnd8t.com) authority API.
4
+
5
+ mnd8t decides whether a proposed financial action falls within authority you
6
+ defined, and records signed evidence of that decision. It holds no funds, no
7
+ payment credentials and no private keys — you, or a provider you choose,
8
+ execute every action.
9
+
10
+ No runtime dependencies. Node 22 or newer.
11
+
12
+ ```bash
13
+ npm install @mnd8t/sdk
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ```ts
19
+ import { MandateClient } from "@mnd8t/sdk";
20
+
21
+ const mandate = new MandateClient({
22
+ apiKey: process.env.MANDATE_API_KEY!,
23
+ baseUrl: "https://api.mnd8t.com",
24
+ });
25
+
26
+ const decision = await mandate.decisions.create({
27
+ agent_external_id: "procurement_agent_12",
28
+ amount_minor: 50_000,
29
+ policy_currency: "GBP",
30
+ asset: "USDC",
31
+ counterparty_external_id: "supplier_acme_cloud",
32
+ purpose: "cloud_infrastructure",
33
+ });
34
+
35
+ if (decision.effective_decision === "APPROVE") {
36
+ // Execute with your own credentials, then confirm.
37
+ }
38
+ ```
39
+
40
+ Every decision returns `APPROVE`, `REJECT` or `ESCALATE` with a rule-by-rule
41
+ trace, and produces an Ed25519-signed, hash-chained evidence receipt you can
42
+ verify without calling us — `verifyReceiptSignature` is exported for exactly
43
+ that.
44
+
45
+ ## Documentation
46
+
47
+ - [SDK reference](https://mnd8t.com/docs/sdk) — every method, type and error
48
+ - [Quickstart](https://mnd8t.com/docs/quickstart) — first decision in under 30 minutes
49
+ - [Developer guide](https://mnd8t.com/docs/developer-guide) — the full integration path
50
+ - [Evidence receipts](https://mnd8t.com/docs/evidence-receipts) — format and verification
51
+
52
+ ## Support
53
+
54
+ mnd8t is in early access. Speak to your account contact, or report a security
55
+ issue under the [responsible disclosure
56
+ policy](https://mnd8t.com/legal/responsible-disclosure).
57
+
58
+ ## Licence
59
+
60
+ MIT © Glencorse Ltd
@@ -0,0 +1,122 @@
1
+ import type { Agent, AuthorizeRequest, AuthorizeResponse, ConfirmRequest, Counterparty, CounterpartyAuthorityStatus, CreateAgentRequest, CreateCounterpartyRequest, CreateMandateRequest, EvidenceReceiptEnvelope, Mandate, PublishMandateOptions, PublishResult } from "./types.js";
2
+ export interface MandateClientOptions {
3
+ apiKey: string;
4
+ /** Defaults to the hosted sandbox; point at http://localhost:4000 locally. */
5
+ baseUrl?: string;
6
+ /** Request timeout in milliseconds (default 15000). */
7
+ timeoutMs?: number;
8
+ /** Retries for idempotent requests on network failure / 5xx (default 2). */
9
+ maxRetries?: number;
10
+ fetch?: typeof fetch;
11
+ }
12
+ export declare class MandateClient {
13
+ private readonly apiKey;
14
+ private readonly baseUrl;
15
+ private readonly timeoutMs;
16
+ private readonly maxRetries;
17
+ private readonly fetchImpl;
18
+ constructor(options: MandateClientOptions);
19
+ private request;
20
+ readonly agents: {
21
+ create: (body: CreateAgentRequest) => Promise<Agent>;
22
+ list: () => Promise<{
23
+ data: Agent[];
24
+ }>;
25
+ get: (id: string) => Promise<Agent>;
26
+ };
27
+ readonly counterparties: {
28
+ create: (body: CreateCounterpartyRequest) => Promise<Counterparty>;
29
+ list: () => Promise<{
30
+ data: Counterparty[];
31
+ }>;
32
+ update: (id: string, body: {
33
+ authority_status?: CounterpartyAuthorityStatus;
34
+ metadata?: Record<string, unknown>;
35
+ }) => Promise<Counterparty>;
36
+ };
37
+ readonly mandates: {
38
+ create: (body: CreateMandateRequest) => Promise<Mandate>;
39
+ /**
40
+ * Publishes the draft version, freezing it. Requires a delegator
41
+ * attestation: whoever publishes asserts they hold the authority being
42
+ * delegated. mnd8t records the assertion as evidence — it does not
43
+ * verify that the authority legally exists.
44
+ */
45
+ publish: (mandateId: string, options: PublishMandateOptions) => Promise<PublishResult>;
46
+ revoke: (mandateId: string) => Promise<Record<string, unknown>>;
47
+ simulate: (mandateId: string, body: {
48
+ amount_minor: number;
49
+ asset: string;
50
+ counterparty_external_id?: string;
51
+ purpose?: string;
52
+ at?: string;
53
+ }) => Promise<{
54
+ would_decide: string;
55
+ reason_codes: string[];
56
+ }>;
57
+ get: (id: string) => Promise<Mandate & {
58
+ versions: unknown[];
59
+ }>;
60
+ list: () => Promise<{
61
+ data: Mandate[];
62
+ }>;
63
+ };
64
+ readonly decisions: {
65
+ /**
66
+ * Submits a proposed financial action. Generates an idempotency key
67
+ * automatically (override with `idempotencyKey`), which also makes the
68
+ * request safely retryable.
69
+ */
70
+ authorize: (body: AuthorizeRequest) => Promise<AuthorizeResponse>;
71
+ confirm: (intentId: string, body: ConfirmRequest) => Promise<Record<string, unknown>>;
72
+ cancel: (intentId: string, reason?: string) => Promise<Record<string, unknown>>;
73
+ get: (intentId: string) => Promise<Record<string, unknown>>;
74
+ list: (params?: {
75
+ status?: string;
76
+ decision?: string;
77
+ limit?: number;
78
+ }) => Promise<{
79
+ data: unknown[];
80
+ }>;
81
+ };
82
+ readonly artifacts: {
83
+ get: (artifactId: string) => Promise<import("./types.js").AuthorisationArtifactEnvelope>;
84
+ /** Atomically claims the artifact for one executor; single use. */
85
+ claim: (artifactId: string, executorReference: string) => Promise<{
86
+ id: string;
87
+ status: string;
88
+ artifact: Record<string, unknown>;
89
+ }>;
90
+ fail: (artifactId: string, reasonCode: string) => Promise<{
91
+ id: string;
92
+ status: string;
93
+ }>;
94
+ reissue: (intentId: string) => Promise<import("./types.js").AuthorisationArtifactSummary>;
95
+ /** Verifies the artifact's Ed25519 signature locally, like receipts. */
96
+ verify: (artifact: Record<string, unknown>, opts?: {
97
+ publicKeyPem?: string;
98
+ }) => Promise<{
99
+ valid: boolean;
100
+ reason: string | null;
101
+ }>;
102
+ };
103
+ readonly receipts: {
104
+ get: (receiptId: string) => Promise<EvidenceReceiptEnvelope>;
105
+ /** Server-side verification. */
106
+ verifyRemote: (receiptId: string) => Promise<{
107
+ valid: boolean;
108
+ reason: string | null;
109
+ }>;
110
+ /**
111
+ * Independent local verification: fetches the public key from the
112
+ * gateway's well-known document (or accepts a pinned PEM) and checks the
113
+ * Ed25519 signature locally.
114
+ */
115
+ verify: (receipt: Record<string, unknown>, opts?: {
116
+ publicKeyPem?: string;
117
+ }) => Promise<{
118
+ valid: boolean;
119
+ reason: string | null;
120
+ }>;
121
+ };
122
+ }
package/dist/client.js ADDED
@@ -0,0 +1,158 @@
1
+ import { errorFromResponse, MandateError } from "./errors.js";
2
+ import { verifyReceiptSignature } from "./verify.js";
3
+ function randomIdempotencyKey() {
4
+ const bytes = new Uint8Array(16);
5
+ crypto.getRandomValues(bytes);
6
+ return `sdk-${Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("")}`;
7
+ }
8
+ export class MandateClient {
9
+ apiKey;
10
+ baseUrl;
11
+ timeoutMs;
12
+ maxRetries;
13
+ fetchImpl;
14
+ constructor(options) {
15
+ if (!options.apiKey)
16
+ throw new Error("MandateClient requires an apiKey");
17
+ this.apiKey = options.apiKey;
18
+ this.baseUrl = (options.baseUrl ?? "http://localhost:4000").replace(/\/$/, "");
19
+ this.timeoutMs = options.timeoutMs ?? 15_000;
20
+ this.maxRetries = options.maxRetries ?? 2;
21
+ this.fetchImpl = options.fetch ?? fetch;
22
+ }
23
+ async request(method, path, opts = {}) {
24
+ // Safe automatic retries: GETs always; writes only when the caller's
25
+ // idempotency key makes the replay safe.
26
+ const retryable = opts.retryable ?? method === "GET";
27
+ const attempts = retryable ? this.maxRetries + 1 : 1;
28
+ let lastError;
29
+ for (let attempt = 0; attempt < attempts; attempt++) {
30
+ try {
31
+ // Only declare a JSON content type when a body is actually sent.
32
+ // Servers reject `content-type: application/json` with an empty
33
+ // body, which would break every bodyless POST (revoke, reissue).
34
+ const hasBody = opts.body !== undefined;
35
+ const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
36
+ method,
37
+ headers: {
38
+ authorization: `Bearer ${this.apiKey}`,
39
+ ...(hasBody ? { "content-type": "application/json" } : {}),
40
+ ...(opts.idempotencyKey ? { "idempotency-key": opts.idempotencyKey } : {}),
41
+ },
42
+ ...(hasBody ? { body: JSON.stringify(opts.body) } : {}),
43
+ signal: AbortSignal.timeout(this.timeoutMs),
44
+ });
45
+ const text = await res.text();
46
+ const json = text ? JSON.parse(text) : null;
47
+ if (res.status >= 200 && res.status < 300)
48
+ return json;
49
+ if (res.status >= 500 && attempt < attempts - 1) {
50
+ lastError = errorFromResponse(res.status, json);
51
+ continue;
52
+ }
53
+ throw errorFromResponse(res.status, json);
54
+ }
55
+ catch (err) {
56
+ if (err instanceof MandateError)
57
+ throw err;
58
+ lastError = err;
59
+ if (attempt >= attempts - 1)
60
+ break;
61
+ }
62
+ }
63
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
64
+ }
65
+ agents = {
66
+ create: (body) => this.request("POST", "/v1/agents", { body }),
67
+ list: () => this.request("GET", "/v1/agents"),
68
+ get: (id) => this.request("GET", `/v1/agents/${id}`),
69
+ };
70
+ counterparties = {
71
+ create: (body) => this.request("POST", "/v1/counterparties", { body }),
72
+ list: () => this.request("GET", "/v1/counterparties"),
73
+ update: (id, body) => this.request("PATCH", `/v1/counterparties/${id}`, { body }),
74
+ };
75
+ mandates = {
76
+ create: (body) => this.request("POST", "/v1/mandates", { body }),
77
+ /**
78
+ * Publishes the draft version, freezing it. Requires a delegator
79
+ * attestation: whoever publishes asserts they hold the authority being
80
+ * delegated. mnd8t records the assertion as evidence — it does not
81
+ * verify that the authority legally exists.
82
+ */
83
+ publish: (mandateId, options) => this.request("POST", `/v1/mandates/${mandateId}/publish`, {
84
+ body: {
85
+ change_note: options.changeNote,
86
+ delegation: {
87
+ delegator_role: options.delegation.delegatorRole,
88
+ authority_source: options.delegation.authoritySource,
89
+ source_reference: options.delegation.sourceReference,
90
+ attested: true,
91
+ },
92
+ },
93
+ }),
94
+ revoke: (mandateId) => this.request("POST", `/v1/mandates/${mandateId}/revoke`),
95
+ simulate: (mandateId, body) => this.request("POST", `/v1/mandates/${mandateId}/simulate`, { body }),
96
+ get: (id) => this.request("GET", `/v1/mandates/${id}`),
97
+ list: () => this.request("GET", "/v1/mandates"),
98
+ };
99
+ decisions = {
100
+ /**
101
+ * Submits a proposed financial action. Generates an idempotency key
102
+ * automatically (override with `idempotencyKey`), which also makes the
103
+ * request safely retryable.
104
+ */
105
+ authorize: (body) => {
106
+ const { idempotencyKey, ...payload } = body;
107
+ return this.request("POST", "/v1/decision-intents", {
108
+ body: payload,
109
+ idempotencyKey: idempotencyKey ?? randomIdempotencyKey(),
110
+ retryable: true,
111
+ });
112
+ },
113
+ confirm: (intentId, body) => this.request("POST", `/v1/decision-intents/${intentId}/confirm`, { body }),
114
+ cancel: (intentId, reason) => this.request("POST", `/v1/decision-intents/${intentId}/cancel`, { body: { reason } }),
115
+ get: (intentId) => this.request("GET", `/v1/decision-intents/${intentId}`),
116
+ list: (params = {}) => {
117
+ const qs = new URLSearchParams(Object.entries(params).filter(([, v]) => v !== undefined)).toString();
118
+ return this.request("GET", `/v1/decision-intents${qs ? `?${qs}` : ""}`);
119
+ },
120
+ };
121
+ artifacts = {
122
+ get: (artifactId) => this.request("GET", `/v1/authorisation-artifacts/${artifactId}`),
123
+ /** Atomically claims the artifact for one executor; single use. */
124
+ claim: (artifactId, executorReference) => this.request("POST", `/v1/authorisation-artifacts/${artifactId}/claim`, {
125
+ body: { executor_reference: executorReference },
126
+ idempotencyKey: randomIdempotencyKey(),
127
+ }),
128
+ fail: (artifactId, reasonCode) => this.request("POST", `/v1/authorisation-artifacts/${artifactId}/fail`, {
129
+ body: { reason_code: reasonCode, reported_by: "CUSTOMER_EXECUTOR" },
130
+ }),
131
+ reissue: (intentId) => this.request("POST", `/v1/decision-intents/${intentId}/reissue-artifact`),
132
+ /** Verifies the artifact's Ed25519 signature locally, like receipts. */
133
+ verify: async (artifact, opts = {}) => this.receipts.verify(artifact, opts),
134
+ };
135
+ receipts = {
136
+ get: (receiptId) => this.request("GET", `/v1/evidence-receipts/${receiptId}`),
137
+ /** Server-side verification. */
138
+ verifyRemote: (receiptId) => this.request("GET", `/v1/evidence-receipts/${receiptId}/verify`),
139
+ /**
140
+ * Independent local verification: fetches the public key from the
141
+ * gateway's well-known document (or accepts a pinned PEM) and checks the
142
+ * Ed25519 signature locally.
143
+ */
144
+ verify: async (receipt, opts = {}) => {
145
+ let pem = opts.publicKeyPem;
146
+ if (!pem) {
147
+ const res = await this.fetchImpl(`${this.baseUrl}/.well-known/mandate-keys.json`);
148
+ const doc = (await res.json());
149
+ const keyId = receipt.signature?.key_id;
150
+ pem = (doc.keys.find((k) => k.key_id === keyId) ?? doc.keys[0])?.public_key_pem;
151
+ }
152
+ if (!pem)
153
+ return { valid: false, reason: "no verification key available" };
154
+ return verifyReceiptSignature(receipt, pem);
155
+ },
156
+ };
157
+ }
158
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export declare class MandateError extends Error {
2
+ readonly status: number;
3
+ readonly code: string;
4
+ readonly details?: unknown | undefined;
5
+ constructor(status: number, code: string, message: string, details?: unknown | undefined);
6
+ }
7
+ export declare class MandateAuthenticationError extends MandateError {
8
+ }
9
+ export declare class MandateValidationError extends MandateError {
10
+ }
11
+ export declare class MandateIdempotencyConflictError extends MandateError {
12
+ }
13
+ export declare class MandateRateLimitError extends MandateError {
14
+ }
15
+ export declare class MandateNotFoundError extends MandateError {
16
+ }
17
+ export declare function errorFromResponse(status: number, body: unknown): MandateError;
package/dist/errors.js ADDED
@@ -0,0 +1,45 @@
1
+ export class MandateError extends Error {
2
+ status;
3
+ code;
4
+ details;
5
+ constructor(status, code, message, details) {
6
+ super(message);
7
+ this.status = status;
8
+ this.code = code;
9
+ this.details = details;
10
+ this.name = "MandateError";
11
+ }
12
+ }
13
+ export class MandateAuthenticationError extends MandateError {
14
+ }
15
+ export class MandateValidationError extends MandateError {
16
+ }
17
+ export class MandateIdempotencyConflictError extends MandateError {
18
+ }
19
+ export class MandateRateLimitError extends MandateError {
20
+ }
21
+ export class MandateNotFoundError extends MandateError {
22
+ }
23
+ export function errorFromResponse(status, body) {
24
+ const err = body?.error;
25
+ const code = err?.code ?? "UNKNOWN";
26
+ const message = err?.message ?? `HTTP ${status}`;
27
+ const details = err?.details;
28
+ switch (status) {
29
+ case 401:
30
+ return new MandateAuthenticationError(status, code, message, details);
31
+ case 404:
32
+ return new MandateNotFoundError(status, code, message, details);
33
+ case 409:
34
+ return code === "IDEMPOTENCY_CONFLICT"
35
+ ? new MandateIdempotencyConflictError(status, code, message, details)
36
+ : new MandateError(status, code, message, details);
37
+ case 422:
38
+ return new MandateValidationError(status, code, message, details);
39
+ case 429:
40
+ return new MandateRateLimitError(status, code, message, details);
41
+ default:
42
+ return new MandateError(status, code, message, details);
43
+ }
44
+ }
45
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,YAAa,SAAQ,KAAK;IAEnB;IACA;IAEA;IAJlB,YACkB,MAAc,EACd,IAAY,EAC5B,OAAe,EACC,OAAiB;QAEjC,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAQ;QAEZ,YAAO,GAAP,OAAO,CAAU;QAGjC,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,OAAO,0BAA2B,SAAQ,YAAY;CAAG;AAC/D,MAAM,OAAO,sBAAuB,SAAQ,YAAY;CAAG;AAC3D,MAAM,OAAO,+BAAgC,SAAQ,YAAY;CAAG;AACpE,MAAM,OAAO,qBAAsB,SAAQ,YAAY;CAAG;AAC1D,MAAM,OAAO,oBAAqB,SAAQ,YAAY;CAAG;AAEzD,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,IAAa;IAC7D,MAAM,GAAG,GAAI,IAA2E,EAAE,KAAK,CAAC;IAChG,MAAM,IAAI,GAAG,GAAG,EAAE,IAAI,IAAI,SAAS,CAAC;IACpC,MAAM,OAAO,GAAG,GAAG,EAAE,OAAO,IAAI,QAAQ,MAAM,EAAE,CAAC;IACjD,MAAM,OAAO,GAAG,GAAG,EAAE,OAAO,CAAC;IAC7B,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,GAAG;YACN,OAAO,IAAI,0BAA0B,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACxE,KAAK,GAAG;YACN,OAAO,IAAI,oBAAoB,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAClE,KAAK,GAAG;YACN,OAAO,IAAI,KAAK,sBAAsB;gBACpC,CAAC,CAAC,IAAI,+BAA+B,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC;gBACrE,CAAC,CAAC,IAAI,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACvD,KAAK,GAAG;YACN,OAAO,IAAI,sBAAsB,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACpE,KAAK,GAAG;YACN,OAAO,IAAI,qBAAqB,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACnE;YACE,OAAO,IAAI,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { MandateClient, type MandateClientOptions } from "./client.js";
2
+ export { verifyReceiptSignature } from "./verify.js";
3
+ export * from "./types.js";
4
+ export * from "./errors.js";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { MandateClient } from "./client.js";
2
+ export { verifyReceiptSignature } from "./verify.js";
3
+ export * from "./types.js";
4
+ export * from "./errors.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA6B,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,220 @@
1
+ export type Decision = "APPROVE" | "REJECT" | "ESCALATE";
2
+ export type EffectiveDecision = Decision | "OBSERVE";
3
+ export interface CreateAgentRequest {
4
+ name: string;
5
+ external_id: string;
6
+ purpose?: string;
7
+ principal_type?: "ORGANISATION" | "PERSON" | "SERVICE";
8
+ principal_reference?: string;
9
+ metadata?: Record<string, unknown>;
10
+ }
11
+ export interface Agent {
12
+ id: string;
13
+ organisation_id: string;
14
+ name: string;
15
+ external_id: string;
16
+ purpose: string | null;
17
+ status: "ACTIVE" | "SUSPENDED" | "REVOKED";
18
+ principal_type: string;
19
+ principal_reference: string | null;
20
+ created_at: string;
21
+ }
22
+ export interface MandatePolicy {
23
+ currency: string;
24
+ mode?: "SHADOW" | "ENFORCE";
25
+ allowed_assets: string[];
26
+ allowed_counterparties?: string[];
27
+ denied_counterparties?: string[];
28
+ per_transaction: {
29
+ autonomous_limit: number;
30
+ absolute_limit: number;
31
+ };
32
+ budgets?: Array<{
33
+ period: "DAY" | "MONTH";
34
+ limit: number;
35
+ }>;
36
+ approval?: {
37
+ above_amount?: number;
38
+ new_counterparty_requires_approval?: boolean;
39
+ reservation_on_escalation?: boolean;
40
+ expires_after_minutes?: number;
41
+ };
42
+ allowed_purposes?: string[];
43
+ schedule?: {
44
+ timezone: string;
45
+ days: string[];
46
+ start: string;
47
+ end: string;
48
+ };
49
+ effective_at: string;
50
+ expires_at: string;
51
+ }
52
+ export interface CreateMandateRequest {
53
+ agent_id: string;
54
+ name: string;
55
+ mode?: "SHADOW" | "ENFORCE";
56
+ policy: MandatePolicy;
57
+ }
58
+ export interface Mandate {
59
+ id: string;
60
+ agent_id: string;
61
+ status: "DRAFT" | "PUBLISHED" | "REVOKED";
62
+ mode: "SHADOW" | "ENFORCE";
63
+ name: string;
64
+ current_version: number;
65
+ created_at: string;
66
+ }
67
+ /**
68
+ * Customer-asserted authority over a counterparty (CR-001-10). This is who
69
+ * you authorise paying — not a sanctions, AML or compliance verdict. mnd8t
70
+ * performs no screening and certifies none.
71
+ */
72
+ export type CounterpartyAuthorityStatus = "CUSTOMER_APPROVED" | "CUSTOMER_PENDING" | "CUSTOMER_BLOCKED";
73
+ export interface CreateCounterpartyRequest {
74
+ external_id: string;
75
+ display_name: string;
76
+ authority_status?: CounterpartyAuthorityStatus;
77
+ destination?: string;
78
+ type?: string;
79
+ category?: string;
80
+ metadata?: Record<string, unknown>;
81
+ /** Results from your own screening provider, stored as supplied. */
82
+ external_checks?: Array<{
83
+ type: string;
84
+ provider: string;
85
+ status: string;
86
+ checked_at?: string;
87
+ reference?: string;
88
+ }>;
89
+ }
90
+ export interface Counterparty {
91
+ id: string;
92
+ organisation_id: string;
93
+ external_id: string;
94
+ display_name: string;
95
+ authority_status: CounterpartyAuthorityStatus;
96
+ destination: string | null;
97
+ type: string | null;
98
+ category: string | null;
99
+ created_at: string;
100
+ }
101
+ /**
102
+ * Delegator authority attestation, required to publish a mandate.
103
+ * The assertion is recorded in the evidence chain; it is not verified.
104
+ */
105
+ export interface PublishMandateOptions {
106
+ delegation: {
107
+ /** The publisher's role, e.g. "Finance Director". */
108
+ delegatorRole: string;
109
+ /** Where the authority comes from, e.g. "CORPORATE_POLICY". */
110
+ authoritySource: string;
111
+ /** Optional pointer to the source document. */
112
+ sourceReference?: string;
113
+ };
114
+ changeNote?: string;
115
+ }
116
+ export interface PublishResult {
117
+ mandate_id: string;
118
+ version: number;
119
+ policy_hash: string;
120
+ published_at: string;
121
+ }
122
+ /** CR-001-03: closed action set. Mandate authorises payments and transfers
123
+ * only — never trading, swaps, staking, lending, or investment. */
124
+ export type FinancialActionType = "PAYMENT" | "TRANSFER";
125
+ export type AuthorisationArtifactStatus = "ISSUED" | "CLAIMED" | "EXECUTED" | "EXPIRED" | "REVOKED" | "CANCELLED" | "FAILED";
126
+ export interface AuthorisationArtifactSummary {
127
+ id: string;
128
+ status: string;
129
+ expires_at: string;
130
+ download_url: string;
131
+ }
132
+ export interface AuthorisationArtifactEnvelope {
133
+ id: string;
134
+ decision_intent_id: string;
135
+ financial_account_id: string | null;
136
+ status: AuthorisationArtifactStatus;
137
+ artifact: Record<string, unknown>;
138
+ artifact_hash: string;
139
+ key_id: string;
140
+ issued_at: string;
141
+ not_before: string;
142
+ expires_at: string;
143
+ claimed_at: string | null;
144
+ executed_at: string | null;
145
+ }
146
+ export interface AuthorizeRequest {
147
+ agent_external_id: string;
148
+ external_reference?: string;
149
+ action_type?: FinancialActionType;
150
+ financial_account_id?: string;
151
+ amount?: {
152
+ asset: string;
153
+ asset_amount_minor: number;
154
+ };
155
+ valuation?: {
156
+ policy_amount_minor: number;
157
+ policy_currency: string;
158
+ source?: string;
159
+ rate_reference?: string;
160
+ valued_at?: string;
161
+ };
162
+ jurisdiction_context?: {
163
+ principal_country?: string;
164
+ provider_country?: string;
165
+ counterparty_country?: string;
166
+ customer_classification?: string;
167
+ };
168
+ /** Deprecated: prefer `amount.asset_amount_minor`. */
169
+ amount_minor?: number;
170
+ policy_amount_minor?: number;
171
+ policy_currency?: string;
172
+ asset: string;
173
+ counterparty_external_id?: string;
174
+ destination?: string;
175
+ purpose?: string;
176
+ occurred_at?: string;
177
+ metadata?: Record<string, unknown>;
178
+ /** Overrides the automatically generated idempotency key. */
179
+ idempotencyKey?: string;
180
+ }
181
+ export interface AuthorizeResponse {
182
+ id: string;
183
+ mode: "SHADOW" | "ENFORCE";
184
+ decision: EffectiveDecision;
185
+ effective_decision: EffectiveDecision;
186
+ would_decide: Decision;
187
+ reason_codes: string[];
188
+ mandate_id: string | null;
189
+ mandate_version: number | null;
190
+ approval: {
191
+ id: string;
192
+ status: string;
193
+ expires_at: string;
194
+ approval_url: string;
195
+ } | null;
196
+ authorisation_artifact: AuthorisationArtifactSummary | null;
197
+ evidence_receipt_id: string | null;
198
+ }
199
+ export interface ConfirmRequest {
200
+ provider: string;
201
+ external_reference: string;
202
+ executed_at?: string;
203
+ /** Required for enforce-mode decisions. */
204
+ authorisation_artifact_id?: string;
205
+ financial_account_id?: string;
206
+ reported_by?: "CUSTOMER_EXECUTOR" | "CUSTOMER_API" | "PROVIDER_WEBHOOK" | "MANDATE_RECONCILIATION";
207
+ verification?: {
208
+ method?: "CUSTOMER_ASSERTED" | "PROVIDER_LOOKUP" | "PROVIDER_WEBHOOK" | "NETWORK_LOOKUP";
209
+ verified?: boolean;
210
+ verified_at?: string;
211
+ };
212
+ }
213
+ export interface EvidenceReceiptEnvelope {
214
+ id: string;
215
+ intent_id: string;
216
+ receipt: Record<string, unknown>;
217
+ receipt_hash: string;
218
+ key_id: string;
219
+ created_at: string;
220
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Dependency-free receipt verification usable in Node (>=20) and modern
3
+ * browsers via WebCrypto. Mirrors the gateway's canonicalisation exactly:
4
+ * sorted keys, no whitespace, integers only, undefined members dropped.
5
+ */
6
+ export declare function verifyReceiptSignature(receipt: Record<string, unknown>, publicKeyPem: string): Promise<{
7
+ valid: boolean;
8
+ reason: string | null;
9
+ }>;
package/dist/verify.js ADDED
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Dependency-free receipt verification usable in Node (>=20) and modern
3
+ * browsers via WebCrypto. Mirrors the gateway's canonicalisation exactly:
4
+ * sorted keys, no whitespace, integers only, undefined members dropped.
5
+ */
6
+ function canonicalJson(value) {
7
+ if (value === null)
8
+ return "null";
9
+ switch (typeof value) {
10
+ case "boolean":
11
+ return value ? "true" : "false";
12
+ case "number":
13
+ if (!Number.isFinite(value) || !Number.isInteger(value)) {
14
+ throw new Error(`canonical JSON permits only finite integers, got ${value}`);
15
+ }
16
+ return JSON.stringify(value);
17
+ case "string":
18
+ return JSON.stringify(value);
19
+ case "object": {
20
+ if (Array.isArray(value)) {
21
+ return `[${value.map((v) => canonicalJson(v === undefined ? null : v)).join(",")}]`;
22
+ }
23
+ const entries = Object.entries(value)
24
+ .filter(([, v]) => v !== undefined)
25
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
26
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`).join(",")}}`;
27
+ }
28
+ default:
29
+ throw new Error(`canonical JSON: unsupported type ${typeof value}`);
30
+ }
31
+ }
32
+ function pemToBytes(pem) {
33
+ const body = pem
34
+ .replace(/\\n/g, "\n")
35
+ .replace(/-----(BEGIN|END) PUBLIC KEY-----/g, "")
36
+ .replace(/\s+/g, "");
37
+ const binary = atob(body);
38
+ const bytes = new Uint8Array(binary.length);
39
+ for (let i = 0; i < binary.length; i++)
40
+ bytes[i] = binary.charCodeAt(i);
41
+ return bytes;
42
+ }
43
+ export async function verifyReceiptSignature(receipt, publicKeyPem) {
44
+ const signature = receipt["signature"];
45
+ if (!signature?.value)
46
+ return { valid: false, reason: "receipt has no signature" };
47
+ if (signature.algorithm !== "Ed25519") {
48
+ return { valid: false, reason: `unsupported algorithm ${signature.algorithm}` };
49
+ }
50
+ try {
51
+ const { signature: _omit, ...body } = receipt;
52
+ const keyBytes = pemToBytes(publicKeyPem);
53
+ const key = await crypto.subtle.importKey("spki", keyBytes.buffer, "Ed25519", false, [
54
+ "verify",
55
+ ]);
56
+ const sigBinary = atob(signature.value);
57
+ const sigBytes = new Uint8Array(sigBinary.length);
58
+ for (let i = 0; i < sigBinary.length; i++)
59
+ sigBytes[i] = sigBinary.charCodeAt(i);
60
+ const payload = new TextEncoder().encode(canonicalJson(body));
61
+ const valid = await crypto.subtle.verify("Ed25519", key, sigBytes, payload);
62
+ return valid ? { valid: true, reason: null } : { valid: false, reason: "signature mismatch" };
63
+ }
64
+ catch (err) {
65
+ return { valid: false, reason: `verification error: ${err.message}` };
66
+ }
67
+ }
68
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@mnd8t/sdk",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for the Mandate Gateway authority API",
5
+ "keywords": [
6
+ "ai-agents",
7
+ "authority",
8
+ "payments",
9
+ "policy",
10
+ "evidence",
11
+ "mnd8t"
12
+ ],
13
+ "license": "MIT",
14
+ "homepage": "https://mnd8t.com/docs/sdk",
15
+ "author": "Glencorse Ltd",
16
+ "type": "module",
17
+ "engines": {
18
+ "node": ">=22"
19
+ },
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "main": "./dist/index.js",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "default": "./dist/index.js"
29
+ }
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "README.md",
34
+ "LICENSE"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsc -p tsconfig.build.json",
38
+ "typecheck": "tsc --noEmit",
39
+ "test": "vitest run"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.10.5",
43
+ "typescript": "^5.7.3",
44
+ "vitest": "^3.0.5"
45
+ }
46
+ }