@tangle-network/hub-sdk 0.30.0-develop.20260820014051.e2dc4fb → 0.30.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/README.md +191 -6
- package/dist/index.d.ts +1064 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +662 -204
- package/dist/index.js.map +1 -1
- package/package.json +8 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,343 @@
|
|
|
1
|
-
import { SSEChunkParser } from "@tangle-network/
|
|
1
|
+
import { SSEChunkParser } from "@tangle-network/agent-core/sse";
|
|
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
|
+
/** Current latched compliance state and the BAA acceptance behind it. */
|
|
100
|
+
async getCompliance(appId) {
|
|
101
|
+
return this.request(`/v1/apps/${encodedId(appId)}/compliance`, { method: "GET" });
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Latch HIPAA compliance for this app. The request MUST carry the exact
|
|
105
|
+
* `agreementVersion` the deployment currently offers — the acceptance is
|
|
106
|
+
* recorded before the claim exists, and the claim can never be cleared:
|
|
107
|
+
* `hipaa: false` on a latched app is a 409, on an unlatched app a no-op.
|
|
108
|
+
*/
|
|
109
|
+
async setCompliance(appId, input) {
|
|
110
|
+
return this.request(`/v1/apps/${encodedId(appId)}/compliance`, jsonInit("PUT", input));
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/inbound-webhooks.ts
|
|
115
|
+
var HubInboundWebhooksClient = class {
|
|
116
|
+
constructor(request) {
|
|
117
|
+
this.request = request;
|
|
118
|
+
}
|
|
119
|
+
async create(connectionId, options = {}) {
|
|
120
|
+
return this.request(this.path(connectionId), jsonInit("POST", options));
|
|
121
|
+
}
|
|
122
|
+
async get(connectionId) {
|
|
123
|
+
return this.request(this.path(connectionId), { method: "GET" });
|
|
124
|
+
}
|
|
125
|
+
/** Add one owned Linq WhatsApp number without rotating the webhook secret. */
|
|
126
|
+
async ensurePhoneNumber(connectionId, phoneNumberId) {
|
|
127
|
+
if (!phoneNumberId || phoneNumberId.length > 128 || !/^[\x21-\x7e]+$/.test(phoneNumberId)) throw new Error("A bounded phone-number id is required");
|
|
128
|
+
return this.request(`${this.path(connectionId)}/phone-numbers/ensure`, jsonInit("POST", { phoneNumberId }));
|
|
129
|
+
}
|
|
130
|
+
/** Remove event subscriptions first. This does not silently rotate a live URL. */
|
|
131
|
+
async delete(connectionId) {
|
|
132
|
+
return this.request(this.path(connectionId), { method: "DELETE" });
|
|
133
|
+
}
|
|
134
|
+
path(connectionId) {
|
|
135
|
+
if (!connectionId || connectionId.length > 256) throw new Error("A bounded connection id is required");
|
|
136
|
+
return `/v1/hub/connections/${encodeURIComponent(connectionId)}/inbound-webhook`;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region src/knowledge-management.ts
|
|
141
|
+
var HubKnowledgeManagementClient = class {
|
|
142
|
+
constructor(request) {
|
|
143
|
+
this.request = request;
|
|
144
|
+
}
|
|
145
|
+
materialize(input) {
|
|
146
|
+
return this.request("/v1/knowledge/attachments/materialize", jsonInit("POST", input));
|
|
147
|
+
}
|
|
148
|
+
authorization() {
|
|
149
|
+
return this.request("/v1/knowledge/authorization", { method: "GET" });
|
|
150
|
+
}
|
|
151
|
+
disconnectAuthorization() {
|
|
152
|
+
return this.request("/v1/knowledge/authorization", { method: "DELETE" });
|
|
153
|
+
}
|
|
154
|
+
capabilities() {
|
|
155
|
+
return this.request("/v1/knowledge/capabilities", { method: "GET" });
|
|
156
|
+
}
|
|
157
|
+
list() {
|
|
158
|
+
return this.request("/v1/knowledge/sources", { method: "GET" });
|
|
159
|
+
}
|
|
160
|
+
get(sourceId) {
|
|
161
|
+
return this.request(`/v1/knowledge/sources/${encodeURIComponent(sourceId)}`, { method: "GET" });
|
|
162
|
+
}
|
|
163
|
+
create(input) {
|
|
164
|
+
return this.request("/v1/knowledge/sources", jsonInit("POST", input));
|
|
165
|
+
}
|
|
166
|
+
refresh(sourceId, input) {
|
|
167
|
+
return this.request(`/v1/knowledge/sources/${encodeURIComponent(sourceId)}/refresh`, jsonInit("POST", input));
|
|
168
|
+
}
|
|
169
|
+
attach(sourceId, input) {
|
|
170
|
+
return this.request(`/v1/knowledge/sources/${encodeURIComponent(sourceId)}/attachments`, jsonInit("POST", input));
|
|
171
|
+
}
|
|
172
|
+
attachments(sandboxId) {
|
|
173
|
+
return this.request(`/v1/knowledge/attachments${sandboxId ? `?sandboxId=${encodeURIComponent(sandboxId)}` : ""}`, { method: "GET" });
|
|
174
|
+
}
|
|
175
|
+
detach(attachmentId) {
|
|
176
|
+
return this.request(`/v1/knowledge/attachments/${encodeURIComponent(attachmentId)}`, { method: "DELETE" });
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
//#endregion
|
|
180
|
+
//#region src/knowledge.ts
|
|
181
|
+
/** Runtime-only retrieval. The authenticated sandbox credential determines the
|
|
182
|
+
* scope on the server; neither a caller nor an agent can supply another scope. */
|
|
183
|
+
var HubKnowledgeClient = class {
|
|
184
|
+
management;
|
|
185
|
+
constructor(request) {
|
|
186
|
+
this.request = request;
|
|
187
|
+
this.management = new HubKnowledgeManagementClient(request);
|
|
188
|
+
}
|
|
189
|
+
bindings() {
|
|
190
|
+
return this.request("/v1/knowledge/runtime/bindings", { method: "GET" });
|
|
191
|
+
}
|
|
192
|
+
query(input, options) {
|
|
193
|
+
return this.request("/v1/knowledge/runtime/query", {
|
|
194
|
+
...jsonInit("POST", {
|
|
195
|
+
query: input.query,
|
|
196
|
+
...input.expectedReferences !== void 0 ? { expectedReferences: input.expectedReferences } : {},
|
|
197
|
+
...input.limit !== void 0 ? { limit: input.limit } : {}
|
|
198
|
+
}),
|
|
199
|
+
signal: options?.signal
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region src/lines.ts
|
|
205
|
+
/** The `on.schedule` mapping a Line schedule helper writes. */
|
|
206
|
+
function scheduleYaml(cron, timezone, until) {
|
|
207
|
+
return ` schedule: { ${[
|
|
208
|
+
`cron: ${JSON.stringify(cron)}`,
|
|
209
|
+
`timezone: ${JSON.stringify(timezone)}`,
|
|
210
|
+
...until ? [`until: ${JSON.stringify(until)}`] : []
|
|
211
|
+
].join(", ")} }`;
|
|
212
|
+
}
|
|
213
|
+
/** Line calls share HubClient authentication and envelope handling. */
|
|
214
|
+
var HubLinesClient = class {
|
|
215
|
+
members;
|
|
216
|
+
memberApplications;
|
|
217
|
+
checkins;
|
|
218
|
+
constructor(request, createWorkflow, requestApplicationDispatchCurrent) {
|
|
219
|
+
this.request = request;
|
|
220
|
+
this.createWorkflow = createWorkflow;
|
|
221
|
+
this.requestApplicationDispatchCurrent = requestApplicationDispatchCurrent;
|
|
222
|
+
this.members = { list: async (lineId) => (await this.request(`/v1/hub/lines/${encodeURIComponent(lineId)}/members`, { method: "GET" })).members };
|
|
223
|
+
const applicationPath = (lineId, memberId) => `/v1/hub/lines/${encodeURIComponent(lineId)}/members/${encodeURIComponent(memberId)}/application`;
|
|
224
|
+
this.memberApplications = {
|
|
225
|
+
get: async (lineId, memberId) => await this.request(applicationPath(lineId, memberId), { method: "GET" }),
|
|
226
|
+
select: async (lineId, memberId, input) => (await this.request(applicationPath(lineId, memberId), jsonInit("PUT", input))).selection,
|
|
227
|
+
clear: async (lineId, memberId, input) => {
|
|
228
|
+
await this.request(applicationPath(lineId, memberId), jsonInit("DELETE", input));
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
this.checkins = { schedule: (cron, options) => {
|
|
232
|
+
const name = options.name ?? `line-checkin-${crypto.randomUUID().slice(0, 8)}`;
|
|
233
|
+
const yaml = [
|
|
234
|
+
`name: ${JSON.stringify(name)}`,
|
|
235
|
+
"on:",
|
|
236
|
+
scheduleYaml(cron, options.timezone, options.until),
|
|
237
|
+
"do:",
|
|
238
|
+
" - agent.run:",
|
|
239
|
+
" line:",
|
|
240
|
+
` id: ${JSON.stringify(options.lineId)}`,
|
|
241
|
+
` member: ${JSON.stringify(options.member)}`,
|
|
242
|
+
` prompt: ${JSON.stringify(options.prompt)}`
|
|
243
|
+
].join("\n");
|
|
244
|
+
return this.createWorkflow(yaml);
|
|
245
|
+
} };
|
|
246
|
+
}
|
|
247
|
+
async scheduleSend(cron, options) {
|
|
248
|
+
const name = options.name ?? `line-send-${crypto.randomUUID().slice(0, 8)}`;
|
|
249
|
+
const yaml = [
|
|
250
|
+
`name: ${JSON.stringify(name)}`,
|
|
251
|
+
"on:",
|
|
252
|
+
scheduleYaml(cron, options.timezone, options.until),
|
|
253
|
+
"do:",
|
|
254
|
+
" - line.send:",
|
|
255
|
+
` lineId: ${JSON.stringify(options.lineId)}`,
|
|
256
|
+
` memberId: ${JSON.stringify(options.memberId)}`,
|
|
257
|
+
` text: ${JSON.stringify(options.text)}`,
|
|
258
|
+
...options.notBefore ? [` notBefore: ${JSON.stringify(options.notBefore)}`] : []
|
|
259
|
+
].join("\n");
|
|
260
|
+
return this.createWorkflow(yaml);
|
|
261
|
+
}
|
|
262
|
+
async context() {
|
|
263
|
+
return this.request("/v1/hub/lines/context", { method: "GET" });
|
|
264
|
+
}
|
|
265
|
+
async send(lineId, input) {
|
|
266
|
+
return this.request(`/v1/hub/lines/${encodeURIComponent(lineId)}/send`, jsonInit("POST", input));
|
|
267
|
+
}
|
|
268
|
+
/** Read an owner send's receipt, including its coded answer. Queued is not delivered. */
|
|
269
|
+
async sentMessage(lineId, messageId) {
|
|
270
|
+
return this.request(`/v1/hub/lines/${encodeURIComponent(lineId)}/outbox/${encodeURIComponent(messageId)}`, { method: "GET" });
|
|
271
|
+
}
|
|
272
|
+
async remind(lineId, input) {
|
|
273
|
+
return this.request(`/v1/hub/lines/${encodeURIComponent(lineId)}/remind`, jsonInit("POST", input));
|
|
274
|
+
}
|
|
275
|
+
async applicationDispatchCurrent(lineId, messageId, input, callbackBearer) {
|
|
276
|
+
if (!this.requestApplicationDispatchCurrent) throw new Error("Use HubClient to check application dispatch authority");
|
|
277
|
+
return (await this.requestApplicationDispatchCurrent(`/v1/hub/lines/${encodeURIComponent(lineId)}/messages/${encodeURIComponent(messageId)}/application-dispatch/current`, jsonInit("POST", input), callbackBearer)).current;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/managed-numbers.ts
|
|
282
|
+
/** Administrative number operations through Hub's authenticated transport.
|
|
283
|
+
* A mutation is one attempt; an uncertain create reuses its quote and reference. */
|
|
284
|
+
var HubManagedNumbersClient = class {
|
|
285
|
+
constructor(request) {
|
|
286
|
+
this.request = request;
|
|
287
|
+
}
|
|
288
|
+
readiness() {
|
|
289
|
+
return this.request("/v1/hub/numbers/readiness", { method: "GET" });
|
|
290
|
+
}
|
|
291
|
+
/** One page of orders. Scope by `clientReference` to ask about one binding,
|
|
292
|
+
* and follow `nextCursor` for the rest; a page is never ownership evidence. */
|
|
293
|
+
list(query = {}) {
|
|
294
|
+
const params = new URLSearchParams();
|
|
295
|
+
if (query.clientReference !== void 0) params.set("clientReference", query.clientReference);
|
|
296
|
+
if (query.cursor !== void 0) params.set("cursor", query.cursor);
|
|
297
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
298
|
+
const search = params.toString();
|
|
299
|
+
return this.request(`/v1/hub/numbers${search ? `?${search}` : ""}`, { method: "GET" });
|
|
300
|
+
}
|
|
301
|
+
get(id) {
|
|
302
|
+
return this.request(this.path(id), { method: "GET" });
|
|
303
|
+
}
|
|
304
|
+
quote(input) {
|
|
305
|
+
return this.request("/v1/hub/numbers/quote", this.post(input));
|
|
306
|
+
}
|
|
307
|
+
/** `clientReference` and `transport`, when given, must match the signed
|
|
308
|
+
* quote or Hub refuses the purchase with a conflict. */
|
|
309
|
+
create(input) {
|
|
310
|
+
return this.request("/v1/hub/numbers", this.post(input));
|
|
311
|
+
}
|
|
312
|
+
/** Fences references so no order can take them again. Call it as the last
|
|
313
|
+
* step before retiring the resource they name: a purchase that races the
|
|
314
|
+
* retirement is then refused (`409 number_reference_fenced`) instead of
|
|
315
|
+
* binding a line to a resource that is gone. Refused with
|
|
316
|
+
* `409 number_reference_held` while a live order holds one of them; cancel
|
|
317
|
+
* it first. A cancelled order no longer holds its reference, so the fence
|
|
318
|
+
* succeeds as soon as `cancel` returns, whether or not its release is still
|
|
319
|
+
* pending. Repeating a fence is harmless. */
|
|
320
|
+
fence(input) {
|
|
321
|
+
return this.request("/v1/hub/numbers/fences", this.post(input));
|
|
322
|
+
}
|
|
323
|
+
advance(id) {
|
|
324
|
+
return this.request(`${this.path(id)}/advance`, this.post({}));
|
|
325
|
+
}
|
|
326
|
+
cancel(id) {
|
|
327
|
+
return this.request(`${this.path(id)}/cancel`, this.post({}));
|
|
328
|
+
}
|
|
329
|
+
path(id) {
|
|
330
|
+
if (!/^num_[a-f0-9]{36}$/.test(id)) throw new Error("Invalid managed number order id");
|
|
331
|
+
return `/v1/hub/numbers/${encodeURIComponent(id)}`;
|
|
332
|
+
}
|
|
333
|
+
post(body) {
|
|
334
|
+
return jsonInit("POST", body);
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
//#endregion
|
|
2
338
|
//#region src/redaction.ts
|
|
3
339
|
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_
|
|
340
|
+
const SECRET_VALUE_PATTERN = /\b(?:sk-tan[-_]|hubcap_|hct_|lrc_|gh[pousr]_)[A-Za-z0-9_.=-]+\b/g;
|
|
5
341
|
function redactHubValue(value) {
|
|
6
342
|
if (typeof value === "string") return value.replace(SECRET_VALUE_PATTERN, "[REDACTED]");
|
|
7
343
|
if (Array.isArray(value)) return value.map((item) => redactHubValue(item));
|
|
@@ -26,16 +362,18 @@ function bodySnippet(body, max = 200) {
|
|
|
26
362
|
const trimmed = body.trim();
|
|
27
363
|
return trimmed.length > max ? `${trimmed.slice(0, max)}…` : trimmed;
|
|
28
364
|
}
|
|
29
|
-
function httpError(path, status, statusText, body, contentType) {
|
|
30
|
-
const suffix = statusText ? ` ${statusText}` : "";
|
|
365
|
+
function httpError(path, status, statusText, body, contentType, omitResponseDetails = false) {
|
|
366
|
+
const suffix = !omitResponseDetails && statusText ? ` ${statusText}` : "";
|
|
31
367
|
return new HubSdkError({
|
|
32
368
|
code: `HUB_HTTP_${status}`,
|
|
33
369
|
message: `Hub request ${path} failed: HTTP ${status}${suffix}`,
|
|
34
370
|
details: {
|
|
35
371
|
status,
|
|
36
372
|
path,
|
|
37
|
-
|
|
38
|
-
|
|
373
|
+
...omitResponseDetails ? {} : {
|
|
374
|
+
contentType: contentType || null,
|
|
375
|
+
bodySnippet: bodySnippet(body)
|
|
376
|
+
}
|
|
39
377
|
}
|
|
40
378
|
}, { status });
|
|
41
379
|
}
|
|
@@ -52,6 +390,9 @@ function isHubSuccessEnvelope(value) {
|
|
|
52
390
|
function isRecord$1(value) {
|
|
53
391
|
return typeof value === "object" && value !== null;
|
|
54
392
|
}
|
|
393
|
+
function isDispatchCurrentData(value) {
|
|
394
|
+
return isRecord$1(value) && typeof value.current === "boolean";
|
|
395
|
+
}
|
|
55
396
|
/** Read a wire field as a string, or "" when the server sent anything else.
|
|
56
397
|
* `raw` is that field straight off the parsed payload, before any check. */
|
|
57
398
|
function optString(raw) {
|
|
@@ -222,13 +563,69 @@ function nonEmpty(value) {
|
|
|
222
563
|
function readProcessEnv() {
|
|
223
564
|
return globalThis.process?.env ?? {};
|
|
224
565
|
}
|
|
225
|
-
var
|
|
566
|
+
var HubTransport = class {
|
|
226
567
|
baseUrl;
|
|
227
568
|
fetch;
|
|
228
569
|
apiKey;
|
|
229
570
|
authHeaders;
|
|
571
|
+
constructor(options) {
|
|
572
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
573
|
+
this.apiKey = options.apiKey;
|
|
574
|
+
this.authHeaders = options.authHeaders;
|
|
575
|
+
this.fetch = options.fetch ?? fetch.bind(globalThis);
|
|
576
|
+
}
|
|
577
|
+
async request(path, init, options = {}) {
|
|
578
|
+
const callerAuth = options.auth === "caller";
|
|
579
|
+
const response = await this.fetch(`${this.baseUrl}${path}`, {
|
|
580
|
+
...init,
|
|
581
|
+
headers: await this.buildHeaders(init.headers, callerAuth)
|
|
582
|
+
});
|
|
583
|
+
const status = response.status;
|
|
584
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
585
|
+
const bodyText = await response.text();
|
|
586
|
+
if (!contentType.includes("application/json")) throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
|
|
587
|
+
let parsed;
|
|
588
|
+
try {
|
|
589
|
+
parsed = JSON.parse(bodyText);
|
|
590
|
+
} catch {
|
|
591
|
+
throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
|
|
592
|
+
}
|
|
593
|
+
if (isHubErrorEnvelope(parsed)) {
|
|
594
|
+
if (callerAuth) throw new HubSdkError({
|
|
595
|
+
code: parsed.error.code,
|
|
596
|
+
message: `Hub request ${path} failed: HTTP ${status}`
|
|
597
|
+
}, { status });
|
|
598
|
+
throw new HubSdkError(parsed.error, { status });
|
|
599
|
+
}
|
|
600
|
+
if (isHubSuccessEnvelope(parsed)) {
|
|
601
|
+
if (callerAuth && !response.ok) throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
|
|
602
|
+
if (options.validateData && !options.validateData(parsed.data)) throw new HubSdkError({
|
|
603
|
+
code: `HUB_HTTP_${status}`,
|
|
604
|
+
message: `Hub request ${path} returned invalid data`,
|
|
605
|
+
details: {
|
|
606
|
+
status,
|
|
607
|
+
path
|
|
608
|
+
}
|
|
609
|
+
}, { status });
|
|
610
|
+
return parsed.data;
|
|
611
|
+
}
|
|
612
|
+
throw httpError(path, status, response.statusText, bodyText, contentType, callerAuth);
|
|
613
|
+
}
|
|
614
|
+
async buildHeaders(headers, callerAuth = false) {
|
|
615
|
+
const mergedHeaders = new Headers({ Accept: "application/json" });
|
|
616
|
+
if (!callerAuth && this.apiKey) mergedHeaders.set("Authorization", `Bearer ${this.apiKey}`);
|
|
617
|
+
if (!callerAuth && this.authHeaders) for (const [key, value] of new Headers(await this.authHeaders())) mergedHeaders.set(key, value);
|
|
618
|
+
for (const [key, value] of new Headers(headers)) mergedHeaders.set(key, value);
|
|
619
|
+
return mergedHeaders;
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
var HubClient = class HubClient extends HubTransport {
|
|
623
|
+
knowledge;
|
|
624
|
+
allowances;
|
|
625
|
+
apps;
|
|
230
626
|
connections;
|
|
231
627
|
channels;
|
|
628
|
+
numbers;
|
|
232
629
|
eventSubscriptions;
|
|
233
630
|
permissions;
|
|
234
631
|
tokens;
|
|
@@ -237,11 +634,13 @@ var HubClient = class HubClient {
|
|
|
237
634
|
audit;
|
|
238
635
|
githubApp;
|
|
239
636
|
workflows;
|
|
637
|
+
lines;
|
|
240
638
|
constructor(options) {
|
|
241
|
-
|
|
242
|
-
this.
|
|
243
|
-
this.
|
|
244
|
-
this.
|
|
639
|
+
super(options);
|
|
640
|
+
this.knowledge = new HubKnowledgeClient((path, init) => this.request(path, init));
|
|
641
|
+
this.allowances = new HubAllowancesClient((path, init) => this.request(path, init));
|
|
642
|
+
this.apps = new HubAppsClient((path, init) => this.request(path, init));
|
|
643
|
+
this.numbers = new HubManagedNumbersClient((path, init) => this.request(path, init));
|
|
245
644
|
this.connections = new HubConnectionsClient((path, init) => this.request(path, init));
|
|
246
645
|
this.channels = new HubChannelsClient((path, init) => this.request(path, init));
|
|
247
646
|
this.eventSubscriptions = new HubEventSubscriptionsClient((path, init) => this.request(path, init));
|
|
@@ -252,6 +651,23 @@ var HubClient = class HubClient {
|
|
|
252
651
|
this.audit = new HubAuditClient((path, init) => this.request(path, init));
|
|
253
652
|
this.githubApp = new HubGithubAppClient((path, init) => this.request(path, init));
|
|
254
653
|
this.workflows = new HubWorkflowsClient((path, init) => this.request(path, init), (path, init) => this.stream(path, init), (path, init) => this.requestBytes(path, init));
|
|
654
|
+
this.lines = new HubLinesClient((path, init) => this.request(path, init), (yaml) => this.workflows.create(yaml), (path, init, callbackBearer) => {
|
|
655
|
+
if (typeof callbackBearer !== "string" || !/^[\x21-\x7e]{16,512}$/.test(callbackBearer)) throw new HubSdkError({
|
|
656
|
+
code: "HUB_INVALID_INPUT",
|
|
657
|
+
message: "Application callback bearer is invalid"
|
|
658
|
+
});
|
|
659
|
+
const headers = new Headers(init.headers);
|
|
660
|
+
headers.set("Authorization", `Bearer ${callbackBearer}`);
|
|
661
|
+
return this.request(path, {
|
|
662
|
+
...init,
|
|
663
|
+
headers,
|
|
664
|
+
credentials: "omit",
|
|
665
|
+
redirect: "manual"
|
|
666
|
+
}, {
|
|
667
|
+
auth: "caller",
|
|
668
|
+
validateData: isDispatchCurrentData
|
|
669
|
+
});
|
|
670
|
+
});
|
|
255
671
|
}
|
|
256
672
|
static fromEnv(options = {}) {
|
|
257
673
|
const env = options.env ?? readProcessEnv();
|
|
@@ -265,25 +681,6 @@ var HubClient = class HubClient {
|
|
|
265
681
|
async status() {
|
|
266
682
|
return this.request("/v1/hub/status", { method: "GET" });
|
|
267
683
|
}
|
|
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
684
|
/**
|
|
288
685
|
* Open a streaming (Server-Sent Events) response and return its raw body.
|
|
289
686
|
* Shares auth-header building + `fetch` with {@link request}, but does NOT
|
|
@@ -350,25 +747,13 @@ var HubClient = class HubClient {
|
|
|
350
747
|
contentType
|
|
351
748
|
};
|
|
352
749
|
}
|
|
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
750
|
};
|
|
362
751
|
var HubTokensClient = class {
|
|
363
752
|
constructor(request) {
|
|
364
753
|
this.request = request;
|
|
365
754
|
}
|
|
366
755
|
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
|
-
});
|
|
756
|
+
return this.request("/v1/hub/tokens", jsonInit("POST", options));
|
|
372
757
|
}
|
|
373
758
|
async list(options = {}) {
|
|
374
759
|
const searchParams = new URLSearchParams();
|
|
@@ -402,38 +787,22 @@ var HubPermissionsClient = class {
|
|
|
402
787
|
return this.request(`/v1/hub/policies?connectionId=${encodeURIComponent(connectionId)}`, { method: "GET" });
|
|
403
788
|
}
|
|
404
789
|
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
|
-
});
|
|
790
|
+
return this.request("/v1/hub/policies", jsonInit("PUT", input));
|
|
410
791
|
}
|
|
411
792
|
/** Reset an action to its default by deleting any stored override. */
|
|
412
793
|
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
|
-
});
|
|
794
|
+
return this.request("/v1/hub/policies", jsonInit("DELETE", input));
|
|
418
795
|
}
|
|
419
796
|
/** Bulk-allow every write action of a connection's provider. Reads are
|
|
420
797
|
* already allowed for sandbox agents; destructive actions stay `ask`.
|
|
421
798
|
* Idempotent: actions with an existing policy are left untouched. */
|
|
422
799
|
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
|
-
});
|
|
800
|
+
return this.request("/v1/hub/policies/allow-writes", jsonInit("POST", { connectionId }));
|
|
428
801
|
}
|
|
429
802
|
/** Inverse of `allowWrites`: delete only the rows it created for this
|
|
430
803
|
* connection. Manual per-action decisions are left intact. */
|
|
431
804
|
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
|
-
});
|
|
805
|
+
return this.request("/v1/hub/policies/revert-writes", jsonInit("POST", { connectionId }));
|
|
437
806
|
}
|
|
438
807
|
};
|
|
439
808
|
var HubToolsClient = class {
|
|
@@ -441,25 +810,17 @@ var HubToolsClient = class {
|
|
|
441
810
|
this.request = request;
|
|
442
811
|
}
|
|
443
812
|
async search(query, options = {}) {
|
|
444
|
-
return this.request("/v1/hub/tools/search", {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
limit: options.limit
|
|
450
|
-
}),
|
|
451
|
-
headers: { "Content-Type": "application/json" }
|
|
452
|
-
});
|
|
813
|
+
return this.request("/v1/hub/tools/search", jsonInit("POST", {
|
|
814
|
+
query,
|
|
815
|
+
provider: options.provider,
|
|
816
|
+
limit: options.limit
|
|
817
|
+
}));
|
|
453
818
|
}
|
|
454
819
|
async sources() {
|
|
455
820
|
return this.request("/v1/hub/tools/sources", { method: "GET" });
|
|
456
821
|
}
|
|
457
822
|
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
|
-
});
|
|
823
|
+
return this.request("/v1/hub/tools/describe", jsonInit("POST", { path }));
|
|
463
824
|
}
|
|
464
825
|
/**
|
|
465
826
|
* Run one hub tool. `raw` is the tool input: the SDK forwards it verbatim as
|
|
@@ -472,8 +833,9 @@ var HubToolsClient = class {
|
|
|
472
833
|
return await this.request("/v1/hub/exec", execInit);
|
|
473
834
|
} catch (error) {
|
|
474
835
|
if (!(error instanceof HubSdkError) || !requiresCapabilityToken(error)) throw error;
|
|
836
|
+
const approvalId = getApprovalId(error);
|
|
837
|
+
if (approvalId && options.approve !== true) throw error;
|
|
475
838
|
if (options.approve) {
|
|
476
|
-
const approvalId = getApprovalId(error);
|
|
477
839
|
if (!approvalId) throw error;
|
|
478
840
|
const approved = await this.request(`/v1/hub/approvals/${encodeURIComponent(approvalId)}/approve`, { method: "POST" });
|
|
479
841
|
validateApprovedExecution(approved, path, options.connectionId);
|
|
@@ -491,15 +853,11 @@ var HubToolsClient = class {
|
|
|
491
853
|
});
|
|
492
854
|
}
|
|
493
855
|
}
|
|
494
|
-
const minted = await this.request("/v1/hub/tokens", {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
provider: options.connectionId ? void 0 : path.split(".")[0]
|
|
500
|
-
}),
|
|
501
|
-
headers: { "Content-Type": "application/json" }
|
|
502
|
-
});
|
|
856
|
+
const minted = await this.request("/v1/hub/tokens", jsonInit("POST", {
|
|
857
|
+
actionPath: path,
|
|
858
|
+
connectionId: options.connectionId,
|
|
859
|
+
provider: options.connectionId ? void 0 : path.split(".")[0]
|
|
860
|
+
}));
|
|
503
861
|
return this.request("/v1/hub/exec", {
|
|
504
862
|
...execInit,
|
|
505
863
|
headers: {
|
|
@@ -509,16 +867,12 @@ var HubToolsClient = class {
|
|
|
509
867
|
});
|
|
510
868
|
}
|
|
511
869
|
buildExecInit(path, raw, options) {
|
|
512
|
-
return {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
idempotencyKey: options.idempotencyKey
|
|
519
|
-
}),
|
|
520
|
-
headers: { "Content-Type": "application/json" }
|
|
521
|
-
};
|
|
870
|
+
return jsonInit("POST", {
|
|
871
|
+
path,
|
|
872
|
+
input: raw,
|
|
873
|
+
connectionId: options.connectionId,
|
|
874
|
+
idempotencyKey: options.idempotencyKey
|
|
875
|
+
});
|
|
522
876
|
}
|
|
523
877
|
};
|
|
524
878
|
function requiresCapabilityToken(error) {
|
|
@@ -548,6 +902,17 @@ function validateApprovedExecution(approved, path, connectionId) {
|
|
|
548
902
|
}
|
|
549
903
|
});
|
|
550
904
|
}
|
|
905
|
+
const GITHUB_EXACT_CONNECT_SCOPES = [
|
|
906
|
+
"read:user",
|
|
907
|
+
"repo",
|
|
908
|
+
"read:org"
|
|
909
|
+
];
|
|
910
|
+
function sameOAuthScopeSet(left, right) {
|
|
911
|
+
if (!Array.isArray(left)) return false;
|
|
912
|
+
const leftSet = new Set(left);
|
|
913
|
+
const rightSet = new Set(right);
|
|
914
|
+
return leftSet.size === left.length && rightSet.size === right.length && leftSet.size === rightSet.size && [...leftSet].every((scope) => rightSet.has(scope));
|
|
915
|
+
}
|
|
551
916
|
var HubChannelsClient = class {
|
|
552
917
|
constructor(request) {
|
|
553
918
|
this.request = request;
|
|
@@ -556,11 +921,7 @@ var HubChannelsClient = class {
|
|
|
556
921
|
return this.request("/v1/hub/channels", { method: "GET" });
|
|
557
922
|
}
|
|
558
923
|
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
|
-
});
|
|
924
|
+
return this.request("/v1/hub/channels/email", jsonInit("POST", input));
|
|
564
925
|
}
|
|
565
926
|
async delete(channelId) {
|
|
566
927
|
return this.request(`/v1/hub/channels/${encodeURIComponent(channelId)}`, { method: "DELETE" });
|
|
@@ -574,19 +935,17 @@ var HubEventSubscriptionsClient = class {
|
|
|
574
935
|
return this.request("/v1/hub/event-subscriptions", { method: "GET" });
|
|
575
936
|
}
|
|
576
937
|
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
|
-
});
|
|
938
|
+
return this.request("/v1/hub/event-subscriptions", jsonInit("POST", input));
|
|
582
939
|
}
|
|
583
940
|
async delete(subscriptionId) {
|
|
584
941
|
return this.request(`/v1/hub/event-subscriptions/${encodeURIComponent(subscriptionId)}`, { method: "DELETE" });
|
|
585
942
|
}
|
|
586
943
|
};
|
|
587
944
|
var HubConnectionsClient = class {
|
|
945
|
+
inboundWebhook;
|
|
588
946
|
constructor(request) {
|
|
589
947
|
this.request = request;
|
|
948
|
+
this.inboundWebhook = new HubInboundWebhooksClient(request);
|
|
590
949
|
}
|
|
591
950
|
async list() {
|
|
592
951
|
return this.request("/v1/hub/connections", { method: "GET" });
|
|
@@ -598,40 +957,38 @@ var HubConnectionsClient = class {
|
|
|
598
957
|
return this.request("/v1/hub/providers", { method: "GET" });
|
|
599
958
|
}
|
|
600
959
|
async start(provider, options = {}) {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
returnUrl: options.returnUrl,
|
|
605
|
-
cli: options.cli,
|
|
606
|
-
connectionParameters: options.connectionParameters
|
|
607
|
-
}),
|
|
608
|
-
headers: { "Content-Type": "application/json" }
|
|
960
|
+
if (options.requestedScopes !== void 0 && (provider !== "github" || !sameOAuthScopeSet(options.requestedScopes, GITHUB_EXACT_CONNECT_SCOPES))) throw new HubSdkError({
|
|
961
|
+
code: "HUB_INVALID_INPUT",
|
|
962
|
+
message: "GitHub requestedScopes must be read:user, repo, and read:org"
|
|
609
963
|
});
|
|
964
|
+
const started = await this.request(`/v1/hub/connections/${encodeURIComponent(provider)}/start`, jsonInit("POST", {
|
|
965
|
+
returnUrl: options.returnUrl,
|
|
966
|
+
cli: options.cli,
|
|
967
|
+
connectionParameters: options.connectionParameters,
|
|
968
|
+
requestedScopes: options.requestedScopes
|
|
969
|
+
}));
|
|
970
|
+
if (options.requestedScopes !== void 0 && (started.provider !== provider || !sameOAuthScopeSet(started.scopes, options.requestedScopes))) throw new HubSdkError({
|
|
971
|
+
code: "HUB_CONFIG_MISSING",
|
|
972
|
+
message: "Hub did not preserve the requested OAuth scopes"
|
|
973
|
+
});
|
|
974
|
+
return started;
|
|
610
975
|
}
|
|
611
976
|
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
|
-
});
|
|
977
|
+
return this.request("/v1/hub/connections/whatsapp-business/embedded-signup/start", jsonInit("POST", { returnUrl: options.returnUrl }));
|
|
617
978
|
}
|
|
618
979
|
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
|
-
});
|
|
980
|
+
return this.request("/v1/hub/connections/whatsapp-business/embedded-signup/complete", jsonInit("POST", input));
|
|
624
981
|
}
|
|
625
982
|
/** Connect a non-OAuth (api-key) connector by submitting the user's key.
|
|
626
983
|
* The server validates the key with a live probe before persisting and
|
|
627
984
|
* returns the created (or reconnected) connection — there is no redirect,
|
|
628
|
-
* unlike `start`.
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
});
|
|
985
|
+
* unlike `start`. Cloudbeds requires propertyId metadata and PriceLabs
|
|
986
|
+
* requires listing ID/PMS pairs; other providers have no metadata. */
|
|
987
|
+
async connectApiKey(provider, apiKey, metadata) {
|
|
988
|
+
return this.request(`/v1/hub/connections/${encodeURIComponent(provider)}/connect-key`, jsonInit("POST", {
|
|
989
|
+
apiKey,
|
|
990
|
+
...metadata === void 0 ? {} : { metadata }
|
|
991
|
+
}));
|
|
635
992
|
}
|
|
636
993
|
async revoke(connectionId) {
|
|
637
994
|
return this.request(`/v1/hub/connections/${encodeURIComponent(connectionId)}`, { method: "DELETE" });
|
|
@@ -659,11 +1016,7 @@ var HubGithubAppClient = class {
|
|
|
659
1016
|
this.request = request;
|
|
660
1017
|
}
|
|
661
1018
|
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
|
-
});
|
|
1019
|
+
return this.request("/v1/hub/github-app/mint-installation-token", jsonInit("POST", input));
|
|
667
1020
|
}
|
|
668
1021
|
/** Every installation the caller may act through — their own and any org's
|
|
669
1022
|
* they were verified against. The management surface's read. */
|
|
@@ -738,11 +1091,7 @@ var HubWorkflowsClient = class {
|
|
|
738
1091
|
return this.request(`/v1/workflows/${encodeURIComponent(id)}`, { method: "GET" });
|
|
739
1092
|
}
|
|
740
1093
|
async create(yaml) {
|
|
741
|
-
return this.request("/v1/workflows", {
|
|
742
|
-
method: "POST",
|
|
743
|
-
body: JSON.stringify({ yaml }),
|
|
744
|
-
headers: { "Content-Type": "application/json" }
|
|
745
|
-
});
|
|
1094
|
+
return this.request("/v1/workflows", jsonInit("POST", { yaml }));
|
|
746
1095
|
}
|
|
747
1096
|
/**
|
|
748
1097
|
* Replace the workflow's definition from YAML (recompiled server-side,
|
|
@@ -753,14 +1102,10 @@ var HubWorkflowsClient = class {
|
|
|
753
1102
|
* concurrent modification, `NOT_FOUND` for an unknown/foreign id.
|
|
754
1103
|
*/
|
|
755
1104
|
async update(id, yaml, opts = {}) {
|
|
756
|
-
return this.request(`/v1/workflows/${encodeURIComponent(id)}`, {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
...opts.note !== void 0 ? { note: opts.note } : {}
|
|
761
|
-
}),
|
|
762
|
-
headers: { "Content-Type": "application/json" }
|
|
763
|
-
});
|
|
1105
|
+
return this.request(`/v1/workflows/${encodeURIComponent(id)}`, jsonInit("PUT", {
|
|
1106
|
+
yaml,
|
|
1107
|
+
...opts.note !== void 0 ? { note: opts.note } : {}
|
|
1108
|
+
}));
|
|
764
1109
|
}
|
|
765
1110
|
async delete(id) {
|
|
766
1111
|
await this.request(`/v1/workflows/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
@@ -771,11 +1116,7 @@ var HubWorkflowsClient = class {
|
|
|
771
1116
|
* via `update`, but it can still be paused/resumed here).
|
|
772
1117
|
*/
|
|
773
1118
|
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
|
-
});
|
|
1119
|
+
return this.request(`/v1/workflows/${encodeURIComponent(id)}`, jsonInit("PATCH", { enabled }));
|
|
779
1120
|
}
|
|
780
1121
|
/**
|
|
781
1122
|
* One page of run history, newest first. Pass the previous page's
|
|
@@ -803,9 +1144,7 @@ var HubWorkflowsClient = class {
|
|
|
803
1144
|
async run(id, inputs, opts = {}) {
|
|
804
1145
|
const hasInputs = inputs !== void 0 && Object.keys(inputs).length > 0;
|
|
805
1146
|
return this.request(`/v1/workflows/${encodeURIComponent(id)}/run`, {
|
|
806
|
-
|
|
807
|
-
body: JSON.stringify(hasInputs ? { inputs } : {}),
|
|
808
|
-
headers: { "Content-Type": "application/json" },
|
|
1147
|
+
...jsonInit("POST", hasInputs ? { inputs } : {}),
|
|
809
1148
|
...opts.signal ? { signal: opts.signal } : {}
|
|
810
1149
|
});
|
|
811
1150
|
}
|
|
@@ -984,11 +1323,7 @@ var HubWorkflowsClient = class {
|
|
|
984
1323
|
* YAML no longer compiles, `CONFLICT` on a concurrent modification.
|
|
985
1324
|
*/
|
|
986
1325
|
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
|
-
});
|
|
1326
|
+
return this.request(`/v1/workflows/${encodeURIComponent(id)}/rollback`, jsonInit("POST", { rev }));
|
|
992
1327
|
}
|
|
993
1328
|
/**
|
|
994
1329
|
* Deterministic health stats over the workflow's last N terminal runs
|
|
@@ -1009,11 +1344,7 @@ var HubWorkflowsClient = class {
|
|
|
1009
1344
|
* until an owner approves.
|
|
1010
1345
|
*/
|
|
1011
1346
|
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
|
-
});
|
|
1347
|
+
return this.request(`/v1/workflows/${encodeURIComponent(id)}/proposals`, jsonInit("POST", input));
|
|
1017
1348
|
}
|
|
1018
1349
|
/**
|
|
1019
1350
|
* Pending (proposed) and declined (rejected) revisions, newest first, with
|
|
@@ -1040,11 +1371,7 @@ var HubWorkflowsClient = class {
|
|
|
1040
1371
|
* pending proposal.
|
|
1041
1372
|
*/
|
|
1042
1373
|
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
|
-
});
|
|
1374
|
+
return this.request(`/v1/workflows/${encodeURIComponent(id)}/proposals/${encodeURIComponent(String(rev))}/reject`, jsonInit("POST", opts.reason !== void 0 ? { reason: opts.reason } : {}));
|
|
1048
1375
|
}
|
|
1049
1376
|
/**
|
|
1050
1377
|
* Mint a fresh webhook hook token, retiring the current one immediately.
|
|
@@ -1124,11 +1451,7 @@ var HubWorkflowsClient = class {
|
|
|
1124
1451
|
* value, stored and read back verbatim, so the client never gives it a shape.
|
|
1125
1452
|
*/
|
|
1126
1453
|
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
|
-
});
|
|
1454
|
+
return this.request(`/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}`, jsonInit("PUT", { value: raw }));
|
|
1132
1455
|
}
|
|
1133
1456
|
/**
|
|
1134
1457
|
* Compare-and-swap: the write lands only when the stored version still
|
|
@@ -1138,14 +1461,10 @@ var HubWorkflowsClient = class {
|
|
|
1138
1461
|
* a shape.
|
|
1139
1462
|
*/
|
|
1140
1463
|
async casKv(id, key, expectedVersion, raw) {
|
|
1141
|
-
return this.request(`/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}/cas`, {
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
value: raw
|
|
1146
|
-
}),
|
|
1147
|
-
headers: { "Content-Type": "application/json" }
|
|
1148
|
-
});
|
|
1464
|
+
return this.request(`/v1/workflows/${encodeURIComponent(id)}/kv/${encodeURIComponent(key)}/cas`, jsonInit("POST", {
|
|
1465
|
+
expectedVersion,
|
|
1466
|
+
value: raw
|
|
1467
|
+
}));
|
|
1149
1468
|
}
|
|
1150
1469
|
/** Delete a key; idempotent — `deleted` reports whether a row was removed. */
|
|
1151
1470
|
async deleteKv(id, key) {
|
|
@@ -1165,11 +1484,7 @@ var HubWorkflowsClient = class {
|
|
|
1165
1484
|
* (400); an unknown template id throws `NOT_FOUND`.
|
|
1166
1485
|
*/
|
|
1167
1486
|
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
|
-
});
|
|
1487
|
+
return this.request(`/v1/workflows/templates/${encodeURIComponent(templateId)}/instantiate`, jsonInit("POST", parameters ? { parameters } : {}));
|
|
1173
1488
|
}
|
|
1174
1489
|
/**
|
|
1175
1490
|
* The caller's open decisions across all workflows — the always-available
|
|
@@ -1196,11 +1511,7 @@ var HubWorkflowsClient = class {
|
|
|
1196
1511
|
* (409 — answered, timed out, or cancelled first).
|
|
1197
1512
|
*/
|
|
1198
1513
|
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
|
-
});
|
|
1514
|
+
return this.request(`/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/decision/resolve`, jsonInit("POST", input));
|
|
1204
1515
|
}
|
|
1205
1516
|
/**
|
|
1206
1517
|
* Dry-run a YAML definition against the platform compiler without saving it.
|
|
@@ -1213,17 +1524,93 @@ var HubWorkflowsClient = class {
|
|
|
1213
1524
|
* the unconnected providers is the point.
|
|
1214
1525
|
*/
|
|
1215
1526
|
async validate(yaml, opts = {}) {
|
|
1216
|
-
return this.request("/v1/workflows/validate", {
|
|
1527
|
+
return this.request("/v1/workflows/validate", jsonInit("POST", {
|
|
1528
|
+
yaml,
|
|
1529
|
+
...opts.structural ? { structural: true } : {}
|
|
1530
|
+
}));
|
|
1531
|
+
}
|
|
1532
|
+
async schema() {
|
|
1533
|
+
return this.request("/v1/workflows/schema", { method: "GET" });
|
|
1534
|
+
}
|
|
1535
|
+
};
|
|
1536
|
+
//#endregion
|
|
1537
|
+
//#region src/broker.ts
|
|
1538
|
+
/** Server-only client. App secrets never become a user's general API key.
|
|
1539
|
+
* Every invocation mints and consumes one short-lived, exact-grant token. */
|
|
1540
|
+
var HubAppBrokerClient = class {
|
|
1541
|
+
baseUrl;
|
|
1542
|
+
fetcher;
|
|
1543
|
+
constructor(options) {
|
|
1544
|
+
this.options = options;
|
|
1545
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
1546
|
+
this.fetcher = options.fetch ?? fetch.bind(globalThis);
|
|
1547
|
+
}
|
|
1548
|
+
async token(path, body) {
|
|
1549
|
+
const response = await this.fetcher(`${this.baseUrl}${path}`, {
|
|
1217
1550
|
method: "POST",
|
|
1551
|
+
redirect: "error",
|
|
1552
|
+
headers: { "Content-Type": "application/json" },
|
|
1218
1553
|
body: JSON.stringify({
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1554
|
+
...body,
|
|
1555
|
+
client_id: this.options.clientId,
|
|
1556
|
+
client_secret: this.options.clientSecret
|
|
1557
|
+
})
|
|
1558
|
+
});
|
|
1559
|
+
const result = await response.json().catch(() => null);
|
|
1560
|
+
if (!response.ok || !result || typeof result !== "object" || Array.isArray(result)) throw new HubSdkError({
|
|
1561
|
+
code: "HUB_CONFIG_MISSING",
|
|
1562
|
+
message: "Application authorization is unavailable"
|
|
1563
|
+
}, { status: response.status });
|
|
1564
|
+
return result;
|
|
1565
|
+
}
|
|
1566
|
+
readToken(body) {
|
|
1567
|
+
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({
|
|
1568
|
+
code: "HUB_CONFIG_MISSING",
|
|
1569
|
+
message: "Invalid application authorization response"
|
|
1223
1570
|
});
|
|
1571
|
+
return {
|
|
1572
|
+
accessToken: body.access_token,
|
|
1573
|
+
expiresIn: body.expires_in,
|
|
1574
|
+
scopes: body.scope.split(" ").filter(Boolean)
|
|
1575
|
+
};
|
|
1224
1576
|
}
|
|
1225
|
-
async
|
|
1226
|
-
|
|
1577
|
+
async exchange(input) {
|
|
1578
|
+
const body = await this.token("/v1/apps/oauth/token", {
|
|
1579
|
+
grant_type: "authorization_code",
|
|
1580
|
+
code: input.code,
|
|
1581
|
+
redirect_uri: input.redirectUri,
|
|
1582
|
+
connection_id: input.connectionId,
|
|
1583
|
+
ttl_seconds: 60
|
|
1584
|
+
});
|
|
1585
|
+
const token = this.readToken(body);
|
|
1586
|
+
if (typeof body.grant_id !== "string" || !body.grant_id || body.connection_id !== input.connectionId) throw new HubSdkError({
|
|
1587
|
+
code: "HUB_CONFIG_MISSING",
|
|
1588
|
+
message: "Application connection did not match consent"
|
|
1589
|
+
});
|
|
1590
|
+
return {
|
|
1591
|
+
...token,
|
|
1592
|
+
grantId: body.grant_id,
|
|
1593
|
+
connectionId: input.connectionId
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
async mint(grantId) {
|
|
1597
|
+
if (!/^[A-Za-z0-9_-]{1,256}$/.test(grantId)) throw new Error("Invalid application grant");
|
|
1598
|
+
return this.readToken(await this.token(`/v1/apps/grants/${encodeURIComponent(grantId)}/mint-broker-token`, {
|
|
1599
|
+
grant_id: grantId,
|
|
1600
|
+
ttl_seconds: 60
|
|
1601
|
+
}));
|
|
1602
|
+
}
|
|
1603
|
+
async invoke(grantId, connectionId, actionPath, input) {
|
|
1604
|
+
const token = await this.mint(grantId);
|
|
1605
|
+
if (!token.scopes.includes(actionPath)) throw new HubSdkError({
|
|
1606
|
+
code: "HUB_POLICY_DENIED",
|
|
1607
|
+
message: "This action was not granted to the application"
|
|
1608
|
+
});
|
|
1609
|
+
return new HubClient({
|
|
1610
|
+
baseUrl: this.baseUrl,
|
|
1611
|
+
apiKey: token.accessToken,
|
|
1612
|
+
fetch: this.fetcher
|
|
1613
|
+
}).tools.invoke(actionPath, input, { connectionId });
|
|
1227
1614
|
}
|
|
1228
1615
|
};
|
|
1229
1616
|
//#endregion
|
|
@@ -1484,6 +1871,77 @@ function requestFailure(code, status, error, headers) {
|
|
|
1484
1871
|
};
|
|
1485
1872
|
}
|
|
1486
1873
|
//#endregion
|
|
1487
|
-
|
|
1874
|
+
//#region src/knowledge-approval.ts
|
|
1875
|
+
/** Called only after the owner reviews this exact pending effect and clicks
|
|
1876
|
+
* Approve. Re-read first: a stale tab cannot approve a substituted operation. */
|
|
1877
|
+
async function approveKnowledgeSource(input) {
|
|
1878
|
+
const { source, port, approvals } = input;
|
|
1879
|
+
if (source.status !== "awaiting-approval" || !source.approval || !source.refreshRequestId || source.approval.preview.sourceId !== source.id || source.approval.preview.requestId !== source.refreshRequestId) throw new Error("This source has no reviewable pending action. Reload knowledge.");
|
|
1880
|
+
const current = await port.get(source.id);
|
|
1881
|
+
if (current.id !== source.id || current.status !== "awaiting-approval" || current.refreshRequestId !== source.refreshRequestId || JSON.stringify(current.approval) !== JSON.stringify(source.approval)) throw new Error("The requested action changed. Reload knowledge and review it again.");
|
|
1882
|
+
let approvalToken;
|
|
1883
|
+
try {
|
|
1884
|
+
const decision = await approvals.approve(source.approval.id);
|
|
1885
|
+
if (decision.approval.id !== source.approval.id || decision.approval.actionPath !== source.approval.path || decision.approval.connectionId !== source.approval.preview.connectionId || decision.approval.providerId !== source.approval.preview.provider || decision.approval.status !== "consumed" || !decision.capabilityToken?.token) throw new Error("The approval did not return a matching one-time capability. Reload knowledge.");
|
|
1886
|
+
approvalToken = decision.capabilityToken.token;
|
|
1887
|
+
return await port.refresh(source.id, {
|
|
1888
|
+
requestId: source.refreshRequestId,
|
|
1889
|
+
approvalToken
|
|
1890
|
+
});
|
|
1891
|
+
} finally {
|
|
1892
|
+
approvalToken = void 0;
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
//#endregion
|
|
1896
|
+
//#region src/line-grants.ts
|
|
1897
|
+
function path(binding, suffix = "") {
|
|
1898
|
+
if (!binding.workspaceId || !binding.workspaceAgentId) throw new Error("A workspace and agent are required for a line grant");
|
|
1899
|
+
return `/v1/hub/line-grants/current${suffix}?${new URLSearchParams({
|
|
1900
|
+
workspaceId: binding.workspaceId,
|
|
1901
|
+
workspaceAgentId: binding.workspaceAgentId
|
|
1902
|
+
})}`;
|
|
1903
|
+
}
|
|
1904
|
+
/** Every call uses HubTransport's authHeaders, so one-use app broker tokens can be minted per request. */
|
|
1905
|
+
var HubLineGrantsClient = class extends HubTransport {
|
|
1906
|
+
current(binding) {
|
|
1907
|
+
return this.request(path(binding), { method: "GET" });
|
|
1908
|
+
}
|
|
1909
|
+
async line(binding) {
|
|
1910
|
+
return (await this.request(path(binding, "/line"), { method: "GET" })).line;
|
|
1911
|
+
}
|
|
1912
|
+
async attach(binding, input) {
|
|
1913
|
+
return (await this.request(path(binding, "/attachment"), jsonInit("PUT", input))).attachment;
|
|
1914
|
+
}
|
|
1915
|
+
detach(binding) {
|
|
1916
|
+
return this.request(path(binding, "/attachment"), { method: "DELETE" });
|
|
1917
|
+
}
|
|
1918
|
+
async threads(binding) {
|
|
1919
|
+
return (await this.request(path(binding, "/threads"), { method: "GET" })).threads;
|
|
1920
|
+
}
|
|
1921
|
+
async messages(binding, threadId) {
|
|
1922
|
+
if (!threadId || threadId.length > 256) throw new Error("A bounded line thread id is required");
|
|
1923
|
+
return (await this.request(path(binding, `/threads/${encodeURIComponent(threadId)}/messages`), { method: "GET" })).messages;
|
|
1924
|
+
}
|
|
1925
|
+
memberApplication(binding) {
|
|
1926
|
+
return this.request(path(binding, "/member-application"), { method: "GET" });
|
|
1927
|
+
}
|
|
1928
|
+
/**
|
|
1929
|
+
* Route the owner's texts to this app's callback; the incumbent attachment
|
|
1930
|
+
* stays. `replaceSelectionId` moves them from another app on the owner's
|
|
1931
|
+
* explicit choice.
|
|
1932
|
+
*/
|
|
1933
|
+
async selectApplication(binding, input) {
|
|
1934
|
+
return (await this.request(path(binding, "/member-application"), jsonInit("PUT", input))).selection;
|
|
1935
|
+
}
|
|
1936
|
+
/** Return the owner's texts to the incumbent attachment. */
|
|
1937
|
+
async clearApplication(binding, input) {
|
|
1938
|
+
await this.request(path(binding, "/member-application"), jsonInit("DELETE", input));
|
|
1939
|
+
}
|
|
1940
|
+
revoke(binding) {
|
|
1941
|
+
return this.request(path(binding), { method: "DELETE" });
|
|
1942
|
+
}
|
|
1943
|
+
};
|
|
1944
|
+
//#endregion
|
|
1945
|
+
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, HubKnowledgeManagementClient, HubLineGrantsClient, HubLinesClient, HubManagedNumbersClient, HubPermissionsClient, HubSdkError, HubTokensClient, HubToolsClient, HubWorkflowsClient, approveKnowledgeSource, authenticateHubEventRequest, deriveHubEventCallbackSecret, parseHubEventDelivery, redactHubValue, resolveHubAuth, resolveHubBaseUrl, verifyHubEventSignature };
|
|
1488
1946
|
|
|
1489
1947
|
//# sourceMappingURL=index.js.map
|