@whittlelabs/sifter 0.30.9 → 0.30.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/bin.js +433 -120
- package/bin.js.map +4 -4
- package/package.json +1 -1
package/bin.js
CHANGED
|
@@ -11199,16 +11199,260 @@ var require_client = __commonJS({
|
|
|
11199
11199
|
}
|
|
11200
11200
|
});
|
|
11201
11201
|
|
|
11202
|
+
// ../../packages/keep/dist/rate-limited.js
|
|
11203
|
+
var require_rate_limited = __commonJS({
|
|
11204
|
+
"../../packages/keep/dist/rate-limited.js"(exports2) {
|
|
11205
|
+
"use strict";
|
|
11206
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11207
|
+
exports2.RateLimitGate = exports2.RATE_LIMIT_DEFAULT_MS = exports2.RATE_LIMIT_CAP_MS = exports2.RATE_LIMIT_FLOOR_MS = exports2.KeepRateLimitedError = void 0;
|
|
11208
|
+
exports2.retryAfterMsOf = retryAfterMsOf;
|
|
11209
|
+
var KeepRateLimitedError = class extends Error {
|
|
11210
|
+
code = "RATE_LIMITED";
|
|
11211
|
+
/** Host the exchange was sent to. */
|
|
11212
|
+
host;
|
|
11213
|
+
/** Keep's own words for the refusal ("Too many attempts. Please try again later."). */
|
|
11214
|
+
reason;
|
|
11215
|
+
/** How long from now to wait before asking again (ms), already floored and capped. */
|
|
11216
|
+
retryAfterMs;
|
|
11217
|
+
/** When the next exchange may be attempted (epoch ms). */
|
|
11218
|
+
retryAt;
|
|
11219
|
+
constructor(message, detail) {
|
|
11220
|
+
super(message);
|
|
11221
|
+
this.name = "KeepRateLimitedError";
|
|
11222
|
+
this.host = detail.host;
|
|
11223
|
+
this.reason = detail.reason;
|
|
11224
|
+
this.retryAt = detail.retryAt;
|
|
11225
|
+
this.retryAfterMs = Math.max(0, detail.retryAt - Date.now());
|
|
11226
|
+
}
|
|
11227
|
+
};
|
|
11228
|
+
exports2.KeepRateLimitedError = KeepRateLimitedError;
|
|
11229
|
+
exports2.RATE_LIMIT_FLOOR_MS = 5e3;
|
|
11230
|
+
exports2.RATE_LIMIT_CAP_MS = 15 * 6e4;
|
|
11231
|
+
exports2.RATE_LIMIT_DEFAULT_MS = 6e4;
|
|
11232
|
+
function retryAfterMsOf(body, headers, now = Date.now()) {
|
|
11233
|
+
return clamp(bodyRetryAfter(body) ?? headerRetryAfter(headers, now) ?? exports2.RATE_LIMIT_DEFAULT_MS);
|
|
11234
|
+
}
|
|
11235
|
+
function bodyRetryAfter(body) {
|
|
11236
|
+
const value = body?.error?.retryAfter;
|
|
11237
|
+
return typeof value === "number" && Number.isFinite(value) ? value * 1e3 : null;
|
|
11238
|
+
}
|
|
11239
|
+
function headerRetryAfter(headers, now) {
|
|
11240
|
+
const raw = headers?.get("retry-after")?.trim();
|
|
11241
|
+
if (!raw)
|
|
11242
|
+
return null;
|
|
11243
|
+
if (/^\d+$/.test(raw))
|
|
11244
|
+
return Number(raw) * 1e3;
|
|
11245
|
+
const at = Date.parse(raw);
|
|
11246
|
+
return Number.isNaN(at) ? null : at - now;
|
|
11247
|
+
}
|
|
11248
|
+
function clamp(ms) {
|
|
11249
|
+
return Math.min(exports2.RATE_LIMIT_CAP_MS, Math.max(exports2.RATE_LIMIT_FLOOR_MS, ms));
|
|
11250
|
+
}
|
|
11251
|
+
var RateLimitGate = class {
|
|
11252
|
+
closed = null;
|
|
11253
|
+
/** Record a 429 and return the error to throw for it. */
|
|
11254
|
+
close(detail) {
|
|
11255
|
+
const retryAt = Date.now() + detail.retryAfterMs;
|
|
11256
|
+
const when = new Date(retryAt).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
11257
|
+
this.closed = new KeepRateLimitedError(`[${detail.manager}] Keep at ${detail.host} is rate limiting this client's token exchange (429: ${detail.reason}); not asking again before ${when}`, { host: detail.host, reason: detail.reason, retryAt });
|
|
11258
|
+
return this.closed;
|
|
11259
|
+
}
|
|
11260
|
+
/** Throws the rate-limited error while the gate is closed; a no-op once the time has passed. */
|
|
11261
|
+
check() {
|
|
11262
|
+
const closed = this.closed;
|
|
11263
|
+
if (closed === null)
|
|
11264
|
+
return;
|
|
11265
|
+
if (Date.now() >= closed.retryAt) {
|
|
11266
|
+
this.closed = null;
|
|
11267
|
+
return;
|
|
11268
|
+
}
|
|
11269
|
+
throw new KeepRateLimitedError(closed.message, {
|
|
11270
|
+
host: closed.host,
|
|
11271
|
+
reason: closed.reason,
|
|
11272
|
+
retryAt: closed.retryAt
|
|
11273
|
+
});
|
|
11274
|
+
}
|
|
11275
|
+
};
|
|
11276
|
+
exports2.RateLimitGate = RateLimitGate;
|
|
11277
|
+
}
|
|
11278
|
+
});
|
|
11279
|
+
|
|
11280
|
+
// ../../packages/keep/dist/exchange.js
|
|
11281
|
+
var require_exchange = __commonJS({
|
|
11282
|
+
"../../packages/keep/dist/exchange.js"(exports2) {
|
|
11283
|
+
"use strict";
|
|
11284
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11285
|
+
exports2.KeepUnavailableError = void 0;
|
|
11286
|
+
exports2.exchangeCredentials = exchangeCredentials;
|
|
11287
|
+
exports2.hostOf = hostOf;
|
|
11288
|
+
var rate_limited_1 = require_rate_limited();
|
|
11289
|
+
var KeepUnavailableError = class extends Error {
|
|
11290
|
+
code = "SERVICE_UNAVAILABLE";
|
|
11291
|
+
/** Host the exchange was sent to, so a log line names the service that is down. */
|
|
11292
|
+
host;
|
|
11293
|
+
/** The status whatever answered sent, or null when nothing answered at all. */
|
|
11294
|
+
statusCode;
|
|
11295
|
+
constructor(message, detail) {
|
|
11296
|
+
super(message, detail.cause !== void 0 ? { cause: detail.cause } : void 0);
|
|
11297
|
+
this.name = "KeepUnavailableError";
|
|
11298
|
+
this.host = detail.host;
|
|
11299
|
+
this.statusCode = detail.statusCode;
|
|
11300
|
+
}
|
|
11301
|
+
};
|
|
11302
|
+
exports2.KeepUnavailableError = KeepUnavailableError;
|
|
11303
|
+
async function exchangeCredentials(request) {
|
|
11304
|
+
const { manager, url } = request;
|
|
11305
|
+
const host = hostOf(url);
|
|
11306
|
+
let response;
|
|
11307
|
+
try {
|
|
11308
|
+
response = await fetch(url, {
|
|
11309
|
+
method: "POST",
|
|
11310
|
+
headers: { "Content-Type": "application/json" },
|
|
11311
|
+
body: JSON.stringify({
|
|
11312
|
+
clientId: request.clientId,
|
|
11313
|
+
clientSecret: request.clientSecret
|
|
11314
|
+
})
|
|
11315
|
+
});
|
|
11316
|
+
} catch (err) {
|
|
11317
|
+
throw new KeepUnavailableError(`[${manager}] could not reach Keep at ${host}: ${describeTransportError(err)}`, { host, statusCode: null, cause: err });
|
|
11318
|
+
}
|
|
11319
|
+
request.onResponse?.(response);
|
|
11320
|
+
const text = await response.text().catch(() => "");
|
|
11321
|
+
let json;
|
|
11322
|
+
try {
|
|
11323
|
+
json = JSON.parse(text);
|
|
11324
|
+
} catch {
|
|
11325
|
+
json = null;
|
|
11326
|
+
}
|
|
11327
|
+
if (response.status >= 500) {
|
|
11328
|
+
const reason = json?.error?.message ?? `${request.exchangeName} failed with status ${response.status}`;
|
|
11329
|
+
throw new KeepUnavailableError(`[${manager}] Keep at ${host} is unavailable (${response.status}): ${reason}`, { host, statusCode: response.status });
|
|
11330
|
+
}
|
|
11331
|
+
if (response.status === 429) {
|
|
11332
|
+
throw request.rateLimit.close({
|
|
11333
|
+
manager,
|
|
11334
|
+
host,
|
|
11335
|
+
reason: json?.error?.message ?? "Too Many Requests",
|
|
11336
|
+
retryAfterMs: (0, rate_limited_1.retryAfterMsOf)(json, response.headers)
|
|
11337
|
+
});
|
|
11338
|
+
}
|
|
11339
|
+
if (json === null) {
|
|
11340
|
+
throw new Error(`[${manager}] Keep at ${host} answered ${response.status} with a body that is not JSON`);
|
|
11341
|
+
}
|
|
11342
|
+
if (!response.ok || !json.success) {
|
|
11343
|
+
const msg = json.error?.message ?? `${request.exchangeName} failed with status ${response.status}`;
|
|
11344
|
+
if (response.status === 401 && request.refused) {
|
|
11345
|
+
throw request.refused(msg);
|
|
11346
|
+
}
|
|
11347
|
+
throw new Error(`[${manager}] ${msg}`);
|
|
11348
|
+
}
|
|
11349
|
+
return json.data;
|
|
11350
|
+
}
|
|
11351
|
+
function hostOf(url) {
|
|
11352
|
+
try {
|
|
11353
|
+
return new URL(url).host;
|
|
11354
|
+
} catch {
|
|
11355
|
+
return url;
|
|
11356
|
+
}
|
|
11357
|
+
}
|
|
11358
|
+
function describeTransportError(err) {
|
|
11359
|
+
if (err instanceof Error) {
|
|
11360
|
+
const cause = err.cause;
|
|
11361
|
+
if (cause instanceof Error && cause.message && cause.message !== err.message) {
|
|
11362
|
+
return `${err.message}: ${cause.message}`;
|
|
11363
|
+
}
|
|
11364
|
+
return err.message;
|
|
11365
|
+
}
|
|
11366
|
+
return String(err);
|
|
11367
|
+
}
|
|
11368
|
+
}
|
|
11369
|
+
});
|
|
11370
|
+
|
|
11371
|
+
// ../../packages/keep/dist/wait-for-token.js
|
|
11372
|
+
var require_wait_for_token = __commonJS({
|
|
11373
|
+
"../../packages/keep/dist/wait-for-token.js"(exports2) {
|
|
11374
|
+
"use strict";
|
|
11375
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11376
|
+
exports2.waitForKeepToken = waitForKeepToken;
|
|
11377
|
+
var WAIT_FOR_TOKEN_MAX_MS = 20 * 6e4;
|
|
11378
|
+
var INITIAL_DELAY_MS = 1e3;
|
|
11379
|
+
var MAX_DELAY_MS = 3e4;
|
|
11380
|
+
async function waitForKeepToken(getToken, options) {
|
|
11381
|
+
const logger = options.logger ?? console;
|
|
11382
|
+
const initialDelay = options.initialDelayMs ?? INITIAL_DELAY_MS;
|
|
11383
|
+
const maxDelay = options.maxDelayMs ?? MAX_DELAY_MS;
|
|
11384
|
+
const started = Date.now();
|
|
11385
|
+
const deadline = started + (options.maxWaitMs ?? WAIT_FOR_TOKEN_MAX_MS);
|
|
11386
|
+
const tag = `[${options.label}]`;
|
|
11387
|
+
let delay = initialDelay;
|
|
11388
|
+
let waiting = null;
|
|
11389
|
+
for (; ; ) {
|
|
11390
|
+
let pause;
|
|
11391
|
+
try {
|
|
11392
|
+
const token = await getToken();
|
|
11393
|
+
if (waiting !== null) {
|
|
11394
|
+
logger.info(`${tag} Keep issued a token after ${formatDuration(Date.now() - started)} of waiting`);
|
|
11395
|
+
}
|
|
11396
|
+
return token;
|
|
11397
|
+
} catch (err) {
|
|
11398
|
+
if (isRateLimited(err)) {
|
|
11399
|
+
pause = Math.max(0, err.retryAfterMs);
|
|
11400
|
+
delay = initialDelay;
|
|
11401
|
+
if (waiting !== "rate-limited") {
|
|
11402
|
+
waiting = "rate-limited";
|
|
11403
|
+
logger.warn(`${tag} Keep is rate limiting this client's token exchange (${err.message}). The credentials are not in question; waiting ${formatDuration(pause)} to ask again.`);
|
|
11404
|
+
}
|
|
11405
|
+
} else if (isUnavailable(err)) {
|
|
11406
|
+
pause = delay;
|
|
11407
|
+
delay = Math.min(delay * 2, maxDelay);
|
|
11408
|
+
if (waiting !== "unavailable") {
|
|
11409
|
+
waiting = "unavailable";
|
|
11410
|
+
logger.warn(`${tag} Keep is unavailable (${err.message}); retrying with backoff.`);
|
|
11411
|
+
}
|
|
11412
|
+
} else {
|
|
11413
|
+
throw err;
|
|
11414
|
+
}
|
|
11415
|
+
if (Date.now() + pause > deadline) {
|
|
11416
|
+
logger.error(`${tag} giving up on a Keep token after ${formatDuration(Date.now() - started)}: ${err.message}`);
|
|
11417
|
+
throw err;
|
|
11418
|
+
}
|
|
11419
|
+
}
|
|
11420
|
+
await new Promise((resolve) => setTimeout(resolve, pause));
|
|
11421
|
+
}
|
|
11422
|
+
}
|
|
11423
|
+
function isRateLimited(err) {
|
|
11424
|
+
const e = err;
|
|
11425
|
+
return e?.code === "RATE_LIMITED" && typeof e.retryAfterMs === "number";
|
|
11426
|
+
}
|
|
11427
|
+
function isUnavailable(err) {
|
|
11428
|
+
return err?.code === "SERVICE_UNAVAILABLE";
|
|
11429
|
+
}
|
|
11430
|
+
function formatDuration(ms) {
|
|
11431
|
+
const s = Math.round(ms / 1e3);
|
|
11432
|
+
if (s < 60)
|
|
11433
|
+
return `${s}s`;
|
|
11434
|
+
const m = Math.floor(s / 60);
|
|
11435
|
+
const rest = s % 60;
|
|
11436
|
+
return rest === 0 ? `${m}m` : `${m}m${rest}s`;
|
|
11437
|
+
}
|
|
11438
|
+
}
|
|
11439
|
+
});
|
|
11440
|
+
|
|
11202
11441
|
// ../../packages/keep/dist/service-token.js
|
|
11203
11442
|
var require_service_token = __commonJS({
|
|
11204
11443
|
"../../packages/keep/dist/service-token.js"(exports2) {
|
|
11205
11444
|
"use strict";
|
|
11206
11445
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11207
11446
|
exports2.ServiceTokenManager = void 0;
|
|
11447
|
+
var rate_limited_1 = require_rate_limited();
|
|
11448
|
+
var exchange_1 = require_exchange();
|
|
11449
|
+
var wait_for_token_1 = require_wait_for_token();
|
|
11208
11450
|
var ServiceTokenManager = class {
|
|
11209
11451
|
token = null;
|
|
11210
11452
|
expiresAt = 0;
|
|
11211
11453
|
pendingExchange = null;
|
|
11454
|
+
/** Closed by a 429 until Keep's retry-after: no exchange is sent before it. */
|
|
11455
|
+
rateLimit = new rate_limited_1.RateLimitGate();
|
|
11212
11456
|
keepApiUrl;
|
|
11213
11457
|
clientId;
|
|
11214
11458
|
clientSecret;
|
|
@@ -11227,6 +11471,14 @@ var require_service_token = __commonJS({
|
|
|
11227
11471
|
/**
|
|
11228
11472
|
* Returns a valid service token, refreshing if needed.
|
|
11229
11473
|
* Returns null if Keep credentials are not configured (graceful degradation for local dev).
|
|
11474
|
+
*
|
|
11475
|
+
* Throws `KeepUnavailableError` when Keep did not answer or answered 5xx,
|
|
11476
|
+
* `KeepRateLimitedError` when Keep's exchange limiter locked this client out
|
|
11477
|
+
* (and, until the time Keep named, without asking again), and a plain `Error`
|
|
11478
|
+
* for any other refusal, a 401 above all. A refresh that fails for either
|
|
11479
|
+
* of the first two reasons while the cached token has not yet expired
|
|
11480
|
+
* answers with the cached token instead: the refresh starts 30s early
|
|
11481
|
+
* precisely so a failed one costs nothing.
|
|
11230
11482
|
*/
|
|
11231
11483
|
async getToken() {
|
|
11232
11484
|
if (!this.enabled)
|
|
@@ -11237,35 +11489,51 @@ var require_service_token = __commonJS({
|
|
|
11237
11489
|
if (this.pendingExchange) {
|
|
11238
11490
|
return this.pendingExchange;
|
|
11239
11491
|
}
|
|
11240
|
-
this.pendingExchange = this.
|
|
11492
|
+
this.pendingExchange = this.refresh();
|
|
11241
11493
|
try {
|
|
11242
11494
|
return await this.pendingExchange;
|
|
11243
11495
|
} finally {
|
|
11244
11496
|
this.pendingExchange = null;
|
|
11245
11497
|
}
|
|
11246
11498
|
}
|
|
11499
|
+
/**
|
|
11500
|
+
* `getToken`, for a service that cannot start without a token: waits out a
|
|
11501
|
+
* rate limit (for the time Keep named) and an outage (with backoff), bounded
|
|
11502
|
+
* by `maxWaitMs` (20 minutes by default, one full lockout and change), and
|
|
11503
|
+
* throws a refusal at once. See `waitForKeepToken`.
|
|
11504
|
+
*/
|
|
11505
|
+
waitForToken(options) {
|
|
11506
|
+
return (0, wait_for_token_1.waitForKeepToken)(() => this.getToken(), options);
|
|
11507
|
+
}
|
|
11508
|
+
async refresh() {
|
|
11509
|
+
try {
|
|
11510
|
+
this.rateLimit.check();
|
|
11511
|
+
return await this.exchange();
|
|
11512
|
+
} catch (err) {
|
|
11513
|
+
const code = err?.code;
|
|
11514
|
+
if (this.token && Date.now() < this.expiresAt - STALE_MARGIN_MS && (code === "SERVICE_UNAVAILABLE" || code === "RATE_LIMITED")) {
|
|
11515
|
+
return this.token;
|
|
11516
|
+
}
|
|
11517
|
+
throw err;
|
|
11518
|
+
}
|
|
11519
|
+
}
|
|
11247
11520
|
async exchange() {
|
|
11248
|
-
const
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
|
|
11254
|
-
|
|
11255
|
-
|
|
11521
|
+
const data = await (0, exchange_1.exchangeCredentials)({
|
|
11522
|
+
manager: "ServiceTokenManager",
|
|
11523
|
+
url: `${this.keepApiUrl}/api/service-tokens`,
|
|
11524
|
+
clientId: this.clientId,
|
|
11525
|
+
clientSecret: this.clientSecret,
|
|
11526
|
+
rateLimit: this.rateLimit,
|
|
11527
|
+
onResponse: this.onResponse,
|
|
11528
|
+
exchangeName: "Token exchange"
|
|
11256
11529
|
});
|
|
11257
|
-
this.
|
|
11258
|
-
|
|
11259
|
-
if (!response.ok || !json.success) {
|
|
11260
|
-
const msg = json.error?.message ?? `Token exchange failed with status ${response.status}`;
|
|
11261
|
-
throw new Error(`[ServiceTokenManager] ${msg}`);
|
|
11262
|
-
}
|
|
11263
|
-
this.token = json.data.token;
|
|
11264
|
-
this.expiresAt = Date.now() + json.data.expiresIn * 1e3;
|
|
11530
|
+
this.token = data.token;
|
|
11531
|
+
this.expiresAt = Date.now() + data.expiresIn * 1e3;
|
|
11265
11532
|
return this.token;
|
|
11266
11533
|
}
|
|
11267
11534
|
};
|
|
11268
11535
|
exports2.ServiceTokenManager = ServiceTokenManager;
|
|
11536
|
+
var STALE_MARGIN_MS = 5e3;
|
|
11269
11537
|
}
|
|
11270
11538
|
});
|
|
11271
11539
|
|
|
@@ -11274,7 +11542,9 @@ var require_agent_token = __commonJS({
|
|
|
11274
11542
|
"../../packages/keep/dist/agent-token.js"(exports2) {
|
|
11275
11543
|
"use strict";
|
|
11276
11544
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11277
|
-
exports2.AgentTokenManager = exports2.
|
|
11545
|
+
exports2.AgentTokenManager = exports2.AgentCredentialRevokedError = void 0;
|
|
11546
|
+
var rate_limited_1 = require_rate_limited();
|
|
11547
|
+
var exchange_1 = require_exchange();
|
|
11278
11548
|
var AgentCredentialRevokedError2 = class extends Error {
|
|
11279
11549
|
code = "PAIRING_REVOKED";
|
|
11280
11550
|
constructor(message) {
|
|
@@ -11283,24 +11553,12 @@ var require_agent_token = __commonJS({
|
|
|
11283
11553
|
}
|
|
11284
11554
|
};
|
|
11285
11555
|
exports2.AgentCredentialRevokedError = AgentCredentialRevokedError2;
|
|
11286
|
-
var KeepUnavailableError = class extends Error {
|
|
11287
|
-
code = "SERVICE_UNAVAILABLE";
|
|
11288
|
-
/** Host the exchange was sent to, so a log line names the service that is down. */
|
|
11289
|
-
host;
|
|
11290
|
-
/** The status whatever answered sent, or null when nothing answered at all. */
|
|
11291
|
-
statusCode;
|
|
11292
|
-
constructor(message, detail) {
|
|
11293
|
-
super(message, detail.cause !== void 0 ? { cause: detail.cause } : void 0);
|
|
11294
|
-
this.name = "KeepUnavailableError";
|
|
11295
|
-
this.host = detail.host;
|
|
11296
|
-
this.statusCode = detail.statusCode;
|
|
11297
|
-
}
|
|
11298
|
-
};
|
|
11299
|
-
exports2.KeepUnavailableError = KeepUnavailableError;
|
|
11300
11556
|
var AgentTokenManager = class {
|
|
11301
11557
|
token = null;
|
|
11302
11558
|
expiresAt = 0;
|
|
11303
11559
|
pendingExchange = null;
|
|
11560
|
+
/** Closed by a 429 until Keep's retry-after: no exchange is sent before it. */
|
|
11561
|
+
rateLimit = new rate_limited_1.RateLimitGate();
|
|
11304
11562
|
keepApiUrl;
|
|
11305
11563
|
clientId;
|
|
11306
11564
|
clientSecret;
|
|
@@ -11322,6 +11580,7 @@ var require_agent_token = __commonJS({
|
|
|
11322
11580
|
if (this.pendingExchange) {
|
|
11323
11581
|
return this.pendingExchange;
|
|
11324
11582
|
}
|
|
11583
|
+
this.rateLimit.check();
|
|
11325
11584
|
this.pendingExchange = this.exchange();
|
|
11326
11585
|
try {
|
|
11327
11586
|
return await this.pendingExchange;
|
|
@@ -11330,66 +11589,22 @@ var require_agent_token = __commonJS({
|
|
|
11330
11589
|
}
|
|
11331
11590
|
}
|
|
11332
11591
|
async exchange() {
|
|
11333
|
-
const
|
|
11334
|
-
|
|
11335
|
-
|
|
11336
|
-
|
|
11337
|
-
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
11341
|
-
|
|
11342
|
-
|
|
11343
|
-
|
|
11344
|
-
|
|
11345
|
-
} catch (err) {
|
|
11346
|
-
throw new KeepUnavailableError(`[AgentTokenManager] could not reach Keep at ${host}: ${describeTransportError(err)}`, { host, statusCode: null, cause: err });
|
|
11347
|
-
}
|
|
11348
|
-
this.onResponse?.(response);
|
|
11349
|
-
const text = await response.text().catch(() => "");
|
|
11350
|
-
let json;
|
|
11351
|
-
try {
|
|
11352
|
-
json = JSON.parse(text);
|
|
11353
|
-
} catch {
|
|
11354
|
-
json = null;
|
|
11355
|
-
}
|
|
11356
|
-
if (response.status >= 500) {
|
|
11357
|
-
const reason = json?.error?.message ?? `Agent token exchange failed with status ${response.status}`;
|
|
11358
|
-
throw new KeepUnavailableError(`[AgentTokenManager] Keep at ${host} is unavailable (${response.status}): ${reason}`, { host, statusCode: response.status });
|
|
11359
|
-
}
|
|
11360
|
-
if (json === null) {
|
|
11361
|
-
throw new Error(`[AgentTokenManager] Keep at ${host} answered ${response.status} with a body that is not JSON`);
|
|
11362
|
-
}
|
|
11363
|
-
if (!response.ok || !json.success) {
|
|
11364
|
-
const msg = json.error?.message ?? `Agent token exchange failed with status ${response.status}`;
|
|
11365
|
-
if (response.status === 401) {
|
|
11366
|
-
throw new AgentCredentialRevokedError2(`[AgentTokenManager] Keep refused this agent's credentials (401): the pairing was revoked or the secret rotated. Re-pair to continue.`);
|
|
11367
|
-
}
|
|
11368
|
-
throw new Error(`[AgentTokenManager] ${msg}`);
|
|
11369
|
-
}
|
|
11370
|
-
this.token = json.data.token;
|
|
11371
|
-
this.expiresAt = Date.now() + json.data.expiresIn * 1e3;
|
|
11592
|
+
const data = await (0, exchange_1.exchangeCredentials)({
|
|
11593
|
+
manager: "AgentTokenManager",
|
|
11594
|
+
url: `${this.keepApiUrl}/api/agent-tokens`,
|
|
11595
|
+
clientId: this.clientId,
|
|
11596
|
+
clientSecret: this.clientSecret,
|
|
11597
|
+
rateLimit: this.rateLimit,
|
|
11598
|
+
onResponse: this.onResponse,
|
|
11599
|
+
exchangeName: "Agent token exchange",
|
|
11600
|
+
refused: () => new AgentCredentialRevokedError2(`[AgentTokenManager] Keep refused this agent's credentials (401): the pairing was revoked or the secret rotated. Re-pair to continue.`)
|
|
11601
|
+
});
|
|
11602
|
+
this.token = data.token;
|
|
11603
|
+
this.expiresAt = Date.now() + data.expiresIn * 1e3;
|
|
11372
11604
|
return this.token;
|
|
11373
11605
|
}
|
|
11374
11606
|
};
|
|
11375
11607
|
exports2.AgentTokenManager = AgentTokenManager;
|
|
11376
|
-
function hostOf(url) {
|
|
11377
|
-
try {
|
|
11378
|
-
return new URL(url).host;
|
|
11379
|
-
} catch {
|
|
11380
|
-
return url;
|
|
11381
|
-
}
|
|
11382
|
-
}
|
|
11383
|
-
function describeTransportError(err) {
|
|
11384
|
-
if (err instanceof Error) {
|
|
11385
|
-
const cause = err.cause;
|
|
11386
|
-
if (cause instanceof Error && cause.message && cause.message !== err.message) {
|
|
11387
|
-
return `${err.message}: ${cause.message}`;
|
|
11388
|
-
}
|
|
11389
|
-
return err.message;
|
|
11390
|
-
}
|
|
11391
|
-
return String(err);
|
|
11392
|
-
}
|
|
11393
11608
|
}
|
|
11394
11609
|
});
|
|
11395
11610
|
|
|
@@ -11398,7 +11613,7 @@ var require_dist2 = __commonJS({
|
|
|
11398
11613
|
"../../packages/keep/dist/index.js"(exports2) {
|
|
11399
11614
|
"use strict";
|
|
11400
11615
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
11401
|
-
exports2.KeepUnavailableError = exports2.AgentCredentialRevokedError = exports2.AgentTokenManager = exports2.ServiceTokenManager = exports2.KeepClient = void 0;
|
|
11616
|
+
exports2.waitForKeepToken = exports2.KeepRateLimitedError = exports2.KeepUnavailableError = exports2.AgentCredentialRevokedError = exports2.AgentTokenManager = exports2.ServiceTokenManager = exports2.KeepClient = void 0;
|
|
11402
11617
|
var client_1 = require_client();
|
|
11403
11618
|
Object.defineProperty(exports2, "KeepClient", { enumerable: true, get: function() {
|
|
11404
11619
|
return client_1.KeepClient;
|
|
@@ -11414,8 +11629,17 @@ var require_dist2 = __commonJS({
|
|
|
11414
11629
|
Object.defineProperty(exports2, "AgentCredentialRevokedError", { enumerable: true, get: function() {
|
|
11415
11630
|
return agent_token_1.AgentCredentialRevokedError;
|
|
11416
11631
|
} });
|
|
11632
|
+
var exchange_1 = require_exchange();
|
|
11417
11633
|
Object.defineProperty(exports2, "KeepUnavailableError", { enumerable: true, get: function() {
|
|
11418
|
-
return
|
|
11634
|
+
return exchange_1.KeepUnavailableError;
|
|
11635
|
+
} });
|
|
11636
|
+
var rate_limited_1 = require_rate_limited();
|
|
11637
|
+
Object.defineProperty(exports2, "KeepRateLimitedError", { enumerable: true, get: function() {
|
|
11638
|
+
return rate_limited_1.KeepRateLimitedError;
|
|
11639
|
+
} });
|
|
11640
|
+
var wait_for_token_1 = require_wait_for_token();
|
|
11641
|
+
Object.defineProperty(exports2, "waitForKeepToken", { enumerable: true, get: function() {
|
|
11642
|
+
return wait_for_token_1.waitForKeepToken;
|
|
11419
11643
|
} });
|
|
11420
11644
|
}
|
|
11421
11645
|
});
|
|
@@ -12282,6 +12506,10 @@ var require_checks = __commonJS({
|
|
|
12282
12506
|
return skip("pairing-live", "no readable pairing; see pairing-present");
|
|
12283
12507
|
}
|
|
12284
12508
|
const minted = await probes.mintAgentToken(stored.value);
|
|
12509
|
+
if (!minted.ok && minted.rateLimited) {
|
|
12510
|
+
const at = formatInstant(minted.rateLimited.retryAt);
|
|
12511
|
+
return warn("pairing-live", `Keep is rate limiting this pairing's token exchange (429), so the pairing could not be checked; it asked for no retry before ${at}`, subject.phase === "run" ? `nothing to do; \`run\` waits until ${at}, asks once, and starts claiming when Keep issues a token` : `wait until ${at}, then run doctor again`);
|
|
12512
|
+
}
|
|
12285
12513
|
if (!minted.ok && minted.unavailable) {
|
|
12286
12514
|
return warn("pairing-live", `Keep did not answer, so the pairing could not be checked: ${oneLine(minted.error).replace(/^\[AgentTokenManager\]\s*/, "")}`, subject.phase === "run" ? "nothing to do if this is a deployment window; `run` waits for Keep and starts claiming when it answers" : `check ${stored.value.keepApiUrl} is reachable, then run doctor again`);
|
|
12287
12515
|
}
|
|
@@ -12339,6 +12567,9 @@ var require_checks = __commonJS({
|
|
|
12339
12567
|
const pairing = stored.value;
|
|
12340
12568
|
return withConfig("jobs-reachable", probes, async (config) => {
|
|
12341
12569
|
const result = await probes.reachJobs(config, pairing);
|
|
12570
|
+
if (!result.ok && result.rateLimited) {
|
|
12571
|
+
return warn("jobs-reachable", `${config.auth.jobsApiUrl} was not asked: Keep is rate limiting the token exchange until ${formatInstant(result.rateLimited.retryAt)}`, "see pairing-live; the run loop asks once Keep issues a token");
|
|
12572
|
+
}
|
|
12342
12573
|
if (!result.ok) {
|
|
12343
12574
|
return warn("jobs-reachable", `${config.auth.jobsApiUrl} did not answer: ${oneLine(result.error)}`, "nothing to do if this is a deployment window; the run loop will keep trying");
|
|
12344
12575
|
}
|
|
@@ -12620,6 +12851,9 @@ var require_checks = __commonJS({
|
|
|
12620
12851
|
function osTmpDirOf(probes) {
|
|
12621
12852
|
return probes.osTmpDir();
|
|
12622
12853
|
}
|
|
12854
|
+
function formatInstant(epochMs) {
|
|
12855
|
+
return new Date(epochMs).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
12856
|
+
}
|
|
12623
12857
|
function oneLine(message) {
|
|
12624
12858
|
return message.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).join(" ");
|
|
12625
12859
|
}
|
|
@@ -20320,6 +20554,20 @@ var require_subscribe = __commonJS({
|
|
|
20320
20554
|
return true;
|
|
20321
20555
|
return err instanceof TypeError && err.message === "fetch failed";
|
|
20322
20556
|
}
|
|
20557
|
+
function isRateLimited(err) {
|
|
20558
|
+
return err?.code === "RATE_LIMITED";
|
|
20559
|
+
}
|
|
20560
|
+
function rateLimitWaitMs(err) {
|
|
20561
|
+
const e = err ?? {};
|
|
20562
|
+
if (typeof e.retryAfterMs === "number" && Number.isFinite(e.retryAfterMs))
|
|
20563
|
+
return Math.max(0, e.retryAfterMs);
|
|
20564
|
+
if (typeof e.retryAt === "number" && Number.isFinite(e.retryAt))
|
|
20565
|
+
return Math.max(0, e.retryAt - Date.now());
|
|
20566
|
+
return 0;
|
|
20567
|
+
}
|
|
20568
|
+
function formatInstant(epochMs) {
|
|
20569
|
+
return new Date(epochMs).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
20570
|
+
}
|
|
20323
20571
|
function describeOutage(err) {
|
|
20324
20572
|
const e = err ?? {};
|
|
20325
20573
|
if (typeof e.host === "string" && typeof e.statusCode === "number") {
|
|
@@ -20386,11 +20634,33 @@ var require_subscribe = __commonJS({
|
|
|
20386
20634
|
let outcome = newOutcome();
|
|
20387
20635
|
let wakeStartup = null;
|
|
20388
20636
|
let unavailableSince = null;
|
|
20637
|
+
let rateLimited = null;
|
|
20389
20638
|
function noteReachable() {
|
|
20390
20639
|
if (unavailableSince !== null) {
|
|
20391
20640
|
logger.info(`Sift is reachable again after ${formatDuration(Date.now() - unavailableSince)}`);
|
|
20392
20641
|
unavailableSince = null;
|
|
20393
20642
|
}
|
|
20643
|
+
if (rateLimited !== null) {
|
|
20644
|
+
logger.info(`${rateLimited.host} stopped rate limiting the Sifter after ${formatDuration(Date.now() - rateLimited.since)}`);
|
|
20645
|
+
rateLimited = null;
|
|
20646
|
+
}
|
|
20647
|
+
}
|
|
20648
|
+
function noteRateLimited(err) {
|
|
20649
|
+
const waitMs = Math.max(pollIntervalMs, rateLimitWaitMs(err));
|
|
20650
|
+
const e = err ?? {};
|
|
20651
|
+
const host = typeof e.host === "string" ? e.host : "the service";
|
|
20652
|
+
if (rateLimited === null) {
|
|
20653
|
+
rateLimited = { since: Date.now(), host };
|
|
20654
|
+
const reason = typeof e.reason === "string" ? `: ${e.reason}` : "";
|
|
20655
|
+
logger.warn(`${host} is rate limiting the Sifter (429${reason}). It will wait and try again at ${formatInstant(Date.now() + waitMs)} (in ${formatDuration(waitMs)}).`);
|
|
20656
|
+
} else {
|
|
20657
|
+
logger.debug?.("still rate limited", {
|
|
20658
|
+
host,
|
|
20659
|
+
rateLimitedFor: formatDuration(Date.now() - rateLimited.since),
|
|
20660
|
+
nextAttemptIn: formatDuration(waitMs)
|
|
20661
|
+
});
|
|
20662
|
+
}
|
|
20663
|
+
return waitMs;
|
|
20394
20664
|
}
|
|
20395
20665
|
function noteUnavailable(err) {
|
|
20396
20666
|
if (unavailableSince === null) {
|
|
@@ -20420,16 +20690,22 @@ var require_subscribe = __commonJS({
|
|
|
20420
20690
|
}
|
|
20421
20691
|
async function untilAvailable(call, mySession) {
|
|
20422
20692
|
for (; ; ) {
|
|
20693
|
+
let pause = pollIntervalMs;
|
|
20423
20694
|
try {
|
|
20424
20695
|
const value = await call();
|
|
20425
20696
|
noteReachable();
|
|
20426
20697
|
return value;
|
|
20427
20698
|
} catch (err) {
|
|
20428
|
-
if (isFatal(err)
|
|
20699
|
+
if (isFatal(err))
|
|
20700
|
+
throw err;
|
|
20701
|
+
if (isRateLimited(err))
|
|
20702
|
+
pause = noteRateLimited(err);
|
|
20703
|
+
else if (isUnavailable(err))
|
|
20704
|
+
noteUnavailable(err);
|
|
20705
|
+
else
|
|
20429
20706
|
throw err;
|
|
20430
|
-
noteUnavailable(err);
|
|
20431
20707
|
}
|
|
20432
|
-
await startupPause(
|
|
20708
|
+
await startupPause(pause);
|
|
20433
20709
|
if (stopped || mySession !== session)
|
|
20434
20710
|
return STOPPED;
|
|
20435
20711
|
}
|
|
@@ -20515,6 +20791,7 @@ var require_subscribe = __commonJS({
|
|
|
20515
20791
|
async function poll(mySession) {
|
|
20516
20792
|
if (stopped || mySession !== session)
|
|
20517
20793
|
return;
|
|
20794
|
+
let nextPollMs = pollIntervalMs;
|
|
20518
20795
|
if (inflight >= maxConcurrency) {
|
|
20519
20796
|
schedulePoll(pollIntervalMs);
|
|
20520
20797
|
return;
|
|
@@ -20557,14 +20834,16 @@ var require_subscribe = __commonJS({
|
|
|
20557
20834
|
void fail(err);
|
|
20558
20835
|
return;
|
|
20559
20836
|
}
|
|
20560
|
-
if (
|
|
20837
|
+
if (isRateLimited(err)) {
|
|
20838
|
+
nextPollMs = noteRateLimited(err);
|
|
20839
|
+
} else if (isUnavailable(err)) {
|
|
20561
20840
|
noteUnavailable(err);
|
|
20562
20841
|
} else {
|
|
20563
20842
|
logger.error("poll failed", { error: err instanceof Error ? err.message : String(err) });
|
|
20564
20843
|
}
|
|
20565
20844
|
}
|
|
20566
20845
|
if (!stopped && mySession === session)
|
|
20567
|
-
schedulePoll(
|
|
20846
|
+
schedulePoll(nextPollMs);
|
|
20568
20847
|
}
|
|
20569
20848
|
async function runOnce(available) {
|
|
20570
20849
|
let dispatch;
|
|
@@ -21035,6 +21314,21 @@ var require_probes = __commonJS({
|
|
|
21035
21314
|
packageName: options.brand.product.packageName
|
|
21036
21315
|
});
|
|
21037
21316
|
};
|
|
21317
|
+
const managers = /* @__PURE__ */ new Map();
|
|
21318
|
+
const tokensFor = (pairing) => {
|
|
21319
|
+
const key = JSON.stringify([pairing.keepApiUrl, pairing.credentials.clientId, pairing.credentials.clientSecret]);
|
|
21320
|
+
let tokens = managers.get(key);
|
|
21321
|
+
if (tokens === void 0) {
|
|
21322
|
+
tokens = new keep_1.AgentTokenManager({
|
|
21323
|
+
keepApiUrl: pairing.keepApiUrl,
|
|
21324
|
+
clientId: pairing.credentials.clientId,
|
|
21325
|
+
clientSecret: pairing.credentials.clientSecret,
|
|
21326
|
+
onResponse: enforceFloor
|
|
21327
|
+
});
|
|
21328
|
+
managers.set(key, tokens);
|
|
21329
|
+
}
|
|
21330
|
+
return tokens;
|
|
21331
|
+
};
|
|
21038
21332
|
let pairingRead;
|
|
21039
21333
|
let configRead;
|
|
21040
21334
|
let scaffoldedRead;
|
|
@@ -21163,12 +21457,7 @@ var require_probes = __commonJS({
|
|
|
21163
21457
|
return scaffoldedRead;
|
|
21164
21458
|
},
|
|
21165
21459
|
async mintAgentToken(pairing) {
|
|
21166
|
-
const tokens =
|
|
21167
|
-
keepApiUrl: pairing.keepApiUrl,
|
|
21168
|
-
clientId: pairing.credentials.clientId,
|
|
21169
|
-
clientSecret: pairing.credentials.clientSecret,
|
|
21170
|
-
onResponse: enforceFloor
|
|
21171
|
-
});
|
|
21460
|
+
const tokens = tokensFor(pairing);
|
|
21172
21461
|
try {
|
|
21173
21462
|
const token = await tokens.getToken();
|
|
21174
21463
|
if (token === null) {
|
|
@@ -21178,16 +21467,14 @@ var require_probes = __commonJS({
|
|
|
21178
21467
|
} catch (err) {
|
|
21179
21468
|
if (isRevoked(err) || isUpgradeRequired(err))
|
|
21180
21469
|
throw err;
|
|
21470
|
+
if (isKeepRateLimited(err)) {
|
|
21471
|
+
return { ok: false, error: describe(err), rateLimited: { retryAt: err.retryAt } };
|
|
21472
|
+
}
|
|
21181
21473
|
return { ok: false, error: describe(err), ...isKeepUnavailable(err) ? { unavailable: true } : {} };
|
|
21182
21474
|
}
|
|
21183
21475
|
},
|
|
21184
21476
|
async reachJobs(config, pairing) {
|
|
21185
|
-
const tokens =
|
|
21186
|
-
keepApiUrl: pairing.keepApiUrl,
|
|
21187
|
-
clientId: pairing.credentials.clientId,
|
|
21188
|
-
clientSecret: pairing.credentials.clientSecret,
|
|
21189
|
-
onResponse: enforceFloor
|
|
21190
|
-
});
|
|
21477
|
+
const tokens = tokensFor(pairing);
|
|
21191
21478
|
const client = new jobs_1.JobsClient({
|
|
21192
21479
|
baseUrl: config.auth.jobsApiUrl,
|
|
21193
21480
|
...config.auth.apiKey ? { apiKey: config.auth.apiKey } : {},
|
|
@@ -21204,6 +21491,9 @@ var require_probes = __commonJS({
|
|
|
21204
21491
|
} catch (err) {
|
|
21205
21492
|
if (isRevoked(err) || isUpgradeRequired(err))
|
|
21206
21493
|
throw err;
|
|
21494
|
+
if (isKeepRateLimited(err)) {
|
|
21495
|
+
return { ok: false, error: describe(err), rateLimited: { retryAt: err.retryAt } };
|
|
21496
|
+
}
|
|
21207
21497
|
return { ok: false, error: describe(err) };
|
|
21208
21498
|
}
|
|
21209
21499
|
},
|
|
@@ -21299,6 +21589,9 @@ var require_probes = __commonJS({
|
|
|
21299
21589
|
function isKeepUnavailable(err) {
|
|
21300
21590
|
return err instanceof Error && err.name === "KeepUnavailableError";
|
|
21301
21591
|
}
|
|
21592
|
+
function isKeepRateLimited(err) {
|
|
21593
|
+
return err instanceof Error && err.name === "KeepRateLimitedError";
|
|
21594
|
+
}
|
|
21302
21595
|
function isUpgradeRequired(err) {
|
|
21303
21596
|
return err instanceof Error && err.name === "UpgradeRequiredError";
|
|
21304
21597
|
}
|
|
@@ -25442,6 +25735,12 @@ var require_shuttle = __commonJS({
|
|
|
25442
25735
|
function isKeepUnavailable(err) {
|
|
25443
25736
|
return err instanceof Error && err.name === "KeepUnavailableError";
|
|
25444
25737
|
}
|
|
25738
|
+
function isKeepRateLimited(err) {
|
|
25739
|
+
return err instanceof Error && err.name === "KeepRateLimitedError";
|
|
25740
|
+
}
|
|
25741
|
+
function formatInstant(epochMs) {
|
|
25742
|
+
return new Date(epochMs).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
25743
|
+
}
|
|
25445
25744
|
async function runOutputGates(dispatch, response, executor, signal, ctx) {
|
|
25446
25745
|
let spec;
|
|
25447
25746
|
try {
|
|
@@ -25897,30 +26196,44 @@ var require_shuttle = __commonJS({
|
|
|
25897
26196
|
}
|
|
25898
26197
|
async function mintWaitingOutKeep(mint, brand, options) {
|
|
25899
26198
|
const maxDelay = options.retryMaxMs ?? KEEP_RETRY_MAX_MS;
|
|
25900
|
-
|
|
25901
|
-
let
|
|
26199
|
+
const initialDelay = options.retryInitialMs ?? KEEP_RETRY_INITIAL_MS;
|
|
26200
|
+
let delay = initialDelay;
|
|
26201
|
+
let waiting = null;
|
|
25902
26202
|
for (; ; ) {
|
|
26203
|
+
let pause;
|
|
25903
26204
|
try {
|
|
25904
26205
|
const token = await mint();
|
|
25905
|
-
if (
|
|
25906
|
-
options.logger?.info(`Keep is reachable again after ${formatDuration(Date.now() -
|
|
26206
|
+
if (waiting?.kind === "unavailable") {
|
|
26207
|
+
options.logger?.info(`Keep is reachable again after ${formatDuration(Date.now() - waiting.since)}`);
|
|
26208
|
+
} else if (waiting?.kind === "rate-limited") {
|
|
26209
|
+
options.logger?.info(`Keep issued a token; the rate limit lifted after ${formatDuration(Date.now() - waiting.since)}`);
|
|
25907
26210
|
}
|
|
25908
26211
|
return token;
|
|
25909
26212
|
} catch (err) {
|
|
25910
|
-
if (
|
|
26213
|
+
if (isKeepRateLimited(err)) {
|
|
26214
|
+
if (waiting?.kind !== "rate-limited") {
|
|
26215
|
+
waiting = { kind: "rate-limited", since: Date.now() };
|
|
26216
|
+
options.logger?.warn(`Keep is rate limiting this ${brand.product.title}'s token exchange (${err.host ?? "Keep"} answered 429: ${err.reason ?? err.message}). The credentials are not in question; the ${brand.product.title} will wait and ask again at ${formatInstant(err.retryAt)} (in ${formatDuration(err.retryAfterMs)}), and start when Keep issues a token.`);
|
|
26217
|
+
}
|
|
26218
|
+
pause = err.retryAfterMs;
|
|
26219
|
+
delay = initialDelay;
|
|
26220
|
+
} else if (isKeepUnavailable(err)) {
|
|
26221
|
+
if (waiting?.kind !== "unavailable") {
|
|
26222
|
+
waiting = { kind: "unavailable", since: Date.now() };
|
|
26223
|
+
const e = err;
|
|
26224
|
+
const what = typeof e.statusCode === "number" ? `${e.host ?? "Keep"} answered ${e.statusCode}` : `${e.host ?? "Keep"} did not answer`;
|
|
26225
|
+
options.logger?.warn(`Keep is unavailable (${what}). This is typical during a deployment window; the ${brand.product.title} will wait for it and start when it answers.`);
|
|
26226
|
+
}
|
|
26227
|
+
pause = delay;
|
|
26228
|
+
delay = Math.min(delay * 2, maxDelay);
|
|
26229
|
+
} else {
|
|
25911
26230
|
throw err;
|
|
25912
|
-
if (unavailableSince === null) {
|
|
25913
|
-
unavailableSince = Date.now();
|
|
25914
|
-
const e = err;
|
|
25915
|
-
const what = typeof e.statusCode === "number" ? `${e.host ?? "Keep"} answered ${e.statusCode}` : `${e.host ?? "Keep"} did not answer`;
|
|
25916
|
-
options.logger?.warn(`Keep is unavailable (${what}). This is typical during a deployment window; the ${brand.product.title} will wait for it and start when it answers.`);
|
|
25917
26231
|
}
|
|
25918
26232
|
}
|
|
25919
|
-
await abortableSleep(
|
|
26233
|
+
await abortableSleep(pause, options.signal);
|
|
25920
26234
|
if (options.signal?.aborted) {
|
|
25921
26235
|
throw options.signal.reason instanceof Error ? options.signal.reason : new Error("stopped while waiting for Keep");
|
|
25922
26236
|
}
|
|
25923
|
-
delay = Math.min(delay * 2, maxDelay);
|
|
25924
26237
|
}
|
|
25925
26238
|
}
|
|
25926
26239
|
}
|
|
@@ -26548,7 +26861,7 @@ var import_path = require("path");
|
|
|
26548
26861
|
var import_promises = require("fs/promises");
|
|
26549
26862
|
var import_yaml = __toESM(require_dist3());
|
|
26550
26863
|
var import_shuttle = __toESM(require_dist5());
|
|
26551
|
-
var buildVersion = true ? "0.30.
|
|
26864
|
+
var buildVersion = true ? "0.30.11" : pkg.version;
|
|
26552
26865
|
var sifterBrand = {
|
|
26553
26866
|
product: {
|
|
26554
26867
|
id: "sifter",
|