@ziggs-ai/api-client 0.7.1 → 0.9.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.
Files changed (38) hide show
  1. package/README.md +10 -0
  2. package/dist/capabilities/artifacts.d.ts +28 -0
  3. package/dist/capabilities/artifacts.js +200 -17
  4. package/dist/capabilities/context.js +37 -16
  5. package/dist/capabilities/grants.d.ts +8 -1
  6. package/dist/capabilities/grants.js +17 -11
  7. package/dist/capabilities/index.d.ts +1 -1
  8. package/dist/capabilities/index.js +1 -1
  9. package/dist/capabilities/types.d.ts +1 -0
  10. package/dist/capabilities/types.js +4 -2
  11. package/dist/http/AgreementClient.d.ts +35 -16
  12. package/dist/http/AgreementClient.js +87 -33
  13. package/dist/http/ArtifactsClient.d.ts +38 -1
  14. package/dist/http/ArtifactsClient.js +70 -10
  15. package/dist/http/ChatClient.js +4 -14
  16. package/dist/http/ContextGrantsClient.d.ts +21 -1
  17. package/dist/http/ContextGrantsClient.js +36 -18
  18. package/dist/http/ContextReadClient.d.ts +30 -3
  19. package/dist/http/ContextReadClient.js +58 -1
  20. package/dist/http/InboxClient.d.ts +32 -3
  21. package/dist/http/MarketplaceClient.d.ts +0 -1
  22. package/dist/http/MarketplaceClient.js +4 -10
  23. package/dist/http/PaymentsClient.js +2 -12
  24. package/dist/http/TaskClient.d.ts +8 -0
  25. package/dist/http/TaskClient.js +4 -21
  26. package/dist/http/grants.d.ts +12 -1
  27. package/dist/http/grants.js +21 -0
  28. package/dist/http/index.d.ts +4 -4
  29. package/dist/http/index.js +2 -2
  30. package/dist/http/operatorHeaders.d.ts +7 -1
  31. package/dist/http/operatorHeaders.js +8 -1
  32. package/dist/index.d.ts +3 -1
  33. package/dist/index.js +5 -1
  34. package/dist/shared/apiError.d.ts +22 -0
  35. package/dist/shared/apiError.js +57 -0
  36. package/dist/types.d.ts +55 -0
  37. package/dist/types.js +19 -0
  38. package/package.json +1 -1
@@ -1,5 +1,28 @@
1
1
  import 'dotenv/config';
2
- export type ContextReadType = 'messages' | 'artifacts' | 'agreements' | 'tasks';
2
+ export declare const CONTEXT_READ_TYPES: readonly ["messages", "artifacts", "agreements", "tasks"];
3
+ export type ContextReadType = (typeof CONTEXT_READ_TYPES)[number];
4
+ /**
5
+ * Entry points a read can name as `via=<kind>:<id>` — the server's `parseVia`
6
+ * grammar. `counterparty` parses but reads nothing: it resolves a scope graph,
7
+ * not content, which is why {@link CONTEXT_READ_VIA} admits it for no type.
8
+ */
9
+ export declare const VIA_KINDS: readonly ["chat", "agreement", "task", "counterparty", "artifact"];
10
+ export type ViaKind = (typeof VIA_KINDS)[number];
11
+ /**
12
+ * Which entry points each read type actually accepts, mirroring the server's
13
+ * `CONTEXT_READ_VIA`. Stated once here so the tool descriptions, the argument
14
+ * check, and this type all read off the same list instead of three prose
15
+ * copies that drift — and so a wrong pairing is refused with the reason rather
16
+ * than as a bare 400 from a round-trip away.
17
+ */
18
+ export declare const CONTEXT_READ_VIA: Record<ContextReadType, readonly ViaKind[]>;
19
+ /** `chat:<id>, agreement:<id>` — the accepted entries for one read type, for humans. */
20
+ export declare function viaHint(type: ContextReadType): string;
21
+ /** Split `chat:abc` into its parts, or null when it is not a `via` at all. */
22
+ export declare function parseVia(via: string): {
23
+ kind: ViaKind;
24
+ id: string;
25
+ } | null;
3
26
  export interface ContextReadQuery {
4
27
  via: string;
5
28
  cursor?: string;
@@ -12,7 +35,7 @@ export interface ContextReadQuery {
12
35
  export interface ContextReadEnvelope<T = unknown> {
13
36
  type: ContextReadType;
14
37
  via: {
15
- kind: string;
38
+ kind: ViaKind;
16
39
  id: string;
17
40
  };
18
41
  items: T[];
@@ -44,11 +67,15 @@ export declare class ContextReadClient {
44
67
  private readonly operatorKey;
45
68
  private readonly agentId?;
46
69
  private readonly baseUrl;
70
+ private readonly laneId?;
47
71
  /**
48
72
  * @param operatorKey Agent-scoped or fleet operator key.
49
73
  * @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
74
+ * @param laneId ZIG-1092 — the wake's lane, sent as X-Ziggs-Lane. This is the
75
+ * path the dogfood leak ran through: `via=artifact:<other customer's spec>`
76
+ * was authorised purely because the same agent had authored it.
50
77
  */
51
- constructor(operatorKey: string, agentId?: string, baseUrl?: string);
78
+ constructor(operatorKey: string, agentId?: string, baseUrl?: string, laneId?: string);
52
79
  read<T = unknown>(type: ContextReadType, query: ContextReadQuery): Promise<ContextReadEnvelope<T>>;
53
80
  /**
54
81
  * Aggregated chat snapshot — `GET /context/snapshot?via=chat:<id>`. The
@@ -1,6 +1,54 @@
1
1
  import 'dotenv/config';
2
2
  import { getBackendUrl } from '../utils/urlUtils.js';
3
3
  import { pollSurfaceError } from '../shared/rateLimit.js';
4
+ export const CONTEXT_READ_TYPES = [
5
+ 'messages',
6
+ 'artifacts',
7
+ 'agreements',
8
+ 'tasks',
9
+ ];
10
+ /**
11
+ * Entry points a read can name as `via=<kind>:<id>` — the server's `parseVia`
12
+ * grammar. `counterparty` parses but reads nothing: it resolves a scope graph,
13
+ * not content, which is why {@link CONTEXT_READ_VIA} admits it for no type.
14
+ */
15
+ export const VIA_KINDS = [
16
+ 'chat',
17
+ 'agreement',
18
+ 'task',
19
+ 'counterparty',
20
+ 'artifact',
21
+ ];
22
+ /**
23
+ * Which entry points each read type actually accepts, mirroring the server's
24
+ * `CONTEXT_READ_VIA`. Stated once here so the tool descriptions, the argument
25
+ * check, and this type all read off the same list instead of three prose
26
+ * copies that drift — and so a wrong pairing is refused with the reason rather
27
+ * than as a bare 400 from a round-trip away.
28
+ */
29
+ export const CONTEXT_READ_VIA = {
30
+ messages: ['chat'],
31
+ artifacts: ['chat', 'agreement', 'task', 'artifact'],
32
+ agreements: ['chat', 'agreement'],
33
+ tasks: ['agreement', 'task'],
34
+ };
35
+ /** `chat:<id>, agreement:<id>` — the accepted entries for one read type, for humans. */
36
+ export function viaHint(type) {
37
+ return CONTEXT_READ_VIA[type].map((k) => `${k}:<id>`).join(', ');
38
+ }
39
+ /** Split `chat:abc` into its parts, or null when it is not a `via` at all. */
40
+ export function parseVia(via) {
41
+ const at = via.indexOf(':');
42
+ if (at <= 0)
43
+ return null;
44
+ const kind = via.slice(0, at);
45
+ const id = via.slice(at + 1);
46
+ if (!id)
47
+ return null;
48
+ return VIA_KINDS.includes(kind)
49
+ ? { kind: kind, id }
50
+ : null;
51
+ }
4
52
  /**
5
53
  * Protocol-first uniform context reads (ZIG-427).
6
54
  * Wraps `GET /context/read/:type` — one client, one envelope, four types.
@@ -9,16 +57,21 @@ export class ContextReadClient {
9
57
  operatorKey;
10
58
  agentId;
11
59
  baseUrl;
60
+ laneId;
12
61
  /**
13
62
  * @param operatorKey Agent-scoped or fleet operator key.
14
63
  * @param agentId Required for fleet keys (sent as X-Agent-Id). Omit for agent-scoped keys.
64
+ * @param laneId ZIG-1092 — the wake's lane, sent as X-Ziggs-Lane. This is the
65
+ * path the dogfood leak ran through: `via=artifact:<other customer's spec>`
66
+ * was authorised purely because the same agent had authored it.
15
67
  */
16
- constructor(operatorKey, agentId, baseUrl) {
68
+ constructor(operatorKey, agentId, baseUrl, laneId) {
17
69
  if (!operatorKey)
18
70
  throw new Error('ContextReadClient: operatorKey is required');
19
71
  this.operatorKey = operatorKey;
20
72
  this.agentId = agentId;
21
73
  this.baseUrl = baseUrl || getBackendUrl();
74
+ this.laneId = laneId;
22
75
  }
23
76
  async read(type, query) {
24
77
  if (!query.via?.trim()) {
@@ -44,6 +97,8 @@ export class ContextReadClient {
44
97
  };
45
98
  if (this.agentId)
46
99
  headers['X-Agent-Id'] = this.agentId;
100
+ if (this.laneId)
101
+ headers['X-Ziggs-Lane'] = this.laneId;
47
102
  if (query.contextGrantId) {
48
103
  headers['X-Context-Grant-Id'] = query.contextGrantId;
49
104
  }
@@ -88,6 +143,8 @@ export class ContextReadClient {
88
143
  };
89
144
  if (this.agentId)
90
145
  headers['X-Agent-Id'] = this.agentId;
146
+ if (this.laneId)
147
+ headers['X-Ziggs-Lane'] = this.laneId;
91
148
  if (opts.contextGrantId) {
92
149
  headers['X-Context-Grant-Id'] = opts.contextGrantId;
93
150
  }
@@ -1,11 +1,21 @@
1
1
  import 'dotenv/config';
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';
2
13
  /**
3
14
  * One thing addressed to this agent. A reference, never content — following it
4
15
  * (a chat read, a task read) is where this agent's grants are enforced.
5
16
  */
6
17
  export interface InboxDeliveryRef {
7
- /** 'message' | 'artifact' | 'task-state' | 'agreement'. */
8
- kind: string;
18
+ kind: InboxDeliveryKind;
9
19
  resourceId: string;
10
20
  chatId: string | null;
11
21
  agreementId: string | null;
@@ -24,16 +34,35 @@ export interface InboxProposalRef {
24
34
  agreementId: string;
25
35
  title: string;
26
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;
27
49
  }
28
50
  export interface InboxConnectionRequestRef {
29
51
  requestId: string;
30
- requesterAgentId: 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;
31
57
  /** ZIG-1039 — human-readable name for consent cards. */
32
58
  requesterDisplayName?: string | null;
33
59
  /** ZIG-1039 — org label for consent cards. */
34
60
  requesterOrgName?: string | null;
35
61
  message: string | null;
36
62
  requestedAt: string | null;
63
+ /** ZIG-1087 — see InboxProposalRef; a link request uses the same gate. */
64
+ pendingApprovalPartyIds?: string[];
65
+ proposedTo?: string | null;
37
66
  }
38
67
  /** Pull-only MCP: prompt the human when proposals need a decision (ZIG-482 / ZIG-481). */
39
68
  export interface InboxHumanAttention {
@@ -31,7 +31,6 @@ export interface PublishQuestPayload {
31
31
  description: string;
32
32
  chatId?: string;
33
33
  payerId?: string;
34
- parentTaskId?: string;
35
34
  price?: number;
36
35
  lifecycle?: string;
37
36
  expiresAt?: string;
@@ -1,12 +1,15 @@
1
1
  import 'dotenv/config';
2
2
  import { getBackendUrl } from '../utils/urlUtils.js';
3
- import { ApiError } from '../types.js';
3
+ import { throwApiError } from '../shared/apiError.js';
4
4
  function getMarketplaceBaseUrl() { return `${getBackendUrl()}/marketplace`; }
5
5
  function buildHeaders(creds) {
6
6
  return {
7
7
  'content-type': 'application/json',
8
8
  Authorization: `Bearer ${creds.operatorKey}`,
9
9
  'X-Agent-Id': creds.agentId,
10
+ // ZIG-1092 — the wake's lane, so the backend can fence this call to the
11
+ // engagement it belongs to rather than the agent's whole authority.
12
+ ...(creds.laneId ? { 'X-Ziggs-Lane': creds.laneId } : {}),
10
13
  };
11
14
  }
12
15
  function assertCreds(creds, op) {
@@ -15,15 +18,6 @@ function assertCreds(creds, op) {
15
18
  if (!creds?.agentId)
16
19
  throw new Error(`agentId is required for ${op}`);
17
20
  }
18
- function throwApiError(response, body, defaultMsg) {
19
- let msg = defaultMsg;
20
- try {
21
- const d = JSON.parse(body);
22
- msg = d['details'] || d['error'] || d['message'] || defaultMsg;
23
- }
24
- catch { /**/ }
25
- throw new ApiError(msg, response.status);
26
- }
27
21
  export async function publishOffer(payload, creds) {
28
22
  assertCreds(creds, 'marketplace offer publish');
29
23
  const res = await fetch(`${getMarketplaceBaseUrl()}/offers/publish`, {
@@ -2,20 +2,10 @@ import 'dotenv/config';
2
2
  import { getBackendUrl } from '../utils/urlUtils.js';
3
3
  import { buildOperatorHeaders } from './operatorHeaders.js';
4
4
  import { GrantsClient } from './GrantsClient.js';
5
+ import { parseErrorMessage } from '../shared/apiError.js';
5
6
  function randomIdempotencyKey(prefix = 'op') {
6
7
  return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
7
8
  }
8
- function parseError(text, fallback) {
9
- if (!text)
10
- return fallback;
11
- try {
12
- const parsed = JSON.parse(text);
13
- return parsed['error'] || parsed['message'] || text;
14
- }
15
- catch {
16
- return text;
17
- }
18
- }
19
9
  /**
20
10
  * ZIG-894 — the one payments client for every surface (agent-sdk, ziggs-mcp,
21
11
  * scripts). Consolidates the former agent-sdk private ZiggsPayClient. Wallet
@@ -227,7 +217,7 @@ export class PaymentsClient {
227
217
  const response = await fetch(`${this.baseUrl}${path}`, init);
228
218
  const text = await response.text();
229
219
  if (!response.ok) {
230
- const err = new Error(parseError(text, `HTTP ${response.status}`));
220
+ const err = new Error(parseErrorMessage(text, `HTTP ${response.status}`));
231
221
  err.status = response.status;
232
222
  err.body = text;
233
223
  throw err;
@@ -1,10 +1,18 @@
1
1
  import 'dotenv/config';
2
2
  import { type Creds, type Task, type TaskState } from '../types.js';
3
+ /**
4
+ * When the buyer reviews a task's plan. Task-rail only — an agreement has no
5
+ * plan to review, which is why ZIG-1095 cut this from the propose/counter/
6
+ * subcontract inputs rather than teaching those routes to keep one.
7
+ */
8
+ export type PlanReviewTiming = 'with_proposal' | 'before_execution';
3
9
  export interface CreateTaskData {
4
10
  description: string;
5
11
  agreementId: string;
6
12
  parentTaskId?: string;
7
13
  plan?: unknown;
14
+ planReviewTiming?: PlanReviewTiming;
15
+ requireMidWorkPlanAck?: boolean;
8
16
  idempotencyKey?: string;
9
17
  /** Explicit delegation target (ZIG-586) — must be a party to the agreement; validated server-side. */
10
18
  assigneeId?: string;
@@ -1,12 +1,15 @@
1
1
  import 'dotenv/config';
2
2
  import { getBackendUrl } from '../utils/urlUtils.js';
3
- import { ApiError } from '../types.js';
3
+ import { throwApiError } from '../shared/apiError.js';
4
4
  function getTaskBaseUrl() { return `${getBackendUrl()}/tasks`; }
5
5
  function buildHeaders(creds) {
6
6
  return {
7
7
  'content-type': 'application/json',
8
8
  Authorization: `Bearer ${creds.operatorKey}`,
9
9
  'X-Agent-Id': creds.agentId,
10
+ // ZIG-1092 — the wake's lane, so the backend can fence this call to the
11
+ // engagement it belongs to rather than the agent's whole authority.
12
+ ...(creds.laneId ? { 'X-Ziggs-Lane': creds.laneId } : {}),
10
13
  };
11
14
  }
12
15
  function assertCreds(creds, op) {
@@ -15,26 +18,6 @@ function assertCreds(creds, op) {
15
18
  if (!creds?.agentId)
16
19
  throw new Error(`agentId is required for ${op}`);
17
20
  }
18
- function parseErrorMessage(responseBody, defaultMessage) {
19
- if (!responseBody)
20
- return defaultMessage;
21
- try {
22
- const d = JSON.parse(responseBody);
23
- // NestJS ValidationPipe returns { message: string[] | string, error: 'Bad
24
- // Request', statusCode }. Prefer the detailed `message` over the generic
25
- // `error` so the real cause (which field failed validation) is surfaced
26
- // instead of a bare "Bad Request". (ZIG-832)
27
- const msg = d['message'];
28
- const detailed = Array.isArray(msg) ? msg.join('; ') : (typeof msg === 'string' ? msg : undefined);
29
- return d['details'] || detailed || d['error'] || defaultMessage;
30
- }
31
- catch {
32
- return responseBody || defaultMessage;
33
- }
34
- }
35
- function throwApiError(response, responseBody, defaultMessage) {
36
- throw new ApiError(parseErrorMessage(responseBody, defaultMessage), response.status, responseBody);
37
- }
38
21
  function extractTask(data) {
39
22
  if (!data || typeof data !== 'object')
40
23
  return null;
@@ -11,7 +11,18 @@
11
11
  * watermark are presented as `temporal` / `watermark_at` caveats.
12
12
  */
13
13
  export type GrantHealth = 'active' | 'expired' | 'revoked';
14
- export type GrantScopeKind = 'chat' | 'agreement' | 'org' | 'connection' | 'wallet';
14
+ /**
15
+ * The context rail's scope kinds, as VALUES — the type below is derived from
16
+ * them, so widening the rail is one edit rather than a type change plus however
17
+ * many hand-written literal lists happen to exist. A literal subset still
18
+ * typechecks against the union, which is how the CLI's grant listings silently
19
+ * stopped showing a whole scope kind after `artifact` was added; anything that
20
+ * means "every context scope" should read this.
21
+ */
22
+ export declare const CONTEXT_GRANT_SCOPE_KINDS: readonly ["chat", "agreement", "org", "artifact"];
23
+ /** Every scope kind across every rail: context + connection + payment. */
24
+ export declare const GRANT_SCOPE_KINDS: readonly ["chat", "agreement", "org", "artifact", "connection", "wallet"];
25
+ export type GrantScopeKind = (typeof GRANT_SCOPE_KINDS)[number];
15
26
  export interface GrantScopeView {
16
27
  kind: GrantScopeKind;
17
28
  id: string;
@@ -1,3 +1,24 @@
1
+ /**
2
+ * The context rail's scope kinds, as VALUES — the type below is derived from
3
+ * them, so widening the rail is one edit rather than a type change plus however
4
+ * many hand-written literal lists happen to exist. A literal subset still
5
+ * typechecks against the union, which is how the CLI's grant listings silently
6
+ * stopped showing a whole scope kind after `artifact` was added; anything that
7
+ * means "every context scope" should read this.
8
+ */
9
+ export const CONTEXT_GRANT_SCOPE_KINDS = [
10
+ 'chat',
11
+ 'agreement',
12
+ 'org',
13
+ // ZIG-1037: narrowest context scope
14
+ 'artifact',
15
+ ];
16
+ /** Every scope kind across every rail: context + connection + payment. */
17
+ export const GRANT_SCOPE_KINDS = [
18
+ ...CONTEXT_GRANT_SCOPE_KINDS,
19
+ 'connection',
20
+ 'wallet',
21
+ ];
1
22
  /** Value of the first caveat of `type` on a grant, or undefined. */
2
23
  export function grantCaveat(grant, type) {
3
24
  return grant.caveats.find((c) => c.type === type)?.value;
@@ -7,15 +7,15 @@ export { MessagesClient } from './MessagesClient.js';
7
7
  export type { ListMessagesOptions, ListMessagesResult } from './MessagesClient.js';
8
8
  export { ArtifactsClient, artifactScopeForSession, AGREEMENT_LANE_PREFIX, } from './ArtifactsClient.js';
9
9
  export type { ArtifactVisibility, ListArtifactsOptions, ListArtifactsQuery, ListArtifactsResult, WriteArtifactInput, } from './ArtifactsClient.js';
10
- export { ContextReadClient } from './ContextReadClient.js';
11
- export type { ContextReadType, ContextReadQuery, ContextReadEnvelope, ContextSnapshotResult, } from './ContextReadClient.js';
10
+ export { ContextReadClient, CONTEXT_READ_TYPES, CONTEXT_READ_VIA, VIA_KINDS, parseVia, viaHint, } from './ContextReadClient.js';
11
+ export type { ContextReadType, ContextReadQuery, ContextReadEnvelope, ContextSnapshotResult, ViaKind, } from './ContextReadClient.js';
12
12
  export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
13
13
  export type { DiscoverableItem } from './ContextDiscoveryClient.js';
14
14
  export { GrantsClient } from './GrantsClient.js';
15
15
  export type { ListGrantsQuery, ListGrantsResult, UnreadableRail } from './GrantsClient.js';
16
16
  export { ContextGrantsClient } from './ContextGrantsClient.js';
17
17
  export type { ContextGrantRecord, ContextGrantScope, ContextGrantScopeKind, ContextTemporal, IssueContextGrantInput, DelegateContextGrantInput, DelegateContextGrantResult, ReachEntry, GrantReachResult, } from './ContextGrantsClient.js';
18
- export { grantCaveat } from './grants.js';
18
+ export { grantCaveat, CONTEXT_GRANT_SCOPE_KINDS, GRANT_SCOPE_KINDS, } from './grants.js';
19
19
  export type { GrantView, GrantScopeKind, GrantScopeView, GrantCaveatView, GrantHealth, } from './grants.js';
20
20
  export { PaymentsClient } from './PaymentsClient.js';
21
21
  export type { PaymentsError, WalletBalance, WalletRef, PaymentTransactionView, TransferResult, HoldResult, ReleaseResult, PaymentGrantView, PaymentGrantEnvelope, RevokeGrantResult, PaymentApproval, WaitForApprovalResult, } from './PaymentsClient.js';
@@ -26,4 +26,4 @@ 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 { InboxDeliveryRef, InboxChatNews, InboxProposalRef, InboxTaskRef, InboxConnectionRequestRef, InboxHumanAttention, InboxEnvelope, InboxAckResult, InboxOperatorAgentEntry, InboxOperatorEnvelope, } from './InboxClient.js';
29
+ export type { InboxDeliveryKind, InboxDeliveryRef, InboxChatNews, InboxProposalRef, InboxTaskRef, InboxConnectionRequestRef, InboxHumanAttention, InboxEnvelope, InboxAckResult, InboxOperatorAgentEntry, InboxOperatorEnvelope, } from './InboxClient.js';
@@ -7,11 +7,11 @@ export { MessagesClient } from './MessagesClient.js';
7
7
  export { ArtifactsClient,
8
8
  // ZIG-1032: agreement lanes are not chats — callers scope artifact writes with this.
9
9
  artifactScopeForSession, AGREEMENT_LANE_PREFIX, } from './ArtifactsClient.js';
10
- export { ContextReadClient } from './ContextReadClient.js';
10
+ export { ContextReadClient, CONTEXT_READ_TYPES, CONTEXT_READ_VIA, VIA_KINDS, parseVia, viaHint, } from './ContextReadClient.js';
11
11
  export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
12
12
  export { GrantsClient } from './GrantsClient.js';
13
13
  export { ContextGrantsClient } from './ContextGrantsClient.js';
14
- export { grantCaveat } from './grants.js';
14
+ export { grantCaveat, CONTEXT_GRANT_SCOPE_KINDS, GRANT_SCOPE_KINDS, } from './grants.js';
15
15
  export { PaymentsClient } from './PaymentsClient.js';
16
16
  export { ConnectionsClient, assertNoLeakedConnectionSecret, } from './ConnectionsClient.js';
17
17
  export { fetchMyOrgs, resolveOrgSelector, fetchDelegateAccess, } from './OrgsClient.js';
@@ -3,4 +3,10 @@
3
3
  * an agentId is present — agent-scoped keys identify the agent themselves;
4
4
  * fleet keys must pass one (ZIG-642).
5
5
  */
6
- export declare function buildOperatorHeaders(operatorKey: string, agentId?: string, extra?: Record<string, string>): Record<string, string>;
6
+ export declare function buildOperatorHeaders(operatorKey: string, agentId?: string, extra?: Record<string, string>,
7
+ /**
8
+ * ZIG-1092 — the lane this call belongs to, sent as `X-Ziggs-Lane`. The
9
+ * backend narrows the wake's reach to the engagement's orgs; omitting it
10
+ * narrows to the agent's own org, so it can never widen reach.
11
+ */
12
+ laneId?: string): Record<string, string>;
@@ -3,10 +3,17 @@
3
3
  * an agentId is present — agent-scoped keys identify the agent themselves;
4
4
  * fleet keys must pass one (ZIG-642).
5
5
  */
6
- export function buildOperatorHeaders(operatorKey, agentId, extra) {
6
+ export function buildOperatorHeaders(operatorKey, agentId, extra,
7
+ /**
8
+ * ZIG-1092 — the lane this call belongs to, sent as `X-Ziggs-Lane`. The
9
+ * backend narrows the wake's reach to the engagement's orgs; omitting it
10
+ * narrows to the agent's own org, so it can never widen reach.
11
+ */
12
+ laneId) {
7
13
  return {
8
14
  Authorization: `Bearer ${operatorKey}`,
9
15
  ...(agentId ? { 'X-Agent-Id': agentId } : {}),
16
+ ...(laneId ? { 'X-Ziggs-Lane': laneId } : {}),
10
17
  ...extra,
11
18
  };
12
19
  }
package/dist/index.d.ts CHANGED
@@ -3,9 +3,11 @@ export * from './capabilities/index.js';
3
3
  export * from './relay/provisionRelayWorkers.js';
4
4
  export { ConnectionManager } from './ConnectionManager.js';
5
5
  export type { StartAgentOptions } from './ConnectionManager.js';
6
- export { EntryTypes, ContentTypes, OPEN_AGREEMENT_TARGET, ORG_AGREEMENT_TARGET, BROADCAST_TARGETS, isBroadcastTarget, AGREEMENT_ENGAGEMENT_KIND, isValidContentType } from './types.js';
6
+ export { EntryTypes, ContentTypes, OPEN_AGREEMENT_TARGET, ORG_AGREEMENT_TARGET, BROADCAST_TARGETS, isBroadcastTarget, isPersonaRef, isRoomPresentationRef, isOpaquePresentationRef, AGREEMENT_ENGAGEMENT_KIND, isValidContentType, } from './types.js';
7
+ export type { PrincipalPresentation } from './types.js';
7
8
  export { getBackendUrl, getWebSocketUrl } from './utils/urlUtils.js';
8
9
  export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
9
10
  export { RateLimitedError, isRateLimited, parseRetryAfterMs, pollSurfaceError, } from './shared/rateLimit.js';
11
+ export { parseErrorMessage, throwApiError } from './shared/apiError.js';
10
12
  export type { Creds, Task, TaskState, PlanStep, PlanStepStatus, Agreement, EngagementKind, BroadcastAudience, EntryType, ContentType, MessageMetadata, MessageHandler, ApiError, } from './types.js';
11
13
  export type { ProposeTerms, ProposeDirectInput, ProposeBroadcastInput, ProposeAgreementData, } from './http/AgreementClient.js';
package/dist/index.js CHANGED
@@ -2,8 +2,12 @@ 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 { EntryTypes, ContentTypes, OPEN_AGREEMENT_TARGET, ORG_AGREEMENT_TARGET, BROADCAST_TARGETS, isBroadcastTarget, AGREEMENT_ENGAGEMENT_KIND, isValidContentType } from './types.js';
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
7
  export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
8
8
  // ZIG-1019: retry loops need the server's own wait, not a guess.
9
9
  export { RateLimitedError, isRateLimited, parseRetryAfterMs, pollSurfaceError, } from './shared/rateLimit.js';
10
+ // One reader for the one error shape the API answers in — exported so nothing has
11
+ // to re-implement the field precedence (it was copy-pasted into six clients, and
12
+ // half of them had drifted).
13
+ export { parseErrorMessage, throwApiError } from './shared/apiError.js';
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Read the message out of a Ziggs error response.
3
+ *
4
+ * The API answers every failure in one shape — `{ error: "<what went wrong>" }`,
5
+ * plus `code` when the server supplied a machine-readable one — because one global
6
+ * exception filter builds it (backend `common/http-exception.filter.ts`, pinned in
7
+ * `common/error-response.spec.ts`). So `error` is read first and is normally the
8
+ * whole answer.
9
+ *
10
+ * `message` and `details` remain as fallbacks for responses that did NOT come from
11
+ * that filter: a proxy, a gateway, or a Nest-shaped body from some other service.
12
+ * On a Nest-shaped body `error` holds the reason phrase ("Bad Request") while
13
+ * `message` holds the real cause, so when both are present the more specific one
14
+ * wins — that ordering is why this lives in ONE place. It used to be copy-pasted
15
+ * into five clients, two of which had been fixed for it and three of which had not,
16
+ * so the same failure read differently depending on which client you called.
17
+ */
18
+ export declare function parseErrorMessage(responseBody: string, defaultMessage: string): string;
19
+ /** Throw the parsed failure as an {@link ApiError}, preserving status and body. */
20
+ export declare function throwApiError(response: {
21
+ status: number;
22
+ }, responseBody: string, defaultMessage: string): never;
@@ -0,0 +1,57 @@
1
+ import { ApiError } from '../types.js';
2
+ /**
3
+ * Read the message out of a Ziggs error response.
4
+ *
5
+ * The API answers every failure in one shape — `{ error: "<what went wrong>" }`,
6
+ * plus `code` when the server supplied a machine-readable one — because one global
7
+ * exception filter builds it (backend `common/http-exception.filter.ts`, pinned in
8
+ * `common/error-response.spec.ts`). So `error` is read first and is normally the
9
+ * whole answer.
10
+ *
11
+ * `message` and `details` remain as fallbacks for responses that did NOT come from
12
+ * that filter: a proxy, a gateway, or a Nest-shaped body from some other service.
13
+ * On a Nest-shaped body `error` holds the reason phrase ("Bad Request") while
14
+ * `message` holds the real cause, so when both are present the more specific one
15
+ * wins — that ordering is why this lives in ONE place. It used to be copy-pasted
16
+ * into five clients, two of which had been fixed for it and three of which had not,
17
+ * so the same failure read differently depending on which client you called.
18
+ */
19
+ export function parseErrorMessage(responseBody, defaultMessage) {
20
+ if (!responseBody)
21
+ return defaultMessage;
22
+ let parsed;
23
+ try {
24
+ parsed = JSON.parse(responseBody);
25
+ }
26
+ catch {
27
+ // Not JSON at all — an HTML error page or a bare string is still better than
28
+ // nothing, so hand back what the server actually said.
29
+ return responseBody || defaultMessage;
30
+ }
31
+ // Valid JSON that is not an object: a quoted string IS the message; anything
32
+ // else (null, a number) carries no message, and echoing its raw text would put
33
+ // "null" in front of a caller.
34
+ if (typeof parsed !== 'object' || parsed === null) {
35
+ return typeof parsed === 'string' && parsed ? parsed : defaultMessage;
36
+ }
37
+ const body = parsed;
38
+ const text = (value) => {
39
+ if (Array.isArray(value)) {
40
+ const joined = value.map(String).filter(Boolean).join('; ');
41
+ return joined || undefined;
42
+ }
43
+ return typeof value === 'string' && value ? value : undefined;
44
+ };
45
+ const error = text(body['error']);
46
+ const message = text(body['message']);
47
+ // A Nest-shaped body carries both: prefer the specific `message` over the
48
+ // reason phrase sitting in `error`.
49
+ const preferMessage = !!message && !!body['statusCode'];
50
+ return (text(body['details']) ??
51
+ (preferMessage ? message : (error ?? message)) ??
52
+ defaultMessage);
53
+ }
54
+ /** Throw the parsed failure as an {@link ApiError}, preserving status and body. */
55
+ export function throwApiError(response, responseBody, defaultMessage) {
56
+ throw new ApiError(parseErrorMessage(responseBody, defaultMessage), response.status, responseBody);
57
+ }