@classytic/arc 2.9.1 → 2.10.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.
- package/README.md +19 -90
- package/dist/{BaseController-Vu2yc56T.mjs → BaseController-CbKKIflT.mjs} +8 -44
- package/dist/{ResourceRegistry-Dq3_zBQP.mjs → ResourceRegistry-BPd6NQDm.mjs} +1 -1
- package/dist/adapters/index.d.mts +3 -3
- package/dist/adapters/index.mjs +2 -2
- package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
- package/dist/audit/index.d.mts +38 -3
- package/dist/audit/index.mjs +41 -7
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +5 -5
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/cache/index.d.mts +17 -15
- package/dist/cache/index.mjs +15 -14
- package/dist/{caching-CjybdRwx.mjs → caching-CBpK_SCM.mjs} +8 -3
- package/dist/cli/commands/describe.mjs +1 -1
- package/dist/cli/commands/docs.mjs +2 -2
- package/dist/cli/commands/generate.mjs +1 -1
- package/dist/cli/commands/init.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 -4
- package/dist/{defineResource-C__jkwvs.mjs → core-CcR01lup.mjs} +44 -12
- package/dist/{createActionRouter-DH1YFL9m.mjs → createActionRouter-Bp_5c_2b.mjs} +1 -1
- package/dist/{createApp-CBJUJKGP.mjs → createApp-BuvPma24.mjs} +14 -14
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +2 -2
- package/dist/{elevation-DxQ6ACbt.mjs → elevation-C7hgL_aI.mjs} +2 -2
- package/dist/{errorHandler-CZDW4EXS.mjs → errorHandler-Bb49BvPD.mjs} +1 -1
- package/dist/{errorHandler-DixGcttC.d.mts → errorHandler-DRQ3EqfL.d.mts} +1 -1
- package/dist/{eventPlugin-BxvaCIZF.d.mts → eventPlugin-CxWgpd6K.d.mts} +1 -1
- package/dist/{eventPlugin-Dl7MoVWH.mjs → eventPlugin-DCUjuiQT.mjs} +1 -1
- package/dist/events/index.d.mts +8 -5
- package/dist/events/index.mjs +34 -17
- 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/{types-DZi1aYhm.d.mts → fields-Lo1VUDpt.d.mts} +121 -1
- package/dist/{filesUpload-q8oHt--L.mjs → filesUpload-t21LS-py.mjs} +2 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +7 -4
- package/dist/idempotency/index.mjs +9 -11
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-Cibkchnx.d.mts → index-8qw4y6ff.d.mts} +2 -2
- package/dist/{index-C-xjcA6F.d.mts → index-ChIw3776.d.mts} +283 -408
- package/dist/{interface-YrWsmKqE.d.mts → index-Cl0uoKd5.d.mts} +1885 -2741
- package/dist/{index-CtGKT0lf.d.mts → index-DStwgFUK.d.mts} +81 -7
- package/dist/index.d.mts +7 -8
- package/dist/index.mjs +11 -12
- 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/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-D218ikEo.d.mts +77 -0
- package/dist/{memory-BFAYkf8H.mjs → memory-B5Amv9A1.mjs} +23 -8
- package/dist/{openapi-CXuTG1M9.mjs → openapi-B5F8AddX.mjs} +2 -2
- package/dist/org/index.d.mts +2 -2
- package/dist/permissions/index.d.mts +3 -4
- package/dist/permissions/index.mjs +5 -5
- package/dist/{permissions-oNZawnkR.mjs → permissions-Dk6mshja.mjs} +315 -397
- package/dist/plugins/index.d.mts +4 -4
- package/dist/plugins/index.mjs +12 -14
- package/dist/plugins/response-cache.mjs +1 -1
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/filesUpload.d.mts +3 -3
- package/dist/presets/filesUpload.mjs +1 -1
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +2 -2
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +1 -1
- package/dist/presets/search.d.mts +91 -4
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-hM4WhNWY.mjs → presets-fLJVXdVn.mjs} +1 -1
- package/dist/{queryCachePlugin-CnTZZTC5.d.mts → queryCachePlugin-BKbWjgDG.d.mts} +1 -1
- package/dist/{queryCachePlugin-DbUVroUG.mjs → queryCachePlugin-DQCEfJis.mjs} +8 -8
- package/dist/{queryParser-Cs-6SHQK.mjs → queryParser-DBqBB6AC.mjs} +1 -1
- package/dist/{redis-MXLp1oOf.d.mts → redis-DqyeggCa.d.mts} +1 -1
- package/dist/{redis-stream-Bz-4q96t.d.mts → redis-stream-CakIQmwR.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/registry/index.mjs +2 -2
- package/dist/{resourceToTools-C3cWymnW.mjs → resourceToTools-BElv3xPT.mjs} +3 -3
- package/dist/scope/index.d.mts +1 -1
- package/dist/scope/index.mjs +2 -2
- package/dist/{sse-CJpt7LGI.mjs → sse-yBCgOLGu.mjs} +1 -1
- package/dist/testing/index.d.mts +6 -5
- package/dist/testing/index.mjs +8 -10
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +4 -4
- package/dist/types/index.mjs +1 -31
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-CoSzA-s-.d.mts → types-Btdda02s.d.mts} +1 -1
- package/dist/{types-CunEX4UX.d.mts → types-Co8k3NyS.d.mts} +9 -9
- package/dist/types-Csi3FLfq.mjs +27 -0
- package/dist/utils/index.d.mts +207 -3
- package/dist/utils/index.mjs +3 -4
- package/dist/{utils-B7FuRr9w.mjs → utils-B2fNOD_i.mjs} +285 -2
- package/dist/{versioning-Cm8qoFDg.mjs → versioning-C2U_bLY0.mjs} +3 -5
- package/package.json +15 -18
- package/skills/arc/SKILL.md +7 -11
- package/skills/arc/references/production.md +0 -41
- package/dist/circuitBreaker-CvXkjfrW.d.mts +0 -206
- package/dist/circuitBreaker-l18oRgL5.mjs +0 -284
- package/dist/core-DNncu0xF.mjs +0 -34
- package/dist/dynamic/index.d.mts +0 -93
- package/dist/dynamic/index.mjs +0 -122
- package/dist/fields-BC7zcmI9.d.mts +0 -121
- package/dist/interface-DplgQO2e.d.mts +0 -54
- package/dist/policies/index.d.mts +0 -425
- package/dist/policies/index.mjs +0 -318
- package/dist/rpc/index.d.mts +0 -90
- package/dist/rpc/index.mjs +0 -248
- /package/dist/{EventTransport-CqZ8FyM_.d.mts → EventTransport-CUw5NNWe.d.mts} +0 -0
- /package/dist/{HookSystem-BjFu7zf1.mjs → HookSystem-BNYKnrXF.mjs} +0 -0
- /package/dist/{applyPermissionResult-bqGpo9ML.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
- /package/dist/{betterAuthOpenApi--rdY15Ld.mjs → betterAuthOpenApi-BBRVhjQN.mjs} +0 -0
- /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
- /package/dist/{elevation-B6S5csVA.d.mts → elevation-C5SwtkAn.d.mts} +0 -0
- /package/dist/{errors-BI8kEKsO.d.mts → errors-CCSsMpXE.d.mts} +0 -0
- /package/dist/{errors-CqWnSqM-.mjs → errors-D5c-5BJL.mjs} +0 -0
- /package/dist/{externalPaths-Bapitwvd.d.mts → externalPaths-BQ8QijNH.d.mts} +0 -0
- /package/dist/{fields-CU6FlaDV.mjs → fields-bxkeltzz.mjs} +0 -0
- /package/dist/{interface-B-pe8fhj.d.mts → interface-CSbZdv_3.d.mts} +0 -0
- /package/dist/{loadResources-Bksk8ydA.mjs → loadResources-BAzJItAJ.mjs} +0 -0
- /package/dist/{logger-CDjpjySd.mjs → logger-DLg8-Ueg.mjs} +0 -0
- /package/dist/{metrics-TuOmguhi.mjs → metrics-DuhiSEZI.mjs} +0 -0
- /package/dist/{pluralize-CWP6MB39.mjs → pluralize-A0tWEl1K.mjs} +0 -0
- /package/dist/{registry-B0Wl7uVV.mjs → registry-B3lRFBWo.mjs} +0 -0
- /package/dist/{replyHelpers-BLojtuvR.mjs → replyHelpers-CXtJDAZ0.mjs} +0 -0
- /package/dist/{requestContext-DYtmNpm5.mjs → requestContext-xHIKedG6.mjs} +0 -0
- /package/dist/{sessionManager-D-oNWHz3.d.mts → sessionManager-BkzVU8h2.d.mts} +0 -0
- /package/dist/{storage-BwGQXUpd.d.mts → storage-CVk_SEn2.d.mts} +0 -0
- /package/dist/{store-helpers-DFiZl5TL.mjs → store-helpers-ZCSMJJAX.mjs} +0 -0
- /package/dist/{tracing-xqXzWeaf.d.mts → tracing-65B51Dw3.d.mts} +0 -0
- /package/dist/{types-ZUu_h0jp.mjs → types-DV9WDfeg.mjs} +0 -0
package/dist/utils/index.d.mts
CHANGED
|
@@ -1,8 +1,212 @@
|
|
|
1
|
-
import {
|
|
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-CvXkjfrW.mjs";
|
|
1
|
+
import { Kt as QueryParserInterface, Wt as ParsedQuery, dn as AnyRecord, rt as OpenApiSchemas } from "../index-Cl0uoKd5.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-CCSsMpXE.mjs";
|
|
4
3
|
import { FastifyInstance, FastifyReply, FastifyRequest, RouteHandlerMethod } from "fastify";
|
|
5
4
|
|
|
5
|
+
//#region src/utils/circuitBreaker.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Circuit Breaker Pattern
|
|
8
|
+
*
|
|
9
|
+
* Wraps external service calls with failure protection.
|
|
10
|
+
* Prevents cascading failures by "opening" the circuit when
|
|
11
|
+
* a service is failing, allowing it time to recover.
|
|
12
|
+
*
|
|
13
|
+
* States:
|
|
14
|
+
* - CLOSED: Normal operation, requests pass through
|
|
15
|
+
* - OPEN: Too many failures, all requests fail fast
|
|
16
|
+
* - HALF_OPEN: Testing if service recovered, limited requests
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* import { CircuitBreaker } from '@classytic/arc/utils';
|
|
20
|
+
*
|
|
21
|
+
* const paymentBreaker = new CircuitBreaker(async (amount) => {
|
|
22
|
+
* return await stripe.charges.create({ amount });
|
|
23
|
+
* }, {
|
|
24
|
+
* failureThreshold: 5,
|
|
25
|
+
* resetTimeout: 30000,
|
|
26
|
+
* timeout: 5000,
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* try {
|
|
30
|
+
* const result = await paymentBreaker.call(100);
|
|
31
|
+
* } catch (error) {
|
|
32
|
+
* // Handle failure or circuit open
|
|
33
|
+
* }
|
|
34
|
+
*/
|
|
35
|
+
declare const CircuitState: {
|
|
36
|
+
readonly CLOSED: "CLOSED";
|
|
37
|
+
readonly OPEN: "OPEN";
|
|
38
|
+
readonly HALF_OPEN: "HALF_OPEN";
|
|
39
|
+
};
|
|
40
|
+
type CircuitState = (typeof CircuitState)[keyof typeof CircuitState];
|
|
41
|
+
interface CircuitBreakerOptions {
|
|
42
|
+
/**
|
|
43
|
+
* Number of failures before opening circuit
|
|
44
|
+
* @default 5
|
|
45
|
+
*/
|
|
46
|
+
failureThreshold?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Time in ms before attempting to close circuit
|
|
49
|
+
* @default 60000 (60 seconds)
|
|
50
|
+
*/
|
|
51
|
+
resetTimeout?: number;
|
|
52
|
+
/**
|
|
53
|
+
* Request timeout in ms
|
|
54
|
+
* @default 10000 (10 seconds)
|
|
55
|
+
*/
|
|
56
|
+
timeout?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Number of successful requests in HALF_OPEN before closing
|
|
59
|
+
* @default 1
|
|
60
|
+
*/
|
|
61
|
+
successThreshold?: number;
|
|
62
|
+
/**
|
|
63
|
+
* Fallback function when circuit is open.
|
|
64
|
+
* Receives the same arguments as the wrapped function.
|
|
65
|
+
*/
|
|
66
|
+
fallback?: (...args: unknown[]) => Promise<unknown>;
|
|
67
|
+
/**
|
|
68
|
+
* Callback when state changes
|
|
69
|
+
*/
|
|
70
|
+
onStateChange?: (from: CircuitState, to: CircuitState) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Callback on error
|
|
73
|
+
*/
|
|
74
|
+
onError?: (error: Error) => void;
|
|
75
|
+
/**
|
|
76
|
+
* Name for logging/monitoring
|
|
77
|
+
*/
|
|
78
|
+
name?: string;
|
|
79
|
+
}
|
|
80
|
+
interface CircuitBreakerStats {
|
|
81
|
+
name?: string;
|
|
82
|
+
state: CircuitState;
|
|
83
|
+
failures: number;
|
|
84
|
+
successes: number;
|
|
85
|
+
totalCalls: number;
|
|
86
|
+
openedAt: number | null;
|
|
87
|
+
lastCallAt: number | null;
|
|
88
|
+
}
|
|
89
|
+
declare class CircuitBreakerError extends Error {
|
|
90
|
+
state: CircuitState;
|
|
91
|
+
constructor(message: string, state: CircuitState);
|
|
92
|
+
}
|
|
93
|
+
declare class CircuitBreaker<T extends (...args: any[]) => Promise<any>> {
|
|
94
|
+
private state;
|
|
95
|
+
private failures;
|
|
96
|
+
private successes;
|
|
97
|
+
private totalCalls;
|
|
98
|
+
private nextAttempt;
|
|
99
|
+
private lastCallAt;
|
|
100
|
+
private openedAt;
|
|
101
|
+
private readonly failureThreshold;
|
|
102
|
+
private readonly resetTimeout;
|
|
103
|
+
private readonly timeout;
|
|
104
|
+
private readonly successThreshold;
|
|
105
|
+
private readonly fallback?;
|
|
106
|
+
private readonly onStateChange?;
|
|
107
|
+
private readonly onError?;
|
|
108
|
+
private readonly name;
|
|
109
|
+
private readonly fn;
|
|
110
|
+
constructor(fn: T, options?: CircuitBreakerOptions);
|
|
111
|
+
/**
|
|
112
|
+
* Call the wrapped function with circuit breaker protection
|
|
113
|
+
*/
|
|
114
|
+
call(...args: Parameters<T>): Promise<ReturnType<T>>;
|
|
115
|
+
/**
|
|
116
|
+
* Execute function with timeout
|
|
117
|
+
*/
|
|
118
|
+
private executeWithTimeout;
|
|
119
|
+
/**
|
|
120
|
+
* Handle successful call
|
|
121
|
+
*/
|
|
122
|
+
private onSuccess;
|
|
123
|
+
/**
|
|
124
|
+
* Handle failed call
|
|
125
|
+
*/
|
|
126
|
+
private onFailure;
|
|
127
|
+
/**
|
|
128
|
+
* Change circuit state
|
|
129
|
+
*/
|
|
130
|
+
private setState;
|
|
131
|
+
/**
|
|
132
|
+
* Manually open the circuit
|
|
133
|
+
*/
|
|
134
|
+
open(): void;
|
|
135
|
+
/**
|
|
136
|
+
* Manually close the circuit
|
|
137
|
+
*/
|
|
138
|
+
close(): void;
|
|
139
|
+
/**
|
|
140
|
+
* Get current statistics
|
|
141
|
+
*/
|
|
142
|
+
getStats(): CircuitBreakerStats;
|
|
143
|
+
/**
|
|
144
|
+
* Get current state
|
|
145
|
+
*/
|
|
146
|
+
getState(): CircuitState;
|
|
147
|
+
/**
|
|
148
|
+
* Check if circuit is open
|
|
149
|
+
*/
|
|
150
|
+
isOpen(): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Check if circuit is closed
|
|
153
|
+
*/
|
|
154
|
+
isClosed(): boolean;
|
|
155
|
+
/**
|
|
156
|
+
* Reset statistics
|
|
157
|
+
*/
|
|
158
|
+
reset(): void;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Create a circuit breaker with sensible defaults
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* const emailBreaker = createCircuitBreaker(
|
|
165
|
+
* async (to, subject, body) => sendEmail(to, subject, body),
|
|
166
|
+
* { name: 'email-service' }
|
|
167
|
+
* );
|
|
168
|
+
*/
|
|
169
|
+
declare function createCircuitBreaker<T extends (...args: any[]) => Promise<any>>(fn: T, options?: CircuitBreakerOptions): CircuitBreaker<T>;
|
|
170
|
+
/**
|
|
171
|
+
* Circuit breaker registry for managing multiple breakers
|
|
172
|
+
*/
|
|
173
|
+
declare class CircuitBreakerRegistry {
|
|
174
|
+
private breakers;
|
|
175
|
+
/**
|
|
176
|
+
* Register a circuit breaker
|
|
177
|
+
*/
|
|
178
|
+
register<T extends (...args: any[]) => Promise<any>>(name: string, fn: T, options?: Omit<CircuitBreakerOptions, "name">): CircuitBreaker<T>;
|
|
179
|
+
/**
|
|
180
|
+
* Get a circuit breaker by name
|
|
181
|
+
*/
|
|
182
|
+
get(name: string): CircuitBreaker<any> | undefined;
|
|
183
|
+
/**
|
|
184
|
+
* Get all breakers
|
|
185
|
+
*/
|
|
186
|
+
getAll(): Map<string, CircuitBreaker<any>>;
|
|
187
|
+
/**
|
|
188
|
+
* Get statistics for all breakers
|
|
189
|
+
*/
|
|
190
|
+
getAllStats(): Record<string, CircuitBreakerStats>;
|
|
191
|
+
/**
|
|
192
|
+
* Reset all breakers
|
|
193
|
+
*/
|
|
194
|
+
resetAll(): void;
|
|
195
|
+
/**
|
|
196
|
+
* Open all breakers
|
|
197
|
+
*/
|
|
198
|
+
openAll(): void;
|
|
199
|
+
/**
|
|
200
|
+
* Close all breakers
|
|
201
|
+
*/
|
|
202
|
+
closeAll(): void;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Create a new CircuitBreakerRegistry instance.
|
|
206
|
+
* Use this instead of a global singleton — attach to fastify.arc or pass explicitly.
|
|
207
|
+
*/
|
|
208
|
+
declare function createCircuitBreakerRegistry(): CircuitBreakerRegistry;
|
|
209
|
+
//#endregion
|
|
6
210
|
//#region src/utils/compensation.d.ts
|
|
7
211
|
/**
|
|
8
212
|
* Compensating Transaction — In-Process Rollback Primitive
|
package/dist/utils/index.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
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-
|
|
2
|
-
import { n as createQueryParser, t as ArcQueryParser } from "../queryParser-
|
|
3
|
-
import {
|
|
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-B7FuRr9w.mjs";
|
|
1
|
+
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-D5c-5BJL.mjs";
|
|
2
|
+
import { n as createQueryParser, t as ArcQueryParser } from "../queryParser-DBqBB6AC.mjs";
|
|
3
|
+
import { C as createCircuitBreakerRegistry, S as createCircuitBreaker, _ as withCompensation, a as getListQueryParams, b as CircuitBreakerRegistry, 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, v as CircuitBreaker, x as CircuitState, y as CircuitBreakerError } from "../utils-B2fNOD_i.mjs";
|
|
5
4
|
import { a as toJsonSchema, i as isZodSchema, n as convertRouteSchema, r as isJsonSchema, t as convertOpenApiSchemas } from "../schemaConverter-BxFDdtXu.mjs";
|
|
6
5
|
import { t as hasEvents } from "../typeGuards-Cj5Rgvlg.mjs";
|
|
7
6
|
export { ArcError, ArcQueryParser, CircuitBreaker, CircuitBreakerError, CircuitBreakerRegistry, CircuitState, ConflictError, ForbiddenError, NotFoundError, OrgAccessDeniedError, OrgRequiredError, RateLimitError, ServiceUnavailableError, 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 };
|
|
@@ -1,4 +1,287 @@
|
|
|
1
|
-
import { t as ArcError } from "./errors-
|
|
1
|
+
import { t as ArcError } from "./errors-D5c-5BJL.mjs";
|
|
2
|
+
//#region src/utils/circuitBreaker.ts
|
|
3
|
+
/**
|
|
4
|
+
* Circuit Breaker Pattern
|
|
5
|
+
*
|
|
6
|
+
* Wraps external service calls with failure protection.
|
|
7
|
+
* Prevents cascading failures by "opening" the circuit when
|
|
8
|
+
* a service is failing, allowing it time to recover.
|
|
9
|
+
*
|
|
10
|
+
* States:
|
|
11
|
+
* - CLOSED: Normal operation, requests pass through
|
|
12
|
+
* - OPEN: Too many failures, all requests fail fast
|
|
13
|
+
* - HALF_OPEN: Testing if service recovered, limited requests
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* import { CircuitBreaker } from '@classytic/arc/utils';
|
|
17
|
+
*
|
|
18
|
+
* const paymentBreaker = new CircuitBreaker(async (amount) => {
|
|
19
|
+
* return await stripe.charges.create({ amount });
|
|
20
|
+
* }, {
|
|
21
|
+
* failureThreshold: 5,
|
|
22
|
+
* resetTimeout: 30000,
|
|
23
|
+
* timeout: 5000,
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* try {
|
|
27
|
+
* const result = await paymentBreaker.call(100);
|
|
28
|
+
* } catch (error) {
|
|
29
|
+
* // Handle failure or circuit open
|
|
30
|
+
* }
|
|
31
|
+
*/
|
|
32
|
+
const CircuitState = {
|
|
33
|
+
CLOSED: "CLOSED",
|
|
34
|
+
OPEN: "OPEN",
|
|
35
|
+
HALF_OPEN: "HALF_OPEN"
|
|
36
|
+
};
|
|
37
|
+
var CircuitBreakerError = class extends Error {
|
|
38
|
+
state;
|
|
39
|
+
constructor(message, state) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "CircuitBreakerError";
|
|
42
|
+
this.state = state;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var CircuitBreaker = class {
|
|
46
|
+
state = CircuitState.CLOSED;
|
|
47
|
+
failures = 0;
|
|
48
|
+
successes = 0;
|
|
49
|
+
totalCalls = 0;
|
|
50
|
+
nextAttempt = 0;
|
|
51
|
+
lastCallAt = null;
|
|
52
|
+
openedAt = null;
|
|
53
|
+
failureThreshold;
|
|
54
|
+
resetTimeout;
|
|
55
|
+
timeout;
|
|
56
|
+
successThreshold;
|
|
57
|
+
fallback;
|
|
58
|
+
onStateChange;
|
|
59
|
+
onError;
|
|
60
|
+
name;
|
|
61
|
+
fn;
|
|
62
|
+
constructor(fn, options = {}) {
|
|
63
|
+
this.fn = fn;
|
|
64
|
+
this.failureThreshold = options.failureThreshold ?? 5;
|
|
65
|
+
this.resetTimeout = options.resetTimeout ?? 6e4;
|
|
66
|
+
this.timeout = options.timeout ?? 1e4;
|
|
67
|
+
this.successThreshold = options.successThreshold ?? 1;
|
|
68
|
+
this.fallback = options.fallback;
|
|
69
|
+
this.onStateChange = options.onStateChange;
|
|
70
|
+
this.onError = options.onError;
|
|
71
|
+
this.name = options.name ?? "CircuitBreaker";
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Call the wrapped function with circuit breaker protection
|
|
75
|
+
*/
|
|
76
|
+
async call(...args) {
|
|
77
|
+
this.totalCalls++;
|
|
78
|
+
this.lastCallAt = Date.now();
|
|
79
|
+
if (this.state === CircuitState.OPEN) {
|
|
80
|
+
if (Date.now() < this.nextAttempt) {
|
|
81
|
+
const error = new CircuitBreakerError(`Circuit breaker is OPEN for ${this.name}`, CircuitState.OPEN);
|
|
82
|
+
if (this.fallback) return this.fallback(...args);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
this.setState(CircuitState.HALF_OPEN);
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const result = await this.executeWithTimeout(args);
|
|
89
|
+
this.onSuccess();
|
|
90
|
+
return result;
|
|
91
|
+
} catch (err) {
|
|
92
|
+
this.onFailure(err instanceof Error ? err : new Error(String(err)));
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Execute function with timeout
|
|
98
|
+
*/
|
|
99
|
+
async executeWithTimeout(args) {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
const timeoutId = setTimeout(() => {
|
|
102
|
+
reject(/* @__PURE__ */ new Error(`Request timeout after ${this.timeout}ms`));
|
|
103
|
+
}, this.timeout);
|
|
104
|
+
this.fn(...args).then((result) => {
|
|
105
|
+
clearTimeout(timeoutId);
|
|
106
|
+
resolve(result);
|
|
107
|
+
}).catch((error) => {
|
|
108
|
+
clearTimeout(timeoutId);
|
|
109
|
+
reject(error);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Handle successful call
|
|
115
|
+
*/
|
|
116
|
+
onSuccess() {
|
|
117
|
+
this.failures = 0;
|
|
118
|
+
this.successes++;
|
|
119
|
+
if (this.state === CircuitState.HALF_OPEN) {
|
|
120
|
+
if (this.successes >= this.successThreshold) {
|
|
121
|
+
this.setState(CircuitState.CLOSED);
|
|
122
|
+
this.successes = 0;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Handle failed call
|
|
128
|
+
*/
|
|
129
|
+
onFailure(error) {
|
|
130
|
+
this.failures++;
|
|
131
|
+
this.successes = 0;
|
|
132
|
+
if (this.onError) this.onError(error);
|
|
133
|
+
if (this.state === CircuitState.HALF_OPEN || this.failures >= this.failureThreshold) {
|
|
134
|
+
this.setState(CircuitState.OPEN);
|
|
135
|
+
this.nextAttempt = Date.now() + this.resetTimeout;
|
|
136
|
+
this.openedAt = Date.now();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Change circuit state
|
|
141
|
+
*/
|
|
142
|
+
setState(newState) {
|
|
143
|
+
const oldState = this.state;
|
|
144
|
+
if (oldState !== newState) {
|
|
145
|
+
this.state = newState;
|
|
146
|
+
if (this.onStateChange) this.onStateChange(oldState, newState);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Manually open the circuit
|
|
151
|
+
*/
|
|
152
|
+
open() {
|
|
153
|
+
this.setState(CircuitState.OPEN);
|
|
154
|
+
this.nextAttempt = Date.now() + this.resetTimeout;
|
|
155
|
+
this.openedAt = Date.now();
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Manually close the circuit
|
|
159
|
+
*/
|
|
160
|
+
close() {
|
|
161
|
+
this.failures = 0;
|
|
162
|
+
this.successes = 0;
|
|
163
|
+
this.setState(CircuitState.CLOSED);
|
|
164
|
+
this.openedAt = null;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get current statistics
|
|
168
|
+
*/
|
|
169
|
+
getStats() {
|
|
170
|
+
return {
|
|
171
|
+
name: this.name,
|
|
172
|
+
state: this.state,
|
|
173
|
+
failures: this.failures,
|
|
174
|
+
successes: this.successes,
|
|
175
|
+
totalCalls: this.totalCalls,
|
|
176
|
+
openedAt: this.openedAt,
|
|
177
|
+
lastCallAt: this.lastCallAt
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get current state
|
|
182
|
+
*/
|
|
183
|
+
getState() {
|
|
184
|
+
return this.state;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Check if circuit is open
|
|
188
|
+
*/
|
|
189
|
+
isOpen() {
|
|
190
|
+
return this.state === CircuitState.OPEN;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Check if circuit is closed
|
|
194
|
+
*/
|
|
195
|
+
isClosed() {
|
|
196
|
+
return this.state === CircuitState.CLOSED;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Reset statistics
|
|
200
|
+
*/
|
|
201
|
+
reset() {
|
|
202
|
+
this.failures = 0;
|
|
203
|
+
this.successes = 0;
|
|
204
|
+
this.totalCalls = 0;
|
|
205
|
+
this.lastCallAt = null;
|
|
206
|
+
this.openedAt = null;
|
|
207
|
+
this.setState(CircuitState.CLOSED);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Create a circuit breaker with sensible defaults
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* const emailBreaker = createCircuitBreaker(
|
|
215
|
+
* async (to, subject, body) => sendEmail(to, subject, body),
|
|
216
|
+
* { name: 'email-service' }
|
|
217
|
+
* );
|
|
218
|
+
*/
|
|
219
|
+
function createCircuitBreaker(fn, options) {
|
|
220
|
+
return new CircuitBreaker(fn, options);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Circuit breaker registry for managing multiple breakers
|
|
224
|
+
*/
|
|
225
|
+
var CircuitBreakerRegistry = class {
|
|
226
|
+
breakers = /* @__PURE__ */ new Map();
|
|
227
|
+
/**
|
|
228
|
+
* Register a circuit breaker
|
|
229
|
+
*/
|
|
230
|
+
register(name, fn, options) {
|
|
231
|
+
const breaker = new CircuitBreaker(fn, {
|
|
232
|
+
...options,
|
|
233
|
+
name
|
|
234
|
+
});
|
|
235
|
+
this.breakers.set(name, breaker);
|
|
236
|
+
return breaker;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get a circuit breaker by name
|
|
240
|
+
*/
|
|
241
|
+
get(name) {
|
|
242
|
+
return this.breakers.get(name);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Get all breakers
|
|
246
|
+
*/
|
|
247
|
+
getAll() {
|
|
248
|
+
return this.breakers;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get statistics for all breakers
|
|
252
|
+
*/
|
|
253
|
+
getAllStats() {
|
|
254
|
+
const stats = {};
|
|
255
|
+
for (const [name, breaker] of this.breakers.entries()) stats[name] = breaker.getStats();
|
|
256
|
+
return stats;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Reset all breakers
|
|
260
|
+
*/
|
|
261
|
+
resetAll() {
|
|
262
|
+
for (const breaker of this.breakers.values()) breaker.reset();
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Open all breakers
|
|
266
|
+
*/
|
|
267
|
+
openAll() {
|
|
268
|
+
for (const breaker of this.breakers.values()) breaker.open();
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Close all breakers
|
|
272
|
+
*/
|
|
273
|
+
closeAll() {
|
|
274
|
+
for (const breaker of this.breakers.values()) breaker.close();
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* Create a new CircuitBreakerRegistry instance.
|
|
279
|
+
* Use this instead of a global singleton — attach to fastify.arc or pass explicitly.
|
|
280
|
+
*/
|
|
281
|
+
function createCircuitBreakerRegistry() {
|
|
282
|
+
return new CircuitBreakerRegistry();
|
|
283
|
+
}
|
|
284
|
+
//#endregion
|
|
2
285
|
//#region src/utils/compensation.ts
|
|
3
286
|
/**
|
|
4
287
|
* Run steps in order with automatic compensation on failure.
|
|
@@ -643,4 +926,4 @@ function createStateMachine(name, transitions = {}, options = {}) {
|
|
|
643
926
|
};
|
|
644
927
|
}
|
|
645
928
|
//#endregion
|
|
646
|
-
export { withCompensation as _, getListQueryParams as a, mutationResponse as c, responses as d, successResponseSchema as f, defineCompensation as g, defineGuard as h, getDefaultCrudSchemas as i, paginationSchema as l, handleRaw as m, deleteResponse as n, itemResponse as o, wrapResponse as p, errorResponseSchema as r, listResponse as s, createStateMachine as t, queryParams as u };
|
|
929
|
+
export { createCircuitBreakerRegistry as C, createCircuitBreaker as S, withCompensation as _, getListQueryParams as a, CircuitBreakerRegistry as b, mutationResponse as c, responses as d, successResponseSchema as f, defineCompensation as g, defineGuard as h, getDefaultCrudSchemas as i, paginationSchema as l, handleRaw as m, deleteResponse as n, itemResponse as o, wrapResponse as p, errorResponseSchema as r, listResponse as s, createStateMachine as t, queryParams as u, CircuitBreaker as v, CircuitState as x, CircuitBreakerError as y };
|
|
@@ -10,7 +10,7 @@ const versioningPlugin = async (fastify, opts) => {
|
|
|
10
10
|
const { type, defaultVersion = "1", headerName = "accept-version", responseHeader = "x-api-version", deprecated = [], sunset } = opts;
|
|
11
11
|
const deprecatedSet = new Set(deprecated);
|
|
12
12
|
fastify.decorateRequest("apiVersion", defaultVersion);
|
|
13
|
-
fastify.addHook("onRequest", async (request) => {
|
|
13
|
+
fastify.addHook("onRequest", async (request, reply) => {
|
|
14
14
|
let version = defaultVersion;
|
|
15
15
|
if (type === "header") {
|
|
16
16
|
const headerValue = request.headers[headerName];
|
|
@@ -20,10 +20,8 @@ const versioningPlugin = async (fastify, opts) => {
|
|
|
20
20
|
if (match) version = match[1] ?? defaultVersion;
|
|
21
21
|
}
|
|
22
22
|
request.apiVersion = version;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
reply.header(responseHeader, request.apiVersion);
|
|
26
|
-
if (deprecatedSet.has(request.apiVersion)) {
|
|
23
|
+
reply.header(responseHeader, version);
|
|
24
|
+
if (deprecatedSet.has(version)) {
|
|
27
25
|
reply.header("deprecation", "true");
|
|
28
26
|
reply.header("sunset", sunset ?? new Date(Date.now() + 2160 * 60 * 60 * 1e3).toISOString());
|
|
29
27
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/arc",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.3",
|
|
4
4
|
"description": "Resource-oriented backend framework for Fastify — clean, minimal, powerful, tree-shakable",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -112,10 +112,6 @@
|
|
|
112
112
|
"types": "./dist/events/transports/redis-stream-entry.d.mts",
|
|
113
113
|
"default": "./dist/events/transports/redis-stream-entry.mjs"
|
|
114
114
|
},
|
|
115
|
-
"./dynamic": {
|
|
116
|
-
"types": "./dist/dynamic/index.d.mts",
|
|
117
|
-
"default": "./dist/dynamic/index.mjs"
|
|
118
|
-
},
|
|
119
115
|
"./testing": {
|
|
120
116
|
"types": "./dist/testing/index.d.mts",
|
|
121
117
|
"default": "./dist/testing/index.mjs"
|
|
@@ -124,10 +120,6 @@
|
|
|
124
120
|
"types": "./dist/testing/storageContract.d.mts",
|
|
125
121
|
"default": "./dist/testing/storageContract.mjs"
|
|
126
122
|
},
|
|
127
|
-
"./policies": {
|
|
128
|
-
"types": "./dist/policies/index.d.mts",
|
|
129
|
-
"default": "./dist/policies/index.mjs"
|
|
130
|
-
},
|
|
131
123
|
"./factory": {
|
|
132
124
|
"types": "./dist/factory/index.d.mts",
|
|
133
125
|
"default": "./dist/factory/index.mjs"
|
|
@@ -188,10 +180,6 @@
|
|
|
188
180
|
"types": "./dist/scope/index.d.mts",
|
|
189
181
|
"default": "./dist/scope/index.mjs"
|
|
190
182
|
},
|
|
191
|
-
"./rpc": {
|
|
192
|
-
"types": "./dist/rpc/index.d.mts",
|
|
193
|
-
"default": "./dist/rpc/index.mjs"
|
|
194
|
-
},
|
|
195
183
|
"./mcp": {
|
|
196
184
|
"types": "./dist/integrations/mcp/index.d.mts",
|
|
197
185
|
"default": "./dist/integrations/mcp/index.mjs"
|
|
@@ -235,7 +223,8 @@
|
|
|
235
223
|
"node": ">=22"
|
|
236
224
|
},
|
|
237
225
|
"peerDependencies": {
|
|
238
|
-
"@classytic/mongokit": ">=3.
|
|
226
|
+
"@classytic/mongokit": ">=3.10.2",
|
|
227
|
+
"@classytic/repo-core": ">=0.1.0",
|
|
239
228
|
"@classytic/streamline": ">=2.1.0",
|
|
240
229
|
"@fastify/cors": ">=11.0.0",
|
|
241
230
|
"@fastify/helmet": ">=13.0.0",
|
|
@@ -255,11 +244,11 @@
|
|
|
255
244
|
"@sinclair/typebox": ">=0.34.0",
|
|
256
245
|
"better-auth": ">=1.6.2",
|
|
257
246
|
"bullmq": ">=5.0.0",
|
|
258
|
-
"fastify": "
|
|
247
|
+
"fastify": "^5.8.5",
|
|
259
248
|
"fastify-raw-body": ">=5.0.0",
|
|
260
249
|
"ioredis": ">=5.0.0",
|
|
261
250
|
"mongodb": ">=7.0.0",
|
|
262
|
-
"mongoose": "
|
|
251
|
+
"mongoose": "^9.4.1",
|
|
263
252
|
"pino-pretty": ">=13.0.0",
|
|
264
253
|
"zod": ">=4.0.0"
|
|
265
254
|
},
|
|
@@ -267,6 +256,9 @@
|
|
|
267
256
|
"@classytic/mongokit": {
|
|
268
257
|
"optional": true
|
|
269
258
|
},
|
|
259
|
+
"@classytic/repo-core": {
|
|
260
|
+
"optional": true
|
|
261
|
+
},
|
|
270
262
|
"mongodb": {
|
|
271
263
|
"optional": true
|
|
272
264
|
},
|
|
@@ -352,9 +344,12 @@
|
|
|
352
344
|
"secure-json-parse": "^4.1.0"
|
|
353
345
|
},
|
|
354
346
|
"devDependencies": {
|
|
347
|
+
"@better-auth/drizzle-adapter": "^1.6.2",
|
|
355
348
|
"@better-auth/mongo-adapter": "^1.6.2",
|
|
356
349
|
"@biomejs/biome": "^2.4.11",
|
|
357
|
-
"@classytic/mongokit": "^3.
|
|
350
|
+
"@classytic/mongokit": "^3.10.2",
|
|
351
|
+
"@classytic/repo-core": "^0.1.0",
|
|
352
|
+
"@classytic/sqlitekit": "^0.1.0",
|
|
358
353
|
"@classytic/streamline": "^2.1.0",
|
|
359
354
|
"@fastify/cors": "^11.2.0",
|
|
360
355
|
"@fastify/helmet": "^13.0.2",
|
|
@@ -372,8 +367,10 @@
|
|
|
372
367
|
"@vitest/coverage-v8": "^3.2.4",
|
|
373
368
|
"ajv": "^8.18.0",
|
|
374
369
|
"better-auth": "^1.6.2",
|
|
370
|
+
"better-sqlite3": "^12.9.0",
|
|
375
371
|
"bullmq": "^5.73.5",
|
|
376
372
|
"dotenv": "^17.4.2",
|
|
373
|
+
"drizzle-orm": "^0.45.2",
|
|
377
374
|
"fast-check": "^4.6.0",
|
|
378
375
|
"fastify-raw-body": "^5.0.0",
|
|
379
376
|
"ioredis": "^5.10.1",
|
|
@@ -381,7 +378,7 @@
|
|
|
381
378
|
"knip": "^6.4.1",
|
|
382
379
|
"mongodb": "^7.1.0",
|
|
383
380
|
"mongodb-memory-server": "^11.0.1",
|
|
384
|
-
"mongoose": "
|
|
381
|
+
"mongoose": ">=9.4.1",
|
|
385
382
|
"tsdown": "^0.21.7",
|
|
386
383
|
"typescript": "^6.0.2",
|
|
387
384
|
"vitest": "^3.0.0",
|
package/skills/arc/SKILL.md
CHANGED
|
@@ -8,11 +8,11 @@ description: |
|
|
|
8
8
|
Triggers: arc, fastify resource, defineResource, createApp, BaseController, arc preset,
|
|
9
9
|
arc auth, arc events, arc jobs, arc websocket, arc mcp, arc plugin, arc testing, arc cli,
|
|
10
10
|
arc permissions, arc hooks, arc pipeline, arc factory, arc cache, arc QueryCache.
|
|
11
|
-
version: 2.
|
|
11
|
+
version: 2.10.3
|
|
12
12
|
license: MIT
|
|
13
13
|
metadata:
|
|
14
14
|
author: Classytic
|
|
15
|
-
version: "2.
|
|
15
|
+
version: "2.10.3"
|
|
16
16
|
tags:
|
|
17
17
|
- fastify
|
|
18
18
|
- rest-api
|
|
@@ -692,14 +692,11 @@ class ProductController extends BaseController<Product> {
|
|
|
692
692
|
import { createMongooseAdapter } from '@classytic/arc';
|
|
693
693
|
const adapter = createMongooseAdapter({ model: ProductModel, repository: productRepo });
|
|
694
694
|
|
|
695
|
-
// Custom adapter — implement
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
update(id: string, data): Promise<TDoc | null>;
|
|
701
|
-
delete(id: string): Promise<boolean>;
|
|
702
|
-
}
|
|
695
|
+
// Custom adapter — implement MinimalRepo from @classytic/repo-core/repository:
|
|
696
|
+
import type { MinimalRepo } from '@classytic/repo-core/repository';
|
|
697
|
+
// MinimalRepo<TDoc> = five-method floor (getAll, getById, create, update, delete)
|
|
698
|
+
// StandardRepo<TDoc> = MinimalRepo + optional batch ops, CAS, soft-delete, etc.
|
|
699
|
+
// Arc feature-detects optional methods at call sites.
|
|
703
700
|
```
|
|
704
701
|
|
|
705
702
|
## Events
|
|
@@ -1178,7 +1175,6 @@ import {
|
|
|
1178
1175
|
} from '@classytic/arc/scope';
|
|
1179
1176
|
import { createTenantKeyGenerator } from '@classytic/arc/scope';
|
|
1180
1177
|
import { createRoleHierarchy } from '@classytic/arc/permissions';
|
|
1181
|
-
import { createServiceClient } from '@classytic/arc/rpc';
|
|
1182
1178
|
import { metricsPlugin, versioningPlugin } from '@classytic/arc/plugins';
|
|
1183
1179
|
import { webhookPlugin } from '@classytic/arc/integrations/webhooks';
|
|
1184
1180
|
import { mcpPlugin, createMcpServer, defineTool, definePrompt, fieldRulesToZod, resourceToTools } from '@classytic/arc/mcp';
|