@stacksjs/ts-cloud 0.7.68 → 0.7.69

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 (55) hide show
  1. package/dist/bin/cli.js +1125 -1125
  2. package/dist/{chunk-349k40rw.js → chunk-j6zaxywt.js} +30 -10
  3. package/dist/deploy/index.js +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/queue/queue.d.ts +8 -0
  6. package/dist/queue/worker.d.ts +2 -0
  7. package/dist/ui/account/automation.html +3 -3
  8. package/dist/ui/account/security.html +2 -2
  9. package/dist/ui/applications/compose.html +3 -3
  10. package/dist/ui/applications/new.html +2 -2
  11. package/dist/ui/data/backups.html +4 -4
  12. package/dist/ui/data/services.html +4 -4
  13. package/dist/ui/data/volumes.html +4 -4
  14. package/dist/ui/index.html +4 -4
  15. package/dist/ui/integrations.html +2 -2
  16. package/dist/ui/operations/alerts.html +4 -4
  17. package/dist/ui/operations/configuration.html +4 -4
  18. package/dist/ui/operations/jobs.html +4 -4
  19. package/dist/ui/operations/maintenance.html +4 -4
  20. package/dist/ui/operations/observability.html +4 -4
  21. package/dist/ui/operations/previews.html +4 -4
  22. package/dist/ui/operations/queue.html +3 -3
  23. package/dist/ui/operations/regions.html +4 -4
  24. package/dist/ui/operations/releases.html +3 -3
  25. package/dist/ui/operations/workloads.html +3 -3
  26. package/dist/ui/security.html +2 -2
  27. package/dist/ui/server/actions.html +4 -4
  28. package/dist/ui/server/activity.html +2 -2
  29. package/dist/ui/server/capacity.html +4 -4
  30. package/dist/ui/server/database.html +3 -3
  31. package/dist/ui/server/deployments.html +3 -3
  32. package/dist/ui/server/diagnostics.html +2 -2
  33. package/dist/ui/server/firewall.html +4 -4
  34. package/dist/ui/server/fleet.html +4 -4
  35. package/dist/ui/server/logs.html +4 -4
  36. package/dist/ui/server/metrics.html +4 -4
  37. package/dist/ui/server/security.html +2 -2
  38. package/dist/ui/server/services.html +2 -2
  39. package/dist/ui/server/sites.html +4 -4
  40. package/dist/ui/server/ssh-keys.html +4 -4
  41. package/dist/ui/server/team.html +4 -4
  42. package/dist/ui/server/terminal.html +2 -2
  43. package/dist/ui/serverless/alarms.html +4 -4
  44. package/dist/ui/serverless/assets.html +2 -2
  45. package/dist/ui/serverless/cost.html +2 -2
  46. package/dist/ui/serverless/data.html +4 -4
  47. package/dist/ui/serverless/firewall.html +2 -2
  48. package/dist/ui/serverless/functions.html +4 -4
  49. package/dist/ui/serverless/logs.html +4 -4
  50. package/dist/ui/serverless/metrics.html +2 -2
  51. package/dist/ui/serverless/queues.html +4 -4
  52. package/dist/ui/serverless/secrets.html +4 -4
  53. package/dist/ui/serverless/traces.html +4 -4
  54. package/dist/ui/serverless.html +4 -4
  55. package/package.json +3 -3
@@ -3435,6 +3435,7 @@ class DurableOperationQueue {
3435
3435
  idFn;
3436
3436
  workerId;
3437
3437
  leaseMs;
3438
+ availabilityListeners = new Set;
3438
3439
  limits;
3439
3440
  constructor(controlPlane, options = {}) {
3440
3441
  this.controlPlane = controlPlane;
@@ -3484,7 +3485,17 @@ class DurableOperationQueue {
3484
3485
  now
3485
3486
  ]);
3486
3487
  this.appendLog(operation.id, "Queued for durable execution.", { stream: "system" });
3487
- return this.view(operation.id);
3488
+ const view = this.view(operation.id);
3489
+ this.notifyAvailable();
3490
+ return view;
3491
+ }
3492
+ onAvailable(listener) {
3493
+ this.availabilityListeners.add(listener);
3494
+ return () => this.availabilityListeners.delete(listener);
3495
+ }
3496
+ notifyAvailable() {
3497
+ for (const listener of this.availabilityListeners)
3498
+ listener();
3488
3499
  }
3489
3500
  getJob(operationId) {
3490
3501
  const row = this.controlPlane.database.query("SELECT * FROM operation_jobs WHERE operation_id=?").get(operationId);
@@ -3497,7 +3508,7 @@ class DurableOperationQueue {
3497
3508
  return;
3498
3509
  let approximatePosition;
3499
3510
  if (operation.state === "queued") {
3500
- const ahead = Number(this.controlPlane.database.query("SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='queued' AND j.available_at<=? AND (o.priority>? OR (o.priority=? AND o.created_at<?))").get(this.now(), operation.priority, operation.priority, operation.createdAt)?.count ?? 0);
3511
+ const ahead = Number(this.controlPlane.database.query(`SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='queued' AND j.available_at<=? AND (o.priority>? OR (o.priority=? AND o.created_at<?))`).get(this.now(), operation.priority, operation.priority, operation.createdAt)?.count ?? 0);
3501
3512
  approximatePosition = { ahead, precision: "bounded" };
3502
3513
  }
3503
3514
  return { operation, job: metadata, approximatePosition };
@@ -3532,17 +3543,17 @@ class DurableOperationQueue {
3532
3543
  if (lock)
3533
3544
  return `resource_lock:${metadata.lockKey}`;
3534
3545
  }
3535
- if (operation.projectId && this.runningCount("SELECT COUNT(*) AS count FROM operations WHERE state='running' AND project_id=?", [
3546
+ if (operation.projectId && this.runningCount(`SELECT COUNT(*) AS count FROM operations WHERE state='running' AND project_id=?`, [
3536
3547
  operation.projectId
3537
3548
  ]) >= this.limits.project)
3538
3549
  return "project_concurrency";
3539
- if (operation.environmentId && this.runningCount("SELECT COUNT(*) AS count FROM operations WHERE state='running' AND environment_id=?", [
3550
+ if (operation.environmentId && this.runningCount(`SELECT COUNT(*) AS count FROM operations WHERE state='running' AND environment_id=?`, [
3540
3551
  operation.environmentId
3541
3552
  ]) >= this.limits.environment)
3542
3553
  return "environment_concurrency";
3543
- if (metadata.providerKey && this.runningCount("SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='running' AND j.provider_key=?", [metadata.providerKey]) >= this.limits.provider)
3554
+ if (metadata.providerKey && this.runningCount(`SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='running' AND j.provider_key=?`, [metadata.providerKey]) >= this.limits.provider)
3544
3555
  return "provider_concurrency";
3545
- if (metadata.buildSlot && this.runningCount("SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='running' AND j.build_slot=1", []) >= this.limits.builds)
3556
+ if (metadata.buildSlot && this.runningCount(`SELECT COUNT(*) AS count FROM operations o JOIN operation_jobs j ON j.operation_id=o.id WHERE o.state='running' AND j.build_slot=1`, []) >= this.limits.builds)
3546
3557
  return "build_concurrency";
3547
3558
  return;
3548
3559
  }
@@ -3597,7 +3608,7 @@ class DurableOperationQueue {
3597
3608
  const now = this.now();
3598
3609
  const expiry = this.leaseExpiry();
3599
3610
  const metadata = this.getJob(operationId);
3600
- const changed = this.controlPlane.database.run("UPDATE operations SET lease_expires_at=?, updated_at=?, version=version+1 WHERE id=? AND state='running' AND lease_owner=? AND version=?", [expiry, now, operationId, this.workerId, operation.version]).changes;
3611
+ const changed = this.controlPlane.database.run(`UPDATE operations SET lease_expires_at=?, updated_at=?, version=version+1 WHERE id=? AND state='running' AND lease_owner=? AND version=?`, [expiry, now, operationId, this.workerId, operation.version]).changes;
3601
3612
  if (changed !== 1)
3602
3613
  throw new Error("Operation lease changed before heartbeat");
3603
3614
  this.controlPlane.database.run("UPDATE operation_jobs SET heartbeat_at=?, current_step=COALESCE(?, current_step), updated_at=? WHERE operation_id=?", [now, step2 ?? null, now, operationId]);
@@ -3691,7 +3702,9 @@ class DurableOperationQueue {
3691
3702
  payload: { errorClass, availableAt: available, nextAttempt: operation.attempt + 1 }
3692
3703
  });
3693
3704
  this.appendLog(operationId, `Retry queued for error class ${errorClass}.`, { stream: "system" });
3694
- return this.controlPlane.getOperation(queued.id);
3705
+ const operationView = this.controlPlane.getOperation(queued.id);
3706
+ this.notifyAvailable();
3707
+ return operationView;
3695
3708
  }
3696
3709
  release(operationId) {
3697
3710
  this.controlPlane.database.run("DELETE FROM operation_locks WHERE operation_id=?", [operationId]);
@@ -3832,7 +3845,7 @@ class DurableOperationQueue {
3832
3845
  expectedVersion: operation.version,
3833
3846
  error: "Worker lease expired; safely requeued from the last checkpoint."
3834
3847
  });
3835
- this.controlPlane.database.run("UPDATE operation_jobs SET available_at=?, blocked_reason='worker_restart', updated_at=? WHERE operation_id=?", [this.now(), this.now(), operation.id]);
3848
+ this.controlPlane.database.run(`UPDATE operation_jobs SET available_at=?, blocked_reason='worker_restart', updated_at=? WHERE operation_id=?`, [this.now(), this.now(), operation.id]);
3836
3849
  this.appendLog(operation.id, "Worker lease expired; operation requeued from its persisted checkpoint.", {
3837
3850
  stream: "system"
3838
3851
  });
@@ -3885,11 +3898,12 @@ class DurableQueueWorker {
3885
3898
  waits = new Map;
3886
3899
  lanes = [];
3887
3900
  running = false;
3901
+ unsubscribeAvailability;
3888
3902
  constructor(queue, handlers, options = {}) {
3889
3903
  this.queue = queue;
3890
3904
  this.handlers = handlers;
3891
3905
  this.parallelism = bounded(options.parallelism, 4, 100);
3892
- this.pollIntervalMs = bounded(options.pollIntervalMs, 500, 60000);
3906
+ this.pollIntervalMs = bounded(options.pollIntervalMs, 5000, 60000);
3893
3907
  this.onResult = options.onResult;
3894
3908
  this.onError = options.onError;
3895
3909
  }
@@ -3900,11 +3914,17 @@ class DurableQueueWorker {
3900
3914
  if (this.running)
3901
3915
  return this;
3902
3916
  this.running = true;
3917
+ this.unsubscribeAvailability = this.queue.onAvailable(() => this.wake());
3903
3918
  this.lanes = Array.from({ length: this.parallelism }, () => this.runLane());
3904
3919
  return this;
3905
3920
  }
3906
3921
  stop() {
3907
3922
  this.running = false;
3923
+ this.unsubscribeAvailability?.();
3924
+ this.unsubscribeAvailability = undefined;
3925
+ this.wake();
3926
+ }
3927
+ wake() {
3908
3928
  for (const [timer, resolve] of this.waits) {
3909
3929
  clearTimeout(timer);
3910
3930
  resolve();
@@ -32,7 +32,7 @@ import {
32
32
  synchronizeDashboardUsers,
33
33
  trackDashboardOperation,
34
34
  verifyStaticApiOrigin
35
- } from "../chunk-349k40rw.js";
35
+ } from "../chunk-j6zaxywt.js";
36
36
  import {
37
37
  deleteStaticSite,
38
38
  deployStaticSite,
package/dist/index.js CHANGED
@@ -285,7 +285,7 @@ import {
285
285
  volumeCapabilities,
286
286
  webhookEndpoint,
287
287
  zeroCapacity
288
- } from "./chunk-349k40rw.js";
288
+ } from "./chunk-j6zaxywt.js";
289
289
  import {
290
290
  deleteStaticSite,
291
291
  deployStaticSite,
@@ -6,6 +6,7 @@ export declare class DurableOperationQueue {
6
6
  private readonly idFn;
7
7
  private readonly workerId;
8
8
  private readonly leaseMs;
9
+ private readonly availabilityListeners;
9
10
  readonly limits: QueueConcurrencyLimits;
10
11
  constructor(controlPlane: ControlPlaneStore, options?: {
11
12
  workerId?: string;
@@ -17,6 +18,13 @@ export declare class DurableOperationQueue {
17
18
  private now;
18
19
  private leaseExpiry;
19
20
  enqueue(input: EnqueueOperationInput): QueueOperationView;
21
+ /**
22
+ * Wake in-process workers as soon as work becomes available. Durable workers
23
+ * still poll as a cross-process/recovery fallback, but dashboard API actions
24
+ * no longer need an aggressive idle database polling interval.
25
+ */
26
+ onAvailable(listener: () => void): () => void;
27
+ private notifyAvailable;
20
28
  getJob(operationId: string): OperationJob | undefined;
21
29
  view(operationId: string): QueueOperationView | undefined;
22
30
  list(input?: {
@@ -20,10 +20,12 @@ export declare class DurableQueueWorker {
20
20
  private readonly waits;
21
21
  private lanes;
22
22
  private running;
23
+ private unsubscribeAvailability?;
23
24
  constructor(queue: DurableOperationQueue, handlers: Record<string, QueueOperationHandler>, options?: DurableQueueWorkerOptions);
24
25
  get active(): boolean;
25
26
  start(): this;
26
27
  stop(): void;
28
+ private wake;
27
29
  settled(): Promise<void>;
28
30
  /** Execute all currently claimable work, using the configured lane bound. */
29
31
  drain(): Promise<QueueRunResult[]>;