@bymax-one/nest-queue 1.0.3 → 1.0.5
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/CHANGELOG.md +107 -0
- package/README.md +8 -8
- package/dist/server/index.d.cts +23 -2
- package/dist/server/index.d.ts +23 -2
- package/package.json +14 -13
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,110 @@ versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [1.0.5] — 2026-08-01
|
|
11
|
+
|
|
12
|
+
Documentation only. `dist/` is byte-identical to `1.0.4` — verified by diffing a
|
|
13
|
+
fresh build against the published tarball — so there is no runtime change.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **The README's configuration examples did not compile in a strict project.**
|
|
18
|
+
Eight snippets passed `process.env.REDIS_URL` where a `string` is required:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
TS2322: Type 'string | undefined' is not assignable to type 'string'.
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`process.env.X` is `string | undefined` under `strict`, so anyone copying the
|
|
25
|
+
Quick Start into a strict TypeScript project — the configuration this library
|
|
26
|
+
itself uses and recommends — got a type error out of the box. Now shown with a
|
|
27
|
+
fallback, which is what the code has to do anyway:
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
connection: {
|
|
31
|
+
url: process.env.REDIS_URL ?? 'redis://localhost:6379'
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Found by `pnpm check:published`, added in the same release, which compiles the
|
|
36
|
+
README's own snippets against the built package. Nobody had reported it, and
|
|
37
|
+
nothing before this would have.
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- **`pnpm check:published`** — a gate that verifies the published surface matches
|
|
42
|
+
the documentation, before a tag rather than after it. It scaffolds a throwaway
|
|
43
|
+
consumer, symlinks the package into its own `node_modules` so resolution runs
|
|
44
|
+
through the `exports` map into `dist/`, and then checks that the README's links
|
|
45
|
+
resolve, that its TypeScript snippets and the type tests compile against the
|
|
46
|
+
built package, and that every `v*.*.*` tag has a `## [x.y.z]` CHANGELOG section.
|
|
47
|
+
|
|
48
|
+
Each of those exists because its absence let a defect reach npm: the 404 link
|
|
49
|
+
corrected in `1.0.3`, the exported type that rejected the README's own snippet
|
|
50
|
+
corrected in `1.0.4`, and a deleted heading that would have turned release notes
|
|
51
|
+
into the generic fallback.
|
|
52
|
+
|
|
53
|
+
It runs in CI, in `release.yml`, and inside `prepublishOnly` — the last one
|
|
54
|
+
because the first publish of a package is manual by design, which is precisely
|
|
55
|
+
the path that bypasses the tag workflow.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## [1.0.4] — 2026-08-01
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- **`BymaxQueueModuleAsyncOptions.useFactory` rejected the factory this library
|
|
64
|
+
documents.** It was declared `(...args: unknown[]) => …`, and a parameter typed
|
|
65
|
+
`unknown` accepts no narrower parameter under `strictFunctionTypes`. So the
|
|
66
|
+
shape shown in the README and in `BymaxQueueModule`'s own `@example`:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
useFactory: (client: Redis) => ({ connection: { client } })
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
failed to typecheck **against the exported interface**:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
TS2322: Type '(client: Redis) => …' is not assignable to
|
|
76
|
+
type '(...args: unknown[]) => …'
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Scope, precisely: `forRootAsync` is typed by NestJS's `ASYNC_OPTIONS_TYPE`, not
|
|
80
|
+
by this interface, so passing the object **inline** always compiled. Only a
|
|
81
|
+
consumer who annotated it — extracting the options into a
|
|
82
|
+
`const opts: BymaxQueueModuleAsyncOptions = { … }` — hit the error. The
|
|
83
|
+
interface was stricter than the module it describes.
|
|
84
|
+
|
|
85
|
+
It is now declared with **method syntax**. `strictFunctionTypes` makes
|
|
86
|
+
parameters contravariant for function-typed _properties_ but leaves method
|
|
87
|
+
parameters bivariant, so the interface accepts a factory that names its
|
|
88
|
+
injected types. This **widens** what is accepted: every factory that compiled
|
|
89
|
+
before still does, the variadic `(...args: unknown[])` form included. Nothing
|
|
90
|
+
needs changing in consumer code.
|
|
91
|
+
|
|
92
|
+
Method syntax rather than a looser parameter type, because the factory has to
|
|
93
|
+
stay **callable**: NestJS invokes it with the values `inject` resolves, and a
|
|
94
|
+
consumer may call it directly in a unit test. A `never[]` rest parameter would
|
|
95
|
+
have bought the same assignability and silently cost that —
|
|
96
|
+
`options.useFactory(client)` fails with `TS2345: Argument of type 'Redis' is
|
|
97
|
+
not assignable to parameter of type 'never'`.
|
|
98
|
+
|
|
99
|
+
Pinned by seven cases in `test/types/public-api.test-d.ts` — typed parameter,
|
|
100
|
+
async, several parameters, zero parameters, the pre-1.0.4 variadic form, and
|
|
101
|
+
two for callability — where `useFactory` was previously pinned by nothing,
|
|
102
|
+
which is why this went unnoticed. Red-checked against **both** rejected
|
|
103
|
+
signatures: the original property form fails the assignability cases, and
|
|
104
|
+
`never[]` fails the callability ones.
|
|
105
|
+
|
|
106
|
+
No runtime change, verified rather than asserted: diffed against the published
|
|
107
|
+
`1.0.3` tarball, all four emitted runtime files (`server` and `shared`, `.mjs`
|
|
108
|
+
and `.cjs`) are byte-identical, and only `dist/server/index.d.ts` / `.d.cts`
|
|
109
|
+
differ. The altered source declares types only, so it produces no Stryker
|
|
110
|
+
mutants and the 99.06% score stands.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
10
114
|
## [1.0.3] — 2026-08-01
|
|
11
115
|
|
|
12
116
|
Documentation only. `dist/` is byte-identical to `1.0.2` — verified by unpacking
|
|
@@ -207,6 +311,9 @@ v6 peer range.
|
|
|
207
311
|
|
|
208
312
|
---
|
|
209
313
|
|
|
314
|
+
[1.0.5]: https://github.com/bymaxone/nest-queue/releases/tag/v1.0.5
|
|
315
|
+
[1.0.4]: https://github.com/bymaxone/nest-queue/releases/tag/v1.0.4
|
|
316
|
+
[1.0.3]: https://github.com/bymaxone/nest-queue/releases/tag/v1.0.3
|
|
210
317
|
[1.0.2]: https://github.com/bymaxone/nest-queue/releases/tag/v1.0.2
|
|
211
318
|
[1.0.1]: https://github.com/bymaxone/nest-queue/releases/tag/v1.0.1
|
|
212
319
|
[1.0.0]: https://github.com/bymaxone/nest-queue/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -149,7 +149,7 @@ import { BymaxQueueModule } from '@bymax-one/nest-queue'
|
|
|
149
149
|
@Module({
|
|
150
150
|
imports: [
|
|
151
151
|
BymaxQueueModule.forRoot({
|
|
152
|
-
connection: { url: process.env.REDIS_URL },
|
|
152
|
+
connection: { url: process.env.REDIS_URL ?? 'redis://localhost:6379' },
|
|
153
153
|
isGlobal: true,
|
|
154
154
|
}),
|
|
155
155
|
],
|
|
@@ -259,7 +259,7 @@ Mode B lets the library own the Redis connections. Pass either a URL or raw iore
|
|
|
259
259
|
```typescript
|
|
260
260
|
// URL form
|
|
261
261
|
BymaxQueueModule.forRoot({
|
|
262
|
-
connection: { url: process.env.REDIS_URL },
|
|
262
|
+
connection: { url: process.env.REDIS_URL ?? 'redis://localhost:6379' },
|
|
263
263
|
isGlobal: true,
|
|
264
264
|
})
|
|
265
265
|
|
|
@@ -267,9 +267,9 @@ BymaxQueueModule.forRoot({
|
|
|
267
267
|
BymaxQueueModule.forRoot({
|
|
268
268
|
connection: {
|
|
269
269
|
options: {
|
|
270
|
-
host: process.env.REDIS_HOST,
|
|
270
|
+
host: process.env.REDIS_HOST ?? 'localhost',
|
|
271
271
|
port: Number(process.env.REDIS_PORT),
|
|
272
|
-
password: process.env.REDIS_PASSWORD,
|
|
272
|
+
password: process.env.REDIS_PASSWORD ?? undefined,
|
|
273
273
|
tls: {},
|
|
274
274
|
},
|
|
275
275
|
},
|
|
@@ -345,7 +345,7 @@ Enable flows in the module options and inject the service:
|
|
|
345
345
|
|
|
346
346
|
```typescript
|
|
347
347
|
BymaxQueueModule.forRoot({
|
|
348
|
-
connection: { url: process.env.REDIS_URL },
|
|
348
|
+
connection: { url: process.env.REDIS_URL ?? 'redis://localhost:6379' },
|
|
349
349
|
flows: { enabled: true },
|
|
350
350
|
})
|
|
351
351
|
|
|
@@ -370,7 +370,7 @@ Provide a per-queue snapshot with a configurable TTL cache:
|
|
|
370
370
|
|
|
371
371
|
```typescript
|
|
372
372
|
BymaxQueueModule.forRoot({
|
|
373
|
-
connection: { url: process.env.REDIS_URL },
|
|
373
|
+
connection: { url: process.env.REDIS_URL ?? 'redis://localhost:6379' },
|
|
374
374
|
metrics: { enabled: true, cacheTtlMs: 5_000 },
|
|
375
375
|
})
|
|
376
376
|
|
|
@@ -562,7 +562,7 @@ Pass a `bullmq-otel` telemetry instance (optional peer dep) to trace spans from
|
|
|
562
562
|
import { BullMQOtel } from 'bullmq-otel'
|
|
563
563
|
|
|
564
564
|
BymaxQueueModule.forRoot({
|
|
565
|
-
connection: { url: process.env.REDIS_URL },
|
|
565
|
+
connection: { url: process.env.REDIS_URL ?? 'redis://localhost:6379' },
|
|
566
566
|
telemetry: new BullMQOtel('my-service', tracer),
|
|
567
567
|
})
|
|
568
568
|
```
|
|
@@ -602,7 +602,7 @@ Tune `drainTimeoutMs` when jobs may run longer than 30 s:
|
|
|
602
602
|
|
|
603
603
|
```typescript
|
|
604
604
|
BymaxQueueModule.forRoot({
|
|
605
|
-
connection: { url: process.env.REDIS_URL },
|
|
605
|
+
connection: { url: process.env.REDIS_URL ?? 'redis://localhost:6379' },
|
|
606
606
|
shutdown: { drainTimeoutMs: 60_000 },
|
|
607
607
|
})
|
|
608
608
|
```
|
package/dist/server/index.d.cts
CHANGED
|
@@ -97,8 +97,29 @@ interface BymaxQueueOptionsFactory {
|
|
|
97
97
|
}
|
|
98
98
|
/** Asynchronous configuration mirroring the NestJS async dynamic-module pattern. */
|
|
99
99
|
interface BymaxQueueModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
|
|
100
|
-
/**
|
|
101
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Factory returning the module options. Its parameters are whatever `inject`
|
|
102
|
+
* resolves to, so declare them with the types you expect:
|
|
103
|
+
*
|
|
104
|
+
* ```ts
|
|
105
|
+
* useFactory: (client: Redis) => ({ connection: { client } })
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* Declared with **method syntax** on purpose. `strictFunctionTypes` makes
|
|
109
|
+
* parameters contravariant for function-typed *properties* but leaves method
|
|
110
|
+
* parameters bivariant, so this accepts a factory that names its injected
|
|
111
|
+
* types — which a property typed `(...args: unknown[]) => …` rejects, since
|
|
112
|
+
* `unknown` is assignable from no narrower parameter. That rejection is what
|
|
113
|
+
* made the form above fail against this interface while compiling when passed
|
|
114
|
+
* inline to `forRootAsync`.
|
|
115
|
+
*
|
|
116
|
+
* Bivariance is the right trade here rather than a looser parameter type:
|
|
117
|
+
* NestJS resolves these arguments from `inject` at runtime, so no signature
|
|
118
|
+
* can make them statically safe, and method syntax keeps the factory
|
|
119
|
+
* **callable** — `options.useFactory(client)` typechecks, which a
|
|
120
|
+
* `never[]` rest parameter would have broken.
|
|
121
|
+
*/
|
|
122
|
+
useFactory?(...args: unknown[]): Promise<BymaxQueueModuleOptions> | BymaxQueueModuleOptions;
|
|
102
123
|
/** Class implementing the options factory. */
|
|
103
124
|
useClass?: Type<BymaxQueueOptionsFactory>;
|
|
104
125
|
/** Existing provider implementing the options factory. */
|
package/dist/server/index.d.ts
CHANGED
|
@@ -97,8 +97,29 @@ interface BymaxQueueOptionsFactory {
|
|
|
97
97
|
}
|
|
98
98
|
/** Asynchronous configuration mirroring the NestJS async dynamic-module pattern. */
|
|
99
99
|
interface BymaxQueueModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
|
|
100
|
-
/**
|
|
101
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Factory returning the module options. Its parameters are whatever `inject`
|
|
102
|
+
* resolves to, so declare them with the types you expect:
|
|
103
|
+
*
|
|
104
|
+
* ```ts
|
|
105
|
+
* useFactory: (client: Redis) => ({ connection: { client } })
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* Declared with **method syntax** on purpose. `strictFunctionTypes` makes
|
|
109
|
+
* parameters contravariant for function-typed *properties* but leaves method
|
|
110
|
+
* parameters bivariant, so this accepts a factory that names its injected
|
|
111
|
+
* types — which a property typed `(...args: unknown[]) => …` rejects, since
|
|
112
|
+
* `unknown` is assignable from no narrower parameter. That rejection is what
|
|
113
|
+
* made the form above fail against this interface while compiling when passed
|
|
114
|
+
* inline to `forRootAsync`.
|
|
115
|
+
*
|
|
116
|
+
* Bivariance is the right trade here rather than a looser parameter type:
|
|
117
|
+
* NestJS resolves these arguments from `inject` at runtime, so no signature
|
|
118
|
+
* can make them statically safe, and method syntax keeps the factory
|
|
119
|
+
* **callable** — `options.useFactory(client)` typechecks, which a
|
|
120
|
+
* `never[]` rest parameter would have broken.
|
|
121
|
+
*/
|
|
122
|
+
useFactory?(...args: unknown[]): Promise<BymaxQueueModuleOptions> | BymaxQueueModuleOptions;
|
|
102
123
|
/** Class implementing the options factory. */
|
|
103
124
|
useClass?: Type<BymaxQueueOptionsFactory>;
|
|
104
125
|
/** Existing provider implementing the options factory. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bymax-one/nest-queue",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "NestJS dynamic module wrapping BullMQ — typed jobs, flows, job schedulers, deduplication, OpenTelemetry, graceful shutdown",
|
|
5
5
|
"author": "Bymax One <support@bymax.one>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -131,23 +131,24 @@
|
|
|
131
131
|
},
|
|
132
132
|
"scripts": {
|
|
133
133
|
"build": "pnpm clean && tsup",
|
|
134
|
+
"check:exports": "attw --pack .",
|
|
135
|
+
"check:published": "node scripts/check-published-surface.mjs",
|
|
136
|
+
"clean": "rm -rf dist coverage",
|
|
134
137
|
"lint": "eslint src scripts test",
|
|
135
138
|
"lint:fix": "eslint src scripts test --fix",
|
|
136
|
-
"test": "jest",
|
|
137
|
-
"test:cov": "jest --coverage",
|
|
138
|
-
"test:watch": "jest --watch",
|
|
139
|
-
"test:e2e": "jest --config jest.e2e.config.ts",
|
|
140
|
-
"test:all": "pnpm test && pnpm test:e2e",
|
|
141
|
-
"test:cov:all": "jest --config jest.coverage.config.ts --coverage",
|
|
142
|
-
"test:types": "tsc --noEmit -p tsconfig.typetest.json",
|
|
143
139
|
"mutation": "stryker run",
|
|
144
|
-
"mutation:incremental": "stryker run --incremental",
|
|
145
140
|
"mutation:dry-run": "stryker run --dryRunOnly",
|
|
146
|
-
"
|
|
141
|
+
"mutation:incremental": "stryker run --incremental",
|
|
142
|
+
"release": "pnpm publish --provenance",
|
|
147
143
|
"size": "node scripts/check-size.mjs",
|
|
148
144
|
"smoke": "node scripts/dogfood-smoke-test.mjs",
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
145
|
+
"test": "jest",
|
|
146
|
+
"test:all": "pnpm test && pnpm test:e2e",
|
|
147
|
+
"test:cov": "jest --coverage",
|
|
148
|
+
"test:cov:all": "jest --config jest.coverage.config.ts --coverage",
|
|
149
|
+
"test:e2e": "jest --config jest.e2e.config.ts",
|
|
150
|
+
"test:types": "tsc --noEmit -p tsconfig.typetest.json",
|
|
151
|
+
"test:watch": "jest --watch",
|
|
152
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.server.json"
|
|
152
153
|
}
|
|
153
154
|
}
|