@tangle-network/hub-sdk 0.24.0-develop.20260814141200.dd5e0f0 → 0.25.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/dist/index.js CHANGED
@@ -1,7 +1,254 @@
1
1
  import { SSEChunkParser } from "@tangle-network/sdk-telemetry";
2
+ //#region src/json-init.ts
3
+ /** The init of a request whose body is JSON. Every client builds its bodies
4
+ * here, so the content type cannot drift from the encoding. */
5
+ function jsonInit(method, body) {
6
+ return {
7
+ method,
8
+ body: JSON.stringify(body),
9
+ headers: { "Content-Type": "application/json" }
10
+ };
11
+ }
12
+ //#endregion
13
+ //#region src/allowances.ts
14
+ var HubAllowancesClient = class {
15
+ constructor(request) {
16
+ this.request = request;
17
+ }
18
+ async plan(meter) {
19
+ return (await this.request(this.path(meter), { method: "GET" })).plan;
20
+ }
21
+ async setPlan(meter, plan) {
22
+ return (await this.request(this.path(meter), this.body("PUT", plan))).plan;
23
+ }
24
+ /** Admit one turn or refuse it. Retrying the same `turnId` never counts twice. */
25
+ async admit(meter, input) {
26
+ return (await this.request(`${this.path(meter)}/turns`, this.body("POST", input))).allowance;
27
+ }
28
+ /** What the member's next turn would get, without counting anything. */
29
+ async status(meter, subject) {
30
+ const query = new URLSearchParams();
31
+ if (subject.role) query.set("role", subject.role);
32
+ if (subject.payer) query.set("payer", subject.payer);
33
+ if (subject.payerRole) query.set("payerRole", subject.payerRole);
34
+ const suffix = query.size ? `?${query}` : "";
35
+ return (await this.request(`${this.memberPath(meter, subject.member)}${suffix}`, { method: "GET" })).allowance;
36
+ }
37
+ /** Move a member to the paid allowance until `expiresAt` (the paid period's end). */
38
+ async grant(meter, member, input) {
39
+ return (await this.request(`${this.memberPath(meter, member)}/grant`, this.body("PUT", {
40
+ tier: "paid",
41
+ ...input
42
+ }))).grant;
43
+ }
44
+ /** Synchronize a paid grant by durable product revision. Null expiry writes
45
+ * a retained revocation. A delayed older update is refused, never reactivated.
46
+ * There is no fallback to the unversioned grant endpoint on older servers. */
47
+ async syncGrant(meter, member, input) {
48
+ const { grant } = await this.request(`${this.memberPath(meter, member)}/grant/sync`, this.body("PUT", input));
49
+ if (grant.member !== member || grant.source !== input.source || grant.revision !== input.revision || grant.reference !== input.reference || grant.expiresAt !== (input.expiresAt === null ? null : new Date(input.expiresAt).toISOString())) throw new Error("The Hub returned a mismatched grant synchronization receipt");
50
+ return grant;
51
+ }
52
+ async revoke(meter, member) {
53
+ await this.request(`${this.memberPath(meter, member)}/grant`, { method: "DELETE" });
54
+ }
55
+ /** Turns per member and per line on one UTC day (default today). */
56
+ async usage(meter, day) {
57
+ const suffix = day ? `?day=${encodeURIComponent(day)}` : "";
58
+ return (await this.request(`${this.path(meter)}/usage${suffix}`, { method: "GET" })).usage;
59
+ }
60
+ path(meter) {
61
+ return `/v1/hub/allowances/${encodeURIComponent(meter)}`;
62
+ }
63
+ memberPath(meter, member) {
64
+ return `${this.path(meter)}/members/${encodeURIComponent(member)}`;
65
+ }
66
+ body(method, body) {
67
+ return jsonInit(method, body);
68
+ }
69
+ };
70
+ //#endregion
71
+ //#region src/apps.ts
72
+ function encodedId(id) {
73
+ if (typeof id !== "string" || !id || id.length > 256 || id === "." || id === "..") throw new Error("A bounded app or grant id is required");
74
+ return encodeURIComponent(id);
75
+ }
76
+ var HubAppsClient = class {
77
+ grants;
78
+ constructor(request) {
79
+ this.request = request;
80
+ this.grants = {
81
+ list: () => this.request("/v1/me/app-grants", { method: "GET" }),
82
+ revoke: async (grantId) => this.request(`/v1/me/app-grants/${encodedId(grantId)}/revoke`, { method: "POST" })
83
+ };
84
+ }
85
+ list() {
86
+ return this.request("/v1/apps", { method: "GET" });
87
+ }
88
+ /** The secret is returned only by creation; keep it in your server vault. */
89
+ create(input) {
90
+ return this.request("/v1/apps", jsonInit("POST", input));
91
+ }
92
+ /** Immutable association of two existing records with the same owner. */
93
+ async linkOAuthClient(appId, clientId) {
94
+ return this.request(`/v1/apps/${encodedId(appId)}/oidc-client`, jsonInit("POST", { clientId }));
95
+ }
96
+ async revoke(appId) {
97
+ return this.request(`/v1/apps/${encodedId(appId)}/revoke`, { method: "POST" });
98
+ }
99
+ };
100
+ //#endregion
101
+ //#region src/inbound-webhooks.ts
102
+ var HubInboundWebhooksClient = class {
103
+ constructor(request) {
104
+ this.request = request;
105
+ }
106
+ async create(connectionId, options = {}) {
107
+ return this.request(this.path(connectionId), jsonInit("POST", options));
108
+ }
109
+ async get(connectionId) {
110
+ return this.request(this.path(connectionId), { method: "GET" });
111
+ }
112
+ /** Add one owned Linq WhatsApp number without rotating the webhook secret. */
113
+ async ensurePhoneNumber(connectionId, phoneNumberId) {
114
+ if (!phoneNumberId || phoneNumberId.length > 128 || !/^[\x21-\x7e]+$/.test(phoneNumberId)) throw new Error("A bounded phone-number id is required");
115
+ return this.request(`${this.path(connectionId)}/phone-numbers/ensure`, jsonInit("POST", { phoneNumberId }));
116
+ }
117
+ /** Remove event subscriptions first. This does not silently rotate a live URL. */
118
+ async delete(connectionId) {
119
+ return this.request(this.path(connectionId), { method: "DELETE" });
120
+ }
121
+ path(connectionId) {
122
+ if (!connectionId || connectionId.length > 256) throw new Error("A bounded connection id is required");
123
+ return `/v1/hub/connections/${encodeURIComponent(connectionId)}/inbound-webhook`;
124
+ }
125
+ };
126
+ //#endregion
127
+ //#region src/lines.ts
128
+ /** Line calls share HubClient authentication and envelope handling. */
129
+ var HubLinesClient = class {
130
+ members;
131
+ memberApplications;
132
+ checkins;
133
+ constructor(request, createWorkflow, requestApplicationDispatchCurrent) {
134
+ this.request = request;
135
+ this.createWorkflow = createWorkflow;
136
+ this.requestApplicationDispatchCurrent = requestApplicationDispatchCurrent;
137
+ this.members = { list: async (lineId) => (await this.request(`/v1/hub/lines/${encodeURIComponent(lineId)}/members`, { method: "GET" })).members };
138
+ const applicationPath = (lineId, memberId) => `/v1/hub/lines/${encodeURIComponent(lineId)}/members/${encodeURIComponent(memberId)}/application`;
139
+ this.memberApplications = {
140
+ get: async (lineId, memberId) => await this.request(applicationPath(lineId, memberId), { method: "GET" }),
141
+ select: async (lineId, memberId, input) => (await this.request(applicationPath(lineId, memberId), jsonInit("PUT", input))).selection,
142
+ clear: async (lineId, memberId, input) => {
143
+ await this.request(applicationPath(lineId, memberId), jsonInit("DELETE", input));
144
+ }
145
+ };
146
+ this.checkins = { schedule: (cron, options) => {
147
+ const name = options.name ?? `line-checkin-${crypto.randomUUID().slice(0, 8)}`;
148
+ const yaml = [
149
+ `name: ${JSON.stringify(name)}`,
150
+ "on:",
151
+ ` schedule: { cron: ${JSON.stringify(cron)}, timezone: ${JSON.stringify(options.timezone)} }`,
152
+ "do:",
153
+ " - agent.run:",
154
+ " line:",
155
+ ` id: ${JSON.stringify(options.lineId)}`,
156
+ ` member: ${JSON.stringify(options.member)}`,
157
+ ` prompt: ${JSON.stringify(options.prompt)}`
158
+ ].join("\n");
159
+ return this.createWorkflow(yaml);
160
+ } };
161
+ }
162
+ async scheduleSend(cron, options) {
163
+ const name = options.name ?? `line-send-${crypto.randomUUID().slice(0, 8)}`;
164
+ const yaml = [
165
+ `name: ${JSON.stringify(name)}`,
166
+ "on:",
167
+ ` schedule: { cron: ${JSON.stringify(cron)}, timezone: ${JSON.stringify(options.timezone)} }`,
168
+ "do:",
169
+ " - line.send:",
170
+ ` lineId: ${JSON.stringify(options.lineId)}`,
171
+ ` memberId: ${JSON.stringify(options.memberId)}`,
172
+ ` text: ${JSON.stringify(options.text)}`,
173
+ ...options.notBefore ? [` notBefore: ${JSON.stringify(options.notBefore)}`] : []
174
+ ].join("\n");
175
+ return this.createWorkflow(yaml);
176
+ }
177
+ async context() {
178
+ return this.request("/v1/hub/lines/context", { method: "GET" });
179
+ }
180
+ async send(lineId, input) {
181
+ return this.request(`/v1/hub/lines/${encodeURIComponent(lineId)}/send`, jsonInit("POST", input));
182
+ }
183
+ async remind(lineId, input) {
184
+ return this.request(`/v1/hub/lines/${encodeURIComponent(lineId)}/remind`, jsonInit("POST", input));
185
+ }
186
+ async applicationDispatchCurrent(lineId, messageId, input, callbackBearer) {
187
+ if (!this.requestApplicationDispatchCurrent) throw new Error("Use HubClient to check application dispatch authority");
188
+ return (await this.requestApplicationDispatchCurrent(`/v1/hub/lines/${encodeURIComponent(lineId)}/messages/${encodeURIComponent(messageId)}/application-dispatch/current`, jsonInit("POST", input), callbackBearer)).current;
189
+ }
190
+ };
191
+ //#endregion
192
+ //#region src/managed-numbers.ts
193
+ /** Administrative number operations through Hub's authenticated transport.
194
+ * A mutation is one attempt; an uncertain create reuses its quote and reference. */
195
+ var HubManagedNumbersClient = class {
196
+ constructor(request) {
197
+ this.request = request;
198
+ }
199
+ readiness() {
200
+ return this.request("/v1/hub/numbers/readiness", { method: "GET" });
201
+ }
202
+ /** One page of orders. Scope by `clientReference` to ask about one binding,
203
+ * and follow `nextCursor` for the rest; a page is never ownership evidence. */
204
+ list(query = {}) {
205
+ const params = new URLSearchParams();
206
+ if (query.clientReference !== void 0) params.set("clientReference", query.clientReference);
207
+ if (query.cursor !== void 0) params.set("cursor", query.cursor);
208
+ if (query.limit !== void 0) params.set("limit", String(query.limit));
209
+ const search = params.toString();
210
+ return this.request(`/v1/hub/numbers${search ? `?${search}` : ""}`, { method: "GET" });
211
+ }
212
+ get(id) {
213
+ return this.request(this.path(id), { method: "GET" });
214
+ }
215
+ quote(input) {
216
+ return this.request("/v1/hub/numbers/quote", this.post(input));
217
+ }
218
+ /** `clientReference` and `transport`, when given, must match the signed
219
+ * quote or Hub refuses the purchase with a conflict. */
220
+ create(input) {
221
+ return this.request("/v1/hub/numbers", this.post(input));
222
+ }
223
+ /** Fences references so no order can take them again. Call it as the last
224
+ * step before retiring the resource they name: a purchase that races the
225
+ * retirement is then refused (`409 number_reference_fenced`) instead of
226
+ * binding a line to a resource that is gone. Refused with
227
+ * `409 number_reference_held` while a live order holds one of them; cancel
228
+ * it first. A cancelled order no longer holds its reference, so the fence
229
+ * succeeds as soon as `cancel` returns, whether or not its release is still
230
+ * pending. Repeating a fence is harmless. */
231
+ fence(input) {
232
+ return this.request("/v1/hub/numbers/fences", this.post(input));
233
+ }
234
+ advance(id) {
235
+ return this.request(`${this.path(id)}/advance`, this.post({}));
236
+ }
237
+ cancel(id) {
238
+ return this.request(`${this.path(id)}/cancel`, this.post({}));
239
+ }
240
+ path(id) {
241
+ if (!/^num_[a-f0-9]{36}$/.test(id)) throw new Error("Invalid managed number order id");
242
+ return `/v1/hub/numbers/${encodeURIComponent(id)}`;
243
+ }
244
+ post(body) {
245
+ return jsonInit("POST", body);
246
+ }
247
+ };
248
+ //#endregion
2
249
  //#region src/redaction.ts
3
250
  const SECRET_KEY_PATTERN = /(api[_-]?key|authorization|capability[_-]?token|token|secret)/i;
4
- const SECRET_VALUE_PATTERN = /\b(?:sk-tan[-_]|hubcap_|hct_|gh[pousr]_)[A-Za-z0-9_=-]+\b/g;
251
+ const SECRET_VALUE_PATTERN = /\b(?:sk-tan[-_]|hubcap_|hct_|lrc_|gh[pousr]_)[A-Za-z0-9_.=-]+\b/g;
5
252
  function redactHubValue(value) {
6
253
  if (typeof value === "string") return value.replace(SECRET_VALUE_PATTERN, "[REDACTED]");
7
254
  if (Array.isArray(value)) return value.map((item) => redactHubValue(item));
@@ -26,16 +273,18 @@ function bodySnippet(body, max = 200) {
26
273
  const trimmed = body.trim();
27
274
  return trimmed.length > max ? `${trimmed.slice(0, max)}…` : trimmed;
28
275
  }
29
- function httpError(path, status, statusText, body, contentType) {
30
- const suffix = statusText ? ` ${statusText}` : "";
276
+ function httpError(path, status, statusText, body, contentType, omitResponseDetails = false) {
277
+ const suffix = !omitResponseDetails && statusText ? ` ${statusText}` : "";
31
278
  return new HubSdkError({
32
279
  code: `HUB_HTTP_${status}`,
33
280
  message: `Hub request ${path} failed: HTTP ${status}${suffix}`,
34
281
  details: {
35
282
  status,
36
283
  path,
37
- contentType: contentType || null,
38
- bodySnippet: bodySnippet(body)
284
+ ...omitResponseDetails ? {} : {
285
+ contentType: contentType || null,
286
+ bodySnippet: bodySnippet(body)
287
+ }
39
288
  }
40
289
  }, { status });
41
290
  }
@@ -52,8 +301,13 @@ function isHubSuccessEnvelope(value) {
52
301
  function isRecord$1(value) {
53
302
  return typeof value === "object" && value !== null;
54
303
  }
55
- function optString(value) {
56
- return typeof value === "string" ? value : "";
304
+ function isDispatchCurrentData(value) {
305
+ return isRecord$1(value) && typeof value.current === "boolean";
306
+ }
307
+ /** Read a wire field as a string, or "" when the server sent anything else.
308
+ * `raw` is that field straight off the parsed payload, before any check. */
309
+ function optString(raw) {
310
+ return typeof raw === "string" ? raw : "";
57
311
  }
58
312
  /** An agent iteration's terminal status (`iteration.ended`) — only ever
59
313
  * succeeded/failed; an iteration is never guard-skipped. */
@@ -81,63 +335,63 @@ function isRunDoneStatus(value) {
81
335
  * malformed `token` can never reach a consumer as `{ delta: undefined }`, and
82
336
  * new server event kinds don't break older clients.
83
337
  */
84
- function toRunStreamEvent(eventType, data) {
338
+ function toRunStreamEvent(eventType, raw) {
85
339
  if (eventType === "ping") return { type: "ping" };
86
- if (!isRecord$1(data)) return null;
340
+ if (!isRecord$1(raw)) return null;
87
341
  switch (eventType) {
88
- case "snapshot": return typeof data.id === "string" && typeof data.workflowId === "string" && typeof data.status === "string" && Array.isArray(data.actionResults) ? {
342
+ case "snapshot": return typeof raw.id === "string" && typeof raw.workflowId === "string" && typeof raw.status === "string" && Array.isArray(raw.actionResults) ? {
89
343
  type: "snapshot",
90
- run: data
344
+ run: raw
91
345
  } : null;
92
- case "token": return typeof data.delta === "string" && typeof data.actionIndex === "number" ? {
346
+ case "token": return typeof raw.delta === "string" && typeof raw.actionIndex === "number" ? {
93
347
  type: "token",
94
- actionIndex: data.actionIndex,
95
- delta: data.delta,
96
- at: optString(data.at)
348
+ actionIndex: raw.actionIndex,
349
+ delta: raw.delta,
350
+ at: optString(raw.at)
97
351
  } : null;
98
- case "run.done": return isRunDoneStatus(data.status) ? {
352
+ case "run.done": return isRunDoneStatus(raw.status) ? {
99
353
  type: "run.done",
100
- status: data.status,
101
- error: typeof data.error === "string" ? data.error : null,
102
- ...typeof data.at === "string" ? { at: data.at } : {}
354
+ status: raw.status,
355
+ error: typeof raw.error === "string" ? raw.error : null,
356
+ ...typeof raw.at === "string" ? { at: raw.at } : {}
103
357
  } : null;
104
- case "run.waiting": return typeof data.decisionId === "string" && data.decisionId.length > 0 ? {
358
+ case "run.waiting": return typeof raw.decisionId === "string" && raw.decisionId.length > 0 ? {
105
359
  type: "run.waiting",
106
- decisionId: data.decisionId,
107
- ...typeof data.at === "string" ? { at: data.at } : {}
360
+ decisionId: raw.decisionId,
361
+ ...typeof raw.at === "string" ? { at: raw.at } : {}
108
362
  } : null;
109
- case "action.started": return typeof data.index === "number" && typeof data.kind === "string" && typeof data.at === "string" ? {
363
+ case "action.started": return typeof raw.index === "number" && typeof raw.kind === "string" && typeof raw.at === "string" ? {
110
364
  type: "action.started",
111
- index: data.index,
112
- kind: data.kind,
113
- at: data.at
365
+ index: raw.index,
366
+ kind: raw.kind,
367
+ at: raw.at
114
368
  } : null;
115
- case "action.finished": return typeof data.index === "number" && typeof data.kind === "string" && isActionFinishedStatus(data.status) && typeof data.at === "string" ? {
369
+ case "action.finished": return typeof raw.index === "number" && typeof raw.kind === "string" && isActionFinishedStatus(raw.status) && typeof raw.at === "string" ? {
116
370
  type: "action.finished",
117
- index: data.index,
118
- kind: data.kind,
119
- status: data.status,
120
- at: data.at,
121
- ...typeof data.costUsd === "number" ? { costUsd: data.costUsd } : {},
122
- ...typeof data.error === "string" ? { error: data.error } : {}
371
+ index: raw.index,
372
+ kind: raw.kind,
373
+ status: raw.status,
374
+ at: raw.at,
375
+ ...typeof raw.costUsd === "number" ? { costUsd: raw.costUsd } : {},
376
+ ...typeof raw.error === "string" ? { error: raw.error } : {}
123
377
  } : null;
124
- case "iteration.started": return typeof data.actionIndex === "number" && typeof data.iterationIndex === "number" && typeof data.at === "string" ? {
378
+ case "iteration.started": return typeof raw.actionIndex === "number" && typeof raw.iterationIndex === "number" && typeof raw.at === "string" ? {
125
379
  type: "iteration.started",
126
- actionIndex: data.actionIndex,
127
- iterationIndex: data.iterationIndex,
128
- at: data.at,
129
- ...typeof data.model === "string" ? { model: data.model } : {}
380
+ actionIndex: raw.actionIndex,
381
+ iterationIndex: raw.iterationIndex,
382
+ at: raw.at,
383
+ ...typeof raw.model === "string" ? { model: raw.model } : {}
130
384
  } : null;
131
- case "iteration.ended": return typeof data.actionIndex === "number" && typeof data.iterationIndex === "number" && isIterationStatus(data.status) && typeof data.at === "string" ? {
385
+ case "iteration.ended": return typeof raw.actionIndex === "number" && typeof raw.iterationIndex === "number" && isIterationStatus(raw.status) && typeof raw.at === "string" ? {
132
386
  type: "iteration.ended",
133
- actionIndex: data.actionIndex,
134
- iterationIndex: data.iterationIndex,
135
- status: data.status,
136
- at: data.at,
137
- ...typeof data.outputPreview === "string" ? { outputPreview: data.outputPreview } : {},
138
- ...typeof data.inputTokens === "number" ? { inputTokens: data.inputTokens } : {},
139
- ...typeof data.outputTokens === "number" ? { outputTokens: data.outputTokens } : {},
140
- ...typeof data.costUsd === "number" ? { costUsd: data.costUsd } : {}
387
+ actionIndex: raw.actionIndex,
388
+ iterationIndex: raw.iterationIndex,
389
+ status: raw.status,
390
+ at: raw.at,
391
+ ...typeof raw.outputPreview === "string" ? { outputPreview: raw.outputPreview } : {},
392
+ ...typeof raw.inputTokens === "number" ? { inputTokens: raw.inputTokens } : {},
393
+ ...typeof raw.outputTokens === "number" ? { outputTokens: raw.outputTokens } : {},
394
+ ...typeof raw.costUsd === "number" ? { costUsd: raw.costUsd } : {}
141
395
  } : null;
142
396
  default: return null;
143
397
  }
@@ -145,8 +399,8 @@ function toRunStreamEvent(eventType, data) {
145
399
  /** True for an aborted/timed-out fetch (or any abort). fetch rejects with the
146
400
  * signal's reason — a DOMException named `AbortError` (caller) or `TimeoutError`
147
401
  * (AbortSignal.timeout). */
148
- function isAbortError(err) {
149
- return err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
402
+ function isAbortError(cause) {
403
+ return cause instanceof Error && (cause.name === "AbortError" || cause.name === "TimeoutError");
150
404
  }
151
405
  /** A signal that aborts when the caller's signal aborts OR `timeoutMs` elapses.
152
406
  * Returns undefined when neither bound applies (no per-request abort needed). */
@@ -220,13 +474,68 @@ function nonEmpty(value) {
220
474
  function readProcessEnv() {
221
475
  return globalThis.process?.env ?? {};
222
476
  }
223
- var HubClient = class HubClient {
477
+ var HubTransport = class {
224
478
  baseUrl;
225
479
  fetch;
226
480
  apiKey;
227
481
  authHeaders;
482
+ constructor(options) {
483
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
484
+ this.apiKey = options.apiKey;
485
+ this.authHeaders = options.authHeaders;
486
+ this.fetch = options.fetch ?? fetch.bind(globalThis);
487
+ }
488
+ async request(path, init, options = {}) {
489
+ const callerAuth = options.auth === "caller";
490
+ const response = await this.fetch(`${this.baseUrl}${path}`, {
491
+ ...init,
492
+ headers: await this.buildHeaders(init.headers, callerAuth)
493
+ });
494
+ const status = response.status;
495
+ const contentType = response.headers.get("content-type") ?? "";
496
+ const bodyText = await response.text();
497
+ if (!contentType.includes("application/json")) throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
498
+ let parsed;
499
+ try {
500
+ parsed = JSON.parse(bodyText);
501
+ } catch {
502
+ throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
503
+ }
504
+ if (isHubErrorEnvelope(parsed)) {
505
+ if (callerAuth) throw new HubSdkError({
506
+ code: parsed.error.code,
507
+ message: `Hub request ${path} failed: HTTP ${status}`
508
+ }, { status });
509
+ throw new HubSdkError(parsed.error, { status });
510
+ }
511
+ if (isHubSuccessEnvelope(parsed)) {
512
+ if (callerAuth && !response.ok) throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
513
+ if (options.validateData && !options.validateData(parsed.data)) throw new HubSdkError({
514
+ code: `HUB_HTTP_${status}`,
515
+ message: `Hub request ${path} returned invalid data`,
516
+ details: {
517
+ status,
518
+ path
519
+ }
520
+ }, { status });
521
+ return parsed.data;
522
+ }
523
+ throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
524
+ }
525
+ async buildHeaders(headers, callerAuth = false) {
526
+ const mergedHeaders = new Headers({ Accept: "application/json" });
527
+ if (!callerAuth && this.apiKey) mergedHeaders.set("Authorization", `Bearer ${this.apiKey}`);
528
+ if (!callerAuth && this.authHeaders) for (const [key, value] of new Headers(await this.authHeaders())) mergedHeaders.set(key, value);
529
+ for (const [key, value] of new Headers(headers)) mergedHeaders.set(key, value);
530
+ return mergedHeaders;
531
+ }
532
+ };
533
+ var HubClient = class HubClient extends HubTransport {
534
+ allowances;
535
+ apps;
228
536
  connections;
229
537
  channels;
538
+ numbers;
230
539
  eventSubscriptions;
231
540
  permissions;
232
541
  tokens;
@@ -235,11 +544,12 @@ var HubClient = class HubClient {
235
544
  audit;
236
545
  githubApp;
237
546
  workflows;
547
+ lines;
238
548
  constructor(options) {
239
- this.baseUrl = options.baseUrl.replace(/\/+$/, "");
240
- this.apiKey = options.apiKey;
241
- this.authHeaders = options.authHeaders;
242
- this.fetch = options.fetch ?? fetch.bind(globalThis);
549
+ super(options);
550
+ this.allowances = new HubAllowancesClient((path, init) => this.request(path, init));
551
+ this.apps = new HubAppsClient((path, init) => this.request(path, init));
552
+ this.numbers = new HubManagedNumbersClient((path, init) => this.request(path, init));
243
553
  this.connections = new HubConnectionsClient((path, init) => this.request(path, init));
244
554
  this.channels = new HubChannelsClient((path, init) => this.request(path, init));
245
555
  this.eventSubscriptions = new HubEventSubscriptionsClient((path, init) => this.request(path, init));
@@ -250,6 +560,23 @@ var HubClient = class HubClient {
250
560
  this.audit = new HubAuditClient((path, init) => this.request(path, init));
251
561
  this.githubApp = new HubGithubAppClient((path, init) => this.request(path, init));
252
562
  this.workflows = new HubWorkflowsClient((path, init) => this.request(path, init), (path, init) => this.stream(path, init), (path, init) => this.requestBytes(path, init));
563
+ this.lines = new HubLinesClient((path, init) => this.request(path, init), (yaml) => this.workflows.create(yaml), (path, init, callbackBearer) => {
564
+ if (typeof callbackBearer !== "string" || !/^[\x21-\x7e]{16,512}$/.test(callbackBearer)) throw new HubSdkError({
565
+ code: "HUB_INVALID_INPUT",
566
+ message: "Application callback bearer is invalid"
567
+ });
568
+ const headers = new Headers(init.headers);
569
+ headers.set("Authorization", `Bearer ${callbackBearer}`);
570
+ return this.request(path, {
571
+ ...init,
572
+ headers,
573
+ credentials: "omit",
574
+ redirect: "manual"
575
+ }, {
576
+ auth: "caller",
577
+ validateData: isDispatchCurrentData
578
+ });
579
+ });
253
580
  }
254
581
  static fromEnv(options = {}) {
255
582
  const env = options.env ?? readProcessEnv();
@@ -263,25 +590,6 @@ var HubClient = class HubClient {
263
590
  async status() {
264
591
  return this.request("/v1/hub/status", { method: "GET" });
265
592
  }
266
- async request(path, init) {
267
- const response = await this.fetch(`${this.baseUrl}${path}`, {
268
- ...init,
269
- headers: await this.buildHeaders(init.headers)
270
- });
271
- const status = response.status;
272
- const contentType = response.headers.get("content-type") ?? "";
273
- const bodyText = await response.text();
274
- if (!contentType.includes("application/json")) throw httpError(path, status, response.statusText, bodyText, contentType);
275
- let parsed;
276
- try {
277
- parsed = JSON.parse(bodyText);
278
- } catch {
279
- throw httpError(path, status, response.statusText, bodyText, contentType);
280
- }
281
- if (isHubErrorEnvelope(parsed)) throw new HubSdkError(parsed.error, { status });
282
- if (isHubSuccessEnvelope(parsed)) return parsed.data;
283
- throw httpError(path, status, response.statusText, bodyText, contentType);
284
- }
285
593
  /**
286
594
  * Open a streaming (Server-Sent Events) response and return its raw body.
287
595
  * Shares auth-header building + `fetch` with {@link request}, but does NOT
@@ -348,25 +656,13 @@ var HubClient = class HubClient {
348
656
  contentType
349
657
  };
350
658
  }
351
- async buildHeaders(headers) {
352
- const mergedHeaders = new Headers(headers);
353
- if (!mergedHeaders.has("Accept")) mergedHeaders.set("Accept", "application/json");
354
- if (this.apiKey) mergedHeaders.set("Authorization", `Bearer ${this.apiKey}`);
355
- if (this.authHeaders) for (const [key, value] of new Headers(await this.authHeaders())) mergedHeaders.set(key, value);
356
- for (const [key, value] of new Headers(headers)) mergedHeaders.set(key, value);
357
- return mergedHeaders;
358
- }
359
659
  };
360
660
  var HubTokensClient = class {
361
661
  constructor(request) {
362
662
  this.request = request;
363
663
  }
364
664
  async mint(options) {
365
- return this.request("/v1/hub/tokens", {
366
- method: "POST",
367
- body: JSON.stringify(options),
368
- headers: { "Content-Type": "application/json" }
369
- });
665
+ return this.request("/v1/hub/tokens", jsonInit("POST", options));
370
666
  }
371
667
  async list(options = {}) {
372
668
  const searchParams = new URLSearchParams();
@@ -400,38 +696,22 @@ var HubPermissionsClient = class {
400
696
  return this.request(`/v1/hub/policies?connectionId=${encodeURIComponent(connectionId)}`, { method: "GET" });
401
697
  }
402
698
  async set(input) {
403
- return this.request("/v1/hub/policies", {
404
- method: "PUT",
405
- body: JSON.stringify(input),
406
- headers: { "Content-Type": "application/json" }
407
- });
699
+ return this.request("/v1/hub/policies", jsonInit("PUT", input));
408
700
  }
409
701
  /** Reset an action to its default by deleting any stored override. */
410
702
  async delete(input) {
411
- return this.request("/v1/hub/policies", {
412
- method: "DELETE",
413
- body: JSON.stringify(input),
414
- headers: { "Content-Type": "application/json" }
415
- });
703
+ return this.request("/v1/hub/policies", jsonInit("DELETE", input));
416
704
  }
417
705
  /** Bulk-allow every write action of a connection's provider. Reads are
418
706
  * already allowed for sandbox agents; destructive actions stay `ask`.
419
707
  * Idempotent: actions with an existing policy are left untouched. */
420
708
  async allowWrites(connectionId) {
421
- return this.request("/v1/hub/policies/allow-writes", {
422
- method: "POST",
423
- body: JSON.stringify({ connectionId }),
424
- headers: { "Content-Type": "application/json" }
425
- });
709
+ return this.request("/v1/hub/policies/allow-writes", jsonInit("POST", { connectionId }));
426
710
  }
427
711
  /** Inverse of `allowWrites`: delete only the rows it created for this
428
712
  * connection. Manual per-action decisions are left intact. */
429
713
  async revertWrites(connectionId) {
430
- return this.request("/v1/hub/policies/revert-writes", {
431
- method: "POST",
432
- body: JSON.stringify({ connectionId }),
433
- headers: { "Content-Type": "application/json" }
434
- });
714
+ return this.request("/v1/hub/policies/revert-writes", jsonInit("POST", { connectionId }));
435
715
  }
436
716
  };
437
717
  var HubToolsClient = class {
@@ -439,34 +719,32 @@ var HubToolsClient = class {
439
719
  this.request = request;
440
720
  }
441
721
  async search(query, options = {}) {
442
- return this.request("/v1/hub/tools/search", {
443
- method: "POST",
444
- body: JSON.stringify({
445
- query,
446
- provider: options.provider,
447
- limit: options.limit
448
- }),
449
- headers: { "Content-Type": "application/json" }
450
- });
722
+ return this.request("/v1/hub/tools/search", jsonInit("POST", {
723
+ query,
724
+ provider: options.provider,
725
+ limit: options.limit
726
+ }));
451
727
  }
452
728
  async sources() {
453
729
  return this.request("/v1/hub/tools/sources", { method: "GET" });
454
730
  }
455
731
  async describe(path) {
456
- return this.request("/v1/hub/tools/describe", {
457
- method: "POST",
458
- body: JSON.stringify({ path }),
459
- headers: { "Content-Type": "application/json" }
460
- });
732
+ return this.request("/v1/hub/tools/describe", jsonInit("POST", { path }));
461
733
  }
462
- async invoke(path, input, options = {}) {
463
- const execInit = this.buildExecInit(path, input, options.connectionId);
734
+ /**
735
+ * Run one hub tool. `raw` is the tool input: the SDK forwards it verbatim as
736
+ * the request body's `input`, and the server validates it against the tool's
737
+ * own schema, so the client never gives it a shape.
738
+ */
739
+ async invoke(path, raw, options = {}) {
740
+ const execInit = this.buildExecInit(path, raw, options);
464
741
  try {
465
742
  return await this.request("/v1/hub/exec", execInit);
466
743
  } catch (error) {
467
744
  if (!(error instanceof HubSdkError) || !requiresCapabilityToken(error)) throw error;
745
+ const approvalId = getApprovalId(error);
746
+ if (approvalId && options.approve !== true) throw error;
468
747
  if (options.approve) {
469
- const approvalId = getApprovalId(error);
470
748
  if (!approvalId) throw error;
471
749
  const approved = await this.request(`/v1/hub/approvals/${encodeURIComponent(approvalId)}/approve`, { method: "POST" });
472
750
  validateApprovedExecution(approved, path, options.connectionId);
@@ -484,15 +762,11 @@ var HubToolsClient = class {
484
762
  });
485
763
  }
486
764
  }
487
- const minted = await this.request("/v1/hub/tokens", {
488
- method: "POST",
489
- body: JSON.stringify({
490
- actionPath: path,
491
- connectionId: options.connectionId,
492
- provider: options.connectionId ? void 0 : path.split(".")[0]
493
- }),
494
- headers: { "Content-Type": "application/json" }
495
- });
765
+ const minted = await this.request("/v1/hub/tokens", jsonInit("POST", {
766
+ actionPath: path,
767
+ connectionId: options.connectionId,
768
+ provider: options.connectionId ? void 0 : path.split(".")[0]
769
+ }));
496
770
  return this.request("/v1/hub/exec", {
497
771
  ...execInit,
498
772
  headers: {
@@ -501,16 +775,13 @@ var HubToolsClient = class {
501
775
  }
502
776
  });
503
777
  }
504
- buildExecInit(path, input, connectionId) {
505
- return {
506
- method: "POST",
507
- body: JSON.stringify({
508
- path,
509
- input,
510
- connectionId
511
- }),
512
- headers: { "Content-Type": "application/json" }
513
- };
778
+ buildExecInit(path, raw, options) {
779
+ return jsonInit("POST", {
780
+ path,
781
+ input: raw,
782
+ connectionId: options.connectionId,
783
+ idempotencyKey: options.idempotencyKey
784
+ });
514
785
  }
515
786
  };
516
787
  function requiresCapabilityToken(error) {
@@ -540,6 +811,17 @@ function validateApprovedExecution(approved, path, connectionId) {
540
811
  }
541
812
  });
542
813
  }
814
+ const GITHUB_EXACT_CONNECT_SCOPES = [
815
+ "read:user",
816
+ "repo",
817
+ "read:org"
818
+ ];
819
+ function sameOAuthScopeSet(left, right) {
820
+ if (!Array.isArray(left)) return false;
821
+ const leftSet = new Set(left);
822
+ const rightSet = new Set(right);
823
+ return leftSet.size === left.length && rightSet.size === right.length && leftSet.size === rightSet.size && [...leftSet].every((scope) => rightSet.has(scope));
824
+ }
543
825
  var HubChannelsClient = class {
544
826
  constructor(request) {
545
827
  this.request = request;
@@ -548,11 +830,7 @@ var HubChannelsClient = class {
548
830
  return this.request("/v1/hub/channels", { method: "GET" });
549
831
  }
550
832
  async createEmail(input = {}) {
551
- return this.request("/v1/hub/channels/email", {
552
- method: "POST",
553
- body: JSON.stringify(input),
554
- headers: { "Content-Type": "application/json" }
555
- });
833
+ return this.request("/v1/hub/channels/email", jsonInit("POST", input));
556
834
  }
557
835
  async delete(channelId) {
558
836
  return this.request(`/v1/hub/channels/${encodeURIComponent(channelId)}`, { method: "DELETE" });
@@ -566,19 +844,17 @@ var HubEventSubscriptionsClient = class {
566
844
  return this.request("/v1/hub/event-subscriptions", { method: "GET" });
567
845
  }
568
846
  async create(input) {
569
- return this.request("/v1/hub/event-subscriptions", {
570
- method: "POST",
571
- body: JSON.stringify(input),
572
- headers: { "Content-Type": "application/json" }
573
- });
847
+ return this.request("/v1/hub/event-subscriptions", jsonInit("POST", input));
574
848
  }
575
849
  async delete(subscriptionId) {
576
850
  return this.request(`/v1/hub/event-subscriptions/${encodeURIComponent(subscriptionId)}`, { method: "DELETE" });
577
851
  }
578
852
  };
579
853
  var HubConnectionsClient = class {
854
+ inboundWebhook;
580
855
  constructor(request) {
581
856
  this.request = request;
857
+ this.inboundWebhook = new HubInboundWebhooksClient(request);
582
858
  }
583
859
  async list() {
584
860
  return this.request("/v1/hub/connections", { method: "GET" });
@@ -590,40 +866,38 @@ var HubConnectionsClient = class {
590
866
  return this.request("/v1/hub/providers", { method: "GET" });
591
867
  }
592
868
  async start(provider, options = {}) {
593
- return this.request(`/v1/hub/connections/${encodeURIComponent(provider)}/start`, {
594
- method: "POST",
595
- body: JSON.stringify({
596
- returnUrl: options.returnUrl,
597
- cli: options.cli,
598
- connectionParameters: options.connectionParameters
599
- }),
600
- headers: { "Content-Type": "application/json" }
869
+ if (options.requestedScopes !== void 0 && (provider !== "github" || !sameOAuthScopeSet(options.requestedScopes, GITHUB_EXACT_CONNECT_SCOPES))) throw new HubSdkError({
870
+ code: "HUB_INVALID_INPUT",
871
+ message: "GitHub requestedScopes must be read:user, repo, and read:org"
872
+ });
873
+ const started = await this.request(`/v1/hub/connections/${encodeURIComponent(provider)}/start`, jsonInit("POST", {
874
+ returnUrl: options.returnUrl,
875
+ cli: options.cli,
876
+ connectionParameters: options.connectionParameters,
877
+ requestedScopes: options.requestedScopes
878
+ }));
879
+ if (options.requestedScopes !== void 0 && (started.provider !== provider || !sameOAuthScopeSet(started.scopes, options.requestedScopes))) throw new HubSdkError({
880
+ code: "HUB_CONFIG_MISSING",
881
+ message: "Hub did not preserve the requested OAuth scopes"
601
882
  });
883
+ return started;
602
884
  }
603
885
  async startWhatsappEmbeddedSignup(options = {}) {
604
- return this.request("/v1/hub/connections/whatsapp-business/embedded-signup/start", {
605
- method: "POST",
606
- body: JSON.stringify({ returnUrl: options.returnUrl }),
607
- headers: { "Content-Type": "application/json" }
608
- });
886
+ return this.request("/v1/hub/connections/whatsapp-business/embedded-signup/start", jsonInit("POST", { returnUrl: options.returnUrl }));
609
887
  }
610
888
  async completeWhatsappEmbeddedSignup(input) {
611
- return this.request("/v1/hub/connections/whatsapp-business/embedded-signup/complete", {
612
- method: "POST",
613
- body: JSON.stringify(input),
614
- headers: { "Content-Type": "application/json" }
615
- });
889
+ return this.request("/v1/hub/connections/whatsapp-business/embedded-signup/complete", jsonInit("POST", input));
616
890
  }
617
891
  /** Connect a non-OAuth (api-key) connector by submitting the user's key.
618
892
  * The server validates the key with a live probe before persisting and
619
893
  * returns the created (or reconnected) connection — there is no redirect,
620
- * unlike `start`. */
621
- async connectApiKey(provider, apiKey) {
622
- return this.request(`/v1/hub/connections/${encodeURIComponent(provider)}/connect-key`, {
623
- method: "POST",
624
- body: JSON.stringify({ apiKey }),
625
- headers: { "Content-Type": "application/json" }
626
- });
894
+ * unlike `start`. Cloudbeds requires propertyId metadata and PriceLabs
895
+ * requires listing ID/PMS pairs; other providers have no metadata. */
896
+ async connectApiKey(provider, apiKey, metadata) {
897
+ return this.request(`/v1/hub/connections/${encodeURIComponent(provider)}/connect-key`, jsonInit("POST", {
898
+ apiKey,
899
+ ...metadata === void 0 ? {} : { metadata }
900
+ }));
627
901
  }
628
902
  async revoke(connectionId) {
629
903
  return this.request(`/v1/hub/connections/${encodeURIComponent(connectionId)}`, { method: "DELETE" });
@@ -651,11 +925,7 @@ var HubGithubAppClient = class {
651
925
  this.request = request;
652
926
  }
653
927
  async mintInstallationToken(input) {
654
- return this.request("/v1/hub/github-app/mint-installation-token", {
655
- method: "POST",
656
- body: JSON.stringify(input),
657
- headers: { "Content-Type": "application/json" }
658
- });
928
+ return this.request("/v1/hub/github-app/mint-installation-token", jsonInit("POST", input));
659
929
  }
660
930
  /** Every installation the caller may act through — their own and any org's
661
931
  * they were verified against. The management surface's read. */
@@ -730,11 +1000,7 @@ var HubWorkflowsClient = class {
730
1000
  return this.request(`/v1/workflows/${encodeURIComponent(id)}`, { method: "GET" });
731
1001
  }
732
1002
  async create(yaml) {
733
- return this.request("/v1/workflows", {
734
- method: "POST",
735
- body: JSON.stringify({ yaml }),
736
- headers: { "Content-Type": "application/json" }
737
- });
1003
+ return this.request("/v1/workflows", jsonInit("POST", { yaml }));
738
1004
  }
739
1005
  /**
740
1006
  * Replace the workflow's definition from YAML (recompiled server-side,
@@ -745,14 +1011,10 @@ var HubWorkflowsClient = class {
745
1011
  * concurrent modification, `NOT_FOUND` for an unknown/foreign id.
746
1012
  */
747
1013
  async update(id, yaml, opts = {}) {
748
- return this.request(`/v1/workflows/${encodeURIComponent(id)}`, {
749
- method: "PUT",
750
- body: JSON.stringify({
751
- yaml,
752
- ...opts.note !== void 0 ? { note: opts.note } : {}
753
- }),
754
- headers: { "Content-Type": "application/json" }
755
- });
1014
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}`, jsonInit("PUT", {
1015
+ yaml,
1016
+ ...opts.note !== void 0 ? { note: opts.note } : {}
1017
+ }));
756
1018
  }
757
1019
  async delete(id) {
758
1020
  await this.request(`/v1/workflows/${encodeURIComponent(id)}`, { method: "DELETE" });
@@ -763,11 +1025,7 @@ var HubWorkflowsClient = class {
763
1025
  * via `update`, but it can still be paused/resumed here).
764
1026
  */
765
1027
  async setEnabled(id, enabled) {
766
- return this.request(`/v1/workflows/${encodeURIComponent(id)}`, {
767
- method: "PATCH",
768
- body: JSON.stringify({ enabled }),
769
- headers: { "Content-Type": "application/json" }
770
- });
1028
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}`, jsonInit("PATCH", { enabled }));
771
1029
  }
772
1030
  /**
773
1031
  * One page of run history, newest first. Pass the previous page's
@@ -795,9 +1053,7 @@ var HubWorkflowsClient = class {
795
1053
  async run(id, inputs, opts = {}) {
796
1054
  const hasInputs = inputs !== void 0 && Object.keys(inputs).length > 0;
797
1055
  return this.request(`/v1/workflows/${encodeURIComponent(id)}/run`, {
798
- method: "POST",
799
- body: JSON.stringify(hasInputs ? { inputs } : {}),
800
- headers: { "Content-Type": "application/json" },
1056
+ ...jsonInit("POST", hasInputs ? { inputs } : {}),
801
1057
  ...opts.signal ? { signal: opts.signal } : {}
802
1058
  });
803
1059
  }
@@ -976,11 +1232,7 @@ var HubWorkflowsClient = class {
976
1232
  * YAML no longer compiles, `CONFLICT` on a concurrent modification.
977
1233
  */
978
1234
  async rollback(id, rev) {
979
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/rollback`, {
980
- method: "POST",
981
- body: JSON.stringify({ rev }),
982
- headers: { "Content-Type": "application/json" }
983
- });
1235
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/rollback`, jsonInit("POST", { rev }));
984
1236
  }
985
1237
  /**
986
1238
  * Deterministic health stats over the workflow's last N terminal runs
@@ -1001,11 +1253,7 @@ var HubWorkflowsClient = class {
1001
1253
  * until an owner approves.
1002
1254
  */
1003
1255
  async propose(id, input) {
1004
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/proposals`, {
1005
- method: "POST",
1006
- body: JSON.stringify(input),
1007
- headers: { "Content-Type": "application/json" }
1008
- });
1256
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/proposals`, jsonInit("POST", input));
1009
1257
  }
1010
1258
  /**
1011
1259
  * Pending (proposed) and declined (rejected) revisions, newest first, with
@@ -1032,11 +1280,7 @@ var HubWorkflowsClient = class {
1032
1280
  * pending proposal.
1033
1281
  */
1034
1282
  async rejectProposal(id, rev, opts = {}) {
1035
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/proposals/${encodeURIComponent(String(rev))}/reject`, {
1036
- method: "POST",
1037
- body: JSON.stringify(opts.reason !== void 0 ? { reason: opts.reason } : {}),
1038
- headers: { "Content-Type": "application/json" }
1039
- });
1283
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/proposals/${encodeURIComponent(String(rev))}/reject`, jsonInit("POST", opts.reason !== void 0 ? { reason: opts.reason } : {}));
1040
1284
  }
1041
1285
  /**
1042
1286
  * Mint a fresh webhook hook token, retiring the current one immediately.
@@ -1112,29 +1356,24 @@ var HubWorkflowsClient = class {
1112
1356
  /**
1113
1357
  * Upsert a key; returns the entry with its NEW version (increments on every
1114
1358
  * write). Throws `HubSdkError(KV_VALUE_TOO_LARGE)` past the 64KiB value cap
1115
- * or `KV_KEY_LIMIT` past the per-workflow key cap.
1359
+ * or `KV_KEY_LIMIT` past the per-workflow key cap. `raw` is the caller's
1360
+ * value, stored and read back verbatim, so the client never gives it a shape.
1116
1361
  */
1117
- async putKv(id, key, value) {
1118
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}`, {
1119
- method: "PUT",
1120
- body: JSON.stringify({ value }),
1121
- headers: { "Content-Type": "application/json" }
1122
- });
1362
+ async putKv(id, key, raw) {
1363
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}`, jsonInit("PUT", { value: raw }));
1123
1364
  }
1124
1365
  /**
1125
1366
  * Compare-and-swap: the write lands only when the stored version still
1126
1367
  * equals `expectedVersion`; otherwise `HubSdkError(KV_VERSION_CONFLICT)`
1127
- * (409) — re-read and retry. Creation is {@link putKv}'s job.
1368
+ * (409) — re-read and retry. Creation is {@link putKv}'s job. `raw` is the
1369
+ * caller's value, stored and read back verbatim, so the client never gives it
1370
+ * a shape.
1128
1371
  */
1129
- async casKv(id, key, expectedVersion, value) {
1130
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}/cas`, {
1131
- method: "POST",
1132
- body: JSON.stringify({
1133
- expectedVersion,
1134
- value
1135
- }),
1136
- headers: { "Content-Type": "application/json" }
1137
- });
1372
+ async casKv(id, key, expectedVersion, raw) {
1373
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}/cas`, jsonInit("POST", {
1374
+ expectedVersion,
1375
+ value: raw
1376
+ }));
1138
1377
  }
1139
1378
  /** Delete a key; idempotent — `deleted` reports whether a row was removed. */
1140
1379
  async deleteKv(id, key) {
@@ -1154,11 +1393,7 @@ var HubWorkflowsClient = class {
1154
1393
  * (400); an unknown template id throws `NOT_FOUND`.
1155
1394
  */
1156
1395
  async instantiateTemplate(templateId, parameters) {
1157
- return this.request(`/v1/workflows/templates/${encodeURIComponent(templateId)}/instantiate`, {
1158
- method: "POST",
1159
- body: JSON.stringify(parameters ? { parameters } : {}),
1160
- headers: { "Content-Type": "application/json" }
1161
- });
1396
+ return this.request(`/v1/workflows/templates/${encodeURIComponent(templateId)}/instantiate`, jsonInit("POST", parameters ? { parameters } : {}));
1162
1397
  }
1163
1398
  /**
1164
1399
  * The caller's open decisions across all workflows — the always-available
@@ -1185,11 +1420,7 @@ var HubWorkflowsClient = class {
1185
1420
  * (409 — answered, timed out, or cancelled first).
1186
1421
  */
1187
1422
  async resolveRunDecision(id, runId, input) {
1188
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/decision/resolve`, {
1189
- method: "POST",
1190
- body: JSON.stringify(input),
1191
- headers: { "Content-Type": "application/json" }
1192
- });
1423
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/decision/resolve`, jsonInit("POST", input));
1193
1424
  }
1194
1425
  /**
1195
1426
  * Dry-run a YAML definition against the platform compiler without saving it.
@@ -1202,14 +1433,10 @@ var HubWorkflowsClient = class {
1202
1433
  * the unconnected providers is the point.
1203
1434
  */
1204
1435
  async validate(yaml, opts = {}) {
1205
- return this.request("/v1/workflows/validate", {
1206
- method: "POST",
1207
- body: JSON.stringify({
1208
- yaml,
1209
- ...opts.structural ? { structural: true } : {}
1210
- }),
1211
- headers: { "Content-Type": "application/json" }
1212
- });
1436
+ return this.request("/v1/workflows/validate", jsonInit("POST", {
1437
+ yaml,
1438
+ ...opts.structural ? { structural: true } : {}
1439
+ }));
1213
1440
  }
1214
1441
  async schema() {
1215
1442
  return this.request("/v1/workflows/schema", { method: "GET" });
@@ -1473,6 +1700,55 @@ function requestFailure(code, status, error, headers) {
1473
1700
  };
1474
1701
  }
1475
1702
  //#endregion
1476
- export { HUB_API_KEY_ENV_VAR, HUB_CAPABILITY_TOKEN_ENV_VAR, HUB_URL_ENV_VAR, HubApprovalsClient, HubAuditClient, HubChannelsClient, HubClient, HubConnectionsClient, HubEventDeliveryError, HubEventSubscriptionsClient, HubGithubAppClient, HubPermissionsClient, HubSdkError, HubTokensClient, HubToolsClient, HubWorkflowsClient, authenticateHubEventRequest, deriveHubEventCallbackSecret, parseHubEventDelivery, redactHubValue, resolveHubAuth, resolveHubBaseUrl, verifyHubEventSignature };
1703
+ //#region src/line-grants.ts
1704
+ function path(binding, suffix = "") {
1705
+ if (!binding.workspaceId || !binding.workspaceAgentId) throw new Error("A workspace and agent are required for a line grant");
1706
+ return `/v1/hub/line-grants/current${suffix}?${new URLSearchParams({
1707
+ workspaceId: binding.workspaceId,
1708
+ workspaceAgentId: binding.workspaceAgentId
1709
+ })}`;
1710
+ }
1711
+ /** Every call uses HubTransport's authHeaders, so one-use app broker tokens can be minted per request. */
1712
+ var HubLineGrantsClient = class extends HubTransport {
1713
+ current(binding) {
1714
+ return this.request(path(binding), { method: "GET" });
1715
+ }
1716
+ async line(binding) {
1717
+ return (await this.request(path(binding, "/line"), { method: "GET" })).line;
1718
+ }
1719
+ async attach(binding, input) {
1720
+ return (await this.request(path(binding, "/attachment"), jsonInit("PUT", input))).attachment;
1721
+ }
1722
+ detach(binding) {
1723
+ return this.request(path(binding, "/attachment"), { method: "DELETE" });
1724
+ }
1725
+ async threads(binding) {
1726
+ return (await this.request(path(binding, "/threads"), { method: "GET" })).threads;
1727
+ }
1728
+ async messages(binding, threadId) {
1729
+ if (!threadId || threadId.length > 256) throw new Error("A bounded line thread id is required");
1730
+ return (await this.request(path(binding, `/threads/${encodeURIComponent(threadId)}/messages`), { method: "GET" })).messages;
1731
+ }
1732
+ memberApplication(binding) {
1733
+ return this.request(path(binding, "/member-application"), { method: "GET" });
1734
+ }
1735
+ /**
1736
+ * Route the owner's texts to this app's callback; the incumbent attachment
1737
+ * stays. `replaceSelectionId` moves them from another app on the owner's
1738
+ * explicit choice.
1739
+ */
1740
+ async selectApplication(binding, input) {
1741
+ return (await this.request(path(binding, "/member-application"), jsonInit("PUT", input))).selection;
1742
+ }
1743
+ /** Return the owner's texts to the incumbent attachment. */
1744
+ async clearApplication(binding, input) {
1745
+ await this.request(path(binding, "/member-application"), jsonInit("DELETE", input));
1746
+ }
1747
+ revoke(binding) {
1748
+ return this.request(path(binding), { method: "DELETE" });
1749
+ }
1750
+ };
1751
+ //#endregion
1752
+ export { HUB_API_KEY_ENV_VAR, HUB_CAPABILITY_TOKEN_ENV_VAR, HUB_URL_ENV_VAR, HubAllowancesClient, HubApprovalsClient, HubAppsClient, HubAuditClient, HubChannelsClient, HubClient, HubConnectionsClient, HubEventDeliveryError, HubEventSubscriptionsClient, HubGithubAppClient, HubInboundWebhooksClient, HubLineGrantsClient, HubLinesClient, HubManagedNumbersClient, HubPermissionsClient, HubSdkError, HubTokensClient, HubToolsClient, HubWorkflowsClient, authenticateHubEventRequest, deriveHubEventCallbackSecret, parseHubEventDelivery, redactHubValue, resolveHubAuth, resolveHubBaseUrl, verifyHubEventSignature };
1477
1753
 
1478
1754
  //# sourceMappingURL=index.js.map