@archlast/server 0.1.8 → 0.1.9
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 +104 -100
- package/dist/admin/auth.d.ts +24 -5
- package/dist/admin/auth.js +49 -25
- package/dist/admin/schema.d.ts +122 -32
- package/dist/admin/schema.js +131 -95
- package/dist/admin/seed.d.ts +1 -1
- package/dist/admin/seed.js +79 -47
- package/dist/auth/api-key-resolver.d.ts +1 -1
- package/dist/auth/api-key-resolver.js +7 -3
- package/dist/auth/archlast-auth-adapter.d.ts +2 -5
- package/dist/auth/archlast-auth-adapter.js +1 -1
- package/dist/auth/better-auth-adapter.d.ts.map +1 -1
- package/dist/auth/better-auth-adapter.js +41 -26
- package/dist/auth/better-auth-adapter.js.map +1 -1
- package/dist/auth/better-auth-admin.d.ts.map +1 -1
- package/dist/auth/better-auth-admin.js +1 -1
- package/dist/auth/better-auth-admin.js.map +1 -1
- package/dist/auth/better-auth-api-key-resolver.js +1 -1
- package/dist/auth/better-auth-api-key-resolver.js.map +1 -1
- package/dist/auth/better-auth-instance.d.ts +249 -301
- package/dist/auth/better-auth-instance.d.ts.map +1 -1
- package/dist/auth/better-auth-instance.js +11 -0
- package/dist/auth/better-auth-instance.js.map +1 -1
- package/dist/auth/better-auth-seed.d.ts +5 -2
- package/dist/auth/better-auth-seed.js +31 -22
- package/dist/auth/better-auth-session-adapter.d.ts.map +1 -1
- package/dist/auth/better-auth-session-adapter.js +14 -10
- package/dist/auth/better-auth-session-adapter.js.map +1 -1
- package/dist/auth/errors.d.ts.map +1 -1
- package/dist/auth/errors.js +11 -11
- package/dist/auth/errors.js.map +1 -1
- package/dist/auth/oauth-proxy.d.ts +5 -2
- package/dist/auth/oauth-proxy.js +23 -27
- package/dist/auth/resolver.d.ts.map +1 -1
- package/dist/auth/resolver.js.map +1 -1
- package/dist/auth/role-helpers.d.ts +1 -1
- package/dist/auth/role-helpers.d.ts.map +1 -1
- package/dist/auth/role-helpers.js.map +1 -1
- package/dist/auth/session-manager.d.ts +2 -5
- package/dist/auth/session-manager.js +16 -6
- package/dist/auth/system/better-auth-schema.d.ts.map +1 -1
- package/dist/auth/system/better-auth-schema.js +6 -23
- package/dist/auth/system/better-auth-schema.js.map +1 -1
- package/dist/cache/circuit-breaker.d.ts +81 -0
- package/dist/cache/circuit-breaker.d.ts.map +1 -0
- package/dist/cache/circuit-breaker.js +170 -0
- package/dist/cache/circuit-breaker.js.map +1 -0
- package/dist/cache/client.d.ts +6 -3
- package/dist/cache/client.d.ts.map +1 -1
- package/dist/cache/client.js +12 -53
- package/dist/cache/client.js.map +1 -1
- package/dist/cache/index.d.ts +2 -0
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +5 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/invalidation-queue.d.ts +63 -0
- package/dist/cache/invalidation-queue.d.ts.map +1 -0
- package/dist/cache/invalidation-queue.js +196 -0
- package/dist/cache/invalidation-queue.js.map +1 -0
- package/dist/cache/layers.d.ts +14 -4
- package/dist/cache/layers.d.ts.map +1 -1
- package/dist/cache/layers.js +66 -72
- package/dist/cache/layers.js.map +1 -1
- package/dist/cache/manager.d.ts.map +1 -1
- package/dist/cache/manager.js +6 -41
- package/dist/cache/manager.js.map +1 -1
- package/dist/cache/protocol.d.ts +4 -39
- package/dist/cache/protocol.d.ts.map +1 -1
- package/dist/cache/protocol.js.map +1 -1
- package/dist/cache/redis-adapter.d.ts +103 -0
- package/dist/cache/redis-adapter.d.ts.map +1 -0
- package/dist/cache/redis-adapter.js +424 -0
- package/dist/cache/redis-adapter.js.map +1 -0
- package/dist/cache/run-sidecar.js +10 -1
- package/dist/cache/run-sidecar.js.map +1 -1
- package/dist/cache/sidecar-server.d.ts +51 -1
- package/dist/cache/sidecar-server.d.ts.map +1 -1
- package/dist/cache/sidecar-server.js +368 -22
- package/dist/cache/sidecar-server.js.map +1 -1
- package/dist/cache/store.d.ts +43 -0
- package/dist/cache/store.d.ts.map +1 -1
- package/dist/cache/store.js +69 -76
- package/dist/cache/store.js.map +1 -1
- package/dist/cache/strategies.d.ts +2 -9
- package/dist/cache/strategies.d.ts.map +1 -1
- package/dist/cache/types.d.ts +130 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +60 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/config/bullmq.d.ts +16 -0
- package/dist/config/bullmq.d.ts.map +1 -0
- package/dist/config/bullmq.js +103 -0
- package/dist/config/bullmq.js.map +1 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/schema.d.ts +80 -6
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +71 -6
- package/dist/config/schema.js.map +1 -1
- package/dist/config/service.d.ts +54 -4
- package/dist/config/service.d.ts.map +1 -1
- package/dist/config/service.js +56 -2
- package/dist/config/service.js.map +1 -1
- package/dist/controllers/admin/admin-tokens.controller.d.ts +131 -115
- package/dist/controllers/admin/admin-tokens.controller.js +117 -98
- package/dist/controllers/admin/api-keys.controller.d.ts +1 -1
- package/dist/controllers/admin/api-keys.controller.d.ts.map +1 -1
- package/dist/controllers/admin/api-keys.controller.js.map +1 -1
- package/dist/controllers/admin/app-users.controller.d.ts +274 -243
- package/dist/controllers/admin/app-users.controller.js +301 -257
- package/dist/controllers/admin/auth.controller.d.ts +260 -236
- package/dist/controllers/admin/auth.controller.js +197 -174
- package/dist/controllers/admin/backup.controller.d.ts.map +1 -1
- package/dist/controllers/admin/backup.controller.js.map +1 -1
- package/dist/controllers/admin/settings.controller.d.ts +1 -1
- package/dist/controllers/admin/storage-stats.controller.d.ts +63 -0
- package/dist/controllers/admin/storage-stats.controller.d.ts.map +1 -0
- package/dist/controllers/admin/storage-stats.controller.js +33 -0
- package/dist/controllers/admin/storage-stats.controller.js.map +1 -0
- package/dist/controllers/admin/tenants.controller.d.ts.map +1 -1
- package/dist/controllers/admin/tenants.controller.js.map +1 -1
- package/dist/controllers/admin/users.controller.d.ts +1 -1
- package/dist/controllers/admin/users.controller.d.ts.map +1 -1
- package/dist/controllers/admin/users.controller.js.map +1 -1
- package/dist/controllers/auth.controller.d.ts +289 -271
- package/dist/controllers/auth.controller.js +275 -226
- package/dist/controllers/crud-generator.controller.d.ts.map +1 -1
- package/dist/controllers/crud-generator.controller.js +127 -125
- package/dist/controllers/crud-generator.controller.js.map +1 -1
- package/dist/controllers/index.d.ts +1 -1
- package/dist/controllers/index.d.ts.map +1 -1
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/introspection.controller.d.ts +642 -0
- package/dist/controllers/introspection.controller.d.ts.map +1 -1
- package/dist/controllers/introspection.controller.js +611 -0
- package/dist/controllers/introspection.controller.js.map +1 -1
- package/dist/controllers/invite.controller.d.ts +190 -170
- package/dist/controllers/invite.controller.js +183 -164
- package/dist/controllers/mfa.controller.d.ts +205 -183
- package/dist/controllers/mfa.controller.js +131 -111
- package/dist/controllers/otp.controller.d.ts +194 -171
- package/dist/controllers/otp.controller.js +192 -175
- package/dist/controllers/storage.controller.d.ts.map +1 -1
- package/dist/controllers/storage.controller.js.map +1 -1
- package/dist/controllers/system.controller.d.ts +5 -3
- package/dist/controllers/system.controller.d.ts.map +1 -1
- package/dist/controllers/system.controller.js +4 -2
- package/dist/controllers/system.controller.js.map +1 -1
- package/dist/controllers/tenant.controller.d.ts +258 -227
- package/dist/controllers/tenant.controller.js +224 -200
- package/dist/db/cachedclient.d.ts +6 -11
- package/dist/db/cachedclient.d.ts.map +1 -1
- package/dist/db/cachedclient.js +79 -43
- package/dist/db/cachedclient.js.map +1 -1
- package/dist/db/distributed-client.d.ts +79 -24
- package/dist/db/distributed-client.js +23 -24
- package/dist/db/factory.d.ts +3 -8
- package/dist/db/factory.d.ts.map +1 -1
- package/dist/db/factory.js +3 -22
- package/dist/db/factory.js.map +1 -1
- package/dist/db/socket-client.d.ts +7 -0
- package/dist/db/socket-client.d.ts.map +1 -1
- package/dist/db/socket-client.js +140 -11
- package/dist/db/socket-client.js.map +1 -1
- package/dist/deployment/handler.d.ts +10 -2
- package/dist/deployment/handler.d.ts.map +1 -1
- package/dist/deployment/handler.js +70 -15
- package/dist/deployment/handler.js.map +1 -1
- package/dist/deployment/persistence.d.ts.map +1 -1
- package/dist/deployment/persistence.js +6 -1
- package/dist/deployment/persistence.js.map +1 -1
- package/dist/docker/compose.d.ts.map +1 -1
- package/dist/docker/compose.js +76 -0
- package/dist/docker/compose.js.map +1 -1
- package/dist/engine/runner.d.ts.map +1 -1
- package/dist/engine/runner.js +0 -43
- package/dist/engine/runner.js.map +1 -1
- package/dist/functions/built-in/auth-apikey.d.ts.map +1 -1
- package/dist/functions/built-in/auth-apikey.js.map +1 -1
- package/dist/functions/built-in/system-cache.d.ts.map +1 -1
- package/dist/functions/built-in/system-cache.js +6 -31
- package/dist/functions/built-in/system-cache.js.map +1 -1
- package/dist/functions/built-in/system-data.d.ts.map +1 -1
- package/dist/functions/built-in/system-data.js +4 -2
- package/dist/functions/built-in/system-data.js.map +1 -1
- package/dist/functions/definition.d.ts.map +1 -1
- package/dist/functions/definition.js +6 -2
- package/dist/functions/definition.js.map +1 -1
- package/dist/http/routes/metrics.d.ts +42 -0
- package/dist/http/routes/metrics.d.ts.map +1 -0
- package/dist/http/routes/metrics.js +29 -0
- package/dist/http/routes/metrics.js.map +1 -0
- package/dist/http/server.d.ts +1 -0
- package/dist/http/server.d.ts.map +1 -1
- package/dist/http/server.js +41 -3
- package/dist/http/server.js.map +1 -1
- package/dist/ipc/socket-bridge.d.ts +1 -0
- package/dist/ipc/socket-bridge.d.ts.map +1 -1
- package/dist/ipc/socket-bridge.js +5 -1
- package/dist/ipc/socket-bridge.js.map +1 -1
- package/dist/jobs/bullmq-adapter.d.ts +154 -0
- package/dist/jobs/bullmq-adapter.d.ts.map +1 -0
- package/dist/jobs/bullmq-adapter.js +688 -0
- package/dist/jobs/bullmq-adapter.js.map +1 -0
- package/dist/jobs/bullmq-circuit-breaker.d.ts +133 -0
- package/dist/jobs/bullmq-circuit-breaker.d.ts.map +1 -0
- package/dist/jobs/bullmq-circuit-breaker.js +323 -0
- package/dist/jobs/bullmq-circuit-breaker.js.map +1 -0
- package/dist/jobs/bullmq-dlq-manager.d.ts +155 -0
- package/dist/jobs/bullmq-dlq-manager.d.ts.map +1 -0
- package/dist/jobs/bullmq-dlq-manager.js +325 -0
- package/dist/jobs/bullmq-dlq-manager.js.map +1 -0
- package/dist/jobs/bullmq-metrics.d.ts +104 -0
- package/dist/jobs/bullmq-metrics.d.ts.map +1 -0
- package/dist/jobs/bullmq-metrics.js +323 -0
- package/dist/jobs/bullmq-metrics.js.map +1 -0
- package/dist/jobs/bullmq-priority-service.d.ts +173 -0
- package/dist/jobs/bullmq-priority-service.d.ts.map +1 -0
- package/dist/jobs/bullmq-priority-service.js +390 -0
- package/dist/jobs/bullmq-priority-service.js.map +1 -0
- package/dist/jobs/bullmq-scheduler.d.ts +111 -0
- package/dist/jobs/bullmq-scheduler.d.ts.map +1 -0
- package/dist/jobs/bullmq-scheduler.js +300 -0
- package/dist/jobs/bullmq-scheduler.js.map +1 -0
- package/dist/jobs/bullmq-worker.d.ts +155 -0
- package/dist/jobs/bullmq-worker.d.ts.map +1 -0
- package/dist/jobs/bullmq-worker.js +651 -0
- package/dist/jobs/bullmq-worker.js.map +1 -0
- package/dist/jobs/circuit-breaker.d.ts +120 -0
- package/dist/jobs/circuit-breaker.d.ts.map +1 -0
- package/dist/jobs/circuit-breaker.js +262 -0
- package/dist/jobs/circuit-breaker.js.map +1 -0
- package/dist/jobs/index.d.ts +1 -1
- package/dist/jobs/index.d.ts.map +1 -1
- package/dist/jobs/index.js.map +1 -1
- package/dist/jobs/queue.d.ts +120 -1
- package/dist/jobs/queue.d.ts.map +1 -1
- package/dist/jobs/queue.js +487 -9
- package/dist/jobs/queue.js.map +1 -1
- package/dist/jobs/redis-connection.d.ts +50 -0
- package/dist/jobs/redis-connection.d.ts.map +1 -0
- package/dist/jobs/redis-connection.js +123 -0
- package/dist/jobs/redis-connection.js.map +1 -0
- package/dist/jobs/run-scheduler.js +163 -10
- package/dist/jobs/run-scheduler.js.map +1 -1
- package/dist/jobs/run-worker.js +101 -9
- package/dist/jobs/run-worker.js.map +1 -1
- package/dist/jobs/worker-thread.d.ts +6 -0
- package/dist/jobs/worker-thread.d.ts.map +1 -1
- package/dist/jobs/worker-thread.js +37 -8
- package/dist/jobs/worker-thread.js.map +1 -1
- package/dist/jobs/worker.d.ts +33 -0
- package/dist/jobs/worker.d.ts.map +1 -1
- package/dist/jobs/worker.js +358 -115
- package/dist/jobs/worker.js.map +1 -1
- package/dist/linq/async-enumerable.d.ts.map +1 -1
- package/dist/linq/async-enumerable.js.map +1 -1
- package/dist/linq/enumerable.d.ts.map +1 -1
- package/dist/linq/enumerable.js +10 -10
- package/dist/linq/enumerable.js.map +1 -1
- package/dist/metrics/collector.d.ts +26 -0
- package/dist/metrics/collector.d.ts.map +1 -0
- package/dist/metrics/collector.js +103 -0
- package/dist/metrics/collector.js.map +1 -0
- package/dist/polling/updates.controller.d.ts +57 -0
- package/dist/polling/updates.controller.d.ts.map +1 -0
- package/dist/polling/updates.controller.js +70 -0
- package/dist/polling/updates.controller.js.map +1 -0
- package/dist/repository/db-set.d.ts.map +1 -1
- package/dist/repository/db-set.js +12 -8
- package/dist/repository/db-set.js.map +1 -1
- package/dist/repository/ef-core.d.ts.map +1 -1
- package/dist/repository/ef-core.js +6 -6
- package/dist/repository/ef-core.js.map +1 -1
- package/dist/repository/factory.d.ts +1 -1
- package/dist/repository/factory.d.ts.map +1 -1
- package/dist/repository/factory.js.map +1 -1
- package/dist/repository/interfaces.d.ts.map +1 -1
- package/dist/repository/interfaces.js.map +1 -1
- package/dist/repository/queryable.d.ts.map +1 -1
- package/dist/repository/queryable.js.map +1 -1
- package/dist/rpc/adapter.d.ts.map +1 -1
- package/dist/rpc/adapter.js.map +1 -1
- package/dist/rpc/router.d.ts +2 -2
- package/dist/rpc/router.d.ts.map +1 -1
- package/dist/rpc/router.js +1 -1
- package/dist/rpc/router.js.map +1 -1
- package/dist/schema/relationship-types.d.ts +7 -2
- package/dist/schema/relationship-types.js +1 -1
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/services/admin/app-users.service.d.ts +1 -1
- package/dist/services/admin/app-users.service.js +31 -38
- package/dist/services/admin/auth.service.d.ts +1 -1
- package/dist/services/admin/auth.service.js +11 -5
- package/dist/services/admin/backup/BackupOrchestrator.d.ts.map +1 -1
- package/dist/services/admin/backup/BackupOrchestrator.js +4 -7
- package/dist/services/admin/backup/BackupOrchestrator.js.map +1 -1
- package/dist/services/admin/backup/SqliteGenerator.js +8 -8
- package/dist/services/admin/backup/StorageStreamer.d.ts +3 -3
- package/dist/services/admin/backup/StorageStreamer.d.ts.map +1 -1
- package/dist/services/admin/backup/StorageStreamer.js +16 -55
- package/dist/services/admin/backup/StorageStreamer.js.map +1 -1
- package/dist/services/admin/backup/ZipComposer.d.ts +2 -0
- package/dist/services/admin/backup/ZipComposer.d.ts.map +1 -1
- package/dist/services/admin/backup/ZipComposer.js +23 -0
- package/dist/services/admin/backup/ZipComposer.js.map +1 -1
- package/dist/services/admin/backup.service.d.ts.map +1 -1
- package/dist/services/admin/backup.service.js.map +1 -1
- package/dist/services/admin/data.service.d.ts.map +1 -1
- package/dist/services/admin/data.service.js +287 -286
- package/dist/services/admin/data.service.js.map +1 -1
- package/dist/services/admin/tenants.service.d.ts.map +1 -1
- package/dist/services/admin/tenants.service.js.map +1 -1
- package/dist/services/auth.service.d.ts +2 -3
- package/dist/services/auth.service.js +16 -16
- package/dist/services/invite.service.d.ts +1 -1
- package/dist/services/invite.service.js +17 -15
- package/dist/services/storage.service.d.ts.map +1 -1
- package/dist/services/storage.service.js +35 -4
- package/dist/services/storage.service.js.map +1 -1
- package/dist/services/system.service.d.ts.map +1 -1
- package/dist/services/system.service.js +1 -1
- package/dist/services/system.service.js.map +1 -1
- package/dist/services/tenant.service.d.ts +1 -1
- package/dist/services/tenant.service.js +43 -31
- package/dist/sse/subscriptions.controller.d.ts +57 -0
- package/dist/sse/subscriptions.controller.d.ts.map +1 -0
- package/dist/sse/subscriptions.controller.js +127 -0
- package/dist/sse/subscriptions.controller.js.map +1 -0
- package/dist/startup/bootstrap.d.ts +13 -2
- package/dist/startup/bootstrap.d.ts.map +1 -1
- package/dist/startup/bootstrap.js +85 -13
- package/dist/startup/bootstrap.js.map +1 -1
- package/dist/storage/s3-backend.d.ts.map +1 -1
- package/dist/storage/s3-backend.js +3 -3
- package/dist/storage/s3-backend.js.map +1 -1
- package/dist/websocket/server.d.ts.map +1 -1
- package/dist/websocket/server.js +14 -3
- package/dist/websocket/server.js.map +1 -1
- package/docker/README.md +309 -11
- package/package.json +214 -210
- package/templates/.env.example +115 -55
- package/templates/archlast.config.js +51 -37
- package/templates/docker-compose.prod.yml +32 -15
- package/templates/docker-compose.yml +117 -33
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BullMQMetricsCollector = void 0;
|
|
4
|
+
exports.setupBullMQPrometheusExporter = setupBullMQPrometheusExporter;
|
|
5
|
+
const bullmq_1 = require("bullmq");
|
|
6
|
+
const prom_client_1 = require("prom-client");
|
|
7
|
+
/**
|
|
8
|
+
* Collects metrics from BullMQ queues and exports to Prometheus.
|
|
9
|
+
* Tracks job lifecycle events, processing times, and queue state.
|
|
10
|
+
*/
|
|
11
|
+
class BullMQMetricsCollector {
|
|
12
|
+
queueEvents = null;
|
|
13
|
+
metrics;
|
|
14
|
+
startTimes;
|
|
15
|
+
queue;
|
|
16
|
+
gaugeUpdateInterval = null;
|
|
17
|
+
options;
|
|
18
|
+
// Prometheus metrics
|
|
19
|
+
prometheusMetrics = null;
|
|
20
|
+
constructor(queueName, connection, options = {}) {
|
|
21
|
+
this.options = {
|
|
22
|
+
prometheusRegistry: options.prometheusRegistry ?? new prom_client_1.Registry(),
|
|
23
|
+
enableHistograms: options.enableHistograms ?? true,
|
|
24
|
+
gaugeUpdateIntervalMs: options.gaugeUpdateIntervalMs ?? 10000,
|
|
25
|
+
};
|
|
26
|
+
this.queue = new bullmq_1.Queue(queueName, { connection });
|
|
27
|
+
this.startTimes = new Map();
|
|
28
|
+
this.metrics = this.createEmptyMetrics();
|
|
29
|
+
this.setupPrometheusMetrics();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Creates an empty metrics object with initial values
|
|
33
|
+
*/
|
|
34
|
+
createEmptyMetrics() {
|
|
35
|
+
return {
|
|
36
|
+
jobsCompleted: 0,
|
|
37
|
+
jobsFailed: 0,
|
|
38
|
+
jobsDelayed: 0,
|
|
39
|
+
jobsStalled: 0,
|
|
40
|
+
processingTimeMs: [],
|
|
41
|
+
queueWaitTimeMs: [],
|
|
42
|
+
pendingJobs: 0,
|
|
43
|
+
activeJobs: 0,
|
|
44
|
+
completedJobs: 0,
|
|
45
|
+
failedJobs: 0,
|
|
46
|
+
delayedJobs: 0,
|
|
47
|
+
errorTypes: {},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Sets up Prometheus metrics with the registry
|
|
52
|
+
*/
|
|
53
|
+
setupPrometheusMetrics() {
|
|
54
|
+
const register = this.options.prometheusRegistry;
|
|
55
|
+
this.prometheusMetrics = {
|
|
56
|
+
jobsCompleted: new prom_client_1.Counter({
|
|
57
|
+
name: "archlast_jobs_completed_total",
|
|
58
|
+
help: "Total number of completed jobs",
|
|
59
|
+
labelNames: ["queue", "job_name"],
|
|
60
|
+
registers: [register],
|
|
61
|
+
}),
|
|
62
|
+
jobsFailed: new prom_client_1.Counter({
|
|
63
|
+
name: "archlast_jobs_failed_total",
|
|
64
|
+
help: "Total number of failed jobs",
|
|
65
|
+
labelNames: ["queue", "job_name", "error_type"],
|
|
66
|
+
registers: [register],
|
|
67
|
+
}),
|
|
68
|
+
jobsRetried: new prom_client_1.Counter({
|
|
69
|
+
name: "archlast_jobs_retried_total",
|
|
70
|
+
help: "Total number of job retries",
|
|
71
|
+
labelNames: ["queue", "job_name"],
|
|
72
|
+
registers: [register],
|
|
73
|
+
}),
|
|
74
|
+
jobsTimedOut: new prom_client_1.Counter({
|
|
75
|
+
name: "archlast_jobs_timed_out_total",
|
|
76
|
+
help: "Total number of jobs that timed out",
|
|
77
|
+
labelNames: ["queue", "job_name"],
|
|
78
|
+
registers: [register],
|
|
79
|
+
}),
|
|
80
|
+
jobsPending: new prom_client_1.Gauge({
|
|
81
|
+
name: "archlast_jobs_pending",
|
|
82
|
+
help: "Number of jobs currently pending",
|
|
83
|
+
labelNames: ["queue"],
|
|
84
|
+
registers: [register],
|
|
85
|
+
}),
|
|
86
|
+
jobsActive: new prom_client_1.Gauge({
|
|
87
|
+
name: "archlast_jobs_active",
|
|
88
|
+
help: "Number of jobs currently being processed",
|
|
89
|
+
labelNames: ["queue"],
|
|
90
|
+
registers: [register],
|
|
91
|
+
}),
|
|
92
|
+
jobsInDLQ: new prom_client_1.Gauge({
|
|
93
|
+
name: "archlast_jobs_dlq_total",
|
|
94
|
+
help: "Number of jobs in dead letter queue",
|
|
95
|
+
labelNames: ["queue"],
|
|
96
|
+
registers: [register],
|
|
97
|
+
}),
|
|
98
|
+
jobDuration: new prom_client_1.Histogram({
|
|
99
|
+
name: "archlast_job_duration_seconds",
|
|
100
|
+
help: "Job processing duration in seconds",
|
|
101
|
+
labelNames: ["queue", "job_name"],
|
|
102
|
+
buckets: [0.1, 0.5, 1, 2, 5, 10, 30, 60],
|
|
103
|
+
registers: [register],
|
|
104
|
+
}),
|
|
105
|
+
jobQueueWait: new prom_client_1.Histogram({
|
|
106
|
+
name: "archlast_job_queue_wait_seconds",
|
|
107
|
+
help: "Time jobs spent waiting in queue",
|
|
108
|
+
labelNames: ["queue", "job_name"],
|
|
109
|
+
buckets: [1, 10, 60, 300, 600, 1800, 3600],
|
|
110
|
+
registers: [register],
|
|
111
|
+
}),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Categorizes error messages into types for metrics
|
|
116
|
+
*/
|
|
117
|
+
categorizeError(reason) {
|
|
118
|
+
if (!reason)
|
|
119
|
+
return "unknown";
|
|
120
|
+
const lowerReason = reason.toLowerCase();
|
|
121
|
+
if (lowerReason.includes("timeout"))
|
|
122
|
+
return "timeout";
|
|
123
|
+
if (lowerReason.includes("econnrefused") ||
|
|
124
|
+
lowerReason.includes("etimedout") ||
|
|
125
|
+
lowerReason.includes("enotfound"))
|
|
126
|
+
return "network";
|
|
127
|
+
if (lowerReason.includes("validation") || lowerReason.includes("invalid"))
|
|
128
|
+
return "validation";
|
|
129
|
+
if (lowerReason.includes("circuit"))
|
|
130
|
+
return "circuit_breaker";
|
|
131
|
+
if (lowerReason.includes("rate limit") || lowerReason.includes("ratelimit"))
|
|
132
|
+
return "rate_limit";
|
|
133
|
+
if (lowerReason.includes("unauthorized") || lowerReason.includes("forbidden"))
|
|
134
|
+
return "auth";
|
|
135
|
+
return "unknown";
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Gets the job name from the job object or returns 'unknown'
|
|
139
|
+
*/
|
|
140
|
+
getJobName(job) {
|
|
141
|
+
return job.name ?? job.data?.name ?? "unknown";
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Starts collecting metrics from the queue.
|
|
145
|
+
* Sets up event listeners and begins periodic gauge updates.
|
|
146
|
+
*/
|
|
147
|
+
async start() {
|
|
148
|
+
if (this.queueEvents) {
|
|
149
|
+
throw new Error("Metrics collector is already started");
|
|
150
|
+
}
|
|
151
|
+
// Create QueueEvents instance for listening to queue events
|
|
152
|
+
this.queueEvents = new bullmq_1.QueueEvents(this.queue.name, {
|
|
153
|
+
connection: this.queue.opts?.connection,
|
|
154
|
+
});
|
|
155
|
+
// Set up event listeners
|
|
156
|
+
this.queueEvents.on("completed", async ({ jobId, returnvalue }) => {
|
|
157
|
+
this.metrics.jobsCompleted++;
|
|
158
|
+
const startTime = this.startTimes.get(jobId);
|
|
159
|
+
if (startTime) {
|
|
160
|
+
const processingTime = Date.now() - startTime;
|
|
161
|
+
this.metrics.processingTimeMs.push(processingTime);
|
|
162
|
+
this.startTimes.delete(jobId);
|
|
163
|
+
// Update Prometheus histogram if enabled
|
|
164
|
+
if (this.prometheusMetrics && this.options.enableHistograms) {
|
|
165
|
+
const job = await this.queue.getJob(jobId);
|
|
166
|
+
const jobName = this.getJobName(job ?? {});
|
|
167
|
+
this.prometheusMetrics.jobDuration.observe({ queue: this.queue.name, job_name: jobName }, processingTime / 1000 // Convert to seconds
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Update Prometheus counter
|
|
172
|
+
if (this.prometheusMetrics) {
|
|
173
|
+
const job = await this.queue.getJob(jobId);
|
|
174
|
+
const jobName = this.getJobName(job ?? {});
|
|
175
|
+
this.prometheusMetrics.jobsCompleted.inc({
|
|
176
|
+
queue: this.queue.name,
|
|
177
|
+
job_name: jobName,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
this.queueEvents.on("failed", async ({ jobId, failedReason }) => {
|
|
182
|
+
this.metrics.jobsFailed++;
|
|
183
|
+
const errorType = this.categorizeError(failedReason);
|
|
184
|
+
this.metrics.errorTypes[errorType] = (this.metrics.errorTypes[errorType] || 0) + 1;
|
|
185
|
+
this.startTimes.delete(jobId);
|
|
186
|
+
// Update Prometheus counter
|
|
187
|
+
if (this.prometheusMetrics) {
|
|
188
|
+
const job = await this.queue.getJob(jobId);
|
|
189
|
+
const jobName = this.getJobName(job ?? {});
|
|
190
|
+
this.prometheusMetrics.jobsFailed.inc({
|
|
191
|
+
queue: this.queue.name,
|
|
192
|
+
job_name: jobName,
|
|
193
|
+
error_type: errorType,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
this.queueEvents.on("stalled", ({ jobId }) => {
|
|
198
|
+
this.metrics.jobsStalled++;
|
|
199
|
+
});
|
|
200
|
+
this.queueEvents.on("active", ({ jobId, prev }) => {
|
|
201
|
+
this.startTimes.set(jobId, Date.now());
|
|
202
|
+
// Track queue wait time if we have previous state
|
|
203
|
+
if (prev === "waiting" && this.prometheusMetrics) {
|
|
204
|
+
this.queue
|
|
205
|
+
.getJob(jobId)
|
|
206
|
+
.then((job) => {
|
|
207
|
+
if (job && job.timestamp) {
|
|
208
|
+
const waitTime = Date.now() - job.timestamp;
|
|
209
|
+
this.metrics.queueWaitTimeMs.push(waitTime);
|
|
210
|
+
if (this.options.enableHistograms) {
|
|
211
|
+
const jobName = this.getJobName(job);
|
|
212
|
+
this.prometheusMetrics?.jobQueueWait.observe({ queue: this.queue.name, job_name: jobName }, waitTime / 1000 // Convert to seconds
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
.catch(() => {
|
|
218
|
+
// Ignore errors when getting job for metrics
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
this.queueEvents.on("delayed", ({ jobId }) => {
|
|
223
|
+
this.metrics.jobsDelayed++;
|
|
224
|
+
});
|
|
225
|
+
this.queueEvents.on("retries-exhausted", async ({ jobId }) => {
|
|
226
|
+
if (this.prometheusMetrics) {
|
|
227
|
+
const job = await this.queue.getJob(jobId);
|
|
228
|
+
const jobName = this.getJobName(job ?? {});
|
|
229
|
+
this.prometheusMetrics.jobsTimedOut.inc({
|
|
230
|
+
queue: this.queue.name,
|
|
231
|
+
job_name: jobName,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
// Set up periodic gauge updates
|
|
236
|
+
await this.updateGauges();
|
|
237
|
+
this.gaugeUpdateInterval = setInterval(() => this.updateGauges(), this.options.gaugeUpdateIntervalMs);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Stops collecting metrics and cleans up resources.
|
|
241
|
+
*/
|
|
242
|
+
async stop() {
|
|
243
|
+
// Clear the gauge update interval
|
|
244
|
+
if (this.gaugeUpdateInterval) {
|
|
245
|
+
clearInterval(this.gaugeUpdateInterval);
|
|
246
|
+
this.gaugeUpdateInterval = null;
|
|
247
|
+
}
|
|
248
|
+
// Close QueueEvents
|
|
249
|
+
if (this.queueEvents) {
|
|
250
|
+
await this.queueEvents.close();
|
|
251
|
+
this.queueEvents = null;
|
|
252
|
+
}
|
|
253
|
+
// Close the queue connection
|
|
254
|
+
await this.queue.close();
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Gets a snapshot of the current metrics.
|
|
258
|
+
*/
|
|
259
|
+
getMetrics() {
|
|
260
|
+
return { ...this.metrics };
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Resets all metrics to their initial values.
|
|
264
|
+
*/
|
|
265
|
+
reset() {
|
|
266
|
+
this.metrics = this.createEmptyMetrics();
|
|
267
|
+
this.startTimes.clear();
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Updates gauge values by fetching current queue state.
|
|
271
|
+
*/
|
|
272
|
+
async updateGauges() {
|
|
273
|
+
try {
|
|
274
|
+
const counts = await this.queue.getJobCounts("waiting", "active", "completed", "failed", "delayed");
|
|
275
|
+
this.metrics.pendingJobs = counts.waiting;
|
|
276
|
+
this.metrics.activeJobs = counts.active;
|
|
277
|
+
this.metrics.completedJobs = counts.completed;
|
|
278
|
+
this.metrics.failedJobs = counts.failed;
|
|
279
|
+
this.metrics.delayedJobs = counts.delayed;
|
|
280
|
+
// Update Prometheus gauges
|
|
281
|
+
if (this.prometheusMetrics) {
|
|
282
|
+
this.prometheusMetrics.jobsPending.set({ queue: this.queue.name }, counts.waiting);
|
|
283
|
+
this.prometheusMetrics.jobsActive.set({ queue: this.queue.name }, counts.active);
|
|
284
|
+
this.prometheusMetrics.jobsInDLQ.set({ queue: this.queue.name }, counts.failed);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
// Silently ignore gauge update errors to prevent metric collection
|
|
289
|
+
// from affecting the main application
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Gets the Prometheus registry associated with this collector.
|
|
294
|
+
*/
|
|
295
|
+
getPrometheusRegistry() {
|
|
296
|
+
return this.options.prometheusRegistry;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
exports.BullMQMetricsCollector = BullMQMetricsCollector;
|
|
300
|
+
/**
|
|
301
|
+
* Convenience function to set up a BullMQ metrics collector with Prometheus export.
|
|
302
|
+
*
|
|
303
|
+
* @param queueName - Name of the BullMQ queue to monitor
|
|
304
|
+
* @param connection - Redis connection (optional, will create default if not provided)
|
|
305
|
+
* @param register - Prometheus registry to use
|
|
306
|
+
* @returns Configured BullMQMetricsCollector instance
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```typescript
|
|
310
|
+
* const collector = setupBullMQPrometheusExporter('my-queue', redis, register);
|
|
311
|
+
* await collector.start();
|
|
312
|
+
*
|
|
313
|
+
* // Later...
|
|
314
|
+
* await collector.stop();
|
|
315
|
+
* ```
|
|
316
|
+
*/
|
|
317
|
+
function setupBullMQPrometheusExporter(queueName, connection, register) {
|
|
318
|
+
return new BullMQMetricsCollector(queueName, connection, {
|
|
319
|
+
prometheusRegistry: register,
|
|
320
|
+
enableHistograms: true,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=bullmq-metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bullmq-metrics.js","sourceRoot":"","sources":["../../src/jobs/bullmq-metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import Redis from "ioredis";
|
|
2
|
+
/**
|
|
3
|
+
* Aging metadata tracked for each job to prevent priority starvation.
|
|
4
|
+
* Stored within the job data under the `__aging__` key.
|
|
5
|
+
*/
|
|
6
|
+
export interface AgingJobData {
|
|
7
|
+
/** Original priority as set by user (1-20, where 1 is highest priority) */
|
|
8
|
+
originalPriority: number;
|
|
9
|
+
/** Current aging bonus (0-5), increases the longer a job waits */
|
|
10
|
+
agingBonus: number;
|
|
11
|
+
/** Timestamp when job was created */
|
|
12
|
+
createdAt: number;
|
|
13
|
+
/** Timestamp of last aging check */
|
|
14
|
+
lastAgingCheck: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Options for configuring the priority aging service.
|
|
18
|
+
*/
|
|
19
|
+
interface PriorityAgingServiceOptions {
|
|
20
|
+
/** How often to check for aging in milliseconds (default: 60000) */
|
|
21
|
+
checkIntervalMs?: number;
|
|
22
|
+
/** Maximum jobs to process per check (default: 100) */
|
|
23
|
+
maxJobsPerCheck?: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Service that implements priority aging for BullMQ jobs.
|
|
27
|
+
*
|
|
28
|
+
* Priority aging prevents job starvation by boosting the priority of jobs
|
|
29
|
+
* that have been waiting in the queue for an extended period. Every 15 minutes,
|
|
30
|
+
* a job's priority is increased by 1 level (up to a maximum bonus of 5).
|
|
31
|
+
*
|
|
32
|
+
* This service runs a background worker that periodically scans waiting jobs
|
|
33
|
+
* and updates their priorities based on their wait time.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const agingService = new BullMQPriorityAgingService(
|
|
38
|
+
* "my-queue",
|
|
39
|
+
* redisConnection,
|
|
40
|
+
* { checkIntervalMs: 60000 }
|
|
41
|
+
* );
|
|
42
|
+
*
|
|
43
|
+
* await agingService.start();
|
|
44
|
+
*
|
|
45
|
+
* // When enqueueing jobs, prepare data with aging metadata:
|
|
46
|
+
* const jobData = BullMQPriorityAgingService.prepareJobData(payload, priority);
|
|
47
|
+
* await queue.add("job-name", jobData, { priority: toBullMQPriority(priority) });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare class BullMQPriorityAgingService {
|
|
51
|
+
private readonly AGING_INTERVAL_MS;
|
|
52
|
+
private readonly MAX_AGING_BONUS;
|
|
53
|
+
private readonly DEFAULT_CHECK_INTERVAL_MS;
|
|
54
|
+
private readonly DEFAULT_MAX_JOBS_PER_CHECK;
|
|
55
|
+
private queue;
|
|
56
|
+
private agingWorker;
|
|
57
|
+
private workerConnection;
|
|
58
|
+
private checkIntervalMs;
|
|
59
|
+
private maxJobsPerCheck;
|
|
60
|
+
private queueName;
|
|
61
|
+
private connection;
|
|
62
|
+
private _isRunning;
|
|
63
|
+
private agingInterval;
|
|
64
|
+
/**
|
|
65
|
+
* Creates a new BullMQPriorityAgingService instance.
|
|
66
|
+
*
|
|
67
|
+
* @param queueName - The name of the BullMQ queue to monitor
|
|
68
|
+
* @param connection - Redis connection for BullMQ
|
|
69
|
+
* @param options - Optional configuration for the aging service
|
|
70
|
+
*/
|
|
71
|
+
constructor(queueName: string, connection: Redis, options?: PriorityAgingServiceOptions);
|
|
72
|
+
/**
|
|
73
|
+
* Start the priority aging service.
|
|
74
|
+
*
|
|
75
|
+
* This creates a background worker that periodically checks waiting jobs
|
|
76
|
+
* and applies priority boosts to jobs that have been waiting too long.
|
|
77
|
+
*
|
|
78
|
+
* @returns Promise that resolves when the service is started
|
|
79
|
+
*/
|
|
80
|
+
start(): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Stop the priority aging service.
|
|
83
|
+
*
|
|
84
|
+
* Closes the aging worker and clears the check interval.
|
|
85
|
+
*
|
|
86
|
+
* @returns Promise that resolves when the service is stopped
|
|
87
|
+
*/
|
|
88
|
+
stop(): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Check if the aging service is currently running.
|
|
91
|
+
*
|
|
92
|
+
* @returns true if the service is running, false otherwise
|
|
93
|
+
*/
|
|
94
|
+
isRunning(): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Manually trigger an aging check.
|
|
97
|
+
*
|
|
98
|
+
* This method scans waiting jobs, calculates their effective priority based on
|
|
99
|
+
* wait time, and updates job priorities if the aging bonus has increased.
|
|
100
|
+
*
|
|
101
|
+
* @returns Statistics about the aging check
|
|
102
|
+
*/
|
|
103
|
+
applyAging(): Promise<{
|
|
104
|
+
jobsChecked: number;
|
|
105
|
+
jobsBoosted: number;
|
|
106
|
+
averageWaitTimeMs: number;
|
|
107
|
+
}>;
|
|
108
|
+
/**
|
|
109
|
+
* Calculate the effective priority for a job based on its base priority and creation time.
|
|
110
|
+
*
|
|
111
|
+
* The aging algorithm adds 1 priority level for every 15 minutes of wait time,
|
|
112
|
+
* up to a maximum bonus of 5 levels.
|
|
113
|
+
*
|
|
114
|
+
* @param basePriority - The original priority (1-20, where 1 is highest)
|
|
115
|
+
* @param createdAt - Timestamp when the job was created
|
|
116
|
+
* @param now - Optional current timestamp (defaults to Date.now())
|
|
117
|
+
* @returns Object containing the effective priority and the calculated aging bonus
|
|
118
|
+
*/
|
|
119
|
+
static calculateEffectivePriority(basePriority: number, createdAt: number, now?: number): {
|
|
120
|
+
effectivePriority: number;
|
|
121
|
+
agingBonus: number;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Convert system priority (1-20) to BullMQ priority (1-2097152).
|
|
125
|
+
*
|
|
126
|
+
* BullMQ uses lower numbers for higher priority. The mapping:
|
|
127
|
+
* - System 1 (highest) → BullMQ 1
|
|
128
|
+
* - System 10 → BullMQ ~1104750
|
|
129
|
+
* - System 20 (lowest) → BullMQ 2097152
|
|
130
|
+
*
|
|
131
|
+
* @param systemPriority - Priority in system format (1-20)
|
|
132
|
+
* @returns Priority in BullMQ format (1-2097152)
|
|
133
|
+
*/
|
|
134
|
+
static toBullMQPriority(systemPriority: number): number;
|
|
135
|
+
/**
|
|
136
|
+
* Convert BullMQ priority (1-2097152) back to system priority (1-20).
|
|
137
|
+
*
|
|
138
|
+
* @param bullmqPriority - Priority in BullMQ format
|
|
139
|
+
* @returns Priority in system format (1-20)
|
|
140
|
+
*/
|
|
141
|
+
static fromBullMQPriority(bullmqPriority: number): number;
|
|
142
|
+
/**
|
|
143
|
+
* Prepare job data with aging tracking metadata.
|
|
144
|
+
*
|
|
145
|
+
* This should be called when creating a new job to ensure aging metadata
|
|
146
|
+
* is properly attached to the job data.
|
|
147
|
+
*
|
|
148
|
+
* @param payload - The job payload/data
|
|
149
|
+
* @param priority - The original priority (1-20)
|
|
150
|
+
* @returns Object containing the payload and aging metadata
|
|
151
|
+
*/
|
|
152
|
+
static prepareJobData(payload: unknown, priority: number): {
|
|
153
|
+
name?: string;
|
|
154
|
+
payload: unknown;
|
|
155
|
+
__aging__: AgingJobData;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Extract aging metadata from BullMQ job data.
|
|
159
|
+
*
|
|
160
|
+
* @param jobData - The job data from BullMQ
|
|
161
|
+
* @returns The aging data if present, null otherwise
|
|
162
|
+
*/
|
|
163
|
+
static extractAgingData(jobData: unknown): AgingJobData | null;
|
|
164
|
+
/**
|
|
165
|
+
* Perform the actual aging check on waiting jobs.
|
|
166
|
+
*
|
|
167
|
+
* This is the internal implementation that scans waiting jobs and applies
|
|
168
|
+
* priority updates based on their wait time.
|
|
169
|
+
*/
|
|
170
|
+
private performAgingCheck;
|
|
171
|
+
}
|
|
172
|
+
export default BullMQPriorityAgingService;
|
|
173
|
+
//# sourceMappingURL=bullmq-priority-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bullmq-priority-service.d.ts","sourceRoot":"","sources":["../../src/jobs/bullmq-priority-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,SAAS,CAAC;AAG5B;;;GAGG;AACH,MAAM,WAAW,YAAY;IACzB,2EAA2E;IAC3E,gBAAgB,EAAE,MAAM,CAAC;IACzB,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,UAAU,2BAA2B;IACjC,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAWD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,0BAA0B;IACnC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAkB;IACpD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAK;IACrC,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAS;IACnD,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAO;IAElD,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAA+B;IAEpD;;;;;;OAMG;gBACS,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,2BAA2B;IAgBvF;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmE5B;;;;;;OAMG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA2C3B;;;;OAIG;IACH,SAAS,IAAI,OAAO;IAIpB;;;;;;;OAOG;IACG,UAAU,IAAI,OAAO,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,iBAAiB,EAAE,MAAM,CAAC;KAC7B,CAAC;IAQF;;;;;;;;;;OAUG;IACH,MAAM,CAAC,0BAA0B,CAC7B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,GAAG,CAAC,EAAE,MAAM,GACb;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;IAcpD;;;;;;;;;;OAUG;IACH,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM;IAMvD;;;;;OAKG;IACH,MAAM,CAAC,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM;IAKzD;;;;;;;;;OASG;IACH,MAAM,CAAC,cAAc,CACjB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,GACjB;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,YAAY,CAAA;KAAE;IAe/D;;;;;OAKG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI;IAiB9D;;;;;OAKG;YACW,iBAAiB;CAqHlC;AAED,eAAe,0BAA0B,CAAC"}
|