@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,4 +1,3 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
1
|
import { type Creds, type Agreement, type EngagementKind, type BroadcastAudience } from '../types.js';
|
|
3
2
|
/**
|
|
4
3
|
* Shared proposal terms. When `engagementKind` is omitted the server defaults to `service`.
|
|
@@ -46,6 +45,33 @@ export interface ProposeDirectInput extends ProposeTerms {
|
|
|
46
45
|
export type ProposeBroadcastInput = Omit<ProposeDirectInput, 'proposedTo'> & {
|
|
47
46
|
audience?: BroadcastAudience;
|
|
48
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* A trust link's agreement, as every caller sees it.
|
|
50
|
+
*
|
|
51
|
+
* A link is reach, not commerce: it carries no money, no escrow, no execution
|
|
52
|
+
* state and no approvals ledger. Handing the raw document over anyway put Mongo
|
|
53
|
+
* bookkeeping in front of an LLM, which is what ZIG-957 forbade.
|
|
54
|
+
*
|
|
55
|
+
* Lives here rather than in `capabilities/links.ts` because this is where the
|
|
56
|
+
* rule is applied (ZIG-1111); that module re-exports it so the public name is
|
|
57
|
+
* unchanged.
|
|
58
|
+
*/
|
|
59
|
+
export declare function linkSummary(a: Agreement): Record<string, unknown>;
|
|
60
|
+
/**
|
|
61
|
+
* Every agreement document this client parses passes through here.
|
|
62
|
+
*
|
|
63
|
+
* The rule — a link is returned as its summary, anything else verbatim — used to
|
|
64
|
+
* be written out at six call sites across the SDK runner, the MCP tools and the
|
|
65
|
+
* capability layer, and three verbs never got it: `agreement_counter`,
|
|
66
|
+
* `agreement_fulfill` and `agreement_subcontract` returned the raw document
|
|
67
|
+
* (ZIG-1111). Applying it at the parse boundary means a new verb inherits the
|
|
68
|
+
* rule instead of remembering to opt in, and no surface can word its own verdict.
|
|
69
|
+
*
|
|
70
|
+
* Typed as `Agreement` on the way out: every key the summary keeps IS an
|
|
71
|
+
* Agreement field, so this narrows a document rather than returning a different
|
|
72
|
+
* shape.
|
|
73
|
+
*/
|
|
74
|
+
export declare function shapeAgreement(a: Agreement): Agreement;
|
|
49
75
|
/** @deprecated Alias for {@link ProposeDirectInput}. */
|
|
50
76
|
export type ProposeAgreementData = ProposeDirectInput;
|
|
51
77
|
export declare function proposeAgreement(proposalData: ProposeDirectInput, creds: Creds): Promise<Agreement>;
|
|
@@ -152,6 +178,7 @@ export interface GetMyAgreementsFilters {
|
|
|
152
178
|
partyOnly?: boolean;
|
|
153
179
|
}
|
|
154
180
|
export declare function getMyAgreements(filters: GetMyAgreementsFilters | undefined, creds: Creds): Promise<Agreement[]>;
|
|
181
|
+
/** One agreement, shaped: a link comes back as its summary. */
|
|
155
182
|
export declare function getAgreement(agreementId: string, creds: Creds): Promise<Agreement | null>;
|
|
156
183
|
export interface CreateAgreementBody {
|
|
157
184
|
proposedToId?: string;
|
|
@@ -181,6 +208,8 @@ export declare function fulfillAgreement(agreementId: string, creds: Creds): Pro
|
|
|
181
208
|
ok: boolean;
|
|
182
209
|
agreement: Agreement;
|
|
183
210
|
}>;
|
|
211
|
+
/** What an open-broadcast claim turned out to be. ⚠️ SYNC: backend AgreementOpenService. */
|
|
212
|
+
export type ClaimedKind = 'link' | 'offer' | 'quest' | 'hand-off';
|
|
184
213
|
/**
|
|
185
214
|
* Claim an open agreement (ZIG-524 phase 2 / ZIG-525):
|
|
186
215
|
* - open link invite (`engagementKind: link`, proposedTo everyone)
|
|
@@ -193,6 +222,7 @@ export declare function fulfillAgreement(agreementId: string, creds: Creds): Pro
|
|
|
193
222
|
export declare function claimAgreement(agreementId: string, creds: Creds): Promise<{
|
|
194
223
|
ok: boolean;
|
|
195
224
|
agreement: Agreement;
|
|
225
|
+
kind?: ClaimedKind;
|
|
196
226
|
}>;
|
|
197
227
|
/**
|
|
198
228
|
* Link types a caller may ASK for — the server's `CALLER_LINK_TYPES`, not its
|
|
@@ -251,6 +281,7 @@ export declare class AgreementClient {
|
|
|
251
281
|
claimAgreement(id: string): Promise<{
|
|
252
282
|
ok: boolean;
|
|
253
283
|
agreement: Agreement;
|
|
284
|
+
kind?: ClaimedKind;
|
|
254
285
|
}>;
|
|
255
286
|
linkToChat(id: string, chatId: string, linkType?: ChatLinkType): Promise<unknown>;
|
|
256
287
|
listChats(id: string): Promise<unknown[]>;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
1
|
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
3
2
|
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
4
3
|
import { OPEN_AGREEMENT_TARGET, ORG_AGREEMENT_TARGET, isBroadcastTarget } from '../types.js';
|
|
5
4
|
import { throwApiError } from '../shared/apiError.js';
|
|
6
|
-
// Lazy: read at call time so
|
|
7
|
-
// still takes effect. Baking it at module-load time would
|
|
8
|
-
// before the
|
|
5
|
+
// Lazy: read at call time so a `configureApiClient` call that lands after this
|
|
6
|
+
// module is imported still takes effect. Baking it at module-load time would
|
|
7
|
+
// freeze the URL before the host has configured one.
|
|
9
8
|
function getAgreementBaseUrl() {
|
|
10
9
|
return `${getBackendUrl()}/agreements`;
|
|
11
10
|
}
|
|
@@ -25,6 +24,54 @@ function assertCreds(creds, op) {
|
|
|
25
24
|
if (!creds?.agentId)
|
|
26
25
|
throw new Error(`agentId is required for ${op}`);
|
|
27
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* A trust link's agreement, as every caller sees it.
|
|
29
|
+
*
|
|
30
|
+
* A link is reach, not commerce: it carries no money, no escrow, no execution
|
|
31
|
+
* state and no approvals ledger. Handing the raw document over anyway put Mongo
|
|
32
|
+
* bookkeeping in front of an LLM, which is what ZIG-957 forbade.
|
|
33
|
+
*
|
|
34
|
+
* Lives here rather than in `capabilities/links.ts` because this is where the
|
|
35
|
+
* rule is applied (ZIG-1111); that module re-exports it so the public name is
|
|
36
|
+
* unchanged.
|
|
37
|
+
*/
|
|
38
|
+
export function linkSummary(a) {
|
|
39
|
+
return {
|
|
40
|
+
agreementId: a.agreementId,
|
|
41
|
+
// Kept deliberately: callers branch on this, and a summary that hides what
|
|
42
|
+
// kind of thing it describes breaks the code it is meant to protect.
|
|
43
|
+
engagementKind: a.engagementKind,
|
|
44
|
+
status: a.status,
|
|
45
|
+
proposalStatus: a.proposalStatus,
|
|
46
|
+
parties: {
|
|
47
|
+
creatorAgent: a.parties?.creatorAgent ?? null,
|
|
48
|
+
providerAgent: a.parties?.providerAgent ?? null,
|
|
49
|
+
creator: a.parties?.creator ?? null,
|
|
50
|
+
proposedTo: a.parties?.proposedTo ?? null,
|
|
51
|
+
},
|
|
52
|
+
...(a.description ? { description: a.description } : {}),
|
|
53
|
+
// Seat bookkeeping on an open invite — link state, not commerce.
|
|
54
|
+
...(a.linkInvite ? { linkInvite: a.linkInvite } : {}),
|
|
55
|
+
createdAt: a.createdAt,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Every agreement document this client parses passes through here.
|
|
60
|
+
*
|
|
61
|
+
* The rule — a link is returned as its summary, anything else verbatim — used to
|
|
62
|
+
* be written out at six call sites across the SDK runner, the MCP tools and the
|
|
63
|
+
* capability layer, and three verbs never got it: `agreement_counter`,
|
|
64
|
+
* `agreement_fulfill` and `agreement_subcontract` returned the raw document
|
|
65
|
+
* (ZIG-1111). Applying it at the parse boundary means a new verb inherits the
|
|
66
|
+
* rule instead of remembering to opt in, and no surface can word its own verdict.
|
|
67
|
+
*
|
|
68
|
+
* Typed as `Agreement` on the way out: every key the summary keeps IS an
|
|
69
|
+
* Agreement field, so this narrows a document rather than returning a different
|
|
70
|
+
* shape.
|
|
71
|
+
*/
|
|
72
|
+
export function shapeAgreement(a) {
|
|
73
|
+
return a.engagementKind === 'link' ? linkSummary(a) : a;
|
|
74
|
+
}
|
|
28
75
|
export async function proposeAgreement(proposalData, creds) {
|
|
29
76
|
if (!proposalData)
|
|
30
77
|
throw new Error('Proposal data is required for proposal creation');
|
|
@@ -48,7 +95,7 @@ export async function proposeAgreement(proposalData, creds) {
|
|
|
48
95
|
if (!data?.['agreement']) {
|
|
49
96
|
throw new Error('Invalid response: expected { agreement } from POST /agreements/proposals');
|
|
50
97
|
}
|
|
51
|
-
return data['agreement'];
|
|
98
|
+
return shapeAgreement(data['agreement']);
|
|
52
99
|
}
|
|
53
100
|
/** Propose a contract to one party (user or agent). Server defaults `engagementKind` to `service`. */
|
|
54
101
|
export async function proposeDirectTo(input, creds) {
|
|
@@ -96,7 +143,7 @@ export async function delegateAgreement(proposalData, creds) {
|
|
|
96
143
|
if (!data?.['agreement']) {
|
|
97
144
|
throw new Error('Invalid response: expected { agreement } from POST /agreements/:parentAgreementId/delegations');
|
|
98
145
|
}
|
|
99
|
-
return data['agreement'];
|
|
146
|
+
return shapeAgreement(data['agreement']);
|
|
100
147
|
}
|
|
101
148
|
/**
|
|
102
149
|
* Approve or reject a pending agreement (ZIG-524 canonical client path).
|
|
@@ -110,7 +157,10 @@ export async function respondToAgreement(agreementId, action, creds, opts = {})
|
|
|
110
157
|
if (!agreementId || !action)
|
|
111
158
|
throw new Error('Agreement ID and action are required for proposal response');
|
|
112
159
|
assertCreds(creds, 'proposal response');
|
|
113
|
-
|
|
160
|
+
// Unshaped on purpose: the approvals ledger below is exactly what the link
|
|
161
|
+
// summary drops, and resolving the caller's slot from a summary would fail
|
|
162
|
+
// every link approval with "no pending approval entry".
|
|
163
|
+
const agreement = opts.agreement ?? (await getAgreementDocument(agreementId, creds));
|
|
114
164
|
if (!agreement) {
|
|
115
165
|
throw new Error(`Agreement ${agreementId} not found`);
|
|
116
166
|
}
|
|
@@ -213,7 +263,7 @@ export async function approveAgreementAsParty(agreementId, partyId, status, cred
|
|
|
213
263
|
if (!data?.['agreement']) {
|
|
214
264
|
throw new Error('Invalid response: expected { agreement } from PUT /agreements/:id/approvals/:partyId');
|
|
215
265
|
}
|
|
216
|
-
return data['agreement'];
|
|
266
|
+
return shapeAgreement(data['agreement']);
|
|
217
267
|
}
|
|
218
268
|
export async function counterAgreement(agreementId, counter, creds) {
|
|
219
269
|
if (!agreementId)
|
|
@@ -232,7 +282,7 @@ export async function counterAgreement(agreementId, counter, creds) {
|
|
|
232
282
|
if (!data?.['agreement']) {
|
|
233
283
|
throw new Error('Invalid response: expected { agreement } from /agreements/:id/counter');
|
|
234
284
|
}
|
|
235
|
-
return data['agreement'];
|
|
285
|
+
return shapeAgreement(data['agreement']);
|
|
236
286
|
}
|
|
237
287
|
export async function getAgreementStatus(agreementId, creds) {
|
|
238
288
|
if (!agreementId)
|
|
@@ -261,8 +311,7 @@ export async function listAgreements(filters = {}, creds) {
|
|
|
261
311
|
assertCreds(creds, 'list agreements');
|
|
262
312
|
// ZIG-699 — return an empty array only for a genuine empty 200 result. Any
|
|
263
313
|
// failure (non-2xx / network) throws so the MCP tool reports a real error
|
|
264
|
-
// instead of "you have no agreements".
|
|
265
|
-
// so the tool's toolError/classifyToolError maps it to a stable code.
|
|
314
|
+
// instead of "you have no agreements". ZIG-1124 — HTTP failures are ApiError.
|
|
266
315
|
// Canonical query path: GET /agreements?scope=&status=&engagementKind=&...
|
|
267
316
|
const url = new URL(getAgreementBaseUrl());
|
|
268
317
|
if (filters.status)
|
|
@@ -284,10 +333,12 @@ export async function listAgreements(filters = {}, creds) {
|
|
|
284
333
|
if (!res.ok) {
|
|
285
334
|
const body = await res.text().catch(() => '');
|
|
286
335
|
runtimeLog.warn('AgreementClient', `⚠️ List agreements failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
287
|
-
|
|
336
|
+
throwApiError(res, body, `GET /agreements failed: ${res.status}`);
|
|
288
337
|
}
|
|
289
338
|
const data = await res.json().catch(() => null);
|
|
290
|
-
return Array.isArray(data?.['agreements'])
|
|
339
|
+
return Array.isArray(data?.['agreements'])
|
|
340
|
+
? data['agreements'].map(shapeAgreement)
|
|
341
|
+
: [];
|
|
291
342
|
}
|
|
292
343
|
export async function getMyAgreements(filters = {}, creds) {
|
|
293
344
|
assertCreds(creds, 'get my agreements');
|
|
@@ -316,20 +367,29 @@ export async function getMyAgreements(filters = {}, creds) {
|
|
|
316
367
|
if (!res.ok) {
|
|
317
368
|
const body = await res.text().catch(() => '');
|
|
318
369
|
runtimeLog.warn('AgreementClient', `⚠️ Get my agreements failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
319
|
-
|
|
370
|
+
throwApiError(res, body, `GET /agreements?scope=mine failed: ${res.status}`);
|
|
320
371
|
}
|
|
321
372
|
const data = await res.json().catch(() => null);
|
|
322
|
-
return Array.isArray(data?.['agreements'])
|
|
373
|
+
return Array.isArray(data?.['agreements'])
|
|
374
|
+
? data['agreements'].map(shapeAgreement)
|
|
375
|
+
: [];
|
|
323
376
|
}
|
|
324
|
-
|
|
377
|
+
/**
|
|
378
|
+
* The full agreement document, unshaped — for this client's OWN reads.
|
|
379
|
+
*
|
|
380
|
+
* `respondToAgreement` resolves which approvals slot the caller may fill, and
|
|
381
|
+
* `claimOpenAgreement` routes on the broadcast's open side; both need fields the
|
|
382
|
+
* link summary deliberately drops. Callers outside this module get the shaped
|
|
383
|
+
* `getAgreement`.
|
|
384
|
+
*/
|
|
385
|
+
async function getAgreementDocument(agreementId, creds) {
|
|
325
386
|
if (!agreementId)
|
|
326
387
|
return null;
|
|
327
388
|
assertCreds(creds, 'get agreement');
|
|
328
389
|
// ZIG-698 — a genuine 404 (and 200-with-no-agreement) is a real "not found"
|
|
329
390
|
// and returns null. Every other failure (403/5xx/network) must throw so the
|
|
330
391
|
// caller can tell "does not exist" from "could not fetch" instead of a 403
|
|
331
|
-
// masquerading as not-found.
|
|
332
|
-
// toolError; the message keeps the status whitespace-delimited for that.
|
|
392
|
+
// masquerading as not-found. ZIG-1124 — thrown as ApiError for toolError.
|
|
333
393
|
let res;
|
|
334
394
|
try {
|
|
335
395
|
res = await fetch(`${getAgreementBaseUrl()}/${agreementId}`, {
|
|
@@ -346,11 +406,16 @@ export async function getAgreement(agreementId, creds) {
|
|
|
346
406
|
if (!res.ok) {
|
|
347
407
|
const body = await res.text().catch(() => '');
|
|
348
408
|
runtimeLog.warn('AgreementClient', `⚠️ Get agreement failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
349
|
-
|
|
409
|
+
throwApiError(res, body, `GET /agreements/${agreementId} failed: ${res.status}`);
|
|
350
410
|
}
|
|
351
411
|
const data = await res.json().catch(() => null);
|
|
352
412
|
return data?.['agreement'] ?? null;
|
|
353
413
|
}
|
|
414
|
+
/** One agreement, shaped: a link comes back as its summary. */
|
|
415
|
+
export async function getAgreement(agreementId, creds) {
|
|
416
|
+
const agreement = await getAgreementDocument(agreementId, creds);
|
|
417
|
+
return agreement ? shapeAgreement(agreement) : null;
|
|
418
|
+
}
|
|
354
419
|
export async function createAgreement(body, creds) {
|
|
355
420
|
if (!body)
|
|
356
421
|
throw new Error('Body is required for agreement creation');
|
|
@@ -369,7 +434,8 @@ export async function createAgreement(body, creds) {
|
|
|
369
434
|
if (!data?.['agreement']) {
|
|
370
435
|
throw new Error('Invalid response: expected { ok, agreement } from POST /agreements');
|
|
371
436
|
}
|
|
372
|
-
|
|
437
|
+
const envelope = data;
|
|
438
|
+
return { ...envelope, agreement: shapeAgreement(envelope.agreement) };
|
|
373
439
|
}
|
|
374
440
|
export async function revokeAgreement(agreementId, creds) {
|
|
375
441
|
if (!agreementId)
|
|
@@ -389,7 +455,8 @@ export async function revokeAgreement(agreementId, creds) {
|
|
|
389
455
|
if (!data?.['agreement']) {
|
|
390
456
|
throw new Error('Invalid response: expected { ok, agreement } from DELETE /agreements/:id');
|
|
391
457
|
}
|
|
392
|
-
|
|
458
|
+
const envelope = data;
|
|
459
|
+
return { ...envelope, agreement: shapeAgreement(envelope.agreement) };
|
|
393
460
|
}
|
|
394
461
|
/** ZIG-832: mark an agreement fulfilled (complete). A provider closing its own
|
|
395
462
|
* delivered work — party-gated server-side. */
|
|
@@ -409,7 +476,8 @@ export async function fulfillAgreement(agreementId, creds) {
|
|
|
409
476
|
if (!data?.['agreement']) {
|
|
410
477
|
throw new Error('Invalid response: expected { ok, agreement } from POST /agreements/:id/fulfill');
|
|
411
478
|
}
|
|
412
|
-
|
|
479
|
+
const envelope = data;
|
|
480
|
+
return { ...envelope, agreement: shapeAgreement(envelope.agreement) };
|
|
413
481
|
}
|
|
414
482
|
/**
|
|
415
483
|
* Claim an open agreement (ZIG-524 phase 2 / ZIG-525):
|
|
@@ -433,7 +501,12 @@ export async function claimAgreement(agreementId, creds) {
|
|
|
433
501
|
if (!data?.['agreement']) {
|
|
434
502
|
throw new Error('Invalid response: expected { ok, agreement } from POST /agreements/:id/claim');
|
|
435
503
|
}
|
|
436
|
-
|
|
504
|
+
// ZIG-1155: the route reports which kind of broadcast this turned out to be.
|
|
505
|
+
// A caller cannot work it out from the row — post-claim no sentinel is left,
|
|
506
|
+
// and a quest (you do the work) reads the same shape as a standing offer (you
|
|
507
|
+
// pay for it) unless you know which slot you landed in.
|
|
508
|
+
const envelope = data;
|
|
509
|
+
return { ...envelope, agreement: shapeAgreement(envelope.agreement) };
|
|
437
510
|
}
|
|
438
511
|
// ---------------------------------------------------------------------------
|
|
439
512
|
// Chat links
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
1
|
import { type Creds } from '../types.js';
|
|
3
2
|
/** Shape of GET /chats/mine items — the backend's ChatReadDto (ZIG-665). */
|
|
4
3
|
export interface ChatSummary {
|
|
@@ -10,7 +9,9 @@ export interface ChatSummary {
|
|
|
10
9
|
orgId: string | null;
|
|
11
10
|
isOrgChat: boolean;
|
|
12
11
|
}
|
|
13
|
-
export declare function openConversation(participantId: string, creds: Creds
|
|
12
|
+
export declare function openConversation(participantId: string, creds: Creds, { newChat }?: {
|
|
13
|
+
newChat?: boolean;
|
|
14
|
+
}): Promise<{
|
|
14
15
|
chatId: string;
|
|
15
16
|
}>;
|
|
16
17
|
export interface SendChatMessageInput {
|
|
@@ -75,7 +76,9 @@ export declare class ChatClient {
|
|
|
75
76
|
* @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
|
|
76
77
|
*/
|
|
77
78
|
constructor(operatorKey: string, agentId?: string);
|
|
78
|
-
open(participantId: string
|
|
79
|
+
open(participantId: string, opts?: {
|
|
80
|
+
newChat?: boolean;
|
|
81
|
+
}): Promise<{
|
|
79
82
|
chatId: string;
|
|
80
83
|
}>;
|
|
81
84
|
addMember(input: AddChatMemberInput): Promise<AddChatMemberResult>;
|
package/dist/http/ChatClient.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
1
|
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
3
2
|
import { getBackendUrl } from '../utils/urlUtils.js';
|
|
4
3
|
import { throwApiError } from '../shared/apiError.js';
|
|
@@ -18,14 +17,16 @@ function assertCreds(creds, op) {
|
|
|
18
17
|
if (!creds?.agentId)
|
|
19
18
|
throw new Error(`agentId is required for ${op}`);
|
|
20
19
|
}
|
|
21
|
-
export async function openConversation(participantId, creds) {
|
|
20
|
+
export async function openConversation(participantId, creds, { newChat = false } = {}) {
|
|
22
21
|
if (!participantId)
|
|
23
22
|
throw new Error('participantId is required for openConversation');
|
|
24
23
|
assertCreds(creds, 'open conversation');
|
|
25
24
|
const res = await fetch(`${getBackendUrl()}/chats`, {
|
|
26
25
|
method: 'POST',
|
|
27
26
|
headers: buildHeaders(creds),
|
|
28
|
-
|
|
27
|
+
// Only sent when asked for: an older backend ignores the field, so a
|
|
28
|
+
// caller that never wants a separate room behaves identically either way.
|
|
29
|
+
body: JSON.stringify({ participantId, ...(newChat ? { newChat: true } : {}) }),
|
|
29
30
|
});
|
|
30
31
|
if (!res.ok) {
|
|
31
32
|
const body = await res.text().catch(() => '');
|
|
@@ -104,7 +105,7 @@ export async function listMyChats(creds) {
|
|
|
104
105
|
assertCreds(creds, 'list my chats');
|
|
105
106
|
// ZIG-699 — empty array only for a genuine empty 200; any failure (non-2xx /
|
|
106
107
|
// network) throws so ziggs_chat_list reports a real error instead of "you
|
|
107
|
-
// have no chats".
|
|
108
|
+
// have no chats". ZIG-1124 — HTTP failures are ApiError (status/body/code).
|
|
108
109
|
let res;
|
|
109
110
|
try {
|
|
110
111
|
res = await fetch(`${getBackendUrl()}/chats/mine`, {
|
|
@@ -119,7 +120,7 @@ export async function listMyChats(creds) {
|
|
|
119
120
|
if (!res.ok) {
|
|
120
121
|
const body = await res.text().catch(() => '');
|
|
121
122
|
runtimeLog.warn('ChatClient', `⚠️ listMyChats failed: ${res.status} ${res.statusText} ${body?.slice(0, 200)}`);
|
|
122
|
-
|
|
123
|
+
throwApiError(res, body, `GET /chats/mine failed: ${res.status}`);
|
|
123
124
|
}
|
|
124
125
|
const data = await res.json().catch(() => null);
|
|
125
126
|
return Array.isArray(data?.['chats']) ? data['chats'] : [];
|
|
@@ -137,7 +138,7 @@ export class ChatClient {
|
|
|
137
138
|
// standalone functions still assert it per call.
|
|
138
139
|
this.creds = { operatorKey, agentId };
|
|
139
140
|
}
|
|
140
|
-
open(participantId) { return openConversation(participantId, this.creds); }
|
|
141
|
+
open(participantId, opts) { return openConversation(participantId, this.creds, opts); }
|
|
141
142
|
addMember(input) { return addChatMember(input, this.creds); }
|
|
142
143
|
sendMessage(input) { return sendChatMessage(input, this.creds); }
|
|
143
144
|
listMine() { return listMyChats(this.creds); }
|
|
@@ -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
|
import { GrantsClient } from './GrantsClient.js';
|
|
5
5
|
// ZIG-569 — defense-in-depth mirror of the backend leak-guard
|
|
@@ -169,10 +169,9 @@ export class ConnectionsClient {
|
|
|
169
169
|
const response = await fetch(`${this.baseUrl}${path}`, init);
|
|
170
170
|
const text = await response.text().catch(() => '');
|
|
171
171
|
if (!response.ok) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
throw err;
|
|
172
|
+
// ZIG-1124 — ApiError (status/body/code); ConnectionsError remains the
|
|
173
|
+
// documented duck type for callers that branch on `.status`.
|
|
174
|
+
throwApiError(response, text, `${method} ${path} failed: ${response.status}`);
|
|
176
175
|
}
|
|
177
176
|
return text;
|
|
178
177
|
}
|
|
@@ -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
|
* P4 discovery — labels-only pointers to context the agent could REQUEST but
|
|
@@ -34,7 +34,7 @@ export class ContextDiscoveryClient {
|
|
|
34
34
|
});
|
|
35
35
|
const body = await res.text().catch(() => '');
|
|
36
36
|
if (!res.ok) {
|
|
37
|
-
|
|
37
|
+
throwApiError(res, body, `ContextDiscoveryClient.discoverGrantable failed: ${res.status}`);
|
|
38
38
|
}
|
|
39
39
|
const parsed = JSON.parse(body);
|
|
40
40
|
return (parsed.items ?? []).map((i) => ({
|
|
@@ -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
|
export const CONTEXT_READ_TYPES = [
|
|
@@ -105,18 +104,11 @@ export class ContextReadClient {
|
|
|
105
104
|
const res = await fetch(url.toString(), { headers });
|
|
106
105
|
const body = await res.text().catch(() => '');
|
|
107
106
|
if (!res.ok) {
|
|
108
|
-
// Carry the status like `snapshot()` does, so callers can branch on it.
|
|
109
107
|
// A 403 here is a legitimate outcome, not a transport failure: addressing
|
|
110
108
|
// and authorisation are separate, so an agent can be told about mail it
|
|
111
|
-
// is not (or is no longer) allowed to open.
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
if (res.status === 429) {
|
|
115
|
-
throw pollSurfaceError(`ContextReadClient.read ${type}`, res, body);
|
|
116
|
-
}
|
|
117
|
-
const err = new Error(`ContextReadClient.read ${type} ${res.status} ${body.slice(0, 200)}`);
|
|
118
|
-
err.status = res.status;
|
|
119
|
-
throw err;
|
|
109
|
+
// is not (or is no longer) allowed to open. ZIG-1124 — one ApiError shape
|
|
110
|
+
// (429 → RateLimitedError with Retry-After).
|
|
111
|
+
throw pollSurfaceError(`ContextReadClient.read ${type}`, res, body);
|
|
120
112
|
}
|
|
121
113
|
return JSON.parse(body);
|
|
122
114
|
}
|
|
@@ -151,12 +143,8 @@ export class ContextReadClient {
|
|
|
151
143
|
const res = await fetch(url.toString(), { headers });
|
|
152
144
|
const body = await res.text().catch(() => '');
|
|
153
145
|
if (!res.ok) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
const err = new Error(`ContextReadClient.snapshot ${res.status} ${body.slice(0, 200)}`);
|
|
158
|
-
err.status = res.status;
|
|
159
|
-
throw err;
|
|
146
|
+
// ZIG-1124 — ApiError for every non-OK (429 → RateLimitedError).
|
|
147
|
+
throw pollSurfaceError('ContextReadClient.snapshot', res, body);
|
|
160
148
|
}
|
|
161
149
|
return JSON.parse(body);
|
|
162
150
|
}
|
|
@@ -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-648 — unified grant listing across every rail. `GET /grants` returns the
|
|
@@ -41,7 +41,7 @@ export class GrantsClient {
|
|
|
41
41
|
});
|
|
42
42
|
const body = await res.text().catch(() => '');
|
|
43
43
|
if (!res.ok) {
|
|
44
|
-
|
|
44
|
+
throwApiError(res, body, `GrantsClient.listGrants failed: ${res.status}`);
|
|
45
45
|
}
|
|
46
46
|
const parsed = JSON.parse(body);
|
|
47
47
|
return {
|