@classytic/arc 2.8.4 → 2.8.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/README.md +28 -0
- package/dist/adapters/index.d.mts +2 -2
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +1 -1
- package/dist/audit/mongodb.d.mts +1 -1
- package/dist/audit/mongodb.mjs +1 -1
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +2 -2
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi-C5lDyRH2.mjs → betterAuthOpenApi-BuUcUEJq.mjs} +1 -1
- package/dist/cache/index.d.mts +73 -3
- package/dist/cache/index.mjs +95 -2
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +1 -1
- package/dist/cli/commands/introspect.mjs +1 -1
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +3 -3
- package/dist/{core-DKSwNSXf.mjs → core-F0QoWBt2.mjs} +1 -1
- package/dist/{createActionRouter-Df1BuawX.mjs → createActionRouter-BORM8f17.mjs} +1 -1
- package/dist/{createApp-BOYjBgdI.mjs → createApp-B1EY8zxa.mjs} +11 -11
- package/dist/{defineResource-Bb_Bdhtw.mjs → defineResource-tcgySDo1.mjs} +2 -2
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/dynamic/index.d.mts +2 -2
- package/dist/dynamic/index.mjs +1 -1
- package/dist/{elevation-BBGFjzIP.mjs → elevation-DtFxrG0s.mjs} +1 -1
- package/dist/{errorHandler-CdZDavNH.d.mts → errorHandler-Bah5JhBd.d.mts} +1 -1
- package/dist/{eventPlugin-CVxlE6De.d.mts → eventPlugin-D9DKB2zM.d.mts} +1 -1
- package/dist/events/index.d.mts +3 -3
- package/dist/events/index.mjs +1 -1
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +2 -2
- package/dist/filesUpload-C7r7HIeA.mjs +319 -0
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/mongodb.d.mts +1 -1
- package/dist/idempotency/redis.d.mts +2 -2
- package/dist/idempotency/redis.mjs +134 -13
- package/dist/{index-CSkeivBx.d.mts → index-BLXBmWud.d.mts} +3 -3
- package/dist/{index-BgmMdpm8.d.mts → index-C1meYuDn.d.mts} +1 -1
- package/dist/{index-CpTSDqmD.d.mts → index-DtDzOBn8.d.mts} +3 -3
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +4 -4
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/jobs.d.mts +25 -3
- package/dist/integrations/jobs.mjs +63 -4
- package/dist/integrations/mcp/index.d.mts +2 -2
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.d.mts +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/{interface-BVuMfeVv.d.mts → interface-CMRutPfe.d.mts} +38 -16
- package/dist/{mongodb-B8U2xaLj.d.mts → mongodb-BsP-WbhN.d.mts} +1 -1
- package/dist/{mongodb-X7LbEjTN.d.mts → mongodb-CTcp0hQZ.d.mts} +1 -1
- package/dist/{openapi-CYCuekCn.mjs → openapi-CbKUJY_m.mjs} +3 -3
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +3 -3
- package/dist/plugins/index.d.mts +4 -4
- package/dist/plugins/index.mjs +8 -8
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/policies/index.d.mts +1 -1
- package/dist/presets/filesUpload.d.mts +49 -0
- package/dist/presets/filesUpload.mjs +2 -0
- package/dist/presets/index.d.mts +3 -2
- package/dist/presets/index.mjs +2 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/{queryCachePlugin-CnTZZTC5.d.mts → queryCachePlugin-BJJGBTlu.d.mts} +1 -1
- package/dist/redis-BM00zaPB.d.mts +115 -0
- package/dist/{redis-stream-D54N5oXs.d.mts → redis-stream-CrsfUmPt.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/{resourceToTools-O_HwWXFa.mjs → resourceToTools-8s-EsCCe.mjs} +1 -1
- package/dist/rpc/index.d.mts +1 -1
- package/dist/{schemaConverter-OxfCshus.mjs → schemaConverter-Y7nCYaLJ.mjs} +24 -8
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +1 -1
- package/dist/{sse-CJpt7LGI.mjs → sse-Ad7ypl9e.mjs} +1 -1
- package/dist/storage-Dfzt4VTl.d.mts +146 -0
- package/dist/testing/index.d.mts +4 -3
- package/dist/testing/index.mjs +3 -2
- package/dist/testing/storageContract.d.mts +26 -0
- package/dist/testing/storageContract.mjs +216 -0
- package/dist/types/index.d.mts +4 -4
- package/dist/types/storage.d.mts +2 -0
- package/dist/types/storage.mjs +1 -0
- package/dist/{types-CcG4avic.d.mts → types-BsbNMEDR.d.mts} +1 -1
- package/dist/{types-Bg2X42_m.d.mts → types-Ch9pTQbf.d.mts} +9 -9
- package/dist/{types-CVC4HOKi.d.mts → types-DZi1aYhm.d.mts} +1 -1
- package/dist/utils/index.d.mts +26 -8
- package/dist/utils/index.mjs +1 -1
- package/package.json +16 -1
- package/skills/arc/references/events.md +29 -0
- package/dist/redis-z3sFr1UP.d.mts +0 -49
- /package/dist/{EventTransport-CinyO7zQ.d.mts → EventTransport-BXja8NOc.d.mts} +0 -0
- /package/dist/{HookSystem-BjFu7zf1.mjs → HookSystem-HprTmvVY.mjs} +0 -0
- /package/dist/{ResourceRegistry-Dq3_zBQP.mjs → ResourceRegistry-C6uXlWe3.mjs} +0 -0
- /package/dist/{caching-CjybdRwx.mjs → caching-IMuYVjTL.mjs} +0 -0
- /package/dist/{circuitBreaker-CvXkjfrW.d.mts → circuitBreaker-dTtG-UyS.d.mts} +0 -0
- /package/dist/{elevation-s5ykdNHr.d.mts → elevation-B6S5csVA.d.mts} +0 -0
- /package/dist/{errorHandler-mzqk4cGl.mjs → errorHandler-f869_8PQ.mjs} +0 -0
- /package/dist/{errors-Bmn3eZT6.d.mts → errors-Ck2h67pm.d.mts} +0 -0
- /package/dist/{eventPlugin-D91S2YF4.mjs → eventPlugin-CDjVTM82.mjs} +0 -0
- /package/dist/{externalPaths-Bapitwvd.d.mts → externalPaths-BnkYrNzp.d.mts} +0 -0
- /package/dist/{fields-DC4So2M2.d.mts → fields-DpZQa_Q3.d.mts} +0 -0
- /package/dist/{interface-DplgQO2e.d.mts → interface-4y979v99.d.mts} +0 -0
- /package/dist/{interface-B-pe8fhj.d.mts → interface-DfLGcus7.d.mts} +0 -0
- /package/dist/{loadResources-Bksk8ydA.mjs → loadResources-PWd0OCpV.mjs} +0 -0
- /package/dist/{logger-CDjpjySd.mjs → logger-D1YrIImS.mjs} +0 -0
- /package/dist/{metrics-TuOmguhi.mjs → metrics-B-PU4-Yu.mjs} +0 -0
- /package/dist/{mongodb-B5O6xaW1.mjs → mongodb-Utc5k_-0.mjs} +0 -0
- /package/dist/{pluralize-A0tWEl1K.mjs → pluralize-CWP6MB39.mjs} +0 -0
- /package/dist/{queryCachePlugin-D0iIVhW_.mjs → queryCachePlugin-BH-fidlv.mjs} +0 -0
- /package/dist/{registry-B0Wl7uVV.mjs → registry-BiTKT1Dg.mjs} +0 -0
- /package/dist/{replyHelpers-BLojtuvR.mjs → replyHelpers-CxkYGT81.mjs} +0 -0
- /package/dist/{sessionManager-D-oNWHz3.d.mts → sessionManager-DDCmiNIo.d.mts} +0 -0
- /package/dist/{tracing-DxjKk7eW.d.mts → tracing-DdN2-wHJ.d.mts} +0 -0
- /package/dist/{types-C72d3NDn.d.mts → types-BD85MlEK.d.mts} +0 -0
- /package/dist/{versioning-Cm8qoFDg.mjs → versioning-CDugduqI.mjs} +0 -0
package/dist/utils/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Y as OpenApiSchemas, Z as ParsedQuery, m as AnyRecord, nt as QueryParserInterface } from "../interface-
|
|
2
|
-
import { a as NotFoundError, c as RateLimitError, d as ValidationError, f as createDomainError, i as ForbiddenError, l as ServiceUnavailableError, m as isArcError, n as ConflictError, o as OrgAccessDeniedError, p as createError, r as ErrorDetails, s as OrgRequiredError, t as ArcError, u as UnauthorizedError } from "../errors-
|
|
3
|
-
import { a as CircuitBreakerStats, c as createCircuitBreakerRegistry, i as CircuitBreakerRegistry, n as CircuitBreakerError, o as CircuitState, r as CircuitBreakerOptions, s as createCircuitBreaker, t as CircuitBreaker } from "../circuitBreaker-
|
|
1
|
+
import { Y as OpenApiSchemas, Z as ParsedQuery, m as AnyRecord, nt as QueryParserInterface } from "../interface-CMRutPfe.mjs";
|
|
2
|
+
import { a as NotFoundError, c as RateLimitError, d as ValidationError, f as createDomainError, i as ForbiddenError, l as ServiceUnavailableError, m as isArcError, n as ConflictError, o as OrgAccessDeniedError, p as createError, r as ErrorDetails, s as OrgRequiredError, t as ArcError, u as UnauthorizedError } from "../errors-Ck2h67pm.mjs";
|
|
3
|
+
import { a as CircuitBreakerStats, c as createCircuitBreakerRegistry, i as CircuitBreakerRegistry, n as CircuitBreakerError, o as CircuitState, r as CircuitBreakerOptions, s as createCircuitBreaker, t as CircuitBreaker } from "../circuitBreaker-dTtG-UyS.mjs";
|
|
4
4
|
import { FastifyInstance, FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
|
|
5
5
|
|
|
6
6
|
//#region src/utils/compensation.d.ts
|
|
@@ -506,6 +506,14 @@ declare function getListQueryParams(): AnyRecord;
|
|
|
506
506
|
declare function getDefaultCrudSchemas(): Record<string, Record<string, unknown>>;
|
|
507
507
|
//#endregion
|
|
508
508
|
//#region src/utils/schemaConverter.d.ts
|
|
509
|
+
/**
|
|
510
|
+
* Supported JSON Schema output targets for Zod v4's `toJSONSchema()`.
|
|
511
|
+
* - `draft-7`: Fastify/AJV validation (default)
|
|
512
|
+
* - `draft-2020-12`: AJV 2020 (opt-in, requires ajv/dist/2020)
|
|
513
|
+
* - `openapi-3.0`: OpenAPI 3.0 document generation
|
|
514
|
+
* - `openapi-3.1`: OpenAPI 3.1 document generation
|
|
515
|
+
*/
|
|
516
|
+
type JsonSchemaTarget = "draft-7" | "draft-2020-12" | "openapi-3.0" | "openapi-3.1";
|
|
509
517
|
/**
|
|
510
518
|
* Check if an object is already a plain JSON Schema.
|
|
511
519
|
* Returns true if it has JSON Schema markers (`type`, `properties`, `$ref`,
|
|
@@ -522,15 +530,22 @@ declare function isZodSchema(input: unknown): boolean;
|
|
|
522
530
|
* Detection order:
|
|
523
531
|
* 1. `null`/`undefined` → `undefined`
|
|
524
532
|
* 2. Already JSON Schema → pass through as-is (zero overhead)
|
|
525
|
-
* 3. Zod v4 schema → `z.toJSONSchema(schema, { target
|
|
533
|
+
* 3. Zod v4 schema → `z.toJSONSchema(schema, { target })`
|
|
526
534
|
* 4. Unrecognized object → return as-is (treat as opaque schema)
|
|
535
|
+
*
|
|
536
|
+
* @param input Schema (Zod, plain JSON Schema, or opaque object)
|
|
537
|
+
* @param target Output target — defaults to `draft-7` for Fastify compatibility.
|
|
538
|
+
* Pass `openapi-3.0`/`openapi-3.1` for OpenAPI document generation.
|
|
527
539
|
*/
|
|
528
|
-
declare function toJsonSchema(input: unknown): Record<string, unknown> | undefined;
|
|
540
|
+
declare function toJsonSchema(input: unknown, target?: JsonSchemaTarget): Record<string, unknown> | undefined;
|
|
529
541
|
/**
|
|
530
542
|
* Convert all schema fields in an OpenApiSchemas object.
|
|
531
543
|
* JSON Schema values pass through unchanged. Only Zod schemas are converted.
|
|
544
|
+
*
|
|
545
|
+
* Defaults to the `openapi-3.0` target since this function feeds OpenAPI doc
|
|
546
|
+
* generation, not Fastify route validation.
|
|
532
547
|
*/
|
|
533
|
-
declare function convertOpenApiSchemas(schemas: OpenApiSchemas): OpenApiSchemas;
|
|
548
|
+
declare function convertOpenApiSchemas(schemas: OpenApiSchemas, target?: JsonSchemaTarget): OpenApiSchemas;
|
|
534
549
|
/**
|
|
535
550
|
* Convert schema values in a Fastify route schema record.
|
|
536
551
|
*
|
|
@@ -540,8 +555,11 @@ declare function convertOpenApiSchemas(schemas: OpenApiSchemas): OpenApiSchemas;
|
|
|
540
555
|
* JSON Schema values pass through unchanged. Only Zod schemas are converted.
|
|
541
556
|
*
|
|
542
557
|
* Used for both additionalRoutes and customSchemas (CRUD overrides).
|
|
558
|
+
*
|
|
559
|
+
* Defaults to `draft-7` so Fastify v5's bundled AJV 8 accepts the output.
|
|
560
|
+
* Pass `openapi-3.0` (or `openapi-3.1`) when generating OpenAPI documents.
|
|
543
561
|
*/
|
|
544
|
-
declare function convertRouteSchema(schema: Record<string, unknown
|
|
562
|
+
declare function convertRouteSchema(schema: Record<string, unknown>, target?: JsonSchemaTarget): Record<string, unknown>;
|
|
545
563
|
//#endregion
|
|
546
564
|
//#region src/utils/stateMachine.d.ts
|
|
547
565
|
/**
|
|
@@ -673,4 +691,4 @@ declare function hasEvents(instance: FastifyInstance): instance is FastifyInstan
|
|
|
673
691
|
events: EventsDecorator;
|
|
674
692
|
};
|
|
675
693
|
//#endregion
|
|
676
|
-
export { ArcError, ArcQueryParser, type ArcQueryParserOptions, CircuitBreaker, CircuitBreakerError, type CircuitBreakerOptions, CircuitBreakerRegistry, type CircuitBreakerStats, CircuitState, type CompensationDefinition, type CompensationError, type CompensationHooks, type CompensationResult, type CompensationStep, ConflictError, type ErrorDetails, type EventsDecorator, ForbiddenError, type Guard, type GuardConfig, type JsonSchema, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, type StateMachine, type TransitionConfig, UnauthorizedError, ValidationError, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createDomainError, createError, createQueryParser, createStateMachine, defineCompensation, defineGuard, deleteResponse, errorResponseSchema, getDefaultCrudSchemas, getListQueryParams, handleRaw, hasEvents, isArcError, isJsonSchema, isZodSchema, itemResponse, listResponse, mutationResponse, paginationSchema, queryParams, responses, successResponseSchema, toJsonSchema, withCompensation, wrapResponse };
|
|
694
|
+
export { ArcError, ArcQueryParser, type ArcQueryParserOptions, CircuitBreaker, CircuitBreakerError, type CircuitBreakerOptions, CircuitBreakerRegistry, type CircuitBreakerStats, CircuitState, type CompensationDefinition, type CompensationError, type CompensationHooks, type CompensationResult, type CompensationStep, ConflictError, type ErrorDetails, type EventsDecorator, ForbiddenError, type Guard, type GuardConfig, type JsonSchema, type JsonSchemaTarget, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, type StateMachine, type TransitionConfig, UnauthorizedError, ValidationError, convertOpenApiSchemas, convertRouteSchema, createCircuitBreaker, createCircuitBreakerRegistry, createDomainError, createError, createQueryParser, createStateMachine, defineCompensation, defineGuard, deleteResponse, errorResponseSchema, getDefaultCrudSchemas, getListQueryParams, handleRaw, hasEvents, isArcError, isJsonSchema, isZodSchema, itemResponse, listResponse, mutationResponse, paginationSchema, queryParams, responses, successResponseSchema, toJsonSchema, withCompensation, wrapResponse };
|
package/dist/utils/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as createQueryParser, t as ArcQueryParser } from "../queryParser-CgCtsjti.mjs";
|
|
2
|
-
import { a as toJsonSchema, i as isZodSchema, n as convertRouteSchema, r as isJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-
|
|
2
|
+
import { a as toJsonSchema, i as isZodSchema, n as convertRouteSchema, r as isJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-Y7nCYaLJ.mjs";
|
|
3
3
|
import { a as createCircuitBreaker, i as CircuitState, n as CircuitBreakerError, o as createCircuitBreakerRegistry, r as CircuitBreakerRegistry, t as CircuitBreaker } from "../circuitBreaker-cmi5XDv5.mjs";
|
|
4
4
|
import { _ as withCompensation, a as getListQueryParams, c as mutationResponse, d as responses, f as successResponseSchema, g as defineCompensation, h as defineGuard, i as getDefaultCrudSchemas, l as paginationSchema, m as handleRaw, n as deleteResponse, o as itemResponse, p as wrapResponse, r as errorResponseSchema, s as listResponse, t as createStateMachine, u as queryParams } from "../utils-yYT3HDXt.mjs";
|
|
5
5
|
import { a as OrgAccessDeniedError, c as ServiceUnavailableError, d as createDomainError, f as createError, i as NotFoundError, l as UnauthorizedError, n as ConflictError, o as OrgRequiredError, p as isArcError, r as ForbiddenError, s as RateLimitError, t as ArcError, u as ValidationError } from "../errors-BF2bIOIS.mjs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/arc",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.5",
|
|
4
4
|
"description": "Resource-oriented backend framework for Fastify — clean, minimal, powerful, tree-shakable",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
"types": "./dist/types/index.d.mts",
|
|
21
21
|
"default": "./dist/types/index.mjs"
|
|
22
22
|
},
|
|
23
|
+
"./types/storage": {
|
|
24
|
+
"types": "./dist/types/storage.d.mts",
|
|
25
|
+
"default": "./dist/types/storage.mjs"
|
|
26
|
+
},
|
|
23
27
|
"./adapters": {
|
|
24
28
|
"types": "./dist/adapters/index.d.mts",
|
|
25
29
|
"default": "./dist/adapters/index.mjs"
|
|
@@ -36,6 +40,10 @@
|
|
|
36
40
|
"types": "./dist/presets/multiTenant.d.mts",
|
|
37
41
|
"default": "./dist/presets/multiTenant.mjs"
|
|
38
42
|
},
|
|
43
|
+
"./presets/files-upload": {
|
|
44
|
+
"types": "./dist/presets/filesUpload.d.mts",
|
|
45
|
+
"default": "./dist/presets/filesUpload.mjs"
|
|
46
|
+
},
|
|
39
47
|
"./auth": {
|
|
40
48
|
"types": "./dist/auth/index.d.mts",
|
|
41
49
|
"default": "./dist/auth/index.mjs"
|
|
@@ -116,6 +124,10 @@
|
|
|
116
124
|
"types": "./dist/testing/index.d.mts",
|
|
117
125
|
"default": "./dist/testing/index.mjs"
|
|
118
126
|
},
|
|
127
|
+
"./testing/storage": {
|
|
128
|
+
"types": "./dist/testing/storageContract.d.mts",
|
|
129
|
+
"default": "./dist/testing/storageContract.mjs"
|
|
130
|
+
},
|
|
119
131
|
"./policies": {
|
|
120
132
|
"types": "./dist/policies/index.d.mts",
|
|
121
133
|
"default": "./dist/policies/index.mjs"
|
|
@@ -364,7 +376,10 @@
|
|
|
364
376
|
"@vitest/coverage-v8": "^3.2.4",
|
|
365
377
|
"ajv": "^8.18.0",
|
|
366
378
|
"better-auth": "^1.6.2",
|
|
379
|
+
"bullmq": "^5.73.5",
|
|
380
|
+
"dotenv": "^17.4.2",
|
|
367
381
|
"fastify-raw-body": "^5.0.0",
|
|
382
|
+
"ioredis": "^5.10.1",
|
|
368
383
|
"jsonwebtoken": "^9.0.0",
|
|
369
384
|
"knip": "^6.4.1",
|
|
370
385
|
"mongodb": "^7.1.0",
|
|
@@ -168,6 +168,35 @@ class KafkaTransport implements EventTransport {
|
|
|
168
168
|
| Redis Pub/Sub | `@classytic/arc/events/redis` | Multi-instance, real-time |
|
|
169
169
|
| Redis Streams | `@classytic/arc/events/redis-stream` | Ordered, persistent, consumer groups |
|
|
170
170
|
|
|
171
|
+
### Streams vs Pub/Sub — pick the right one
|
|
172
|
+
|
|
173
|
+
Choosing wrong loses messages silently. Default to **Streams** for anything business-critical.
|
|
174
|
+
|
|
175
|
+
| Requirement | Use |
|
|
176
|
+
|---|---|
|
|
177
|
+
| Message MUST NOT be lost (billing, payments, audit) | **Streams** |
|
|
178
|
+
| Real-time notifications, OK to miss when no subscriber is up | Pub/Sub |
|
|
179
|
+
| Need to replay/reprocess past events | **Streams** |
|
|
180
|
+
| Multiple workers processing the same queue | **Streams** (consumer groups) |
|
|
181
|
+
| Simple broadcast to live WebSocket clients | Pub/Sub |
|
|
182
|
+
| Event sourcing or audit trail | **Streams** |
|
|
183
|
+
| Single-instance dev | Memory |
|
|
184
|
+
| At-least-once delivery with durable WAL | **Streams** + outbox pattern |
|
|
185
|
+
|
|
186
|
+
**Why it matters:** Pub/Sub is fire-and-forget. If no subscriber is connected when you publish, the message is gone. Streams persist until every consumer group acknowledges them — crashes, restarts, and network blips are survivable.
|
|
187
|
+
|
|
188
|
+
**Defense-in-depth:** pair `eventPlugin` with the transactional outbox (`EventOutbox` + `MemoryOutboxStore` or your own persistent store) for guaranteed delivery even if Redis is unreachable at publish time.
|
|
189
|
+
|
|
190
|
+
### Redis eviction policy — required for queues and idempotency
|
|
191
|
+
|
|
192
|
+
When you back events (Streams), jobs (BullMQ), idempotency, or cache with Redis, your Redis instance **must** be configured with `maxmemory-policy: noeviction`. Any other policy can silently evict in-flight stream entries or pending jobs.
|
|
193
|
+
|
|
194
|
+
- **Self-hosted Redis:** `redis-cli CONFIG SET maxmemory-policy noeviction` (or set in `redis.conf`).
|
|
195
|
+
- **Upstash:** free/paid DBs default to `optimistic-volatile`. You'll see `IMPORTANT! Eviction policy is optimistic-volatile. It should be "noeviction"` in BullMQ logs. **Do one of:** open a support ticket to request `noeviction`, use a dedicated DB for queues, or accept that long-idle jobs may be evicted.
|
|
196
|
+
- **ElastiCache / Redis Cloud:** set the parameter group's `maxmemory-policy` to `noeviction` before pointing arc at it.
|
|
197
|
+
|
|
198
|
+
For a pure cache DB (no queues, no idempotency), `allkeys-lru` is correct and what you want.
|
|
199
|
+
|
|
171
200
|
## Injectable Logger
|
|
172
201
|
|
|
173
202
|
All transports and retry accept a `logger` option — defaults to `console`, compatible with pino/fastify.log:
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { n as IdempotencyResult, r as IdempotencyStore } from "./interface-B-pe8fhj.mjs";
|
|
2
|
-
|
|
3
|
-
//#region src/idempotency/stores/redis.d.ts
|
|
4
|
-
interface RedisClient {
|
|
5
|
-
get(key: string): Promise<string | null>;
|
|
6
|
-
set(key: string, value: string, options?: {
|
|
7
|
-
EX?: number;
|
|
8
|
-
NX?: boolean;
|
|
9
|
-
}): Promise<string | null>;
|
|
10
|
-
del(key: string | string[]): Promise<number>;
|
|
11
|
-
exists(key: string | string[]): Promise<number>;
|
|
12
|
-
/** SCAN command — compatible with node-redis and ioredis varargs signatures. */
|
|
13
|
-
scan?(cursor: string | number, ...args: (string | number)[]): Promise<[string | number, string[]]>;
|
|
14
|
-
quit?(): Promise<string>;
|
|
15
|
-
disconnect?(): Promise<void>;
|
|
16
|
-
}
|
|
17
|
-
interface RedisIdempotencyStoreOptions {
|
|
18
|
-
/** Redis client instance */
|
|
19
|
-
client: RedisClient;
|
|
20
|
-
/** Key prefix (default: 'idem:') */
|
|
21
|
-
prefix?: string;
|
|
22
|
-
/** Lock key prefix (default: 'idem:lock:') */
|
|
23
|
-
lockPrefix?: string;
|
|
24
|
-
/** Default TTL in ms (default: 86400000 = 24 hours) */
|
|
25
|
-
ttlMs?: number;
|
|
26
|
-
}
|
|
27
|
-
declare class RedisIdempotencyStore implements IdempotencyStore {
|
|
28
|
-
readonly name = "redis";
|
|
29
|
-
private client;
|
|
30
|
-
private prefix;
|
|
31
|
-
private lockPrefix;
|
|
32
|
-
private ttlMs;
|
|
33
|
-
constructor(options: RedisIdempotencyStoreOptions);
|
|
34
|
-
private resultKey;
|
|
35
|
-
private lockKey;
|
|
36
|
-
get(key: string): Promise<IdempotencyResult | undefined>;
|
|
37
|
-
set(key: string, result: Omit<IdempotencyResult, "key">): Promise<void>;
|
|
38
|
-
tryLock(key: string, requestId: string, ttlMs: number): Promise<boolean>;
|
|
39
|
-
unlock(key: string, requestId: string): Promise<void>;
|
|
40
|
-
isLocked(key: string): Promise<boolean>;
|
|
41
|
-
delete(key: string): Promise<void>;
|
|
42
|
-
deleteByPrefix(prefix: string): Promise<number>;
|
|
43
|
-
findByPrefix(prefix: string): Promise<IdempotencyResult | undefined>;
|
|
44
|
-
/** Scan Redis keys matching a prefix pattern. Falls back to empty if SCAN unavailable. */
|
|
45
|
-
private scanByPrefix;
|
|
46
|
-
close(): Promise<void>;
|
|
47
|
-
}
|
|
48
|
-
//#endregion
|
|
49
|
-
export { RedisIdempotencyStore as n, RedisIdempotencyStoreOptions as r, RedisClient as t };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|