@tangle-network/hub-sdk 0.60.78-develop.20261017134105.a6b32a2 → 0.60.78-develop.20261021225232.c7da8cb

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -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/client.ts
322
+ //#region src/transport.ts
349
323
  var HubSdkError = class extends Error {
350
324
  code;
351
325
  details;
@@ -390,190 +364,21 @@ 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;
569
- apiKey;
570
370
  authHeaders;
371
+ #apiKey;
571
372
  constructor(options) {
572
373
  this.baseUrl = options.baseUrl.replace(/\/+$/, "");
573
- this.apiKey = options.apiKey;
374
+ this.#apiKey = options.apiKey;
574
375
  this.authHeaders = options.authHeaders;
575
376
  this.fetch = options.fetch ?? fetch.bind(globalThis);
576
377
  }
378
+ /** The API key this client authenticates with, when it has one. */
379
+ get apiKey() {
380
+ return this.#apiKey;
381
+ }
577
382
  async request(path, init, options = {}) {
578
383
  const callerAuth = options.auth === "caller";
579
384
  const response = await this.fetch(`${this.baseUrl}${path}`, {
@@ -619,135 +424,68 @@ var HubTransport = class {
619
424
  return mergedHeaders;
620
425
  }
621
426
  };
622
- var HubClient = class HubClient extends HubTransport {
623
- knowledge;
624
- allowances;
625
- apps;
626
- connections;
627
- channels;
628
- numbers;
629
- eventSubscriptions;
630
- permissions;
631
- tokens;
632
- tools;
633
- approvals;
634
- audit;
635
- githubApp;
636
- workflows;
637
- lines;
638
- constructor(options) {
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));
644
- this.connections = new HubConnectionsClient((path, init) => this.request(path, init));
645
- this.channels = new HubChannelsClient((path, init) => this.request(path, init));
646
- this.eventSubscriptions = new HubEventSubscriptionsClient((path, init) => this.request(path, init));
647
- this.permissions = new HubPermissionsClient((path, init) => this.request(path, init));
648
- this.tokens = new HubTokensClient((path, init) => this.request(path, init));
649
- this.tools = new HubToolsClient((path, init) => this.request(path, init));
650
- this.approvals = new HubApprovalsClient((path, init) => this.request(path, init));
651
- this.audit = new HubAuditClient((path, init) => this.request(path, init));
652
- this.githubApp = new HubGithubAppClient((path, init) => this.request(path, init));
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
- });
671
- }
672
- static fromEnv(options = {}) {
673
- const env = options.env ?? readProcessEnv();
674
- return new HubClient({
675
- baseUrl: resolveHubBaseUrl(env),
676
- apiKey: options.apiKey ?? (options.authHeaders ? void 0 : resolveHubAuth(env)),
677
- authHeaders: options.authHeaders,
678
- fetch: options.fetch
679
- });
680
- }
681
- async status() {
682
- return this.request("/v1/hub/status", { method: "GET" });
683
- }
684
- /**
685
- * Open a streaming (Server-Sent Events) response and return its raw body.
686
- * Shares auth-header building + `fetch` with {@link request}, but does NOT
687
- * buffer or JSON-parse the body — the caller consumes the stream.
688
- *
689
- * A successful stream comes back as `text/event-stream`. Anything else is an
690
- * error envelope (404/429/401 JSON) or a transport failure (gateway/HTML
691
- * page); it is surfaced the same way {@link request} surfaces errors — a
692
- * typed `HubSdkError` from a `{success:false}` envelope, otherwise an
693
- * `HUB_HTTP_<status>` transport error — rather than handed back as bogus SSE.
694
- */
695
- async stream(path, init) {
696
- const response = await this.fetch(`${this.baseUrl}${path}`, {
697
- ...init,
698
- headers: await this.buildHeaders(init.headers)
699
- });
700
- const status = response.status;
701
- const contentType = response.headers.get("content-type") ?? "";
702
- if (!response.ok || !contentType.includes("text/event-stream")) {
703
- const bodyText = await response.text().catch(() => "");
704
- if (contentType.includes("application/json")) {
705
- let parsed;
706
- try {
707
- parsed = JSON.parse(bodyText);
708
- } catch {
709
- parsed = void 0;
710
- }
711
- if (isHubErrorEnvelope(parsed)) throw new HubSdkError(parsed.error, { status });
712
- }
713
- 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;
714
436
  }
715
- if (!response.body) throw httpError(path, status, response.statusText, "event-stream response had no body", contentType);
716
- return response.body;
437
+ if (isHubErrorEnvelope(parsed)) throw new HubSdkError(parsed.error, { status });
717
438
  }
718
- /**
719
- * Fetch raw (non-envelope) bytes — the artifact download route, whose 200 is
720
- * the artifact's own content type, not JSON. Error responses on such routes
721
- * are still the standard envelope, so a failure surfaces exactly like
722
- * {@link request}: a typed `HubSdkError` from a `{success:false}` body,
723
- * otherwise an `HUB_HTTP_<status>` transport error.
724
- */
725
- async requestBytes(path, init) {
726
- const response = await this.fetch(`${this.baseUrl}${path}`, {
727
- ...init,
728
- headers: await this.buildHeaders(init.headers)
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 }
729
461
  });
730
- const status = response.status;
731
- const contentType = response.headers.get("content-type") ?? "";
732
- if (!response.ok) {
733
- const bodyText = await response.text().catch(() => "");
734
- if (contentType.includes("application/json")) {
735
- let parsed;
736
- try {
737
- parsed = JSON.parse(bodyText);
738
- } catch {
739
- parsed = void 0;
740
- }
741
- if (isHubErrorEnvelope(parsed)) throw new HubSdkError(parsed.error, { status });
742
- }
743
- throw httpError(path, status, response.statusText, bodyText, contentType);
744
- }
745
- return {
746
- bytes: new Uint8Array(await response.arrayBuffer()),
747
- contentType
748
- };
749
462
  }
750
- };
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
751
489
  var HubTokensClient = class {
752
490
  constructor(request) {
753
491
  this.request = request;
@@ -805,6 +543,22 @@ var HubPermissionsClient = class {
805
543
  return this.request("/v1/hub/policies/revert-writes", jsonInit("POST", { connectionId }));
806
544
  }
807
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
808
562
  var HubToolsClient = class {
809
563
  constructor(request) {
810
564
  this.request = request;
@@ -902,6 +656,34 @@ function validateApprovedExecution(approved, path, connectionId) {
902
656
  }
903
657
  });
904
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
905
687
  const GITHUB_EXACT_CONNECT_SCOPES = [
906
688
  "read:user",
907
689
  "repo",
@@ -913,34 +695,6 @@ function sameOAuthScopeSet(left, right) {
913
695
  const rightSet = new Set(right);
914
696
  return leftSet.size === left.length && rightSet.size === right.length && leftSet.size === rightSet.size && [...leftSet].every((scope) => rightSet.has(scope));
915
697
  }
916
- var HubChannelsClient = class {
917
- constructor(request) {
918
- this.request = request;
919
- }
920
- async list() {
921
- return this.request("/v1/hub/channels", { method: "GET" });
922
- }
923
- async createEmail(input = {}) {
924
- return this.request("/v1/hub/channels/email", jsonInit("POST", input));
925
- }
926
- async delete(channelId) {
927
- return this.request(`/v1/hub/channels/${encodeURIComponent(channelId)}`, { method: "DELETE" });
928
- }
929
- };
930
- var HubEventSubscriptionsClient = class {
931
- constructor(request) {
932
- this.request = request;
933
- }
934
- async list() {
935
- return this.request("/v1/hub/event-subscriptions", { method: "GET" });
936
- }
937
- async create(input) {
938
- return this.request("/v1/hub/event-subscriptions", jsonInit("POST", input));
939
- }
940
- async delete(subscriptionId) {
941
- return this.request(`/v1/hub/event-subscriptions/${encodeURIComponent(subscriptionId)}`, { method: "DELETE" });
942
- }
943
- };
944
698
  var HubConnectionsClient = class {
945
699
  inboundWebhook;
946
700
  constructor(request) {
@@ -993,24 +747,42 @@ var HubConnectionsClient = class {
993
747
  async revoke(connectionId) {
994
748
  return this.request(`/v1/hub/connections/${encodeURIComponent(connectionId)}`, { method: "DELETE" });
995
749
  }
996
- async health(connectionId) {
997
- 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" });
998
768
  }
999
769
  };
1000
- var HubApprovalsClient = class {
770
+ var HubEventSubscriptionsClient = class {
1001
771
  constructor(request) {
1002
772
  this.request = request;
1003
773
  }
1004
774
  async list() {
1005
- return this.request("/v1/hub/approvals", { method: "GET" });
775
+ return this.request("/v1/hub/event-subscriptions", { method: "GET" });
1006
776
  }
1007
- async approve(approvalId) {
1008
- return this.request(`/v1/hub/approvals/${encodeURIComponent(approvalId)}/approve`, { method: "POST" });
777
+ async create(input) {
778
+ return this.request("/v1/hub/event-subscriptions", jsonInit("POST", input));
1009
779
  }
1010
- async deny(approvalId) {
1011
- return this.request(`/v1/hub/approvals/${encodeURIComponent(approvalId)}/deny`, { method: "POST" });
780
+ async delete(subscriptionId) {
781
+ return this.request(`/v1/hub/event-subscriptions/${encodeURIComponent(subscriptionId)}`, { method: "DELETE" });
1012
782
  }
1013
783
  };
784
+ //#endregion
785
+ //#region src/github-app.ts
1014
786
  var HubGithubAppClient = class {
1015
787
  constructor(request) {
1016
788
  this.request = request;
@@ -1051,6 +823,8 @@ var HubGithubAppClient = class {
1051
823
  return this.request(`/v1/hub/github-app/is-repo-installed?${params.toString()}`, { method: "GET" });
1052
824
  }
1053
825
  };
826
+ //#endregion
827
+ //#region src/audit.ts
1054
828
  var HubAuditClient = class {
1055
829
  constructor(request) {
1056
830
  this.request = request;
@@ -1068,6 +842,136 @@ var HubAuditClient = class {
1068
842
  return this.request(`/v1/hub/audit${query ? `?${query}` : ""}`, { method: "GET" });
1069
843
  }
1070
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
+ }
1071
975
  var HubWorkflowsClient = class {
1072
976
  constructor(request, stream, download) {
1073
977
  this.request = request;
@@ -1138,8 +1042,9 @@ var HubWorkflowsClient = class {
1138
1042
  * `{ "pull_request.number": "123" }`. Omit it for a one-click run of a
1139
1043
  * workflow that reads no trigger fields. Throws `HubSdkError`:
1140
1044
  * `MISSING_RUN_INPUTS` when a required field is absent (`details.missing`
1141
- * names them), `WORKFLOW_DISABLED` when the workflow is paused, `NOT_FOUND`
1142
- * for an unknown/foreign id. Pass `opts.signal` to abort a slow request.
1045
+ * names them), `NOT_FOUND` for an unknown/foreign id. A paused workflow
1046
+ * still runs once; pausing only stops its triggers. Pass `opts.signal` to
1047
+ * abort a slow request.
1143
1048
  */
1144
1049
  async run(id, inputs, opts = {}) {
1145
1050
  const hasInputs = inputs !== void 0 && Object.keys(inputs).length > 0;
@@ -1184,8 +1089,8 @@ var HubWorkflowsClient = class {
1184
1089
  * follow it with {@link getRun}/{@link watchRun}/{@link waitForRun} like any
1185
1090
  * other run. Throws `HubSdkError`: `RUN_NOT_RETRYABLE` when the run is not
1186
1091
  * terminal-failed/cancelled (queued/running/waiting, or succeeded),
1187
- * `WORKFLOW_DISABLED` when the workflow has since been disabled, `NOT_FOUND`
1188
- * for an unknown/foreign run id. Pass `opts.signal` to abort a slow request.
1092
+ * `NOT_FOUND` for an unknown/foreign run id; a workflow paused since the
1093
+ * failure still retries. Pass `opts.signal` to abort a slow request.
1189
1094
  */
1190
1095
  async retryRun(id, runId, opts = {}) {
1191
1096
  return this.request(`/v1/workflows/${encodeURIComponent(id)}/runs/${encodeURIComponent(runId)}/retry`, {
@@ -1534,6 +1439,116 @@ var HubWorkflowsClient = class {
1534
1439
  }
1535
1440
  };
1536
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
1537
1552
  //#region src/broker.ts
1538
1553
  /** Server-only client. App secrets never become a user's general API key.
1539
1554
  * Every invocation mints and consumes one short-lived, exact-grant token. */
@@ -1952,6 +1967,12 @@ var HubLineGrantsClient = class extends HubTransport {
1952
1967
  }
1953
1968
  };
1954
1969
  //#endregion
1955
- 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 };
1970
+ //#region src/workflow-definition-types.ts
1971
+ /** Stable identity shared by workflow connection requirements and prerequisite references. */
1972
+ function workflowConnectionRequirementKey(ref) {
1973
+ return `${ref.kind}:${ref.provider}`;
1974
+ }
1975
+ //#endregion
1976
+ 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, workflowConnectionRequirementKey };
1956
1977
 
1957
1978
  //# sourceMappingURL=index.js.map