@tangle-network/hub-sdk 0.29.0-develop.20260819122040.176c418 → 0.29.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,284 @@
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/knowledge.ts
128
+ /** Runtime-only retrieval. The authenticated sandbox credential determines the
129
+ * scope on the server; neither a caller nor an agent can supply another scope. */
130
+ var HubKnowledgeClient = class {
131
+ constructor(request) {
132
+ this.request = request;
133
+ }
134
+ query(input, options) {
135
+ return this.request("/v1/knowledge/runtime/query", {
136
+ ...jsonInit("POST", {
137
+ query: input.query,
138
+ ...input.limit !== void 0 ? { limit: input.limit } : {}
139
+ }),
140
+ signal: options?.signal
141
+ });
142
+ }
143
+ };
144
+ //#endregion
145
+ //#region src/lines.ts
146
+ /** The `on.schedule` mapping a Line schedule helper writes. */
147
+ function scheduleYaml(cron, timezone, until) {
148
+ return ` schedule: { ${[
149
+ `cron: ${JSON.stringify(cron)}`,
150
+ `timezone: ${JSON.stringify(timezone)}`,
151
+ ...until ? [`until: ${JSON.stringify(until)}`] : []
152
+ ].join(", ")} }`;
153
+ }
154
+ /** Line calls share HubClient authentication and envelope handling. */
155
+ var HubLinesClient = class {
156
+ members;
157
+ memberApplications;
158
+ checkins;
159
+ constructor(request, createWorkflow, requestApplicationDispatchCurrent) {
160
+ this.request = request;
161
+ this.createWorkflow = createWorkflow;
162
+ this.requestApplicationDispatchCurrent = requestApplicationDispatchCurrent;
163
+ this.members = { list: async (lineId) => (await this.request(`/v1/hub/lines/${encodeURIComponent(lineId)}/members`, { method: "GET" })).members };
164
+ const applicationPath = (lineId, memberId) => `/v1/hub/lines/${encodeURIComponent(lineId)}/members/${encodeURIComponent(memberId)}/application`;
165
+ this.memberApplications = {
166
+ get: async (lineId, memberId) => await this.request(applicationPath(lineId, memberId), { method: "GET" }),
167
+ select: async (lineId, memberId, input) => (await this.request(applicationPath(lineId, memberId), jsonInit("PUT", input))).selection,
168
+ clear: async (lineId, memberId, input) => {
169
+ await this.request(applicationPath(lineId, memberId), jsonInit("DELETE", input));
170
+ }
171
+ };
172
+ this.checkins = { schedule: (cron, options) => {
173
+ const name = options.name ?? `line-checkin-${crypto.randomUUID().slice(0, 8)}`;
174
+ const yaml = [
175
+ `name: ${JSON.stringify(name)}`,
176
+ "on:",
177
+ scheduleYaml(cron, options.timezone, options.until),
178
+ "do:",
179
+ " - agent.run:",
180
+ " line:",
181
+ ` id: ${JSON.stringify(options.lineId)}`,
182
+ ` member: ${JSON.stringify(options.member)}`,
183
+ ` prompt: ${JSON.stringify(options.prompt)}`
184
+ ].join("\n");
185
+ return this.createWorkflow(yaml);
186
+ } };
187
+ }
188
+ async scheduleSend(cron, options) {
189
+ const name = options.name ?? `line-send-${crypto.randomUUID().slice(0, 8)}`;
190
+ const yaml = [
191
+ `name: ${JSON.stringify(name)}`,
192
+ "on:",
193
+ scheduleYaml(cron, options.timezone, options.until),
194
+ "do:",
195
+ " - line.send:",
196
+ ` lineId: ${JSON.stringify(options.lineId)}`,
197
+ ` memberId: ${JSON.stringify(options.memberId)}`,
198
+ ` text: ${JSON.stringify(options.text)}`,
199
+ ...options.notBefore ? [` notBefore: ${JSON.stringify(options.notBefore)}`] : []
200
+ ].join("\n");
201
+ return this.createWorkflow(yaml);
202
+ }
203
+ async context() {
204
+ return this.request("/v1/hub/lines/context", { method: "GET" });
205
+ }
206
+ async send(lineId, input) {
207
+ return this.request(`/v1/hub/lines/${encodeURIComponent(lineId)}/send`, jsonInit("POST", input));
208
+ }
209
+ /** Read an owner send's receipt, including its coded answer. Queued is not delivered. */
210
+ async sentMessage(lineId, messageId) {
211
+ return this.request(`/v1/hub/lines/${encodeURIComponent(lineId)}/outbox/${encodeURIComponent(messageId)}`, { method: "GET" });
212
+ }
213
+ async remind(lineId, input) {
214
+ return this.request(`/v1/hub/lines/${encodeURIComponent(lineId)}/remind`, jsonInit("POST", input));
215
+ }
216
+ async applicationDispatchCurrent(lineId, messageId, input, callbackBearer) {
217
+ if (!this.requestApplicationDispatchCurrent) throw new Error("Use HubClient to check application dispatch authority");
218
+ return (await this.requestApplicationDispatchCurrent(`/v1/hub/lines/${encodeURIComponent(lineId)}/messages/${encodeURIComponent(messageId)}/application-dispatch/current`, jsonInit("POST", input), callbackBearer)).current;
219
+ }
220
+ };
221
+ //#endregion
222
+ //#region src/managed-numbers.ts
223
+ /** Administrative number operations through Hub's authenticated transport.
224
+ * A mutation is one attempt; an uncertain create reuses its quote and reference. */
225
+ var HubManagedNumbersClient = class {
226
+ constructor(request) {
227
+ this.request = request;
228
+ }
229
+ readiness() {
230
+ return this.request("/v1/hub/numbers/readiness", { method: "GET" });
231
+ }
232
+ /** One page of orders. Scope by `clientReference` to ask about one binding,
233
+ * and follow `nextCursor` for the rest; a page is never ownership evidence. */
234
+ list(query = {}) {
235
+ const params = new URLSearchParams();
236
+ if (query.clientReference !== void 0) params.set("clientReference", query.clientReference);
237
+ if (query.cursor !== void 0) params.set("cursor", query.cursor);
238
+ if (query.limit !== void 0) params.set("limit", String(query.limit));
239
+ const search = params.toString();
240
+ return this.request(`/v1/hub/numbers${search ? `?${search}` : ""}`, { method: "GET" });
241
+ }
242
+ get(id) {
243
+ return this.request(this.path(id), { method: "GET" });
244
+ }
245
+ quote(input) {
246
+ return this.request("/v1/hub/numbers/quote", this.post(input));
247
+ }
248
+ /** `clientReference` and `transport`, when given, must match the signed
249
+ * quote or Hub refuses the purchase with a conflict. */
250
+ create(input) {
251
+ return this.request("/v1/hub/numbers", this.post(input));
252
+ }
253
+ /** Fences references so no order can take them again. Call it as the last
254
+ * step before retiring the resource they name: a purchase that races the
255
+ * retirement is then refused (`409 number_reference_fenced`) instead of
256
+ * binding a line to a resource that is gone. Refused with
257
+ * `409 number_reference_held` while a live order holds one of them; cancel
258
+ * it first. A cancelled order no longer holds its reference, so the fence
259
+ * succeeds as soon as `cancel` returns, whether or not its release is still
260
+ * pending. Repeating a fence is harmless. */
261
+ fence(input) {
262
+ return this.request("/v1/hub/numbers/fences", this.post(input));
263
+ }
264
+ advance(id) {
265
+ return this.request(`${this.path(id)}/advance`, this.post({}));
266
+ }
267
+ cancel(id) {
268
+ return this.request(`${this.path(id)}/cancel`, this.post({}));
269
+ }
270
+ path(id) {
271
+ if (!/^num_[a-f0-9]{36}$/.test(id)) throw new Error("Invalid managed number order id");
272
+ return `/v1/hub/numbers/${encodeURIComponent(id)}`;
273
+ }
274
+ post(body) {
275
+ return jsonInit("POST", body);
276
+ }
277
+ };
278
+ //#endregion
2
279
  //#region src/redaction.ts
3
280
  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;
281
+ const SECRET_VALUE_PATTERN = /\b(?:sk-tan[-_]|hubcap_|hct_|lrc_|gh[pousr]_)[A-Za-z0-9_.=-]+\b/g;
5
282
  function redactHubValue(value) {
6
283
  if (typeof value === "string") return value.replace(SECRET_VALUE_PATTERN, "[REDACTED]");
7
284
  if (Array.isArray(value)) return value.map((item) => redactHubValue(item));
@@ -26,16 +303,18 @@ function bodySnippet(body, max = 200) {
26
303
  const trimmed = body.trim();
27
304
  return trimmed.length > max ? `${trimmed.slice(0, max)}…` : trimmed;
28
305
  }
29
- function httpError(path, status, statusText, body, contentType) {
30
- const suffix = statusText ? ` ${statusText}` : "";
306
+ function httpError(path, status, statusText, body, contentType, omitResponseDetails = false) {
307
+ const suffix = !omitResponseDetails && statusText ? ` ${statusText}` : "";
31
308
  return new HubSdkError({
32
309
  code: `HUB_HTTP_${status}`,
33
310
  message: `Hub request ${path} failed: HTTP ${status}${suffix}`,
34
311
  details: {
35
312
  status,
36
313
  path,
37
- contentType: contentType || null,
38
- bodySnippet: bodySnippet(body)
314
+ ...omitResponseDetails ? {} : {
315
+ contentType: contentType || null,
316
+ bodySnippet: bodySnippet(body)
317
+ }
39
318
  }
40
319
  }, { status });
41
320
  }
@@ -52,6 +331,9 @@ function isHubSuccessEnvelope(value) {
52
331
  function isRecord$1(value) {
53
332
  return typeof value === "object" && value !== null;
54
333
  }
334
+ function isDispatchCurrentData(value) {
335
+ return isRecord$1(value) && typeof value.current === "boolean";
336
+ }
55
337
  /** Read a wire field as a string, or "" when the server sent anything else.
56
338
  * `raw` is that field straight off the parsed payload, before any check. */
57
339
  function optString(raw) {
@@ -222,13 +504,69 @@ function nonEmpty(value) {
222
504
  function readProcessEnv() {
223
505
  return globalThis.process?.env ?? {};
224
506
  }
225
- var HubClient = class HubClient {
507
+ var HubTransport = class {
226
508
  baseUrl;
227
509
  fetch;
228
510
  apiKey;
229
511
  authHeaders;
512
+ constructor(options) {
513
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
514
+ this.apiKey = options.apiKey;
515
+ this.authHeaders = options.authHeaders;
516
+ this.fetch = options.fetch ?? fetch.bind(globalThis);
517
+ }
518
+ async request(path, init, options = {}) {
519
+ const callerAuth = options.auth === "caller";
520
+ const response = await this.fetch(`${this.baseUrl}${path}`, {
521
+ ...init,
522
+ headers: await this.buildHeaders(init.headers, callerAuth)
523
+ });
524
+ const status = response.status;
525
+ const contentType = response.headers.get("content-type") ?? "";
526
+ const bodyText = await response.text();
527
+ if (!contentType.includes("application/json")) throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
528
+ let parsed;
529
+ try {
530
+ parsed = JSON.parse(bodyText);
531
+ } catch {
532
+ throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
533
+ }
534
+ if (isHubErrorEnvelope(parsed)) {
535
+ if (callerAuth) throw new HubSdkError({
536
+ code: parsed.error.code,
537
+ message: `Hub request ${path} failed: HTTP ${status}`
538
+ }, { status });
539
+ throw new HubSdkError(parsed.error, { status });
540
+ }
541
+ if (isHubSuccessEnvelope(parsed)) {
542
+ if (callerAuth && !response.ok) throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
543
+ if (options.validateData && !options.validateData(parsed.data)) throw new HubSdkError({
544
+ code: `HUB_HTTP_${status}`,
545
+ message: `Hub request ${path} returned invalid data`,
546
+ details: {
547
+ status,
548
+ path
549
+ }
550
+ }, { status });
551
+ return parsed.data;
552
+ }
553
+ throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
554
+ }
555
+ async buildHeaders(headers, callerAuth = false) {
556
+ const mergedHeaders = new Headers({ Accept: "application/json" });
557
+ if (!callerAuth && this.apiKey) mergedHeaders.set("Authorization", `Bearer ${this.apiKey}`);
558
+ if (!callerAuth && this.authHeaders) for (const [key, value] of new Headers(await this.authHeaders())) mergedHeaders.set(key, value);
559
+ for (const [key, value] of new Headers(headers)) mergedHeaders.set(key, value);
560
+ return mergedHeaders;
561
+ }
562
+ };
563
+ var HubClient = class HubClient extends HubTransport {
564
+ knowledge;
565
+ allowances;
566
+ apps;
230
567
  connections;
231
568
  channels;
569
+ numbers;
232
570
  eventSubscriptions;
233
571
  permissions;
234
572
  tokens;
@@ -237,11 +575,13 @@ var HubClient = class HubClient {
237
575
  audit;
238
576
  githubApp;
239
577
  workflows;
578
+ lines;
240
579
  constructor(options) {
241
- this.baseUrl = options.baseUrl.replace(/\/+$/, "");
242
- this.apiKey = options.apiKey;
243
- this.authHeaders = options.authHeaders;
244
- this.fetch = options.fetch ?? fetch.bind(globalThis);
580
+ super(options);
581
+ this.knowledge = new HubKnowledgeClient((path, init) => this.request(path, init));
582
+ this.allowances = new HubAllowancesClient((path, init) => this.request(path, init));
583
+ this.apps = new HubAppsClient((path, init) => this.request(path, init));
584
+ this.numbers = new HubManagedNumbersClient((path, init) => this.request(path, init));
245
585
  this.connections = new HubConnectionsClient((path, init) => this.request(path, init));
246
586
  this.channels = new HubChannelsClient((path, init) => this.request(path, init));
247
587
  this.eventSubscriptions = new HubEventSubscriptionsClient((path, init) => this.request(path, init));
@@ -252,6 +592,23 @@ var HubClient = class HubClient {
252
592
  this.audit = new HubAuditClient((path, init) => this.request(path, init));
253
593
  this.githubApp = new HubGithubAppClient((path, init) => this.request(path, init));
254
594
  this.workflows = new HubWorkflowsClient((path, init) => this.request(path, init), (path, init) => this.stream(path, init), (path, init) => this.requestBytes(path, init));
595
+ this.lines = new HubLinesClient((path, init) => this.request(path, init), (yaml) => this.workflows.create(yaml), (path, init, callbackBearer) => {
596
+ if (typeof callbackBearer !== "string" || !/^[\x21-\x7e]{16,512}$/.test(callbackBearer)) throw new HubSdkError({
597
+ code: "HUB_INVALID_INPUT",
598
+ message: "Application callback bearer is invalid"
599
+ });
600
+ const headers = new Headers(init.headers);
601
+ headers.set("Authorization", `Bearer ${callbackBearer}`);
602
+ return this.request(path, {
603
+ ...init,
604
+ headers,
605
+ credentials: "omit",
606
+ redirect: "manual"
607
+ }, {
608
+ auth: "caller",
609
+ validateData: isDispatchCurrentData
610
+ });
611
+ });
255
612
  }
256
613
  static fromEnv(options = {}) {
257
614
  const env = options.env ?? readProcessEnv();
@@ -265,25 +622,6 @@ var HubClient = class HubClient {
265
622
  async status() {
266
623
  return this.request("/v1/hub/status", { method: "GET" });
267
624
  }
268
- async request(path, init) {
269
- const response = await this.fetch(`${this.baseUrl}${path}`, {
270
- ...init,
271
- headers: await this.buildHeaders(init.headers)
272
- });
273
- const status = response.status;
274
- const contentType = response.headers.get("content-type") ?? "";
275
- const bodyText = await response.text();
276
- if (!contentType.includes("application/json")) throw httpError(path, status, response.statusText, bodyText, contentType);
277
- let parsed;
278
- try {
279
- parsed = JSON.parse(bodyText);
280
- } catch {
281
- throw httpError(path, status, response.statusText, bodyText, contentType);
282
- }
283
- if (isHubErrorEnvelope(parsed)) throw new HubSdkError(parsed.error, { status });
284
- if (isHubSuccessEnvelope(parsed)) return parsed.data;
285
- throw httpError(path, status, response.statusText, bodyText, contentType);
286
- }
287
625
  /**
288
626
  * Open a streaming (Server-Sent Events) response and return its raw body.
289
627
  * Shares auth-header building + `fetch` with {@link request}, but does NOT
@@ -350,25 +688,13 @@ var HubClient = class HubClient {
350
688
  contentType
351
689
  };
352
690
  }
353
- async buildHeaders(headers) {
354
- const mergedHeaders = new Headers(headers);
355
- if (!mergedHeaders.has("Accept")) mergedHeaders.set("Accept", "application/json");
356
- if (this.apiKey) mergedHeaders.set("Authorization", `Bearer ${this.apiKey}`);
357
- if (this.authHeaders) for (const [key, value] of new Headers(await this.authHeaders())) mergedHeaders.set(key, value);
358
- for (const [key, value] of new Headers(headers)) mergedHeaders.set(key, value);
359
- return mergedHeaders;
360
- }
361
691
  };
362
692
  var HubTokensClient = class {
363
693
  constructor(request) {
364
694
  this.request = request;
365
695
  }
366
696
  async mint(options) {
367
- return this.request("/v1/hub/tokens", {
368
- method: "POST",
369
- body: JSON.stringify(options),
370
- headers: { "Content-Type": "application/json" }
371
- });
697
+ return this.request("/v1/hub/tokens", jsonInit("POST", options));
372
698
  }
373
699
  async list(options = {}) {
374
700
  const searchParams = new URLSearchParams();
@@ -402,38 +728,22 @@ var HubPermissionsClient = class {
402
728
  return this.request(`/v1/hub/policies?connectionId=${encodeURIComponent(connectionId)}`, { method: "GET" });
403
729
  }
404
730
  async set(input) {
405
- return this.request("/v1/hub/policies", {
406
- method: "PUT",
407
- body: JSON.stringify(input),
408
- headers: { "Content-Type": "application/json" }
409
- });
731
+ return this.request("/v1/hub/policies", jsonInit("PUT", input));
410
732
  }
411
733
  /** Reset an action to its default by deleting any stored override. */
412
734
  async delete(input) {
413
- return this.request("/v1/hub/policies", {
414
- method: "DELETE",
415
- body: JSON.stringify(input),
416
- headers: { "Content-Type": "application/json" }
417
- });
735
+ return this.request("/v1/hub/policies", jsonInit("DELETE", input));
418
736
  }
419
737
  /** Bulk-allow every write action of a connection's provider. Reads are
420
738
  * already allowed for sandbox agents; destructive actions stay `ask`.
421
739
  * Idempotent: actions with an existing policy are left untouched. */
422
740
  async allowWrites(connectionId) {
423
- return this.request("/v1/hub/policies/allow-writes", {
424
- method: "POST",
425
- body: JSON.stringify({ connectionId }),
426
- headers: { "Content-Type": "application/json" }
427
- });
741
+ return this.request("/v1/hub/policies/allow-writes", jsonInit("POST", { connectionId }));
428
742
  }
429
743
  /** Inverse of `allowWrites`: delete only the rows it created for this
430
744
  * connection. Manual per-action decisions are left intact. */
431
745
  async revertWrites(connectionId) {
432
- return this.request("/v1/hub/policies/revert-writes", {
433
- method: "POST",
434
- body: JSON.stringify({ connectionId }),
435
- headers: { "Content-Type": "application/json" }
436
- });
746
+ return this.request("/v1/hub/policies/revert-writes", jsonInit("POST", { connectionId }));
437
747
  }
438
748
  };
439
749
  var HubToolsClient = class {
@@ -441,25 +751,17 @@ var HubToolsClient = class {
441
751
  this.request = request;
442
752
  }
443
753
  async search(query, options = {}) {
444
- return this.request("/v1/hub/tools/search", {
445
- method: "POST",
446
- body: JSON.stringify({
447
- query,
448
- provider: options.provider,
449
- limit: options.limit
450
- }),
451
- headers: { "Content-Type": "application/json" }
452
- });
754
+ return this.request("/v1/hub/tools/search", jsonInit("POST", {
755
+ query,
756
+ provider: options.provider,
757
+ limit: options.limit
758
+ }));
453
759
  }
454
760
  async sources() {
455
761
  return this.request("/v1/hub/tools/sources", { method: "GET" });
456
762
  }
457
763
  async describe(path) {
458
- return this.request("/v1/hub/tools/describe", {
459
- method: "POST",
460
- body: JSON.stringify({ path }),
461
- headers: { "Content-Type": "application/json" }
462
- });
764
+ return this.request("/v1/hub/tools/describe", jsonInit("POST", { path }));
463
765
  }
464
766
  /**
465
767
  * Run one hub tool. `raw` is the tool input: the SDK forwards it verbatim as
@@ -472,8 +774,9 @@ var HubToolsClient = class {
472
774
  return await this.request("/v1/hub/exec", execInit);
473
775
  } catch (error) {
474
776
  if (!(error instanceof HubSdkError) || !requiresCapabilityToken(error)) throw error;
777
+ const approvalId = getApprovalId(error);
778
+ if (approvalId && options.approve !== true) throw error;
475
779
  if (options.approve) {
476
- const approvalId = getApprovalId(error);
477
780
  if (!approvalId) throw error;
478
781
  const approved = await this.request(`/v1/hub/approvals/${encodeURIComponent(approvalId)}/approve`, { method: "POST" });
479
782
  validateApprovedExecution(approved, path, options.connectionId);
@@ -491,15 +794,11 @@ var HubToolsClient = class {
491
794
  });
492
795
  }
493
796
  }
494
- const minted = await this.request("/v1/hub/tokens", {
495
- method: "POST",
496
- body: JSON.stringify({
497
- actionPath: path,
498
- connectionId: options.connectionId,
499
- provider: options.connectionId ? void 0 : path.split(".")[0]
500
- }),
501
- headers: { "Content-Type": "application/json" }
502
- });
797
+ const minted = await this.request("/v1/hub/tokens", jsonInit("POST", {
798
+ actionPath: path,
799
+ connectionId: options.connectionId,
800
+ provider: options.connectionId ? void 0 : path.split(".")[0]
801
+ }));
503
802
  return this.request("/v1/hub/exec", {
504
803
  ...execInit,
505
804
  headers: {
@@ -509,16 +808,12 @@ var HubToolsClient = class {
509
808
  });
510
809
  }
511
810
  buildExecInit(path, raw, options) {
512
- return {
513
- method: "POST",
514
- body: JSON.stringify({
515
- path,
516
- input: raw,
517
- connectionId: options.connectionId,
518
- idempotencyKey: options.idempotencyKey
519
- }),
520
- headers: { "Content-Type": "application/json" }
521
- };
811
+ return jsonInit("POST", {
812
+ path,
813
+ input: raw,
814
+ connectionId: options.connectionId,
815
+ idempotencyKey: options.idempotencyKey
816
+ });
522
817
  }
523
818
  };
524
819
  function requiresCapabilityToken(error) {
@@ -548,6 +843,17 @@ function validateApprovedExecution(approved, path, connectionId) {
548
843
  }
549
844
  });
550
845
  }
846
+ const GITHUB_EXACT_CONNECT_SCOPES = [
847
+ "read:user",
848
+ "repo",
849
+ "read:org"
850
+ ];
851
+ function sameOAuthScopeSet(left, right) {
852
+ if (!Array.isArray(left)) return false;
853
+ const leftSet = new Set(left);
854
+ const rightSet = new Set(right);
855
+ return leftSet.size === left.length && rightSet.size === right.length && leftSet.size === rightSet.size && [...leftSet].every((scope) => rightSet.has(scope));
856
+ }
551
857
  var HubChannelsClient = class {
552
858
  constructor(request) {
553
859
  this.request = request;
@@ -556,11 +862,7 @@ var HubChannelsClient = class {
556
862
  return this.request("/v1/hub/channels", { method: "GET" });
557
863
  }
558
864
  async createEmail(input = {}) {
559
- return this.request("/v1/hub/channels/email", {
560
- method: "POST",
561
- body: JSON.stringify(input),
562
- headers: { "Content-Type": "application/json" }
563
- });
865
+ return this.request("/v1/hub/channels/email", jsonInit("POST", input));
564
866
  }
565
867
  async delete(channelId) {
566
868
  return this.request(`/v1/hub/channels/${encodeURIComponent(channelId)}`, { method: "DELETE" });
@@ -574,19 +876,17 @@ var HubEventSubscriptionsClient = class {
574
876
  return this.request("/v1/hub/event-subscriptions", { method: "GET" });
575
877
  }
576
878
  async create(input) {
577
- return this.request("/v1/hub/event-subscriptions", {
578
- method: "POST",
579
- body: JSON.stringify(input),
580
- headers: { "Content-Type": "application/json" }
581
- });
879
+ return this.request("/v1/hub/event-subscriptions", jsonInit("POST", input));
582
880
  }
583
881
  async delete(subscriptionId) {
584
882
  return this.request(`/v1/hub/event-subscriptions/${encodeURIComponent(subscriptionId)}`, { method: "DELETE" });
585
883
  }
586
884
  };
587
885
  var HubConnectionsClient = class {
886
+ inboundWebhook;
588
887
  constructor(request) {
589
888
  this.request = request;
889
+ this.inboundWebhook = new HubInboundWebhooksClient(request);
590
890
  }
591
891
  async list() {
592
892
  return this.request("/v1/hub/connections", { method: "GET" });
@@ -598,40 +898,38 @@ var HubConnectionsClient = class {
598
898
  return this.request("/v1/hub/providers", { method: "GET" });
599
899
  }
600
900
  async start(provider, options = {}) {
601
- return this.request(`/v1/hub/connections/${encodeURIComponent(provider)}/start`, {
602
- method: "POST",
603
- body: JSON.stringify({
604
- returnUrl: options.returnUrl,
605
- cli: options.cli,
606
- connectionParameters: options.connectionParameters
607
- }),
608
- headers: { "Content-Type": "application/json" }
901
+ if (options.requestedScopes !== void 0 && (provider !== "github" || !sameOAuthScopeSet(options.requestedScopes, GITHUB_EXACT_CONNECT_SCOPES))) throw new HubSdkError({
902
+ code: "HUB_INVALID_INPUT",
903
+ message: "GitHub requestedScopes must be read:user, repo, and read:org"
904
+ });
905
+ const started = await this.request(`/v1/hub/connections/${encodeURIComponent(provider)}/start`, jsonInit("POST", {
906
+ returnUrl: options.returnUrl,
907
+ cli: options.cli,
908
+ connectionParameters: options.connectionParameters,
909
+ requestedScopes: options.requestedScopes
910
+ }));
911
+ if (options.requestedScopes !== void 0 && (started.provider !== provider || !sameOAuthScopeSet(started.scopes, options.requestedScopes))) throw new HubSdkError({
912
+ code: "HUB_CONFIG_MISSING",
913
+ message: "Hub did not preserve the requested OAuth scopes"
609
914
  });
915
+ return started;
610
916
  }
611
917
  async startWhatsappEmbeddedSignup(options = {}) {
612
- return this.request("/v1/hub/connections/whatsapp-business/embedded-signup/start", {
613
- method: "POST",
614
- body: JSON.stringify({ returnUrl: options.returnUrl }),
615
- headers: { "Content-Type": "application/json" }
616
- });
918
+ return this.request("/v1/hub/connections/whatsapp-business/embedded-signup/start", jsonInit("POST", { returnUrl: options.returnUrl }));
617
919
  }
618
920
  async completeWhatsappEmbeddedSignup(input) {
619
- return this.request("/v1/hub/connections/whatsapp-business/embedded-signup/complete", {
620
- method: "POST",
621
- body: JSON.stringify(input),
622
- headers: { "Content-Type": "application/json" }
623
- });
921
+ return this.request("/v1/hub/connections/whatsapp-business/embedded-signup/complete", jsonInit("POST", input));
624
922
  }
625
923
  /** Connect a non-OAuth (api-key) connector by submitting the user's key.
626
924
  * The server validates the key with a live probe before persisting and
627
925
  * returns the created (or reconnected) connection — there is no redirect,
628
- * unlike `start`. */
629
- async connectApiKey(provider, apiKey) {
630
- return this.request(`/v1/hub/connections/${encodeURIComponent(provider)}/connect-key`, {
631
- method: "POST",
632
- body: JSON.stringify({ apiKey }),
633
- headers: { "Content-Type": "application/json" }
634
- });
926
+ * unlike `start`. Cloudbeds requires propertyId metadata and PriceLabs
927
+ * requires listing ID/PMS pairs; other providers have no metadata. */
928
+ async connectApiKey(provider, apiKey, metadata) {
929
+ return this.request(`/v1/hub/connections/${encodeURIComponent(provider)}/connect-key`, jsonInit("POST", {
930
+ apiKey,
931
+ ...metadata === void 0 ? {} : { metadata }
932
+ }));
635
933
  }
636
934
  async revoke(connectionId) {
637
935
  return this.request(`/v1/hub/connections/${encodeURIComponent(connectionId)}`, { method: "DELETE" });
@@ -659,11 +957,7 @@ var HubGithubAppClient = class {
659
957
  this.request = request;
660
958
  }
661
959
  async mintInstallationToken(input) {
662
- return this.request("/v1/hub/github-app/mint-installation-token", {
663
- method: "POST",
664
- body: JSON.stringify(input),
665
- headers: { "Content-Type": "application/json" }
666
- });
960
+ return this.request("/v1/hub/github-app/mint-installation-token", jsonInit("POST", input));
667
961
  }
668
962
  /** Every installation the caller may act through — their own and any org's
669
963
  * they were verified against. The management surface's read. */
@@ -738,11 +1032,7 @@ var HubWorkflowsClient = class {
738
1032
  return this.request(`/v1/workflows/${encodeURIComponent(id)}`, { method: "GET" });
739
1033
  }
740
1034
  async create(yaml) {
741
- return this.request("/v1/workflows", {
742
- method: "POST",
743
- body: JSON.stringify({ yaml }),
744
- headers: { "Content-Type": "application/json" }
745
- });
1035
+ return this.request("/v1/workflows", jsonInit("POST", { yaml }));
746
1036
  }
747
1037
  /**
748
1038
  * Replace the workflow's definition from YAML (recompiled server-side,
@@ -753,14 +1043,10 @@ var HubWorkflowsClient = class {
753
1043
  * concurrent modification, `NOT_FOUND` for an unknown/foreign id.
754
1044
  */
755
1045
  async update(id, yaml, opts = {}) {
756
- return this.request(`/v1/workflows/${encodeURIComponent(id)}`, {
757
- method: "PUT",
758
- body: JSON.stringify({
759
- yaml,
760
- ...opts.note !== void 0 ? { note: opts.note } : {}
761
- }),
762
- headers: { "Content-Type": "application/json" }
763
- });
1046
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}`, jsonInit("PUT", {
1047
+ yaml,
1048
+ ...opts.note !== void 0 ? { note: opts.note } : {}
1049
+ }));
764
1050
  }
765
1051
  async delete(id) {
766
1052
  await this.request(`/v1/workflows/${encodeURIComponent(id)}`, { method: "DELETE" });
@@ -771,11 +1057,7 @@ var HubWorkflowsClient = class {
771
1057
  * via `update`, but it can still be paused/resumed here).
772
1058
  */
773
1059
  async setEnabled(id, enabled) {
774
- return this.request(`/v1/workflows/${encodeURIComponent(id)}`, {
775
- method: "PATCH",
776
- body: JSON.stringify({ enabled }),
777
- headers: { "Content-Type": "application/json" }
778
- });
1060
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}`, jsonInit("PATCH", { enabled }));
779
1061
  }
780
1062
  /**
781
1063
  * One page of run history, newest first. Pass the previous page's
@@ -803,9 +1085,7 @@ var HubWorkflowsClient = class {
803
1085
  async run(id, inputs, opts = {}) {
804
1086
  const hasInputs = inputs !== void 0 && Object.keys(inputs).length > 0;
805
1087
  return this.request(`/v1/workflows/${encodeURIComponent(id)}/run`, {
806
- method: "POST",
807
- body: JSON.stringify(hasInputs ? { inputs } : {}),
808
- headers: { "Content-Type": "application/json" },
1088
+ ...jsonInit("POST", hasInputs ? { inputs } : {}),
809
1089
  ...opts.signal ? { signal: opts.signal } : {}
810
1090
  });
811
1091
  }
@@ -984,11 +1264,7 @@ var HubWorkflowsClient = class {
984
1264
  * YAML no longer compiles, `CONFLICT` on a concurrent modification.
985
1265
  */
986
1266
  async rollback(id, rev) {
987
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/rollback`, {
988
- method: "POST",
989
- body: JSON.stringify({ rev }),
990
- headers: { "Content-Type": "application/json" }
991
- });
1267
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/rollback`, jsonInit("POST", { rev }));
992
1268
  }
993
1269
  /**
994
1270
  * Deterministic health stats over the workflow's last N terminal runs
@@ -1009,11 +1285,7 @@ var HubWorkflowsClient = class {
1009
1285
  * until an owner approves.
1010
1286
  */
1011
1287
  async propose(id, input) {
1012
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/proposals`, {
1013
- method: "POST",
1014
- body: JSON.stringify(input),
1015
- headers: { "Content-Type": "application/json" }
1016
- });
1288
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/proposals`, jsonInit("POST", input));
1017
1289
  }
1018
1290
  /**
1019
1291
  * Pending (proposed) and declined (rejected) revisions, newest first, with
@@ -1040,11 +1312,7 @@ var HubWorkflowsClient = class {
1040
1312
  * pending proposal.
1041
1313
  */
1042
1314
  async rejectProposal(id, rev, opts = {}) {
1043
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/proposals/${encodeURIComponent(String(rev))}/reject`, {
1044
- method: "POST",
1045
- body: JSON.stringify(opts.reason !== void 0 ? { reason: opts.reason } : {}),
1046
- headers: { "Content-Type": "application/json" }
1047
- });
1315
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/proposals/${encodeURIComponent(String(rev))}/reject`, jsonInit("POST", opts.reason !== void 0 ? { reason: opts.reason } : {}));
1048
1316
  }
1049
1317
  /**
1050
1318
  * Mint a fresh webhook hook token, retiring the current one immediately.
@@ -1124,11 +1392,7 @@ var HubWorkflowsClient = class {
1124
1392
  * value, stored and read back verbatim, so the client never gives it a shape.
1125
1393
  */
1126
1394
  async putKv(id, key, raw) {
1127
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}`, {
1128
- method: "PUT",
1129
- body: JSON.stringify({ value: raw }),
1130
- headers: { "Content-Type": "application/json" }
1131
- });
1395
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}`, jsonInit("PUT", { value: raw }));
1132
1396
  }
1133
1397
  /**
1134
1398
  * Compare-and-swap: the write lands only when the stored version still
@@ -1138,14 +1402,10 @@ var HubWorkflowsClient = class {
1138
1402
  * a shape.
1139
1403
  */
1140
1404
  async casKv(id, key, expectedVersion, raw) {
1141
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}/cas`, {
1142
- method: "POST",
1143
- body: JSON.stringify({
1144
- expectedVersion,
1145
- value: raw
1146
- }),
1147
- headers: { "Content-Type": "application/json" }
1148
- });
1405
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}/cas`, jsonInit("POST", {
1406
+ expectedVersion,
1407
+ value: raw
1408
+ }));
1149
1409
  }
1150
1410
  /** Delete a key; idempotent — `deleted` reports whether a row was removed. */
1151
1411
  async deleteKv(id, key) {
@@ -1165,11 +1425,7 @@ var HubWorkflowsClient = class {
1165
1425
  * (400); an unknown template id throws `NOT_FOUND`.
1166
1426
  */
1167
1427
  async instantiateTemplate(templateId, parameters) {
1168
- return this.request(`/v1/workflows/templates/${encodeURIComponent(templateId)}/instantiate`, {
1169
- method: "POST",
1170
- body: JSON.stringify(parameters ? { parameters } : {}),
1171
- headers: { "Content-Type": "application/json" }
1172
- });
1428
+ return this.request(`/v1/workflows/templates/${encodeURIComponent(templateId)}/instantiate`, jsonInit("POST", parameters ? { parameters } : {}));
1173
1429
  }
1174
1430
  /**
1175
1431
  * The caller's open decisions across all workflows — the always-available
@@ -1196,11 +1452,7 @@ var HubWorkflowsClient = class {
1196
1452
  * (409 — answered, timed out, or cancelled first).
1197
1453
  */
1198
1454
  async resolveRunDecision(id, runId, input) {
1199
- return this.request(`/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/decision/resolve`, {
1200
- method: "POST",
1201
- body: JSON.stringify(input),
1202
- headers: { "Content-Type": "application/json" }
1203
- });
1455
+ return this.request(`/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/decision/resolve`, jsonInit("POST", input));
1204
1456
  }
1205
1457
  /**
1206
1458
  * Dry-run a YAML definition against the platform compiler without saving it.
@@ -1213,17 +1465,93 @@ var HubWorkflowsClient = class {
1213
1465
  * the unconnected providers is the point.
1214
1466
  */
1215
1467
  async validate(yaml, opts = {}) {
1216
- return this.request("/v1/workflows/validate", {
1468
+ return this.request("/v1/workflows/validate", jsonInit("POST", {
1469
+ yaml,
1470
+ ...opts.structural ? { structural: true } : {}
1471
+ }));
1472
+ }
1473
+ async schema() {
1474
+ return this.request("/v1/workflows/schema", { method: "GET" });
1475
+ }
1476
+ };
1477
+ //#endregion
1478
+ //#region src/broker.ts
1479
+ /** Server-only client. App secrets never become a user's general API key.
1480
+ * Every invocation mints and consumes one short-lived, exact-grant token. */
1481
+ var HubAppBrokerClient = class {
1482
+ baseUrl;
1483
+ fetcher;
1484
+ constructor(options) {
1485
+ this.options = options;
1486
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
1487
+ this.fetcher = options.fetch ?? fetch.bind(globalThis);
1488
+ }
1489
+ async token(path, body) {
1490
+ const response = await this.fetcher(`${this.baseUrl}${path}`, {
1217
1491
  method: "POST",
1492
+ redirect: "error",
1493
+ headers: { "Content-Type": "application/json" },
1218
1494
  body: JSON.stringify({
1219
- yaml,
1220
- ...opts.structural ? { structural: true } : {}
1221
- }),
1222
- headers: { "Content-Type": "application/json" }
1495
+ ...body,
1496
+ client_id: this.options.clientId,
1497
+ client_secret: this.options.clientSecret
1498
+ })
1499
+ });
1500
+ const result = await response.json().catch(() => null);
1501
+ if (!response.ok || !result || typeof result !== "object" || Array.isArray(result)) throw new HubSdkError({
1502
+ code: "HUB_CONFIG_MISSING",
1503
+ message: "Application authorization is unavailable"
1504
+ }, { status: response.status });
1505
+ return result;
1506
+ }
1507
+ readToken(body) {
1508
+ if (typeof body.access_token !== "string" || !body.access_token.startsWith("sk-tan-broker-") || body.token_type !== "Bearer" || typeof body.expires_in !== "number" || !Number.isSafeInteger(body.expires_in) || body.expires_in <= 0 || typeof body.scope !== "string") throw new HubSdkError({
1509
+ code: "HUB_CONFIG_MISSING",
1510
+ message: "Invalid application authorization response"
1223
1511
  });
1512
+ return {
1513
+ accessToken: body.access_token,
1514
+ expiresIn: body.expires_in,
1515
+ scopes: body.scope.split(" ").filter(Boolean)
1516
+ };
1224
1517
  }
1225
- async schema() {
1226
- return this.request("/v1/workflows/schema", { method: "GET" });
1518
+ async exchange(input) {
1519
+ const body = await this.token("/v1/apps/oauth/token", {
1520
+ grant_type: "authorization_code",
1521
+ code: input.code,
1522
+ redirect_uri: input.redirectUri,
1523
+ connection_id: input.connectionId,
1524
+ ttl_seconds: 60
1525
+ });
1526
+ const token = this.readToken(body);
1527
+ if (typeof body.grant_id !== "string" || !body.grant_id || body.connection_id !== input.connectionId) throw new HubSdkError({
1528
+ code: "HUB_CONFIG_MISSING",
1529
+ message: "Application connection did not match consent"
1530
+ });
1531
+ return {
1532
+ ...token,
1533
+ grantId: body.grant_id,
1534
+ connectionId: input.connectionId
1535
+ };
1536
+ }
1537
+ async mint(grantId) {
1538
+ if (!/^[A-Za-z0-9_-]{1,256}$/.test(grantId)) throw new Error("Invalid application grant");
1539
+ return this.readToken(await this.token(`/v1/apps/grants/${encodeURIComponent(grantId)}/mint-broker-token`, {
1540
+ grant_id: grantId,
1541
+ ttl_seconds: 60
1542
+ }));
1543
+ }
1544
+ async invoke(grantId, connectionId, actionPath, input) {
1545
+ const token = await this.mint(grantId);
1546
+ if (!token.scopes.includes(actionPath)) throw new HubSdkError({
1547
+ code: "HUB_POLICY_DENIED",
1548
+ message: "This action was not granted to the application"
1549
+ });
1550
+ return new HubClient({
1551
+ baseUrl: this.baseUrl,
1552
+ apiKey: token.accessToken,
1553
+ fetch: this.fetcher
1554
+ }).tools.invoke(actionPath, input, { connectionId });
1227
1555
  }
1228
1556
  };
1229
1557
  //#endregion
@@ -1484,6 +1812,55 @@ function requestFailure(code, status, error, headers) {
1484
1812
  };
1485
1813
  }
1486
1814
  //#endregion
1487
- 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 };
1815
+ //#region src/line-grants.ts
1816
+ function path(binding, suffix = "") {
1817
+ if (!binding.workspaceId || !binding.workspaceAgentId) throw new Error("A workspace and agent are required for a line grant");
1818
+ return `/v1/hub/line-grants/current${suffix}?${new URLSearchParams({
1819
+ workspaceId: binding.workspaceId,
1820
+ workspaceAgentId: binding.workspaceAgentId
1821
+ })}`;
1822
+ }
1823
+ /** Every call uses HubTransport's authHeaders, so one-use app broker tokens can be minted per request. */
1824
+ var HubLineGrantsClient = class extends HubTransport {
1825
+ current(binding) {
1826
+ return this.request(path(binding), { method: "GET" });
1827
+ }
1828
+ async line(binding) {
1829
+ return (await this.request(path(binding, "/line"), { method: "GET" })).line;
1830
+ }
1831
+ async attach(binding, input) {
1832
+ return (await this.request(path(binding, "/attachment"), jsonInit("PUT", input))).attachment;
1833
+ }
1834
+ detach(binding) {
1835
+ return this.request(path(binding, "/attachment"), { method: "DELETE" });
1836
+ }
1837
+ async threads(binding) {
1838
+ return (await this.request(path(binding, "/threads"), { method: "GET" })).threads;
1839
+ }
1840
+ async messages(binding, threadId) {
1841
+ if (!threadId || threadId.length > 256) throw new Error("A bounded line thread id is required");
1842
+ return (await this.request(path(binding, `/threads/${encodeURIComponent(threadId)}/messages`), { method: "GET" })).messages;
1843
+ }
1844
+ memberApplication(binding) {
1845
+ return this.request(path(binding, "/member-application"), { method: "GET" });
1846
+ }
1847
+ /**
1848
+ * Route the owner's texts to this app's callback; the incumbent attachment
1849
+ * stays. `replaceSelectionId` moves them from another app on the owner's
1850
+ * explicit choice.
1851
+ */
1852
+ async selectApplication(binding, input) {
1853
+ return (await this.request(path(binding, "/member-application"), jsonInit("PUT", input))).selection;
1854
+ }
1855
+ /** Return the owner's texts to the incumbent attachment. */
1856
+ async clearApplication(binding, input) {
1857
+ await this.request(path(binding, "/member-application"), jsonInit("DELETE", input));
1858
+ }
1859
+ revoke(binding) {
1860
+ return this.request(path(binding), { method: "DELETE" });
1861
+ }
1862
+ };
1863
+ //#endregion
1864
+ export { HUB_API_KEY_ENV_VAR, HUB_CAPABILITY_TOKEN_ENV_VAR, HUB_URL_ENV_VAR, HubAllowancesClient, HubAppBrokerClient, HubApprovalsClient, HubAppsClient, HubAuditClient, HubChannelsClient, HubClient, HubConnectionsClient, HubEventDeliveryError, HubEventSubscriptionsClient, HubGithubAppClient, HubInboundWebhooksClient, HubKnowledgeClient, HubLineGrantsClient, HubLinesClient, HubManagedNumbersClient, HubPermissionsClient, HubSdkError, HubTokensClient, HubToolsClient, HubWorkflowsClient, authenticateHubEventRequest, deriveHubEventCallbackSecret, parseHubEventDelivery, redactHubValue, resolveHubAuth, resolveHubBaseUrl, verifyHubEventSignature };
1488
1865
 
1489
1866
  //# sourceMappingURL=index.js.map