@stacksjs/ts-cloud 0.7.109 → 0.7.111

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 (70) hide show
  1. package/dist/aws/index.js +3 -3
  2. package/dist/bin/cli.js +938 -930
  3. package/dist/bin/dashboard-server.js +255 -247
  4. package/dist/{chunk-grx1rp09.js → chunk-19bs955w.js} +56 -16
  5. package/dist/{chunk-cktwk9hy.js → chunk-3ee2jav4.js} +8 -8
  6. package/dist/{chunk-x6yzgv7y.js → chunk-6a1t7fnq.js} +2 -2
  7. package/dist/{chunk-xrtwv3v2.js → chunk-d48vtdj4.js} +14 -1
  8. package/dist/{chunk-9v2pwxv9.js → chunk-kpeb5rcs.js} +2 -2
  9. package/dist/{chunk-hpv68b4a.js → chunk-nsgqsmrh.js} +1 -1
  10. package/dist/{chunk-wj3s95p9.js → chunk-rds0sy87.js} +3 -2
  11. package/dist/{chunk-k114qwg9.js → chunk-ttz2ra5j.js} +2 -2
  12. package/dist/{chunk-8kh577qh.js → chunk-v0vpamnf.js} +3 -3
  13. package/dist/{chunk-d3vx2ekv.js → chunk-wh1y5rtk.js} +5 -2
  14. package/dist/deploy/index.js +7 -7
  15. package/dist/drivers/index.js +2 -2
  16. package/dist/index.js +8 -8
  17. package/dist/protection/controls.d.ts +14 -0
  18. package/dist/protection/index.js +3 -1
  19. package/dist/spend/index.js +1 -1
  20. package/dist/spend/signals.d.ts +21 -0
  21. package/dist/ui/access-denied.html +2 -2
  22. package/dist/ui/account/automation.html +3 -3
  23. package/dist/ui/account/security.html +2 -2
  24. package/dist/ui/applications/compose.html +4 -4
  25. package/dist/ui/applications/new.html +2 -2
  26. package/dist/ui/data/backups.html +3 -3
  27. package/dist/ui/data/services.html +4 -4
  28. package/dist/ui/data/volumes.html +4 -4
  29. package/dist/ui/index.html +4 -4
  30. package/dist/ui/infrastructure/topology.html +4 -4
  31. package/dist/ui/operations/alerts.html +4 -4
  32. package/dist/ui/operations/configuration.html +4 -4
  33. package/dist/ui/operations/jobs.html +3 -3
  34. package/dist/ui/operations/maintenance.html +4 -4
  35. package/dist/ui/operations/observability.html +4 -4
  36. package/dist/ui/operations/previews.html +4 -4
  37. package/dist/ui/operations/queue.html +4 -4
  38. package/dist/ui/operations/regions.html +3 -3
  39. package/dist/ui/operations/releases.html +4 -4
  40. package/dist/ui/operations/spend.html +4 -4
  41. package/dist/ui/operations/workloads.html +3 -3
  42. package/dist/ui/security.html +2 -2
  43. package/dist/ui/server/actions.html +4 -4
  44. package/dist/ui/server/activity.html +2 -2
  45. package/dist/ui/server/capacity.html +4 -4
  46. package/dist/ui/server/database.html +4 -4
  47. package/dist/ui/server/deployments.html +4 -4
  48. package/dist/ui/server/diagnostics.html +2 -2
  49. package/dist/ui/server/firewall.html +3 -3
  50. package/dist/ui/server/fleet.html +4 -4
  51. package/dist/ui/server/logs.html +3 -3
  52. package/dist/ui/server/metrics.html +4 -4
  53. package/dist/ui/server/security.html +2 -2
  54. package/dist/ui/server/services.html +2 -2
  55. package/dist/ui/server/sites.html +3 -3
  56. package/dist/ui/server/ssh-keys.html +4 -4
  57. package/dist/ui/server/team.html +3 -3
  58. package/dist/ui/server/terminal.html +2 -2
  59. package/dist/ui/serverless/alarms.html +4 -4
  60. package/dist/ui/serverless/assets.html +2 -2
  61. package/dist/ui/serverless/data.html +4 -4
  62. package/dist/ui/serverless/deployments.html +2 -2
  63. package/dist/ui/serverless/functions.html +4 -4
  64. package/dist/ui/serverless/logs.html +4 -4
  65. package/dist/ui/serverless/metrics.html +2 -2
  66. package/dist/ui/serverless/queues.html +4 -4
  67. package/dist/ui/serverless/secrets.html +4 -4
  68. package/dist/ui/serverless/traces.html +4 -4
  69. package/dist/ui/serverless.html +4 -4
  70. package/package.json +3 -3
@@ -462,7 +462,7 @@ function aggregateDeltas(deltas) {
462
462
  import { createHash as createHash3 } from "node:crypto";
463
463
 
464
464
  // src/control-plane/migrations.ts
465
- var CONTROL_PLANE_SCHEMA_VERSION = 39;
465
+ var CONTROL_PLANE_SCHEMA_VERSION = 40;
466
466
  var controlPlaneMigrations = [
467
467
  {
468
468
  version: 1,
@@ -2126,6 +2126,20 @@ var controlPlaneMigrations = [
2126
2126
  DROP TABLE notification_channels;
2127
2127
  ALTER TABLE notification_channels_new RENAME TO notification_channels;
2128
2128
  `
2129
+ },
2130
+ {
2131
+ version: 40,
2132
+ name: "telemetry_kind_scope_index",
2133
+ sql: `
2134
+ -- Anomaly detection filters request records by (project, kind, time).
2135
+ -- The existing scope index leads with project_id and environment_id but
2136
+ -- never mentions kind, so every request series scanned each project's
2137
+ -- logs, metrics, and traces too and discarded them in memory. On a
2138
+ -- project emitting mostly logs that is several times the necessary work,
2139
+ -- once a minute, forever.
2140
+ CREATE INDEX telemetry_kind_scope_time_idx
2141
+ ON telemetry_records(project_id, kind, timestamp);
2142
+ `
2129
2143
  }
2130
2144
  ];
2131
2145
  // src/control-plane/store.ts
@@ -5016,21 +5030,23 @@ class AnomalyConfigStore {
5016
5030
  }
5017
5031
  // src/spend/signals.ts
5018
5032
  var DETECTABLE_SIGNALS = [
5019
- { key: "cost", label: "Cost", source: "usage", gapPolicy: "zero", minSamples: 0, unit: "cents" },
5020
- { key: "edge.requests", label: "Edge requests", source: "usage", gapPolicy: "zero", minSamples: 0, unit: "requests" },
5021
- { key: "edge.egress_gb", label: "Edge egress", source: "usage", gapPolicy: "zero", minSamples: 0, unit: "GB" },
5033
+ { key: "cost", routeAware: false, label: "Cost", source: "usage", gapPolicy: "zero", minSamples: 0, unit: "cents" },
5034
+ { key: "edge.requests", routeAware: false, label: "Edge requests", source: "usage", gapPolicy: "zero", minSamples: 0, unit: "requests" },
5035
+ { key: "edge.egress_gb", routeAware: false, label: "Edge egress", source: "usage", gapPolicy: "zero", minSamples: 0, unit: "GB" },
5022
5036
  {
5023
5037
  key: "function.invocations",
5038
+ routeAware: false,
5024
5039
  label: "Function invocations",
5025
5040
  source: "usage",
5026
5041
  gapPolicy: "zero",
5027
5042
  minSamples: 0,
5028
5043
  unit: "invocations"
5029
5044
  },
5030
- { key: "http.requests", label: "HTTP requests", source: "telemetry", gapPolicy: "zero", minSamples: 0, unit: "requests" },
5031
- { key: "http.errors", label: "HTTP 5xx", source: "telemetry", gapPolicy: "zero", minSamples: 0, unit: "responses" },
5045
+ { key: "http.requests", routeAware: true, label: "HTTP requests", source: "telemetry", gapPolicy: "zero", minSamples: 0, unit: "requests" },
5046
+ { key: "http.errors", routeAware: true, label: "HTTP 5xx", source: "telemetry", gapPolicy: "zero", minSamples: 0, unit: "responses" },
5032
5047
  {
5033
5048
  key: "http.error_rate",
5049
+ routeAware: true,
5034
5050
  label: "HTTP error rate",
5035
5051
  source: "telemetry",
5036
5052
  gapPolicy: "gap",
@@ -5040,6 +5056,7 @@ var DETECTABLE_SIGNALS = [
5040
5056
  },
5041
5057
  {
5042
5058
  key: "http.client_error_rate",
5059
+ routeAware: true,
5043
5060
  label: "HTTP 4xx rate",
5044
5061
  source: "telemetry",
5045
5062
  gapPolicy: "gap",
@@ -5049,6 +5066,7 @@ var DETECTABLE_SIGNALS = [
5049
5066
  },
5050
5067
  {
5051
5068
  key: "http.latency_p95",
5069
+ routeAware: true,
5052
5070
  label: "Latency p95",
5053
5071
  source: "telemetry",
5054
5072
  gapPolicy: "gap",
@@ -5093,6 +5111,7 @@ function assemble(definition, window, values) {
5093
5111
  class SignalSource {
5094
5112
  controlPlane;
5095
5113
  spend;
5114
+ counterCache = new Map;
5096
5115
  constructor(controlPlane, spend) {
5097
5116
  this.controlPlane = controlPlane;
5098
5117
  this.spend = spend;
@@ -5117,10 +5136,8 @@ class SignalSource {
5117
5136
  });
5118
5137
  return assemble(definition, window, values);
5119
5138
  }
5120
- telemetrySeries(definition, scope, window) {
5121
- if (!scope.projectId)
5122
- return { signal: definition.key, points: [], populated: 0, suppressed: 0, unit: definition.unit };
5123
- const clauses = ["kind = 'request'", "project_id = ?", "timestamp >= ?", "timestamp < ?"];
5139
+ requestFilter(scope, window) {
5140
+ const clauses = ["project_id = ?", "kind = 'request'", "timestamp >= ?", "timestamp < ?"];
5124
5141
  const bindings = [scope.projectId, window.from, window.to];
5125
5142
  if (scope.environmentId) {
5126
5143
  clauses.push("environment_id = ?");
@@ -5130,16 +5147,35 @@ class SignalSource {
5130
5147
  clauses.push("path_template = ?");
5131
5148
  bindings.push(scope.route);
5132
5149
  }
5150
+ return { clauses, bindings };
5151
+ }
5152
+ counters(scope, window) {
5153
+ const key = [scope.projectId, scope.environmentId ?? "", scope.route ?? "", window.from, window.to].join("\x00");
5154
+ const cached = this.counterCache.get(key);
5155
+ if (cached)
5156
+ return cached;
5157
+ const { clauses, bindings } = this.requestFilter(scope, window);
5133
5158
  const rows = this.query(`SELECT
5134
5159
  CAST(strftime('%s', timestamp) AS INTEGER) / 3600 AS bucket,
5135
5160
  COUNT(*) AS total,
5136
5161
  SUM(CASE WHEN status_code >= 500 THEN 1 ELSE 0 END) AS server_errors,
5137
- SUM(CASE WHEN status_code >= 400 AND status_code < 500 THEN 1 ELSE 0 END) AS client_errors,
5138
- SUM(CASE WHEN duration_ms IS NOT NULL THEN 1 ELSE 0 END) AS timed
5162
+ SUM(CASE WHEN status_code >= 400 AND status_code < 500 THEN 1 ELSE 0 END) AS client_errors
5139
5163
  FROM telemetry_records
5140
5164
  WHERE ${clauses.join(" AND ")}
5141
5165
  GROUP BY bucket
5142
5166
  ORDER BY bucket`, bindings);
5167
+ this.counterCache.set(key, rows);
5168
+ return rows;
5169
+ }
5170
+ resetCache() {
5171
+ this.counterCache.clear();
5172
+ }
5173
+ telemetrySeries(definition, scope, window) {
5174
+ if (!scope.projectId)
5175
+ return { signal: definition.key, points: [], populated: 0, suppressed: 0, unit: definition.unit };
5176
+ if (definition.key === "http.latency_p95")
5177
+ return this.latencySeries(definition, scope, window);
5178
+ const rows = this.counters(scope, window);
5143
5179
  const values = new Map;
5144
5180
  for (const row of rows) {
5145
5181
  const bucket = Number(row.bucket) * HOUR;
@@ -5153,11 +5189,10 @@ class SignalSource {
5153
5189
  else if (definition.key === "http.client_error_rate")
5154
5190
  values.set(bucket, { value: total > 0 ? Number(row.client_errors) / total : 0, samples: total });
5155
5191
  }
5156
- if (definition.key === "http.latency_p95")
5157
- return this.latencySeries(definition, clauses, bindings, window);
5158
5192
  return assemble(definition, window, values);
5159
5193
  }
5160
- latencySeries(definition, clauses, bindings, window) {
5194
+ latencySeries(definition, scope, window) {
5195
+ const { clauses, bindings } = this.requestFilter(scope, window);
5161
5196
  const rows = this.query(`WITH ranked AS (
5162
5197
  SELECT
5163
5198
  CAST(strftime('%s', timestamp) AS INTEGER) / 3600 AS bucket,
@@ -5415,18 +5450,23 @@ class SpendService {
5415
5450
  };
5416
5451
  const wanted = options.signals ?? DETECTABLE_SIGNALS.map((signal) => signal.key);
5417
5452
  const found = [];
5453
+ let routes;
5418
5454
  for (const signal of wanted) {
5419
5455
  const hours = overrides.seasonLength ? Math.max(24 * 14, overrides.seasonLength * ((overrides.minHistory ?? 3) + 1)) : lookbackHoursForSignal(signal);
5420
5456
  const window = { from: new Date(new Date(to).getTime() - hours * 3600000).toISOString(), to };
5421
5457
  found.push(...this.detectSignal(signal, scope, window, overrides));
5422
5458
  if (!options.routes)
5423
5459
  continue;
5424
- for (const route of this.signals.busiestRoutes(scope, window)) {
5460
+ if (!signalDefinition(signal)?.routeAware)
5461
+ continue;
5462
+ routes ??= this.signals.busiestRoutes(scope, window);
5463
+ for (const route of routes) {
5425
5464
  if (this.anomalyConfigs.isSilenced(scope, { signal, route }))
5426
5465
  continue;
5427
5466
  found.push(...this.detectSignal(signal, { ...scope, route }, window, overrides, route));
5428
5467
  }
5429
5468
  }
5469
+ this.signals.resetCache();
5430
5470
  return found;
5431
5471
  }
5432
5472
  detectSignal(signal, scope, window, overrides, route) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  deployStaticSiteWithExternalDnsFull
3
- } from "./chunk-8kh577qh.js";
3
+ } from "./chunk-v0vpamnf.js";
4
4
  import {
5
5
  box,
6
6
  error,
@@ -22,10 +22,10 @@ import {
22
22
  SQSClient,
23
23
  STSClient,
24
24
  SecretsManagerClient
25
- } from "./chunk-x6yzgv7y.js";
25
+ } from "./chunk-6a1t7fnq.js";
26
26
  import {
27
27
  IAMClient
28
- } from "./chunk-hpv68b4a.js";
28
+ } from "./chunk-nsgqsmrh.js";
29
29
  import {
30
30
  CloudFrontClient
31
31
  } from "./chunk-01d86gt1.js";
@@ -50,7 +50,7 @@ import {
50
50
  resolveSiteKind,
51
51
  resolveUiSource,
52
52
  siteInstallBase
53
- } from "./chunk-d3vx2ekv.js";
53
+ } from "./chunk-wh1y5rtk.js";
54
54
  import {
55
55
  SSMClient
56
56
  } from "./chunk-7m60qnc8.js";
@@ -60,7 +60,7 @@ import {
60
60
  import {
61
61
  S3Client,
62
62
  resolveCredentials
63
- } from "./chunk-wj3s95p9.js";
63
+ } from "./chunk-rds0sy87.js";
64
64
  import {
65
65
  AWSClient,
66
66
  buildQueryParams
@@ -104,7 +104,7 @@ import {
104
104
  spendOpenApiPaths,
105
105
  telemetryCursor,
106
106
  telemetryEstimatedMonthlyCost
107
- } from "./chunk-grx1rp09.js";
107
+ } from "./chunk-19bs955w.js";
108
108
  import {
109
109
  artifactKey,
110
110
  buildCloudFormationTemplate,
@@ -10395,7 +10395,7 @@ async function sendAuthenticationEmail(config, message) {
10395
10395
  if (!from)
10396
10396
  return false;
10397
10397
  try {
10398
- const { EmailClient } = await import("./chunk-k114qwg9.js");
10398
+ const { EmailClient } = await import("./chunk-ttz2ra5j.js");
10399
10399
  const email = new EmailClient({ region: config.project.region, defaultFrom: from });
10400
10400
  await email.send(message);
10401
10401
  return true;
@@ -36403,7 +36403,7 @@ async function startLocalDashboardServer(options = {}) {
36403
36403
  });
36404
36404
  const notificationRouter = new NotificationRouter(alertStore, {
36405
36405
  emailImpl: async (input) => {
36406
- const { email } = await import("./chunk-k114qwg9.js");
36406
+ const { email } = await import("./chunk-ttz2ra5j.js");
36407
36407
  return email.send(input);
36408
36408
  }
36409
36409
  });
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  SESClient
3
- } from "./chunk-hpv68b4a.js";
3
+ } from "./chunk-nsgqsmrh.js";
4
4
  import {
5
5
  S3Client,
6
6
  resolveCredentials
7
- } from "./chunk-wj3s95p9.js";
7
+ } from "./chunk-rds0sy87.js";
8
8
  import {
9
9
  AWSClient
10
10
  } from "./chunk-zqtpg06c.js";
@@ -417,4 +417,17 @@ function applyControlsToDdos(config, controls) {
417
417
  }
418
418
  };
419
419
  }
420
- export { RATE_LIMIT_KEY_SEPARATOR, globMatches, ruleMatches, rateLimitKey, RateLimiter, rateLimitHeaders, defaultRateLimitRules, PROTECTION_SETTING, MAX_CONTROL_HOURS, DEFAULT_ATTACK_MODE_HOURS, ProtectionControlStore, describePosture, applyControlsToRateLimits, applyControlsToDdos };
420
+ function mergeControlsIntoConfig(config, controls) {
421
+ const compute = config?.infrastructure?.compute;
422
+ if (!compute || compute.ddos === false)
423
+ return config;
424
+ const base = typeof compute.ddos === "object" && compute.ddos !== null ? compute.ddos : {};
425
+ return {
426
+ ...config,
427
+ infrastructure: {
428
+ ...config.infrastructure,
429
+ compute: { ...compute, ddos: applyControlsToDdos(base, controls) }
430
+ }
431
+ };
432
+ }
433
+ export { RATE_LIMIT_KEY_SEPARATOR, globMatches, ruleMatches, rateLimitKey, RateLimiter, rateLimitHeaders, defaultRateLimitRules, PROTECTION_SETTING, MAX_CONTROL_HOURS, DEFAULT_ATTACK_MODE_HOURS, ProtectionControlStore, describePosture, applyControlsToRateLimits, applyControlsToDdos, mergeControlsIntoConfig };
@@ -5,12 +5,12 @@ import {
5
5
  generateStaticSiteTemplate,
6
6
  invalidateCache,
7
7
  uploadStaticFiles
8
- } from "./chunk-8kh577qh.js";
8
+ } from "./chunk-v0vpamnf.js";
9
9
  import"./chunk-01d86gt1.js";
10
10
  import"./chunk-gttvakpv.js";
11
11
  import"./chunk-32e7ya18.js";
12
12
  import"./chunk-4cjrg98a.js";
13
- import"./chunk-wj3s95p9.js";
13
+ import"./chunk-rds0sy87.js";
14
14
  import"./chunk-zqtpg06c.js";
15
15
  import"./chunk-v0bahtg2.js";
16
16
  export {
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-32e7ya18.js";
4
4
  import {
5
5
  S3Client
6
- } from "./chunk-wj3s95p9.js";
6
+ } from "./chunk-rds0sy87.js";
7
7
  import {
8
8
  AWSClient
9
9
  } from "./chunk-zqtpg06c.js";
@@ -1407,7 +1407,8 @@ host:${host}
1407
1407
  queryParams: { uploads: "" },
1408
1408
  headers
1409
1409
  });
1410
- return { UploadId: result?.InitiateMultipartUploadResult?.UploadId };
1410
+ const root = result?.InitiateMultipartUploadResult ?? result;
1411
+ return { UploadId: root?.UploadId };
1411
1412
  }
1412
1413
  async uploadPart(bucket, key, uploadId, partNumber, body) {
1413
1414
  const { accessKeyId, secretAccessKey, sessionToken } = this.getCredentials();
@@ -1504,7 +1505,7 @@ host:${host}
1504
1505
  bucket,
1505
1506
  queryParams: { uploads: "" }
1506
1507
  });
1507
- const uploads = result?.ListMultipartUploadsResult?.Upload;
1508
+ const uploads = (result?.ListMultipartUploadsResult ?? result)?.Upload;
1508
1509
  if (!uploads)
1509
1510
  return [];
1510
1511
  const list = Array.isArray(uploads) ? uploads : [uploads];
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  EmailClient,
3
3
  email
4
- } from "./chunk-hpv68b4a.js";
4
+ } from "./chunk-nsgqsmrh.js";
5
5
  import"./chunk-32e7ya18.js";
6
- import"./chunk-wj3s95p9.js";
6
+ import"./chunk-rds0sy87.js";
7
7
  import"./chunk-zqtpg06c.js";
8
8
  import"./chunk-v0bahtg2.js";
9
9
  export {
@@ -16,7 +16,7 @@ import {
16
16
  } from "./chunk-4cjrg98a.js";
17
17
  import {
18
18
  S3Client
19
- } from "./chunk-wj3s95p9.js";
19
+ } from "./chunk-rds0sy87.js";
20
20
  import {
21
21
  __require
22
22
  } from "./chunk-v0bahtg2.js";
@@ -815,7 +815,7 @@ async function deployStaticSiteWithExternalDnsFull(config) {
815
815
  }
816
816
  }
817
817
  onProgress?.("upload", "Uploading files to S3...");
818
- const { uploadStaticFiles } = await import("./chunk-9v2pwxv9.js");
818
+ const { uploadStaticFiles } = await import("./chunk-kpeb5rcs.js");
819
819
  const uploadResult = await uploadStaticFiles({
820
820
  sourceDir,
821
821
  bucket: infraResult.bucket,
@@ -835,7 +835,7 @@ async function deployStaticSiteWithExternalDnsFull(config) {
835
835
  }
836
836
  if (infraResult.distributionId && uploadResult.uploaded > 0) {
837
837
  onProgress?.("invalidate", "Invalidating CloudFront cache...");
838
- const { invalidateCache } = await import("./chunk-9v2pwxv9.js");
838
+ const { invalidateCache } = await import("./chunk-kpeb5rcs.js");
839
839
  await invalidateCache(infraResult.distributionId);
840
840
  }
841
841
  onProgress?.("complete", "Deployment complete!");
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-4cjrg98a.js";
8
8
  import {
9
9
  S3Client
10
- } from "./chunk-wj3s95p9.js";
10
+ } from "./chunk-rds0sy87.js";
11
11
  import {
12
12
  renderWafInstallScript
13
13
  } from "./chunk-va2yd85b.js";
@@ -1287,7 +1287,7 @@ async function sendNotifications(config, event, message, options = {}) {
1287
1287
  }
1288
1288
  async function sendEmailNotification(email, event, message) {
1289
1289
  try {
1290
- const mod = await import("./chunk-k114qwg9.js");
1290
+ const mod = await import("./chunk-ttz2ra5j.js");
1291
1291
  await mod.email.send({
1292
1292
  to: email.to,
1293
1293
  from: email.from,
@@ -1877,6 +1877,9 @@ function buildRpxProvisionScript(options) {
1877
1877
  "OOMPolicy=stop",
1878
1878
  "Restart=always",
1879
1879
  "RestartSec=5",
1880
+ "StartLimitIntervalSec=120",
1881
+ "StartLimitBurst=5",
1882
+ `ExecStartPre=/bin/sh -c 'for p in 80 443; do fuser -k -n tcp "$p" 2>/dev/null || true; done; sleep 1'`,
1880
1883
  "LimitNOFILE=1048576",
1881
1884
  "AmbientCapabilities=CAP_NET_BIND_SERVICE",
1882
1885
  "",
@@ -36,7 +36,7 @@ import {
36
36
  synchronizeDashboardUsers,
37
37
  trackDashboardOperation,
38
38
  verifyStaticApiOrigin
39
- } from "../chunk-cktwk9hy.js";
39
+ } from "../chunk-3ee2jav4.js";
40
40
  import {
41
41
  deleteStaticSite,
42
42
  deployStaticSite,
@@ -47,12 +47,12 @@ import {
47
47
  generateStaticSiteTemplate,
48
48
  invalidateCache,
49
49
  uploadStaticFiles
50
- } from "../chunk-8kh577qh.js";
50
+ } from "../chunk-v0vpamnf.js";
51
51
  import {
52
52
  buildAndPushServerlessImage
53
53
  } from "../chunk-wmbep3b5.js";
54
- import"../chunk-x6yzgv7y.js";
55
- import"../chunk-hpv68b4a.js";
54
+ import"../chunk-6a1t7fnq.js";
55
+ import"../chunk-nsgqsmrh.js";
56
56
  import"../chunk-01d86gt1.js";
57
57
  import"../chunk-50jpda9q.js";
58
58
  import"../chunk-he9a874b.js";
@@ -78,12 +78,12 @@ import {
78
78
  siteInstallBase,
79
79
  validateDeploymentConfig,
80
80
  verifyAddressRecord
81
- } from "../chunk-d3vx2ekv.js";
81
+ } from "../chunk-wh1y5rtk.js";
82
82
  import"../chunk-7m60qnc8.js";
83
83
  import"../chunk-4cjrg98a.js";
84
- import"../chunk-wj3s95p9.js";
84
+ import"../chunk-rds0sy87.js";
85
85
  import"../chunk-zqtpg06c.js";
86
- import"../chunk-grx1rp09.js";
86
+ import"../chunk-19bs955w.js";
87
87
  import"../chunk-va2yd85b.js";
88
88
  import"../chunk-aa2dkn7b.js";
89
89
  import"../chunk-t2s3gdq6.js";
@@ -68,10 +68,10 @@ import {
68
68
  waitForSsh,
69
69
  wrapCloudInitUserData,
70
70
  writeResizeCheckpoint
71
- } from "../chunk-d3vx2ekv.js";
71
+ } from "../chunk-wh1y5rtk.js";
72
72
  import"../chunk-7m60qnc8.js";
73
73
  import"../chunk-4cjrg98a.js";
74
- import"../chunk-wj3s95p9.js";
74
+ import"../chunk-rds0sy87.js";
75
75
  import"../chunk-zqtpg06c.js";
76
76
  import"../chunk-va2yd85b.js";
77
77
  import"../chunk-aa2dkn7b.js";
package/dist/index.js CHANGED
@@ -208,7 +208,7 @@ import {
208
208
  verifyUpdateSignature,
209
209
  webhookEndpoint,
210
210
  zeroCapacity
211
- } from "./chunk-cktwk9hy.js";
211
+ } from "./chunk-3ee2jav4.js";
212
212
  import {
213
213
  deleteStaticSite,
214
214
  deployStaticSite,
@@ -219,7 +219,7 @@ import {
219
219
  generateStaticSiteTemplate,
220
220
  invalidateCache,
221
221
  uploadStaticFiles
222
- } from "./chunk-8kh577qh.js";
222
+ } from "./chunk-v0vpamnf.js";
223
223
  import {
224
224
  buildAndPushServerlessImage
225
225
  } from "./chunk-wmbep3b5.js";
@@ -260,12 +260,12 @@ import {
260
260
  providerEndpoint,
261
261
  remapKey,
262
262
  resolveObjectStorage
263
- } from "./chunk-x6yzgv7y.js";
263
+ } from "./chunk-6a1t7fnq.js";
264
264
  import {
265
265
  EmailClient,
266
266
  IAMClient,
267
267
  SESClient
268
- } from "./chunk-hpv68b4a.js";
268
+ } from "./chunk-nsgqsmrh.js";
269
269
  import {
270
270
  CloudFrontClient
271
271
  } from "./chunk-01d86gt1.js";
@@ -338,7 +338,7 @@ import {
338
338
  waitForCloudInit,
339
339
  waitForSsh,
340
340
  wrapCloudInitUserData
341
- } from "./chunk-d3vx2ekv.js";
341
+ } from "./chunk-wh1y5rtk.js";
342
342
  import {
343
343
  EC2Client,
344
344
  SSMClient
@@ -348,7 +348,7 @@ import {
348
348
  } from "./chunk-4cjrg98a.js";
349
349
  import {
350
350
  S3Client
351
- } from "./chunk-wj3s95p9.js";
351
+ } from "./chunk-rds0sy87.js";
352
352
  import {
353
353
  AWSClient
354
354
  } from "./chunk-zqtpg06c.js";
@@ -511,7 +511,7 @@ import {
511
511
  zeroFill,
512
512
  zoneOffsetMs,
513
513
  zonedParts
514
- } from "./chunk-grx1rp09.js";
514
+ } from "./chunk-19bs955w.js";
515
515
  import {
516
516
  DEFAULT_ATTACK_MODE_HOURS,
517
517
  MAX_CONTROL_HOURS,
@@ -526,7 +526,7 @@ import {
526
526
  rateLimitHeaders,
527
527
  rateLimitKey,
528
528
  ruleMatches
529
- } from "./chunk-xrtwv3v2.js";
529
+ } from "./chunk-d48vtdj4.js";
530
530
  import {
531
531
  escapeSecLang,
532
532
  globToRegex,
@@ -111,3 +111,17 @@ export declare function describePosture(controls: ReturnType<ProtectionControlSt
111
111
  export declare function applyControlsToRateLimits(rules: readonly RateLimitRule[], controls: ReturnType<ProtectionControlStore['current']>): RateLimitRule[];
112
112
  /** Apply the controls to a firewall config before it is rendered. */
113
113
  export declare function applyControlsToDdos(config: DdosConfig, controls: ReturnType<ProtectionControlStore['current']>): DdosConfig;
114
+ /**
115
+ * Fold live operator controls into a cloud config before it reaches a driver.
116
+ *
117
+ * The provisioning path takes a `CloudConfig` and nothing else, deliberately:
118
+ * it also builds golden images, and baking one operator's live blocklist into a
119
+ * reusable image would be wrong. So the merge happens here, at the deploy call
120
+ * site that has a control plane, rather than inside the builder.
121
+ *
122
+ * Without this, `cloud protect:block` writes a rule that the next deploy
123
+ * silently renders without - the control appears to work and does nothing.
124
+ *
125
+ * Returns a shallow copy; the caller's config is not mutated.
126
+ */
127
+ export declare function mergeControlsIntoConfig<T extends Record<string, any>>(config: T, controls: ReturnType<ProtectionControlStore['current']>): T;
@@ -10,10 +10,11 @@ import {
10
10
  defaultRateLimitRules,
11
11
  describePosture,
12
12
  globMatches,
13
+ mergeControlsIntoConfig,
13
14
  rateLimitHeaders,
14
15
  rateLimitKey,
15
16
  ruleMatches
16
- } from "../chunk-xrtwv3v2.js";
17
+ } from "../chunk-d48vtdj4.js";
17
18
  import {
18
19
  escapeSecLang,
19
20
  globToRegex,
@@ -60,6 +61,7 @@ export {
60
61
  propagationHeaders,
61
62
  planMitigation,
62
63
  parseChain,
64
+ mergeControlsIntoConfig,
63
65
  isValidCidr,
64
66
  isSafePattern,
65
67
  inspectInvocation,
@@ -82,7 +82,7 @@ import {
82
82
  zeroFill,
83
83
  zoneOffsetMs,
84
84
  zonedParts
85
- } from "../chunk-grx1rp09.js";
85
+ } from "../chunk-19bs955w.js";
86
86
  import"../chunk-aa2dkn7b.js";
87
87
  import"../chunk-t2s3gdq6.js";
88
88
  import"../chunk-v0bahtg2.js";
@@ -18,6 +18,15 @@ export interface SignalDefinition {
18
18
  unit: string;
19
19
  /** True when the signal is a ratio in 0-1. */
20
20
  ratio?: boolean;
21
+ /**
22
+ * True when the signal can be narrowed to a route.
23
+ *
24
+ * Usage rollups have no route dimension: they are priced per meter, not per
25
+ * path. Running route detection over them produces a series that is actually
26
+ * project-wide and records it under a route's name, which is worse than
27
+ * useless - it is a confidently mislabelled anomaly.
28
+ */
29
+ routeAware: boolean;
21
30
  }
22
31
  /**
23
32
  * The signals detection can run on.
@@ -53,10 +62,22 @@ export interface SignalSeries {
53
62
  export declare class SignalSource {
54
63
  private readonly controlPlane;
55
64
  private readonly spend;
65
+ private readonly counterCache;
56
66
  constructor(controlPlane: ControlPlaneStore, spend: SpendStore);
57
67
  private query;
58
68
  /** Usage-backed series: cost, or one meter's quantity. */
59
69
  private usageSeries;
70
+ private requestFilter;
71
+ /**
72
+ * Per-bucket request counters for a scope and window.
73
+ *
74
+ * Memoized because four signals derive from the same numbers. Computing them
75
+ * separately meant four full passes over the request history every cycle, and
76
+ * with per-route detection that multiplied by the route count.
77
+ */
78
+ private counters;
79
+ /** Drop the memo so a long-lived source re-reads on the next cycle. */
80
+ resetCache(): void;
60
81
  /**
61
82
  * Telemetry-backed series, aggregated in SQL.
62
83
  *