@whittlelabs/sifter 0.27.3 → 0.27.5
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/bin.js +124 -4
- package/bin.js.map +4 -4
- package/package.json +1 -1
package/bin.js
CHANGED
|
@@ -15318,12 +15318,92 @@ ${issues}`);
|
|
|
15318
15318
|
}
|
|
15319
15319
|
});
|
|
15320
15320
|
|
|
15321
|
+
// ../../packages/jobs/dist/response.js
|
|
15322
|
+
var require_response = __commonJS({
|
|
15323
|
+
"../../packages/jobs/dist/response.js"(exports2) {
|
|
15324
|
+
"use strict";
|
|
15325
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
15326
|
+
exports2.NonJsonResponseError = exports2.ServiceUnavailableError = void 0;
|
|
15327
|
+
exports2.readJsonResponse = readJsonResponse;
|
|
15328
|
+
var EXCERPT_LIMIT = 120;
|
|
15329
|
+
var UNAVAILABLE_STATUSES = /* @__PURE__ */ new Set([502, 503, 504]);
|
|
15330
|
+
var UnreadableResponseError = class extends Error {
|
|
15331
|
+
host;
|
|
15332
|
+
statusCode;
|
|
15333
|
+
statusText;
|
|
15334
|
+
contentType;
|
|
15335
|
+
bodyExcerpt;
|
|
15336
|
+
constructor(message, detail) {
|
|
15337
|
+
super(message);
|
|
15338
|
+
this.host = detail.host;
|
|
15339
|
+
this.statusCode = detail.statusCode;
|
|
15340
|
+
this.statusText = detail.statusText;
|
|
15341
|
+
this.contentType = detail.contentType;
|
|
15342
|
+
this.bodyExcerpt = detail.bodyExcerpt;
|
|
15343
|
+
}
|
|
15344
|
+
};
|
|
15345
|
+
var ServiceUnavailableError = class extends UnreadableResponseError {
|
|
15346
|
+
code = "SERVICE_UNAVAILABLE";
|
|
15347
|
+
constructor(detail) {
|
|
15348
|
+
super(`${detail.host} answered ${formatStatus(detail)} (content-type: ${detail.contentType ?? "none"})${detail.bodyExcerpt ? `: ${detail.bodyExcerpt}` : ""}`, detail);
|
|
15349
|
+
this.name = "ServiceUnavailableError";
|
|
15350
|
+
}
|
|
15351
|
+
};
|
|
15352
|
+
exports2.ServiceUnavailableError = ServiceUnavailableError;
|
|
15353
|
+
var NonJsonResponseError = class extends UnreadableResponseError {
|
|
15354
|
+
code = "RESPONSE_NOT_JSON";
|
|
15355
|
+
constructor(detail) {
|
|
15356
|
+
super(`${detail.host} answered ${formatStatus(detail)} with content-type ${detail.contentType ?? "none"}, not JSON${detail.bodyExcerpt ? `: ${detail.bodyExcerpt}` : ""}`, detail);
|
|
15357
|
+
this.name = "NonJsonResponseError";
|
|
15358
|
+
}
|
|
15359
|
+
};
|
|
15360
|
+
exports2.NonJsonResponseError = NonJsonResponseError;
|
|
15361
|
+
function formatStatus(detail) {
|
|
15362
|
+
return detail.statusText ? `${detail.statusCode} ${detail.statusText}` : `${detail.statusCode}`;
|
|
15363
|
+
}
|
|
15364
|
+
function isJson(contentType) {
|
|
15365
|
+
if (!contentType)
|
|
15366
|
+
return false;
|
|
15367
|
+
const essence = contentType.split(";")[0].trim().toLowerCase();
|
|
15368
|
+
return essence === "application/json" || essence.endsWith("+json");
|
|
15369
|
+
}
|
|
15370
|
+
function excerpt(body) {
|
|
15371
|
+
const collapsed = body.replace(/\s+/g, " ").trim();
|
|
15372
|
+
return collapsed.length > EXCERPT_LIMIT ? `${collapsed.slice(0, EXCERPT_LIMIT)}...` : collapsed;
|
|
15373
|
+
}
|
|
15374
|
+
function hostOf(url) {
|
|
15375
|
+
try {
|
|
15376
|
+
return new URL(url).host;
|
|
15377
|
+
} catch {
|
|
15378
|
+
return url;
|
|
15379
|
+
}
|
|
15380
|
+
}
|
|
15381
|
+
async function readJsonResponse(response, url) {
|
|
15382
|
+
const contentType = response.headers.get("content-type");
|
|
15383
|
+
const unavailable = UNAVAILABLE_STATUSES.has(response.status);
|
|
15384
|
+
if (unavailable || !isJson(contentType)) {
|
|
15385
|
+
const body = await response.text().catch(() => "");
|
|
15386
|
+
const detail = {
|
|
15387
|
+
host: hostOf(url),
|
|
15388
|
+
statusCode: response.status,
|
|
15389
|
+
statusText: response.statusText ?? "",
|
|
15390
|
+
contentType,
|
|
15391
|
+
bodyExcerpt: excerpt(body)
|
|
15392
|
+
};
|
|
15393
|
+
throw unavailable ? new ServiceUnavailableError(detail) : new NonJsonResponseError(detail);
|
|
15394
|
+
}
|
|
15395
|
+
return await response.json();
|
|
15396
|
+
}
|
|
15397
|
+
}
|
|
15398
|
+
});
|
|
15399
|
+
|
|
15321
15400
|
// ../../packages/jobs/dist/client.js
|
|
15322
15401
|
var require_client = __commonJS({
|
|
15323
15402
|
"../../packages/jobs/dist/client.js"(exports2) {
|
|
15324
15403
|
"use strict";
|
|
15325
15404
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
15326
15405
|
exports2.JobsClient = void 0;
|
|
15406
|
+
var response_1 = require_response();
|
|
15327
15407
|
var JobsClient = class {
|
|
15328
15408
|
baseUrl;
|
|
15329
15409
|
apiKey;
|
|
@@ -15534,10 +15614,16 @@ var require_client = __commonJS({
|
|
|
15534
15614
|
};
|
|
15535
15615
|
}
|
|
15536
15616
|
// ── HTTP plumbing ────────────────────────────────────────────────
|
|
15617
|
+
/**
|
|
15618
|
+
* Every call's one reader. `readJsonResponse` refuses to parse a reply that
|
|
15619
|
+
* is not the API's JSON — an ingress 502/503/504 while a pod rolls, or any
|
|
15620
|
+
* non-JSON body — and throws a named failure instead of a parse error. What
|
|
15621
|
+
* comes back here is the API's own envelope, success or not.
|
|
15622
|
+
*/
|
|
15537
15623
|
async request(method, path, body) {
|
|
15538
15624
|
const url = `${this.baseUrl}${path}`;
|
|
15539
15625
|
const response = await this.fetchWithAuthRetry(method, url, body ? JSON.stringify(body) : void 0);
|
|
15540
|
-
const json = await
|
|
15626
|
+
const json = await (0, response_1.readJsonResponse)(response, url);
|
|
15541
15627
|
if (!response.ok || !json.success) {
|
|
15542
15628
|
const errorMessage = json.error?.message ?? `Request failed with status ${response.status}`;
|
|
15543
15629
|
const error = new Error(errorMessage);
|
|
@@ -15558,6 +15644,7 @@ var require_subscribe = __commonJS({
|
|
|
15558
15644
|
"use strict";
|
|
15559
15645
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
15560
15646
|
exports2.subscribe = subscribe;
|
|
15647
|
+
var response_1 = require_response();
|
|
15561
15648
|
var NULL_LOGGER = {
|
|
15562
15649
|
debug: () => {
|
|
15563
15650
|
},
|
|
@@ -15571,6 +15658,14 @@ var require_subscribe = __commonJS({
|
|
|
15571
15658
|
function sleep(ms) {
|
|
15572
15659
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
15573
15660
|
}
|
|
15661
|
+
function formatDuration(ms) {
|
|
15662
|
+
const seconds = Math.round(ms / 1e3);
|
|
15663
|
+
if (seconds < 60)
|
|
15664
|
+
return `${seconds}s`;
|
|
15665
|
+
const minutes = Math.floor(seconds / 60);
|
|
15666
|
+
const rest = seconds % 60;
|
|
15667
|
+
return rest === 0 ? `${minutes}m` : `${minutes}m ${rest}s`;
|
|
15668
|
+
}
|
|
15574
15669
|
function subscribe(opts) {
|
|
15575
15670
|
const logger = opts.logger ?? NULL_LOGGER;
|
|
15576
15671
|
const pollIntervalMs = opts.pollIntervalMs ?? 2e3;
|
|
@@ -15579,6 +15674,7 @@ var require_subscribe = __commonJS({
|
|
|
15579
15674
|
let pollTimer = null;
|
|
15580
15675
|
let inflight = 0;
|
|
15581
15676
|
let resolvedPoolIds = [];
|
|
15677
|
+
let unavailableSince = null;
|
|
15582
15678
|
async function start() {
|
|
15583
15679
|
if (!stopped)
|
|
15584
15680
|
return;
|
|
@@ -15629,6 +15725,10 @@ var require_subscribe = __commonJS({
|
|
|
15629
15725
|
limit: maxConcurrency - inflight,
|
|
15630
15726
|
sort: "priority:desc,queued_at:asc"
|
|
15631
15727
|
});
|
|
15728
|
+
if (unavailableSince !== null) {
|
|
15729
|
+
logger.info(`Sift is reachable again after ${formatDuration(Date.now() - unavailableSince)}`);
|
|
15730
|
+
unavailableSince = null;
|
|
15731
|
+
}
|
|
15632
15732
|
if (directives && Object.keys(directives).length > 0 && opts.onDirectives) {
|
|
15633
15733
|
try {
|
|
15634
15734
|
await opts.onDirectives(directives);
|
|
@@ -15649,7 +15749,20 @@ var require_subscribe = __commonJS({
|
|
|
15649
15749
|
});
|
|
15650
15750
|
}
|
|
15651
15751
|
} catch (err) {
|
|
15652
|
-
|
|
15752
|
+
if (err instanceof response_1.ServiceUnavailableError) {
|
|
15753
|
+
if (unavailableSince === null) {
|
|
15754
|
+
unavailableSince = Date.now();
|
|
15755
|
+
logger.warn(`Sift is unavailable (${err.host} answered ${err.statusCode}${err.statusText ? ` ${err.statusText}` : ""}). This is typical during a deployment window; the Sifter will keep trying.`);
|
|
15756
|
+
} else {
|
|
15757
|
+
logger.debug?.("Sift still unavailable", {
|
|
15758
|
+
host: err.host,
|
|
15759
|
+
status: err.statusCode,
|
|
15760
|
+
unavailableFor: formatDuration(Date.now() - unavailableSince)
|
|
15761
|
+
});
|
|
15762
|
+
}
|
|
15763
|
+
} else {
|
|
15764
|
+
logger.error("poll failed", { error: err instanceof Error ? err.message : String(err) });
|
|
15765
|
+
}
|
|
15653
15766
|
}
|
|
15654
15767
|
if (!stopped)
|
|
15655
15768
|
schedulePoll(pollIntervalMs);
|
|
@@ -15732,11 +15845,18 @@ var require_dist2 = __commonJS({
|
|
|
15732
15845
|
"../../packages/jobs/dist/index.js"(exports2) {
|
|
15733
15846
|
"use strict";
|
|
15734
15847
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
15735
|
-
exports2.subscribe = exports2.JobsClient = void 0;
|
|
15848
|
+
exports2.subscribe = exports2.ServiceUnavailableError = exports2.NonJsonResponseError = exports2.JobsClient = void 0;
|
|
15736
15849
|
var client_1 = require_client();
|
|
15737
15850
|
Object.defineProperty(exports2, "JobsClient", { enumerable: true, get: function() {
|
|
15738
15851
|
return client_1.JobsClient;
|
|
15739
15852
|
} });
|
|
15853
|
+
var response_1 = require_response();
|
|
15854
|
+
Object.defineProperty(exports2, "NonJsonResponseError", { enumerable: true, get: function() {
|
|
15855
|
+
return response_1.NonJsonResponseError;
|
|
15856
|
+
} });
|
|
15857
|
+
Object.defineProperty(exports2, "ServiceUnavailableError", { enumerable: true, get: function() {
|
|
15858
|
+
return response_1.ServiceUnavailableError;
|
|
15859
|
+
} });
|
|
15740
15860
|
var subscribe_1 = require_subscribe();
|
|
15741
15861
|
Object.defineProperty(exports2, "subscribe", { enumerable: true, get: function() {
|
|
15742
15862
|
return subscribe_1.subscribe;
|
|
@@ -22450,7 +22570,7 @@ var import_path = require("path");
|
|
|
22450
22570
|
var import_promises = require("fs/promises");
|
|
22451
22571
|
var import_yaml = __toESM(require_dist());
|
|
22452
22572
|
var import_shuttle = __toESM(require_dist5());
|
|
22453
|
-
var buildVersion = true ? "0.27.
|
|
22573
|
+
var buildVersion = true ? "0.27.5" : pkg.version;
|
|
22454
22574
|
var sifterBrand = {
|
|
22455
22575
|
product: {
|
|
22456
22576
|
id: "sifter",
|