snugkv-nest 0.1.0 → 0.3.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.
Files changed (71) hide show
  1. package/README.md +118 -2
  2. package/dist/core/bus.d.ts +4 -0
  3. package/dist/core/bus.js +7 -0
  4. package/dist/core/bus.js.map +1 -1
  5. package/dist/core/cache.d.ts +27 -0
  6. package/dist/core/cache.js +71 -0
  7. package/dist/core/cache.js.map +1 -0
  8. package/dist/core/client.d.ts +115 -2
  9. package/dist/core/client.js +270 -1
  10. package/dist/core/client.js.map +1 -1
  11. package/dist/core/connection.d.ts +4 -0
  12. package/dist/core/connection.js +12 -2
  13. package/dist/core/connection.js.map +1 -1
  14. package/dist/core/index.d.ts +6 -0
  15. package/dist/core/index.js +6 -0
  16. package/dist/core/index.js.map +1 -1
  17. package/dist/core/lock.d.ts +38 -0
  18. package/dist/core/lock.js +68 -0
  19. package/dist/core/lock.js.map +1 -0
  20. package/dist/core/pubsub.d.ts +28 -0
  21. package/dist/core/pubsub.js +134 -0
  22. package/dist/core/pubsub.js.map +1 -0
  23. package/dist/core/queue/cron.d.ts +21 -0
  24. package/dist/core/queue/cron.js +144 -0
  25. package/dist/core/queue/cron.js.map +1 -0
  26. package/dist/core/queue/events.d.ts +32 -0
  27. package/dist/core/queue/events.js +98 -0
  28. package/dist/core/queue/events.js.map +1 -0
  29. package/dist/core/queue/flow.d.ts +35 -0
  30. package/dist/core/queue/flow.js +64 -0
  31. package/dist/core/queue/flow.js.map +1 -0
  32. package/dist/core/queue/index.d.ts +7 -0
  33. package/dist/core/queue/index.js +27 -0
  34. package/dist/core/queue/index.js.map +1 -0
  35. package/dist/core/queue/job.d.ts +68 -0
  36. package/dist/core/queue/job.js +221 -0
  37. package/dist/core/queue/job.js.map +1 -0
  38. package/dist/core/queue/queue.d.ts +152 -0
  39. package/dist/core/queue/queue.js +346 -0
  40. package/dist/core/queue/queue.js.map +1 -0
  41. package/dist/core/queue/types.d.ts +79 -0
  42. package/dist/core/queue/types.js +85 -0
  43. package/dist/core/queue/types.js.map +1 -0
  44. package/dist/core/queue/worker.d.ts +87 -0
  45. package/dist/core/queue/worker.js +307 -0
  46. package/dist/core/queue/worker.js.map +1 -0
  47. package/dist/core/ratelimit.d.ts +16 -0
  48. package/dist/core/ratelimit.js +30 -0
  49. package/dist/core/ratelimit.js.map +1 -0
  50. package/dist/core/tx.d.ts +24 -0
  51. package/dist/core/tx.js +52 -0
  52. package/dist/core/tx.js.map +1 -0
  53. package/dist/nest/explorer.d.ts +13 -0
  54. package/dist/nest/explorer.js +51 -0
  55. package/dist/nest/explorer.js.map +1 -1
  56. package/dist/nest/index.d.ts +3 -1
  57. package/dist/nest/index.js +4 -1
  58. package/dist/nest/index.js.map +1 -1
  59. package/dist/nest/module.d.ts +14 -1
  60. package/dist/nest/module.js +31 -4
  61. package/dist/nest/module.js.map +1 -1
  62. package/dist/nest/queue-decorators.d.ts +34 -0
  63. package/dist/nest/queue-decorators.js +56 -0
  64. package/dist/nest/queue-decorators.js.map +1 -0
  65. package/dist/nest/queue-module.d.ts +22 -0
  66. package/dist/nest/queue-module.js +41 -0
  67. package/dist/nest/queue-module.js.map +1 -0
  68. package/dist/nest/runtime.d.ts +1 -0
  69. package/dist/nest/runtime.js +15 -2
  70. package/dist/nest/runtime.js.map +1 -1
  71. package/package.json +49 -10
package/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # snugkv-nest
2
2
 
3
- A message bus for NestJS microservices, built on [SnugKV](https://github.com/edijs1984/snugkv) streams.
3
+ The NestJS module and TypeScript client for [SnugKV](https://github.com/edijs1984/snugkv): strings, hashes, lists, sets, sorted sets, expiry, Lua, pub/sub and transactions, plus cache, lock and rate-limit helpers and a durable message bus on streams.
4
+
5
+ - [Using SnugKV as a data store](#using-snugkv-as-a-data-store)
6
+ - [Messaging (streams)](#messaging-streams)
4
7
 
5
8
  - **Durable topics.** Messages are stream entries. They survive restarts and are replayable.
6
9
  - **Consumer groups.** Instances of one service share the work; every different service gets every message.
@@ -18,6 +21,119 @@ npm install snugkv-nest
18
21
 
19
22
  Needs Node 18+ and NestJS 10 or 11.
20
23
 
24
+ ## Using SnugKV as a data store
25
+
26
+ Import the module once; everything below can be injected.
27
+
28
+ ```ts
29
+ import { Injectable } from '@nestjs/common';
30
+ import { SnugKvCache, SnugKvClient, SnugKvLocks, SnugKvModule, SnugKvRateLimiter, SnugKvSubscriber } from 'snugkv-nest';
31
+
32
+ // app.module.ts
33
+ @Module({ imports: [SnugKvModule.forRoot({ url: process.env.SNUGKV_URL, cache: { prefix: 'app:', ttlSeconds: 120 } })] })
34
+ export class AppModule {}
35
+
36
+ @Injectable()
37
+ export class UsersService {
38
+ constructor(
39
+ private readonly kv: SnugKvClient,
40
+ private readonly cache: SnugKvCache,
41
+ private readonly locks: SnugKvLocks,
42
+ private readonly limiter: SnugKvRateLimiter,
43
+ private readonly pubsub: SnugKvSubscriber,
44
+ ) {}
45
+
46
+ profile(id: string) {
47
+ return this.cache.wrap(`user:${id}`, () => this.loadFromDb(id)); // loader runs once, result cached 120 s
48
+ }
49
+
50
+ async rebuild() {
51
+ const r = await this.locks.run('rebuild', () => this.doRebuild(), { ttlMs: 60_000 });
52
+ return r.acquired;
53
+ }
54
+
55
+ async allow(ip: string) {
56
+ return (await this.limiter.hit(ip, 100, 60_000)).allowed; // 100 per minute
57
+ }
58
+ }
59
+ ```
60
+
61
+ `service` is only needed for messaging; without it the module uses `app`. Outside Nest, use `new SnugKvClient({ url })` from `snugkv-nest/core`.
62
+
63
+ ### Client
64
+
65
+ ```ts
66
+ await kv.set('a', '1'); await kv.setOpts('a', '1', { nx: true, exSeconds: 30 });
67
+ await kv.incr('visits'); await kv.setJson('cfg', { a: 1 }); await kv.getJson('cfg');
68
+ await kv.hset('user:1', { name: 'Ann', age: 31 }); await kv.hgetall('user:1');
69
+ await kv.rpush('queue', 'a', 'b'); await kv.lrange('queue');
70
+ await kv.sadd('tags', 'x', 'y'); await kv.smembers('tags');
71
+ await kv.zadd('board', [{ member: 'ann', score: 10 }]); await kv.zrange('board', 0, 9, { reverse: true });
72
+ await kv.expire('a', 60); await kv.ttl('a');
73
+ for await (const key of kv.scanIterator({ match: 'user:*' })) { /* … */ }
74
+ await kv.eval("return redis.call('get', KEYS[1])", ['a']);
75
+ await kv.tx().set('a', '1').incr('n').hset('h', { f: 1 }).exec(); // MULTI/EXEC in one write
76
+ await kv.call('ANYTHING', 'else'); // raw command
77
+ ```
78
+
79
+ ### Pub/sub
80
+
81
+ Fire-and-forget broadcast. Use the streams below when a message must not be lost.
82
+
83
+ ```ts
84
+ const off = await pubsub.subscribe('news', (message, channel) => console.log(channel, message));
85
+ await pubsub.psubscribe('events.*', (message, channel, pattern) => { /* … */ });
86
+ await kv.publish('news', 'hello');
87
+ await off();
88
+ ```
89
+
90
+ Subscriptions are restored after a reconnect; messages sent while disconnected are not replayed.
91
+
92
+ ### Cache, locks, rate limits
93
+
94
+ - `SnugKvCache`: `get`, `set`, `del`, `wrap(key, loader, ttl)` (concurrent callers share one load), `clear(pattern)`.
95
+ - `SnugKvLocks`: `acquire(name, { ttlMs, waitMs })`, `run(name, fn)`. A lock expires on its own, and only its holder can release or extend it. It protects against crashed holders, not against the server itself failing, so keep critical sections idempotent.
96
+ - `SnugKvRateLimiter`: `hit(key, limit, windowMs)` is a fixed window; it returns `{ allowed, count, remaining, resetMs }`.
97
+
98
+ ## Job queues
99
+
100
+ BullMQ-style queues that run inside SnugKV (the `snugq` function library, loaded by the server by default). Needs a server version that includes it.
101
+
102
+ ```ts
103
+ import { Queue, Worker, QueueEvents, FlowProducer } from 'snugkv-nest';
104
+
105
+ const emails = new Queue('emails', { connection: { host: '127.0.0.1', port: 6379 } });
106
+ await emails.add('welcome', { to: 'a@b.c' }, { attempts: 3, backoff: { type: 'exponential', delay: 1000 }, removeOnComplete: 100 });
107
+
108
+ const worker = new Worker('emails', async (job) => {
109
+ await job.updateProgress(50);
110
+ return send(job.data);
111
+ }, { connection: { host: '127.0.0.1', port: 6379 }, concurrency: 5 });
112
+ worker.on('failed', (job, err) => console.error(job.id, err.message));
113
+ ```
114
+
115
+ With Nest, register queues and mark processors; workers start and stop with the app:
116
+
117
+ ```ts
118
+ SnugKvQueueModule.registerQueue({ name: 'emails' })
119
+
120
+ @SnugProcessor('emails', { concurrency: 5 })
121
+ export class EmailProcessor extends WorkerHost {
122
+ async process(job: Job<{ to: string }>) { /* … */ }
123
+
124
+ @OnSnugWorkerEvent('failed')
125
+ onFailed(job: Job, err: Error) { /* … */ }
126
+ }
127
+
128
+ constructor(@InjectSnugQueue('emails') private readonly emails: Queue) {}
129
+ ```
130
+
131
+ Use `@SnugProcess('jobName')` on methods instead of `process()` to route by job name.
132
+
133
+ Supported: priorities, LIFO, delayed jobs, attempts with fixed, exponential or custom backoff (`UnrecoverableError` skips retries), locks with stalled-job recovery, pause/resume, global concurrency, queue rate limits (`limiter`, `queue.setRateLimit`, `worker.rateLimit` + `RateLimitError`), custom ids and deduplication, `removeOnComplete`/`removeOnFail`, progress and logs, `QueueEvents` and `job.waitUntilFinished`, `drain`/`clean`/`obliterate`/`retryJobs`/`promoteJobs`, repeatable jobs (`upsertJobScheduler` with `every` or a cron `pattern` and `tz`), and parent/child flows (`FlowProducer`, `job.getChildrenValues()`, `failParentOnFailure`, `ignoreDependencyOnFailure`). Job data must be JSON-serialisable. Cron patterns are computed by workers, so keep one running. See the server's `docs/QUEUES.md` for the storage layout.
134
+
135
+ ## Messaging (streams)
136
+
21
137
  ## Quick start
22
138
 
23
139
  ```ts
@@ -188,4 +304,4 @@ Tests that need a server are skipped when `SNUGKV_BIN` is not set.
188
304
 
189
305
  ## License
190
306
 
191
- MIT
307
+ MIT. This package is only a client. The SnugKV server it talks to is a separate project, licensed under AGPL-3.0 with a commercial licence option.
@@ -1,5 +1,6 @@
1
1
  import { SnugKvClient, SnugKvClientOptions } from './client';
2
2
  import { MessageHandler, SubscribeOptions, ConsumerStats } from './consumer';
3
+ import { SnugKvSubscriber } from './pubsub';
3
4
  import { PresenceOptions } from './presence';
4
5
  import { BatchMessage, PublishOptions, Publisher, Serializer } from './publisher';
5
6
  import { BusLogger } from './util';
@@ -39,6 +40,7 @@ export declare class SnugKvBus {
39
40
  private readonly logger;
40
41
  private readonly keyPrefix;
41
42
  private closed;
43
+ private pubsub?;
42
44
  constructor(options: SnugKvBusOptions);
43
45
  /** Connects the main connection. Rejects if the server is not reachable in time. */
44
46
  connect(): Promise<void>;
@@ -48,6 +50,8 @@ export declare class SnugKvBus {
48
50
  }): Promise<string[]>;
49
51
  /** Starts a consumer. Resolves when it is reading. */
50
52
  subscribe<T = unknown>(options: SubscribeOptions, handler: MessageHandler<T>): Promise<Subscription>;
53
+ /** Shared pub/sub subscriber (own connection, opened on first use, closed with the bus). */
54
+ subscriber(): SnugKvSubscriber;
51
55
  stats(): {
52
56
  published: Record<string, number>;
53
57
  consumers: ConsumerStats[];
package/dist/core/bus.js CHANGED
@@ -20,6 +20,7 @@ class SnugKvBus {
20
20
  logger;
21
21
  keyPrefix;
22
22
  closed = false;
23
+ pubsub;
23
24
  constructor(options) {
24
25
  this.options = options;
25
26
  if (!options.service)
@@ -86,6 +87,11 @@ class SnugKvBus {
86
87
  },
87
88
  };
88
89
  }
90
+ /** Shared pub/sub subscriber (own connection, opened on first use, closed with the bus). */
91
+ subscriber() {
92
+ this.pubsub ??= this.client.subscriber();
93
+ return this.pubsub;
94
+ }
89
95
  stats() {
90
96
  return { published: this.publisher.stats(), consumers: this.consumers.map((c) => c.stats()) };
91
97
  }
@@ -96,6 +102,7 @@ class SnugKvBus {
96
102
  this.closed = true;
97
103
  await Promise.allSettled(this.consumers.splice(0).map((c) => c.stop()));
98
104
  await this.presence?.stop();
105
+ this.pubsub?.close();
99
106
  this.client.close();
100
107
  }
101
108
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bus.js","sourceRoot":"","sources":["../../src/core/bus.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bus.js","sourceRoot":"","sources":["../../src/core/bus.ts"],"names":[],"mappings":";;;AAAA,qCAAmC;AACnC,qCAA6D;AAC7D,yCAAuF;AAEvF,yCAA+D;AAC/D,2CAAkG;AAClG,iCAAwD;AA2BxD,wEAAwE;AACxE,MAAa,SAAS;IAaS;IAZpB,MAAM,CAAe;IACrB,OAAO,CAAS;IAChB,QAAQ,CAAS;IACjB,SAAS,CAAY;IACb,QAAQ,CAAoB;IAC5B,SAAS,GAAe,EAAE,CAAC;IAC3B,UAAU,CAAa;IACvB,MAAM,CAAY;IAClB,SAAS,CAAS;IAC3B,MAAM,GAAG,KAAK,CAAC;IACf,MAAM,CAAoB;IAElC,YAA6B,OAAyB;QAAzB,YAAO,GAAP,OAAO,CAAkB;QACpD,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACvE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,GAAG,IAAA,kBAAQ,GAAE,IAAI,IAAA,WAAI,GAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC1E,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,0BAAc,CAAC;QACvD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,oBAAa,CAAC;QAC9C,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;QACzC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;QAClH,IAAI,CAAC,MAAM,GAAG,IAAI,qBAAY,CAAC,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QACtF,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC1F,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;YAC/B,IAAI,CAAC,QAAQ,GAAG,IAAI,2BAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/H,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,qBAAS,CAC5B,IAAI,CAAC,MAAM,EACX,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,EACzI,IAAI,CAAC,QAAQ,CACd,CAAC;IACJ,CAAC;IAED,oFAAoF;IACpF,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,IAAI,MAAM,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,CAAc,KAAa,EAAE,OAAU,EAAE,OAAwB;QACtE,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACzD,CAAC;IAED,YAAY,CAAc,KAAa,EAAE,QAAgC,EAAE,OAA6B;QACtG,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/D,CAAC;IAED,sDAAsD;IACtD,KAAK,CAAC,SAAS,CAAc,OAAyB,EAAE,OAA0B;QAChF,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC1D,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,SAAS,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACvG,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACxF,MAAM,QAAQ,GAAG,IAAI,mBAAQ,CAAC,OAAO,EAAE,OAAyB,EAAE;YAChE,GAAG,EAAE,IAAI,CAAC,MAAM;YAChB,IAAI;YACJ,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;QACH,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;YAC3D,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,OAAO;YACL,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,KAAK,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE;YAC7B,IAAI,EAAE,KAAK,IAAI,EAAE;gBACf,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC3C,IAAI,CAAC,IAAI,CAAC;oBAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACxC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxB,CAAC;SACF,CAAC;IACJ,CAAC;IAED,4FAA4F;IAC5F,UAAU;QACR,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACzC,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,KAAK;QACH,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC;IAChG,CAAC;IAED,0GAA0G;IAC1G,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACxE,MAAM,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACF;AAtGD,8BAsGC"}
@@ -0,0 +1,27 @@
1
+ import type { SnugKvClient } from './client';
2
+ export interface CacheOptions {
3
+ /** Prefix for every key. Default `cache:`. */
4
+ prefix?: string;
5
+ /** Default time to live in seconds. Default 60. */
6
+ ttlSeconds?: number;
7
+ }
8
+ /**
9
+ * JSON cache on top of strings with expiry. `wrap` runs the loader at most
10
+ * once at a time per key inside this process (concurrent callers share the
11
+ * result).
12
+ */
13
+ export declare class SnugKvCache {
14
+ private readonly client;
15
+ private readonly prefix;
16
+ private readonly ttl;
17
+ private readonly inflight;
18
+ constructor(client: SnugKvClient, opts?: CacheOptions);
19
+ key(key: string): string;
20
+ get<T = unknown>(key: string): Promise<T | undefined>;
21
+ set(key: string, value: unknown, ttlSeconds?: number): Promise<void>;
22
+ del(...keys: string[]): Promise<number>;
23
+ /** Returns the cached value, or runs `load`, stores the result and returns it. `undefined` results are not cached. */
24
+ wrap<T>(key: string, load: () => Promise<T> | T, ttlSeconds?: number): Promise<T>;
25
+ /** Deletes every key under the cache prefix that matches `pattern` (default all). */
26
+ clear(pattern?: string): Promise<number>;
27
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SnugKvCache = void 0;
4
+ /**
5
+ * JSON cache on top of strings with expiry. `wrap` runs the loader at most
6
+ * once at a time per key inside this process (concurrent callers share the
7
+ * result).
8
+ */
9
+ class SnugKvCache {
10
+ client;
11
+ prefix;
12
+ ttl;
13
+ inflight = new Map();
14
+ constructor(client, opts = {}) {
15
+ this.client = client;
16
+ this.prefix = opts.prefix ?? 'cache:';
17
+ this.ttl = opts.ttlSeconds ?? 60;
18
+ }
19
+ key(key) {
20
+ return this.prefix + key;
21
+ }
22
+ async get(key) {
23
+ const raw = await this.client.get(this.key(key));
24
+ return raw === null ? undefined : JSON.parse(raw);
25
+ }
26
+ async set(key, value, ttlSeconds = this.ttl) {
27
+ await this.client.setJson(this.key(key), value, ttlSeconds);
28
+ }
29
+ async del(...keys) {
30
+ return keys.length ? this.client.del(...keys.map((k) => this.key(k))) : 0;
31
+ }
32
+ /** Returns the cached value, or runs `load`, stores the result and returns it. `undefined` results are not cached. */
33
+ async wrap(key, load, ttlSeconds = this.ttl) {
34
+ const hit = await this.get(key);
35
+ if (hit !== undefined)
36
+ return hit;
37
+ const running = this.inflight.get(key);
38
+ if (running)
39
+ return running;
40
+ const p = (async () => {
41
+ try {
42
+ const value = await load();
43
+ if (value !== undefined)
44
+ await this.set(key, value, ttlSeconds);
45
+ return value;
46
+ }
47
+ finally {
48
+ this.inflight.delete(key);
49
+ }
50
+ })();
51
+ this.inflight.set(key, p);
52
+ return p;
53
+ }
54
+ /** Deletes every key under the cache prefix that matches `pattern` (default all). */
55
+ async clear(pattern = '*') {
56
+ let n = 0;
57
+ let batch = [];
58
+ for await (const k of this.client.scanIterator({ match: this.prefix + pattern, count: 200 })) {
59
+ batch.push(k);
60
+ if (batch.length >= 200) {
61
+ n += await this.client.del(...batch);
62
+ batch = [];
63
+ }
64
+ }
65
+ if (batch.length)
66
+ n += await this.client.del(...batch);
67
+ return n;
68
+ }
69
+ }
70
+ exports.SnugKvCache = SnugKvCache;
71
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/core/cache.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,23 @@
1
1
  import { EventEmitter } from 'node:events';
2
- import { ConnectionOptions } from './connection';
2
+ import { Connection, ConnectionOptions } from './connection';
3
3
  import { Arg, Reply } from './resp';
4
+ import { SnugKvSubscriber } from './pubsub';
5
+ import { Transaction } from './tx';
4
6
  export interface SnugKvClientOptions extends Partial<ConnectionOptions> {
5
7
  /** `redis://user:pass@host:port`, `rediss://…`, `snugkv://…` or `snugkvs://…`. */
6
8
  url?: string;
7
9
  }
10
+ export interface SetOptions {
11
+ exSeconds?: number;
12
+ pxMs?: number;
13
+ /** Only set when the key does not exist. */
14
+ nx?: boolean;
15
+ /** Only set when the key already exists. */
16
+ xx?: boolean;
17
+ keepTtl?: boolean;
18
+ }
19
+ export declare function asArray(r: Reply): Reply[];
20
+ export declare function pairsToObject(flat: Reply[]): Record<string, string>;
8
21
  export interface StreamEntry {
9
22
  id: string;
10
23
  fields: Record<string, string>;
@@ -36,7 +49,8 @@ export interface XReadGroupOptions {
36
49
  }
37
50
  export declare function toEntries(raw: Reply): StreamEntry[];
38
51
  /**
39
- * A small client for the commands the bus needs, plus a raw `call` for
52
+ * A typed client for SnugKV: strings, hashes, lists, sets, sorted sets,
53
+ * expiry, scan, Lua, pub/sub, transactions and streams, plus a raw `call` for
40
54
  * anything else. One client owns one connection; blocking reads belong on
41
55
  * their own client (see {@link SnugKvClient.duplicate}).
42
56
  */
@@ -44,6 +58,8 @@ export declare class SnugKvClient extends EventEmitter {
44
58
  private readonly conn;
45
59
  private readonly options;
46
60
  constructor(options?: SnugKvClientOptions);
61
+ /** @internal */
62
+ get connection(): Connection;
47
63
  get isReady(): boolean;
48
64
  connect(timeoutMs?: number): Promise<void>;
49
65
  /** New client with its own connection and the same settings. */
@@ -59,6 +75,103 @@ export declare class SnugKvClient extends EventEmitter {
59
75
  exSeconds?: number;
60
76
  }): Promise<void>;
61
77
  del(...keys: string[]): Promise<number>;
78
+ setOpts(key: string, value: string | number, opts?: SetOptions): Promise<boolean>;
79
+ mget(...keys: string[]): Promise<Array<string | null>>;
80
+ mset(values: Record<string, string | number>): Promise<void>;
81
+ incr(key: string, by?: number): Promise<number>;
82
+ decr(key: string, by?: number): Promise<number>;
83
+ incrByFloat(key: string, by: number): Promise<number>;
84
+ append(key: string, value: string): Promise<number>;
85
+ getDel(key: string): Promise<string | null>;
86
+ /** JSON convenience: stores `JSON.stringify(value)`; `ttlSeconds` optional. */
87
+ setJson(key: string, value: unknown, ttlSeconds?: number): Promise<void>;
88
+ getJson<T = unknown>(key: string): Promise<T | null>;
89
+ exists(...keys: string[]): Promise<number>;
90
+ type(key: string): Promise<string>;
91
+ expire(key: string, seconds: number): Promise<boolean>;
92
+ pexpire(key: string, ms: number): Promise<boolean>;
93
+ persist(key: string): Promise<boolean>;
94
+ /** Seconds left; -1 = no expiry, -2 = no such key. */
95
+ ttl(key: string): Promise<number>;
96
+ pttl(key: string): Promise<number>;
97
+ rename(from: string, to: string): Promise<void>;
98
+ dbsize(): Promise<number>;
99
+ /** One SCAN page. */
100
+ scan(cursor: string, opts?: {
101
+ match?: string;
102
+ count?: number;
103
+ type?: string;
104
+ }): Promise<{
105
+ cursor: string;
106
+ keys: string[];
107
+ }>;
108
+ /** Iterates every matching key without loading them all at once. */
109
+ scanIterator(opts?: {
110
+ match?: string;
111
+ count?: number;
112
+ type?: string;
113
+ }): AsyncGenerator<string>;
114
+ /** Sets fields; returns how many were new. */
115
+ hset(key: string, fields: Record<string, string | number>): Promise<number>;
116
+ hget(key: string, field: string): Promise<string | null>;
117
+ hmget(key: string, ...fields: string[]): Promise<Array<string | null>>;
118
+ hgetall(key: string): Promise<Record<string, string>>;
119
+ hdel(key: string, ...fields: string[]): Promise<number>;
120
+ hexists(key: string, field: string): Promise<boolean>;
121
+ hlen(key: string): Promise<number>;
122
+ hkeys(key: string): Promise<string[]>;
123
+ hvals(key: string): Promise<string[]>;
124
+ hincrBy(key: string, field: string, by?: number): Promise<number>;
125
+ hincrByFloat(key: string, field: string, by: number): Promise<number>;
126
+ lpush(key: string, ...values: Array<string | number>): Promise<number>;
127
+ rpush(key: string, ...values: Array<string | number>): Promise<number>;
128
+ lpop(key: string): Promise<string | null>;
129
+ rpop(key: string): Promise<string | null>;
130
+ lrange(key: string, start?: number, stop?: number): Promise<string[]>;
131
+ llen(key: string): Promise<number>;
132
+ ltrim(key: string, start: number, stop: number): Promise<void>;
133
+ sadd(key: string, ...members: string[]): Promise<number>;
134
+ srem(key: string, ...members: string[]): Promise<number>;
135
+ smembers(key: string): Promise<string[]>;
136
+ sismember(key: string, member: string): Promise<boolean>;
137
+ scard(key: string): Promise<number>;
138
+ spop(key: string): Promise<string | null>;
139
+ /** Adds or updates members; returns how many were new. */
140
+ zadd(key: string, members: Array<{
141
+ member: string;
142
+ score: number;
143
+ }>): Promise<number>;
144
+ zincrBy(key: string, member: string, by?: number): Promise<number>;
145
+ zscore(key: string, member: string): Promise<number | null>;
146
+ zrank(key: string, member: string): Promise<number | null>;
147
+ zrem(key: string, ...members: string[]): Promise<number>;
148
+ zcard(key: string): Promise<number>;
149
+ /** Members by rank, lowest score first (or highest first with `reverse`). */
150
+ zrange(key: string, start?: number, stop?: number, opts?: {
151
+ reverse?: boolean;
152
+ }): Promise<Array<{
153
+ member: string;
154
+ score: number;
155
+ }>>;
156
+ /** Members with min <= score <= max. Use `-inf` / `+inf` or `(5` for exclusive bounds. */
157
+ zrangeByScore(key: string, min: number | string, max: number | string, opts?: {
158
+ offset?: number;
159
+ count?: number;
160
+ }): Promise<string[]>;
161
+ zpopMin(key: string): Promise<{
162
+ member: string;
163
+ score: number;
164
+ } | null>;
165
+ /** Runs a Lua script. */
166
+ eval(script: string, keys?: string[], args?: Array<string | number>): Promise<Reply>;
167
+ /** Returns the number of subscribers that received it. */
168
+ publish(channel: string, message: string): Promise<number>;
169
+ /** A subscriber with its own connection and the same settings. */
170
+ subscriber(overrides?: SnugKvClientOptions): SnugKvSubscriber;
171
+ /** Builds a MULTI/EXEC block that is sent in one write, so other callers cannot interleave. */
172
+ tx(): Transaction;
173
+ /** @internal */
174
+ execBlock(commands: Arg[][]): Promise<Reply[]>;
62
175
  static xaddArgs(key: string, fields: Record<string, string>, opts?: XAddOptions): Arg[];
63
176
  xadd(key: string, fields: Record<string, string>, opts?: XAddOptions): Promise<string>;
64
177
  xlen(key: string): Promise<number>;