@bumail/queue 0.11.0 → 0.12.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/README.md CHANGED
@@ -28,6 +28,7 @@ queue that only uses a smarthost needs none.
28
28
  | `@bumail/queue/sqlite` | `SqliteQueueStore`: on disk with `bun:sqlite`, shared by the processes of one machine |
29
29
  | `@bumail/queue/postgres` | `PostgresQueueStore`: on PostgreSQL through Bun's own `Bun.sql`, shared by instances on several machines |
30
30
  | `@bumail/queue/redis` | `RedisQueueStore`: on Redis through Bun's own `Bun.redis`, shared by instances on several machines |
31
+ | `@bumail/queue/conformance` | `describeQueueStore`: the `QueueStore` contract suite, run with `bun test` against a store written outside the package |
31
32
 
32
33
  ## Usage
33
34
 
@@ -255,6 +256,29 @@ if (next) await queue.retryNow(next.id); // false while a worker delivers it
255
256
  if (next) await queue.cancel(next.id); // no DSN
256
257
  ```
257
258
 
259
+ ## A store of your own
260
+
261
+ `QueueStore` may grow in a 0.x minor version (methods, fields); a store of your own follows it.
262
+
263
+ Hold a `QueueStore` you wrote to the same tests the stores here pass.
264
+ The spec runs with `bun test` (the suite imports `bun:test`):
265
+
266
+ ```ts
267
+ // my-store.spec.ts
268
+ import { describeQueueStore } from '@bumail/queue/conformance';
269
+ import { MyQueueStore } from './my-store';
270
+
271
+ describeQueueStore('MyQueueStore', {
272
+ create: () => MyQueueStore.open({ url: process.env.MY_STORE_URL }),
273
+ share: (store) => (store as MyQueueStore).connectAgain(), // a second handle on the same queue
274
+ dispose: (store) => (store as MyQueueStore).close(),
275
+ });
276
+ ```
277
+
278
+ Without `share` the two several-workers tests are skipped, and a store
279
+ shared over a network should pass a real second connection. See
280
+ [Holding your own store to the contract](https://github.com/softistx/bumail/blob/develop/packages/queue/docs/guide.md#holding-your-own-store-to-the-contract).
281
+
258
282
  ## Testing
259
283
 
260
284
  ```ts
@@ -346,6 +370,7 @@ control character in it.
346
370
  | `createQueue(options)`, `Queue` | the queue: `enqueue`, `deliverDue`, `start`, `stop`, `on`, `list`, `get`, `retryNow`, `cancel`, `owner` |
347
371
  | `QueueOptions` (`route`, `routes`, `fallback`), `Route`, `Smarthost`, `RetrySchedule`, `DsnOptions`, `QueueLimits`, `Clock`, `Sender` | what `createQueue` takes |
348
372
  | `MessageSource`, `QueueEnvelope` (`ret`, `envid`, `recipients`), `RecipientDsn`, `RecipientNotify`, `NotifyEvent`, `OriginalRecipient`, `RetMode` | what `enqueue` takes, with the DSN parameters |
373
+ | `describeQueueStore`, `QueueStoreHarness`, `CreateQueueStore`, `ShareStore` | from `@bumail/queue/conformance`: `describeQueueStore(name, { create, share?, dispose? })`, run under `bun test`; without `share` the two several-workers tests are skipped |
349
374
  | `deliveredDsn(input)`, `DeliveredDsnInput`, `DeliveredRecipient` | the `delivered` DSN for a local delivery: the bytes to enqueue, or `undefined` when no recipient asked for `SUCCESS` |
350
375
  | `failedDsn(input)`, `FailedDsnInput`, `FailedRecipient`, `DEFAULT_MAX_RETURN` | the `failed` DSN for a recipient the application could not deliver locally: the bytes to enqueue, or `undefined` for a null reverse-path or when no recipient asked for failures; `DEFAULT_MAX_RETURN` is the 64 KiB a DSN returns of the original by default |
351
376
  | `QueueEvents`, `QueueListener`, `RecipientEvent` (`route`, `fallback`, `mxReply`, `mayHaveReachedMx`, `mayHaveReachedFallback`), `DeferredEvent`, `DsnEvent`, `QueueErrorEvent` | the events |
@@ -0,0 +1,4 @@
1
+ import { type StoreFactories } from './setup';
2
+ /** Claims, leases and schedules. */
3
+ export declare function describeClaims(factories: StoreFactories): void;
4
+ //# sourceMappingURL=claims.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claims.d.ts","sourceRoot":"","sources":["../../src/conformance/claims.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0B,KAAK,cAAc,EAAM,MAAM,SAAS,CAAC;AAa1E,oCAAoC;AACpC,wBAAgB,cAAc,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,CAM9D"}
@@ -0,0 +1,4 @@
1
+ import { type StoreFactories } from './setup';
2
+ /** The DSNs `complete` takes: stored with the outcome, or not at all. */
3
+ export declare function completeDsns(factories: StoreFactories): void;
4
+ //# sourceMappingURL=complete-dsns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complete-dsns.d.ts","sourceRoot":"","sources":["../../src/conformance/complete-dsns.ts"],"names":[],"mappings":"AAEA,OAAO,EAON,KAAK,cAAc,EAEnB,MAAM,SAAS,CAAC;AAgBjB,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,CAK5D"}
@@ -0,0 +1,4 @@
1
+ import { type StoreFactories } from './setup';
2
+ /** Several claimers on one queue, and a claimer that crashed. */
3
+ export declare function describeConcurrency({ create, share }: StoreFactories): void;
4
+ //# sourceMappingURL=concurrency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../../src/conformance/concurrency.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,cAAc,EAAM,MAAM,SAAS,CAAC;AA2BjE,iEAAiE;AACjE,wBAAgB,mBAAmB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,cAAc,GAAG,IAAI,CAkD3E"}
@@ -0,0 +1,11 @@
1
+ import type { QueueStoreHarness } from './setup';
2
+ /**
3
+ * The specs every `QueueStore` must pass, to call from a spec file run by
4
+ * `bun test`. The harness builds an empty store with `create`; `share` is
5
+ * another handle on the same queue (a second connection, as a second
6
+ * process opens), so the claim's atomicity is checked across handles, not
7
+ * only within one: without it those tests are registered as skipped.
8
+ * `dispose` runs after every test with the stores that test created.
9
+ */
10
+ export declare function describeQueueStore(name: string, harness: QueueStoreHarness): void;
11
+ //# sourceMappingURL=describe-queue-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe-queue-store.d.ts","sourceRoot":"","sources":["../../src/conformance/describe-queue-store.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,iBAAiB,GACxB,IAAI,CA6BN"}
@@ -0,0 +1,5 @@
1
+ import { type StoreFactories } from './setup';
2
+ /** The marks a recipient keeps when a server may hold a copy. */
3
+ export declare function doubt({ create }: StoreFactories): void;
4
+ export declare function fallbackDoubt({ create }: StoreFactories): void;
5
+ //# sourceMappingURL=doubt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doubt.d.ts","sourceRoot":"","sources":["../../src/conformance/doubt.ts"],"names":[],"mappings":"AAEA,OAAO,EAMN,KAAK,cAAc,EAEnB,MAAM,SAAS,CAAC;AAEjB,iEAAiE;AACjE,wBAAgB,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,cAAc,GAAG,IAAI,CAwEtD;AAED,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,EAAE,cAAc,GAAG,IAAI,CA8E9D"}
@@ -0,0 +1,4 @@
1
+ import { type StoreFactories } from './setup';
2
+ /** RFC 3461's parameters: kept as given, for the item's whole life. */
3
+ export declare function dsnParameters({ create }: StoreFactories): void;
4
+ //# sourceMappingURL=dsn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsn.d.ts","sourceRoot":"","sources":["../../src/conformance/dsn.ts"],"names":[],"mappings":"AACA,OAAO,EAKN,KAAK,cAAc,EAEnB,MAAM,SAAS,CAAC;AAEjB,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,EAAE,cAAc,GAAG,IAAI,CAqJ9D"}
@@ -0,0 +1,3 @@
1
+ export { describeQueueStore } from './describe-queue-store';
2
+ export type { CreateQueueStore, QueueStoreHarness, ShareStore } from './setup';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conformance/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC"}