@nest-batch/bullmq 0.2.0 → 0.2.1
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 +7 -6
- package/dist/src/adapters/bullmq.adapter.d.ts +2 -2
- package/dist/src/adapters/bullmq.adapter.d.ts.map +1 -1
- package/dist/src/adapters/bullmq.adapter.js +9 -9
- package/dist/src/adapters/bullmq.adapter.js.map +1 -1
- package/dist/src/bullmq-execution-strategy.d.ts +3 -3
- package/dist/src/bullmq-execution-strategy.d.ts.map +1 -1
- package/dist/src/bullmq-execution-strategy.js +4 -4
- package/dist/src/bullmq-execution-strategy.js.map +1 -1
- package/dist/src/bullmq-runtime.d.ts +237 -0
- package/dist/src/bullmq-runtime.d.ts.map +1 -0
- package/dist/src/bullmq-runtime.js +441 -0
- package/dist/src/bullmq-runtime.js.map +1 -0
- package/dist/src/bullmq-schedule.d.ts +134 -0
- package/dist/src/bullmq-schedule.d.ts.map +1 -0
- package/dist/src/bullmq-schedule.js +290 -0
- package/dist/src/bullmq-schedule.js.map +1 -0
- package/dist/src/bullmq-schedule.service.d.ts +21 -9
- package/dist/src/bullmq-schedule.service.d.ts.map +1 -1
- package/dist/src/bullmq-schedule.service.js +57 -3
- package/dist/src/bullmq-schedule.service.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/package.json +3 -3
- package/src/adapters/bullmq.adapter.ts +17 -21
- package/src/bullmq-execution-strategy.ts +3 -6
- package/src/{bullmq-runtime.service.ts → bullmq-runtime.ts} +10 -17
- package/src/{bullmq-schedule.service.ts → bullmq-schedule.ts} +110 -22
- package/src/index.ts +1 -1
package/README.md
CHANGED
|
@@ -218,7 +218,7 @@ every sub-module.
|
|
|
218
218
|
The adapter enqueues **one BullMQ job per step** (or, in a future
|
|
219
219
|
enhancement, one job per partition for chunked steps). It does not
|
|
220
220
|
enqueue one job per row, per chunk, or per item. The contract is
|
|
221
|
-
enforced by the `
|
|
221
|
+
enforced by the `BullmqRuntime.launch()` method, which
|
|
222
222
|
takes the step's `id` from the `JobDefinition` and uses it as the
|
|
223
223
|
BullMQ `name` discriminator. The chunk loop runs _inside_ the
|
|
224
224
|
single BullMQ job, in the worker.
|
|
@@ -297,11 +297,12 @@ cannot poison the BullMQ event stream.
|
|
|
297
297
|
- A batch engine. Step / chunk / tasklet semantics, skip, restart,
|
|
298
298
|
checkpoint, and business retry live in
|
|
299
299
|
[`@nest-batch/core`](../core). BullMQ is the courier.
|
|
300
|
-
- A scheduler. Cron-style scheduling
|
|
301
|
-
`@nest-batch/core`'s `@BatchScheduled` decorator,
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
300
|
+
- A separate scheduler package. Cron-style scheduling starts with
|
|
301
|
+
`@nest-batch/core`'s `@BatchScheduled` decorator, and this BullMQ
|
|
302
|
+
adapter installs the non-inert entries with `upsertJobScheduler`.
|
|
303
|
+
When `autoStartWorker` is enabled, `BullmqSchedule` also
|
|
304
|
+
consumes the schedule queue and bridges each fire to
|
|
305
|
+
`JobLauncher.launch(jobId, params)`.
|
|
305
306
|
- An admin UI, metrics backend, tracing backend, or webhook system.
|
|
306
307
|
Hook a `BatchObserver` to ship events where you need them.
|
|
307
308
|
- Alternative queue transports (Sidekiq, RabbitMQ, SQS, ...).
|
|
@@ -22,8 +22,8 @@ export declare class BullmqModule {
|
|
|
22
22
|
* Overrides the default `EXECUTION_STRATEGY` token with a BullMQ-
|
|
23
23
|
* backed `IExecutionStrategy` (`BullMqExecutionStrategy`) and wires
|
|
24
24
|
* the runtime services that own the BullMQ client lifecycle
|
|
25
|
-
* (`
|
|
26
|
-
* `
|
|
25
|
+
* (`BullmqRuntime` for step enqueue + worker, plus
|
|
26
|
+
* `BullmqSchedule` for `@BatchScheduled` cron entries).
|
|
27
27
|
*
|
|
28
28
|
* Two static methods:
|
|
29
29
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bullmq.adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/bullmq.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,aAAa,EAAiB,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAMzE,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;GAUG;AACH,qBACa,YAAY;CAAG;
|
|
1
|
+
{"version":3,"file":"bullmq.adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/bullmq.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,aAAa,EAAiB,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAMzE,OAAO,EAEL,KAAK,mBAAmB,EAEzB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;;GAUG;AACH,qBACa,YAAY;CAAG;AAwD5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkFG;AACH,qBAAa,aAAa;IACxB;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY;IAa/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE;QAChC,OAAO,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;QACnC,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;QAC5B,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,mBAAmB,CAAC,GAAG,mBAAmB,CAAC;KACxF,GAAG,YAAY;CAkDjB"}
|
|
@@ -19,8 +19,8 @@ _export(exports, {
|
|
|
19
19
|
const _common = require("@nestjs/common");
|
|
20
20
|
const _core = require("@nest-batch/core");
|
|
21
21
|
const _bullmqexecutionstrategy = require("../bullmq-execution-strategy");
|
|
22
|
-
const
|
|
23
|
-
const
|
|
22
|
+
const _bullmqruntime = require("../bullmq-runtime");
|
|
23
|
+
const _bullmqschedule = require("../bullmq-schedule");
|
|
24
24
|
const _connection = require("../connection");
|
|
25
25
|
const _moduleoptions = require("../module-options");
|
|
26
26
|
function _ts_decorate(decorators, target, key, desc) {
|
|
@@ -60,7 +60,7 @@ BullmqModule = _ts_decorate([
|
|
|
60
60
|
*
|
|
61
61
|
* The set mirrors the legacy `BullmqBatchModule.forRoot()` exports
|
|
62
62
|
* (the `forRootAsync()` legacy path was missing
|
|
63
|
-
* `
|
|
63
|
+
* `BullmqRuntime` from `exports` — that omission is fixed
|
|
64
64
|
* here, both paths now export the same five entries).
|
|
65
65
|
*
|
|
66
66
|
* - `EXECUTION_STRATEGY` — the DI token, so host code (e.g. a
|
|
@@ -71,16 +71,16 @@ BullmqModule = _ts_decorate([
|
|
|
71
71
|
* builders.
|
|
72
72
|
* - `BullMqExecutionStrategy` — the concrete class, for type-
|
|
73
73
|
* strict consumers that prefer class injection.
|
|
74
|
-
* - `
|
|
74
|
+
* - `BullmqRuntime` — the runtime that owns the
|
|
75
75
|
* `Queue` / `Worker` / `QueueEvents` lifecycle.
|
|
76
|
-
* - `
|
|
76
|
+
* - `BullmqSchedule` — the runtime that owns the
|
|
77
77
|
* `@BatchScheduled` cron-to-BullMQ translation.
|
|
78
78
|
*/ const ADAPTER_EXPORTS = [
|
|
79
79
|
_core.EXECUTION_STRATEGY,
|
|
80
80
|
_moduleoptions.BULLMQ_MODULE_OPTIONS,
|
|
81
81
|
_bullmqexecutionstrategy.BullMqExecutionStrategy,
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
_bullmqruntime.BullmqRuntime,
|
|
83
|
+
_bullmqschedule.BullmqSchedule
|
|
84
84
|
];
|
|
85
85
|
let BullmqAdapter = class BullmqAdapter {
|
|
86
86
|
/**
|
|
@@ -202,8 +202,8 @@ let BullmqAdapter = class BullmqAdapter {
|
|
|
202
202
|
*/ function buildStaticProviders(resolved) {
|
|
203
203
|
return [
|
|
204
204
|
_bullmqexecutionstrategy.BullMqExecutionStrategy,
|
|
205
|
-
|
|
206
|
-
|
|
205
|
+
_bullmqruntime.BullmqRuntime,
|
|
206
|
+
_bullmqschedule.BullmqSchedule,
|
|
207
207
|
{
|
|
208
208
|
provide: _core.EXECUTION_STRATEGY,
|
|
209
209
|
useExisting: _bullmqexecutionstrategy.BullMqExecutionStrategy
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/adapters/bullmq.adapter.ts"],"sourcesContent":["import { Module, type DynamicModule, type Provider } from '@nestjs/common';\nimport { EXECUTION_STRATEGY, type BatchAdapter } from '@nest-batch/core';\n\nimport { BullMqExecutionStrategy } from '../bullmq-execution-strategy';\nimport { BullmqRuntimeService } from '../bullmq-runtime.service';\nimport { BullmqScheduleService } from '../bullmq-schedule.service';\nimport { resolveBullMqConnection } from '../connection';\nimport {\n BULLMQ_MODULE_OPTIONS,\n type BullMqModuleOptions,\n type ResolvedBullMqModuleOptions,\n} from '../module-options';\n\n/**\n * Empty Nest module class that owns the BullMQ transport's\n * provider graph.\n *\n * Mirrors `InProcessModule` in `@nest-batch/core/src/adapters/\n * in-process.adapter.ts`: the class has no body on purpose. It is\n * purely a `DynamicModule` carrier — Nest's module system requires\n * *some* class to identify the module, and the empty class is the\n * minimum possible surface (no decorators, no lifecycle hooks, no\n * metadata). All real behaviour lives on the providers.\n */\n@Module({})\nexport class BullmqModule {}\n\n/**\n * Sentinel token for the async-options factory chain.\n *\n * `forRootAsync` registers a `useFactory` provider under this token\n * that runs the user's factory, then a second provider\n * (`BULLMQ_MODULE_OPTIONS`) that depends on it and freezes the\n * resolved options. A duplicate `provide` for\n * `BULLMQ_MODULE_OPTIONS` would crash Nest's container, so the\n * chain uses this private symbol as the intermediate step.\n *\n * Mirrors the `Symbol.for('@nest-batch/bullmq/OPTIONS_FACTORY')`\n * used by the legacy `BullmqBatchModule.forRootAsync()` — the\n * `Symbol.for` key is process-scoped and stable across module\n * versions, so any host still wiring up the legacy class is not\n * affected.\n */\nconst OPTIONS_FACTORY: symbol = Symbol.for('@nest-batch/bullmq/OPTIONS_FACTORY');\n\n/**\n * The list of exports the BullMQ adapter's `DynamicModule` exposes\n * to the host application.\n *\n * Centralised so the sync and async paths stay in lockstep — any\n * future addition (e.g. a `BullmqScheduler` controller) only needs\n * to be added here.\n *\n * The set mirrors the legacy `BullmqBatchModule.forRoot()` exports\n * (the `forRootAsync()` legacy path was missing\n * `BullmqRuntimeService` from `exports` — that omission is fixed\n * here, both paths now export the same five entries).\n *\n * - `EXECUTION_STRATEGY` — the DI token, so host code (e.g. a\n * `/healthz` endpoint) can resolve the strategy class via\n * `moduleRef.get(EXECUTION_STRATEGY)`.\n * - `BULLMQ_MODULE_OPTIONS` — the resolved connection / worker\n * config bag, for inspection and (future) for per-role client\n * builders.\n * - `BullMqExecutionStrategy` — the concrete class, for type-\n * strict consumers that prefer class injection.\n * - `BullmqRuntimeService` — the runtime that owns the\n * `Queue` / `Worker` / `QueueEvents` lifecycle.\n * - `BullmqScheduleService` — the runtime that owns the\n * `@BatchScheduled` cron-to-BullMQ translation.\n */\nconst ADAPTER_EXPORTS: ReadonlyArray<symbol | typeof BullMqExecutionStrategy | typeof BullmqRuntimeService | typeof BullmqScheduleService> = [\n EXECUTION_STRATEGY,\n BULLMQ_MODULE_OPTIONS,\n BullMqExecutionStrategy,\n BullmqRuntimeService,\n BullmqScheduleService,\n];\n\n/**\n * `BullmqAdapter` — the transport adapter for `@nest-batch/bullmq`\n * used by the new factory-pattern\n * `NestBatchModule.forRoot({ adapters: { transport, ... } })` API.\n *\n * Overrides the default `EXECUTION_STRATEGY` token with a BullMQ-\n * backed `IExecutionStrategy` (`BullMqExecutionStrategy`) and wires\n * the runtime services that own the BullMQ client lifecycle\n * (`BullmqRuntimeService` for step enqueue + worker, plus\n * `BullmqScheduleService` for `@BatchScheduled` cron entries).\n *\n * Two static methods:\n *\n * - `forRoot(options)` — synchronous configuration. The\n * connection options are resolved up-front and frozen under\n * the `BULLMQ_MODULE_OPTIONS` token. Use this when the Redis\n * host is known at module composition time.\n *\n * - `forRootAsync({ imports, inject, useFactory })` — async\n * configuration. The factory is registered as a sentinel\n * provider; the `BULLMQ_MODULE_OPTIONS` provider depends on\n * it. Use this when the connection comes from a config\n * service or another async source.\n *\n * The two methods share the same provider list via the\n * `buildStaticProviders` helper — the only difference is whether\n * `BULLMQ_MODULE_OPTIONS` is a value provider (sync) or a factory\n * provider that resolves the user's `useFactory` result (async).\n *\n * `globalProviders` is intentionally omitted. The recommended path\n * is to expose host-visible providers via the module's own\n * `exports` (see `ADAPTER_EXPORTS` above) — the `BatchAdapter`\n * interface's `globalProviders` field is for runtime classes the\n * adapter's own module needs but that core itself would also\n * re-export. `JobLauncher` (registered by `NestBatchModule`, not\n * by this adapter) injects the strategy by the `EXECUTION_STRATEGY`\n * token, which is already in `exports`, so the resolution chain\n * works without core having to know which adapter is active.\n *\n * @example\n * ```ts\n * // Synchronous wiring (connection known at module-build time)\n * import { Module } from '@nestjs/common';\n * import { NestBatchModule, InProcessAdapter } from '@nest-batch/core';\n * import { MikroOrmAdapter } from '@nest-batch/mikro-orm';\n * import { BullmqAdapter } from '@nest-batch/bullmq';\n *\n * @Module({\n * imports: [\n * NestBatchModule.forRoot({\n * adapters: {\n * persistence: MikroOrmAdapter,\n * transport: BullmqAdapter.forRoot({\n * connection: {\n * host: process.env.REDIS_HOST,\n * port: Number(process.env.REDIS_PORT),\n * keyPrefix: 'nest-batch:',\n * },\n * autoStartWorker: true,\n * }),\n * },\n * }),\n * ],\n * })\n * class AppModule {}\n * ```\n *\n * @example\n * ```ts\n * // Async wiring (connection sourced from ConfigService)\n * BullmqAdapter.forRootAsync({\n * imports: [ConfigModule],\n * inject: [ConfigService],\n * useFactory: (cfg: ConfigService) => ({\n * connection: {\n * host: cfg.get<string>('redis.host'),\n * port: cfg.get<number>('redis.port'),\n * password: cfg.get<string>('redis.password'),\n * },\n * }),\n * });\n * ```\n */\nexport class BullmqAdapter {\n /**\n * Synchronous configuration.\n *\n * Resolves the connection options up-front (`resolveBullMqConnection`\n * fills in defaults + freezes the bag) and emits a\n * `BatchAdapter` whose `module` is a `global: true`\n * `DynamicModule` registering the strategy class, the runtime\n * services, the `EXECUTION_STRATEGY` binding, and the resolved\n * options as a value provider under `BULLMQ_MODULE_OPTIONS`.\n *\n * No options object is required: the module accepts an empty\n * `{}` and applies all defaults (host `127.0.0.1`, port `6379`,\n * keyPrefix `nest-batch:`, no auth, no TLS, `autoStartWorker:\n * false`).\n *\n * @param options - Connection + worker config. All fields optional.\n * @returns A `BatchAdapter` with `name: 'bullmq'` and the\n * `BullmqModule` dynamic module.\n */\n static forRoot(options: BullMqModuleOptions = {}): BatchAdapter {\n const resolved: ResolvedBullMqModuleOptions = Object.freeze({\n connection: resolveBullMqConnection(options.connection),\n autoStartWorker: options.autoStartWorker ?? false,\n });\n return {\n name: 'bullmq',\n module: buildBullmqDynamicModule({\n providers: buildStaticProviders(resolved),\n }),\n };\n }\n\n /**\n * Async configuration — useful when the Redis connection comes\n * from a config service or another async provider.\n *\n * The shape mirrors `NestBatchModule.forRootAsync`:\n * - `imports` is forwarded to the resulting\n * `DynamicModule.imports` (so `ConfigModule` is available\n * when the factory runs).\n * - `inject` lists the providers the factory needs in its\n * argument list.\n * - `useFactory` resolves the options bag at module-build\n * time. The factory's return value is treated as\n * `BullMqModuleOptions` and is fed through\n * `resolveBullMqConnection` by the `BULLMQ_MODULE_OPTIONS`\n * factory provider (defaults applied, bag frozen).\n *\n * Implementation note: the factory is registered under the\n * package-private `OPTIONS_FACTORY` sentinel token; the\n * `BULLMQ_MODULE_OPTIONS` provider depends on it. This is the\n * same chain the legacy `BullmqBatchModule.forRootAsync` used\n * — the dynamic module is built off the static provider list,\n * with the static `BULLMQ_MODULE_OPTIONS` value provider\n * replaced by the async factory pair.\n *\n * @param asyncOptions - `{ imports, inject, useFactory }` bag.\n * `useFactory` is required; `imports` and `inject` are\n * optional and default to `[]`.\n * @returns A `BatchAdapter` with `name: 'bullmq'` and the\n * `BullmqModule` dynamic module (with `imports` wired).\n */\n static forRootAsync(asyncOptions: {\n imports?: DynamicModule['imports'];\n inject?: readonly unknown[];\n useFactory: (\n ...args: unknown[]\n ) => Promise<BullMqModuleOptions> | BullMqModuleOptions;\n }): BatchAdapter {\n const factoryProvider: Provider = {\n provide: OPTIONS_FACTORY,\n useFactory: asyncOptions.useFactory as (...args: unknown[]) => unknown,\n inject: [...(asyncOptions.inject ?? [])] as Array<string | symbol | Function>,\n };\n\n const mergedOptionsProvider: Provider = {\n provide: BULLMQ_MODULE_OPTIONS,\n useFactory: (\n fromFactory: BullMqModuleOptions | undefined,\n ): ResolvedBullMqModuleOptions => {\n return Object.freeze({\n connection: resolveBullMqConnection(fromFactory?.connection),\n autoStartWorker: fromFactory?.autoStartWorker ?? false,\n });\n },\n inject: [OPTIONS_FACTORY],\n };\n\n // The static provider list is the same as `forRoot` except\n // the value provider for `BULLMQ_MODULE_OPTIONS` is replaced\n // with the async factory above (a duplicate `provide` would\n // crash Nest's container). We seed `buildStaticProviders`\n // with a placeholder resolved bag (its value is discarded\n // — the async provider overrides the slot) so the function\n // can be the single source of truth for the rest of the\n // provider list.\n const baseProviders = buildStaticProviders(\n Object.freeze({\n connection: resolveBullMqConnection(undefined),\n autoStartWorker: false,\n }),\n );\n const filtered = baseProviders.filter(\n (p) =>\n !(\n typeof p === 'object' &&\n p !== null &&\n 'provide' in p &&\n (p as { provide: unknown }).provide === BULLMQ_MODULE_OPTIONS\n ),\n );\n\n return {\n name: 'bullmq',\n module: buildBullmqDynamicModule({\n providers: [factoryProvider, mergedOptionsProvider, ...filtered],\n imports: asyncOptions.imports,\n }),\n };\n }\n}\n\n/**\n * Build the static provider list shared by `forRoot()` and\n * `forRootAsync()`.\n *\n * Centralised so the sync and async paths declare the same set of\n * providers (and any future addition — e.g. a per-role client\n * builder — only needs to be added here).\n *\n * The async path then filters the `BULLMQ_MODULE_OPTIONS` entry\n * out of the returned array and replaces it with the factory\n * pair. Everything else is shared.\n */\nfunction buildStaticProviders(\n resolved: ResolvedBullMqModuleOptions,\n): Provider[] {\n return [\n BullMqExecutionStrategy,\n BullmqRuntimeService,\n BullmqScheduleService,\n {\n provide: EXECUTION_STRATEGY,\n useExisting: BullMqExecutionStrategy,\n },\n {\n provide: BULLMQ_MODULE_OPTIONS,\n useValue: resolved,\n },\n ];\n}\n\n/**\n * Build the `DynamicModule` payload for the BullMQ adapter.\n *\n * Extracted from the two factory methods so the provider /\n * export / global-true shape lives in one place. NestJS's\n * `validateExportedProvider` check rejects an `exports` entry\n * that is not in `providers` (or imported), so adding to one\n * without the other is a silent runtime failure — keeping the\n * two arrays synchronised by construction is the safest\n * pattern.\n *\n * `imports` is optional: `forRoot` does not need any (it has no\n * async providers), `forRootAsync` forwards the user's\n * `imports` (typically `ConfigModule`) so the factory's\n * `inject` targets resolve.\n */\nfunction buildBullmqDynamicModule(args: {\n providers: Provider[];\n imports?: DynamicModule['imports'];\n}): DynamicModule {\n const module: DynamicModule = {\n module: BullmqModule,\n global: true,\n providers: args.providers,\n exports: [...ADAPTER_EXPORTS],\n };\n if (args.imports !== undefined) {\n return { ...module, imports: [...args.imports] };\n }\n return module;\n}\n"],"names":["BullmqAdapter","BullmqModule","OPTIONS_FACTORY","Symbol","for","ADAPTER_EXPORTS","EXECUTION_STRATEGY","BULLMQ_MODULE_OPTIONS","BullMqExecutionStrategy","BullmqRuntimeService","BullmqScheduleService","forRoot","options","resolved","Object","freeze","connection","resolveBullMqConnection","autoStartWorker","name","module","buildBullmqDynamicModule","providers","buildStaticProviders","forRootAsync","asyncOptions","factoryProvider","provide","useFactory","inject","mergedOptionsProvider","fromFactory","baseProviders","undefined","filtered","filter","p","imports","useExisting","useValue","args","global","exports"],"mappings":";;;;;;;;;;;QAkKaA;eAAAA;;QAzIAC;eAAAA;;;wBAzB6C;sBACJ;yCAEd;sCACH;uCACC;4BACE;+BAKjC;;;;;;;AAcA,IAAA,AAAMA,eAAN,MAAMA;AAAc;;;;AAE3B;;;;;;;;;;;;;;;CAeC,GACD,MAAMC,kBAA0BC,OAAOC,GAAG,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;CAyBC,GACD,MAAMC,kBAAuI;IAC3IC,wBAAkB;IAClBC,oCAAqB;IACrBC,gDAAuB;IACvBC,0CAAoB;IACpBC,4CAAqB;CACtB;AAqFM,IAAA,AAAMV,gBAAN,MAAMA;IACX;;;;;;;;;;;;;;;;;;GAkBC,GACD,OAAOW,QAAQC,UAA+B,CAAC,CAAC,EAAgB;QAC9D,MAAMC,WAAwCC,OAAOC,MAAM,CAAC;YAC1DC,YAAYC,IAAAA,mCAAuB,EAACL,QAAQI,UAAU;YACtDE,iBAAiBN,QAAQM,eAAe,IAAI;QAC9C;QACA,OAAO;YACLC,MAAM;YACNC,QAAQC,yBAAyB;gBAC/BC,WAAWC,qBAAqBV;YAClC;QACF;IACF;IAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BC,GACD,OAAOW,aAAaC,YAMnB,EAAgB;QACf,MAAMC,kBAA4B;YAChCC,SAASzB;YACT0B,YAAYH,aAAaG,UAAU;YACnCC,QAAQ;mBAAKJ,aAAaI,MAAM,IAAI,EAAE;aAAE;QAC1C;QAEA,MAAMC,wBAAkC;YACtCH,SAASpB,oCAAqB;YAC9BqB,YAAY,CACVG;gBAEA,OAAOjB,OAAOC,MAAM,CAAC;oBACnBC,YAAYC,IAAAA,mCAAuB,EAACc,aAAaf;oBACjDE,iBAAiBa,aAAab,mBAAmB;gBACnD;YACF;YACAW,QAAQ;gBAAC3B;aAAgB;QAC3B;QAEA,2DAA2D;QAC3D,6DAA6D;QAC7D,4DAA4D;QAC5D,0DAA0D;QAC1D,0DAA0D;QAC1D,2DAA2D;QAC3D,wDAAwD;QACxD,iBAAiB;QACjB,MAAM8B,gBAAgBT,qBACpBT,OAAOC,MAAM,CAAC;YACZC,YAAYC,IAAAA,mCAAuB,EAACgB;YACpCf,iBAAiB;QACnB;QAEF,MAAMgB,WAAWF,cAAcG,MAAM,CACnC,CAACC,IACC,CACE,CAAA,OAAOA,MAAM,YACbA,MAAM,QACN,aAAaA,KACb,AAACA,EAA2BT,OAAO,KAAKpB,oCAAqB,AAAD;QAIlE,OAAO;YACLY,MAAM;YACNC,QAAQC,yBAAyB;gBAC/BC,WAAW;oBAACI;oBAAiBI;uBAA0BI;iBAAS;gBAChEG,SAASZ,aAAaY,OAAO;YAC/B;QACF;IACF;AACF;AAEA;;;;;;;;;;;CAWC,GACD,SAASd,qBACPV,QAAqC;IAErC,OAAO;QACLL,gDAAuB;QACvBC,0CAAoB;QACpBC,4CAAqB;QACrB;YACEiB,SAASrB,wBAAkB;YAC3BgC,aAAa9B,gDAAuB;QACtC;QACA;YACEmB,SAASpB,oCAAqB;YAC9BgC,UAAU1B;QACZ;KACD;AACH;AAEA;;;;;;;;;;;;;;;CAeC,GACD,SAASQ,yBAAyBmB,IAGjC;IACC,MAAMpB,SAAwB;QAC5BA,QAAQnB;QACRwC,QAAQ;QACRnB,WAAWkB,KAAKlB,SAAS;QACzBoB,SAAS;eAAIrC;SAAgB;IAC/B;IACA,IAAImC,KAAKH,OAAO,KAAKJ,WAAW;QAC9B,OAAO;YAAE,GAAGb,MAAM;YAAEiB,SAAS;mBAAIG,KAAKH,OAAO;aAAC;QAAC;IACjD;IACA,OAAOjB;AACT"}
|
|
1
|
+
{"version":3,"sources":["../../../src/adapters/bullmq.adapter.ts"],"sourcesContent":["import { Module, type DynamicModule, type Provider } from '@nestjs/common';\nimport { EXECUTION_STRATEGY, type BatchAdapter } from '@nest-batch/core';\n\nimport { BullMqExecutionStrategy } from '../bullmq-execution-strategy';\nimport { BullmqRuntime } from '../bullmq-runtime';\nimport { BullmqSchedule } from '../bullmq-schedule';\nimport { resolveBullMqConnection } from '../connection';\nimport {\n BULLMQ_MODULE_OPTIONS,\n type BullMqModuleOptions,\n type ResolvedBullMqModuleOptions,\n} from '../module-options';\n\n/**\n * Empty Nest module class that owns the BullMQ transport's\n * provider graph.\n *\n * Mirrors `InProcessModule` in `@nest-batch/core/src/adapters/\n * in-process.adapter.ts`: the class has no body on purpose. It is\n * purely a `DynamicModule` carrier — Nest's module system requires\n * *some* class to identify the module, and the empty class is the\n * minimum possible surface (no decorators, no lifecycle hooks, no\n * metadata). All real behaviour lives on the providers.\n */\n@Module({})\nexport class BullmqModule {}\n\n/**\n * Sentinel token for the async-options factory chain.\n *\n * `forRootAsync` registers a `useFactory` provider under this token\n * that runs the user's factory, then a second provider\n * (`BULLMQ_MODULE_OPTIONS`) that depends on it and freezes the\n * resolved options. A duplicate `provide` for\n * `BULLMQ_MODULE_OPTIONS` would crash Nest's container, so the\n * chain uses this private symbol as the intermediate step.\n *\n * Mirrors the `Symbol.for('@nest-batch/bullmq/OPTIONS_FACTORY')`\n * used by the legacy `BullmqBatchModule.forRootAsync()` — the\n * `Symbol.for` key is process-scoped and stable across module\n * versions, so any host still wiring up the legacy class is not\n * affected.\n */\nconst OPTIONS_FACTORY: symbol = Symbol.for('@nest-batch/bullmq/OPTIONS_FACTORY');\n\n/**\n * The list of exports the BullMQ adapter's `DynamicModule` exposes\n * to the host application.\n *\n * Centralised so the sync and async paths stay in lockstep — any\n * future addition (e.g. a `BullmqScheduler` controller) only needs\n * to be added here.\n *\n * The set mirrors the legacy `BullmqBatchModule.forRoot()` exports\n * (the `forRootAsync()` legacy path was missing\n * `BullmqRuntime` from `exports` — that omission is fixed\n * here, both paths now export the same five entries).\n *\n * - `EXECUTION_STRATEGY` — the DI token, so host code (e.g. a\n * `/healthz` endpoint) can resolve the strategy class via\n * `moduleRef.get(EXECUTION_STRATEGY)`.\n * - `BULLMQ_MODULE_OPTIONS` — the resolved connection / worker\n * config bag, for inspection and (future) for per-role client\n * builders.\n * - `BullMqExecutionStrategy` — the concrete class, for type-\n * strict consumers that prefer class injection.\n * - `BullmqRuntime` — the runtime that owns the\n * `Queue` / `Worker` / `QueueEvents` lifecycle.\n * - `BullmqSchedule` — the runtime that owns the\n * `@BatchScheduled` cron-to-BullMQ translation.\n */\nconst ADAPTER_EXPORTS: ReadonlyArray<\n symbol | typeof BullMqExecutionStrategy | typeof BullmqRuntime | typeof BullmqSchedule\n> = [\n EXECUTION_STRATEGY,\n BULLMQ_MODULE_OPTIONS,\n BullMqExecutionStrategy,\n BullmqRuntime,\n BullmqSchedule,\n];\n\n/**\n * `BullmqAdapter` — the transport adapter for `@nest-batch/bullmq`\n * used by the new factory-pattern\n * `NestBatchModule.forRoot({ adapters: { transport, ... } })` API.\n *\n * Overrides the default `EXECUTION_STRATEGY` token with a BullMQ-\n * backed `IExecutionStrategy` (`BullMqExecutionStrategy`) and wires\n * the runtime services that own the BullMQ client lifecycle\n * (`BullmqRuntime` for step enqueue + worker, plus\n * `BullmqSchedule` for `@BatchScheduled` cron entries).\n *\n * Two static methods:\n *\n * - `forRoot(options)` — synchronous configuration. The\n * connection options are resolved up-front and frozen under\n * the `BULLMQ_MODULE_OPTIONS` token. Use this when the Redis\n * host is known at module composition time.\n *\n * - `forRootAsync({ imports, inject, useFactory })` — async\n * configuration. The factory is registered as a sentinel\n * provider; the `BULLMQ_MODULE_OPTIONS` provider depends on\n * it. Use this when the connection comes from a config\n * service or another async source.\n *\n * The two methods share the same provider list via the\n * `buildStaticProviders` helper — the only difference is whether\n * `BULLMQ_MODULE_OPTIONS` is a value provider (sync) or a factory\n * provider that resolves the user's `useFactory` result (async).\n *\n * `globalProviders` is intentionally omitted. The recommended path\n * is to expose host-visible providers via the module's own\n * `exports` (see `ADAPTER_EXPORTS` above) — the `BatchAdapter`\n * interface's `globalProviders` field is for runtime classes the\n * adapter's own module needs but that core itself would also\n * re-export. `JobLauncher` (registered by `NestBatchModule`, not\n * by this adapter) injects the strategy by the `EXECUTION_STRATEGY`\n * token, which is already in `exports`, so the resolution chain\n * works without core having to know which adapter is active.\n *\n * @example\n * ```ts\n * // Synchronous wiring (connection known at module-build time)\n * import { Module } from '@nestjs/common';\n * import { NestBatchModule, InProcessAdapter } from '@nest-batch/core';\n * import { MikroOrmAdapter } from '@nest-batch/mikro-orm';\n * import { BullmqAdapter } from '@nest-batch/bullmq';\n *\n * @Module({\n * imports: [\n * NestBatchModule.forRoot({\n * adapters: {\n * persistence: MikroOrmAdapter,\n * transport: BullmqAdapter.forRoot({\n * connection: {\n * host: process.env.REDIS_HOST,\n * port: Number(process.env.REDIS_PORT),\n * keyPrefix: 'nest-batch:',\n * },\n * autoStartWorker: true,\n * }),\n * },\n * }),\n * ],\n * })\n * class AppModule {}\n * ```\n *\n * @example\n * ```ts\n * // Async wiring (connection sourced from ConfigService)\n * BullmqAdapter.forRootAsync({\n * imports: [ConfigModule],\n * inject: [ConfigService],\n * useFactory: (cfg: ConfigService) => ({\n * connection: {\n * host: cfg.get<string>('redis.host'),\n * port: cfg.get<number>('redis.port'),\n * password: cfg.get<string>('redis.password'),\n * },\n * }),\n * });\n * ```\n */\nexport class BullmqAdapter {\n /**\n * Synchronous configuration.\n *\n * Resolves the connection options up-front (`resolveBullMqConnection`\n * fills in defaults + freezes the bag) and emits a\n * `BatchAdapter` whose `module` is a `global: true`\n * `DynamicModule` registering the strategy class, the runtime\n * services, the `EXECUTION_STRATEGY` binding, and the resolved\n * options as a value provider under `BULLMQ_MODULE_OPTIONS`.\n *\n * No options object is required: the module accepts an empty\n * `{}` and applies all defaults (host `127.0.0.1`, port `6379`,\n * keyPrefix `nest-batch:`, no auth, no TLS, `autoStartWorker:\n * false`).\n *\n * @param options - Connection + worker config. All fields optional.\n * @returns A `BatchAdapter` with `name: 'bullmq'` and the\n * `BullmqModule` dynamic module.\n */\n static forRoot(options: BullMqModuleOptions = {}): BatchAdapter {\n const resolved: ResolvedBullMqModuleOptions = Object.freeze({\n connection: resolveBullMqConnection(options.connection),\n autoStartWorker: options.autoStartWorker ?? false,\n });\n return {\n name: 'bullmq',\n module: buildBullmqDynamicModule({\n providers: buildStaticProviders(resolved),\n }),\n };\n }\n\n /**\n * Async configuration — useful when the Redis connection comes\n * from a config service or another async provider.\n *\n * The shape mirrors `NestBatchModule.forRootAsync`:\n * - `imports` is forwarded to the resulting\n * `DynamicModule.imports` (so `ConfigModule` is available\n * when the factory runs).\n * - `inject` lists the providers the factory needs in its\n * argument list.\n * - `useFactory` resolves the options bag at module-build\n * time. The factory's return value is treated as\n * `BullMqModuleOptions` and is fed through\n * `resolveBullMqConnection` by the `BULLMQ_MODULE_OPTIONS`\n * factory provider (defaults applied, bag frozen).\n *\n * Implementation note: the factory is registered under the\n * package-private `OPTIONS_FACTORY` sentinel token; the\n * `BULLMQ_MODULE_OPTIONS` provider depends on it. This is the\n * same chain the legacy `BullmqBatchModule.forRootAsync` used\n * — the dynamic module is built off the static provider list,\n * with the static `BULLMQ_MODULE_OPTIONS` value provider\n * replaced by the async factory pair.\n *\n * @param asyncOptions - `{ imports, inject, useFactory }` bag.\n * `useFactory` is required; `imports` and `inject` are\n * optional and default to `[]`.\n * @returns A `BatchAdapter` with `name: 'bullmq'` and the\n * `BullmqModule` dynamic module (with `imports` wired).\n */\n static forRootAsync(asyncOptions: {\n imports?: DynamicModule['imports'];\n inject?: readonly unknown[];\n useFactory: (...args: unknown[]) => Promise<BullMqModuleOptions> | BullMqModuleOptions;\n }): BatchAdapter {\n const factoryProvider: Provider = {\n provide: OPTIONS_FACTORY,\n useFactory: asyncOptions.useFactory as (...args: unknown[]) => unknown,\n inject: [...(asyncOptions.inject ?? [])] as Array<string | symbol | Function>,\n };\n\n const mergedOptionsProvider: Provider = {\n provide: BULLMQ_MODULE_OPTIONS,\n useFactory: (fromFactory: BullMqModuleOptions | undefined): ResolvedBullMqModuleOptions => {\n return Object.freeze({\n connection: resolveBullMqConnection(fromFactory?.connection),\n autoStartWorker: fromFactory?.autoStartWorker ?? false,\n });\n },\n inject: [OPTIONS_FACTORY],\n };\n\n // The static provider list is the same as `forRoot` except\n // the value provider for `BULLMQ_MODULE_OPTIONS` is replaced\n // with the async factory above (a duplicate `provide` would\n // crash Nest's container). We seed `buildStaticProviders`\n // with a placeholder resolved bag (its value is discarded\n // — the async provider overrides the slot) so the function\n // can be the single source of truth for the rest of the\n // provider list.\n const baseProviders = buildStaticProviders(\n Object.freeze({\n connection: resolveBullMqConnection(undefined),\n autoStartWorker: false,\n }),\n );\n const filtered = baseProviders.filter(\n (p) =>\n !(\n typeof p === 'object' &&\n p !== null &&\n 'provide' in p &&\n (p as { provide: unknown }).provide === BULLMQ_MODULE_OPTIONS\n ),\n );\n\n return {\n name: 'bullmq',\n module: buildBullmqDynamicModule({\n providers: [factoryProvider, mergedOptionsProvider, ...filtered],\n imports: asyncOptions.imports,\n }),\n };\n }\n}\n\n/**\n * Build the static provider list shared by `forRoot()` and\n * `forRootAsync()`.\n *\n * Centralised so the sync and async paths declare the same set of\n * providers (and any future addition — e.g. a per-role client\n * builder — only needs to be added here).\n *\n * The async path then filters the `BULLMQ_MODULE_OPTIONS` entry\n * out of the returned array and replaces it with the factory\n * pair. Everything else is shared.\n */\nfunction buildStaticProviders(resolved: ResolvedBullMqModuleOptions): Provider[] {\n return [\n BullMqExecutionStrategy,\n BullmqRuntime,\n BullmqSchedule,\n {\n provide: EXECUTION_STRATEGY,\n useExisting: BullMqExecutionStrategy,\n },\n {\n provide: BULLMQ_MODULE_OPTIONS,\n useValue: resolved,\n },\n ];\n}\n\n/**\n * Build the `DynamicModule` payload for the BullMQ adapter.\n *\n * Extracted from the two factory methods so the provider /\n * export / global-true shape lives in one place. NestJS's\n * `validateExportedProvider` check rejects an `exports` entry\n * that is not in `providers` (or imported), so adding to one\n * without the other is a silent runtime failure — keeping the\n * two arrays synchronised by construction is the safest\n * pattern.\n *\n * `imports` is optional: `forRoot` does not need any (it has no\n * async providers), `forRootAsync` forwards the user's\n * `imports` (typically `ConfigModule`) so the factory's\n * `inject` targets resolve.\n */\nfunction buildBullmqDynamicModule(args: {\n providers: Provider[];\n imports?: DynamicModule['imports'];\n}): DynamicModule {\n const module: DynamicModule = {\n module: BullmqModule,\n global: true,\n providers: args.providers,\n exports: [...ADAPTER_EXPORTS],\n };\n if (args.imports !== undefined) {\n return { ...module, imports: [...args.imports] };\n }\n return module;\n}\n"],"names":["BullmqAdapter","BullmqModule","OPTIONS_FACTORY","Symbol","for","ADAPTER_EXPORTS","EXECUTION_STRATEGY","BULLMQ_MODULE_OPTIONS","BullMqExecutionStrategy","BullmqRuntime","BullmqSchedule","forRoot","options","resolved","Object","freeze","connection","resolveBullMqConnection","autoStartWorker","name","module","buildBullmqDynamicModule","providers","buildStaticProviders","forRootAsync","asyncOptions","factoryProvider","provide","useFactory","inject","mergedOptionsProvider","fromFactory","baseProviders","undefined","filtered","filter","p","imports","useExisting","useValue","args","global","exports"],"mappings":";;;;;;;;;;;QAoKaA;eAAAA;;QA3IAC;eAAAA;;;wBAzB6C;sBACJ;yCAEd;+BACV;gCACC;4BACS;+BAKjC;;;;;;;AAcA,IAAA,AAAMA,eAAN,MAAMA;AAAc;;;;AAE3B;;;;;;;;;;;;;;;CAeC,GACD,MAAMC,kBAA0BC,OAAOC,GAAG,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;CAyBC,GACD,MAAMC,kBAEF;IACFC,wBAAkB;IAClBC,oCAAqB;IACrBC,gDAAuB;IACvBC,4BAAa;IACbC,8BAAc;CACf;AAqFM,IAAA,AAAMV,gBAAN,MAAMA;IACX;;;;;;;;;;;;;;;;;;GAkBC,GACD,OAAOW,QAAQC,UAA+B,CAAC,CAAC,EAAgB;QAC9D,MAAMC,WAAwCC,OAAOC,MAAM,CAAC;YAC1DC,YAAYC,IAAAA,mCAAuB,EAACL,QAAQI,UAAU;YACtDE,iBAAiBN,QAAQM,eAAe,IAAI;QAC9C;QACA,OAAO;YACLC,MAAM;YACNC,QAAQC,yBAAyB;gBAC/BC,WAAWC,qBAAqBV;YAClC;QACF;IACF;IAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BC,GACD,OAAOW,aAAaC,YAInB,EAAgB;QACf,MAAMC,kBAA4B;YAChCC,SAASzB;YACT0B,YAAYH,aAAaG,UAAU;YACnCC,QAAQ;mBAAKJ,aAAaI,MAAM,IAAI,EAAE;aAAE;QAC1C;QAEA,MAAMC,wBAAkC;YACtCH,SAASpB,oCAAqB;YAC9BqB,YAAY,CAACG;gBACX,OAAOjB,OAAOC,MAAM,CAAC;oBACnBC,YAAYC,IAAAA,mCAAuB,EAACc,aAAaf;oBACjDE,iBAAiBa,aAAab,mBAAmB;gBACnD;YACF;YACAW,QAAQ;gBAAC3B;aAAgB;QAC3B;QAEA,2DAA2D;QAC3D,6DAA6D;QAC7D,4DAA4D;QAC5D,0DAA0D;QAC1D,0DAA0D;QAC1D,2DAA2D;QAC3D,wDAAwD;QACxD,iBAAiB;QACjB,MAAM8B,gBAAgBT,qBACpBT,OAAOC,MAAM,CAAC;YACZC,YAAYC,IAAAA,mCAAuB,EAACgB;YACpCf,iBAAiB;QACnB;QAEF,MAAMgB,WAAWF,cAAcG,MAAM,CACnC,CAACC,IACC,CACE,CAAA,OAAOA,MAAM,YACbA,MAAM,QACN,aAAaA,KACb,AAACA,EAA2BT,OAAO,KAAKpB,oCAAqB,AAAD;QAIlE,OAAO;YACLY,MAAM;YACNC,QAAQC,yBAAyB;gBAC/BC,WAAW;oBAACI;oBAAiBI;uBAA0BI;iBAAS;gBAChEG,SAASZ,aAAaY,OAAO;YAC/B;QACF;IACF;AACF;AAEA;;;;;;;;;;;CAWC,GACD,SAASd,qBAAqBV,QAAqC;IACjE,OAAO;QACLL,gDAAuB;QACvBC,4BAAa;QACbC,8BAAc;QACd;YACEiB,SAASrB,wBAAkB;YAC3BgC,aAAa9B,gDAAuB;QACtC;QACA;YACEmB,SAASpB,oCAAqB;YAC9BgC,UAAU1B;QACZ;KACD;AACH;AAEA;;;;;;;;;;;;;;;CAeC,GACD,SAASQ,yBAAyBmB,IAGjC;IACC,MAAMpB,SAAwB;QAC5BA,QAAQnB;QACRwC,QAAQ;QACRnB,WAAWkB,KAAKlB,SAAS;QACzBoB,SAAS;eAAIrC;SAAgB;IAC/B;IACA,IAAImC,KAAKH,OAAO,KAAKJ,WAAW;QAC9B,OAAO;YAAE,GAAGb,MAAM;YAAEiB,SAAS;mBAAIG,KAAKH,OAAO;aAAC;QAAC;IACjD;IACA,OAAOjB;AACT"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ExecutionStrategyContext, type IExecutionStrategy, type JobDefinition, type JobParameters, type LaunchResult } from '@nest-batch/core';
|
|
2
|
-
import {
|
|
2
|
+
import { BullmqRuntime, BULLMQ_STRATEGY_NAME } from './bullmq-runtime';
|
|
3
3
|
/**
|
|
4
4
|
* BullMQ execution strategy — the `@nest-batch/core`-facing
|
|
5
5
|
* transport that hands a `JobExecution` off to a BullMQ `Queue`
|
|
@@ -8,7 +8,7 @@ import { BullmqRuntimeService, BULLMQ_STRATEGY_NAME } from './bullmq-runtime.ser
|
|
|
8
8
|
* Design (T18):
|
|
9
9
|
* - The actual BullMQ resource ownership (queue / worker /
|
|
10
10
|
* queue-events lifecycle, connection tuning, event bridge)
|
|
11
|
-
* lives in `
|
|
11
|
+
* lives in `BullmqRuntime`. This class is a thin
|
|
12
12
|
* adapter that maps the `IExecutionStrategy` contract to
|
|
13
13
|
* the runtime service's `launch()` shape.
|
|
14
14
|
* - Splitting the two lets the runtime service be
|
|
@@ -36,7 +36,7 @@ export declare class BullMqExecutionStrategy implements IExecutionStrategy {
|
|
|
36
36
|
/** Strategy name. Mirrors the runtime service's name. */
|
|
37
37
|
readonly name = "bullmq";
|
|
38
38
|
private readonly logger;
|
|
39
|
-
constructor(runtime:
|
|
39
|
+
constructor(runtime: BullmqRuntime);
|
|
40
40
|
/**
|
|
41
41
|
* Enqueue the work and return the BullMQ job id. The DB
|
|
42
42
|
* execution row was created by the launcher BEFORE this
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bullmq-execution-strategy.d.ts","sourceRoot":"","sources":["../../src/bullmq-execution-strategy.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,
|
|
1
|
+
{"version":3,"file":"bullmq-execution-strategy.d.ts","sourceRoot":"","sources":["../../src/bullmq-execution-strategy.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBACa,uBAAwB,YAAW,kBAAkB;IAMpD,OAAO,CAAC,QAAQ,CAAC,OAAO;IALpC,yDAAyD;IACzD,QAAQ,CAAC,IAAI,YAAwB;IAErC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;gBAEtC,OAAO,EAAE,aAAa;IAEnD;;;;;;;;;;;OAWG;IACG,MAAM,CACV,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,wBAAwB,GAC5B,OAAO,CAAC,YAAY,CAAC;CAGzB;AAED;;;GAGG;AACH,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
|
|
@@ -10,14 +10,14 @@ function _export(target, all) {
|
|
|
10
10
|
}
|
|
11
11
|
_export(exports, {
|
|
12
12
|
get BULLMQ_STRATEGY_NAME () {
|
|
13
|
-
return
|
|
13
|
+
return _bullmqruntime.BULLMQ_STRATEGY_NAME;
|
|
14
14
|
},
|
|
15
15
|
get BullMqExecutionStrategy () {
|
|
16
16
|
return BullMqExecutionStrategy;
|
|
17
17
|
}
|
|
18
18
|
});
|
|
19
19
|
const _common = require("@nestjs/common");
|
|
20
|
-
const
|
|
20
|
+
const _bullmqruntime = require("./bullmq-runtime");
|
|
21
21
|
function _ts_decorate(decorators, target, key, desc) {
|
|
22
22
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
23
23
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -29,7 +29,7 @@ function _ts_metadata(k, v) {
|
|
|
29
29
|
}
|
|
30
30
|
let BullMqExecutionStrategy = class BullMqExecutionStrategy {
|
|
31
31
|
runtime;
|
|
32
|
-
/** Strategy name. Mirrors the runtime service's name. */ name =
|
|
32
|
+
/** Strategy name. Mirrors the runtime service's name. */ name = _bullmqruntime.BULLMQ_STRATEGY_NAME;
|
|
33
33
|
logger = new _common.Logger(BullMqExecutionStrategy.name);
|
|
34
34
|
constructor(runtime){
|
|
35
35
|
this.runtime = runtime;
|
|
@@ -53,7 +53,7 @@ BullMqExecutionStrategy = _ts_decorate([
|
|
|
53
53
|
(0, _common.Injectable)(),
|
|
54
54
|
_ts_metadata("design:type", Function),
|
|
55
55
|
_ts_metadata("design:paramtypes", [
|
|
56
|
-
typeof
|
|
56
|
+
typeof _bullmqruntime.BullmqRuntime === "undefined" ? Object : _bullmqruntime.BullmqRuntime
|
|
57
57
|
])
|
|
58
58
|
], BullMqExecutionStrategy);
|
|
59
59
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bullmq-execution-strategy.ts"],"sourcesContent":["import { Injectable, Logger } from '@nestjs/common';\n\nimport {\n type ExecutionStrategyContext,\n type IExecutionStrategy,\n type JobDefinition,\n type JobParameters,\n type LaunchResult,\n} from '@nest-batch/core';\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/bullmq-execution-strategy.ts"],"sourcesContent":["import { Injectable, Logger } from '@nestjs/common';\n\nimport {\n type ExecutionStrategyContext,\n type IExecutionStrategy,\n type JobDefinition,\n type JobParameters,\n type LaunchResult,\n} from '@nest-batch/core';\n\nimport { BullmqRuntime, BULLMQ_STRATEGY_NAME } from './bullmq-runtime';\n\n/**\n * BullMQ execution strategy — the `@nest-batch/core`-facing\n * transport that hands a `JobExecution` off to a BullMQ `Queue`\n * and lets a `Worker` process the work.\n *\n * Design (T18):\n * - The actual BullMQ resource ownership (queue / worker /\n * queue-events lifecycle, connection tuning, event bridge)\n * lives in `BullmqRuntime`. This class is a thin\n * adapter that maps the `IExecutionStrategy` contract to\n * the runtime service's `launch()` shape.\n * - Splitting the two lets the runtime service be\n * independently testable (e.g. a test that wants to drive\n * the worker without going through the launcher can\n * instantiate the runtime service alone), and lets the\n * strategy class stay as a stable public surface for\n * `EXECUTION_STRATEGY` consumers.\n * - The strategy inherits the runtime service's\n * `name` (`'bullmq'`) — the runtime service is the\n * single source of truth for the strategy name.\n *\n * `name` and `launch()` together comprise the T18 contract:\n * - `name = 'bullmq'` — replaces the T17 stub's\n * `'bullmq-stub'` so log lines and boundary reports can\n * tell the real implementation from the skeleton.\n * - `launch()` enqueues exactly one BullMQ job per step\n * (one job per step, NEVER one job per row/chunk) and\n * returns `{ kind: 'enqueued', queueJobId }`. The launch\n * is fire-and-forget; the launcher re-resolves the\n * canonical `JobExecution` from the repository.\n */\n@Injectable()\nexport class BullMqExecutionStrategy implements IExecutionStrategy {\n /** Strategy name. Mirrors the runtime service's name. */\n readonly name = BULLMQ_STRATEGY_NAME;\n\n private readonly logger = new Logger(BullMqExecutionStrategy.name);\n\n constructor(private readonly runtime: BullmqRuntime) {}\n\n /**\n * Enqueue the work and return the BullMQ job id. The DB\n * execution row was created by the launcher BEFORE this\n * method was called — this method MUST NOT re-create it\n * (the launcher's atomic create-or-lock would race with us).\n *\n * Throws on producer failure. The launcher propagates the\n * error to its caller; the canonical `JobExecution` row\n * stays in `STARTING` and the host's recovery path is\n * responsible for transitioning it (a future task will\n * wire a \"dead letter\" cleanup).\n */\n async launch(\n job: JobDefinition,\n params: JobParameters,\n ctx: ExecutionStrategyContext,\n ): Promise<LaunchResult> {\n return this.runtime.launch(job, params, ctx);\n }\n}\n\n/**\n * Re-export the canonical `name` for tests that want to assert\n * on it without importing the runtime service directly.\n */\nexport { BULLMQ_STRATEGY_NAME };\n"],"names":["BULLMQ_STRATEGY_NAME","BullMqExecutionStrategy","name","logger","Logger","runtime","launch","job","params","ctx"],"mappings":";;;;;;;;;;;QA6ESA;eAAAA,mCAAoB;;QAjChBC;eAAAA;;;wBA5CsB;+BAUiB;;;;;;;;;;AAkC7C,IAAA,AAAMA,0BAAN,MAAMA;;IACX,uDAAuD,GACvD,AAASC,OAAOF,mCAAoB,CAAC;IAEpBG,SAAS,IAAIC,cAAM,CAACH,wBAAwBC,IAAI,EAAE;IAEnE,YAAY,AAAiBG,OAAsB,CAAE;aAAxBA,UAAAA;IAAyB;IAEtD;;;;;;;;;;;GAWC,GACD,MAAMC,OACJC,GAAkB,EAClBC,MAAqB,EACrBC,GAA6B,EACN;QACvB,OAAO,IAAI,CAACJ,OAAO,CAACC,MAAM,CAACC,KAAKC,QAAQC;IAC1C;AACF"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { OnApplicationBootstrap, OnApplicationShutdown } from '@nestjs/common';
|
|
2
|
+
import { type IExecutionStrategy, type JobDefinition, type BatchObserver, type JobRepository } from '@nest-batch/core';
|
|
3
|
+
import { JobExecutor, JobRegistry } from '@nest-batch/core';
|
|
4
|
+
import { type ResolvedBullMqModuleOptions } from './module-options';
|
|
5
|
+
/**
|
|
6
|
+
* Payload shape stored in a BullMQ job's `data` field.
|
|
7
|
+
*
|
|
8
|
+
* The strategy enqueues one BullMQ job per step (or per partition,
|
|
9
|
+
* in a future enhancement). The worker reconstructs the
|
|
10
|
+
* `JobExecution` from the repository via `executionId` and the
|
|
11
|
+
* `JobDefinition` from the registry via `jobId`.
|
|
12
|
+
*
|
|
13
|
+
* Why not store the full `JobDefinition` in the payload?
|
|
14
|
+
* - IR is mutable across the host process (decorators / builders
|
|
15
|
+
* may swap providers in tests, hot-reload, etc.). The
|
|
16
|
+
* repository + registry are the canonical sources; the
|
|
17
|
+
* payload carries only the keys needed to look them up.
|
|
18
|
+
* - Storage size — IRs can be large (listeners, resolvers).
|
|
19
|
+
* Redis is transport, not cache; small payloads are cheaper.
|
|
20
|
+
*/
|
|
21
|
+
export interface BullmqJobPayload {
|
|
22
|
+
/** JobExecution id, used to load the canonical execution row. */
|
|
23
|
+
readonly executionId: string;
|
|
24
|
+
/** Mirrors `executionId` today; kept distinct for forward compat. */
|
|
25
|
+
readonly jobExecutionId: string;
|
|
26
|
+
/** JobDefinition id, used to look up the IR from the registry. */
|
|
27
|
+
readonly jobId: string;
|
|
28
|
+
/** Step id (the `name` field of the BullMQ job). */
|
|
29
|
+
readonly stepId: string;
|
|
30
|
+
/**
|
|
31
|
+
* Partition index. Reserved for a future enhancement where a
|
|
32
|
+
* chunk step is split into N partitions and enqueued as N
|
|
33
|
+
* BullMQ jobs. Today the strategy always enqueues one job
|
|
34
|
+
* per step (regardless of chunk size), so the field is
|
|
35
|
+
* `undefined`. Kept in the payload shape so the worker
|
|
36
|
+
* can distinguish "this is a step" from "this is a partition"
|
|
37
|
+
* without a separate discriminator.
|
|
38
|
+
*/
|
|
39
|
+
readonly partitionIndex?: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The single BullMQ queue name used by the strategy + worker +
|
|
43
|
+
* queue-events. We deliberately do not fan out into per-step
|
|
44
|
+
* queues — that would force the host to pre-declare every step
|
|
45
|
+
* name at compile time, which is at odds with the decorator /
|
|
46
|
+
* builder APIs that discover steps at runtime. A single queue
|
|
47
|
+
* keyed by the step's `name` field is the standard BullMQ pattern
|
|
48
|
+
* (the `name` field discriminates the work).
|
|
49
|
+
*
|
|
50
|
+
* BullMQ 5 rejects queue names that contain a colon (`:`) because
|
|
51
|
+
* it is the path separator in the Redis key layout. We use a
|
|
52
|
+
* hyphen-separated name accordingly.
|
|
53
|
+
*/
|
|
54
|
+
export declare const BULLMQ_QUEUE_NAME = "nest-batch-work";
|
|
55
|
+
/**
|
|
56
|
+
* Name of the BullMQ strategy. Logged by the bridge for diagnostic
|
|
57
|
+
* purposes and asserted by tests that need to distinguish the
|
|
58
|
+
* real implementation from the T17 stub.
|
|
59
|
+
*/
|
|
60
|
+
export declare const BULLMQ_STRATEGY_NAME = "bullmq";
|
|
61
|
+
/**
|
|
62
|
+
* Bridge between the BullMQ `Queue` / `Worker` / `QueueEvents` and
|
|
63
|
+
* the `@nest-batch/core` execution pipeline.
|
|
64
|
+
*
|
|
65
|
+
* Responsibilities (T18 contract):
|
|
66
|
+
* 1. Own the producer / worker connection clients with the
|
|
67
|
+
* role-specific tuning (fail-fast producer, blocking worker).
|
|
68
|
+
* 2. Implement the `IExecutionStrategy` contract: `launch()`
|
|
69
|
+
* enqueues a single BullMQ job per step, returns
|
|
70
|
+
* `{ kind: 'enqueued', queueJobId }`. The launch is
|
|
71
|
+
* fire-and-forget — the strategy does NOT block on the
|
|
72
|
+
* worker.
|
|
73
|
+
* 3. Drive the worker lifecycle (`OnApplicationBootstrap` /
|
|
74
|
+
* `OnApplicationShutdown`).
|
|
75
|
+
* 4. Bridge `QueueEvents` `completed` / `failed` / `stalled`
|
|
76
|
+
* into the `BatchObserver` (defaulting to `NoopBatchObserver`).
|
|
77
|
+
* 5. Hand off to `JobExecutor.execute(execution, jobDef)` from
|
|
78
|
+
* inside the worker — Batch Core remains the source of truth
|
|
79
|
+
* for state transitions, skip/retry, checkpoint, restart.
|
|
80
|
+
*
|
|
81
|
+
* Why a single class (not separate `Queue` / `Worker` providers)?
|
|
82
|
+
* - The producer and worker share a `connection` record but
|
|
83
|
+
* carry *different* `ConnectionOptions` (different
|
|
84
|
+
* `maxRetriesPerRequest`, `enableReadyCheck`, ...). Splitting
|
|
85
|
+
* them across providers would force the connection-tuning
|
|
86
|
+
* logic into two places and risk the worker accidentally
|
|
87
|
+
* inheriting the producer's fail-fast config (or vice versa).
|
|
88
|
+
* - Lifecycle is a unit: open producer + worker + events
|
|
89
|
+
* together, close them together in the documented order
|
|
90
|
+
* (workers first, then events, then queues). Centralising
|
|
91
|
+
* this in one class makes the close-order a single source
|
|
92
|
+
* of truth and a single method (`close()`).
|
|
93
|
+
*/
|
|
94
|
+
export declare class BullmqRuntime implements IExecutionStrategy, OnApplicationBootstrap, OnApplicationShutdown {
|
|
95
|
+
private readonly options;
|
|
96
|
+
private readonly repository;
|
|
97
|
+
private readonly registry;
|
|
98
|
+
private readonly jobExecutor;
|
|
99
|
+
private readonly observer;
|
|
100
|
+
/**
|
|
101
|
+
* Strategy name. Distinct from the T17 stub's `'bullmq-stub'`
|
|
102
|
+
* so log lines and boundary reports can tell them apart.
|
|
103
|
+
*/
|
|
104
|
+
readonly name = "bullmq";
|
|
105
|
+
private readonly logger;
|
|
106
|
+
/** BullMQ queue (producer side). */
|
|
107
|
+
private queue;
|
|
108
|
+
/** BullMQ worker (consumer side). */
|
|
109
|
+
private worker;
|
|
110
|
+
/** BullMQ QueueEvents stream listener. */
|
|
111
|
+
private queueEvents;
|
|
112
|
+
/**
|
|
113
|
+
* Promise-chain lock for the close path. We capture the first
|
|
114
|
+
* `close()` invocation and short-circuit subsequent ones so a
|
|
115
|
+
* stray double-shutdown (Nest calls `OnApplicationShutdown`
|
|
116
|
+
* once, but tests sometimes do their own) does not race the
|
|
117
|
+
* in-flight close.
|
|
118
|
+
*/
|
|
119
|
+
private closePromise;
|
|
120
|
+
constructor(options: ResolvedBullMqModuleOptions, repository: JobRepository, registry: JobRegistry, jobExecutor: JobExecutor, observer?: BatchObserver);
|
|
121
|
+
/**
|
|
122
|
+
* Nest lifecycle: spin up the queue, worker, and queue-events
|
|
123
|
+
* after the DI container is fully wired. We do this in
|
|
124
|
+
* `onApplicationBootstrap` (not `onModuleInit`) so every other
|
|
125
|
+
* provider — including user-supplied `JobRepository` overrides —
|
|
126
|
+
* is already instantiated and injectable.
|
|
127
|
+
*
|
|
128
|
+
* Worker startup is gated on `options.autoStartWorker`. The
|
|
129
|
+
* flag exists for launcher-only deployments (e.g. an API
|
|
130
|
+
* service that only enqueues) and for tests that want to
|
|
131
|
+
* exercise the producer side in isolation. When the flag is
|
|
132
|
+
* `false` the queue is still created (so `launch()` can
|
|
133
|
+
* enqueue), but the worker is not started (no consumer means
|
|
134
|
+
* the jobs sit in the queue indefinitely).
|
|
135
|
+
*/
|
|
136
|
+
onApplicationBootstrap(): void;
|
|
137
|
+
/**
|
|
138
|
+
* Nest lifecycle: close every BullMQ resource in the documented
|
|
139
|
+
* order — workers first (let in-flight jobs finish or be
|
|
140
|
+
* returned to the queue), then events (no new events can
|
|
141
|
+
* arrive once the worker is closed), then queues (the producer
|
|
142
|
+
* is closed last so any pending `add()` calls had a chance to
|
|
143
|
+
* land).
|
|
144
|
+
*
|
|
145
|
+
* Idempotent: a second call to `onApplicationShutdown` (which
|
|
146
|
+
* can happen in tests) short-circuits to the first close's
|
|
147
|
+
* promise rather than racing.
|
|
148
|
+
*/
|
|
149
|
+
onApplicationShutdown(): Promise<void>;
|
|
150
|
+
/**
|
|
151
|
+
* Enqueue a single BullMQ job per step. Returns
|
|
152
|
+
* `{ kind: 'enqueued', queueJobId }` after the producer has
|
|
153
|
+
* acknowledged the enqueue. The execution is fire-and-forget:
|
|
154
|
+
* the launcher resolves the latest persisted `JobExecution`
|
|
155
|
+
* (which is still in `STARTING`/`STARTED` because the executor
|
|
156
|
+
* has not run yet).
|
|
157
|
+
*
|
|
158
|
+
* The canonical `JobExecution` row is created by the launcher
|
|
159
|
+
* via `repository.createExecutionAtomic` BEFORE this method is
|
|
160
|
+
* called (the `executionId` in `ctx` is the result). This
|
|
161
|
+
* strategy does NOT re-create it; doing so would race the
|
|
162
|
+
* launcher's atomic create and break the `SELECT ... FOR
|
|
163
|
+
* UPDATE SKIP LOCKED` invariant.
|
|
164
|
+
*
|
|
165
|
+
* Throws if the producer cannot enqueue (Redis down, key
|
|
166
|
+
* collision, etc.). The launcher re-throws the error to its
|
|
167
|
+
* caller; the `JobExecution` row remains in `STARTING` —
|
|
168
|
+
* the host's recovery path (or a manual cleanup) is
|
|
169
|
+
* responsible for transitioning it.
|
|
170
|
+
*/
|
|
171
|
+
launch(job: JobDefinition, _params: Record<string, unknown>, ctx: {
|
|
172
|
+
executionId: string;
|
|
173
|
+
jobExecutionId: string;
|
|
174
|
+
}): Promise<{
|
|
175
|
+
kind: 'enqueued';
|
|
176
|
+
queueJobId: string;
|
|
177
|
+
}>;
|
|
178
|
+
private buildQueue;
|
|
179
|
+
private buildWorker;
|
|
180
|
+
private buildQueueEvents;
|
|
181
|
+
/**
|
|
182
|
+
* Wire the `QueueEvents` listeners to the configured
|
|
183
|
+
* `BatchObserver`. Each listener swallows observer errors so
|
|
184
|
+
* a slow / failing observer cannot poison the BullMQ event
|
|
185
|
+
* stream.
|
|
186
|
+
*/
|
|
187
|
+
private attachQueueEventsBridge;
|
|
188
|
+
private bridgeEvent;
|
|
189
|
+
/**
|
|
190
|
+
* Worker entry point. Loads the canonical `JobExecution` from
|
|
191
|
+
* the repository and the `JobDefinition` from the registry, then
|
|
192
|
+
* hands the work to `JobExecutor.execute`. All batch semantics
|
|
193
|
+
* (step dispatch, chunk loop, skip/retry, checkpoint) live in
|
|
194
|
+
* the executor — this method is a thin bridge.
|
|
195
|
+
*/
|
|
196
|
+
private processJob;
|
|
197
|
+
/**
|
|
198
|
+
* Producer-side connection tuning. The two flags below are
|
|
199
|
+
* the contract the T18 "Redis-down" test depends on:
|
|
200
|
+
*
|
|
201
|
+
* - `enableOfflineQueue: false` — a `Queue.add()` against a
|
|
202
|
+
* dead Redis MUST throw synchronously rather than buffer
|
|
203
|
+
* the command. Without this, BullMQ keeps the command in
|
|
204
|
+
* memory and `add()` returns success, breaking the
|
|
205
|
+
* "fail fast" guarantee.
|
|
206
|
+
* - `maxRetriesPerRequest: 1` — keep the first `add`
|
|
207
|
+
* fast; subsequent reconnects are handled by ioredis
|
|
208
|
+
* itself (we do not want BullMQ to block on retries
|
|
209
|
+
* during the launcher call).
|
|
210
|
+
*
|
|
211
|
+
* BullMQ specifically warns against `maxRetriesPerRequest: null`
|
|
212
|
+
* on the producer, because the producer does not use blocking
|
|
213
|
+
* commands. We use `1` for the same reason.
|
|
214
|
+
*/
|
|
215
|
+
private producerConnectionOptions;
|
|
216
|
+
/**
|
|
217
|
+
* Worker-side connection tuning. Two flags that BullMQ
|
|
218
|
+
* *requires* for blocking workers (per the BullMQ docs):
|
|
219
|
+
*
|
|
220
|
+
* - `maxRetriesPerRequest: null` — the worker's
|
|
221
|
+
* `BLPOP` / `BRPOPLPUSH` / `XREADGROUP` commands MUST NOT
|
|
222
|
+
* retry per request. A stalled worker surfaces as a
|
|
223
|
+
* stall, not a connection error.
|
|
224
|
+
* - `enableReadyCheck: false` — the worker should not
|
|
225
|
+
* refuse to start when Redis is in the middle of a
|
|
226
|
+
* failover; ioredis reconnects on its own.
|
|
227
|
+
*/
|
|
228
|
+
private workerConnectionOptions;
|
|
229
|
+
/**
|
|
230
|
+
* Close all BullMQ resources in the documented order:
|
|
231
|
+
* worker → events → queue. Each step is best-effort: a close
|
|
232
|
+
* error on one resource does not prevent the others from
|
|
233
|
+
* being closed.
|
|
234
|
+
*/
|
|
235
|
+
private close;
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=bullmq-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bullmq-runtime.d.ts","sourceRoot":"","sources":["../../src/bullmq-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,sBAAsB,EACtB,qBAAqB,EAEtB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,aAAa,EAElB,KAAK,aAAa,EAInB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,WAAW,EAAkC,MAAM,kBAAkB,CAAC;AAE5F,OAAO,EAAyB,KAAK,2BAA2B,EAAE,MAAM,kBAAkB,CAAC;AAE3F;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,oBAAoB,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBACa,aACX,YAAW,kBAAkB,EAAE,sBAAsB,EAAE,qBAAqB;IA2B1E,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAE5B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IA/B3B;;;OAGG;IACH,QAAQ,CAAC,IAAI,YAAwB;IAErC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IAEzD,oCAAoC;IACpC,OAAO,CAAC,KAAK,CAAsB;IACnC,qCAAqC;IACrC,OAAO,CAAC,MAAM,CAAyC;IACvD,0CAA0C;IAC1C,OAAO,CAAC,WAAW,CAA4B;IAC/C;;;;;;OAMG;IACH,OAAO,CAAC,YAAY,CAA8B;gBAI/B,OAAO,EAAE,2BAA2B,EAEpC,UAAU,EAAE,aAAa,EACzB,QAAQ,EAAE,WAAW,EACrB,WAAW,EAAE,WAAW,EAExB,QAAQ,GAAE,aAAwD;IAGrF;;;;;;;;;;;;;;OAcG;IACH,sBAAsB,IAAI,IAAI;IAmB9B;;;;;;;;;;;OAWG;IACG,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5C;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,MAAM,CACV,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,GAAG,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,GACnD,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAsEpD,OAAO,CAAC,UAAU;IAiClB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,gBAAgB;IAOxB;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;YAiBjB,WAAW;IAsBzB;;;;;;OAMG;YACW,UAAU;IAyBxB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,yBAAyB;IAajC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,uBAAuB;IAiB/B;;;;;OAKG;YACW,KAAK;CA8BpB"}
|