@classytic/arc 2.9.1 → 2.10.8

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 (132) hide show
  1. package/README.md +20 -91
  2. package/dist/{BaseController-Vu2yc56T.mjs → BaseController-DVNKvoX4.mjs} +154 -170
  3. package/dist/{ResourceRegistry-Dq3_zBQP.mjs → ResourceRegistry-CcN2LVrc.mjs} +1 -1
  4. package/dist/actionPermissions-TUVR3uiZ.mjs +22 -0
  5. package/dist/adapters/index.d.mts +3 -3
  6. package/dist/adapters/index.mjs +2 -2
  7. package/dist/{adapters-BBqAVvPK.mjs → adapters-BXY4i-hw.mjs} +210 -41
  8. package/dist/audit/index.d.mts +38 -3
  9. package/dist/audit/index.mjs +54 -22
  10. package/dist/auth/index.d.mts +2 -2
  11. package/dist/auth/index.mjs +3 -3
  12. package/dist/cache/index.d.mts +17 -15
  13. package/dist/cache/index.mjs +16 -15
  14. package/dist/{caching-CjybdRwx.mjs → caching-3h93rkJM.mjs} +8 -3
  15. package/dist/cli/commands/describe.mjs +1 -1
  16. package/dist/cli/commands/docs.mjs +2 -2
  17. package/dist/cli/commands/init.mjs +1 -1
  18. package/dist/cli/commands/introspect.mjs +1 -1
  19. package/dist/context/index.d.mts +58 -0
  20. package/dist/context/index.mjs +2 -0
  21. package/dist/core/index.d.mts +2 -2
  22. package/dist/core/index.mjs +3 -4
  23. package/dist/{defineResource-C__jkwvs.mjs → core-3MWJosCH.mjs} +174 -94
  24. package/dist/{createActionRouter-DH1YFL9m.mjs → createActionRouter-C8UUB3Px.mjs} +1 -1
  25. package/dist/{createApp-CBJUJKGP.mjs → createApp-BwnEAO2h.mjs} +53 -19
  26. package/dist/docs/index.d.mts +1 -1
  27. package/dist/docs/index.mjs +2 -2
  28. package/dist/{elevation-DxQ6ACbt.mjs → elevation-Dci0AYLT.mjs} +2 -2
  29. package/dist/errorHandler-2ii4RIYr.d.mts +114 -0
  30. package/dist/{errorHandler-CZDW4EXS.mjs → errorHandler-CSxe7KIM.mjs} +1 -1
  31. package/dist/{eventPlugin-Dl7MoVWH.mjs → eventPlugin-ByU4Cv0e.mjs} +1 -1
  32. package/dist/{eventPlugin-BxvaCIZF.d.mts → eventPlugin-D1ThQ1Pp.d.mts} +1 -1
  33. package/dist/events/index.d.mts +8 -5
  34. package/dist/events/index.mjs +87 -52
  35. package/dist/events/transports/redis-stream-entry.d.mts +1 -1
  36. package/dist/events/transports/redis.d.mts +1 -1
  37. package/dist/factory/index.d.mts +1 -1
  38. package/dist/factory/index.mjs +1 -1
  39. package/dist/{types-DZi1aYhm.d.mts → fields-C8Y0XLAu.d.mts} +122 -2
  40. package/dist/hooks/index.d.mts +1 -1
  41. package/dist/idempotency/index.d.mts +5 -2
  42. package/dist/idempotency/index.mjs +46 -37
  43. package/dist/{interface-YrWsmKqE.d.mts → index-BGbpGVyM.d.mts} +2107 -2756
  44. package/dist/{index-CtGKT0lf.d.mts → index-BziRPS4H.d.mts} +81 -7
  45. package/dist/{index-C-xjcA6F.d.mts → index-C_Noptz-.d.mts} +284 -409
  46. package/dist/{index-Cibkchnx.d.mts → index-EqQN6p0W.d.mts} +3 -3
  47. package/dist/index.d.mts +6 -219
  48. package/dist/index.mjs +10 -131
  49. package/dist/integrations/event-gateway.d.mts +1 -1
  50. package/dist/integrations/event-gateway.mjs +1 -1
  51. package/dist/integrations/index.d.mts +1 -1
  52. package/dist/integrations/mcp/index.d.mts +2 -2
  53. package/dist/integrations/mcp/index.mjs +1 -1
  54. package/dist/integrations/mcp/testing.d.mts +1 -1
  55. package/dist/integrations/mcp/testing.mjs +1 -1
  56. package/dist/interface-yhyb_pLY.d.mts +77 -0
  57. package/dist/logger/index.d.mts +81 -0
  58. package/dist/{logger-CDjpjySd.mjs → logger/index.mjs} +1 -6
  59. package/dist/{memory-BFAYkf8H.mjs → memory-DqI-449b.mjs} +23 -8
  60. package/dist/middleware/index.d.mts +109 -0
  61. package/dist/middleware/index.mjs +70 -0
  62. package/dist/multipartBody-CUQGVlM_.mjs +123 -0
  63. package/dist/{openapi-CXuTG1M9.mjs → openapi-DpNpqBmo.mjs} +9 -7
  64. package/dist/org/index.d.mts +2 -2
  65. package/dist/permissions/index.d.mts +3 -4
  66. package/dist/permissions/index.mjs +5 -5
  67. package/dist/{permissions-oNZawnkR.mjs → permissions-wkqRwicB.mjs} +315 -397
  68. package/dist/pipe-CGJxqDGx.mjs +62 -0
  69. package/dist/pipeline/index.d.mts +62 -0
  70. package/dist/pipeline/index.mjs +53 -0
  71. package/dist/plugins/index.d.mts +23 -3
  72. package/dist/plugins/index.mjs +9 -11
  73. package/dist/plugins/response-cache.mjs +1 -1
  74. package/dist/plugins/tracing-entry.mjs +1 -1
  75. package/dist/presets/filesUpload.d.mts +3 -3
  76. package/dist/presets/filesUpload.mjs +255 -1
  77. package/dist/presets/index.d.mts +1 -1
  78. package/dist/presets/index.mjs +2 -2
  79. package/dist/presets/multiTenant.d.mts +1 -1
  80. package/dist/presets/multiTenant.mjs +43 -9
  81. package/dist/presets/search.d.mts +91 -4
  82. package/dist/presets/search.mjs +1 -1
  83. package/dist/{presets-hM4WhNWY.mjs → presets-CrwOvuXI.mjs} +1 -1
  84. package/dist/{queryCachePlugin-DbUVroUG.mjs → queryCachePlugin-ChLNZvFT.mjs} +9 -9
  85. package/dist/{queryCachePlugin-CnTZZTC5.d.mts → queryCachePlugin-Dumka73q.d.mts} +1 -1
  86. package/dist/{queryParser-Cs-6SHQK.mjs → queryParser-NR__Qiju.mjs} +69 -2
  87. package/dist/{redis-stream-Bz-4q96t.d.mts → redis-stream-bkO88VHx.d.mts} +1 -1
  88. package/dist/registry/index.d.mts +1 -1
  89. package/dist/registry/index.mjs +1 -1
  90. package/dist/{requestContext-DYtmNpm5.mjs → requestContext-C38GskNt.mjs} +1 -1
  91. package/dist/{resourceToTools-C3cWymnW.mjs → resourceToTools-BhF3JV5p.mjs} +8 -3
  92. package/dist/scope/index.d.mts +2 -2
  93. package/dist/scope/index.mjs +2 -2
  94. package/dist/{sse-CJpt7LGI.mjs → sse-D8UeDwis.mjs} +1 -1
  95. package/dist/{store-helpers-DFiZl5TL.mjs → store-helpers-DYYUQbQN.mjs} +4 -0
  96. package/dist/testing/index.d.mts +6 -5
  97. package/dist/testing/index.mjs +17 -10
  98. package/dist/types/index.d.mts +5 -5
  99. package/dist/types/index.mjs +1 -31
  100. package/dist/types-CDnTEpga.mjs +27 -0
  101. package/dist/{types-CoSzA-s-.d.mts → types-CVKBssX5.d.mts} +1 -1
  102. package/dist/{types-CunEX4UX.d.mts → types-CVdgPXBW.d.mts} +20 -7
  103. package/dist/utils/index.d.mts +277 -3
  104. package/dist/utils/index.mjs +4 -5
  105. package/dist/{utils-B7FuRr9w.mjs → utils-LMwVidKy.mjs} +303 -2
  106. package/dist/{versioning-Cm8qoFDg.mjs → versioning-B6mimogM.mjs} +3 -5
  107. package/dist/versioning-CeUXHfjw.d.mts +117 -0
  108. package/package.json +31 -18
  109. package/skills/arc/SKILL.md +8 -12
  110. package/skills/arc/references/production.md +0 -41
  111. package/dist/circuitBreaker-CvXkjfrW.d.mts +0 -206
  112. package/dist/circuitBreaker-l18oRgL5.mjs +0 -284
  113. package/dist/core-DNncu0xF.mjs +0 -34
  114. package/dist/dynamic/index.d.mts +0 -93
  115. package/dist/dynamic/index.mjs +0 -122
  116. package/dist/errorHandler-DixGcttC.d.mts +0 -218
  117. package/dist/fields-BC7zcmI9.d.mts +0 -121
  118. package/dist/filesUpload-q8oHt--L.mjs +0 -377
  119. package/dist/interface-DplgQO2e.d.mts +0 -54
  120. package/dist/policies/index.d.mts +0 -425
  121. package/dist/policies/index.mjs +0 -318
  122. package/dist/rpc/index.d.mts +0 -90
  123. package/dist/rpc/index.mjs +0 -248
  124. /package/dist/{EventTransport-CqZ8FyM_.d.mts → EventTransport-CfVEGaEl.d.mts} +0 -0
  125. /package/dist/{applyPermissionResult-bqGpo9ML.mjs → applyPermissionResult-QhV1Pa-g.mjs} +0 -0
  126. /package/dist/{constants-Cxde4rpC.mjs → constants-BhY1OHoH.mjs} +0 -0
  127. /package/dist/{elevation-B6S5csVA.d.mts → elevation-s5ykdNHr.d.mts} +0 -0
  128. /package/dist/{errors-CqWnSqM-.mjs → errors-BqdUDja_.mjs} +0 -0
  129. /package/dist/{fields-CU6FlaDV.mjs → fields-CTMWOUDt.mjs} +0 -0
  130. /package/dist/{keys-qcD-TVJl.mjs → keys-nWQGUTu1.mjs} +0 -0
  131. /package/dist/{types-ZUu_h0jp.mjs → types-D57iXYb8.mjs} +0 -0
  132. /package/dist/{types-BD85MlEK.d.mts → types-tgR4Pt8F.d.mts} +0 -0
@@ -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
- fastify.addHook("onSend", async (request, reply) => {
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
  }
@@ -0,0 +1,117 @@
1
+ import { n as DomainEvent } from "./EventTransport-CfVEGaEl.mjs";
2
+ import { FastifyPluginAsync, FastifyRequest } from "fastify";
3
+
4
+ //#region src/plugins/caching.d.ts
5
+ interface CachingRule {
6
+ /** Path prefix to match (e.g., '/api/products') */
7
+ match: string;
8
+ /** Cache-Control max-age in seconds */
9
+ maxAge: number;
10
+ /** Cache-Control: private vs public (default: public) */
11
+ private?: boolean;
12
+ /** stale-while-revalidate directive in seconds */
13
+ staleWhileRevalidate?: number;
14
+ }
15
+ interface CachingOptions {
16
+ /** Default max-age in seconds for Cache-Control (default: 0 = no-cache) */
17
+ maxAge?: number;
18
+ /** Enable ETag generation (default: true) */
19
+ etag?: boolean;
20
+ /** Enable conditional requests — 304 Not Modified (default: true) */
21
+ conditional?: boolean;
22
+ /** HTTP methods to cache (default: ['GET', 'HEAD']) */
23
+ methods?: string[];
24
+ /** Paths to exclude from caching (prefix match) */
25
+ exclude?: string[];
26
+ /** Custom cache rules per path prefix */
27
+ rules?: CachingRule[];
28
+ }
29
+ declare const cachingPlugin: FastifyPluginAsync<CachingOptions>;
30
+ declare const _default$3: FastifyPluginAsync<CachingOptions>;
31
+ //#endregion
32
+ //#region src/plugins/sse.d.ts
33
+ interface SSEOptions {
34
+ /** SSE endpoint path (default: '/events/stream') */
35
+ path?: string;
36
+ /** Require authentication (default: true) */
37
+ requireAuth?: boolean;
38
+ /** Event patterns to stream (default: ['*'] = all) */
39
+ patterns?: string[];
40
+ /** Heartbeat interval in ms (default: 30000) */
41
+ heartbeat?: number;
42
+ /** Filter events by organizationId from request.scope (default: false) */
43
+ orgScoped?: boolean;
44
+ /** Custom event filter function */
45
+ filter?: (event: DomainEvent<unknown>, request: FastifyRequest) => boolean;
46
+ }
47
+ declare const ssePlugin: FastifyPluginAsync<SSEOptions>;
48
+ declare const _default$2: FastifyPluginAsync<SSEOptions>;
49
+ //#endregion
50
+ //#region src/plugins/metrics.d.ts
51
+ interface MetricsOptions {
52
+ /** Endpoint path (default: '/_metrics') */
53
+ path?: string;
54
+ /** Prefix for all metric names (default: 'arc') */
55
+ prefix?: string;
56
+ /** Called after metrics are collected (for OTLP push, etc.) */
57
+ onCollect?: (metrics: MetricEntry[]) => void;
58
+ }
59
+ interface MetricEntry {
60
+ name: string;
61
+ type: "counter" | "histogram" | "gauge";
62
+ help: string;
63
+ values: Array<{
64
+ labels: Record<string, string>;
65
+ value: number;
66
+ }>;
67
+ }
68
+ interface MetricsCollector {
69
+ /** Get all metrics as structured data */
70
+ collect(): MetricEntry[];
71
+ /** Reset all metrics */
72
+ reset(): void;
73
+ /** Record a CRUD operation */
74
+ recordOperation(resource: string, operation: string, status: number, durationMs: number): void;
75
+ /** Record a cache hit */
76
+ recordCacheHit(resource: string): void;
77
+ /** Record a cache miss */
78
+ recordCacheMiss(resource: string): void;
79
+ /** Record an event publish */
80
+ recordEventPublish(eventType: string): void;
81
+ /** Record an event consume */
82
+ recordEventConsume(eventType: string): void;
83
+ /** Record a circuit breaker state change */
84
+ recordCircuitBreakerState(service: string, state: string): void;
85
+ }
86
+ declare module "fastify" {
87
+ interface FastifyInstance {
88
+ metrics: MetricsCollector;
89
+ }
90
+ }
91
+ declare const metricsPlugin: FastifyPluginAsync<MetricsOptions>;
92
+ declare const _default$1: FastifyPluginAsync<MetricsOptions>;
93
+ //#endregion
94
+ //#region src/plugins/versioning.d.ts
95
+ interface VersioningOptions {
96
+ /** Versioning strategy */
97
+ type: "header" | "prefix";
98
+ /** Default version when none specified (default: '1') */
99
+ defaultVersion?: string;
100
+ /** Header name to read (default: 'accept-version') */
101
+ headerName?: string;
102
+ /** Response header name (default: 'x-api-version') */
103
+ responseHeader?: string;
104
+ /** Deprecated versions — adds Deprecation + Sunset headers */
105
+ deprecated?: string[];
106
+ /** Sunset date for deprecated versions (ISO 8601) */
107
+ sunset?: string;
108
+ }
109
+ declare module "fastify" {
110
+ interface FastifyRequest {
111
+ apiVersion: string;
112
+ }
113
+ }
114
+ declare const versioningPlugin: FastifyPluginAsync<VersioningOptions>;
115
+ declare const _default: FastifyPluginAsync<VersioningOptions>;
116
+ //#endregion
117
+ export { MetricsCollector as a, metricsPlugin as c, ssePlugin as d, CachingOptions as f, cachingPlugin as h, MetricEntry as i, SSEOptions as l, _default$3 as m, _default as n, MetricsOptions as o, CachingRule as p, versioningPlugin as r, _default$1 as s, VersioningOptions as t, _default$2 as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/arc",
3
- "version": "2.9.1",
3
+ "version": "2.10.8",
4
4
  "description": "Resource-oriented backend framework for Fastify — clean, minimal, powerful, tree-shakable",
5
5
  "type": "module",
6
6
  "exports": {
@@ -64,6 +64,22 @@
64
64
  "types": "./dist/hooks/index.d.mts",
65
65
  "default": "./dist/hooks/index.mjs"
66
66
  },
67
+ "./middleware": {
68
+ "types": "./dist/middleware/index.d.mts",
69
+ "default": "./dist/middleware/index.mjs"
70
+ },
71
+ "./pipeline": {
72
+ "types": "./dist/pipeline/index.d.mts",
73
+ "default": "./dist/pipeline/index.mjs"
74
+ },
75
+ "./context": {
76
+ "types": "./dist/context/index.d.mts",
77
+ "default": "./dist/context/index.mjs"
78
+ },
79
+ "./logger": {
80
+ "types": "./dist/logger/index.d.mts",
81
+ "default": "./dist/logger/index.mjs"
82
+ },
67
83
  "./registry": {
68
84
  "types": "./dist/registry/index.d.mts",
69
85
  "default": "./dist/registry/index.mjs"
@@ -112,10 +128,6 @@
112
128
  "types": "./dist/events/transports/redis-stream-entry.d.mts",
113
129
  "default": "./dist/events/transports/redis-stream-entry.mjs"
114
130
  },
115
- "./dynamic": {
116
- "types": "./dist/dynamic/index.d.mts",
117
- "default": "./dist/dynamic/index.mjs"
118
- },
119
131
  "./testing": {
120
132
  "types": "./dist/testing/index.d.mts",
121
133
  "default": "./dist/testing/index.mjs"
@@ -124,10 +136,6 @@
124
136
  "types": "./dist/testing/storageContract.d.mts",
125
137
  "default": "./dist/testing/storageContract.mjs"
126
138
  },
127
- "./policies": {
128
- "types": "./dist/policies/index.d.mts",
129
- "default": "./dist/policies/index.mjs"
130
- },
131
139
  "./factory": {
132
140
  "types": "./dist/factory/index.d.mts",
133
141
  "default": "./dist/factory/index.mjs"
@@ -188,10 +196,6 @@
188
196
  "types": "./dist/scope/index.d.mts",
189
197
  "default": "./dist/scope/index.mjs"
190
198
  },
191
- "./rpc": {
192
- "types": "./dist/rpc/index.d.mts",
193
- "default": "./dist/rpc/index.mjs"
194
- },
195
199
  "./mcp": {
196
200
  "types": "./dist/integrations/mcp/index.d.mts",
197
201
  "default": "./dist/integrations/mcp/index.mjs"
@@ -235,7 +239,8 @@
235
239
  "node": ">=22"
236
240
  },
237
241
  "peerDependencies": {
238
- "@classytic/mongokit": ">=3.8.0",
242
+ "@classytic/mongokit": ">=3.11.0",
243
+ "@classytic/repo-core": ">=0.2.0",
239
244
  "@classytic/streamline": ">=2.1.0",
240
245
  "@fastify/cors": ">=11.0.0",
241
246
  "@fastify/helmet": ">=13.0.0",
@@ -255,11 +260,11 @@
255
260
  "@sinclair/typebox": ">=0.34.0",
256
261
  "better-auth": ">=1.6.2",
257
262
  "bullmq": ">=5.0.0",
258
- "fastify": ">=5.0.0",
263
+ "fastify": "^5.8.5",
259
264
  "fastify-raw-body": ">=5.0.0",
260
265
  "ioredis": ">=5.0.0",
261
266
  "mongodb": ">=7.0.0",
262
- "mongoose": ">=9.4.1",
267
+ "mongoose": "^9.4.1",
263
268
  "pino-pretty": ">=13.0.0",
264
269
  "zod": ">=4.0.0"
265
270
  },
@@ -267,6 +272,9 @@
267
272
  "@classytic/mongokit": {
268
273
  "optional": true
269
274
  },
275
+ "@classytic/repo-core": {
276
+ "optional": true
277
+ },
270
278
  "mongodb": {
271
279
  "optional": true
272
280
  },
@@ -352,9 +360,12 @@
352
360
  "secure-json-parse": "^4.1.0"
353
361
  },
354
362
  "devDependencies": {
363
+ "@better-auth/drizzle-adapter": "^1.6.2",
355
364
  "@better-auth/mongo-adapter": "^1.6.2",
356
365
  "@biomejs/biome": "^2.4.11",
357
- "@classytic/mongokit": "^3.8.0",
366
+ "@classytic/mongokit": "^3.11.0",
367
+ "@classytic/repo-core": "^0.2.0",
368
+ "@classytic/sqlitekit": "^0.2.0",
358
369
  "@classytic/streamline": "^2.1.0",
359
370
  "@fastify/cors": "^11.2.0",
360
371
  "@fastify/helmet": "^13.0.2",
@@ -372,8 +383,10 @@
372
383
  "@vitest/coverage-v8": "^3.2.4",
373
384
  "ajv": "^8.18.0",
374
385
  "better-auth": "^1.6.2",
386
+ "better-sqlite3": "^12.9.0",
375
387
  "bullmq": "^5.73.5",
376
388
  "dotenv": "^17.4.2",
389
+ "drizzle-orm": "^0.45.2",
377
390
  "fast-check": "^4.6.0",
378
391
  "fastify-raw-body": "^5.0.0",
379
392
  "ioredis": "^5.10.1",
@@ -381,7 +394,7 @@
381
394
  "knip": "^6.4.1",
382
395
  "mongodb": "^7.1.0",
383
396
  "mongodb-memory-server": "^11.0.1",
384
- "mongoose": "^9.4.1",
397
+ "mongoose": ">=9.4.1",
385
398
  "tsdown": "^0.21.7",
386
399
  "typescript": "^6.0.2",
387
400
  "vitest": "^3.0.0",
@@ -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.9.1
11
+ version: 2.10.3
12
12
  license: MIT
13
13
  metadata:
14
14
  author: Classytic
15
- version: "2.9.1"
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 CrudRepository interface:
696
- interface CrudRepository<TDoc> {
697
- getAll(params?): Promise<TDoc[] | PaginatedResult<TDoc>>;
698
- getById(id: string): Promise<TDoc | null>;
699
- create(data): Promise<TDoc>;
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
@@ -790,7 +787,7 @@ afterUpdate(hooks, 'product', async (ctx) => { await invalidateCache(ctx.result.
790
787
  ## Pipeline
791
788
 
792
789
  ```typescript
793
- import { guard, transform, intercept } from '@classytic/arc';
790
+ import { guard, transform, intercept } from '@classytic/arc/pipeline';
794
791
 
795
792
  defineResource({
796
793
  pipe: {
@@ -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';
@@ -366,28 +366,6 @@ const runner = new MigrationRunner(mongoose.connection.db);
366
366
  await runner.up([v2]);
367
367
  ```
368
368
 
369
- ## Policies
370
-
371
- Query-level authorization — modify queries based on user:
372
-
373
- ```typescript
374
- import { createAccessControlPolicy } from '@classytic/arc/policies';
375
-
376
- const editorPolicy = createAccessControlPolicy({
377
- statements: [
378
- { resource: 'product', action: ['create', 'update'] },
379
- { resource: 'order', action: ['read'] },
380
- ],
381
- });
382
-
383
- defineResource({
384
- permissions: {
385
- create: editorPolicy,
386
- update: editorPolicy,
387
- },
388
- });
389
- ```
390
-
391
369
  ## OpenAPI & External Paths
392
370
 
393
371
  Arc auto-generates OpenAPI 3.0 specs from resource definitions. External integrations (auth adapters, custom routes) inject their paths via `ExternalOpenApiPaths`.
@@ -562,25 +540,6 @@ const relayed = await outbox.relay(); // publishes pending → transport
562
540
 
563
541
  **OutboxStore interface**: `save(event)`, `getPending(limit)`, `acknowledge(eventId)` (+ optional `claimPending`, `fail`, `getDeadLettered`, `purge`). When you pass `repository`, arc adapts it internally.
564
542
 
565
- ## RPC Service Client — Schema Versioning
566
-
567
- The service client supports a `schemaVersion` option for contract compatibility between services:
568
-
569
- ```typescript
570
- import { createServiceClient } from '@classytic/arc/rpc';
571
-
572
- const catalog = createServiceClient({
573
- baseUrl: 'http://catalog:3000',
574
- schemaVersion: '1.2.0', // sent as x-arc-schema-version header
575
- correlationId: () => request.id,
576
- retry: { maxRetries: 2 },
577
- });
578
-
579
- const products = await catalog.resource('product').list();
580
- ```
581
-
582
- Receiving services can check `request.headers['x-arc-schema-version']` to detect version mismatches.
583
-
584
543
  ## Bulk Operations Preset
585
544
 
586
545
  Adds bulk CRUD routes — repository must provide `createMany`, `updateMany`, `deleteMany`:
@@ -1,206 +0,0 @@
1
- //#region src/utils/circuitBreaker.d.ts
2
- /**
3
- * Circuit Breaker Pattern
4
- *
5
- * Wraps external service calls with failure protection.
6
- * Prevents cascading failures by "opening" the circuit when
7
- * a service is failing, allowing it time to recover.
8
- *
9
- * States:
10
- * - CLOSED: Normal operation, requests pass through
11
- * - OPEN: Too many failures, all requests fail fast
12
- * - HALF_OPEN: Testing if service recovered, limited requests
13
- *
14
- * @example
15
- * import { CircuitBreaker } from '@classytic/arc/utils';
16
- *
17
- * const paymentBreaker = new CircuitBreaker(async (amount) => {
18
- * return await stripe.charges.create({ amount });
19
- * }, {
20
- * failureThreshold: 5,
21
- * resetTimeout: 30000,
22
- * timeout: 5000,
23
- * });
24
- *
25
- * try {
26
- * const result = await paymentBreaker.call(100);
27
- * } catch (error) {
28
- * // Handle failure or circuit open
29
- * }
30
- */
31
- declare const CircuitState: {
32
- readonly CLOSED: "CLOSED";
33
- readonly OPEN: "OPEN";
34
- readonly HALF_OPEN: "HALF_OPEN";
35
- };
36
- type CircuitState = (typeof CircuitState)[keyof typeof CircuitState];
37
- interface CircuitBreakerOptions {
38
- /**
39
- * Number of failures before opening circuit
40
- * @default 5
41
- */
42
- failureThreshold?: number;
43
- /**
44
- * Time in ms before attempting to close circuit
45
- * @default 60000 (60 seconds)
46
- */
47
- resetTimeout?: number;
48
- /**
49
- * Request timeout in ms
50
- * @default 10000 (10 seconds)
51
- */
52
- timeout?: number;
53
- /**
54
- * Number of successful requests in HALF_OPEN before closing
55
- * @default 1
56
- */
57
- successThreshold?: number;
58
- /**
59
- * Fallback function when circuit is open.
60
- * Receives the same arguments as the wrapped function.
61
- */
62
- fallback?: (...args: unknown[]) => Promise<unknown>;
63
- /**
64
- * Callback when state changes
65
- */
66
- onStateChange?: (from: CircuitState, to: CircuitState) => void;
67
- /**
68
- * Callback on error
69
- */
70
- onError?: (error: Error) => void;
71
- /**
72
- * Name for logging/monitoring
73
- */
74
- name?: string;
75
- }
76
- interface CircuitBreakerStats {
77
- name?: string;
78
- state: CircuitState;
79
- failures: number;
80
- successes: number;
81
- totalCalls: number;
82
- openedAt: number | null;
83
- lastCallAt: number | null;
84
- }
85
- declare class CircuitBreakerError extends Error {
86
- state: CircuitState;
87
- constructor(message: string, state: CircuitState);
88
- }
89
- declare class CircuitBreaker<T extends (...args: any[]) => Promise<any>> {
90
- private state;
91
- private failures;
92
- private successes;
93
- private totalCalls;
94
- private nextAttempt;
95
- private lastCallAt;
96
- private openedAt;
97
- private readonly failureThreshold;
98
- private readonly resetTimeout;
99
- private readonly timeout;
100
- private readonly successThreshold;
101
- private readonly fallback?;
102
- private readonly onStateChange?;
103
- private readonly onError?;
104
- private readonly name;
105
- private readonly fn;
106
- constructor(fn: T, options?: CircuitBreakerOptions);
107
- /**
108
- * Call the wrapped function with circuit breaker protection
109
- */
110
- call(...args: Parameters<T>): Promise<ReturnType<T>>;
111
- /**
112
- * Execute function with timeout
113
- */
114
- private executeWithTimeout;
115
- /**
116
- * Handle successful call
117
- */
118
- private onSuccess;
119
- /**
120
- * Handle failed call
121
- */
122
- private onFailure;
123
- /**
124
- * Change circuit state
125
- */
126
- private setState;
127
- /**
128
- * Manually open the circuit
129
- */
130
- open(): void;
131
- /**
132
- * Manually close the circuit
133
- */
134
- close(): void;
135
- /**
136
- * Get current statistics
137
- */
138
- getStats(): CircuitBreakerStats;
139
- /**
140
- * Get current state
141
- */
142
- getState(): CircuitState;
143
- /**
144
- * Check if circuit is open
145
- */
146
- isOpen(): boolean;
147
- /**
148
- * Check if circuit is closed
149
- */
150
- isClosed(): boolean;
151
- /**
152
- * Reset statistics
153
- */
154
- reset(): void;
155
- }
156
- /**
157
- * Create a circuit breaker with sensible defaults
158
- *
159
- * @example
160
- * const emailBreaker = createCircuitBreaker(
161
- * async (to, subject, body) => sendEmail(to, subject, body),
162
- * { name: 'email-service' }
163
- * );
164
- */
165
- declare function createCircuitBreaker<T extends (...args: any[]) => Promise<any>>(fn: T, options?: CircuitBreakerOptions): CircuitBreaker<T>;
166
- /**
167
- * Circuit breaker registry for managing multiple breakers
168
- */
169
- declare class CircuitBreakerRegistry {
170
- private breakers;
171
- /**
172
- * Register a circuit breaker
173
- */
174
- register<T extends (...args: any[]) => Promise<any>>(name: string, fn: T, options?: Omit<CircuitBreakerOptions, "name">): CircuitBreaker<T>;
175
- /**
176
- * Get a circuit breaker by name
177
- */
178
- get(name: string): CircuitBreaker<any> | undefined;
179
- /**
180
- * Get all breakers
181
- */
182
- getAll(): Map<string, CircuitBreaker<any>>;
183
- /**
184
- * Get statistics for all breakers
185
- */
186
- getAllStats(): Record<string, CircuitBreakerStats>;
187
- /**
188
- * Reset all breakers
189
- */
190
- resetAll(): void;
191
- /**
192
- * Open all breakers
193
- */
194
- openAll(): void;
195
- /**
196
- * Close all breakers
197
- */
198
- closeAll(): void;
199
- }
200
- /**
201
- * Create a new CircuitBreakerRegistry instance.
202
- * Use this instead of a global singleton — attach to fastify.arc or pass explicitly.
203
- */
204
- declare function createCircuitBreakerRegistry(): CircuitBreakerRegistry;
205
- //#endregion
206
- export { CircuitBreakerStats as a, createCircuitBreakerRegistry as c, CircuitBreakerRegistry as i, CircuitBreakerError as n, CircuitState as o, CircuitBreakerOptions as r, createCircuitBreaker as s, CircuitBreaker as t };