@classytic/arc 1.1.0 → 2.1.3

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 (200) hide show
  1. package/README.md +247 -794
  2. package/bin/arc.js +91 -52
  3. package/dist/EventTransport-BkUDYZEb.d.mts +99 -0
  4. package/dist/HookSystem-BsGV-j2l.mjs +404 -0
  5. package/dist/ResourceRegistry-7Ic20ZMw.mjs +249 -0
  6. package/dist/adapters/index.d.mts +5 -0
  7. package/dist/adapters/index.mjs +3 -0
  8. package/dist/audit/index.d.mts +81 -0
  9. package/dist/audit/index.mjs +275 -0
  10. package/dist/audit/mongodb.d.mts +5 -0
  11. package/dist/audit/mongodb.mjs +3 -0
  12. package/dist/audited-CGdLiSlE.mjs +140 -0
  13. package/dist/auth/index.d.mts +188 -0
  14. package/dist/auth/index.mjs +1096 -0
  15. package/dist/auth/redis-session.d.mts +43 -0
  16. package/dist/auth/redis-session.mjs +75 -0
  17. package/dist/betterAuthOpenApi-DjWDddNc.mjs +249 -0
  18. package/dist/cache/index.d.mts +145 -0
  19. package/dist/cache/index.mjs +91 -0
  20. package/dist/caching-GSDJcA6-.mjs +93 -0
  21. package/dist/chunk-C7Uep-_p.mjs +20 -0
  22. package/dist/circuitBreaker-DYhWBW_D.mjs +1096 -0
  23. package/dist/cli/commands/describe.d.mts +18 -0
  24. package/dist/cli/commands/describe.mjs +238 -0
  25. package/dist/cli/commands/docs.d.mts +13 -0
  26. package/dist/cli/commands/docs.mjs +52 -0
  27. package/dist/cli/commands/{generate.d.ts → generate.d.mts} +3 -2
  28. package/dist/cli/commands/generate.mjs +357 -0
  29. package/dist/cli/commands/{init.d.ts → init.d.mts} +11 -8
  30. package/dist/cli/commands/{init.js → init.mjs} +807 -617
  31. package/dist/cli/commands/introspect.d.mts +10 -0
  32. package/dist/cli/commands/introspect.mjs +75 -0
  33. package/dist/cli/index.d.mts +16 -0
  34. package/dist/cli/index.mjs +156 -0
  35. package/dist/constants-DdXFXQtN.mjs +84 -0
  36. package/dist/core/index.d.mts +5 -0
  37. package/dist/core/index.mjs +4 -0
  38. package/dist/createApp-D2D5XXaV.mjs +559 -0
  39. package/dist/defineResource-PXzSJ15_.mjs +2197 -0
  40. package/dist/discovery/index.d.mts +46 -0
  41. package/dist/discovery/index.mjs +109 -0
  42. package/dist/docs/index.d.mts +162 -0
  43. package/dist/docs/index.mjs +74 -0
  44. package/dist/elevation-DGo5shaX.d.mts +87 -0
  45. package/dist/elevation-DSTbVvYj.mjs +113 -0
  46. package/dist/errorHandler-C3GY3_ow.mjs +108 -0
  47. package/dist/errorHandler-CW3OOeYq.d.mts +72 -0
  48. package/dist/errors-DAWRdiYP.d.mts +124 -0
  49. package/dist/errors-DBANPbGr.mjs +211 -0
  50. package/dist/eventPlugin-BEOvaDqo.mjs +229 -0
  51. package/dist/eventPlugin-H6wDDjGO.d.mts +124 -0
  52. package/dist/events/index.d.mts +53 -0
  53. package/dist/events/index.mjs +51 -0
  54. package/dist/events/transports/redis-stream-entry.d.mts +2 -0
  55. package/dist/events/transports/redis-stream-entry.mjs +177 -0
  56. package/dist/events/transports/redis.d.mts +76 -0
  57. package/dist/events/transports/redis.mjs +124 -0
  58. package/dist/externalPaths-SyPF2tgK.d.mts +50 -0
  59. package/dist/factory/index.d.mts +63 -0
  60. package/dist/factory/index.mjs +3 -0
  61. package/dist/fastifyAdapter-C8DlE0YH.d.mts +216 -0
  62. package/dist/fields-Bi_AVKSo.d.mts +109 -0
  63. package/dist/fields-CTd_CrKr.mjs +114 -0
  64. package/dist/hooks/index.d.mts +4 -0
  65. package/dist/hooks/index.mjs +3 -0
  66. package/dist/idempotency/index.d.mts +96 -0
  67. package/dist/idempotency/index.mjs +319 -0
  68. package/dist/idempotency/mongodb.d.mts +2 -0
  69. package/dist/idempotency/mongodb.mjs +114 -0
  70. package/dist/idempotency/redis.d.mts +2 -0
  71. package/dist/idempotency/redis.mjs +103 -0
  72. package/dist/index.d.mts +260 -0
  73. package/dist/index.mjs +104 -0
  74. package/dist/integrations/event-gateway.d.mts +46 -0
  75. package/dist/integrations/event-gateway.mjs +43 -0
  76. package/dist/integrations/index.d.mts +5 -0
  77. package/dist/integrations/index.mjs +1 -0
  78. package/dist/integrations/jobs.d.mts +103 -0
  79. package/dist/integrations/jobs.mjs +123 -0
  80. package/dist/integrations/streamline.d.mts +60 -0
  81. package/dist/integrations/streamline.mjs +125 -0
  82. package/dist/integrations/websocket.d.mts +82 -0
  83. package/dist/integrations/websocket.mjs +288 -0
  84. package/dist/interface-CSNjltAc.d.mts +77 -0
  85. package/dist/interface-DTbsvIWe.d.mts +54 -0
  86. package/dist/interface-e9XfSsUV.d.mts +1097 -0
  87. package/dist/introspectionPlugin-B3JkrjwU.mjs +53 -0
  88. package/dist/keys-DhqDRxv3.mjs +42 -0
  89. package/dist/logger-ByrvQWZO.mjs +78 -0
  90. package/dist/memory-B2v7KrCB.mjs +143 -0
  91. package/dist/migrations/index.d.mts +156 -0
  92. package/dist/migrations/index.mjs +260 -0
  93. package/dist/mongodb-ClykrfGo.d.mts +118 -0
  94. package/dist/mongodb-DNKEExbf.mjs +93 -0
  95. package/dist/mongodb-Dg8O_gvd.d.mts +71 -0
  96. package/dist/openapi-9nB_kiuR.mjs +525 -0
  97. package/dist/org/index.d.mts +68 -0
  98. package/dist/org/index.mjs +513 -0
  99. package/dist/org/types.d.mts +82 -0
  100. package/dist/org/types.mjs +1 -0
  101. package/dist/permissions/index.d.mts +278 -0
  102. package/dist/permissions/index.mjs +579 -0
  103. package/dist/plugins/index.d.mts +172 -0
  104. package/dist/plugins/index.mjs +522 -0
  105. package/dist/plugins/response-cache.d.mts +87 -0
  106. package/dist/plugins/response-cache.mjs +283 -0
  107. package/dist/plugins/tracing-entry.d.mts +2 -0
  108. package/dist/plugins/tracing-entry.mjs +185 -0
  109. package/dist/pluralize-CM-jZg7p.mjs +86 -0
  110. package/dist/policies/{index.d.ts → index.d.mts} +204 -170
  111. package/dist/policies/index.mjs +321 -0
  112. package/dist/presets/{index.d.ts → index.d.mts} +62 -131
  113. package/dist/presets/index.mjs +143 -0
  114. package/dist/presets/multiTenant.d.mts +24 -0
  115. package/dist/presets/multiTenant.mjs +113 -0
  116. package/dist/presets-BTeYbw7h.d.mts +57 -0
  117. package/dist/presets-CeFtfDR8.mjs +119 -0
  118. package/dist/prisma-C3iornoK.d.mts +274 -0
  119. package/dist/prisma-DJbMt3yf.mjs +627 -0
  120. package/dist/queryCachePlugin-B6R0d4av.mjs +138 -0
  121. package/dist/queryCachePlugin-Q6SYuHZ6.d.mts +71 -0
  122. package/dist/redis-UwjEp8Ea.d.mts +49 -0
  123. package/dist/redis-stream-CBg0upHI.d.mts +103 -0
  124. package/dist/registry/index.d.mts +11 -0
  125. package/dist/registry/index.mjs +4 -0
  126. package/dist/requestContext-xi6OKBL-.mjs +55 -0
  127. package/dist/schemaConverter-Dtg0Kt9T.mjs +98 -0
  128. package/dist/schemas/index.d.mts +63 -0
  129. package/dist/schemas/index.mjs +82 -0
  130. package/dist/scope/index.d.mts +21 -0
  131. package/dist/scope/index.mjs +65 -0
  132. package/dist/sessionManager-D_iEHjQl.d.mts +186 -0
  133. package/dist/sse-DkqQ1uxb.mjs +123 -0
  134. package/dist/testing/index.d.mts +907 -0
  135. package/dist/testing/index.mjs +1976 -0
  136. package/dist/tracing-8CEbhF0w.d.mts +70 -0
  137. package/dist/typeGuards-DwxA1t_L.mjs +9 -0
  138. package/dist/types/index.d.mts +946 -0
  139. package/dist/types/index.mjs +14 -0
  140. package/dist/types-B0dhNrnd.d.mts +445 -0
  141. package/dist/types-Beqn1Un7.mjs +38 -0
  142. package/dist/types-DelU6kln.mjs +25 -0
  143. package/dist/types-RLkFVgaw.d.mts +101 -0
  144. package/dist/utils/index.d.mts +747 -0
  145. package/dist/utils/index.mjs +6 -0
  146. package/package.json +194 -68
  147. package/dist/BaseController-DVAiHxEQ.d.ts +0 -233
  148. package/dist/adapters/index.d.ts +0 -237
  149. package/dist/adapters/index.js +0 -668
  150. package/dist/arcCorePlugin-CsShQdyP.d.ts +0 -273
  151. package/dist/audit/index.d.ts +0 -195
  152. package/dist/audit/index.js +0 -319
  153. package/dist/auth/index.d.ts +0 -47
  154. package/dist/auth/index.js +0 -174
  155. package/dist/cli/commands/docs.d.ts +0 -11
  156. package/dist/cli/commands/docs.js +0 -474
  157. package/dist/cli/commands/generate.js +0 -334
  158. package/dist/cli/commands/introspect.d.ts +0 -8
  159. package/dist/cli/commands/introspect.js +0 -338
  160. package/dist/cli/index.d.ts +0 -4
  161. package/dist/cli/index.js +0 -3269
  162. package/dist/core/index.d.ts +0 -220
  163. package/dist/core/index.js +0 -2786
  164. package/dist/createApp-Ce9wl8W9.d.ts +0 -77
  165. package/dist/docs/index.d.ts +0 -166
  166. package/dist/docs/index.js +0 -658
  167. package/dist/errors-8WIxGS_6.d.ts +0 -122
  168. package/dist/events/index.d.ts +0 -117
  169. package/dist/events/index.js +0 -89
  170. package/dist/factory/index.d.ts +0 -38
  171. package/dist/factory/index.js +0 -1652
  172. package/dist/hooks/index.d.ts +0 -4
  173. package/dist/hooks/index.js +0 -199
  174. package/dist/idempotency/index.d.ts +0 -323
  175. package/dist/idempotency/index.js +0 -500
  176. package/dist/index-B4t03KQ0.d.ts +0 -1366
  177. package/dist/index.d.ts +0 -135
  178. package/dist/index.js +0 -4756
  179. package/dist/migrations/index.d.ts +0 -185
  180. package/dist/migrations/index.js +0 -274
  181. package/dist/org/index.d.ts +0 -129
  182. package/dist/org/index.js +0 -220
  183. package/dist/permissions/index.d.ts +0 -144
  184. package/dist/permissions/index.js +0 -103
  185. package/dist/plugins/index.d.ts +0 -46
  186. package/dist/plugins/index.js +0 -1069
  187. package/dist/policies/index.js +0 -196
  188. package/dist/presets/index.js +0 -384
  189. package/dist/presets/multiTenant.d.ts +0 -39
  190. package/dist/presets/multiTenant.js +0 -112
  191. package/dist/registry/index.d.ts +0 -16
  192. package/dist/registry/index.js +0 -253
  193. package/dist/testing/index.d.ts +0 -618
  194. package/dist/testing/index.js +0 -48020
  195. package/dist/types/index.d.ts +0 -4
  196. package/dist/types/index.js +0 -8
  197. package/dist/types-B99TBmFV.d.ts +0 -76
  198. package/dist/types-BvckRbs2.d.ts +0 -143
  199. package/dist/utils/index.d.ts +0 -679
  200. package/dist/utils/index.js +0 -931
@@ -1,4 +0,0 @@
1
- export { ac as HookContext, ad as HookHandler, aI as HookOperation, aH as HookPhase, aJ as HookRegistration, H as HookSystem, aK as HookSystemOptions, aC as afterCreate, aG as afterDelete, aE as afterUpdate, aB as beforeCreate, aF as beforeDelete, aD as beforeUpdate, aA as createHookSystem, ab as hookSystem } from '../index-B4t03KQ0.js';
2
- import 'mongoose';
3
- import 'fastify';
4
- import '../types-B99TBmFV.js';
@@ -1,199 +0,0 @@
1
- // src/hooks/HookSystem.ts
2
- var HookSystem = class {
3
- hooks;
4
- logger;
5
- constructor(options) {
6
- this.hooks = /* @__PURE__ */ new Map();
7
- this.logger = options?.logger ?? { error: (...args) => console.error(...args) };
8
- }
9
- /**
10
- * Generate hook key
11
- */
12
- getKey(resource, operation, phase) {
13
- return `${resource}:${operation}:${phase}`;
14
- }
15
- /**
16
- * Register a hook
17
- * Supports both object parameter and positional arguments
18
- */
19
- register(resourceOrOptions, operation, phase, handler, priority = 10) {
20
- let resource;
21
- let finalOperation;
22
- let finalPhase;
23
- let finalHandler;
24
- let finalPriority;
25
- if (typeof resourceOrOptions === "object") {
26
- resource = resourceOrOptions.resource;
27
- finalOperation = resourceOrOptions.operation;
28
- finalPhase = resourceOrOptions.phase;
29
- finalHandler = resourceOrOptions.handler;
30
- finalPriority = resourceOrOptions.priority ?? 10;
31
- } else {
32
- resource = resourceOrOptions;
33
- finalOperation = operation;
34
- finalPhase = phase;
35
- finalHandler = handler;
36
- finalPriority = priority;
37
- }
38
- const key = this.getKey(resource, finalOperation, finalPhase);
39
- if (!this.hooks.has(key)) {
40
- this.hooks.set(key, []);
41
- }
42
- const registration = {
43
- resource,
44
- operation: finalOperation,
45
- phase: finalPhase,
46
- handler: finalHandler,
47
- priority: finalPriority
48
- };
49
- const hooks = this.hooks.get(key);
50
- hooks.push(registration);
51
- hooks.sort((a, b) => a.priority - b.priority);
52
- return () => {
53
- const idx = hooks.indexOf(registration);
54
- if (idx !== -1) {
55
- hooks.splice(idx, 1);
56
- }
57
- };
58
- }
59
- /**
60
- * Register before hook
61
- */
62
- before(resource, operation, handler, priority = 10) {
63
- return this.register(resource, operation, "before", handler, priority);
64
- }
65
- /**
66
- * Register after hook
67
- */
68
- after(resource, operation, handler, priority = 10) {
69
- return this.register(resource, operation, "after", handler, priority);
70
- }
71
- /**
72
- * Execute hooks for a given context
73
- */
74
- async execute(ctx) {
75
- const key = this.getKey(ctx.resource, ctx.operation, ctx.phase);
76
- const hooks = this.hooks.get(key) ?? [];
77
- const wildcardKey = this.getKey("*", ctx.operation, ctx.phase);
78
- const wildcardHooks = this.hooks.get(wildcardKey) ?? [];
79
- const allHooks = [...wildcardHooks, ...hooks];
80
- allHooks.sort((a, b) => a.priority - b.priority);
81
- let result = ctx.data;
82
- for (const hook of allHooks) {
83
- const handlerContext = {
84
- resource: ctx.resource,
85
- operation: ctx.operation,
86
- phase: ctx.phase,
87
- data: result,
88
- result: ctx.result,
89
- user: ctx.user,
90
- context: ctx.context,
91
- meta: ctx.meta
92
- };
93
- const hookResult = await hook.handler(handlerContext);
94
- if (hookResult !== void 0 && hookResult !== null) {
95
- result = hookResult;
96
- }
97
- }
98
- return result;
99
- }
100
- /**
101
- * Execute before hooks
102
- */
103
- async executeBefore(resource, operation, data, options) {
104
- const result = await this.execute({
105
- resource,
106
- operation,
107
- phase: "before",
108
- data,
109
- user: options?.user,
110
- context: options?.context,
111
- meta: options?.meta
112
- });
113
- return result ?? data;
114
- }
115
- /**
116
- * Execute after hooks
117
- * Errors in after hooks are logged but don't fail the request
118
- */
119
- async executeAfter(resource, operation, result, options) {
120
- try {
121
- await this.execute({
122
- resource,
123
- operation,
124
- phase: "after",
125
- result,
126
- user: options?.user,
127
- context: options?.context,
128
- meta: options?.meta
129
- });
130
- } catch (error) {
131
- this.logger.error(
132
- `[HookSystem] Error in after hook for ${resource}:${operation}:`,
133
- error
134
- );
135
- }
136
- }
137
- /**
138
- * Get all registered hooks
139
- */
140
- getAll() {
141
- const all = [];
142
- for (const hooks of this.hooks.values()) {
143
- all.push(...hooks);
144
- }
145
- return all;
146
- }
147
- /**
148
- * Get hooks for a specific resource
149
- */
150
- getForResource(resource) {
151
- const all = [];
152
- for (const [key, hooks] of this.hooks.entries()) {
153
- if (key.startsWith(`${resource}:`)) {
154
- all.push(...hooks);
155
- }
156
- }
157
- return all;
158
- }
159
- /**
160
- * Clear all hooks
161
- */
162
- clear() {
163
- this.hooks.clear();
164
- }
165
- /**
166
- * Clear hooks for a specific resource
167
- */
168
- clearResource(resource) {
169
- for (const key of this.hooks.keys()) {
170
- if (key.startsWith(`${resource}:`)) {
171
- this.hooks.delete(key);
172
- }
173
- }
174
- }
175
- };
176
- function createHookSystem(options) {
177
- return new HookSystem(options);
178
- }
179
- var hookSystem = new HookSystem();
180
- function beforeCreate(resource, handler, priority = 10) {
181
- return hookSystem.before(resource, "create", handler, priority);
182
- }
183
- function afterCreate(resource, handler, priority = 10) {
184
- return hookSystem.after(resource, "create", handler, priority);
185
- }
186
- function beforeUpdate(resource, handler, priority = 10) {
187
- return hookSystem.before(resource, "update", handler, priority);
188
- }
189
- function afterUpdate(resource, handler, priority = 10) {
190
- return hookSystem.after(resource, "update", handler, priority);
191
- }
192
- function beforeDelete(resource, handler, priority = 10) {
193
- return hookSystem.before(resource, "delete", handler, priority);
194
- }
195
- function afterDelete(resource, handler, priority = 10) {
196
- return hookSystem.after(resource, "delete", handler, priority);
197
- }
198
-
199
- export { HookSystem, afterCreate, afterDelete, afterUpdate, beforeCreate, beforeDelete, beforeUpdate, createHookSystem, hookSystem };
@@ -1,323 +0,0 @@
1
- import { FastifyPluginAsync } from 'fastify';
2
-
3
- /**
4
- * Idempotency Store Interface
5
- *
6
- * Defines the contract for idempotency key storage backends.
7
- * Implement this interface for custom stores (Redis, DynamoDB, etc.)
8
- */
9
- interface IdempotencyResult {
10
- /** The idempotency key */
11
- key: string;
12
- /** HTTP status code of the cached response */
13
- statusCode: number;
14
- /** Response headers to replay */
15
- headers: Record<string, string>;
16
- /** Response body */
17
- body: unknown;
18
- /** When this entry was created */
19
- createdAt: Date;
20
- /** When this entry expires */
21
- expiresAt: Date;
22
- }
23
- interface IdempotencyLock {
24
- /** The idempotency key being locked */
25
- key: string;
26
- /** Request ID that holds the lock */
27
- requestId: string;
28
- /** When the lock was acquired */
29
- lockedAt: Date;
30
- /** When the lock expires (auto-release) */
31
- expiresAt: Date;
32
- }
33
- interface IdempotencyStore {
34
- /** Store name for logging */
35
- readonly name: string;
36
- /**
37
- * Get a cached result for an idempotency key
38
- * Returns undefined if not found or expired
39
- */
40
- get(key: string): Promise<IdempotencyResult | undefined>;
41
- /**
42
- * Store a result for an idempotency key
43
- * TTL is handled by the store implementation
44
- */
45
- set(key: string, result: Omit<IdempotencyResult, 'key'>): Promise<void>;
46
- /**
47
- * Try to acquire a lock for processing a key
48
- * Returns true if lock acquired, false if already locked
49
- * Used to prevent concurrent processing of the same key
50
- */
51
- tryLock(key: string, requestId: string, ttlMs: number): Promise<boolean>;
52
- /**
53
- * Release a lock after processing complete
54
- */
55
- unlock(key: string, requestId: string): Promise<void>;
56
- /**
57
- * Check if a key is currently locked
58
- */
59
- isLocked(key: string): Promise<boolean>;
60
- /**
61
- * Delete a cached result (for manual invalidation)
62
- */
63
- delete(key: string): Promise<void>;
64
- /**
65
- * Close the store (cleanup connections)
66
- */
67
- close?(): Promise<void>;
68
- }
69
- /**
70
- * Helper to create a result object
71
- */
72
- declare function createIdempotencyResult(statusCode: number, body: unknown, headers: Record<string, string>, ttlMs: number): Omit<IdempotencyResult, 'key'>;
73
-
74
- /**
75
- * Idempotency Plugin
76
- *
77
- * Duplicate request protection for mutating operations.
78
- * Uses idempotency keys to ensure safe retries.
79
- *
80
- * @example
81
- * import { idempotencyPlugin } from '@classytic/arc/idempotency';
82
- *
83
- * await fastify.register(idempotencyPlugin, {
84
- * enabled: true,
85
- * headerName: 'idempotency-key',
86
- * ttlMs: 86400000, // 24 hours
87
- * });
88
- *
89
- * // Client sends:
90
- * // POST /api/orders
91
- * // Idempotency-Key: order-123-abc
92
- *
93
- * // If same key sent again within TTL, returns cached response
94
- */
95
-
96
- interface IdempotencyPluginOptions {
97
- /** Enable idempotency (default: false) */
98
- enabled?: boolean;
99
- /** Header name for idempotency key (default: 'idempotency-key') */
100
- headerName?: string;
101
- /** TTL for cached responses in ms (default: 86400000 = 24h) */
102
- ttlMs?: number;
103
- /** Lock timeout in ms (default: 30000 = 30s) */
104
- lockTimeoutMs?: number;
105
- /** HTTP methods to apply idempotency to (default: ['POST', 'PUT', 'PATCH']) */
106
- methods?: string[];
107
- /** URL patterns to include (regex). If set, only matching URLs use idempotency */
108
- include?: RegExp[];
109
- /** URL patterns to exclude (regex). Excluded patterns take precedence */
110
- exclude?: RegExp[];
111
- /** Custom store (default: MemoryIdempotencyStore) */
112
- store?: IdempotencyStore;
113
- /** Retry-After header value in seconds when request is in-flight (default: 1) */
114
- retryAfterSeconds?: number;
115
- }
116
- declare module 'fastify' {
117
- interface FastifyRequest {
118
- /** The idempotency key for this request (if present) */
119
- idempotencyKey?: string;
120
- /** Whether this response was replayed from cache */
121
- idempotencyReplayed?: boolean;
122
- }
123
- interface FastifyInstance {
124
- /** Idempotency utilities */
125
- idempotency: {
126
- /** Manually invalidate an idempotency key */
127
- invalidate: (key: string) => Promise<void>;
128
- /** Check if a key has a cached response */
129
- has: (key: string) => Promise<boolean>;
130
- };
131
- }
132
- }
133
- declare const idempotencyPlugin: FastifyPluginAsync<IdempotencyPluginOptions>;
134
- declare const _default: FastifyPluginAsync<IdempotencyPluginOptions>;
135
-
136
- /**
137
- * In-Memory Idempotency Store
138
- *
139
- * Default store for development and small deployments.
140
- * NOT suitable for multi-instance deployments - use Redis or similar.
141
- *
142
- * Features:
143
- * - Automatic TTL expiration
144
- * - Lock support for concurrent request handling
145
- * - Periodic cleanup of expired entries
146
- */
147
-
148
- interface MemoryIdempotencyStoreOptions {
149
- /** Default TTL in milliseconds (default: 86400000 = 24h) */
150
- ttlMs?: number;
151
- /** Cleanup interval in milliseconds (default: 60000 = 1 min) */
152
- cleanupIntervalMs?: number;
153
- /** Maximum entries before oldest are evicted (default: 10000) */
154
- maxEntries?: number;
155
- }
156
- declare class MemoryIdempotencyStore implements IdempotencyStore {
157
- readonly name = "memory";
158
- private results;
159
- private locks;
160
- private ttlMs;
161
- private maxEntries;
162
- private cleanupInterval;
163
- constructor(options?: MemoryIdempotencyStoreOptions);
164
- get(key: string): Promise<IdempotencyResult | undefined>;
165
- set(key: string, result: Omit<IdempotencyResult, 'key'>): Promise<void>;
166
- tryLock(key: string, requestId: string, ttlMs: number): Promise<boolean>;
167
- unlock(key: string, requestId: string): Promise<void>;
168
- isLocked(key: string): Promise<boolean>;
169
- delete(key: string): Promise<void>;
170
- close(): Promise<void>;
171
- /**
172
- * Get current stats (for debugging/monitoring)
173
- */
174
- getStats(): {
175
- results: number;
176
- locks: number;
177
- };
178
- /**
179
- * Remove expired entries
180
- */
181
- private cleanup;
182
- /**
183
- * Evict oldest entries when at capacity
184
- */
185
- private evictOldest;
186
- }
187
-
188
- /**
189
- * Redis Idempotency Store
190
- *
191
- * Durable idempotency store using Redis.
192
- * Suitable for multi-instance deployments.
193
- *
194
- * @example
195
- * import { createClient } from 'redis';
196
- * import { RedisIdempotencyStore } from '@classytic/arc/idempotency';
197
- *
198
- * const redis = createClient({ url: process.env.REDIS_URL });
199
- * await redis.connect();
200
- *
201
- * await fastify.register(idempotencyPlugin, {
202
- * store: new RedisIdempotencyStore({ client: redis }),
203
- * });
204
- */
205
-
206
- interface RedisClient {
207
- get(key: string): Promise<string | null>;
208
- set(key: string, value: string, options?: {
209
- EX?: number;
210
- NX?: boolean;
211
- }): Promise<string | null>;
212
- del(key: string | string[]): Promise<number>;
213
- exists(key: string | string[]): Promise<number>;
214
- quit?(): Promise<string>;
215
- disconnect?(): Promise<void>;
216
- }
217
- interface RedisIdempotencyStoreOptions {
218
- /** Redis client instance */
219
- client: RedisClient;
220
- /** Key prefix (default: 'idem:') */
221
- prefix?: string;
222
- /** Lock key prefix (default: 'idem:lock:') */
223
- lockPrefix?: string;
224
- /** Default TTL in ms (default: 86400000 = 24 hours) */
225
- ttlMs?: number;
226
- }
227
- declare class RedisIdempotencyStore implements IdempotencyStore {
228
- readonly name = "redis";
229
- private client;
230
- private prefix;
231
- private lockPrefix;
232
- private ttlMs;
233
- constructor(options: RedisIdempotencyStoreOptions);
234
- private resultKey;
235
- private lockKey;
236
- get(key: string): Promise<IdempotencyResult | undefined>;
237
- set(key: string, result: Omit<IdempotencyResult, 'key'>): Promise<void>;
238
- tryLock(key: string, requestId: string, ttlMs: number): Promise<boolean>;
239
- unlock(key: string, requestId: string): Promise<void>;
240
- isLocked(key: string): Promise<boolean>;
241
- delete(key: string): Promise<void>;
242
- close(): Promise<void>;
243
- }
244
-
245
- /**
246
- * MongoDB Idempotency Store
247
- *
248
- * Durable idempotency store using MongoDB.
249
- * Suitable for multi-instance deployments.
250
- *
251
- * @example
252
- * import mongoose from 'mongoose';
253
- * import { MongoIdempotencyStore } from '@classytic/arc/idempotency';
254
- *
255
- * await fastify.register(idempotencyPlugin, {
256
- * store: new MongoIdempotencyStore({
257
- * connection: mongoose.connection,
258
- * collection: 'idempotency_keys',
259
- * }),
260
- * });
261
- */
262
-
263
- interface MongoConnection {
264
- db: {
265
- collection(name: string): MongoCollection;
266
- };
267
- }
268
- interface MongoCollection {
269
- findOne(filter: object): Promise<IdempotencyDocument | null>;
270
- insertOne(doc: object): Promise<{
271
- acknowledged: boolean;
272
- }>;
273
- updateOne(filter: object, update: object, options?: object): Promise<{
274
- acknowledged: boolean;
275
- }>;
276
- deleteOne(filter: object): Promise<{
277
- deletedCount: number;
278
- }>;
279
- createIndex(spec: object, options?: object): Promise<string>;
280
- }
281
- interface IdempotencyDocument {
282
- _id: string;
283
- result?: {
284
- statusCode: number;
285
- headers: Record<string, string>;
286
- body: unknown;
287
- };
288
- lock?: {
289
- requestId: string;
290
- expiresAt: Date;
291
- };
292
- createdAt: Date;
293
- expiresAt: Date;
294
- }
295
- interface MongoIdempotencyStoreOptions {
296
- /** Mongoose connection or MongoDB connection object */
297
- connection: MongoConnection;
298
- /** Collection name (default: 'arc_idempotency') */
299
- collection?: string;
300
- /** Create TTL index on startup (default: true) */
301
- createIndex?: boolean;
302
- /** Default TTL in ms (default: 86400000 = 24 hours) */
303
- ttlMs?: number;
304
- }
305
- declare class MongoIdempotencyStore implements IdempotencyStore {
306
- readonly name = "mongodb";
307
- private connection;
308
- private collectionName;
309
- private ttlMs;
310
- private indexCreated;
311
- constructor(options: MongoIdempotencyStoreOptions);
312
- private get collection();
313
- private ensureIndex;
314
- get(key: string): Promise<IdempotencyResult | undefined>;
315
- set(key: string, result: Omit<IdempotencyResult, 'key'>): Promise<void>;
316
- tryLock(key: string, requestId: string, ttlMs: number): Promise<boolean>;
317
- unlock(key: string, requestId: string): Promise<void>;
318
- isLocked(key: string): Promise<boolean>;
319
- delete(key: string): Promise<void>;
320
- close(): Promise<void>;
321
- }
322
-
323
- export { type IdempotencyLock, type IdempotencyPluginOptions, type IdempotencyResult, type IdempotencyStore, MemoryIdempotencyStore, type MemoryIdempotencyStoreOptions, MongoIdempotencyStore, type MongoIdempotencyStoreOptions, type RedisClient, RedisIdempotencyStore, type RedisIdempotencyStoreOptions, createIdempotencyResult, _default as idempotencyPlugin, idempotencyPlugin as idempotencyPluginFn };