@ziggs-ai/api-client 0.9.0 → 0.9.2
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/dist/ConnectionManager.d.ts +23 -59
- package/dist/ConnectionManager.js +37 -166
- package/dist/capabilities/agreements.js +2 -2
- package/dist/capabilities/chat.js +13 -3
- package/dist/capabilities/connections.js +1 -1
- package/dist/capabilities/index.d.ts +1 -1
- package/dist/capabilities/index.js +1 -1
- package/dist/capabilities/links.d.ts +0 -8
- package/dist/capabilities/links.js +3 -25
- package/dist/capabilities/payments.js +5 -0
- package/dist/capabilities/types.js +3 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.js +42 -0
- package/dist/http/AgentSearchClient.d.ts +0 -1
- package/dist/http/AgentSearchClient.js +0 -1
- package/dist/http/AgreementClient.d.ts +32 -1
- package/dist/http/AgreementClient.js +96 -23
- package/dist/http/ArtifactsClient.d.ts +0 -1
- package/dist/http/ArtifactsClient.js +0 -1
- package/dist/http/ChatClient.d.ts +6 -3
- package/dist/http/ChatClient.js +7 -6
- package/dist/http/ConnectionsClient.d.ts +0 -1
- package/dist/http/ConnectionsClient.js +4 -5
- package/dist/http/ContextDiscoveryClient.d.ts +0 -1
- package/dist/http/ContextDiscoveryClient.js +2 -2
- package/dist/http/ContextGrantsClient.d.ts +0 -1
- package/dist/http/ContextGrantsClient.js +0 -1
- package/dist/http/ContextReadClient.d.ts +0 -1
- package/dist/http/ContextReadClient.js +5 -17
- package/dist/http/GrantsClient.d.ts +0 -1
- package/dist/http/GrantsClient.js +2 -2
- package/dist/http/InboxClient.d.ts +1 -177
- package/dist/http/InboxClient.js +0 -40
- package/dist/http/MarketplaceClient.d.ts +0 -1
- package/dist/http/MarketplaceClient.js +5 -4
- package/dist/http/MessagesClient.d.ts +0 -1
- package/dist/http/MessagesClient.js +3 -6
- package/dist/http/OrgsClient.d.ts +0 -1
- package/dist/http/OrgsClient.js +3 -3
- package/dist/http/PaymentsClient.d.ts +4 -2
- package/dist/http/PaymentsClient.js +27 -7
- package/dist/http/TaskClient.d.ts +0 -1
- package/dist/http/TaskClient.js +0 -1
- package/dist/http/TelemetryClient.d.ts +0 -1
- package/dist/http/TelemetryClient.js +0 -1
- package/dist/http/agreementFlows.d.ts +13 -5
- package/dist/http/agreementFlows.js +18 -24
- package/dist/http/index.d.ts +0 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.js +5 -2
- package/dist/shared/apiError.d.ts +22 -1
- package/dist/shared/apiError.js +60 -3
- package/dist/shared/rateLimit.d.ts +12 -22
- package/dist/shared/rateLimit.js +18 -51
- package/dist/shared/runtimeLog.d.ts +0 -6
- package/dist/shared/runtimeLog.js +10 -7
- package/dist/types.d.ts +167 -1
- package/dist/types.js +20 -1
- package/dist/utils/urlUtils.js +3 -2
- package/package.json +1 -2
|
@@ -1,172 +1,4 @@
|
|
|
1
|
-
import '
|
|
2
|
-
/**
|
|
3
|
-
* What a delivery can be about. A closed union, not a comment: a consumer that
|
|
4
|
-
* dispatches on `kind` (the MCP read plan) is only safe if the compiler can tell
|
|
5
|
-
* it a case is missing. The task-only deliverable that was acked unread got
|
|
6
|
-
* through precisely because this was `string`.
|
|
7
|
-
*
|
|
8
|
-
* A type and not a value list, unlike the backend's `RESOURCE_KINDS` — nothing
|
|
9
|
-
* on this side validates a delivery kind at runtime (the server does that on the
|
|
10
|
-
* way in), and exhaustiveness checking is purely type-level.
|
|
11
|
-
*/
|
|
12
|
-
export type InboxDeliveryKind = 'message' | 'artifact' | 'task-state' | 'agreement';
|
|
13
|
-
/**
|
|
14
|
-
* One thing addressed to this agent. A reference, never content — following it
|
|
15
|
-
* (a chat read, a task read) is where this agent's grants are enforced.
|
|
16
|
-
*/
|
|
17
|
-
export interface InboxDeliveryRef {
|
|
18
|
-
kind: InboxDeliveryKind;
|
|
19
|
-
resourceId: string;
|
|
20
|
-
chatId: string | null;
|
|
21
|
-
agreementId: string | null;
|
|
22
|
-
taskId: string | null;
|
|
23
|
-
/** Who wrote it. Never this agent — you are not woken by your own writes. */
|
|
24
|
-
actorId: string | null;
|
|
25
|
-
ts: string;
|
|
26
|
-
}
|
|
27
|
-
/** Message/artifact deliveries folded by chat, so you can open chats directly. */
|
|
28
|
-
export interface InboxChatNews {
|
|
29
|
-
chatId: string;
|
|
30
|
-
count: number;
|
|
31
|
-
latestAt: string;
|
|
32
|
-
}
|
|
33
|
-
export interface InboxProposalRef {
|
|
34
|
-
agreementId: string;
|
|
35
|
-
title: string;
|
|
36
|
-
proposedAt: string | null;
|
|
37
|
-
/**
|
|
38
|
-
* ZIG-1087 — party ids still owing a decision, and the named responder slot.
|
|
39
|
-
* The inbox lists proposals awaiting the agent OR its human, and only the
|
|
40
|
-
* agent's own slot is one it can submit; these say which is which.
|
|
41
|
-
*
|
|
42
|
-
* Optional because a backend deployed before ZIG-1087 omits them, and this
|
|
43
|
-
* client is installed independently of the server it talks to. Absent reads
|
|
44
|
-
* as "no slot of mine", which routes the decision to the human — the safe
|
|
45
|
-
* direction: it withholds a call, it never invents authority.
|
|
46
|
-
*/
|
|
47
|
-
pendingApprovalPartyIds?: string[];
|
|
48
|
-
proposedTo?: string | null;
|
|
49
|
-
}
|
|
50
|
-
export interface InboxConnectionRequestRef {
|
|
51
|
-
requestId: string;
|
|
52
|
-
/**
|
|
53
|
-
* Non-addressable persona reference for the requester (`psn_*`).
|
|
54
|
-
* Never use as an account id for lookup / wake / pay (ZIG-1137).
|
|
55
|
-
*/
|
|
56
|
-
requesterRef: string;
|
|
57
|
-
/** ZIG-1039 — human-readable name for consent cards. */
|
|
58
|
-
requesterDisplayName?: string | null;
|
|
59
|
-
/** ZIG-1039 — org label for consent cards. */
|
|
60
|
-
requesterOrgName?: string | null;
|
|
61
|
-
message: string | null;
|
|
62
|
-
requestedAt: string | null;
|
|
63
|
-
/** ZIG-1087 — see InboxProposalRef; a link request uses the same gate. */
|
|
64
|
-
pendingApprovalPartyIds?: string[];
|
|
65
|
-
proposedTo?: string | null;
|
|
66
|
-
}
|
|
67
|
-
/** Pull-only MCP: prompt the human when proposals need a decision (ZIG-482 / ZIG-481). */
|
|
68
|
-
export interface InboxHumanAttention {
|
|
69
|
-
required: true;
|
|
70
|
-
reason: 'proposals_awaiting_me' | 'connection_requests_awaiting_me' | 'multiple';
|
|
71
|
-
proposalCount: number;
|
|
72
|
-
truncatedProposals: number;
|
|
73
|
-
connectionRequestCount: number;
|
|
74
|
-
truncatedConnectionRequests: number;
|
|
75
|
-
promptUser: string;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* An open task assigned to this agent (ZIG-973). References only — read the
|
|
79
|
-
* task for its description/plan/inputs.
|
|
80
|
-
*
|
|
81
|
-
* Tasks ride their own channel because assignment IS their delivery: before
|
|
82
|
-
* this, a task wake was a synthetic chat row, so work under a chat-less
|
|
83
|
-
* agreement (or self-assigned) reached nobody.
|
|
84
|
-
*/
|
|
85
|
-
export interface InboxTaskRef {
|
|
86
|
-
taskId: string;
|
|
87
|
-
agreementId: string | null;
|
|
88
|
-
title: string;
|
|
89
|
-
state: string;
|
|
90
|
-
updatedAt: string | null;
|
|
91
|
-
}
|
|
92
|
-
export interface InboxEnvelope {
|
|
93
|
-
asOf: string;
|
|
94
|
-
/**
|
|
95
|
-
* Unacked deliveries addressed to this agent, newest first. This IS the
|
|
96
|
-
* inbox — read straight out of the delivery log, not derived from grants.
|
|
97
|
-
*/
|
|
98
|
-
deliveries: InboxDeliveryRef[];
|
|
99
|
-
/** True when there was more than one envelope's worth; the rest stay unacked. */
|
|
100
|
-
deliveriesCapped: boolean;
|
|
101
|
-
/** The chat-bearing deliveries above, folded by chat. */
|
|
102
|
-
chats: InboxChatNews[];
|
|
103
|
-
/**
|
|
104
|
-
* Pass to `ack()` after acting. Null when there is nothing to ack. Ack after
|
|
105
|
-
* acting, not after reading: a crash in between redelivers.
|
|
106
|
-
*/
|
|
107
|
-
ackTo: string | null;
|
|
108
|
-
/** Open tasks assigned to this agent — the work channel (ZIG-973). */
|
|
109
|
-
tasksAwaitingMe: InboxTaskRef[];
|
|
110
|
-
truncatedTasks: number;
|
|
111
|
-
proposalsAwaitingMe: InboxProposalRef[];
|
|
112
|
-
truncatedProposals: number;
|
|
113
|
-
connectionRequestsAwaitingMe: InboxConnectionRequestRef[];
|
|
114
|
-
truncatedConnectionRequests: number;
|
|
115
|
-
humanAttention?: InboxHumanAttention;
|
|
116
|
-
}
|
|
117
|
-
export interface InboxAckResult {
|
|
118
|
-
/** Where the watermark now sits. Monotonic — a rewind is a no-op, not an error. */
|
|
119
|
-
ackedUpTo: string | null;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Long-poll option shared by the inbox reads. The server holds the request up
|
|
123
|
-
* to this many seconds (server-clamped, ~25s ceiling) and returns as soon as
|
|
124
|
-
* anything actionable exists. Omit for an immediate snapshot — the response
|
|
125
|
-
* shape is identical either way, so `wait` only changes how long an EMPTY
|
|
126
|
-
* answer is withheld.
|
|
127
|
-
*/
|
|
128
|
-
export interface InboxReadOptions {
|
|
129
|
-
waitSeconds?: number;
|
|
130
|
-
/**
|
|
131
|
-
* Operator read only (ZIG-965): restrict the sweep to this roster. The
|
|
132
|
-
* server intersects it with the agents the key owner runs — it narrows,
|
|
133
|
-
* never widens. A launcher hosting a subset should always pass the agents
|
|
134
|
-
* it actually registered, or it pays for a sweep of the owner's whole
|
|
135
|
-
* seeded fleet.
|
|
136
|
-
*/
|
|
137
|
-
agents?: string[];
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* One agent's line in the operator sweep: enough to decide whether to start a
|
|
141
|
-
* host, and nothing more.
|
|
142
|
-
*
|
|
143
|
-
* Deliberately NOT that agent's envelope. The launcher only chooses who to
|
|
144
|
-
* run; the host it starts reads its own inbox on its own credentials a moment
|
|
145
|
-
* later, so building N envelopes here was work thrown away.
|
|
146
|
-
*/
|
|
147
|
-
export interface InboxOperatorAgentEntry {
|
|
148
|
-
agentId: string;
|
|
149
|
-
/** Newest delivery addressed to this agent, or null if it never had one. */
|
|
150
|
-
deliveredUpTo: string | null;
|
|
151
|
-
/** How far it has acked. Mail exists when `deliveredUpTo > ackedUpTo`. */
|
|
152
|
-
ackedUpTo: string | null;
|
|
153
|
-
/**
|
|
154
|
-
* True when this agent holds open assigned work. Independent of the
|
|
155
|
-
* watermark: a host that died mid-task already acked past the task's
|
|
156
|
-
* delivery, and the open task is the only durable trace it needs restarting.
|
|
157
|
-
*/
|
|
158
|
-
hasOpenTasks: boolean;
|
|
159
|
-
}
|
|
160
|
-
/** GET /inbox/operator: which of the key owner's agents have mail or open work. */
|
|
161
|
-
export interface InboxOperatorEnvelope {
|
|
162
|
-
asOf: string;
|
|
163
|
-
/** Agents with mail or open work. */
|
|
164
|
-
agents: InboxOperatorAgentEntry[];
|
|
165
|
-
/** Agents examined that had neither. */
|
|
166
|
-
idleAgents: number;
|
|
167
|
-
/** Owned agents beyond the server's per-pass cap — not examined. */
|
|
168
|
-
truncatedAgents: number;
|
|
169
|
-
}
|
|
1
|
+
import type { InboxAckResult, InboxEnvelope, InboxReadOptions } from '../types.js';
|
|
170
2
|
/**
|
|
171
3
|
* The doorbell, not the door (ZIG-434): references addressed to this agent
|
|
172
4
|
* since its last ack — never content. Flow: inbox → read → act → ack
|
|
@@ -184,14 +16,6 @@ export declare class InboxClient {
|
|
|
184
16
|
private headers;
|
|
185
17
|
private inboxUrl;
|
|
186
18
|
getInbox(opts?: InboxReadOptions): Promise<InboxEnvelope>;
|
|
187
|
-
/**
|
|
188
|
-
* Operator-level multiplexed read: which of this key owner's agents have
|
|
189
|
-
* mail or open work (an agent-scoped key collapses to its one agent).
|
|
190
|
-
*
|
|
191
|
-
* Returns who to start, never what they were sent — the host you start
|
|
192
|
-
* reads its own inbox on its own identity. Ack stays per agent.
|
|
193
|
-
*/
|
|
194
|
-
getOperatorInbox(opts?: InboxReadOptions): Promise<InboxOperatorEnvelope>;
|
|
195
19
|
/**
|
|
196
20
|
* Advance this agent's watermark — pass the envelope's `ackTo`. Monotonic
|
|
197
21
|
* server-side: an older value is a no-op, so a replayed ack can never
|
package/dist/http/InboxClient.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
1
|
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
3
2
|
import { pollSurfaceError } from '../shared/rateLimit.js';
|
|
4
3
|
/**
|
|
@@ -35,9 +34,6 @@ export class InboxClient {
|
|
|
35
34
|
if (opts.waitSeconds != null && opts.waitSeconds > 0) {
|
|
36
35
|
url.searchParams.set('wait', String(opts.waitSeconds));
|
|
37
36
|
}
|
|
38
|
-
if (opts.agents?.length) {
|
|
39
|
-
url.searchParams.set('agents', opts.agents.join(','));
|
|
40
|
-
}
|
|
41
37
|
return url.toString();
|
|
42
38
|
}
|
|
43
39
|
async getInbox(opts = {}) {
|
|
@@ -50,42 +46,6 @@ export class InboxClient {
|
|
|
50
46
|
}
|
|
51
47
|
return JSON.parse(body);
|
|
52
48
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Operator-level multiplexed read: which of this key owner's agents have
|
|
55
|
-
* mail or open work (an agent-scoped key collapses to its one agent).
|
|
56
|
-
*
|
|
57
|
-
* Returns who to start, never what they were sent — the host you start
|
|
58
|
-
* reads its own inbox on its own identity. Ack stays per agent.
|
|
59
|
-
*/
|
|
60
|
-
async getOperatorInbox(opts = {}) {
|
|
61
|
-
// Bounded wait (ZIG-965): the server holds at most `waitSeconds` (+ sweep
|
|
62
|
-
// time); a poll that outlives that by a wide margin is a dead sweep, and
|
|
63
|
-
// without a timeout it blocked the launcher's whole poll loop — lazy wake
|
|
64
|
-
// simply stopped. Abort and let the caller's retry loop take over.
|
|
65
|
-
const timeoutMs = ((opts.waitSeconds ?? 0) + 30) * 1000;
|
|
66
|
-
const ac = new AbortController();
|
|
67
|
-
const timer = setTimeout(() => ac.abort(), timeoutMs);
|
|
68
|
-
let res;
|
|
69
|
-
try {
|
|
70
|
-
res = await fetch(this.inboxUrl('/inbox/operator', opts), {
|
|
71
|
-
headers: this.headers(),
|
|
72
|
-
signal: ac.signal,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
catch (err) {
|
|
76
|
-
throw ac.signal.aborted
|
|
77
|
-
? new Error(`InboxClient.getOperatorInbox timed out after ${timeoutMs}ms`)
|
|
78
|
-
: err;
|
|
79
|
-
}
|
|
80
|
-
finally {
|
|
81
|
-
clearTimeout(timer);
|
|
82
|
-
}
|
|
83
|
-
const body = await res.text().catch(() => '');
|
|
84
|
-
if (!res.ok) {
|
|
85
|
-
throw pollSurfaceError('InboxClient.getOperatorInbox', res, body);
|
|
86
|
-
}
|
|
87
|
-
return JSON.parse(body);
|
|
88
|
-
}
|
|
89
49
|
/**
|
|
90
50
|
* Advance this agent's watermark — pass the envelope's `ackTo`. Monotonic
|
|
91
51
|
* server-side: an older value is a no-op, so a replayed ack can never
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// ZIG-1111: one shaping rule for every agreement this package parses.
|
|
2
|
+
import { shapeAgreement } from './AgreementClient.js';
|
|
2
3
|
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
3
4
|
import { throwApiError } from '../shared/apiError.js';
|
|
4
5
|
function getMarketplaceBaseUrl() { return `${getBackendUrl()}/marketplace`; }
|
|
@@ -30,7 +31,7 @@ export async function publishOffer(payload, creds) {
|
|
|
30
31
|
throwApiError(res, body, `Marketplace offer publish failed: ${res.status}`);
|
|
31
32
|
}
|
|
32
33
|
const data = await res.json().catch(() => null);
|
|
33
|
-
return (data?.['offer'] ?? data);
|
|
34
|
+
return shapeAgreement((data?.['offer'] ?? data));
|
|
34
35
|
}
|
|
35
36
|
export async function pullOffers(options, creds) {
|
|
36
37
|
assertCreds(creds, 'marketplace offers pull');
|
|
@@ -67,7 +68,7 @@ export async function claimOffer(agreementId, creds) {
|
|
|
67
68
|
const data = await res.json().catch(() => null);
|
|
68
69
|
if (!data?.['ok'])
|
|
69
70
|
throw new Error(data?.['error'] || 'Claim failed');
|
|
70
|
-
return data['offer'];
|
|
71
|
+
return shapeAgreement(data['offer']);
|
|
71
72
|
}
|
|
72
73
|
export async function publishQuest(payload, creds) {
|
|
73
74
|
assertCreds(creds, 'quest publish');
|
|
@@ -83,7 +84,7 @@ export async function publishQuest(payload, creds) {
|
|
|
83
84
|
const data = await res.json().catch(() => null);
|
|
84
85
|
if (!data?.['agreement'])
|
|
85
86
|
throw new Error('Quest publish returned no agreement');
|
|
86
|
-
return data['agreement'];
|
|
87
|
+
return shapeAgreement(data['agreement']);
|
|
87
88
|
}
|
|
88
89
|
export async function pullQuests(options, creds) {
|
|
89
90
|
assertCreds(creds, 'quest pull');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
1
|
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
2
|
+
import { throwApiError } from '../shared/apiError.js';
|
|
3
3
|
/**
|
|
4
4
|
* Read-side client for forward-delta message reads.
|
|
5
5
|
*
|
|
@@ -35,11 +35,8 @@ export class MessagesClient {
|
|
|
35
35
|
const res = await fetch(url.toString(), { headers: this._headers() });
|
|
36
36
|
if (!res.ok) {
|
|
37
37
|
const body = await res.text().catch(() => '');
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// without parsing the message string.
|
|
41
|
-
err.status = res.status;
|
|
42
|
-
throw err;
|
|
38
|
+
// Callers branch on ApiError.status (404 = chat deleted/not visible).
|
|
39
|
+
throwApiError(res, body, `MessagesClient.list failed: ${res.status}`);
|
|
43
40
|
}
|
|
44
41
|
return (await res.json());
|
|
45
42
|
}
|
package/dist/http/OrgsClient.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
1
|
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
2
|
+
import { throwApiError } from '../shared/apiError.js';
|
|
3
3
|
import { buildOperatorHeaders } from './operatorHeaders.js';
|
|
4
4
|
/**
|
|
5
5
|
* ZIG-739 / ZIG-956 — the operator's full org membership (not just granted
|
|
@@ -15,7 +15,7 @@ export async function fetchMyOrgs(creds, baseUrl) {
|
|
|
15
15
|
});
|
|
16
16
|
const body = await res.text().catch(() => '');
|
|
17
17
|
if (!res.ok) {
|
|
18
|
-
|
|
18
|
+
throwApiError(res, body, `GET /orgs/me failed: ${res.status}`);
|
|
19
19
|
}
|
|
20
20
|
const parsed = body ? JSON.parse(body) : {};
|
|
21
21
|
return (parsed.orgs ?? []).map((o) => ({
|
|
@@ -55,7 +55,7 @@ export async function fetchDelegateAccess(creds, baseUrl) {
|
|
|
55
55
|
});
|
|
56
56
|
const body = await res.text().catch(() => '');
|
|
57
57
|
if (!res.ok) {
|
|
58
|
-
|
|
58
|
+
throwApiError(res, body, `GET /agents/claude-delegate/access failed: ${res.status}`);
|
|
59
59
|
}
|
|
60
60
|
return body ? JSON.parse(body) : {};
|
|
61
61
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
1
|
import type { GrantView } from './grants.js';
|
|
3
2
|
/** Thrown by PaymentsClient with the HTTP status and raw body attached. */
|
|
4
3
|
export interface PaymentsError extends Error {
|
|
@@ -101,11 +100,14 @@ export declare class PaymentsClient {
|
|
|
101
100
|
description?: string;
|
|
102
101
|
paymentGrantId?: string;
|
|
103
102
|
}): Promise<TransferResult>;
|
|
104
|
-
hold({ amount, idempotencyKey, description, }: {
|
|
103
|
+
hold({ amount, idempotencyKey, description, paymentGrantId, }: {
|
|
105
104
|
amount: number;
|
|
106
105
|
idempotencyKey?: string;
|
|
107
106
|
description?: string;
|
|
107
|
+
paymentGrantId?: string;
|
|
108
108
|
}): Promise<HoldResult>;
|
|
109
|
+
/** Prefer a single active wallet grant the agent already holds (ZIG-1182). */
|
|
110
|
+
private resolveAgentPaymentGrantId;
|
|
109
111
|
release({ holdId, action, toWalletId, idempotencyKey, }: {
|
|
110
112
|
holdId: string;
|
|
111
113
|
action?: string;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
1
|
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
3
2
|
import { buildOperatorHeaders } from './operatorHeaders.js';
|
|
4
3
|
import { GrantsClient } from './GrantsClient.js';
|
|
5
|
-
import {
|
|
4
|
+
import { throwApiError } from '../shared/apiError.js';
|
|
6
5
|
function randomIdempotencyKey(prefix = 'op') {
|
|
7
6
|
return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
8
7
|
}
|
|
@@ -51,6 +50,11 @@ export class PaymentsClient {
|
|
|
51
50
|
throw new Error('transfer: `to` is required');
|
|
52
51
|
if (!(Number.isInteger(amount) && amount > 0))
|
|
53
52
|
throw new Error('transfer: `amount` must be a positive integer (cents)');
|
|
53
|
+
// ZIG-1182 — resolve a standing/active grant when the caller omitted one
|
|
54
|
+
// (Claude/MCP ensureForUser mints it). Explicit id still wins.
|
|
55
|
+
if (this.agentId && !paymentGrantId) {
|
|
56
|
+
paymentGrantId = (await this.resolveAgentPaymentGrantId()) ?? undefined;
|
|
57
|
+
}
|
|
54
58
|
if (this.agentId && !paymentGrantId)
|
|
55
59
|
throw new Error('transfer: paymentGrantId is required for agent-impersonated transfers. The wallet owner must have issued a payment grant to this agentId.');
|
|
56
60
|
let toWalletId = to;
|
|
@@ -86,15 +90,33 @@ export class PaymentsClient {
|
|
|
86
90
|
amount,
|
|
87
91
|
};
|
|
88
92
|
}
|
|
89
|
-
async hold({ amount, idempotencyKey, description, }) {
|
|
93
|
+
async hold({ amount, idempotencyKey, description, paymentGrantId, }) {
|
|
90
94
|
if (!(Number.isInteger(amount) && amount > 0))
|
|
91
95
|
throw new Error('hold: `amount` must be a positive integer (cents)');
|
|
96
|
+
// ZIG-1182 — agent holds reserve the owner's wallet; require a grant.
|
|
97
|
+
if (this.agentId && !paymentGrantId) {
|
|
98
|
+
paymentGrantId = (await this.resolveAgentPaymentGrantId()) ?? undefined;
|
|
99
|
+
}
|
|
100
|
+
if (this.agentId && !paymentGrantId)
|
|
101
|
+
throw new Error('hold: paymentGrantId is required for agent-impersonated holds. The wallet owner must have issued a payment grant to this agentId.');
|
|
92
102
|
return (await this._post('/payments/hold', {
|
|
93
103
|
amount,
|
|
94
104
|
idempotencyKey: idempotencyKey || randomIdempotencyKey('hold'),
|
|
95
105
|
description,
|
|
106
|
+
paymentGrantId,
|
|
96
107
|
}));
|
|
97
108
|
}
|
|
109
|
+
/** Prefer a single active wallet grant the agent already holds (ZIG-1182). */
|
|
110
|
+
async resolveAgentPaymentGrantId() {
|
|
111
|
+
try {
|
|
112
|
+
const grants = await this.listGrants();
|
|
113
|
+
const id = grants[0]?.grantId;
|
|
114
|
+
return typeof id === 'string' && id.length > 0 ? id : null;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
98
120
|
async release({ holdId, action = 'complete', toWalletId, idempotencyKey, }) {
|
|
99
121
|
return (await this._post(`/payments/release/${holdId}`, {
|
|
100
122
|
idempotencyKey: idempotencyKey || randomIdempotencyKey('rel'),
|
|
@@ -217,10 +239,8 @@ export class PaymentsClient {
|
|
|
217
239
|
const response = await fetch(`${this.baseUrl}${path}`, init);
|
|
218
240
|
const text = await response.text();
|
|
219
241
|
if (!response.ok) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
err.body = text;
|
|
223
|
-
throw err;
|
|
242
|
+
// ZIG-1124 — ApiError; PaymentsError remains the duck type for `.status`.
|
|
243
|
+
throwApiError(response, text, `HTTP ${response.status}`);
|
|
224
244
|
}
|
|
225
245
|
return text ? JSON.parse(text) : null;
|
|
226
246
|
}
|
package/dist/http/TaskClient.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ProposeTerms } from './AgreementClient.js';
|
|
1
|
+
import { type ClaimedKind, type ProposeTerms } from './AgreementClient.js';
|
|
2
2
|
import { type Agreement, type Creds, type EngagementKind } from '../types.js';
|
|
3
3
|
/**
|
|
4
4
|
* ZIG-1022 — one propose grammar. Direct, broadcast (quest and standing
|
|
@@ -22,11 +22,19 @@ export declare function proposeUnified(input: UnifiedProposeInput, creds: Creds)
|
|
|
22
22
|
agreement: Agreement;
|
|
23
23
|
shape: ProposeShape;
|
|
24
24
|
}>;
|
|
25
|
-
export type ClaimedKind = 'link' | 'offer' | 'quest' | 'hand-off';
|
|
26
25
|
/**
|
|
27
|
-
* ZIG-1021 — one claim verb for any open broadcast
|
|
28
|
-
*
|
|
29
|
-
*
|
|
26
|
+
* ZIG-1021 — one claim verb for any open broadcast: link invite, quest,
|
|
27
|
+
* hand-off, or standing offer.
|
|
28
|
+
*
|
|
29
|
+
* One request. This used to read the agreement first to decide which endpoint to
|
|
30
|
+
* post to, and `GET /agreements/:id` is party-scoped — a claimer is by definition
|
|
31
|
+
* not yet a party to the broadcast it is claiming, so the routing read 404'd and
|
|
32
|
+
* every standing offer in the store failed with "Agreement not found" before
|
|
33
|
+
* either claim endpoint was called (ZIG-1155). The backend routes it now, where
|
|
34
|
+
* the row is readable without being a party to it.
|
|
35
|
+
*
|
|
36
|
+
* `kind` arrives on the claim response — the route that did the routing reports
|
|
37
|
+
* which broadcast kind this turned out to be.
|
|
30
38
|
*/
|
|
31
39
|
export declare function claimOpenAgreement(agreementId: string, creds: Creds): Promise<{
|
|
32
40
|
agreement: Agreement;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createAgreement, claimAgreement,
|
|
2
|
-
import {
|
|
1
|
+
import { createAgreement, claimAgreement, proposeBroadcast, proposeDirectTo, } from './AgreementClient.js';
|
|
2
|
+
import { publishOffer } from './MarketplaceClient.js';
|
|
3
3
|
import { isBroadcastTarget, } from '../types.js';
|
|
4
4
|
export async function proposeUnified(input, creds) {
|
|
5
5
|
const { proposedTo, chatId, engagementKind, providerId, ...terms } = input;
|
|
@@ -56,30 +56,24 @@ export async function proposeUnified(input, creds) {
|
|
|
56
56
|
return { agreement, shape: 'direct' };
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
|
-
* ZIG-1021 — one claim verb for any open broadcast
|
|
60
|
-
*
|
|
61
|
-
*
|
|
59
|
+
* ZIG-1021 — one claim verb for any open broadcast: link invite, quest,
|
|
60
|
+
* hand-off, or standing offer.
|
|
61
|
+
*
|
|
62
|
+
* One request. This used to read the agreement first to decide which endpoint to
|
|
63
|
+
* post to, and `GET /agreements/:id` is party-scoped — a claimer is by definition
|
|
64
|
+
* not yet a party to the broadcast it is claiming, so the routing read 404'd and
|
|
65
|
+
* every standing offer in the store failed with "Agreement not found" before
|
|
66
|
+
* either claim endpoint was called (ZIG-1155). The backend routes it now, where
|
|
67
|
+
* the row is readable without being a party to it.
|
|
68
|
+
*
|
|
69
|
+
* `kind` arrives on the claim response — the route that did the routing reports
|
|
70
|
+
* which broadcast kind this turned out to be.
|
|
62
71
|
*/
|
|
63
72
|
export async function claimOpenAgreement(agreementId, creds) {
|
|
64
73
|
if (!agreementId)
|
|
65
74
|
throw new Error('agreementId is required');
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const { agreement } = await claimAgreement(agreementId, creds);
|
|
71
|
-
return { agreement, kind: 'link' };
|
|
72
|
-
}
|
|
73
|
-
if (isBroadcastTarget(existing.parties?.payer)) {
|
|
74
|
-
// Seller-broadcast standing offer: the open side is the payer — you buy.
|
|
75
|
-
const agreement = await claimOffer(agreementId, creds);
|
|
76
|
-
return { agreement, kind: 'offer' };
|
|
77
|
-
}
|
|
78
|
-
const { agreement } = await claimAgreement(agreementId, creds);
|
|
79
|
-
// ZIG-1059: a pinned provider inverts the quest reading — the publisher's
|
|
80
|
-
// hired agent does the work and the claimer is who it is done FOR.
|
|
81
|
-
return {
|
|
82
|
-
agreement,
|
|
83
|
-
kind: existing.providerPinned === true ? 'hand-off' : 'quest',
|
|
84
|
-
};
|
|
75
|
+
const { agreement, kind } = await claimAgreement(agreementId, creds);
|
|
76
|
+
// A server that has not shipped the `kind` field yet still claims correctly;
|
|
77
|
+
// 'quest' is the shape the route has always handled.
|
|
78
|
+
return { agreement, kind: kind ?? 'quest' };
|
|
85
79
|
}
|
package/dist/http/index.d.ts
CHANGED
|
@@ -26,4 +26,3 @@ export type { MyOrg, OrgResolution } from './OrgsClient.js';
|
|
|
26
26
|
export { AgentSearchClient } from './AgentSearchClient.js';
|
|
27
27
|
export { TelemetryClient } from './TelemetryClient.js';
|
|
28
28
|
export { InboxClient } from './InboxClient.js';
|
|
29
|
-
export type { InboxDeliveryKind, InboxDeliveryRef, InboxChatNews, InboxProposalRef, InboxTaskRef, InboxConnectionRequestRef, InboxHumanAttention, InboxEnvelope, InboxAckResult, InboxOperatorAgentEntry, InboxOperatorEnvelope, } from './InboxClient.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -2,12 +2,14 @@ export * from './http/index.js';
|
|
|
2
2
|
export * from './capabilities/index.js';
|
|
3
3
|
export * from './relay/provisionRelayWorkers.js';
|
|
4
4
|
export { ConnectionManager } from './ConnectionManager.js';
|
|
5
|
-
export type { StartAgentOptions } from './ConnectionManager.js';
|
|
6
5
|
export { EntryTypes, ContentTypes, OPEN_AGREEMENT_TARGET, ORG_AGREEMENT_TARGET, BROADCAST_TARGETS, isBroadcastTarget, isPersonaRef, isRoomPresentationRef, isOpaquePresentationRef, AGREEMENT_ENGAGEMENT_KIND, isValidContentType, } from './types.js';
|
|
7
6
|
export type { PrincipalPresentation } from './types.js';
|
|
8
7
|
export { getBackendUrl, getWebSocketUrl } from './utils/urlUtils.js';
|
|
8
|
+
export { configureApiClient, apiClientConfig } from './config.js';
|
|
9
|
+
export type { ApiClientConfig, ApiClientLogLevel } from './config.js';
|
|
9
10
|
export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
|
|
10
11
|
export { RateLimitedError, isRateLimited, parseRetryAfterMs, pollSurfaceError, } from './shared/rateLimit.js';
|
|
11
|
-
export { parseErrorMessage, throwApiError } from './shared/apiError.js';
|
|
12
|
-
export
|
|
12
|
+
export { parseErrorMessage, parseErrorCode, throwApiError, } from './shared/apiError.js';
|
|
13
|
+
export { ApiError } from './types.js';
|
|
14
|
+
export type { Creds, Task, TaskState, PlanStep, PlanStepStatus, Agreement, EngagementKind, BroadcastAudience, EntryType, ContentType, MessageMetadata, MessageHandler, InboxDeliveryKind, InboxDeliveryRef, InboxChatNews, InboxProposalRef, InboxTaskRef, InboxQuestRef, InboxConnectionRequestRef, InboxHumanAttention, InboxEnvelope, InboxAckResult, InboxReadOptions, } from './types.js';
|
|
13
15
|
export type { ProposeTerms, ProposeDirectInput, ProposeBroadcastInput, ProposeAgreementData, } from './http/AgreementClient.js';
|
package/dist/index.js
CHANGED
|
@@ -4,10 +4,13 @@ export * from './relay/provisionRelayWorkers.js';
|
|
|
4
4
|
export { ConnectionManager } from './ConnectionManager.js';
|
|
5
5
|
export { EntryTypes, ContentTypes, OPEN_AGREEMENT_TARGET, ORG_AGREEMENT_TARGET, BROADCAST_TARGETS, isBroadcastTarget, isPersonaRef, isRoomPresentationRef, isOpaquePresentationRef, AGREEMENT_ENGAGEMENT_KIND, isValidContentType, } from './types.js';
|
|
6
6
|
export { getBackendUrl, getWebSocketUrl } from './utils/urlUtils.js';
|
|
7
|
+
// ZIG-652: the host injects the environment; this package never reads it.
|
|
8
|
+
export { configureApiClient, apiClientConfig } from './config.js';
|
|
7
9
|
export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
|
|
8
|
-
// ZIG-1019:
|
|
10
|
+
// ZIG-1019 / ZIG-1124: one ApiError shape; 429s carry the server's wait.
|
|
9
11
|
export { RateLimitedError, isRateLimited, parseRetryAfterMs, pollSurfaceError, } from './shared/rateLimit.js';
|
|
10
12
|
// One reader for the one error shape the API answers in — exported so nothing has
|
|
11
13
|
// to re-implement the field precedence (it was copy-pasted into six clients, and
|
|
12
14
|
// half of them had drifted).
|
|
13
|
-
export { parseErrorMessage, throwApiError } from './shared/apiError.js';
|
|
15
|
+
export { parseErrorMessage, parseErrorCode, throwApiError, } from './shared/apiError.js';
|
|
16
|
+
export { ApiError } from './types.js';
|
|
@@ -16,7 +16,28 @@
|
|
|
16
16
|
* so the same failure read differently depending on which client you called.
|
|
17
17
|
*/
|
|
18
18
|
export declare function parseErrorMessage(responseBody: string, defaultMessage: string): string;
|
|
19
|
-
/**
|
|
19
|
+
/** Machine code from `{ error, code }` when the filter (or thrower) supplied one. */
|
|
20
|
+
export declare function parseErrorCode(responseBody: string): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Read the wait out of a 429 response. `Retry-After` wins (it is the explicit
|
|
23
|
+
* one) and is accepted in both forms — delta-seconds or an HTTP date;
|
|
24
|
+
* `RateLimit-Reset` is the standard-headers fallback, in seconds. Capped so a
|
|
25
|
+
* bad header cannot park a loop for an hour, floored at a second so a `0` does
|
|
26
|
+
* not reproduce the hot-retry it is meant to stop.
|
|
27
|
+
*
|
|
28
|
+
* Lives next to {@link throwApiError} so every client path (not only the poll
|
|
29
|
+
* surface) can honour the server's number (ZIG-1124).
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseRetryAfterMs(headers: {
|
|
32
|
+
get(name: string): string | null;
|
|
33
|
+
}): number | null;
|
|
34
|
+
/**
|
|
35
|
+
* Throw the parsed failure as an {@link ApiError} (or {@link RateLimitedError}
|
|
36
|
+
* for 429), preserving status, body, machine code, and Retry-After.
|
|
37
|
+
*/
|
|
20
38
|
export declare function throwApiError(response: {
|
|
21
39
|
status: number;
|
|
40
|
+
headers?: {
|
|
41
|
+
get(name: string): string | null;
|
|
42
|
+
};
|
|
22
43
|
}, responseBody: string, defaultMessage: string): never;
|