@whittlelabs/sifter 0.43.2 → 0.43.3

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.
Files changed (3) hide show
  1. package/bin.js +269 -126
  2. package/bin.js.map +4 -4
  3. package/package.json +1 -1
package/bin.js CHANGED
@@ -9780,12 +9780,129 @@ var require_canonicalise = __commonJS({
9780
9780
  }
9781
9781
  });
9782
9782
 
9783
+ // ../../packages/contracts/dist/client.js
9784
+ var require_client = __commonJS({
9785
+ "../../packages/contracts/dist/client.js"(exports2) {
9786
+ "use strict";
9787
+ Object.defineProperty(exports2, "__esModule", { value: true });
9788
+ exports2.createContractClient = createContractClient;
9789
+ function createContractClient({ baseUrl, transport }) {
9790
+ const root = baseUrl.replace(/\/+$/, "");
9791
+ async function request(method, template, options = {}) {
9792
+ const headers = { Accept: "application/json" };
9793
+ if (options.body !== void 0)
9794
+ headers["Content-Type"] = "application/json";
9795
+ Object.assign(headers, options.headers);
9796
+ let response;
9797
+ try {
9798
+ response = await transport(`${root}${filledPath(template, options.path)}${queryString(options.query)}`, {
9799
+ method: method.toUpperCase(),
9800
+ headers,
9801
+ body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
9802
+ signal: options.signal
9803
+ });
9804
+ } catch (err2) {
9805
+ return failure("NETWORK_ERROR", err2 instanceof Error ? err2.message : "Network request failed", null);
9806
+ }
9807
+ return answered(response);
9808
+ }
9809
+ const call = (method) => (path, options) => request(method, path, options);
9810
+ return {
9811
+ get: call("get"),
9812
+ post: call("post"),
9813
+ put: call("put"),
9814
+ patch: call("patch"),
9815
+ delete: call("delete")
9816
+ };
9817
+ }
9818
+ function filledPath(template, params) {
9819
+ const values = params ?? {};
9820
+ return template.replace(/\{([^}]+)\}/g, (_, name2) => {
9821
+ const value = values[name2];
9822
+ if (value === void 0 || value === null)
9823
+ throw new TypeError(`${template} needs the path parameter ${name2}`);
9824
+ return encodeURIComponent(String(value));
9825
+ });
9826
+ }
9827
+ function queryString(query) {
9828
+ const search = new URLSearchParams();
9829
+ for (const [key, value] of Object.entries(query ?? {})) {
9830
+ if (value === void 0 || value === null)
9831
+ continue;
9832
+ for (const item of Array.isArray(value) ? value : [value])
9833
+ search.append(key, String(item));
9834
+ }
9835
+ const text = search.toString();
9836
+ return text ? `?${text}` : "";
9837
+ }
9838
+ async function answered(response) {
9839
+ const { status } = response;
9840
+ let text;
9841
+ try {
9842
+ text = await response.text();
9843
+ } catch (err2) {
9844
+ return failure("NETWORK_ERROR", err2 instanceof Error ? err2.message : "The response could not be read", status);
9845
+ }
9846
+ let payload;
9847
+ let parsed = true;
9848
+ if (text !== "") {
9849
+ try {
9850
+ payload = JSON.parse(text);
9851
+ } catch {
9852
+ parsed = false;
9853
+ }
9854
+ }
9855
+ if (response.ok) {
9856
+ if (text === "")
9857
+ return { success: true, data: void 0, status };
9858
+ if (!parsed)
9859
+ return failure("SERVER_ERROR", `The ${status} response was not JSON`, status);
9860
+ if (isRecord(payload) && payload.success === true)
9861
+ return { success: true, data: payload.data, status };
9862
+ return { success: true, data: payload, status };
9863
+ }
9864
+ if (isRecord(payload) && payload.success === false && isRecord(payload.error)) {
9865
+ const { code, message } = payload.error;
9866
+ if (typeof code === "string" && typeof message === "string") {
9867
+ return failure(code, message, status, saysMore(payload, payload.error) ? payload : void 0);
9868
+ }
9869
+ }
9870
+ return failure("SERVER_ERROR", `Request failed with status ${status}`, status, text !== "" && parsed ? payload : void 0);
9871
+ }
9872
+ function saysMore(envelope, error) {
9873
+ return Object.keys(envelope).some((key) => key !== "success" && key !== "error") || Object.keys(error).some((key) => key !== "code" && key !== "message");
9874
+ }
9875
+ function failure(code, message, status, body2) {
9876
+ return { success: false, error: { code, message, status, ...body2 !== void 0 ? { body: body2 } : {} } };
9877
+ }
9878
+ function isRecord(value) {
9879
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9880
+ }
9881
+ }
9882
+ });
9883
+
9884
+ // ../../packages/contracts/dist/services/loom.js
9885
+ var require_loom = __commonJS({
9886
+ "../../packages/contracts/dist/services/loom.js"(exports2) {
9887
+ "use strict";
9888
+ Object.defineProperty(exports2, "__esModule", { value: true });
9889
+ exports2.service = void 0;
9890
+ exports2.createClient = createClient;
9891
+ var client_1 = require_client();
9892
+ exports2.service = "whittle-loom";
9893
+ function createClient(options) {
9894
+ return (0, client_1.createContractClient)(options);
9895
+ }
9896
+ }
9897
+ });
9898
+
9783
9899
  // ../../packages/loom/dist/seed/seed-workflows.js
9784
9900
  var require_seed_workflows = __commonJS({
9785
9901
  "../../packages/loom/dist/seed/seed-workflows.js"(exports2) {
9786
9902
  "use strict";
9787
9903
  Object.defineProperty(exports2, "__esModule", { value: true });
9788
9904
  exports2.seedWorkflows = seedWorkflows;
9905
+ var loom_1 = require_loom();
9789
9906
  var canonicalise_1 = require_canonicalise();
9790
9907
  var errors_1 = require_errors2();
9791
9908
  var NULL_LOGGER = {
@@ -9799,13 +9916,16 @@ var require_seed_workflows = __commonJS({
9799
9916
  async function seedWorkflows(opts) {
9800
9917
  const logger = opts.logger ?? NULL_LOGGER;
9801
9918
  const fetchFn = opts.fetchFn ?? fetch;
9802
- const baseUrl = opts.loomApiUrl.replace(/\/$/, "");
9803
- const headers = { "Content-Type": "application/json" };
9804
- if ("accessToken" in opts.auth) {
9805
- headers["Authorization"] = `Bearer ${opts.auth.accessToken}`;
9806
- } else {
9807
- headers["X-API-Key"] = opts.auth.apiKey;
9808
- }
9919
+ const credential = "accessToken" in opts.auth ? { Authorization: `Bearer ${opts.auth.accessToken}` } : { "X-API-Key": opts.auth.apiKey };
9920
+ const loom = (0, loom_1.createClient)({
9921
+ baseUrl: opts.loomApiUrl,
9922
+ transport: (url, init2) => {
9923
+ const headers = new Headers(init2.headers);
9924
+ for (const [name2, value] of Object.entries(credential))
9925
+ headers.set(name2, value);
9926
+ return fetchFn(url, { ...init2, headers });
9927
+ }
9928
+ });
9809
9929
  const results = [];
9810
9930
  for (const workflow of opts.workflows) {
9811
9931
  let ownerClass;
@@ -9841,17 +9961,12 @@ var require_seed_workflows = __commonJS({
9841
9961
  nodes: body2.nodes.length,
9842
9962
  transitions: body2.transitions.length
9843
9963
  });
9844
- const response = await fetchFn(`${baseUrl}/api/admin/seed-workflow`, {
9845
- method: "POST",
9846
- headers,
9847
- body: JSON.stringify(body2)
9848
- });
9849
- const json = await response.json();
9850
- if (!response.ok || !json.success || !json.data) {
9851
- const message = json.error?.message ?? `seedWorkflows: ${workflow.name} failed with HTTP ${response.status}`;
9964
+ const result = await loom.post("/api/admin/seed-workflow", { body: body2 });
9965
+ if (!result.success) {
9966
+ const message = result.error.code === "SERVER_ERROR" ? `seedWorkflows: ${workflow.name} failed with HTTP ${result.error.status}` : result.error.message;
9852
9967
  throw new errors_1.SeedWorkflowsError(workflow.name, message);
9853
9968
  }
9854
- results.push(json.data);
9969
+ results.push(result.data);
9855
9970
  }
9856
9971
  return { workflows: results };
9857
9972
  }
@@ -58981,7 +59096,7 @@ var require_http_api = __commonJS({
58981
59096
  });
58982
59097
 
58983
59098
  // ../../packages/keep/dist/client.js
58984
- var require_client = __commonJS({
59099
+ var require_client2 = __commonJS({
58985
59100
  "../../packages/keep/dist/client.js"(exports2) {
58986
59101
  "use strict";
58987
59102
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -59700,7 +59815,7 @@ var require_dist4 = __commonJS({
59700
59815
  "use strict";
59701
59816
  Object.defineProperty(exports2, "__esModule", { value: true });
59702
59817
  exports2.waitForKeepToken = exports2.KeepCredentialsRefusedError = exports2.KeepRateLimitedError = exports2.KeepUnavailableError = exports2.AgentCredentialRevokedError = exports2.AgentTokenManager = exports2.ServiceTokenManager = exports2.KeepClient = void 0;
59703
- var client_1 = require_client();
59818
+ var client_1 = require_client2();
59704
59819
  Object.defineProperty(exports2, "KeepClient", { enumerable: true, get: function() {
59705
59820
  return client_1.KeepClient;
59706
59821
  } });
@@ -68558,13 +68673,28 @@ var require_typed_exit = __commonJS({
68558
68673
  }
68559
68674
  });
68560
68675
 
68676
+ // ../../packages/contracts/dist/services/jobs.js
68677
+ var require_jobs = __commonJS({
68678
+ "../../packages/contracts/dist/services/jobs.js"(exports2) {
68679
+ "use strict";
68680
+ Object.defineProperty(exports2, "__esModule", { value: true });
68681
+ exports2.service = void 0;
68682
+ exports2.createClient = createClient;
68683
+ var client_1 = require_client();
68684
+ exports2.service = "whittle-jobs";
68685
+ function createClient(options) {
68686
+ return (0, client_1.createContractClient)(options);
68687
+ }
68688
+ }
68689
+ });
68690
+
68561
68691
  // ../../packages/jobs/dist/response.js
68562
68692
  var require_response = __commonJS({
68563
68693
  "../../packages/jobs/dist/response.js"(exports2) {
68564
68694
  "use strict";
68565
68695
  Object.defineProperty(exports2, "__esModule", { value: true });
68566
68696
  exports2.NonJsonResponseError = exports2.ServiceUnavailableError = void 0;
68567
- exports2.readJsonResponse = readJsonResponse;
68697
+ exports2.refuseUnreadable = refuseUnreadable;
68568
68698
  var EXCERPT_LIMIT = 120;
68569
68699
  var UNAVAILABLE_STATUSES = /* @__PURE__ */ new Set([502, 503, 504]);
68570
68700
  var UnreadableResponseError = class extends Error {
@@ -68618,31 +68748,31 @@ var require_response = __commonJS({
68618
68748
  return url;
68619
68749
  }
68620
68750
  }
68621
- async function readJsonResponse(response, url) {
68751
+ async function refuseUnreadable(response, url) {
68622
68752
  const contentType = response.headers.get("content-type");
68623
68753
  const unavailable = UNAVAILABLE_STATUSES.has(response.status);
68624
- if (unavailable || !isJson(contentType)) {
68625
- const body2 = await response.text().catch(() => "");
68626
- const detail = {
68627
- host: hostOf(url),
68628
- statusCode: response.status,
68629
- statusText: response.statusText ?? "",
68630
- contentType,
68631
- bodyExcerpt: excerpt(body2)
68632
- };
68633
- throw unavailable ? new ServiceUnavailableError(detail) : new NonJsonResponseError(detail);
68634
- }
68635
- return await response.json();
68754
+ if (!unavailable && isJson(contentType))
68755
+ return;
68756
+ const body2 = await response.text().catch(() => "");
68757
+ const detail = {
68758
+ host: hostOf(url),
68759
+ statusCode: response.status,
68760
+ statusText: response.statusText ?? "",
68761
+ contentType,
68762
+ bodyExcerpt: excerpt(body2)
68763
+ };
68764
+ throw unavailable ? new ServiceUnavailableError(detail) : new NonJsonResponseError(detail);
68636
68765
  }
68637
68766
  }
68638
68767
  });
68639
68768
 
68640
68769
  // ../../packages/jobs/dist/client.js
68641
- var require_client2 = __commonJS({
68770
+ var require_client3 = __commonJS({
68642
68771
  "../../packages/jobs/dist/client.js"(exports2) {
68643
68772
  "use strict";
68644
68773
  Object.defineProperty(exports2, "__esModule", { value: true });
68645
68774
  exports2.JobsClient = void 0;
68775
+ var jobs_1 = require_jobs();
68646
68776
  var response_1 = require_response();
68647
68777
  var JobsClient = class {
68648
68778
  baseUrl;
@@ -68682,19 +68812,26 @@ var require_client2 = __commonJS({
68682
68812
  * revoke-then-repair, clock skew) while the local expiry timer still thinks
68683
68813
  * it's valid. Force a re-mint and retry once before surfacing the failure.
68684
68814
  * `onResponse` (min-version contract) fires on the response we actually act
68685
- * on. `body` is a string, so it is safe to resend.
68815
+ * on. The contract client hands over its body as a string, so it is safe to resend.
68686
68816
  */
68687
- async fetchWithAuthRetry(method, url, body2) {
68688
- let response = await fetch(url, { method, headers: await this.buildHeaders(), body: body2 });
68817
+ async fetchWithAuthRetry(url, init2) {
68818
+ const send = async (forceRefresh) => {
68819
+ const headers = new Headers(init2.headers);
68820
+ for (const [name2, value] of Object.entries(await this.buildHeaders(forceRefresh)))
68821
+ headers.set(name2, value);
68822
+ return fetch(url, { ...init2, headers });
68823
+ };
68824
+ let response = await send(false);
68689
68825
  if (response.status === 401 && this.getAccessToken) {
68690
- response = await fetch(url, { method, headers: await this.buildHeaders(true), body: body2 });
68826
+ await response.body?.cancel().catch(() => void 0);
68827
+ response = await send(true);
68691
68828
  }
68692
68829
  this.onResponse?.(response);
68693
68830
  return response;
68694
68831
  }
68695
68832
  // ── Job Pools ──────────────────────────────────────────────
68696
68833
  async createJobPool(options) {
68697
- return this.request("POST", "/api/job-pools", options);
68834
+ return this.call((api) => api.post("/api/job-pools", { body: options }));
68698
68835
  }
68699
68836
  /**
68700
68837
  * Idempotent upsert by owner and name. When the
@@ -68702,7 +68839,7 @@ var require_client2 = __commonJS({
68702
68839
  * constraints. The Sift provisioning hook relies on this semantics.
68703
68840
  */
68704
68841
  async findOrCreateJobPool(options) {
68705
- return this.request("POST", "/api/job-pools?idempotent=true", options);
68842
+ return this.call((api) => api.post("/api/job-pools", { query: { idempotent: "true" }, body: options }));
68706
68843
  }
68707
68844
  /**
68708
68845
  * Every tenant's pools, which needs jobs:job-pools:read at operator context
@@ -68710,17 +68847,12 @@ var require_client2 = __commonJS({
68710
68847
  * one exact name; neither confers standing (BE-035).
68711
68848
  */
68712
68849
  async listJobPools(filters) {
68713
- const params = new URLSearchParams();
68714
- if (filters?.owner)
68715
- params.set("owner", `${filters.owner.principalClass}:${filters.owner.principalId}`);
68716
- if (filters?.name)
68717
- params.set("name", filters.name);
68718
- const qs = params.toString();
68719
- const { pools } = await this.request("GET", `/api/job-pools${qs ? `?${qs}` : ""}`);
68850
+ const owner = filters?.owner ? `${filters.owner.principalClass}:${filters.owner.principalId}` : void 0;
68851
+ const { pools } = await this.call((api) => api.get("/api/job-pools", { query: { owner, name: filters?.name } }));
68720
68852
  return pools;
68721
68853
  }
68722
68854
  async getJobPool(poolId) {
68723
- return this.request("GET", `/api/job-pools/${poolId}`);
68855
+ return this.call((api) => api.get("/api/job-pools/{id}", { path: { id: poolId } }));
68724
68856
  }
68725
68857
  /**
68726
68858
  * Resolve a pool by exact name. Names are unique per OWNER, not globally
@@ -68756,46 +68888,51 @@ var require_client2 = __commonJS({
68756
68888
  // A subscriber joins a pool by registering as a member of it. These
68757
68889
  // map to the server's `/api/job-pools/:poolId/members` routes.
68758
68890
  async listMembers(poolId) {
68759
- const { members } = await this.request("GET", `/api/job-pools/${poolId}/members`);
68891
+ const { members } = await this.call((api) => api.get("/api/job-pools/{poolId}/members", { path: { poolId } }));
68760
68892
  return members;
68761
68893
  }
68762
68894
  async registerMember(poolId, options) {
68763
- return this.request("POST", `/api/job-pools/${poolId}/members`, options);
68895
+ return this.call((api) => api.post("/api/job-pools/{poolId}/members", { path: { poolId }, body: options }));
68764
68896
  }
68765
68897
  async updateMember(poolId, memberId, options) {
68766
- return this.request("PUT", `/api/job-pools/${poolId}/members/${memberId}`, options);
68898
+ return this.call((api) => api.put("/api/job-pools/{poolId}/members/{mid}", { path: { poolId, mid: memberId }, body: options }));
68767
68899
  }
68768
68900
  // ── Jobs (producer) ──────────────────────────────────────────────
68769
68901
  /**
68770
68902
  * Enqueue a job into a job pool. The `inputs` are opaque to Jobs; a Shuttle
68771
68903
  * reads the strategy header inside them to decide how to run it (ADR 0005).
68904
+ * The body names its fields one by one, so nothing a caller spreads into
68905
+ * the options reaches the wire.
68772
68906
  */
68773
68907
  async enqueueJob(options) {
68774
68908
  const jobPoolId = await this.resolvePoolRef(options.pool);
68775
- const body2 = {
68776
- jobPoolId,
68777
- title: options.title,
68778
- progressChannel: options.progressChannel,
68779
- instructions: options.instructions,
68780
- maxAttempts: options.maxAttempts,
68781
- deadlineDuration: options.deadlineDuration,
68782
- claimDeadlineDuration: options.claimDeadlineDuration,
68783
- priority: options.priority,
68784
- tags: options.tags,
68785
- clientRef: options.clientRef,
68786
- clientContext: options.clientContext,
68787
- inputs: options.inputs
68788
- };
68789
- return this.request("POST", "/api/jobs", body2);
68909
+ return this.call((api) => api.post("/api/jobs", {
68910
+ body: {
68911
+ jobPoolId,
68912
+ title: options.title,
68913
+ progressChannel: options.progressChannel,
68914
+ instructions: options.instructions,
68915
+ maxAttempts: options.maxAttempts,
68916
+ deadlineDuration: options.deadlineDuration,
68917
+ claimDeadlineDuration: options.claimDeadlineDuration,
68918
+ priority: options.priority,
68919
+ tags: options.tags,
68920
+ clientRef: options.clientRef,
68921
+ clientContext: options.clientContext,
68922
+ inputs: options.inputs
68923
+ }
68924
+ }));
68790
68925
  }
68791
68926
  async getJob(jobId) {
68792
- return this.request("GET", `/api/jobs/${jobId}`);
68927
+ return this.call((api) => api.get("/api/jobs/{id}", { path: { id: jobId } }));
68793
68928
  }
68929
+ /** Answers the job without its inputs, as the route does. */
68794
68930
  async updateJob(jobId, options) {
68795
- return this.request("PATCH", `/api/jobs/${jobId}`, options);
68931
+ return this.call((api) => api.patch("/api/jobs/{id}", { path: { id: jobId }, body: options }));
68796
68932
  }
68933
+ /** Answers the job without its inputs, as the route does. */
68797
68934
  async cancelJob(jobId) {
68798
- return this.request("PUT", `/api/jobs/${jobId}`);
68935
+ return this.call((api) => api.put("/api/jobs/{id}", { path: { id: jobId } }));
68799
68936
  }
68800
68937
  /**
68801
68938
  * Permanently delete every job filed under `clientRefPrefix` (which must end
@@ -68803,14 +68940,14 @@ var require_client2 = __commonJS({
68803
68940
  * the caller needs `jobs:job-purges:write` at '*'. Idempotent.
68804
68941
  */
68805
68942
  async purgeJobs(clientRefPrefix) {
68806
- return this.request("POST", "/api/job-purges", { clientRefPrefix });
68943
+ return this.call((api) => api.post("/api/job-purges", { body: { clientRefPrefix } }));
68807
68944
  }
68808
68945
  // ── Outputs ──────────────────────────────────────────────────────
68809
68946
  async listOutputs(jobId) {
68810
68947
  const all = [];
68811
- const pageSize = 100;
68812
- for (let offset = 0; ; offset += pageSize) {
68813
- const { outputs, total } = await this.request("GET", `/api/jobs/${jobId}/output?limit=${pageSize}&offset=${offset}`);
68948
+ const limit = 100;
68949
+ for (let offset = 0; ; offset += limit) {
68950
+ const { outputs, total } = await this.call((api) => api.get("/api/jobs/{jobId}/output", { path: { jobId }, query: { limit, offset } }));
68814
68951
  all.push(...outputs);
68815
68952
  if (outputs.length === 0 || all.length >= total)
68816
68953
  break;
@@ -68818,7 +68955,7 @@ var require_client2 = __commonJS({
68818
68955
  return all;
68819
68956
  }
68820
68957
  async createOutput(jobId, options) {
68821
- return this.request("POST", `/api/jobs/${jobId}/output`, options);
68958
+ return this.call((api) => api.post("/api/jobs/{jobId}/output", { path: { jobId }, body: options }));
68822
68959
  }
68823
68960
  /**
68824
68961
  * Post a batch of live progress frames for a running job. Best-effort
@@ -68827,7 +68964,7 @@ var require_client2 = __commonJS({
68827
68964
  * let a dropped frame affect the job.
68828
68965
  */
68829
68966
  async postProgress(jobId, options) {
68830
- await this.request("POST", `/api/jobs/${jobId}/progress`, options);
68967
+ await this.call((api) => api.post("/api/jobs/{jobId}/progress", { path: { jobId }, body: options }));
68831
68968
  }
68832
68969
  // ── Attendance (subscriber dispatch lifecycle) ───────────────────
68833
68970
  /**
@@ -68836,7 +68973,10 @@ var require_client2 = __commonJS({
68836
68973
  * subscriber needs to execute and submit.
68837
68974
  */
68838
68975
  async acceptDispatch(jobId, options) {
68839
- return this.request("POST", `/api/jobs/${jobId}/attendance`, options?.shiftId ? { shiftId: options.shiftId } : void 0);
68976
+ return this.call((api) => api.post("/api/jobs/{jobId}/attendance", {
68977
+ path: { jobId },
68978
+ body: options?.shiftId ? { shiftId: options.shiftId } : void 0
68979
+ }));
68840
68980
  }
68841
68981
  // ── Shifts (whittlelabs ADR 0129) ────────────────────────────────
68842
68982
  /**
@@ -68844,39 +68984,33 @@ var require_client2 = __commonJS({
68844
68984
  * answers 404; the subscribe loop then claims without one.
68845
68985
  */
68846
68986
  async startShift() {
68847
- return this.request("POST", "/api/my/shifts");
68987
+ return this.call((api) => api.post("/api/my/shifts"));
68848
68988
  }
68849
68989
  /** End a shift, releasing every claim still taken on it back to the queue. */
68850
68990
  async endShift(shiftId) {
68851
- await this.request("DELETE", `/api/my/shifts/${shiftId}`);
68991
+ await this.call((api) => api.delete("/api/my/shifts/{shiftId}", { path: { shiftId } }));
68852
68992
  }
68853
68993
  async submit(jobId, options) {
68854
- return this.request("PUT", `/api/jobs/${jobId}/attendance`, options);
68994
+ return this.call((api) => api.put("/api/jobs/{jobId}/attendance", { path: { jobId }, body: options }));
68855
68995
  }
68856
68996
  // ── Discovery (rare) ─────────────────────────────────────────────
68857
68997
  async listDispatchableJobs(options) {
68858
- const params = new URLSearchParams();
68859
- if (options?.pools?.length)
68860
- params.set("pools", options.pools.join(","));
68861
- if (options?.tags?.length)
68862
- params.set("tags", options.tags.join(","));
68863
- if (options?.maxAttempts !== void 0)
68864
- params.set("maxAttempts", String(options.maxAttempts));
68865
- if (options?.minPriority !== void 0)
68866
- params.set("minPriority", String(options.minPriority));
68867
- if (options?.limit !== void 0)
68868
- params.set("limit", String(options.limit));
68869
- if (options?.offset !== void 0)
68870
- params.set("offset", String(options.offset));
68871
- if (options?.sort)
68872
- params.set("sort", options.sort);
68873
- if (options?.shift)
68874
- params.set("shift", options.shift);
68875
- const qs = params.toString();
68876
- const { jobs, total, directives, shift } = await this.request("GET", `/api/my/jobs${qs ? `?${qs}` : ""}`);
68998
+ const { jobs, total, directives, shift } = await this.call((api) => api.get("/api/my/jobs", {
68999
+ query: {
69000
+ pools: options?.pools?.length ? options.pools.join(",") : void 0,
69001
+ tags: options?.tags?.length ? options.tags.join(",") : void 0,
69002
+ maxAttempts: options?.maxAttempts === void 0 ? void 0 : String(options.maxAttempts),
69003
+ minPriority: options?.minPriority === void 0 ? void 0 : String(options.minPriority),
69004
+ limit: options?.limit,
69005
+ offset: options?.offset,
69006
+ sort: options?.sort || void 0,
69007
+ shift: options?.shift || void 0
69008
+ }
69009
+ }));
68877
69010
  return {
68878
69011
  data: jobs,
68879
69012
  pagination: { total, limit: options?.limit ?? 25, offset: options?.offset ?? 0 },
69013
+ // Absent from a Jobs that predates directives or shifts.
68880
69014
  directives: directives ?? null,
68881
69015
  shift: shift ?? null
68882
69016
  };
@@ -68890,38 +69024,47 @@ var require_client2 = __commonJS({
68890
69024
  async openHintStream(options = {}) {
68891
69025
  const qs = options.shift ? `?shift=${encodeURIComponent(options.shift)}` : "";
68892
69026
  const url = `${this.baseUrl}/api/my/jobs/stream${qs}`;
68893
- const headers = async (forceRefresh) => ({
68894
- ...await this.buildHeaders(forceRefresh),
68895
- Accept: "text/event-stream",
68896
- ...options.lastEventId ? { "Last-Event-ID": options.lastEventId } : {}
69027
+ return this.fetchWithAuthRetry(url, {
69028
+ headers: { Accept: "text/event-stream", ...options.lastEventId ? { "Last-Event-ID": options.lastEventId } : {} },
69029
+ signal: options.signal
68897
69030
  });
68898
- let response = await fetch(url, { headers: await headers(false), signal: options.signal });
68899
- if (response.status === 401 && this.getAccessToken) {
68900
- await response.body?.cancel().catch(() => void 0);
68901
- response = await fetch(url, { headers: await headers(true), signal: options.signal });
68902
- }
68903
- this.onResponse?.(response);
68904
- return response;
68905
69031
  }
68906
69032
  // ── HTTP plumbing ────────────────────────────────────────────────
68907
69033
  /**
68908
- * Every call's one reader. `readJsonResponse` refuses to parse a reply that
68909
- * is not the API's JSON — an ingress 502/503/504 while a pod rolls, or any
68910
- * non-JSON body — and throws a named failure instead of a parse error. What
68911
- * comes back here is the API's own envelope, success or not.
69034
+ * Every call's one path. The contract client builds the request and reads
69035
+ * the API's envelope; the transport under it authenticates (one retry on a
69036
+ * 401 for a token provider), fires `onResponse`, and refuses a reply that is
69037
+ * not the API's JSON with a named failure (`refuseUnreadable`: an ingress
69038
+ * 502/503/504 while a pod rolls, or any non-JSON body). A failure the
69039
+ * transport raises is rethrown as raised, so `ServiceUnavailableError` and
69040
+ * fetch's own `TypeError` reach the subscribe loop's outage handling rather
69041
+ * than arriving as a NETWORK_ERROR result. The API's own refusal throws an
69042
+ * `Error` carrying `code` and `statusCode`, as it always has.
68912
69043
  */
68913
- async request(method, path, body2) {
68914
- const url = `${this.baseUrl}${path}`;
68915
- const response = await this.fetchWithAuthRetry(method, url, body2 ? JSON.stringify(body2) : void 0);
68916
- const json = await (0, response_1.readJsonResponse)(response, url);
68917
- if (!response.ok || !json.success) {
68918
- const errorMessage = json.error?.message ?? `Request failed with status ${response.status}`;
68919
- const error = new Error(errorMessage);
68920
- error.code = json.error?.code;
68921
- error.statusCode = response.status;
68922
- throw error;
68923
- }
68924
- return json.data;
69044
+ async call(send) {
69045
+ let raised;
69046
+ const api = (0, jobs_1.createClient)({
69047
+ baseUrl: this.baseUrl,
69048
+ transport: async (url, init2) => {
69049
+ try {
69050
+ const response = await this.fetchWithAuthRetry(url, init2);
69051
+ await (0, response_1.refuseUnreadable)(response, url);
69052
+ return response;
69053
+ } catch (error2) {
69054
+ raised = { error: error2 };
69055
+ throw error2;
69056
+ }
69057
+ }
69058
+ });
69059
+ const result = await send(api);
69060
+ if (raised)
69061
+ throw raised.error;
69062
+ if (result.success)
69063
+ return result.data;
69064
+ const error = new Error(result.error.message);
69065
+ error.code = result.error.code;
69066
+ error.statusCode = result.error.status ?? void 0;
69067
+ throw error;
68925
69068
  }
68926
69069
  };
68927
69070
  exports2.JobsClient = JobsClient;
@@ -69804,7 +69947,7 @@ var require_dist7 = __commonJS({
69804
69947
  "use strict";
69805
69948
  Object.defineProperty(exports2, "__esModule", { value: true });
69806
69949
  exports2.subscribe = exports2.ServiceUnavailableError = exports2.NonJsonResponseError = exports2.JobsClient = void 0;
69807
- var client_1 = require_client2();
69950
+ var client_1 = require_client3();
69808
69951
  Object.defineProperty(exports2, "JobsClient", { enumerable: true, get: function() {
69809
69952
  return client_1.JobsClient;
69810
69953
  } });
@@ -76245,7 +76388,7 @@ var import_shuttle2 = __toESM(require_dist8());
76245
76388
 
76246
76389
  // src/brand.ts
76247
76390
  var import_shuttle = __toESM(require_dist8());
76248
- var buildVersion = true ? "0.43.2" : pkg.version;
76391
+ var buildVersion = true ? "0.43.3" : pkg.version;
76249
76392
  var AGENT_EXECUTORS = ["claude-code", "codex", "copilot"];
76250
76393
  var sifterBrand = {
76251
76394
  product: {