@elysra/tungsten-runtime 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +55 -0
- package/dist/auth.d.ts +50 -0
- package/dist/auth.js +264 -0
- package/dist/classify.d.ts +64 -0
- package/dist/classify.js +301 -0
- package/dist/client.d.ts +49 -0
- package/dist/client.js +2309 -0
- package/dist/confirm.d.ts +7 -0
- package/dist/confirm.js +32 -0
- package/dist/define.d.ts +13 -0
- package/dist/define.js +12 -0
- package/dist/envelope.d.ts +24 -0
- package/dist/envelope.js +152 -0
- package/dist/errors.d.ts +37 -0
- package/dist/errors.js +75 -0
- package/dist/expr.d.ts +24 -0
- package/dist/expr.js +198 -0
- package/dist/idempotency.d.ts +27 -0
- package/dist/idempotency.js +56 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +19 -0
- package/dist/node.d.ts +17 -0
- package/dist/node.js +98 -0
- package/dist/oauth.d.ts +124 -0
- package/dist/oauth.js +367 -0
- package/dist/serialize.d.ts +55 -0
- package/dist/serialize.js +323 -0
- package/dist/sse.d.ts +42 -0
- package/dist/sse.js +166 -0
- package/dist/streams.d.ts +65 -0
- package/dist/streams.js +96 -0
- package/dist/transport.d.ts +88 -0
- package/dist/transport.js +245 -0
- package/dist/types.d.ts +667 -0
- package/dist/types.js +1 -0
- package/dist/util.d.ts +73 -0
- package/dist/util.js +317 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.js +4 -0
- package/package.json +27 -4
- package/README.md +0 -3
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The contract between SDKs generated by tungsten and this runtime
|
|
3
|
+
* (planning/05 "TypeScript SDK", planning/06 "Runtime and safety").
|
|
4
|
+
*
|
|
5
|
+
* Generated code is mostly data: one `OperationDescriptor` per operation,
|
|
6
|
+
* one `ApiDescriptor` per client, and thin typed wrappers that call
|
|
7
|
+
* `ClientCore`. Everything with behaviour (validation, auth, idempotency,
|
|
8
|
+
* retries, error envelopes, previews, verification, pagination) lives in the
|
|
9
|
+
* runtime, so a fix ships as a runtime release instead of a regeneration.
|
|
10
|
+
*
|
|
11
|
+
* PHASE-2 CONTRACT: these types are shared by the runtime and the
|
|
12
|
+
* TypeScript emitter. Additive changes only (new optional fields, new
|
|
13
|
+
* union members), and only with both sides updated.
|
|
14
|
+
*/
|
|
15
|
+
import type { TokenStore } from "./oauth.js";
|
|
16
|
+
import type { EventStream } from "./streams.js";
|
|
17
|
+
export type Safety = "read_only" | "mutating" | "destructive" | "irreversible";
|
|
18
|
+
export type Retryable = "never" | "after_delay" | "same_key_only" | "after_remediation";
|
|
19
|
+
/** Closed set of error categories shared by every tungsten runtime. */
|
|
20
|
+
export type Category = "VALIDATION_FAILED" | "MALFORMED_REQUEST" | "REQUEST_TOO_LARGE" | "AUTH_FAILED" | "NOT_FOUND" | "CONFLICT" | "PRECONDITION_FAILED" | "RATE_LIMITED" | "UPSTREAM_UNAVAILABLE" | "OUTCOME_UNKNOWN" | "TRANSPORT_FAILED" | "CONFIRMATION_REQUIRED" | "GATE_DISABLED" | "UNEXPECTED_RESPONSE";
|
|
21
|
+
/** The diagnostic error envelope (planning/06). Field names are snake_case
|
|
22
|
+
* on purpose: the envelope is pasted verbatim into a model's context and is
|
|
23
|
+
* identical across the TypeScript, Python and Rust runtimes. */
|
|
24
|
+
export interface Diagnostic {
|
|
25
|
+
status: "error";
|
|
26
|
+
category: Category;
|
|
27
|
+
/** Operation id, e.g. `public.replayWebhookDelivery`. */
|
|
28
|
+
operation: string;
|
|
29
|
+
http_status: number | null;
|
|
30
|
+
/** The API's error code from the response body, when present. */
|
|
31
|
+
code: string | null;
|
|
32
|
+
/** JSON path of the offending argument (`body.recipient_e164`). */
|
|
33
|
+
failed_parameter: string | null;
|
|
34
|
+
/** Redacted when the parameter is sensitive; strings cut to 200 chars. */
|
|
35
|
+
received_value: unknown;
|
|
36
|
+
expected: string | null;
|
|
37
|
+
remediation: string;
|
|
38
|
+
retryable: Retryable;
|
|
39
|
+
retry_after_ms: number | null;
|
|
40
|
+
/** What to do next, e.g. the verification operation to call. */
|
|
41
|
+
next_action: string | null;
|
|
42
|
+
request_id: string | null;
|
|
43
|
+
trace: {
|
|
44
|
+
attempts: number;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export interface ResponseMeta {
|
|
48
|
+
status: number;
|
|
49
|
+
headers: Record<string, string>;
|
|
50
|
+
requestId: string | null;
|
|
51
|
+
attempts: number;
|
|
52
|
+
}
|
|
53
|
+
/** The meta of a stream item: the answer of the connection the event
|
|
54
|
+
* arrived on (the last one, after a reconnect) and how often the stream
|
|
55
|
+
* reconnected up to this event. */
|
|
56
|
+
export interface StreamMeta extends ResponseMeta {
|
|
57
|
+
reconnects: number;
|
|
58
|
+
}
|
|
59
|
+
export interface Verification {
|
|
60
|
+
checked: boolean;
|
|
61
|
+
/** True when `expect` held; false when it did not within the budget. */
|
|
62
|
+
passed: boolean;
|
|
63
|
+
/** The verification operation's last result body. */
|
|
64
|
+
observed: unknown;
|
|
65
|
+
/** True when polling for `terminal` ran out of budget. */
|
|
66
|
+
timedOut?: boolean;
|
|
67
|
+
/** Why the check could not run (verification call failed); `checked` is false. */
|
|
68
|
+
error?: Diagnostic;
|
|
69
|
+
}
|
|
70
|
+
/** The outcome of a call. A success response without a body (204, or any
|
|
71
|
+
* success status the spec declares without content) has `value: undefined`;
|
|
72
|
+
* generated SDKs type such operations as `void` (or `T | undefined` when the
|
|
73
|
+
* operation can also answer with a body). */
|
|
74
|
+
export type Result<T> = {
|
|
75
|
+
ok: true;
|
|
76
|
+
value: T;
|
|
77
|
+
meta: ResponseMeta;
|
|
78
|
+
verification?: Verification;
|
|
79
|
+
} | {
|
|
80
|
+
ok: false;
|
|
81
|
+
error: Diagnostic;
|
|
82
|
+
/** What the failed call or macro already produced, when its effect
|
|
83
|
+
* happened: the success body of a mutation whose response failed
|
|
84
|
+
* strict validation, or a macro's completed step results by their
|
|
85
|
+
* `as` names. It can hold values the API shows only once (a signing
|
|
86
|
+
* secret), so store them before acting on the error; they are never
|
|
87
|
+
* repeated in the envelope. */
|
|
88
|
+
partial?: unknown;
|
|
89
|
+
};
|
|
90
|
+
export type HttpMethod = "GET" | "PUT" | "POST" | "DELETE" | "OPTIONS" | "HEAD" | "PATCH" | "TRACE";
|
|
91
|
+
export type ParamLocation = "path" | "query" | "header" | "cookie";
|
|
92
|
+
export type ParamStyle = "simple" | "form" | "label" | "matrix" | "space_delimited" | "pipe_delimited" | "deep_object";
|
|
93
|
+
export type ParamRole = "plain" | "idempotency_key" | "dry_run" | "origin" | "auth" | "constant";
|
|
94
|
+
export interface ParamDescriptor {
|
|
95
|
+
/** Key in the generated method's args object. Roles `idempotency_key`,
|
|
96
|
+
* `origin`, `auth` and `constant` are not args: they come from
|
|
97
|
+
* `CallOptions.idempotencyKey` and the auth profile (`ClientOptions.auth`),
|
|
98
|
+
* and their `name` is informational. */
|
|
99
|
+
name: string;
|
|
100
|
+
/** Name on the wire. */
|
|
101
|
+
wire: string;
|
|
102
|
+
in: ParamLocation;
|
|
103
|
+
required: boolean;
|
|
104
|
+
style: ParamStyle;
|
|
105
|
+
explode: boolean;
|
|
106
|
+
role: ParamRole;
|
|
107
|
+
/** Header value of a `constant` parameter: the runtime sends it on every
|
|
108
|
+
* call (`ClientOptions.headers` and `CallOptions.headers` replace it). */
|
|
109
|
+
constant?: string;
|
|
110
|
+
sensitive?: boolean;
|
|
111
|
+
}
|
|
112
|
+
export type BodyEncoding = "json" | "form" | "multipart" | "bytes" | "text";
|
|
113
|
+
export interface BodyDescriptor {
|
|
114
|
+
mediaType: string;
|
|
115
|
+
encoding: BodyEncoding;
|
|
116
|
+
required: boolean;
|
|
117
|
+
/** `merged`: the body is a JSON object whose fields are keys of the args
|
|
118
|
+
* object, listed in `fields` (wire names; TypeScript models keep wire
|
|
119
|
+
* names). `arg`: the whole body is `args[arg]` (bytes, text, unions,
|
|
120
|
+
* arrays, or field names that collide with a parameter). */
|
|
121
|
+
shape: {
|
|
122
|
+
kind: "merged";
|
|
123
|
+
fields: string[];
|
|
124
|
+
} | {
|
|
125
|
+
kind: "arg";
|
|
126
|
+
arg: string;
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
export type StatusMatch = number | "1XX" | "2XX" | "3XX" | "4XX" | "5XX" | "default";
|
|
130
|
+
export interface ResponseDescriptor {
|
|
131
|
+
status: StatusMatch;
|
|
132
|
+
kind: "success" | "error" | "ambiguous";
|
|
133
|
+
/** First media type, or null for a bare status. */
|
|
134
|
+
mediaType: string | null;
|
|
135
|
+
}
|
|
136
|
+
export type PaginationDescriptor = {
|
|
137
|
+
style: "cursor";
|
|
138
|
+
requestParam: string;
|
|
139
|
+
/** Response field holding the next cursor; empty when only `cursorItemField` applies. */
|
|
140
|
+
responseField: string;
|
|
141
|
+
itemsField: string;
|
|
142
|
+
pageSizeParam: string | null;
|
|
143
|
+
/** Response boolean (`has_more`): iteration stops as soon as it is `false`. */
|
|
144
|
+
hasMoreField?: string;
|
|
145
|
+
/** Without a cursor in the response, the next cursor is this field of the last item. */
|
|
146
|
+
cursorItemField?: string;
|
|
147
|
+
} | {
|
|
148
|
+
style: "offset";
|
|
149
|
+
offsetParam: string;
|
|
150
|
+
limitParam: string;
|
|
151
|
+
itemsField: string;
|
|
152
|
+
} | {
|
|
153
|
+
style: "page";
|
|
154
|
+
pageParam: string;
|
|
155
|
+
sizeParam: string;
|
|
156
|
+
itemsField: string;
|
|
157
|
+
} | {
|
|
158
|
+
style: "link_header";
|
|
159
|
+
itemsField: string;
|
|
160
|
+
};
|
|
161
|
+
export type IdempotencyKind = "none" | "auto" | "caller_owned" | "content_hash" | "content_identity";
|
|
162
|
+
export interface RemediationEntry {
|
|
163
|
+
category?: Category;
|
|
164
|
+
text?: string;
|
|
165
|
+
retryable?: Retryable;
|
|
166
|
+
next_action?: string;
|
|
167
|
+
}
|
|
168
|
+
export interface VerifyDescriptor {
|
|
169
|
+
/** Operation id of the read operation to call. */
|
|
170
|
+
operation: string;
|
|
171
|
+
/** Argument mapping, keyed by the read operation's parameter wire names
|
|
172
|
+
* (or generated names); string values starting with `$response.` or
|
|
173
|
+
* `$args.` are resolved against the call, `$args` by generated or wire
|
|
174
|
+
* name. */
|
|
175
|
+
args: Record<string, unknown>;
|
|
176
|
+
/** Field path → predicate (`{in: [...]}`, `{equals: x}`, `{contains: {...}}`).
|
|
177
|
+
* `$response.` and `$args.` references in `expect` and `terminal` are
|
|
178
|
+
* resolved against the call; an unresolved one never matches. */
|
|
179
|
+
expect: Record<string, unknown>;
|
|
180
|
+
terminal: Record<string, unknown>;
|
|
181
|
+
pollIntervalMs: number | null;
|
|
182
|
+
pollBudgetMs: number | null;
|
|
183
|
+
}
|
|
184
|
+
export interface AgentMeta {
|
|
185
|
+
safety: Safety;
|
|
186
|
+
idempotency: {
|
|
187
|
+
policy: IdempotencyKind;
|
|
188
|
+
header: string | null;
|
|
189
|
+
format: string | null;
|
|
190
|
+
persistRequired: boolean;
|
|
191
|
+
note: string | null;
|
|
192
|
+
};
|
|
193
|
+
preview: {
|
|
194
|
+
mode: "local";
|
|
195
|
+
} | {
|
|
196
|
+
mode: "header";
|
|
197
|
+
header: string;
|
|
198
|
+
value: string;
|
|
199
|
+
} | {
|
|
200
|
+
mode: "endpoint";
|
|
201
|
+
operation: string;
|
|
202
|
+
} | {
|
|
203
|
+
mode: "none";
|
|
204
|
+
};
|
|
205
|
+
confirmation: {
|
|
206
|
+
summaryFields: string[];
|
|
207
|
+
message: string | null;
|
|
208
|
+
} | null;
|
|
209
|
+
verify: VerifyDescriptor | null;
|
|
210
|
+
/** Operation-specific remediation by API error code. */
|
|
211
|
+
remediation: Record<string, RemediationEntry>;
|
|
212
|
+
remediationNote: string | null;
|
|
213
|
+
sensitiveResponseFields: string[];
|
|
214
|
+
/** Arguments marked sensitive (`x-agent-sensitive` on request body
|
|
215
|
+
* fields), as dotted paths into the args object (`pin`, `body.pin`,
|
|
216
|
+
* `profile.recovery_phrase`; array items are not indexed). Redacted in
|
|
217
|
+
* `received_value`, previews, middleware and diagnostics. */
|
|
218
|
+
sensitiveRequestFields?: string[];
|
|
219
|
+
shownOnce: boolean;
|
|
220
|
+
}
|
|
221
|
+
/** Structural subset of a Zod schema (`safeParse`), so the runtime does not
|
|
222
|
+
* depend on a Zod version. */
|
|
223
|
+
export interface SchemaLike<T = unknown> {
|
|
224
|
+
safeParse(value: unknown): {
|
|
225
|
+
success: true;
|
|
226
|
+
data: T;
|
|
227
|
+
} | {
|
|
228
|
+
success: false;
|
|
229
|
+
error: {
|
|
230
|
+
issues: Array<{
|
|
231
|
+
path: Array<string | number>;
|
|
232
|
+
message: string;
|
|
233
|
+
code?: string;
|
|
234
|
+
}>;
|
|
235
|
+
};
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
export interface OperationDescriptor {
|
|
239
|
+
/** IR operation id (`public.replayWebhookDelivery`). */
|
|
240
|
+
id: string;
|
|
241
|
+
method: HttpMethod;
|
|
242
|
+
/** Path template as in the spec (`/v1/webhooks/{endpoint_id}/rotate`);
|
|
243
|
+
* placeholders use wire names. */
|
|
244
|
+
path: string;
|
|
245
|
+
params: ParamDescriptor[];
|
|
246
|
+
body: BodyDescriptor | null;
|
|
247
|
+
responses: ResponseDescriptor[];
|
|
248
|
+
/** OR of AND-sets of auth scheme names. Empty: no auth. */
|
|
249
|
+
security: string[][];
|
|
250
|
+
pagination: PaginationDescriptor | null;
|
|
251
|
+
/** For rpc-unflattened operations: the envelope field and value to send,
|
|
252
|
+
* and the field the args are placed under. `constants` are further
|
|
253
|
+
* envelope members sent verbatim (JSON-RPC `jsonrpc: "2.0"`). */
|
|
254
|
+
rpc: {
|
|
255
|
+
field: string;
|
|
256
|
+
value: string;
|
|
257
|
+
paramsField: string;
|
|
258
|
+
constants?: Record<string, unknown>;
|
|
259
|
+
} | null;
|
|
260
|
+
/** Field path of the API error code in error bodies (`code`, `error.code`). */
|
|
261
|
+
errorCodeField: string | null;
|
|
262
|
+
status: {
|
|
263
|
+
kind: "implemented";
|
|
264
|
+
} | {
|
|
265
|
+
kind: "gated";
|
|
266
|
+
envVar: string;
|
|
267
|
+
disabledStatus: number;
|
|
268
|
+
};
|
|
269
|
+
agent: AgentMeta;
|
|
270
|
+
/** Validates the args object before any network call. */
|
|
271
|
+
request?: SchemaLike;
|
|
272
|
+
/** Validates the success body (per `ClientOptions.validateResponses`).
|
|
273
|
+
*
|
|
274
|
+
* Untagged unions (IR `UnionStrategy::Untagged`, TG0301) are emitted as
|
|
275
|
+
* `z.union([...])` with the variants in IR order, and Zod tries them in
|
|
276
|
+
* that order: the body is accepted when any variant accepts it, and the
|
|
277
|
+
* first variant that does decides which refinements applied. The
|
|
278
|
+
* result's `value` is always the decoded wire body itself, never the
|
|
279
|
+
* schema's output, so an earlier variant that overlaps a later one (or
|
|
280
|
+
* strips unknown members) cannot drop or rewrite members of the body. */
|
|
281
|
+
response?: SchemaLike;
|
|
282
|
+
/** One-line summary (compacted description); the last line of preview effects. */
|
|
283
|
+
summary?: string | null;
|
|
284
|
+
/** The operation's event stream (`ClientCore.stream`); absent when it has none. */
|
|
285
|
+
stream?: StreamDescriptor;
|
|
286
|
+
}
|
|
287
|
+
/** The server-sent events of an operation (IR `StreamSpec`). */
|
|
288
|
+
export interface StreamDescriptor {
|
|
289
|
+
/** Validates the decoded `data` of every event (per
|
|
290
|
+
* `ClientOptions.validateResponses`); absent: events are any JSON value. */
|
|
291
|
+
event?: SchemaLike;
|
|
292
|
+
/** A `data` value that ends the stream without being an event (`[DONE]`). */
|
|
293
|
+
done?: string;
|
|
294
|
+
/** Wire name of the boolean request body field that selects the stream;
|
|
295
|
+
* `ClientCore.stream` sets it to `true`. */
|
|
296
|
+
flag?: string;
|
|
297
|
+
}
|
|
298
|
+
/** The `authorizationCode` flow of an OAuth2 scheme (present only when the
|
|
299
|
+
* spec declares one). `refreshUrl` falls back to `tokenUrl`. */
|
|
300
|
+
export interface AuthorizationCodeDescriptor {
|
|
301
|
+
authorizationUrl: string;
|
|
302
|
+
tokenUrl: string;
|
|
303
|
+
refreshUrl: string | null;
|
|
304
|
+
scopes: string[];
|
|
305
|
+
}
|
|
306
|
+
export type AuthSchemeDescriptor = {
|
|
307
|
+
kind: "api_key";
|
|
308
|
+
name: string;
|
|
309
|
+
in: "header" | "query" | "cookie";
|
|
310
|
+
wire: string;
|
|
311
|
+
}
|
|
312
|
+
/** `prefix`: the token must start with it (tungsten.yml
|
|
313
|
+
* `auth_profiles.<name>.bearer.prefix`, e.g. `ztw_`); checked before any
|
|
314
|
+
* request is sent, and a mismatch is `AUTH_FAILED` with zero network calls. */
|
|
315
|
+
| {
|
|
316
|
+
kind: "http_bearer";
|
|
317
|
+
name: string;
|
|
318
|
+
prefix: string | null;
|
|
319
|
+
} | {
|
|
320
|
+
kind: "http_basic";
|
|
321
|
+
name: string;
|
|
322
|
+
} | {
|
|
323
|
+
kind: "oauth2";
|
|
324
|
+
name: string;
|
|
325
|
+
tokenUrl: string | null;
|
|
326
|
+
scopes: string[];
|
|
327
|
+
authorizationCode?: AuthorizationCodeDescriptor;
|
|
328
|
+
} | {
|
|
329
|
+
kind: "composite";
|
|
330
|
+
name: string;
|
|
331
|
+
/** Spec scheme names this profile satisfies together. */
|
|
332
|
+
satisfies: string[];
|
|
333
|
+
parts: Array<{
|
|
334
|
+
kind: "cookie";
|
|
335
|
+
name: string;
|
|
336
|
+
} | {
|
|
337
|
+
kind: "header";
|
|
338
|
+
name: string;
|
|
339
|
+
equalsCookie: string | null;
|
|
340
|
+
fromConfig: string | null;
|
|
341
|
+
mutationOnly: boolean;
|
|
342
|
+
} | {
|
|
343
|
+
kind: "bearer";
|
|
344
|
+
prefix: string | null;
|
|
345
|
+
}>;
|
|
346
|
+
};
|
|
347
|
+
export interface ApiDescriptor {
|
|
348
|
+
/** Machine name (`zrotext`). */
|
|
349
|
+
name: string;
|
|
350
|
+
/** SDK package version. */
|
|
351
|
+
version: string;
|
|
352
|
+
tungstenVersion: string;
|
|
353
|
+
servers: string[];
|
|
354
|
+
auth: AuthSchemeDescriptor[];
|
|
355
|
+
/** Global remediation by API error code (agent.yml `errors.codes`). */
|
|
356
|
+
errorCodes: Record<string, RemediationEntry>;
|
|
357
|
+
/** Statuses that make a mutation's outcome unknown. */
|
|
358
|
+
ambiguousStatuses: number[];
|
|
359
|
+
/** Non-JSON error mapping (agent.yml `errors.non_json`); `media` is a
|
|
360
|
+
* media type or `"none"` for a bare status. */
|
|
361
|
+
nonJson: Array<{
|
|
362
|
+
status: number;
|
|
363
|
+
media: string;
|
|
364
|
+
category: Category;
|
|
365
|
+
retryable: Retryable;
|
|
366
|
+
text: string | null;
|
|
367
|
+
}>;
|
|
368
|
+
/** Runtime gate env var → explanation. */
|
|
369
|
+
gates: Record<string, string>;
|
|
370
|
+
/** Retry defaults by safety tier (agent.yml `defaults.retries`):
|
|
371
|
+
* `readOnly` for read-only operations, `mutating` for every other tier
|
|
372
|
+
* (a mutation is still retried only with an idempotency key or an
|
|
373
|
+
* identity body). `ClientOptions.retries` overrides them field by field.
|
|
374
|
+
* Absent: the runtime defaults apply to every tier. */
|
|
375
|
+
retries?: {
|
|
376
|
+
readOnly: Partial<RetryOptions>;
|
|
377
|
+
mutating: Partial<RetryOptions>;
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
/** Credentials per auth scheme name. A string is the secret of an
|
|
381
|
+
* `api_key`, `http_bearer` or `http_basic` (`user:password`) scheme. A
|
|
382
|
+
* composite profile takes an object keyed by cookie name or config key
|
|
383
|
+
* (for ZROtext's owner session: the two cookie values and `origin`). */
|
|
384
|
+
export type AuthConfig = Record<string, string | Record<string, string>>;
|
|
385
|
+
export interface IdempotencyStore {
|
|
386
|
+
get(scope: string, logicalId: string): Promise<string | undefined>;
|
|
387
|
+
put(scope: string, logicalId: string, key: string): Promise<void>;
|
|
388
|
+
}
|
|
389
|
+
/** What middleware sees of one attempt. Secrets are redacted: secret
|
|
390
|
+
* headers, auth query values, and in a JSON or form body the arguments
|
|
391
|
+
* marked sensitive (or named like credentials) as `<redacted>`. */
|
|
392
|
+
export interface RequestContext {
|
|
393
|
+
operation: OperationDescriptor;
|
|
394
|
+
attempt: number;
|
|
395
|
+
method: HttpMethod;
|
|
396
|
+
url: string;
|
|
397
|
+
headers: Record<string, string>;
|
|
398
|
+
body: BodyInit | null;
|
|
399
|
+
}
|
|
400
|
+
export interface Middleware {
|
|
401
|
+
onRequest?(ctx: RequestContext): void | Promise<void>;
|
|
402
|
+
onResponse?(ctx: RequestContext, response: Response): void | Promise<void>;
|
|
403
|
+
onRetry?(ctx: RequestContext, reason: Diagnostic): void | Promise<void>;
|
|
404
|
+
}
|
|
405
|
+
export interface RetryOptions {
|
|
406
|
+
/** Attempts after the first, for retryable outcomes. */
|
|
407
|
+
max: number;
|
|
408
|
+
baseMs: number;
|
|
409
|
+
maxMs: number;
|
|
410
|
+
jitter: "none" | "full" | "equal";
|
|
411
|
+
honorRetryAfter: boolean;
|
|
412
|
+
}
|
|
413
|
+
export interface ClientOptions {
|
|
414
|
+
/** Defaults to the first server. */
|
|
415
|
+
baseUrl?: string;
|
|
416
|
+
auth?: AuthConfig;
|
|
417
|
+
/** Holds the tokens of `authorizationCode` schemes (configure such a
|
|
418
|
+
* scheme as `{flow: "authorizationCode", clientId, clientSecret?,
|
|
419
|
+
* redirectUri?}`). Default: in memory, per client. */
|
|
420
|
+
tokenStore?: TokenStore;
|
|
421
|
+
/** Defaults to `globalThis.fetch`. */
|
|
422
|
+
fetch?: typeof fetch;
|
|
423
|
+
/** Per-attempt timeout. Default 30000. */
|
|
424
|
+
timeoutMs?: number;
|
|
425
|
+
/** Overrides the API's per-tier retry defaults (`ApiDescriptor.retries`)
|
|
426
|
+
* field by field, for every tier. */
|
|
427
|
+
retries?: Partial<RetryOptions>;
|
|
428
|
+
idempotencyStore?: IdempotencyStore;
|
|
429
|
+
middleware?: Middleware[];
|
|
430
|
+
/** Default `warn`: report through `onDiagnostic`, never fail the call. */
|
|
431
|
+
validateResponses?: "off" | "warn" | "strict";
|
|
432
|
+
/** Receives warnings (response validation, deprecations). */
|
|
433
|
+
onDiagnostic?: (d: Diagnostic) => void;
|
|
434
|
+
/** Extra headers on every request. */
|
|
435
|
+
headers?: Record<string, string>;
|
|
436
|
+
/** Largest server-sent event `stream()` accepts, in UTF-8 bytes (the field
|
|
437
|
+
* lines of one event plus the line being read). A larger one ends the
|
|
438
|
+
* stream with an `UNEXPECTED_RESPONSE` failure. Default 1048576 (1 MiB). */
|
|
439
|
+
maxEventBytes?: number;
|
|
440
|
+
/** How often `stream()` reconnects a dropped stream (a lost connection, or
|
|
441
|
+
* a clean end before the `done` event the operation declares) with
|
|
442
|
+
* `Last-Event-ID` set to the last event id it delivered; events whose id
|
|
443
|
+
* was delivered are never delivered twice. Only for operations that are
|
|
444
|
+
* safe to repeat (read-only, or with replay protection) and only once
|
|
445
|
+
* an event id is known (or before the first event). 0 disables it.
|
|
446
|
+
* Default 3. */
|
|
447
|
+
maxReconnects?: number;
|
|
448
|
+
/** Longest wait before a reconnect, in milliseconds: the server's `retry`
|
|
449
|
+
* value (250 ms when it sent none) is capped at this and then reduced by
|
|
450
|
+
* up to 25 % at random. Default 30000. */
|
|
451
|
+
reconnectMaxMs?: number;
|
|
452
|
+
/** A stream that delivers no bytes (comments count) for this many
|
|
453
|
+
* milliseconds is idle: it is reconnected like a dropped one, else ends
|
|
454
|
+
* with a failure whose `code` is `STREAM_IDLE`. Default: the per-attempt
|
|
455
|
+
* `timeoutMs`, which ends the stream without a reconnect. */
|
|
456
|
+
idleTimeoutMs?: number;
|
|
457
|
+
/** Overrides the key used to sign confirmation tokens. Default: random
|
|
458
|
+
* per client instance. */
|
|
459
|
+
confirmationKey?: Uint8Array;
|
|
460
|
+
/** Operations the core can resolve by id: verification hooks, endpoint
|
|
461
|
+
* previews and macro steps. Operations passed to `call` are added too. */
|
|
462
|
+
operations?: OperationDescriptor[];
|
|
463
|
+
/** Clock in epoch milliseconds (token expiry, Retry-After dates). Default `Date.now`. */
|
|
464
|
+
now?: () => number;
|
|
465
|
+
/** Random number in [0, 1) for retry jitter. Default `Math.random`. */
|
|
466
|
+
random?: () => number;
|
|
467
|
+
}
|
|
468
|
+
export interface CallOptions {
|
|
469
|
+
/** Required for `caller_owned` operations with `persistRequired`. */
|
|
470
|
+
idempotencyKey?: string;
|
|
471
|
+
/** Token from `preview()`; required for `irreversible`, and for
|
|
472
|
+
* `destructive` unless `true` is given. A token authorizes one intent:
|
|
473
|
+
* the first call that sends spends it, and it is accepted again only for
|
|
474
|
+
* a retry with the same idempotency key (or the identical body of a
|
|
475
|
+
* `content_identity` operation). */
|
|
476
|
+
confirm?: string | true;
|
|
477
|
+
/** `false`: `confirm: true` does not confirm a destructive operation
|
|
478
|
+
* either, and remediation never offers it (callers that only forward
|
|
479
|
+
* preview tokens, such as an MCP server). Default `true`. */
|
|
480
|
+
allowConfirmTrue?: boolean;
|
|
481
|
+
signal?: AbortSignal;
|
|
482
|
+
timeoutMs?: number;
|
|
483
|
+
/** Optional hard response-body byte cap. Positive safe integer; checked
|
|
484
|
+
* against actual bytes while reading, including non-SSE responses. */
|
|
485
|
+
maxResponseBytes?: number;
|
|
486
|
+
/** Run the operation's verification hook after success. */
|
|
487
|
+
verify?: boolean;
|
|
488
|
+
headers?: Record<string, string>;
|
|
489
|
+
}
|
|
490
|
+
export interface RenderedRequest {
|
|
491
|
+
method: HttpMethod;
|
|
492
|
+
url: string;
|
|
493
|
+
/** Secrets redacted as `<redacted>`. */
|
|
494
|
+
headers: Record<string, string>;
|
|
495
|
+
body: unknown;
|
|
496
|
+
}
|
|
497
|
+
/** One step of a macro preview (`ClientCore.previewMacro`). */
|
|
498
|
+
export interface MacroStepPreview {
|
|
499
|
+
/** 1-based position in the macro. */
|
|
500
|
+
step: number;
|
|
501
|
+
kind: MacroStep["kind"];
|
|
502
|
+
/** The step's operation id. */
|
|
503
|
+
operation: string;
|
|
504
|
+
/** The name the step's result is bound to, or null. */
|
|
505
|
+
as: string | null;
|
|
506
|
+
safety: Safety;
|
|
507
|
+
/** The request the step sends (a `poll` or `paginate` step's first
|
|
508
|
+
* request), rendered without sending anything. Arguments taken from an
|
|
509
|
+
* earlier step's result show as `<from step NAME: path>` (NAME is that
|
|
510
|
+
* step's `as` name; `<from step NAME>` for the whole result), shown as
|
|
511
|
+
* written in the URL, headers and body, and exempt from pre-flight
|
|
512
|
+
* validation. Null when the step's whole argument object comes from an
|
|
513
|
+
* earlier result, or a value from an earlier result would have to be
|
|
514
|
+
* encoded before it is known (a `bytes` or `multipart` body). */
|
|
515
|
+
request: RenderedRequest | null;
|
|
516
|
+
/** The step's own effects: its confirmation message (with the same
|
|
517
|
+
* placeholders), what a `poll` or `paginate` step repeats
|
|
518
|
+
* (`Repeats <op> every N ms until <predicate>, for at most M ms.`,
|
|
519
|
+
* `Reads up to N pages of <op>.`) and its remediation note. */
|
|
520
|
+
effects: string[];
|
|
521
|
+
}
|
|
522
|
+
export interface PreviewResult {
|
|
523
|
+
operation: string;
|
|
524
|
+
safety: Safety;
|
|
525
|
+
/** For a macro: the first step's request (also `steps[0].request`). */
|
|
526
|
+
request: RenderedRequest;
|
|
527
|
+
/** Side-effect summary from the manifest's confirmation message, the
|
|
528
|
+
* remediation note and the operation's summary. */
|
|
529
|
+
effects: string[];
|
|
530
|
+
/** Present for mutating operations; bound to the exact arguments. */
|
|
531
|
+
confirmation_token: string | null;
|
|
532
|
+
expires_in_ms: number | null;
|
|
533
|
+
/** For `header`/`endpoint` previews: the server's answer. */
|
|
534
|
+
server_preview?: unknown;
|
|
535
|
+
/** Macro previews only: every step's rendered request and effects, in
|
|
536
|
+
* order. `effects` above lists them all, each step's under a
|
|
537
|
+
* `Step N: <kind> <operation> (<safety>).` line. */
|
|
538
|
+
steps?: MacroStepPreview[];
|
|
539
|
+
}
|
|
540
|
+
export interface Page<T> {
|
|
541
|
+
items: T[];
|
|
542
|
+
/** The full page body. */
|
|
543
|
+
body: unknown;
|
|
544
|
+
/** Cursor, offset, page number or URL for the next page; null at the end. */
|
|
545
|
+
next: unknown;
|
|
546
|
+
}
|
|
547
|
+
/** Until-predicate for `ClientCore.poll`, same shape as `VerifyDescriptor.expect`. */
|
|
548
|
+
export type Predicate = Record<string, unknown>;
|
|
549
|
+
/** One macro step in the canonical form (`tungsten_ir::Macro.steps`).
|
|
550
|
+
* `args`, `budget_ms` and the macro output are expressions: strings
|
|
551
|
+
* starting with `$` reference `$input` or an earlier step's `as` name,
|
|
552
|
+
* `{expr: "<ref> in [..]" | "<ref> == x" | "<ref> != x"}` is a boolean,
|
|
553
|
+
* anything else a literal. */
|
|
554
|
+
export interface MacroStep {
|
|
555
|
+
kind: "call" | "poll" | "paginate";
|
|
556
|
+
/** Operation id, resolved among the operations registered with the core. */
|
|
557
|
+
operation: string;
|
|
558
|
+
args: unknown;
|
|
559
|
+
as: string | null;
|
|
560
|
+
/** `poll` only: predicate on the step's success body. When the budget
|
|
561
|
+
* runs out before it holds, the step's `as` name is bound to `null`, so
|
|
562
|
+
* an output like `{expr: "$status == null"}` reports the timeout. */
|
|
563
|
+
until: Predicate | null;
|
|
564
|
+
interval_ms: number | null;
|
|
565
|
+
budget_ms: unknown;
|
|
566
|
+
/** `paginate` only: page limit. */
|
|
567
|
+
max_pages: number | null;
|
|
568
|
+
}
|
|
569
|
+
/** A compiled macro (`tungsten_ir::Macro`).
|
|
570
|
+
*
|
|
571
|
+
* Confirmation is macro-level: when the macro's tier (the strictest of its
|
|
572
|
+
* declared `safety` and its steps' tiers) is `destructive` or
|
|
573
|
+
* `irreversible`, `runMacro` requires `confirm` like an operation of that
|
|
574
|
+
* tier, with a token from `previewMacro` bound to the macro name and its
|
|
575
|
+
* exact input. That one confirmation authorizes every step of the run;
|
|
576
|
+
* steps never ask for their own tokens, since their arguments may depend on
|
|
577
|
+
* earlier steps' results. The token is spent (bound to the run's
|
|
578
|
+
* idempotency key) by the first step that passes pre-flight and sends, so
|
|
579
|
+
* a run refused before sending anything can be corrected and repeated with
|
|
580
|
+
* the same token. */
|
|
581
|
+
export interface MacroDescriptor {
|
|
582
|
+
name: string;
|
|
583
|
+
summary: string;
|
|
584
|
+
safety: Safety;
|
|
585
|
+
steps: MacroStep[];
|
|
586
|
+
output: unknown;
|
|
587
|
+
/** The macro input: an operation's args (`extends`) plus added fields.
|
|
588
|
+
* An added field's JSON Schema `default` is applied when the input
|
|
589
|
+
* omits it. */
|
|
590
|
+
input: {
|
|
591
|
+
extends: string | null;
|
|
592
|
+
add: Record<string, unknown>;
|
|
593
|
+
};
|
|
594
|
+
/** Output fields carrying secrets (dotted paths); redacted in traces. */
|
|
595
|
+
sensitiveResponseFields?: string[];
|
|
596
|
+
/** The output holds values the API returns only once. */
|
|
597
|
+
shownOnce?: boolean;
|
|
598
|
+
/** Disclosure cluster (agent.yml `disclosure.clusters`). */
|
|
599
|
+
cluster?: string | null;
|
|
600
|
+
}
|
|
601
|
+
/** Further `ClientCore` methods beyond {@link ClientCoreApi}. */
|
|
602
|
+
export interface ClientCoreExtensions {
|
|
603
|
+
/** Make operations resolvable by id (verification, endpoint previews, macros). */
|
|
604
|
+
register(...ops: OperationDescriptor[]): void;
|
|
605
|
+
/** A registered operation by id. */
|
|
606
|
+
operation(id: string): OperationDescriptor | undefined;
|
|
607
|
+
/** Run a compiled macro; returns its output or the first failing step's
|
|
608
|
+
* envelope, with the completed steps' results as `partial` (a rerun is
|
|
609
|
+
* never offered when a completed mutating step has no replay
|
|
610
|
+
* protection). A `destructive` or `irreversible` macro needs
|
|
611
|
+
* `opts.confirm` (see {@link MacroDescriptor}). */
|
|
612
|
+
runMacro<T>(macro: MacroDescriptor, input: Record<string, unknown>, opts?: CallOptions): Promise<Result<T>>;
|
|
613
|
+
/** Preview a macro without sending anything: validates and renders
|
|
614
|
+
* every step's request (arguments from earlier results as
|
|
615
|
+
* `<from step NAME: path>` placeholders, from a dry evaluation), lists
|
|
616
|
+
* every step's effects and, unless the macro is read-only, returns a
|
|
617
|
+
* confirmation token bound to the macro and this exact input. A step
|
|
618
|
+
* whose arguments fail pre-flight for reasons other than a placeholder
|
|
619
|
+
* fails the preview, naming the step. */
|
|
620
|
+
previewMacro(macro: MacroDescriptor, input: Record<string, unknown>, opts?: CallOptions): Promise<Result<PreviewResult>>;
|
|
621
|
+
}
|
|
622
|
+
/** One item of a stream: an event, or the failure that ends the stream
|
|
623
|
+
* (an envelope; a failure before the first event is the only item). */
|
|
624
|
+
export type StreamItem<T> = {
|
|
625
|
+
ok: true;
|
|
626
|
+
/** The event's `data`, decoded from JSON (and validated). */
|
|
627
|
+
value: T;
|
|
628
|
+
/** The `event` field of the server-sent event, `message` when it has none. */
|
|
629
|
+
event: string;
|
|
630
|
+
/** The last event id the stream has set so far, or null. */
|
|
631
|
+
id: string | null;
|
|
632
|
+
/** The last `retry` value (milliseconds) the stream has set so far, or null. */
|
|
633
|
+
retry: number | null;
|
|
634
|
+
meta: StreamMeta;
|
|
635
|
+
} | {
|
|
636
|
+
ok: false;
|
|
637
|
+
error: Diagnostic;
|
|
638
|
+
};
|
|
639
|
+
/** What `ClientCore` (implemented in `client.ts`) offers generated code. */
|
|
640
|
+
export interface ClientCoreApi {
|
|
641
|
+
readonly api: ApiDescriptor;
|
|
642
|
+
/** Validate, authenticate, apply idempotency and confirmation rules, send
|
|
643
|
+
* with retries, classify the response. Never throws for API or transport
|
|
644
|
+
* errors; returns `{ok: false, error}`. */
|
|
645
|
+
call<T>(op: OperationDescriptor, args: Record<string, unknown>, opts?: CallOptions): Promise<Result<T>>;
|
|
646
|
+
/** Run the operation's preview mode. */
|
|
647
|
+
preview(op: OperationDescriptor, args: Record<string, unknown>, opts?: CallOptions): Promise<Result<PreviewResult>>;
|
|
648
|
+
/** Iterate the events of an operation's event stream (`text/event-stream`).
|
|
649
|
+
* Errors before the stream starts (validation, auth, an error status) are
|
|
650
|
+
* the only item, as for `call`, and are retried by the same rules. A
|
|
651
|
+
* started stream that drops is reconnected with `Last-Event-ID`
|
|
652
|
+
* (`ClientOptions.maxReconnects`) when the operation is safe to repeat;
|
|
653
|
+
* otherwise, or when the reconnects are used up, a connection lost or an
|
|
654
|
+
* idle timeout ends it with a final failure item (`TRANSPORT_FAILED`,
|
|
655
|
+
* `UPSTREAM_UNAVAILABLE` for a read; `OUTCOME_UNKNOWN` for a mutation;
|
|
656
|
+
* `code` `STREAM_IDLE` for `ClientOptions.idleTimeoutMs`), as does an event
|
|
657
|
+
* that is not JSON or (with `validateResponses: "strict"`) does not match
|
|
658
|
+
* the event type. The result is an async iterable with helpers
|
|
659
|
+
* (`on`, `collect`, `reduce`, `first`, `cancel`). */
|
|
660
|
+
stream<T>(op: OperationDescriptor, args: Record<string, unknown>, opts?: CallOptions): EventStream<T>;
|
|
661
|
+
/** Iterate pages; stops after the last page or the first error result. */
|
|
662
|
+
pages<T>(op: OperationDescriptor, args: Record<string, unknown>, opts?: CallOptions): AsyncIterable<Result<Page<T>>>;
|
|
663
|
+
/** Call a read operation until `until` holds or the budget runs out. */
|
|
664
|
+
poll<T>(op: OperationDescriptor, args: Record<string, unknown>, until: Predicate, intervalMs: number, budgetMs: number, opts?: CallOptions): Promise<Result<T> & {
|
|
665
|
+
timedOut?: boolean;
|
|
666
|
+
}>;
|
|
667
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|