@tangle-network/hub-sdk 0.30.7 → 0.30.9
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.d.ts +985 -943
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +371 -361
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -111,32 +111,6 @@ var HubAppsClient = class {
|
|
|
111
111
|
}
|
|
112
112
|
};
|
|
113
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
114
|
//#region src/knowledge-management.ts
|
|
141
115
|
var HubKnowledgeManagementClient = class {
|
|
142
116
|
constructor(request) {
|
|
@@ -345,7 +319,7 @@ function redactHubValue(value) {
|
|
|
345
319
|
return value;
|
|
346
320
|
}
|
|
347
321
|
//#endregion
|
|
348
|
-
//#region src/
|
|
322
|
+
//#region src/transport.ts
|
|
349
323
|
var HubSdkError = class extends Error {
|
|
350
324
|
code;
|
|
351
325
|
details;
|
|
@@ -390,179 +364,6 @@ function isHubSuccessEnvelope(value) {
|
|
|
390
364
|
function isRecord$1(value) {
|
|
391
365
|
return typeof value === "object" && value !== null;
|
|
392
366
|
}
|
|
393
|
-
function isDispatchCurrentData(value) {
|
|
394
|
-
return isRecord$1(value) && typeof value.current === "boolean";
|
|
395
|
-
}
|
|
396
|
-
/** Read a wire field as a string, or "" when the server sent anything else.
|
|
397
|
-
* `raw` is that field straight off the parsed payload, before any check. */
|
|
398
|
-
function optString(raw) {
|
|
399
|
-
return typeof raw === "string" ? raw : "";
|
|
400
|
-
}
|
|
401
|
-
/** An agent iteration's terminal status (`iteration.ended`) — only ever
|
|
402
|
-
* succeeded/failed; an iteration is never guard-skipped. */
|
|
403
|
-
function isIterationStatus(value) {
|
|
404
|
-
return value === "succeeded" || value === "failed";
|
|
405
|
-
}
|
|
406
|
-
/** An action's terminal status on `action.finished`. Beyond succeeded/failed a
|
|
407
|
-
* guarded action can end `skipped` (its `if` resolved false, so it never ran) —
|
|
408
|
-
* accepted here so a skipped event is surfaced, not dropped as malformed. */
|
|
409
|
-
function isActionFinishedStatus(value) {
|
|
410
|
-
return value === "succeeded" || value === "failed" || value === "skipped";
|
|
411
|
-
}
|
|
412
|
-
/** Terminal status of a whole run's `run.done` event. A run can end `cancelled`
|
|
413
|
-
* (a user cancel) — a value neither the action nor iteration status checkers
|
|
414
|
-
* accept — so `run.done` uses this rather than them, which would drop a
|
|
415
|
-
* cancelled terminal event and hang the stream. */
|
|
416
|
-
function isRunDoneStatus(value) {
|
|
417
|
-
return value === "succeeded" || value === "failed" || value === "cancelled";
|
|
418
|
-
}
|
|
419
|
-
/**
|
|
420
|
-
* Map one raw SSE event (its `event:` name + parsed JSON `data:`) to a typed
|
|
421
|
-
* run-stream event, validating the fields each variant declares rather than
|
|
422
|
-
* blindly casting the wire payload. A frame that doesn't match its event's
|
|
423
|
-
* shape (or an unknown event name) returns null so the consumer skips it — a
|
|
424
|
-
* malformed `token` can never reach a consumer as `{ delta: undefined }`, and
|
|
425
|
-
* new server event kinds don't break older clients.
|
|
426
|
-
*/
|
|
427
|
-
function toRunStreamEvent(eventType, raw) {
|
|
428
|
-
if (eventType === "ping") return { type: "ping" };
|
|
429
|
-
if (!isRecord$1(raw)) return null;
|
|
430
|
-
switch (eventType) {
|
|
431
|
-
case "snapshot": return typeof raw.id === "string" && typeof raw.workflowId === "string" && typeof raw.status === "string" && Array.isArray(raw.actionResults) ? {
|
|
432
|
-
type: "snapshot",
|
|
433
|
-
run: raw
|
|
434
|
-
} : null;
|
|
435
|
-
case "token": return typeof raw.delta === "string" && typeof raw.actionIndex === "number" ? {
|
|
436
|
-
type: "token",
|
|
437
|
-
actionIndex: raw.actionIndex,
|
|
438
|
-
delta: raw.delta,
|
|
439
|
-
at: optString(raw.at)
|
|
440
|
-
} : null;
|
|
441
|
-
case "run.done": return isRunDoneStatus(raw.status) ? {
|
|
442
|
-
type: "run.done",
|
|
443
|
-
status: raw.status,
|
|
444
|
-
error: typeof raw.error === "string" ? raw.error : null,
|
|
445
|
-
...typeof raw.at === "string" ? { at: raw.at } : {}
|
|
446
|
-
} : null;
|
|
447
|
-
case "run.waiting": return typeof raw.decisionId === "string" && raw.decisionId.length > 0 ? {
|
|
448
|
-
type: "run.waiting",
|
|
449
|
-
decisionId: raw.decisionId,
|
|
450
|
-
...typeof raw.at === "string" ? { at: raw.at } : {}
|
|
451
|
-
} : null;
|
|
452
|
-
case "action.started": return typeof raw.index === "number" && typeof raw.kind === "string" && typeof raw.at === "string" ? {
|
|
453
|
-
type: "action.started",
|
|
454
|
-
index: raw.index,
|
|
455
|
-
kind: raw.kind,
|
|
456
|
-
at: raw.at
|
|
457
|
-
} : null;
|
|
458
|
-
case "action.finished": return typeof raw.index === "number" && typeof raw.kind === "string" && isActionFinishedStatus(raw.status) && typeof raw.at === "string" ? {
|
|
459
|
-
type: "action.finished",
|
|
460
|
-
index: raw.index,
|
|
461
|
-
kind: raw.kind,
|
|
462
|
-
status: raw.status,
|
|
463
|
-
at: raw.at,
|
|
464
|
-
...typeof raw.costUsd === "number" ? { costUsd: raw.costUsd } : {},
|
|
465
|
-
...typeof raw.error === "string" ? { error: raw.error } : {}
|
|
466
|
-
} : null;
|
|
467
|
-
case "iteration.started": return typeof raw.actionIndex === "number" && typeof raw.iterationIndex === "number" && typeof raw.at === "string" ? {
|
|
468
|
-
type: "iteration.started",
|
|
469
|
-
actionIndex: raw.actionIndex,
|
|
470
|
-
iterationIndex: raw.iterationIndex,
|
|
471
|
-
at: raw.at,
|
|
472
|
-
...typeof raw.model === "string" ? { model: raw.model } : {}
|
|
473
|
-
} : null;
|
|
474
|
-
case "iteration.ended": return typeof raw.actionIndex === "number" && typeof raw.iterationIndex === "number" && isIterationStatus(raw.status) && typeof raw.at === "string" ? {
|
|
475
|
-
type: "iteration.ended",
|
|
476
|
-
actionIndex: raw.actionIndex,
|
|
477
|
-
iterationIndex: raw.iterationIndex,
|
|
478
|
-
status: raw.status,
|
|
479
|
-
at: raw.at,
|
|
480
|
-
...typeof raw.outputPreview === "string" ? { outputPreview: raw.outputPreview } : {},
|
|
481
|
-
...typeof raw.inputTokens === "number" ? { inputTokens: raw.inputTokens } : {},
|
|
482
|
-
...typeof raw.outputTokens === "number" ? { outputTokens: raw.outputTokens } : {},
|
|
483
|
-
...typeof raw.costUsd === "number" ? { costUsd: raw.costUsd } : {}
|
|
484
|
-
} : null;
|
|
485
|
-
default: return null;
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
/** True for an aborted/timed-out fetch (or any abort). fetch rejects with the
|
|
489
|
-
* signal's reason — a DOMException named `AbortError` (caller) or `TimeoutError`
|
|
490
|
-
* (AbortSignal.timeout). */
|
|
491
|
-
function isAbortError(cause) {
|
|
492
|
-
return cause instanceof Error && (cause.name === "AbortError" || cause.name === "TimeoutError");
|
|
493
|
-
}
|
|
494
|
-
/** A signal that aborts when the caller's signal aborts OR `timeoutMs` elapses.
|
|
495
|
-
* Returns undefined when neither bound applies (no per-request abort needed). */
|
|
496
|
-
function combineAbortSignals(caller, timeoutMs) {
|
|
497
|
-
const signals = [];
|
|
498
|
-
if (caller) signals.push(caller);
|
|
499
|
-
if (timeoutMs !== null) signals.push(AbortSignal.timeout(timeoutMs));
|
|
500
|
-
if (signals.length === 0) return void 0;
|
|
501
|
-
return signals.length === 1 ? signals[0] : AbortSignal.any(signals);
|
|
502
|
-
}
|
|
503
|
-
/** Resolve after `ms`, or reject if `signal` aborts first. Clears its timer on
|
|
504
|
-
* abort so a cancelled wait leaves nothing pending. */
|
|
505
|
-
function delay(ms, signal) {
|
|
506
|
-
return new Promise((resolve, reject) => {
|
|
507
|
-
if (signal?.aborted) {
|
|
508
|
-
reject(signal.reason ?? /* @__PURE__ */ new Error("The operation was aborted"));
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
const onAbort = () => {
|
|
512
|
-
clearTimeout(timer);
|
|
513
|
-
reject(signal?.reason ?? /* @__PURE__ */ new Error("The operation was aborted"));
|
|
514
|
-
};
|
|
515
|
-
const timer = setTimeout(() => {
|
|
516
|
-
signal?.removeEventListener("abort", onAbort);
|
|
517
|
-
resolve();
|
|
518
|
-
}, ms);
|
|
519
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
const HUB_URL_ENV_VAR = "TANGLE_HUB_URL";
|
|
523
|
-
const HUB_API_KEY_ENV_VAR = "TANGLE_API_KEY";
|
|
524
|
-
const HUB_CAPABILITY_TOKEN_ENV_VAR = "TANGLE_HUB_CAPABILITY_TOKEN";
|
|
525
|
-
function resolveHubBaseUrl(env = readProcessEnv()) {
|
|
526
|
-
const raw = env[HUB_URL_ENV_VAR];
|
|
527
|
-
if (raw === void 0 || raw.trim() === "") throw new HubSdkError({
|
|
528
|
-
code: "HUB_CONFIG_MISSING",
|
|
529
|
-
message: `${HUB_URL_ENV_VAR} is required`,
|
|
530
|
-
details: { envVar: HUB_URL_ENV_VAR }
|
|
531
|
-
});
|
|
532
|
-
const trimmed = raw.trim();
|
|
533
|
-
try {
|
|
534
|
-
new URL(trimmed);
|
|
535
|
-
} catch {
|
|
536
|
-
throw new HubSdkError({
|
|
537
|
-
code: "HUB_CONFIG_INVALID",
|
|
538
|
-
message: `${HUB_URL_ENV_VAR} is not a valid URL`,
|
|
539
|
-
details: { envVar: HUB_URL_ENV_VAR }
|
|
540
|
-
});
|
|
541
|
-
}
|
|
542
|
-
return trimmed.replace(/\/+$/, "").replace(/\/v1\/hub$/, "");
|
|
543
|
-
}
|
|
544
|
-
function resolveHubAuth(env = readProcessEnv()) {
|
|
545
|
-
const present = [nonEmpty(env[HUB_API_KEY_ENV_VAR]), nonEmpty(env[HUB_CAPABILITY_TOKEN_ENV_VAR])].filter((value) => value !== void 0);
|
|
546
|
-
if (present.length === 0) throw new HubSdkError({
|
|
547
|
-
code: "HUB_CONFIG_MISSING",
|
|
548
|
-
message: `One of ${HUB_API_KEY_ENV_VAR} or ${HUB_CAPABILITY_TOKEN_ENV_VAR} is required`,
|
|
549
|
-
details: { envVars: [HUB_API_KEY_ENV_VAR, HUB_CAPABILITY_TOKEN_ENV_VAR] }
|
|
550
|
-
});
|
|
551
|
-
if (present.length > 1) throw new HubSdkError({
|
|
552
|
-
code: "HUB_CONFIG_INVALID",
|
|
553
|
-
message: `Set exactly one of ${HUB_API_KEY_ENV_VAR} or ${HUB_CAPABILITY_TOKEN_ENV_VAR}, not both`,
|
|
554
|
-
details: { envVars: [HUB_API_KEY_ENV_VAR, HUB_CAPABILITY_TOKEN_ENV_VAR] }
|
|
555
|
-
});
|
|
556
|
-
return present[0];
|
|
557
|
-
}
|
|
558
|
-
function nonEmpty(value) {
|
|
559
|
-
if (value === void 0) return void 0;
|
|
560
|
-
const trimmed = value.trim();
|
|
561
|
-
return trimmed.length === 0 ? void 0 : trimmed;
|
|
562
|
-
}
|
|
563
|
-
function readProcessEnv() {
|
|
564
|
-
return globalThis.process?.env ?? {};
|
|
565
|
-
}
|
|
566
367
|
var HubTransport = class {
|
|
567
368
|
baseUrl;
|
|
568
369
|
fetch;
|
|
@@ -623,135 +424,68 @@ var HubTransport = class {
|
|
|
623
424
|
return mergedHeaders;
|
|
624
425
|
}
|
|
625
426
|
};
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
tokens;
|
|
636
|
-
tools;
|
|
637
|
-
approvals;
|
|
638
|
-
audit;
|
|
639
|
-
githubApp;
|
|
640
|
-
workflows;
|
|
641
|
-
lines;
|
|
642
|
-
constructor(options) {
|
|
643
|
-
super(options);
|
|
644
|
-
this.knowledge = new HubKnowledgeClient((path, init) => this.request(path, init));
|
|
645
|
-
this.allowances = new HubAllowancesClient((path, init) => this.request(path, init));
|
|
646
|
-
this.apps = new HubAppsClient((path, init) => this.request(path, init));
|
|
647
|
-
this.numbers = new HubManagedNumbersClient((path, init) => this.request(path, init));
|
|
648
|
-
this.connections = new HubConnectionsClient((path, init) => this.request(path, init));
|
|
649
|
-
this.channels = new HubChannelsClient((path, init) => this.request(path, init));
|
|
650
|
-
this.eventSubscriptions = new HubEventSubscriptionsClient((path, init) => this.request(path, init));
|
|
651
|
-
this.permissions = new HubPermissionsClient((path, init) => this.request(path, init));
|
|
652
|
-
this.tokens = new HubTokensClient((path, init) => this.request(path, init));
|
|
653
|
-
this.tools = new HubToolsClient((path, init) => this.request(path, init));
|
|
654
|
-
this.approvals = new HubApprovalsClient((path, init) => this.request(path, init));
|
|
655
|
-
this.audit = new HubAuditClient((path, init) => this.request(path, init));
|
|
656
|
-
this.githubApp = new HubGithubAppClient((path, init) => this.request(path, init));
|
|
657
|
-
this.workflows = new HubWorkflowsClient((path, init) => this.request(path, init), (path, init) => this.stream(path, init), (path, init) => this.requestBytes(path, init));
|
|
658
|
-
this.lines = new HubLinesClient((path, init) => this.request(path, init), (yaml) => this.workflows.create(yaml), (path, init, callbackBearer) => {
|
|
659
|
-
if (typeof callbackBearer !== "string" || !/^[\x21-\x7e]{16,512}$/.test(callbackBearer)) throw new HubSdkError({
|
|
660
|
-
code: "HUB_INVALID_INPUT",
|
|
661
|
-
message: "Application callback bearer is invalid"
|
|
662
|
-
});
|
|
663
|
-
const headers = new Headers(init.headers);
|
|
664
|
-
headers.set("Authorization", `Bearer ${callbackBearer}`);
|
|
665
|
-
return this.request(path, {
|
|
666
|
-
...init,
|
|
667
|
-
headers,
|
|
668
|
-
credentials: "omit",
|
|
669
|
-
redirect: "manual"
|
|
670
|
-
}, {
|
|
671
|
-
auth: "caller",
|
|
672
|
-
validateData: isDispatchCurrentData
|
|
673
|
-
});
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
static fromEnv(options = {}) {
|
|
677
|
-
const env = options.env ?? readProcessEnv();
|
|
678
|
-
return new HubClient({
|
|
679
|
-
baseUrl: resolveHubBaseUrl(env),
|
|
680
|
-
apiKey: options.apiKey ?? (options.authHeaders ? void 0 : resolveHubAuth(env)),
|
|
681
|
-
authHeaders: options.authHeaders,
|
|
682
|
-
fetch: options.fetch
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
async status() {
|
|
686
|
-
return this.request("/v1/hub/status", { method: "GET" });
|
|
687
|
-
}
|
|
688
|
-
/**
|
|
689
|
-
* Open a streaming (Server-Sent Events) response and return its raw body.
|
|
690
|
-
* Shares auth-header building + `fetch` with {@link request}, but does NOT
|
|
691
|
-
* buffer or JSON-parse the body — the caller consumes the stream.
|
|
692
|
-
*
|
|
693
|
-
* A successful stream comes back as `text/event-stream`. Anything else is an
|
|
694
|
-
* error envelope (404/429/401 JSON) or a transport failure (gateway/HTML
|
|
695
|
-
* page); it is surfaced the same way {@link request} surfaces errors — a
|
|
696
|
-
* typed `HubSdkError` from a `{success:false}` envelope, otherwise an
|
|
697
|
-
* `HUB_HTTP_<status>` transport error — rather than handed back as bogus SSE.
|
|
698
|
-
*/
|
|
699
|
-
async stream(path, init) {
|
|
700
|
-
const response = await this.fetch(`${this.baseUrl}${path}`, {
|
|
701
|
-
...init,
|
|
702
|
-
headers: await this.buildHeaders(init.headers)
|
|
703
|
-
});
|
|
704
|
-
const status = response.status;
|
|
705
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
706
|
-
if (!response.ok || !contentType.includes("text/event-stream")) {
|
|
707
|
-
const bodyText = await response.text().catch(() => "");
|
|
708
|
-
if (contentType.includes("application/json")) {
|
|
709
|
-
let parsed;
|
|
710
|
-
try {
|
|
711
|
-
parsed = JSON.parse(bodyText);
|
|
712
|
-
} catch {
|
|
713
|
-
parsed = void 0;
|
|
714
|
-
}
|
|
715
|
-
if (isHubErrorEnvelope(parsed)) throw new HubSdkError(parsed.error, { status });
|
|
716
|
-
}
|
|
717
|
-
throw httpError(path, status, response.statusText, bodyText, contentType);
|
|
427
|
+
/** Decode a failed non-envelope response using the same redacted SDK errors. */
|
|
428
|
+
async function throwHubResponseError(path, response, status, contentType) {
|
|
429
|
+
const bodyText = await response.text().catch(() => "");
|
|
430
|
+
if (contentType.includes("application/json")) {
|
|
431
|
+
let parsed;
|
|
432
|
+
try {
|
|
433
|
+
parsed = JSON.parse(bodyText);
|
|
434
|
+
} catch {
|
|
435
|
+
parsed = void 0;
|
|
718
436
|
}
|
|
719
|
-
if (
|
|
720
|
-
return response.body;
|
|
437
|
+
if (isHubErrorEnvelope(parsed)) throw new HubSdkError(parsed.error, { status });
|
|
721
438
|
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
439
|
+
throw httpError(path, status, response.statusText, bodyText, contentType);
|
|
440
|
+
}
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/environment.ts
|
|
443
|
+
const HUB_URL_ENV_VAR = "TANGLE_HUB_URL";
|
|
444
|
+
const HUB_API_KEY_ENV_VAR = "TANGLE_API_KEY";
|
|
445
|
+
const HUB_CAPABILITY_TOKEN_ENV_VAR = "TANGLE_HUB_CAPABILITY_TOKEN";
|
|
446
|
+
function resolveHubBaseUrl(env = readProcessEnv()) {
|
|
447
|
+
const raw = env[HUB_URL_ENV_VAR];
|
|
448
|
+
if (raw === void 0 || raw.trim() === "") throw new HubSdkError({
|
|
449
|
+
code: "HUB_CONFIG_MISSING",
|
|
450
|
+
message: `${HUB_URL_ENV_VAR} is required`,
|
|
451
|
+
details: { envVar: HUB_URL_ENV_VAR }
|
|
452
|
+
});
|
|
453
|
+
const trimmed = raw.trim();
|
|
454
|
+
try {
|
|
455
|
+
new URL(trimmed);
|
|
456
|
+
} catch {
|
|
457
|
+
throw new HubSdkError({
|
|
458
|
+
code: "HUB_CONFIG_INVALID",
|
|
459
|
+
message: `${HUB_URL_ENV_VAR} is not a valid URL`,
|
|
460
|
+
details: { envVar: HUB_URL_ENV_VAR }
|
|
733
461
|
});
|
|
734
|
-
const status = response.status;
|
|
735
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
736
|
-
if (!response.ok) {
|
|
737
|
-
const bodyText = await response.text().catch(() => "");
|
|
738
|
-
if (contentType.includes("application/json")) {
|
|
739
|
-
let parsed;
|
|
740
|
-
try {
|
|
741
|
-
parsed = JSON.parse(bodyText);
|
|
742
|
-
} catch {
|
|
743
|
-
parsed = void 0;
|
|
744
|
-
}
|
|
745
|
-
if (isHubErrorEnvelope(parsed)) throw new HubSdkError(parsed.error, { status });
|
|
746
|
-
}
|
|
747
|
-
throw httpError(path, status, response.statusText, bodyText, contentType);
|
|
748
|
-
}
|
|
749
|
-
return {
|
|
750
|
-
bytes: new Uint8Array(await response.arrayBuffer()),
|
|
751
|
-
contentType
|
|
752
|
-
};
|
|
753
462
|
}
|
|
754
|
-
|
|
463
|
+
return trimmed.replace(/\/+$/, "").replace(/\/v1\/hub$/, "");
|
|
464
|
+
}
|
|
465
|
+
function resolveHubAuth(env = readProcessEnv()) {
|
|
466
|
+
const present = [nonEmpty(env[HUB_API_KEY_ENV_VAR]), nonEmpty(env[HUB_CAPABILITY_TOKEN_ENV_VAR])].filter((value) => value !== void 0);
|
|
467
|
+
if (present.length === 0) throw new HubSdkError({
|
|
468
|
+
code: "HUB_CONFIG_MISSING",
|
|
469
|
+
message: `One of ${HUB_API_KEY_ENV_VAR} or ${HUB_CAPABILITY_TOKEN_ENV_VAR} is required`,
|
|
470
|
+
details: { envVars: [HUB_API_KEY_ENV_VAR, HUB_CAPABILITY_TOKEN_ENV_VAR] }
|
|
471
|
+
});
|
|
472
|
+
if (present.length > 1) throw new HubSdkError({
|
|
473
|
+
code: "HUB_CONFIG_INVALID",
|
|
474
|
+
message: `Set exactly one of ${HUB_API_KEY_ENV_VAR} or ${HUB_CAPABILITY_TOKEN_ENV_VAR}, not both`,
|
|
475
|
+
details: { envVars: [HUB_API_KEY_ENV_VAR, HUB_CAPABILITY_TOKEN_ENV_VAR] }
|
|
476
|
+
});
|
|
477
|
+
return present[0];
|
|
478
|
+
}
|
|
479
|
+
function nonEmpty(value) {
|
|
480
|
+
if (value === void 0) return void 0;
|
|
481
|
+
const trimmed = value.trim();
|
|
482
|
+
return trimmed.length === 0 ? void 0 : trimmed;
|
|
483
|
+
}
|
|
484
|
+
function readProcessEnv() {
|
|
485
|
+
return globalThis.process?.env ?? {};
|
|
486
|
+
}
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region src/authorization.ts
|
|
755
489
|
var HubTokensClient = class {
|
|
756
490
|
constructor(request) {
|
|
757
491
|
this.request = request;
|
|
@@ -809,6 +543,22 @@ var HubPermissionsClient = class {
|
|
|
809
543
|
return this.request("/v1/hub/policies/revert-writes", jsonInit("POST", { connectionId }));
|
|
810
544
|
}
|
|
811
545
|
};
|
|
546
|
+
var HubApprovalsClient = class {
|
|
547
|
+
constructor(request) {
|
|
548
|
+
this.request = request;
|
|
549
|
+
}
|
|
550
|
+
async list() {
|
|
551
|
+
return this.request("/v1/hub/approvals", { method: "GET" });
|
|
552
|
+
}
|
|
553
|
+
async approve(approvalId) {
|
|
554
|
+
return this.request(`/v1/hub/approvals/${encodeURIComponent(approvalId)}/approve`, { method: "POST" });
|
|
555
|
+
}
|
|
556
|
+
async deny(approvalId) {
|
|
557
|
+
return this.request(`/v1/hub/approvals/${encodeURIComponent(approvalId)}/deny`, { method: "POST" });
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
//#endregion
|
|
561
|
+
//#region src/tools.ts
|
|
812
562
|
var HubToolsClient = class {
|
|
813
563
|
constructor(request) {
|
|
814
564
|
this.request = request;
|
|
@@ -906,6 +656,34 @@ function validateApprovedExecution(approved, path, connectionId) {
|
|
|
906
656
|
}
|
|
907
657
|
});
|
|
908
658
|
}
|
|
659
|
+
//#endregion
|
|
660
|
+
//#region src/inbound-webhooks.ts
|
|
661
|
+
var HubInboundWebhooksClient = class {
|
|
662
|
+
constructor(request) {
|
|
663
|
+
this.request = request;
|
|
664
|
+
}
|
|
665
|
+
async create(connectionId, options = {}) {
|
|
666
|
+
return this.request(this.path(connectionId), jsonInit("POST", options));
|
|
667
|
+
}
|
|
668
|
+
async get(connectionId) {
|
|
669
|
+
return this.request(this.path(connectionId), { method: "GET" });
|
|
670
|
+
}
|
|
671
|
+
/** Add one owned Linq WhatsApp number without rotating the webhook secret. */
|
|
672
|
+
async ensurePhoneNumber(connectionId, phoneNumberId) {
|
|
673
|
+
if (!phoneNumberId || phoneNumberId.length > 128 || !/^[\x21-\x7e]+$/.test(phoneNumberId)) throw new Error("A bounded phone-number id is required");
|
|
674
|
+
return this.request(`${this.path(connectionId)}/phone-numbers/ensure`, jsonInit("POST", { phoneNumberId }));
|
|
675
|
+
}
|
|
676
|
+
/** Remove event subscriptions first. This does not silently rotate a live URL. */
|
|
677
|
+
async delete(connectionId) {
|
|
678
|
+
return this.request(this.path(connectionId), { method: "DELETE" });
|
|
679
|
+
}
|
|
680
|
+
path(connectionId) {
|
|
681
|
+
if (!connectionId || connectionId.length > 256) throw new Error("A bounded connection id is required");
|
|
682
|
+
return `/v1/hub/connections/${encodeURIComponent(connectionId)}/inbound-webhook`;
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
//#endregion
|
|
686
|
+
//#region src/connections.ts
|
|
909
687
|
const GITHUB_EXACT_CONNECT_SCOPES = [
|
|
910
688
|
"read:user",
|
|
911
689
|
"repo",
|
|
@@ -917,34 +695,6 @@ function sameOAuthScopeSet(left, right) {
|
|
|
917
695
|
const rightSet = new Set(right);
|
|
918
696
|
return leftSet.size === left.length && rightSet.size === right.length && leftSet.size === rightSet.size && [...leftSet].every((scope) => rightSet.has(scope));
|
|
919
697
|
}
|
|
920
|
-
var HubChannelsClient = class {
|
|
921
|
-
constructor(request) {
|
|
922
|
-
this.request = request;
|
|
923
|
-
}
|
|
924
|
-
async list() {
|
|
925
|
-
return this.request("/v1/hub/channels", { method: "GET" });
|
|
926
|
-
}
|
|
927
|
-
async createEmail(input = {}) {
|
|
928
|
-
return this.request("/v1/hub/channels/email", jsonInit("POST", input));
|
|
929
|
-
}
|
|
930
|
-
async delete(channelId) {
|
|
931
|
-
return this.request(`/v1/hub/channels/${encodeURIComponent(channelId)}`, { method: "DELETE" });
|
|
932
|
-
}
|
|
933
|
-
};
|
|
934
|
-
var HubEventSubscriptionsClient = class {
|
|
935
|
-
constructor(request) {
|
|
936
|
-
this.request = request;
|
|
937
|
-
}
|
|
938
|
-
async list() {
|
|
939
|
-
return this.request("/v1/hub/event-subscriptions", { method: "GET" });
|
|
940
|
-
}
|
|
941
|
-
async create(input) {
|
|
942
|
-
return this.request("/v1/hub/event-subscriptions", jsonInit("POST", input));
|
|
943
|
-
}
|
|
944
|
-
async delete(subscriptionId) {
|
|
945
|
-
return this.request(`/v1/hub/event-subscriptions/${encodeURIComponent(subscriptionId)}`, { method: "DELETE" });
|
|
946
|
-
}
|
|
947
|
-
};
|
|
948
698
|
var HubConnectionsClient = class {
|
|
949
699
|
inboundWebhook;
|
|
950
700
|
constructor(request) {
|
|
@@ -997,24 +747,42 @@ var HubConnectionsClient = class {
|
|
|
997
747
|
async revoke(connectionId) {
|
|
998
748
|
return this.request(`/v1/hub/connections/${encodeURIComponent(connectionId)}`, { method: "DELETE" });
|
|
999
749
|
}
|
|
1000
|
-
async health(connectionId) {
|
|
1001
|
-
return this.request(`/v1/hub/connections/${encodeURIComponent(connectionId)}/health`, { method: "POST" });
|
|
750
|
+
async health(connectionId) {
|
|
751
|
+
return this.request(`/v1/hub/connections/${encodeURIComponent(connectionId)}/health`, { method: "POST" });
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
//#endregion
|
|
755
|
+
//#region src/channels.ts
|
|
756
|
+
var HubChannelsClient = class {
|
|
757
|
+
constructor(request) {
|
|
758
|
+
this.request = request;
|
|
759
|
+
}
|
|
760
|
+
async list() {
|
|
761
|
+
return this.request("/v1/hub/channels", { method: "GET" });
|
|
762
|
+
}
|
|
763
|
+
async createEmail(input = {}) {
|
|
764
|
+
return this.request("/v1/hub/channels/email", jsonInit("POST", input));
|
|
765
|
+
}
|
|
766
|
+
async delete(channelId) {
|
|
767
|
+
return this.request(`/v1/hub/channels/${encodeURIComponent(channelId)}`, { method: "DELETE" });
|
|
1002
768
|
}
|
|
1003
769
|
};
|
|
1004
|
-
var
|
|
770
|
+
var HubEventSubscriptionsClient = class {
|
|
1005
771
|
constructor(request) {
|
|
1006
772
|
this.request = request;
|
|
1007
773
|
}
|
|
1008
774
|
async list() {
|
|
1009
|
-
return this.request("/v1/hub/
|
|
775
|
+
return this.request("/v1/hub/event-subscriptions", { method: "GET" });
|
|
1010
776
|
}
|
|
1011
|
-
async
|
|
1012
|
-
return this.request(
|
|
777
|
+
async create(input) {
|
|
778
|
+
return this.request("/v1/hub/event-subscriptions", jsonInit("POST", input));
|
|
1013
779
|
}
|
|
1014
|
-
async
|
|
1015
|
-
return this.request(`/v1/hub/
|
|
780
|
+
async delete(subscriptionId) {
|
|
781
|
+
return this.request(`/v1/hub/event-subscriptions/${encodeURIComponent(subscriptionId)}`, { method: "DELETE" });
|
|
1016
782
|
}
|
|
1017
783
|
};
|
|
784
|
+
//#endregion
|
|
785
|
+
//#region src/github-app.ts
|
|
1018
786
|
var HubGithubAppClient = class {
|
|
1019
787
|
constructor(request) {
|
|
1020
788
|
this.request = request;
|
|
@@ -1055,6 +823,8 @@ var HubGithubAppClient = class {
|
|
|
1055
823
|
return this.request(`/v1/hub/github-app/is-repo-installed?${params.toString()}`, { method: "GET" });
|
|
1056
824
|
}
|
|
1057
825
|
};
|
|
826
|
+
//#endregion
|
|
827
|
+
//#region src/audit.ts
|
|
1058
828
|
var HubAuditClient = class {
|
|
1059
829
|
constructor(request) {
|
|
1060
830
|
this.request = request;
|
|
@@ -1072,6 +842,136 @@ var HubAuditClient = class {
|
|
|
1072
842
|
return this.request(`/v1/hub/audit${query ? `?${query}` : ""}`, { method: "GET" });
|
|
1073
843
|
}
|
|
1074
844
|
};
|
|
845
|
+
//#endregion
|
|
846
|
+
//#region src/workflow-run-events.ts
|
|
847
|
+
/** Read a wire field as a string, or "" when the server sent anything else.
|
|
848
|
+
* `raw` is that field straight off the parsed payload, before any check. */
|
|
849
|
+
function optString(raw) {
|
|
850
|
+
return typeof raw === "string" ? raw : "";
|
|
851
|
+
}
|
|
852
|
+
/** An agent iteration's terminal status (`iteration.ended`) — only ever
|
|
853
|
+
* succeeded/failed; an iteration is never guard-skipped. */
|
|
854
|
+
function isIterationStatus(value) {
|
|
855
|
+
return value === "succeeded" || value === "failed";
|
|
856
|
+
}
|
|
857
|
+
/** An action's terminal status on `action.finished`. Beyond succeeded/failed a
|
|
858
|
+
* guarded action can end `skipped` (its `if` resolved false, so it never ran) —
|
|
859
|
+
* accepted here so a skipped event is surfaced, not dropped as malformed. */
|
|
860
|
+
function isActionFinishedStatus(value) {
|
|
861
|
+
return value === "succeeded" || value === "failed" || value === "skipped";
|
|
862
|
+
}
|
|
863
|
+
/** Terminal status of a whole run's `run.done` event. A run can end `cancelled`
|
|
864
|
+
* (a user cancel) — a value neither the action nor iteration status checkers
|
|
865
|
+
* accept — so `run.done` uses this rather than them, which would drop a
|
|
866
|
+
* cancelled terminal event and hang the stream. */
|
|
867
|
+
function isRunDoneStatus(value) {
|
|
868
|
+
return value === "succeeded" || value === "failed" || value === "cancelled";
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Map one raw SSE event (its `event:` name + parsed JSON `data:`) to a typed
|
|
872
|
+
* run-stream event, validating the fields each variant declares rather than
|
|
873
|
+
* blindly casting the wire payload. A frame that doesn't match its event's
|
|
874
|
+
* shape (or an unknown event name) returns null so the consumer skips it — a
|
|
875
|
+
* malformed `token` can never reach a consumer as `{ delta: undefined }`, and
|
|
876
|
+
* new server event kinds don't break older clients.
|
|
877
|
+
*/
|
|
878
|
+
function toRunStreamEvent(eventType, raw) {
|
|
879
|
+
if (eventType === "ping") return { type: "ping" };
|
|
880
|
+
if (!isRecord$1(raw)) return null;
|
|
881
|
+
switch (eventType) {
|
|
882
|
+
case "snapshot": return typeof raw.id === "string" && typeof raw.workflowId === "string" && typeof raw.status === "string" && Array.isArray(raw.actionResults) ? {
|
|
883
|
+
type: "snapshot",
|
|
884
|
+
run: raw
|
|
885
|
+
} : null;
|
|
886
|
+
case "token": return typeof raw.delta === "string" && typeof raw.actionIndex === "number" ? {
|
|
887
|
+
type: "token",
|
|
888
|
+
actionIndex: raw.actionIndex,
|
|
889
|
+
delta: raw.delta,
|
|
890
|
+
at: optString(raw.at)
|
|
891
|
+
} : null;
|
|
892
|
+
case "run.done": return isRunDoneStatus(raw.status) ? {
|
|
893
|
+
type: "run.done",
|
|
894
|
+
status: raw.status,
|
|
895
|
+
error: typeof raw.error === "string" ? raw.error : null,
|
|
896
|
+
...typeof raw.at === "string" ? { at: raw.at } : {}
|
|
897
|
+
} : null;
|
|
898
|
+
case "run.waiting": return typeof raw.decisionId === "string" && raw.decisionId.length > 0 ? {
|
|
899
|
+
type: "run.waiting",
|
|
900
|
+
decisionId: raw.decisionId,
|
|
901
|
+
...typeof raw.at === "string" ? { at: raw.at } : {}
|
|
902
|
+
} : null;
|
|
903
|
+
case "action.started": return typeof raw.index === "number" && typeof raw.kind === "string" && typeof raw.at === "string" ? {
|
|
904
|
+
type: "action.started",
|
|
905
|
+
index: raw.index,
|
|
906
|
+
kind: raw.kind,
|
|
907
|
+
at: raw.at
|
|
908
|
+
} : null;
|
|
909
|
+
case "action.finished": return typeof raw.index === "number" && typeof raw.kind === "string" && isActionFinishedStatus(raw.status) && typeof raw.at === "string" ? {
|
|
910
|
+
type: "action.finished",
|
|
911
|
+
index: raw.index,
|
|
912
|
+
kind: raw.kind,
|
|
913
|
+
status: raw.status,
|
|
914
|
+
at: raw.at,
|
|
915
|
+
...typeof raw.costUsd === "number" ? { costUsd: raw.costUsd } : {},
|
|
916
|
+
...typeof raw.error === "string" ? { error: raw.error } : {}
|
|
917
|
+
} : null;
|
|
918
|
+
case "iteration.started": return typeof raw.actionIndex === "number" && typeof raw.iterationIndex === "number" && typeof raw.at === "string" ? {
|
|
919
|
+
type: "iteration.started",
|
|
920
|
+
actionIndex: raw.actionIndex,
|
|
921
|
+
iterationIndex: raw.iterationIndex,
|
|
922
|
+
at: raw.at,
|
|
923
|
+
...typeof raw.model === "string" ? { model: raw.model } : {}
|
|
924
|
+
} : null;
|
|
925
|
+
case "iteration.ended": return typeof raw.actionIndex === "number" && typeof raw.iterationIndex === "number" && isIterationStatus(raw.status) && typeof raw.at === "string" ? {
|
|
926
|
+
type: "iteration.ended",
|
|
927
|
+
actionIndex: raw.actionIndex,
|
|
928
|
+
iterationIndex: raw.iterationIndex,
|
|
929
|
+
status: raw.status,
|
|
930
|
+
at: raw.at,
|
|
931
|
+
...typeof raw.outputPreview === "string" ? { outputPreview: raw.outputPreview } : {},
|
|
932
|
+
...typeof raw.inputTokens === "number" ? { inputTokens: raw.inputTokens } : {},
|
|
933
|
+
...typeof raw.outputTokens === "number" ? { outputTokens: raw.outputTokens } : {},
|
|
934
|
+
...typeof raw.costUsd === "number" ? { costUsd: raw.costUsd } : {}
|
|
935
|
+
} : null;
|
|
936
|
+
default: return null;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
//#endregion
|
|
940
|
+
//#region src/workflows.ts
|
|
941
|
+
/** True for an aborted/timed-out fetch (or any abort). fetch rejects with the
|
|
942
|
+
* signal's reason — a DOMException named `AbortError` (caller) or `TimeoutError`
|
|
943
|
+
* (AbortSignal.timeout). */
|
|
944
|
+
function isAbortError(cause) {
|
|
945
|
+
return cause instanceof Error && (cause.name === "AbortError" || cause.name === "TimeoutError");
|
|
946
|
+
}
|
|
947
|
+
/** A signal that aborts when the caller's signal aborts OR `timeoutMs` elapses.
|
|
948
|
+
* Returns undefined when neither bound applies (no per-request abort needed). */
|
|
949
|
+
function combineAbortSignals(caller, timeoutMs) {
|
|
950
|
+
const signals = [];
|
|
951
|
+
if (caller) signals.push(caller);
|
|
952
|
+
if (timeoutMs !== null) signals.push(AbortSignal.timeout(timeoutMs));
|
|
953
|
+
if (signals.length === 0) return void 0;
|
|
954
|
+
return signals.length === 1 ? signals[0] : AbortSignal.any(signals);
|
|
955
|
+
}
|
|
956
|
+
/** Resolve after `ms`, or reject if `signal` aborts first. Clears its timer on
|
|
957
|
+
* abort so a cancelled wait leaves nothing pending. */
|
|
958
|
+
function delay(ms, signal) {
|
|
959
|
+
return new Promise((resolve, reject) => {
|
|
960
|
+
if (signal?.aborted) {
|
|
961
|
+
reject(signal.reason ?? /* @__PURE__ */ new Error("The operation was aborted"));
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
const onAbort = () => {
|
|
965
|
+
clearTimeout(timer);
|
|
966
|
+
reject(signal?.reason ?? /* @__PURE__ */ new Error("The operation was aborted"));
|
|
967
|
+
};
|
|
968
|
+
const timer = setTimeout(() => {
|
|
969
|
+
signal?.removeEventListener("abort", onAbort);
|
|
970
|
+
resolve();
|
|
971
|
+
}, ms);
|
|
972
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
973
|
+
});
|
|
974
|
+
}
|
|
1075
975
|
var HubWorkflowsClient = class {
|
|
1076
976
|
constructor(request, stream, download) {
|
|
1077
977
|
this.request = request;
|
|
@@ -1539,6 +1439,116 @@ var HubWorkflowsClient = class {
|
|
|
1539
1439
|
}
|
|
1540
1440
|
};
|
|
1541
1441
|
//#endregion
|
|
1442
|
+
//#region src/client.ts
|
|
1443
|
+
function isDispatchCurrentData(value) {
|
|
1444
|
+
return isRecord$1(value) && typeof value.current === "boolean";
|
|
1445
|
+
}
|
|
1446
|
+
var HubClient = class HubClient extends HubTransport {
|
|
1447
|
+
knowledge;
|
|
1448
|
+
allowances;
|
|
1449
|
+
apps;
|
|
1450
|
+
connections;
|
|
1451
|
+
channels;
|
|
1452
|
+
numbers;
|
|
1453
|
+
eventSubscriptions;
|
|
1454
|
+
permissions;
|
|
1455
|
+
tokens;
|
|
1456
|
+
tools;
|
|
1457
|
+
approvals;
|
|
1458
|
+
audit;
|
|
1459
|
+
githubApp;
|
|
1460
|
+
workflows;
|
|
1461
|
+
lines;
|
|
1462
|
+
constructor(options) {
|
|
1463
|
+
super(options);
|
|
1464
|
+
this.knowledge = new HubKnowledgeClient((path, init) => this.request(path, init));
|
|
1465
|
+
this.allowances = new HubAllowancesClient((path, init) => this.request(path, init));
|
|
1466
|
+
this.apps = new HubAppsClient((path, init) => this.request(path, init));
|
|
1467
|
+
this.numbers = new HubManagedNumbersClient((path, init) => this.request(path, init));
|
|
1468
|
+
this.connections = new HubConnectionsClient((path, init) => this.request(path, init));
|
|
1469
|
+
this.channels = new HubChannelsClient((path, init) => this.request(path, init));
|
|
1470
|
+
this.eventSubscriptions = new HubEventSubscriptionsClient((path, init) => this.request(path, init));
|
|
1471
|
+
this.permissions = new HubPermissionsClient((path, init) => this.request(path, init));
|
|
1472
|
+
this.tokens = new HubTokensClient((path, init) => this.request(path, init));
|
|
1473
|
+
this.tools = new HubToolsClient((path, init) => this.request(path, init));
|
|
1474
|
+
this.approvals = new HubApprovalsClient((path, init) => this.request(path, init));
|
|
1475
|
+
this.audit = new HubAuditClient((path, init) => this.request(path, init));
|
|
1476
|
+
this.githubApp = new HubGithubAppClient((path, init) => this.request(path, init));
|
|
1477
|
+
this.workflows = new HubWorkflowsClient((path, init) => this.request(path, init), (path, init) => this.stream(path, init), (path, init) => this.requestBytes(path, init));
|
|
1478
|
+
this.lines = new HubLinesClient((path, init) => this.request(path, init), (yaml) => this.workflows.create(yaml), (path, init, callbackBearer) => {
|
|
1479
|
+
if (typeof callbackBearer !== "string" || !/^[\x21-\x7e]{16,512}$/.test(callbackBearer)) throw new HubSdkError({
|
|
1480
|
+
code: "HUB_INVALID_INPUT",
|
|
1481
|
+
message: "Application callback bearer is invalid"
|
|
1482
|
+
});
|
|
1483
|
+
const headers = new Headers(init.headers);
|
|
1484
|
+
headers.set("Authorization", `Bearer ${callbackBearer}`);
|
|
1485
|
+
return this.request(path, {
|
|
1486
|
+
...init,
|
|
1487
|
+
headers,
|
|
1488
|
+
credentials: "omit",
|
|
1489
|
+
redirect: "manual"
|
|
1490
|
+
}, {
|
|
1491
|
+
auth: "caller",
|
|
1492
|
+
validateData: isDispatchCurrentData
|
|
1493
|
+
});
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
static fromEnv(options = {}) {
|
|
1497
|
+
const env = options.env ?? readProcessEnv();
|
|
1498
|
+
return new HubClient({
|
|
1499
|
+
baseUrl: resolveHubBaseUrl(env),
|
|
1500
|
+
apiKey: options.apiKey ?? (options.authHeaders ? void 0 : resolveHubAuth(env)),
|
|
1501
|
+
authHeaders: options.authHeaders,
|
|
1502
|
+
fetch: options.fetch
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
async status() {
|
|
1506
|
+
return this.request("/v1/hub/status", { method: "GET" });
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* Open a streaming (Server-Sent Events) response and return its raw body.
|
|
1510
|
+
* Shares auth-header building + `fetch` with {@link request}, but does NOT
|
|
1511
|
+
* buffer or JSON-parse the body — the caller consumes the stream.
|
|
1512
|
+
*
|
|
1513
|
+
* A successful stream comes back as `text/event-stream`. Anything else is an
|
|
1514
|
+
* error envelope (404/429/401 JSON) or a transport failure (gateway/HTML
|
|
1515
|
+
* page); it is surfaced the same way {@link request} surfaces errors — a
|
|
1516
|
+
* typed `HubSdkError` from a `{success:false}` envelope, otherwise an
|
|
1517
|
+
* `HUB_HTTP_<status>` transport error — rather than handed back as bogus SSE.
|
|
1518
|
+
*/
|
|
1519
|
+
async stream(path, init) {
|
|
1520
|
+
const response = await this.fetch(`${this.baseUrl}${path}`, {
|
|
1521
|
+
...init,
|
|
1522
|
+
headers: await this.buildHeaders(init.headers)
|
|
1523
|
+
});
|
|
1524
|
+
const status = response.status;
|
|
1525
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
1526
|
+
if (!response.ok || !contentType.includes("text/event-stream")) await throwHubResponseError(path, response, status, contentType);
|
|
1527
|
+
if (!response.body) throw httpError(path, status, response.statusText, "event-stream response had no body", contentType);
|
|
1528
|
+
return response.body;
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Fetch raw (non-envelope) bytes — the artifact download route, whose 200 is
|
|
1532
|
+
* the artifact's own content type, not JSON. Error responses on such routes
|
|
1533
|
+
* are still the standard envelope, so a failure surfaces exactly like
|
|
1534
|
+
* {@link request}: a typed `HubSdkError` from a `{success:false}` body,
|
|
1535
|
+
* otherwise an `HUB_HTTP_<status>` transport error.
|
|
1536
|
+
*/
|
|
1537
|
+
async requestBytes(path, init) {
|
|
1538
|
+
const response = await this.fetch(`${this.baseUrl}${path}`, {
|
|
1539
|
+
...init,
|
|
1540
|
+
headers: await this.buildHeaders(init.headers)
|
|
1541
|
+
});
|
|
1542
|
+
const status = response.status;
|
|
1543
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
1544
|
+
if (!response.ok) await throwHubResponseError(path, response, status, contentType);
|
|
1545
|
+
return {
|
|
1546
|
+
bytes: new Uint8Array(await response.arrayBuffer()),
|
|
1547
|
+
contentType
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
};
|
|
1551
|
+
//#endregion
|
|
1542
1552
|
//#region src/broker.ts
|
|
1543
1553
|
/** Server-only client. App secrets never become a user's general API key.
|
|
1544
1554
|
* Every invocation mints and consumes one short-lived, exact-grant token. */
|