@oneunit/redis 0.0.0-stage → 1.0.0
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/ARCHITECTURE.md +422 -0
- package/CHANGELOG.md +186 -0
- package/CONTRIBUTING.md +353 -0
- package/LICENSE +21 -0
- package/README.md +760 -2
- package/dist/client/check.d.ts +19 -0
- package/dist/client/check.d.ts.map +1 -0
- package/dist/client/check.js +44 -0
- package/dist/client/check.js.map +1 -0
- package/dist/client/client.d.ts +10 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +25 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/events.d.ts +5 -0
- package/dist/client/events.d.ts.map +1 -0
- package/dist/client/events.js +66 -0
- package/dist/client/events.js.map +1 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +5 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/shutdown.d.ts +4 -0
- package/dist/client/shutdown.d.ts.map +1 -0
- package/dist/client/shutdown.js +78 -0
- package/dist/client/shutdown.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +23 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +120 -0
- package/dist/logger.js.map +1 -0
- package/dist/pipeline/builder.d.ts +111 -0
- package/dist/pipeline/builder.d.ts.map +1 -0
- package/dist/pipeline/builder.js +197 -0
- package/dist/pipeline/builder.js.map +1 -0
- package/dist/pipeline/index.d.ts +3 -0
- package/dist/pipeline/index.d.ts.map +1 -0
- package/dist/pipeline/index.js +2 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/queue/events.d.ts +13 -0
- package/dist/queue/events.d.ts.map +1 -0
- package/dist/queue/events.js +109 -0
- package/dist/queue/events.js.map +1 -0
- package/dist/queue/index.d.ts +7 -0
- package/dist/queue/index.d.ts.map +1 -0
- package/dist/queue/index.js +4 -0
- package/dist/queue/index.js.map +1 -0
- package/dist/queue/queue.d.ts +13 -0
- package/dist/queue/queue.d.ts.map +1 -0
- package/dist/queue/queue.js +37 -0
- package/dist/queue/queue.js.map +1 -0
- package/dist/queue/worker.d.ts +15 -0
- package/dist/queue/worker.d.ts.map +1 -0
- package/dist/queue/worker.js +20 -0
- package/dist/queue/worker.js.map +1 -0
- package/examples/README.md +86 -0
- package/examples/_setup.js +143 -0
- package/examples/cache.js +111 -0
- package/examples/pipeline.js +161 -0
- package/examples/pubsub.js +101 -0
- package/examples/queue-worker.js +189 -0
- package/examples/session.js +145 -0
- package/examples/standalone.js +58 -0
- package/package.json +100 -4
- package/src/client/check.ts +69 -0
- package/src/client/client.ts +45 -0
- package/src/client/events.ts +101 -0
- package/src/client/index.ts +5 -0
- package/src/client/shutdown.ts +97 -0
- package/src/index.ts +4 -0
- package/src/logger.ts +159 -0
- package/src/pipeline/builder.ts +307 -0
- package/src/pipeline/index.ts +7 -0
- package/src/queue/events.ts +158 -0
- package/src/queue/index.ts +6 -0
- package/src/queue/queue.ts +60 -0
- package/src/queue/worker.ts +44 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# Contributing to `@oneunit/redis`
|
|
2
|
+
|
|
3
|
+
Contributions are welcome — bug reports, tests, docs, and code. No CLA to sign
|
|
4
|
+
and no maintainer approval needed to open a pull request. The package is MIT
|
|
5
|
+
licensed, so your work stays yours.
|
|
6
|
+
|
|
7
|
+
Repository-wide conventions live in the [root CONTRIBUTING.md](../../CONTRIBUTING.md).
|
|
8
|
+
This file covers what is specific to a Redis client and queue library.
|
|
9
|
+
|
|
10
|
+
Before changing anything, read [ARCHITECTURE.md](./ARCHITECTURE.md). This
|
|
11
|
+
package is a thin layer over `ioredis` and `bullmq`, and most of the code here
|
|
12
|
+
exists to work around a specific sharp edge in one of them. Several of those
|
|
13
|
+
workarounds look like pointless indirection until you know which bug they
|
|
14
|
+
prevent.
|
|
15
|
+
|
|
16
|
+
## Reporting a security vulnerability
|
|
17
|
+
|
|
18
|
+
**Do not open a public issue or pull request for a security report.**
|
|
19
|
+
|
|
20
|
+
A connection helper has a wide blast radius: a flaw here reaches every
|
|
21
|
+
application that installs it, and a public write-up with details gives attackers
|
|
22
|
+
a head start while the fix is written. Report privately, in order of preference:
|
|
23
|
+
|
|
24
|
+
1. **GitHub Security Advisories** — the repository's _Security_ tab →
|
|
25
|
+
_Report a vulnerability_. This opens a private thread only maintainers can
|
|
26
|
+
see.
|
|
27
|
+
2. **Email** the maintainer at `04mayank09@gmail.com`.
|
|
28
|
+
|
|
29
|
+
Please include the affected version, a minimal reproduction, and the impact you
|
|
30
|
+
expect. You will get an acknowledgement, and you will be credited in the release
|
|
31
|
+
notes unless you would rather not be.
|
|
32
|
+
|
|
33
|
+
Everything else — a confusing error message, a missing test, an API that is
|
|
34
|
+
awkward to use — is a normal issue and welcome as one.
|
|
35
|
+
|
|
36
|
+
## Getting set up
|
|
37
|
+
|
|
38
|
+
Requires **Node.js 20+**. You can work directly inside `packages/redis` with **npm**, or across the monorepo using **pnpm 11.9.0** (`corepack enable` gets you the right pnpm).
|
|
39
|
+
|
|
40
|
+
### Working directly in `packages/redis` (standalone)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Inside packages/redis
|
|
44
|
+
npm install
|
|
45
|
+
npm run build
|
|
46
|
+
npm test
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Working from the monorepo root
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# From repository root
|
|
53
|
+
pnpm install
|
|
54
|
+
pnpm --filter @oneunit/redis build
|
|
55
|
+
pnpm --filter @oneunit/redis test
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The build step is required before the tests, not optional: the suite imports
|
|
59
|
+
`dist`, which is gitignored and does not exist on a fresh checkout.
|
|
60
|
+
|
|
61
|
+
A **Redis on `localhost:6379`** makes the tests mean something. Without one they
|
|
62
|
+
still pass, but the queue, worker, pipeline, and performance cases no-op. Set
|
|
63
|
+
`REDIS_URL` to point somewhere else. Nothing in the suite hangs for want of a
|
|
64
|
+
server, but do not infer that from a green run with nothing listening.
|
|
65
|
+
|
|
66
|
+
The package typechecks, tests, and builds entirely on its own, so you do not
|
|
67
|
+
need the rest of the monorepo to work on it.
|
|
68
|
+
|
|
69
|
+
## The checks a pull request must pass
|
|
70
|
+
|
|
71
|
+
Run the full verification suite before submitting a pull request:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Inside packages/redis:
|
|
75
|
+
npm run verify
|
|
76
|
+
|
|
77
|
+
# Or from monorepo root:
|
|
78
|
+
pnpm --filter @oneunit/redis verify
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`npm run verify` runs the exact five checks in order:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npm run build # Clean dist/ and compile TypeScript
|
|
85
|
+
npm run typecheck # Typecheck without emitting files
|
|
86
|
+
npm run lint # ESLint across src/ and test/
|
|
87
|
+
npm test # Run test suite with Node's native test runner via tsx
|
|
88
|
+
npm run pack:check # Dry-run npm pack to catch packaging errors
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
CI runs these on **Node 20, 22, and 24** against a `redis` service container,
|
|
92
|
+
then installs the packed tarball into a clean project and exercises the public
|
|
93
|
+
API against it. That last step catches the failure mode unit tests miss: an
|
|
94
|
+
export that only resolves inside this repository.
|
|
95
|
+
|
|
96
|
+
Because CI always has a server, it cannot catch a test that quietly requires one.
|
|
97
|
+
The server-backed tests no-op when nothing is listening, so a run without Redis
|
|
98
|
+
is green while covering a good part of nothing — and one that was missing its
|
|
99
|
+
guard hung the suite outright rather than failing. **Start a Redis on
|
|
100
|
+
`localhost:6379` before trusting a local test run**, and see
|
|
101
|
+
[Tests that need Redis](#tests-that-need-redis).
|
|
102
|
+
|
|
103
|
+
**Build comes first, and the order is load-bearing.** `npm test` runs against
|
|
104
|
+
`dist`, not `src`: every test file imports `../dist/index.js`, and `dist/` is
|
|
105
|
+
gitignored, so a fresh checkout cannot load the suite at all until it is built.
|
|
106
|
+
Running `test` before `build` does not fail an assertion — it fails to resolve
|
|
107
|
+
the module, on every file, every run. `npm run verify` (or `pnpm --filter @oneunit/redis verify`)
|
|
108
|
+
orders all five correctly; reach for it rather than the individual scripts.
|
|
109
|
+
`prepublishOnly` builds before testing for the same reason.
|
|
110
|
+
|
|
111
|
+
## Writing tests
|
|
112
|
+
|
|
113
|
+
Tests use the Node built-in runner (`node:test`) via `tsx`. There is no test
|
|
114
|
+
framework to configure.
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Inside packages/redis:
|
|
118
|
+
npm test
|
|
119
|
+
|
|
120
|
+
# Run tests in watch mode:
|
|
121
|
+
npm run test:watch
|
|
122
|
+
|
|
123
|
+
# From monorepo root:
|
|
124
|
+
pnpm --filter @oneunit/redis test
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Test Suite Structure
|
|
128
|
+
|
|
129
|
+
The test suite in `test/` is organized into focused suites:
|
|
130
|
+
|
|
131
|
+
| Test File | Scope & Responsibilities |
|
|
132
|
+
| :------------------------- | :---------------------------------------------------------------------------------------------------- |
|
|
133
|
+
| `test/redis.test.ts` | Client defaults, URL normalization, BullMQ queue/worker options, health timeout, shutdown idempotency. |
|
|
134
|
+
| `test/pipeline.test.ts` | Batch command execution, 1-to-1 step validation, timeout guarantees, error redaction, `pipelineValues`. |
|
|
135
|
+
| `test/security.test.ts` | Plaintext credential redaction (`AUTH`/`HELLO`), prototype pollution guards, safe key names. |
|
|
136
|
+
| `test/performance.test.ts` | Latency bounds, concurrent health checks, high-volume pipeline throughput. |
|
|
137
|
+
| `test/examples.test.ts` | End-to-end execution smoke tests verifying each runnable script in `examples/`. |
|
|
138
|
+
| `test/helpers.ts` | Shared connectivity probe (`redisAvailable()`, `cachedRedisAvailable()`). |
|
|
139
|
+
|
|
140
|
+
### A regression test must fail without its fix
|
|
141
|
+
|
|
142
|
+
This is the rule that matters most here, and it is easy to get wrong. Write the
|
|
143
|
+
test, then reintroduce the bug and confirm the suite goes red. If it still
|
|
144
|
+
passes, the test is protecting nothing.
|
|
145
|
+
|
|
146
|
+
Two traps in this package specifically:
|
|
147
|
+
|
|
148
|
+
- **bullmq swallows listener exceptions.** `QueueBase.emit` catches a throwing
|
|
149
|
+
listener and re-emits the event as `error`. If that also throws, it lands on
|
|
150
|
+
`console.error`. So a test that only asserts "did not throw" will pass against
|
|
151
|
+
a broken event handler. Assert on `console.error` instead — see
|
|
152
|
+
`attachQueueEvents tolerates a missing logger on event dispatch`.
|
|
153
|
+
- **Some failures only appear in a fresh process.** The health-check deadline
|
|
154
|
+
bug (an `unref`'d timer letting Node exit before the promise settled) is
|
|
155
|
+
invisible in-process, because the test runner keeps the loop alive for other
|
|
156
|
+
reasons. That test spawns a child process.
|
|
157
|
+
|
|
158
|
+
### Tests that need Redis
|
|
159
|
+
|
|
160
|
+
Anything constructing a `Queue`, `Worker`, or `QueueEvents` needs a live server:
|
|
161
|
+
bullmq opens a blocking connection and retries a dead port for ~30s after
|
|
162
|
+
`close()`, which makes a suite pointed at nothing listening both slow and
|
|
163
|
+
handle-leaking. Use the existing `redisAvailable()` guard so the test returns
|
|
164
|
+
early instead:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
test("does the thing", async () => {
|
|
168
|
+
if (!(await redisAvailable())) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
// ...
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`redisAvailable()` comes from `test/helpers.ts` — import it, do not redeclare
|
|
176
|
+
it. It used to be copied into each test file, and the copies drifted: some had a
|
|
177
|
+
`Promise.race` backstop and some did not. There is now one implementation and
|
|
178
|
+
one `cachedRedisAvailable()` per file, so the guard that decides whether the
|
|
179
|
+
server-backed half of the suite silently does nothing lives in a single place.
|
|
180
|
+
|
|
181
|
+
**The guard is needed for a bare `client.ping()` too, not just for bullmq
|
|
182
|
+
objects.** `createClient` defaults `maxRetriesPerRequest` to `null`, which is
|
|
183
|
+
what bullmq requires, and `null` means ioredis never gives up on a queued
|
|
184
|
+
command. So against a Redis that is not listening, an unguarded `await
|
|
185
|
+
client.ping()` parks in the offline queue and never settles — the test, and the
|
|
186
|
+
whole run, hangs forever rather than failing. That is not hypothetical: three
|
|
187
|
+
tests in `security.test.ts` were missing the guard, one of which hung the suite
|
|
188
|
+
indefinitely on a machine with no server. CI does not catch it, because
|
|
189
|
+
`.github/workflows/redis.yml` starts a Redis service for the `verify` job.
|
|
190
|
+
|
|
191
|
+
Tests for pure functions (`createClient` defaults, `health` against a fake
|
|
192
|
+
client, `shutdown` against a fake client) need no server. Prefer those; they are
|
|
193
|
+
fast and deterministic. `health` accepts any object with a `ping` method, and
|
|
194
|
+
`shutdown` any object with `status` and `quit`, so both are testable without
|
|
195
|
+
ioredis.
|
|
196
|
+
|
|
197
|
+
Two more rules that the suite has broken in the past:
|
|
198
|
+
|
|
199
|
+
- **A test must not rebuild `dist/`.** Every test file imports `../dist/index.js`
|
|
200
|
+
and node's test runner executes files in parallel child processes, so anything
|
|
201
|
+
that mutates the build mid-run takes `dist/` away from its siblings and
|
|
202
|
+
produces `ERR_MODULE_NOT_FOUND` attributed to the wrong file. If a test needs
|
|
203
|
+
the published file list, use `npm pack --dry-run --json --ignore-scripts`;
|
|
204
|
+
without that flag `prepack` runs `build`, whose `clean` step deletes `dist/`.
|
|
205
|
+
- **Proven red before green.** See the rule above; it applies to every new
|
|
206
|
+
regression test, including a fix whose "before" state is a hang.
|
|
207
|
+
|
|
208
|
+
## Working with ioredis and bullmq defaults
|
|
209
|
+
|
|
210
|
+
The single most common bug in this package's history has been forwarding an
|
|
211
|
+
explicit `undefined` to bullmq, which overrides a default it would otherwise
|
|
212
|
+
have applied. Both factories spread conditionally:
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
...(concurrency === undefined ? {} : { concurrency }),
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Do not "simplify" that to `concurrency,`. If you add an option, follow the
|
|
219
|
+
same pattern. The same applies to `createClient`: `url` must stay the first
|
|
220
|
+
positional argument to the ioredis constructor, because ioredis ignores a `url`
|
|
221
|
+
key inside the options object and silently connects to `localhost`.
|
|
222
|
+
|
|
223
|
+
`createQueue`'s `defaultJobOptions` cannot use the conditional-spread form,
|
|
224
|
+
because it merges into an existing object of defaults. It merges per key instead,
|
|
225
|
+
skipping `undefined`. Do not "simplify" that to `...defaultJobOptions` either: a
|
|
226
|
+
spread writes `undefined` over every default the caller did not set. `null` is
|
|
227
|
+
deliberate and passes through — bullmq reads `removeOnComplete: null` as "keep
|
|
228
|
+
this job".
|
|
229
|
+
|
|
230
|
+
The inverse trap is just as quiet: a `url` passed as a **string** must not be
|
|
231
|
+
destructured as an options object either. Both mistakes end up on
|
|
232
|
+
`localhost:6379` with no error. `createClient` accepts a string for exactly
|
|
233
|
+
that reason.
|
|
234
|
+
|
|
235
|
+
Logger argument order is the other thing to get right. Every call site uses
|
|
236
|
+
`(message, extra)`, matching the `Logger` interface in `src/logger.ts`. pino is
|
|
237
|
+
the exception and takes `(bindings, message)`, so it is detected by the
|
|
238
|
+
`bindings()` method and `levels` map it carries — **not** by `child()`, which
|
|
239
|
+
this package's own interface declares and therefore cannot be a signal.
|
|
240
|
+
|
|
241
|
+
Pipelines have the same two failure modes in a new place. A command that fails
|
|
242
|
+
inside a pipeline does not fail the pipeline: ioredis resolves `EXEC` and puts
|
|
243
|
+
the error in that command's tuple, so anything that reads only the values treats
|
|
244
|
+
a dropped write as a success. And a pipeline `exec()` against an unreachable
|
|
245
|
+
server never settles, because ioredis parks queued commands while reconnecting.
|
|
246
|
+
`runPipeline` exists for both; keep both properties if you extend it. Anything
|
|
247
|
+
reaching a logger or an exception from a pipeline result goes through
|
|
248
|
+
`redactError` first — the step array is meant to be loggable as a whole, so the
|
|
249
|
+
redaction has to have already happened by the time it is returned. That applies
|
|
250
|
+
to a rejected `exec()` as well as to the resolved tuples; a rejection skips the
|
|
251
|
+
tuple mapping entirely, so redacting only the tuples leaves one path unguarded.
|
|
252
|
+
|
|
253
|
+
Results are paired with steps by **position**, so each step must queue exactly
|
|
254
|
+
one command. `runPipeline` enforces it by reading ioredis's own
|
|
255
|
+
`pipeline.length` either side of every step and raising `PipelineStepError`; do
|
|
256
|
+
not relax that check. Two ways of breaking it compile silently, because
|
|
257
|
+
TypeScript allows any value to be returned from a `void`-typed signature:
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
{ label: "seed", run: (p) => { p.set("a", "1"); p.set("b", "2"); } },
|
|
261
|
+
{ label: "x", run: async (p) => { await something(); void p.get("a"); } },
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
The first shifts every later result by one, so the caller gets a real value
|
|
265
|
+
against the wrong label. The second queues nothing before `exec()` is sent and
|
|
266
|
+
loses the command with no error anywhere. If you change how steps are queued,
|
|
267
|
+
keep a test that a two-command step and an `async` step both raise — and note
|
|
268
|
+
that a test fake standing in for ioredis has to expose a `length` that tracks
|
|
269
|
+
the queue, or the guard cannot be exercised at all.
|
|
270
|
+
|
|
271
|
+
Anywhere an error reaches the logger, it goes through `redactError(error)`
|
|
272
|
+
first. ioredis attaches the failing command to its errors, and for `AUTH` that
|
|
273
|
+
command's args are the password in plaintext. There are three such call sites —
|
|
274
|
+
the client `error` event, the `QueueEvents` `error` event, and `shutdown`'s
|
|
275
|
+
failure report — and adding a fourth without redacting writes the credential to
|
|
276
|
+
the app's log.
|
|
277
|
+
|
|
278
|
+
## Things that look like bugs but are not
|
|
279
|
+
|
|
280
|
+
- **`close` logs on every reconnect.** ioredis emits `close` on each failed
|
|
281
|
+
attempt during an outage. That is expected, not a leak.
|
|
282
|
+
- **One client shared by queue and worker is fine.** bullmq duplicates the
|
|
283
|
+
connection for its blocking needs; closing the queue or worker does not close
|
|
284
|
+
your client. That is what `shutdown` is for.
|
|
285
|
+
- **`prefix` is not global.** It is per-call on all three factories. Set it on
|
|
286
|
+
every one, or let `attachQueueEvents` inherit it from the queue.
|
|
287
|
+
- **`maxRetriesPerRequest` is `null` on purpose.** ioredis defaults to `20` and
|
|
288
|
+
bullmq refuses anything else. See ARCHITECTURE.md.
|
|
289
|
+
- **`status` can stay `reconnecting` after a forced close.** `disconnect()` never
|
|
290
|
+
runs ioredis's `closeHandler` from a client in `reconnecting`, so the status
|
|
291
|
+
does not move to `end` even though the retry loop is gone. `shutdown` keeps its
|
|
292
|
+
own record for exactly this reason; do not add a status check expecting
|
|
293
|
+
otherwise.
|
|
294
|
+
|
|
295
|
+
## Publishing and Releasing
|
|
296
|
+
|
|
297
|
+
`npm run verify` is the whole gate in order: build, typecheck, lint, tests,
|
|
298
|
+
`pack:check`. Run it rather than the individual scripts — the pack check is what
|
|
299
|
+
catches a packaging mistake that no amount of unit testing will.
|
|
300
|
+
|
|
301
|
+
Two packaging rules, both learned the hard way:
|
|
302
|
+
|
|
303
|
+
- **`src` must stay in `files`.** The compiler emits sourcemaps that reference
|
|
304
|
+
`../src/*.ts`. Without it they resolve to nothing in an installed package, and
|
|
305
|
+
consumer stack traces silently degrade.
|
|
306
|
+
- **`build` must clean `dist`.** `tsc` never removes output for a deleted source
|
|
307
|
+
file, so a module you delete keeps shipping its compiled copy. Do not "simplify"
|
|
308
|
+
the clean step away.
|
|
309
|
+
|
|
310
|
+
The package is configured for public npm distribution under the `@oneunit` scope:
|
|
311
|
+
|
|
312
|
+
```json
|
|
313
|
+
"publishConfig": {
|
|
314
|
+
"access": "public",
|
|
315
|
+
"registry": "https://registry.npmjs.org/"
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Direct npm CLI Publishing
|
|
320
|
+
|
|
321
|
+
`package.json` defines `"prepublishOnly": "npm run build && npm test"`, ensuring
|
|
322
|
+
a clean build and full test execution precede every publish:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
# Inside packages/redis:
|
|
326
|
+
npm login
|
|
327
|
+
npm publish
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Automated CI Release Workflow
|
|
331
|
+
|
|
332
|
+
Releases are also driven by git tags: `git tag redis-v1.0.0 && git push origin redis-v1.0.0`.
|
|
333
|
+
`.github/workflows/redis.yml` verifies on Node 20/22/24, installs
|
|
334
|
+
the real tarball into a clean project and exercises the public API against a
|
|
335
|
+
Redis service container, then checks the tag matches `package.json` before
|
|
336
|
+
uploading. npm will not let you reuse a version number, so a mistyped tag is not
|
|
337
|
+
retryable.
|
|
338
|
+
|
|
339
|
+
## Docs and naming
|
|
340
|
+
|
|
341
|
+
The package is published as `@oneunit/redis`. Internal links, install commands,
|
|
342
|
+
and the repository URL should all say `oneunit`; the old `bootstrap-framework`
|
|
343
|
+
name is retired. Anything in this monorepo that still imports the redis plugin
|
|
344
|
+
by the old name will not resolve, and the server's optional redis plugin reports
|
|
345
|
+
that as "package not installed" rather than naming the fault. Update
|
|
346
|
+
`CHANGELOG.md` under an `Unreleased` heading as part of your change — a bug fix
|
|
347
|
+
without a changelog entry will be asked for.
|
|
348
|
+
|
|
349
|
+
## Examples
|
|
350
|
+
|
|
351
|
+
`examples/` is shipped in the tarball and exercised by CI, so an example that
|
|
352
|
+
does not run is a broken build. Each script reads `REDIS_URL` and honours
|
|
353
|
+
`REDIS_SILENT=true`. Check yours against a local Redis before sending it.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mayank
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|