@whittlelabs/sifter 0.30.18 → 0.30.19

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 +81 -5
  2. package/bin.js.map +4 -4
  3. package/package.json +1 -1
package/bin.js CHANGED
@@ -11433,6 +11433,69 @@ var require_exchange = __commonJS({
11433
11433
  }
11434
11434
  });
11435
11435
 
11436
+ // ../../packages/keep/dist/refusal-budget.js
11437
+ var require_refusal_budget = __commonJS({
11438
+ "../../packages/keep/dist/refusal-budget.js"(exports2) {
11439
+ "use strict";
11440
+ Object.defineProperty(exports2, "__esModule", { value: true });
11441
+ exports2.RefusalBudget = exports2.REFUSAL_SPAN_MS = exports2.REFUSED_EXCHANGES_PER_SPAN = exports2.KeepCredentialsRefusedError = void 0;
11442
+ var KeepCredentialsRefusedError = class extends Error {
11443
+ code = "CREDENTIALS_REFUSED";
11444
+ /** Host the exchange was sent to. */
11445
+ host;
11446
+ /** When the manager will next send an exchange for these credentials (epoch ms). */
11447
+ retryAt;
11448
+ /** How long from now that is (ms); zero while the budget has room. */
11449
+ retryAfterMs;
11450
+ constructor(message, detail) {
11451
+ super(message);
11452
+ this.name = "KeepCredentialsRefusedError";
11453
+ this.host = detail.host;
11454
+ this.retryAt = detail.retryAt;
11455
+ this.retryAfterMs = Math.max(0, detail.retryAt - Date.now());
11456
+ }
11457
+ };
11458
+ exports2.KeepCredentialsRefusedError = KeepCredentialsRefusedError;
11459
+ var KEEP_EXCHANGE_WINDOW_MS = 15 * 6e4;
11460
+ exports2.REFUSED_EXCHANGES_PER_SPAN = 3;
11461
+ exports2.REFUSAL_SPAN_MS = KEEP_EXCHANGE_WINDOW_MS + 3e4;
11462
+ var RefusalBudget = class {
11463
+ refusedAt = [];
11464
+ last = null;
11465
+ /** Throws the last refusal while the budget is spent; a no-op while it has room. */
11466
+ check() {
11467
+ const last = this.last;
11468
+ if (last === null)
11469
+ return;
11470
+ const retryAt = this.nextExchangeAt();
11471
+ if (Date.now() >= retryAt)
11472
+ return;
11473
+ const when = new Date(retryAt).toISOString().replace(/\.\d{3}Z$/, "Z");
11474
+ throw new KeepCredentialsRefusedError(`${last.message} (refused ${this.refusedAt.length} times in ${exports2.REFUSAL_SPAN_MS / 6e4} minutes; not asking Keep again before ${when})`, { host: last.host, retryAt });
11475
+ }
11476
+ /** Record a 401 and return the error to throw for it. */
11477
+ refuse(detail) {
11478
+ this.refusedAt.push(Date.now());
11479
+ this.last = new KeepCredentialsRefusedError(detail.message, { host: detail.host, retryAt: this.nextExchangeAt() });
11480
+ return this.last;
11481
+ }
11482
+ /** Keep issued a token, which clears its count; so does this. */
11483
+ clear() {
11484
+ this.refusedAt = [];
11485
+ this.last = null;
11486
+ }
11487
+ nextExchangeAt() {
11488
+ const now = Date.now();
11489
+ this.refusedAt = this.refusedAt.filter((at) => now - at < exports2.REFUSAL_SPAN_MS);
11490
+ if (this.refusedAt.length < exports2.REFUSED_EXCHANGES_PER_SPAN)
11491
+ return now;
11492
+ return this.refusedAt[this.refusedAt.length - exports2.REFUSED_EXCHANGES_PER_SPAN] + exports2.REFUSAL_SPAN_MS;
11493
+ }
11494
+ };
11495
+ exports2.RefusalBudget = RefusalBudget;
11496
+ }
11497
+ });
11498
+
11436
11499
  // ../../packages/keep/dist/wait-for-token.js
11437
11500
  var require_wait_for_token = __commonJS({
11438
11501
  "../../packages/keep/dist/wait-for-token.js"(exports2) {
@@ -11511,6 +11574,7 @@ var require_service_token = __commonJS({
11511
11574
  exports2.ServiceTokenManager = void 0;
11512
11575
  var rate_limited_1 = require_rate_limited();
11513
11576
  var exchange_1 = require_exchange();
11577
+ var refusal_budget_1 = require_refusal_budget();
11514
11578
  var wait_for_token_1 = require_wait_for_token();
11515
11579
  var ServiceTokenManager = class {
11516
11580
  token = null;
@@ -11518,6 +11582,8 @@ var require_service_token = __commonJS({
11518
11582
  pendingExchange = null;
11519
11583
  /** Closed by a 429 until Keep's retry-after: no exchange is sent before it. */
11520
11584
  rateLimit = new rate_limited_1.RateLimitGate();
11585
+ /** Spent by refused exchanges: past it, no exchange is sent until the oldest ages out. */
11586
+ refusals = new refusal_budget_1.RefusalBudget();
11521
11587
  keepApiUrl;
11522
11588
  clientId;
11523
11589
  clientSecret;
@@ -11539,8 +11605,11 @@ var require_service_token = __commonJS({
11539
11605
  *
11540
11606
  * Throws `KeepUnavailableError` when Keep did not answer or answered 5xx,
11541
11607
  * `KeepRateLimitedError` when Keep's exchange limiter locked this client out
11542
- * (and, until the time Keep named, without asking again), and a plain `Error`
11543
- * for any other refusal, a 401 above all. A refresh that fails for either
11608
+ * (and, until the time Keep named, without asking again),
11609
+ * `KeepCredentialsRefusedError` for a 401 (and, once three fall inside one of
11610
+ * Keep's lockout windows, without asking again until the oldest ages out:
11611
+ * see `RefusalBudget`), and a plain `Error` for any other refusal. A refresh
11612
+ * that fails for either
11544
11613
  * of the first two reasons while the cached token has not yet expired
11545
11614
  * answers with the cached token instead: the refresh starts 30s early
11546
11615
  * precisely so a failed one costs nothing.
@@ -11573,6 +11642,7 @@ var require_service_token = __commonJS({
11573
11642
  async refresh() {
11574
11643
  try {
11575
11644
  this.rateLimit.check();
11645
+ this.refusals.check();
11576
11646
  return await this.exchange();
11577
11647
  } catch (err) {
11578
11648
  const code = err?.code;
@@ -11590,8 +11660,10 @@ var require_service_token = __commonJS({
11590
11660
  clientSecret: this.clientSecret,
11591
11661
  rateLimit: this.rateLimit,
11592
11662
  onResponse: this.onResponse,
11593
- exchangeName: "Token exchange"
11663
+ exchangeName: "Token exchange",
11664
+ refused: (message) => this.refusals.refuse({ message: `[ServiceTokenManager] ${message}`, host: (0, exchange_1.hostOf)(this.keepApiUrl) })
11594
11665
  });
11666
+ this.refusals.clear();
11595
11667
  this.token = data.token;
11596
11668
  this.expiresAt = Date.now() + data.expiresIn * 1e3;
11597
11669
  return this.token;
@@ -11678,7 +11750,7 @@ var require_dist2 = __commonJS({
11678
11750
  "../../packages/keep/dist/index.js"(exports2) {
11679
11751
  "use strict";
11680
11752
  Object.defineProperty(exports2, "__esModule", { value: true });
11681
- exports2.waitForKeepToken = exports2.KeepRateLimitedError = exports2.KeepUnavailableError = exports2.AgentCredentialRevokedError = exports2.AgentTokenManager = exports2.ServiceTokenManager = exports2.KeepClient = void 0;
11753
+ exports2.waitForKeepToken = exports2.KeepCredentialsRefusedError = exports2.KeepRateLimitedError = exports2.KeepUnavailableError = exports2.AgentCredentialRevokedError = exports2.AgentTokenManager = exports2.ServiceTokenManager = exports2.KeepClient = void 0;
11682
11754
  var client_1 = require_client();
11683
11755
  Object.defineProperty(exports2, "KeepClient", { enumerable: true, get: function() {
11684
11756
  return client_1.KeepClient;
@@ -11702,6 +11774,10 @@ var require_dist2 = __commonJS({
11702
11774
  Object.defineProperty(exports2, "KeepRateLimitedError", { enumerable: true, get: function() {
11703
11775
  return rate_limited_1.KeepRateLimitedError;
11704
11776
  } });
11777
+ var refusal_budget_1 = require_refusal_budget();
11778
+ Object.defineProperty(exports2, "KeepCredentialsRefusedError", { enumerable: true, get: function() {
11779
+ return refusal_budget_1.KeepCredentialsRefusedError;
11780
+ } });
11705
11781
  var wait_for_token_1 = require_wait_for_token();
11706
11782
  Object.defineProperty(exports2, "waitForKeepToken", { enumerable: true, get: function() {
11707
11783
  return wait_for_token_1.waitForKeepToken;
@@ -27010,7 +27086,7 @@ var import_path = require("path");
27010
27086
  var import_promises = require("fs/promises");
27011
27087
  var import_yaml = __toESM(require_dist3());
27012
27088
  var import_shuttle = __toESM(require_dist5());
27013
- var buildVersion = true ? "0.30.18" : pkg.version;
27089
+ var buildVersion = true ? "0.30.19" : pkg.version;
27014
27090
  var sifterBrand = {
27015
27091
  product: {
27016
27092
  id: "sifter",