@classytic/arc 2.3.0 → 2.4.2
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 +187 -18
- package/bin/arc.js +11 -3
- package/dist/BaseController-CkM5dUh_.mjs +1031 -0
- package/dist/{EventTransport-BkUDYZEb.d.mts → EventTransport-wc5hSLik.d.mts} +1 -1
- package/dist/{HookSystem-BsGV-j2l.mjs → HookSystem-COkyWztM.mjs} +2 -3
- package/dist/{ResourceRegistry-7Ic20ZMw.mjs → ResourceRegistry-DeCIFlix.mjs} +8 -5
- package/dist/adapters/index.d.mts +3 -5
- package/dist/adapters/index.mjs +2 -3
- package/dist/{prisma-DJbMt3yf.mjs → adapters-DTC4Ug66.mjs} +45 -12
- package/dist/audit/index.d.mts +4 -7
- package/dist/audit/index.mjs +2 -29
- package/dist/audit/mongodb.d.mts +1 -4
- package/dist/audit/mongodb.mjs +2 -3
- package/dist/auth/index.d.mts +7 -9
- package/dist/auth/index.mjs +65 -63
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/auth/redis-session.mjs +1 -2
- package/dist/{betterAuthOpenApi-DjWDddNc.mjs → betterAuthOpenApi-lz0IRbXJ.mjs} +4 -6
- package/dist/cache/index.d.mts +23 -23
- package/dist/cache/index.mjs +4 -6
- package/dist/{caching-GSDJcA6-.mjs → caching-BSXB-Xr7.mjs} +2 -24
- package/dist/chunk-BpYLSNr0.mjs +14 -0
- package/dist/circuitBreaker-BOBOpN2w.mjs +284 -0
- package/dist/circuitBreaker-JP2GdJ4b.d.mts +206 -0
- package/dist/cli/commands/describe.mjs +24 -7
- package/dist/cli/commands/docs.mjs +6 -7
- package/dist/cli/commands/doctor.d.mts +10 -0
- package/dist/cli/commands/doctor.mjs +156 -0
- package/dist/cli/commands/generate.mjs +66 -17
- package/dist/cli/commands/init.mjs +315 -45
- package/dist/cli/commands/introspect.mjs +2 -4
- package/dist/cli/index.d.mts +1 -10
- package/dist/cli/index.mjs +4 -153
- package/dist/{constants-DdXFXQtN.mjs → constants-Cxde4rpC.mjs} +1 -2
- package/dist/core/index.d.mts +3 -5
- package/dist/core/index.mjs +5 -4
- package/dist/core-C1XCMtqM.mjs +185 -0
- package/dist/{createApp-CgKOPhA4.mjs → createApp-ByWNRsZj.mjs} +64 -35
- package/dist/{defineResource-DWbpJYtm.mjs → defineResource-D9aY5Cy6.mjs} +108 -1157
- package/dist/discovery/index.mjs +37 -5
- package/dist/docs/index.d.mts +6 -9
- package/dist/docs/index.mjs +3 -21
- package/dist/dynamic/index.d.mts +93 -0
- package/dist/dynamic/index.mjs +122 -0
- package/dist/{elevation-DSTbVvYj.mjs → elevation-BEdACOLB.mjs} +5 -36
- package/dist/{elevation-DGo5shaX.d.mts → elevation-Ca_yveIO.d.mts} +41 -7
- package/dist/{errorHandler-C3GY3_ow.mjs → errorHandler--zp54tGc.mjs} +3 -5
- package/dist/errorHandler-Do4vVQ1f.d.mts +139 -0
- package/dist/{errors-DBANPbGr.mjs → errors-rxhfP7Hf.mjs} +1 -2
- package/dist/{eventPlugin-BEOvaDqo.mjs → eventPlugin-Ba00swHF.mjs} +25 -27
- package/dist/{eventPlugin-H6wDDjGO.d.mts → eventPlugin-iGrSEmwJ.d.mts} +105 -5
- package/dist/events/index.d.mts +72 -7
- package/dist/events/index.mjs +216 -4
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis-stream-entry.mjs +19 -7
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/events/transports/redis.mjs +3 -4
- package/dist/factory/index.d.mts +23 -9
- package/dist/factory/index.mjs +48 -3
- package/dist/{fields-Bi_AVKSo.d.mts → fields-DFwdaWCq.d.mts} +1 -1
- package/dist/{fields-CTd_CrKr.mjs → fields-ipsbIRPK.mjs} +1 -2
- package/dist/hooks/index.d.mts +1 -3
- package/dist/hooks/index.mjs +2 -3
- package/dist/idempotency/index.d.mts +5 -5
- package/dist/idempotency/index.mjs +3 -7
- package/dist/idempotency/mongodb.d.mts +1 -1
- package/dist/idempotency/mongodb.mjs +4 -5
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/idempotency/redis.mjs +2 -5
- package/dist/{fastifyAdapter-6b_eRDBw.d.mts → index-BL8CaQih.d.mts} +56 -57
- package/dist/index-Diqcm14c.d.mts +369 -0
- package/dist/{prisma-Dy5S5F5i.d.mts → index-yhxyjqNb.d.mts} +4 -5
- package/dist/index.d.mts +100 -105
- package/dist/index.mjs +85 -58
- package/dist/integrations/event-gateway.d.mts +1 -1
- package/dist/integrations/event-gateway.mjs +8 -4
- package/dist/integrations/index.d.mts +4 -2
- package/dist/integrations/index.mjs +1 -1
- package/dist/integrations/jobs.d.mts +2 -2
- package/dist/integrations/jobs.mjs +63 -14
- package/dist/integrations/mcp/index.d.mts +219 -0
- package/dist/integrations/mcp/index.mjs +572 -0
- package/dist/integrations/mcp/testing.d.mts +53 -0
- package/dist/integrations/mcp/testing.mjs +104 -0
- package/dist/integrations/streamline.mjs +39 -19
- package/dist/integrations/webhooks.d.mts +56 -0
- package/dist/integrations/webhooks.mjs +139 -0
- package/dist/integrations/websocket-redis.d.mts +46 -0
- package/dist/integrations/websocket-redis.mjs +50 -0
- package/dist/integrations/websocket.d.mts +68 -2
- package/dist/integrations/websocket.mjs +96 -13
- package/dist/{interface-CSNjltAc.d.mts → interface-B4awm1RJ.d.mts} +2 -2
- package/dist/interface-DGmPxakH.d.mts +2213 -0
- package/dist/{keys-DhqDRxv3.mjs → keys-qcD-TVJl.mjs} +3 -4
- package/dist/{logger-ByrvQWZO.mjs → logger-Dz3j1ItV.mjs} +2 -4
- package/dist/{memory-B2v7KrCB.mjs → memory-Cb_7iy9e.mjs} +2 -4
- package/dist/metrics-Csh4nsvv.mjs +224 -0
- package/dist/migrations/index.d.mts +113 -44
- package/dist/migrations/index.mjs +84 -102
- package/dist/{mongodb-DNKEExbf.mjs → mongodb-BuQ7fNTg.mjs} +1 -4
- package/dist/{mongodb-ClykrfGo.d.mts → mongodb-CUpYfxfD.d.mts} +2 -3
- package/dist/{mongodb-Dg8O_gvd.d.mts → mongodb-bga9AbkD.d.mts} +2 -2
- package/dist/{openapi-9nB_kiuR.mjs → openapi-CBmZ6EQN.mjs} +4 -21
- package/dist/org/index.d.mts +12 -14
- package/dist/org/index.mjs +92 -119
- package/dist/org/types.d.mts +2 -2
- package/dist/org/types.mjs +1 -1
- package/dist/permissions/index.d.mts +4 -278
- package/dist/permissions/index.mjs +4 -579
- package/dist/permissions-CA5zg0yK.mjs +751 -0
- package/dist/plugins/index.d.mts +104 -107
- package/dist/plugins/index.mjs +203 -313
- package/dist/plugins/response-cache.mjs +4 -69
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +24 -11
- package/dist/{pluralize-CM-jZg7p.mjs → pluralize-CcT6qF0a.mjs} +12 -13
- package/dist/policies/index.d.mts +2 -2
- package/dist/policies/index.mjs +80 -83
- package/dist/presets/index.d.mts +26 -19
- package/dist/presets/index.mjs +2 -142
- package/dist/presets/multiTenant.d.mts +1 -4
- package/dist/presets/multiTenant.mjs +4 -6
- package/dist/presets-C9QXJV1u.mjs +422 -0
- package/dist/{queryCachePlugin-B6R0d4av.mjs → queryCachePlugin-ClosZdNS.mjs} +6 -27
- package/dist/{queryCachePlugin-Q6SYuHZ6.d.mts → queryCachePlugin-DcmETvcB.d.mts} +3 -3
- package/dist/queryParser-CgCtsjti.mjs +352 -0
- package/dist/{redis-UwjEp8Ea.d.mts → redis-CQ5YxMC5.d.mts} +2 -2
- package/dist/{redis-stream-CBg0upHI.d.mts → redis-stream-BW9UKLZM.d.mts} +9 -2
- package/dist/registry/index.d.mts +1 -4
- package/dist/registry/index.mjs +3 -4
- package/dist/{introspectionPlugin-B3JkrjwU.mjs → registry-I-ogLgL9.mjs} +1 -8
- package/dist/{requestContext-xi6OKBL-.mjs → requestContext-DYtmNpm5.mjs} +1 -3
- package/dist/resourceToTools-PMFE8HIv.mjs +533 -0
- package/dist/rpc/index.d.mts +90 -0
- package/dist/rpc/index.mjs +248 -0
- package/dist/{schemaConverter-Dtg0Kt9T.mjs → schemaConverter-DjzHpFam.mjs} +1 -2
- package/dist/schemas/index.d.mts +30 -30
- package/dist/schemas/index.mjs +2 -4
- package/dist/scope/index.d.mts +13 -2
- package/dist/scope/index.mjs +18 -5
- package/dist/{sessionManager-D_iEHjQl.d.mts → sessionManager-wbkYj2HL.d.mts} +2 -2
- package/dist/{sse-DkqQ1uxb.mjs → sse-BkViJPlT.mjs} +4 -25
- package/dist/testing/index.d.mts +551 -567
- package/dist/testing/index.mjs +1744 -1799
- package/dist/{tracing-8CEbhF0w.d.mts → tracing-bz_U4EM1.d.mts} +6 -1
- package/dist/{typeGuards-DwxA1t_L.mjs → typeGuards-Cj5Rgvlg.mjs} +1 -2
- package/dist/types/index.d.mts +4 -946
- package/dist/types/index.mjs +2 -4
- package/dist/types-BJmgxNbF.d.mts +275 -0
- package/dist/{types-RLkFVgaw.d.mts → types-BNUccdcf.d.mts} +2 -2
- package/dist/{types-Beqn1Un7.mjs → types-C6TQjtdi.mjs} +30 -2
- package/dist/{types-tKwaViYB.d.mts → types-Dt0-AI6E.d.mts} +68 -27
- package/dist/{types-DelU6kln.mjs → types-ZUu_h0jp.mjs} +1 -2
- package/dist/utils/index.d.mts +254 -351
- package/dist/utils/index.mjs +7 -6
- package/dist/utils-Dc0WhlIl.mjs +594 -0
- package/dist/versioning-BzfeHmhj.mjs +37 -0
- package/package.json +44 -10
- package/skills/arc/SKILL.md +518 -0
- package/skills/arc/references/auth.md +250 -0
- package/skills/arc/references/events.md +272 -0
- package/skills/arc/references/integrations.md +385 -0
- package/skills/arc/references/mcp.md +431 -0
- package/skills/arc/references/production.md +610 -0
- package/skills/arc/references/testing.md +183 -0
- package/dist/audited-CGdLiSlE.mjs +0 -140
- package/dist/chunk-C7Uep-_p.mjs +0 -20
- package/dist/circuitBreaker-CSS2VvL6.mjs +0 -1109
- package/dist/errorHandler-CW3OOeYq.d.mts +0 -72
- package/dist/interface-BtdYtQUA.d.mts +0 -1114
- package/dist/presets-BTeYbw7h.d.mts +0 -57
- package/dist/presets-CeFtfDR8.mjs +0 -119
- /package/dist/{errors-DAWRdiYP.d.mts → errors-CPpvPHT0.d.mts} +0 -0
- /package/dist/{externalPaths-SyPF2tgK.d.mts → externalPaths-DpO-s7r8.d.mts} +0 -0
- /package/dist/{interface-DTbsvIWe.d.mts → interface-D_BWALyZ.d.mts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/arc",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"description": "Resource-oriented backend framework for Fastify — clean, minimal, powerful, tree-shakable",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -108,6 +108,10 @@
|
|
|
108
108
|
"types": "./dist/events/transports/redis-stream-entry.d.mts",
|
|
109
109
|
"default": "./dist/events/transports/redis-stream-entry.mjs"
|
|
110
110
|
},
|
|
111
|
+
"./dynamic": {
|
|
112
|
+
"types": "./dist/dynamic/index.d.mts",
|
|
113
|
+
"default": "./dist/dynamic/index.mjs"
|
|
114
|
+
},
|
|
111
115
|
"./testing": {
|
|
112
116
|
"types": "./dist/testing/index.d.mts",
|
|
113
117
|
"default": "./dist/testing/index.mjs"
|
|
@@ -144,6 +148,10 @@
|
|
|
144
148
|
"types": "./dist/integrations/websocket.d.mts",
|
|
145
149
|
"default": "./dist/integrations/websocket.mjs"
|
|
146
150
|
},
|
|
151
|
+
"./integrations/websocket-redis": {
|
|
152
|
+
"types": "./dist/integrations/websocket-redis.d.mts",
|
|
153
|
+
"default": "./dist/integrations/websocket-redis.mjs"
|
|
154
|
+
},
|
|
147
155
|
"./integrations/jobs": {
|
|
148
156
|
"types": "./dist/integrations/jobs.d.mts",
|
|
149
157
|
"default": "./dist/integrations/jobs.mjs"
|
|
@@ -152,6 +160,10 @@
|
|
|
152
160
|
"types": "./dist/integrations/event-gateway.d.mts",
|
|
153
161
|
"default": "./dist/integrations/event-gateway.mjs"
|
|
154
162
|
},
|
|
163
|
+
"./integrations/webhooks": {
|
|
164
|
+
"types": "./dist/integrations/webhooks.d.mts",
|
|
165
|
+
"default": "./dist/integrations/webhooks.mjs"
|
|
166
|
+
},
|
|
155
167
|
"./auth/redis": {
|
|
156
168
|
"types": "./dist/auth/redis-session.d.mts",
|
|
157
169
|
"default": "./dist/auth/redis-session.mjs"
|
|
@@ -163,6 +175,18 @@
|
|
|
163
175
|
"./scope": {
|
|
164
176
|
"types": "./dist/scope/index.d.mts",
|
|
165
177
|
"default": "./dist/scope/index.mjs"
|
|
178
|
+
},
|
|
179
|
+
"./rpc": {
|
|
180
|
+
"types": "./dist/rpc/index.d.mts",
|
|
181
|
+
"default": "./dist/rpc/index.mjs"
|
|
182
|
+
},
|
|
183
|
+
"./mcp": {
|
|
184
|
+
"types": "./dist/integrations/mcp/index.d.mts",
|
|
185
|
+
"default": "./dist/integrations/mcp/index.mjs"
|
|
186
|
+
},
|
|
187
|
+
"./mcp/testing": {
|
|
188
|
+
"types": "./dist/integrations/mcp/testing.d.mts",
|
|
189
|
+
"default": "./dist/integrations/mcp/testing.mjs"
|
|
166
190
|
}
|
|
167
191
|
},
|
|
168
192
|
"main": "./dist/index.mjs",
|
|
@@ -173,26 +197,31 @@
|
|
|
173
197
|
"sideEffects": false,
|
|
174
198
|
"files": [
|
|
175
199
|
"dist",
|
|
176
|
-
"bin"
|
|
200
|
+
"bin",
|
|
201
|
+
"skills"
|
|
177
202
|
],
|
|
178
203
|
"scripts": {
|
|
179
204
|
"build": "tsdown",
|
|
180
205
|
"dev": "tsdown --watch",
|
|
181
206
|
"typecheck": "tsc --noEmit",
|
|
207
|
+
"lint": "biome check src/",
|
|
208
|
+
"lint:fix": "biome check --fix src/",
|
|
209
|
+
"lint:all": "biome check src/ tests/",
|
|
182
210
|
"test": "vitest run",
|
|
183
211
|
"test:watch": "vitest",
|
|
184
212
|
"test:ui": "vitest --ui",
|
|
185
213
|
"test:coverage": "vitest run --coverage",
|
|
186
214
|
"test:e2e": "vitest run tests/e2e",
|
|
187
215
|
"test:unit": "vitest run tests/core tests/hooks tests/utils tests/plugins",
|
|
188
|
-
"
|
|
216
|
+
"smoke": "node scripts/smoke-test.mjs",
|
|
217
|
+
"prepublishOnly": "npm run typecheck && npm test && npm run build && npm run smoke"
|
|
189
218
|
},
|
|
190
219
|
"engines": {
|
|
191
220
|
"node": ">=22"
|
|
192
221
|
},
|
|
193
222
|
"peerDependencies": {
|
|
194
|
-
"@classytic/mongokit": ">=3.3
|
|
195
|
-
"@classytic/streamline": ">=
|
|
223
|
+
"@classytic/mongokit": ">=3.4.3",
|
|
224
|
+
"@classytic/streamline": ">=2.0.0",
|
|
196
225
|
"@fastify/cors": "^11.0.0",
|
|
197
226
|
"@fastify/helmet": "^13.0.0",
|
|
198
227
|
"@fastify/jwt": "^10.0.0",
|
|
@@ -202,14 +231,14 @@
|
|
|
202
231
|
"@fastify/type-provider-typebox": "^6.0.0",
|
|
203
232
|
"@fastify/under-pressure": "^9.0.0",
|
|
204
233
|
"@fastify/websocket": "^11.0.0",
|
|
205
|
-
"@
|
|
234
|
+
"@modelcontextprotocol/sdk": ">=1.28.0",
|
|
206
235
|
"@opentelemetry/auto-instrumentations-node": ">=0.40.0",
|
|
207
236
|
"@opentelemetry/exporter-trace-otlp-http": ">=0.50.0",
|
|
208
237
|
"@opentelemetry/instrumentation-http": ">=0.50.0",
|
|
209
238
|
"@opentelemetry/instrumentation-mongodb": ">=0.40.0",
|
|
210
239
|
"@opentelemetry/sdk-node": ">=0.50.0",
|
|
211
240
|
"@sinclair/typebox": "^0.34.0",
|
|
212
|
-
"better-auth": ">=1.
|
|
241
|
+
"better-auth": ">=1.5.5",
|
|
213
242
|
"bullmq": "^5.0.0",
|
|
214
243
|
"fastify": "^5.7.4",
|
|
215
244
|
"fastify-raw-body": "^5.0.0",
|
|
@@ -297,6 +326,9 @@
|
|
|
297
326
|
},
|
|
298
327
|
"zod": {
|
|
299
328
|
"optional": true
|
|
329
|
+
},
|
|
330
|
+
"@modelcontextprotocol/sdk": {
|
|
331
|
+
"optional": true
|
|
300
332
|
}
|
|
301
333
|
},
|
|
302
334
|
"dependencies": {
|
|
@@ -304,11 +336,13 @@
|
|
|
304
336
|
"qs": "^6.14.1"
|
|
305
337
|
},
|
|
306
338
|
"devDependencies": {
|
|
307
|
-
"@
|
|
339
|
+
"@biomejs/biome": "^2.4.10",
|
|
340
|
+
"@classytic/mongokit": "^3.4.3",
|
|
308
341
|
"@fastify/jwt": "^10.0.0",
|
|
309
342
|
"@fastify/multipart": "^9.0.0",
|
|
310
343
|
"@fastify/type-provider-typebox": "^6.0.0",
|
|
311
344
|
"@fastify/websocket": "^11.0.0",
|
|
345
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
312
346
|
"@sinclair/typebox": "^0.34.0",
|
|
313
347
|
"@types/node": "^22.10.0",
|
|
314
348
|
"@types/qs": "^6.14.0",
|
|
@@ -317,8 +351,8 @@
|
|
|
317
351
|
"jsonwebtoken": "^9.0.0",
|
|
318
352
|
"mongodb": "^7.1.0",
|
|
319
353
|
"mongodb-memory-server": "^11.0.1",
|
|
320
|
-
"tsdown": "^0.
|
|
321
|
-
"typescript": "^
|
|
354
|
+
"tsdown": "^0.21.7",
|
|
355
|
+
"typescript": "^6.0.2",
|
|
322
356
|
"vitest": "^3.0.0",
|
|
323
357
|
"ws": "^8.0.0",
|
|
324
358
|
"zod": "^4.3.6"
|
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: arc
|
|
3
|
+
description: |
|
|
4
|
+
@classytic/arc — Resource-oriented backend framework for Fastify.
|
|
5
|
+
Use when building REST APIs with Fastify, resource CRUD, defineResource, createApp,
|
|
6
|
+
permissions, presets, database adapters, hooks, events, QueryCache, authentication,
|
|
7
|
+
multi-tenant SaaS, OpenAPI, job queues, WebSocket, MCP tools, or production deployment.
|
|
8
|
+
Triggers: arc, fastify resource, defineResource, createApp, BaseController, arc preset,
|
|
9
|
+
arc auth, arc events, arc jobs, arc websocket, arc mcp, arc plugin, arc testing, arc cli,
|
|
10
|
+
arc permissions, arc hooks, arc pipeline, arc factory, arc cache, arc QueryCache.
|
|
11
|
+
version: 2.4.2
|
|
12
|
+
license: MIT
|
|
13
|
+
metadata:
|
|
14
|
+
author: Classytic
|
|
15
|
+
version: "2.4.1"
|
|
16
|
+
tags:
|
|
17
|
+
- fastify
|
|
18
|
+
- rest-api
|
|
19
|
+
- resource-framework
|
|
20
|
+
- crud
|
|
21
|
+
- permissions
|
|
22
|
+
- multi-tenant
|
|
23
|
+
- presets
|
|
24
|
+
- typescript
|
|
25
|
+
- cache
|
|
26
|
+
- events
|
|
27
|
+
- openapi
|
|
28
|
+
progressive_disclosure:
|
|
29
|
+
entry_point:
|
|
30
|
+
summary: "Resource-oriented Fastify framework: defineResource(), presets, permissions, QueryCache, events, multi-tenant, OpenAPI"
|
|
31
|
+
when_to_use: "Building REST APIs with Fastify, resource CRUD, authentication, presets, caching, events, or production deployment"
|
|
32
|
+
quick_start: "1. npm install @classytic/arc fastify 2. createApp({ preset: 'production', auth: { type: 'jwt', jwt: { secret } } }) 3. defineResource({ name, adapter, presets, permissions })"
|
|
33
|
+
context_limit: 700
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
# @classytic/arc
|
|
37
|
+
|
|
38
|
+
Resource-oriented backend framework for Fastify. Database-agnostic, tree-shakable, production-ready.
|
|
39
|
+
|
|
40
|
+
**Requires:** Fastify `^5.7.4` | Node.js `>=22` | ESM only
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Install the Arc agent skill (Claude Code / AI agents)
|
|
46
|
+
npx skills add classytic/arc
|
|
47
|
+
|
|
48
|
+
# Install the npm package
|
|
49
|
+
npm install @classytic/arc fastify
|
|
50
|
+
npm install @classytic/mongokit mongoose # MongoDB adapter
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { createApp } from '@classytic/arc/factory';
|
|
57
|
+
import mongoose from 'mongoose';
|
|
58
|
+
|
|
59
|
+
await mongoose.connect(process.env.DB_URI);
|
|
60
|
+
|
|
61
|
+
const app = await createApp({
|
|
62
|
+
preset: 'production',
|
|
63
|
+
auth: { type: 'jwt', jwt: { secret: process.env.JWT_SECRET } },
|
|
64
|
+
cors: { origin: process.env.ALLOWED_ORIGINS?.split(',') },
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
await app.register(productResource.toPlugin());
|
|
68
|
+
await app.listen({ port: 8040, host: '0.0.0.0' });
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## defineResource()
|
|
72
|
+
|
|
73
|
+
Single API to define a full REST resource:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { defineResource, createMongooseAdapter, allowPublic, requireRoles } from '@classytic/arc';
|
|
77
|
+
|
|
78
|
+
const productResource = defineResource({
|
|
79
|
+
name: 'product',
|
|
80
|
+
adapter: createMongooseAdapter({ model: ProductModel, repository: productRepo }),
|
|
81
|
+
controller: productController, // optional — auto-created if omitted
|
|
82
|
+
presets: ['softDelete', 'slugLookup', { name: 'multiTenant', tenantField: 'orgId' }],
|
|
83
|
+
permissions: {
|
|
84
|
+
list: allowPublic(),
|
|
85
|
+
get: allowPublic(),
|
|
86
|
+
create: requireRoles(['admin']),
|
|
87
|
+
update: requireRoles(['admin']),
|
|
88
|
+
delete: requireRoles(['admin']),
|
|
89
|
+
},
|
|
90
|
+
cache: { staleTime: 30, gcTime: 300, tags: ['catalog'] },
|
|
91
|
+
additionalRoutes: [
|
|
92
|
+
{ method: 'GET', path: '/featured', handler: 'getFeatured', permissions: allowPublic(), wrapHandler: true },
|
|
93
|
+
],
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
await fastify.register(productResource.toPlugin());
|
|
97
|
+
// Auto-generates: GET /, GET /:id, POST /, PATCH /:id, DELETE /:id
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Authentication
|
|
101
|
+
|
|
102
|
+
Auth uses a **discriminated union** with `type` field:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Arc JWT (with optional token extraction and revocation)
|
|
106
|
+
auth: {
|
|
107
|
+
type: 'jwt',
|
|
108
|
+
jwt: { secret, expiresIn: '15m', refreshSecret, refreshExpiresIn: '7d' },
|
|
109
|
+
tokenExtractor: (req) => req.cookies?.['auth-token'] ?? null, // optional
|
|
110
|
+
isRevoked: async (decoded) => redis.sismember('revoked', decoded.jti), // optional
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Better Auth (recommended for SaaS with orgs)
|
|
114
|
+
import { createBetterAuthAdapter } from '@classytic/arc/auth';
|
|
115
|
+
auth: { type: 'betterAuth', betterAuth: createBetterAuthAdapter({ auth, orgContext: true }) }
|
|
116
|
+
|
|
117
|
+
// Custom Fastify plugin (must decorate fastify.authenticate)
|
|
118
|
+
auth: { type: 'custom', plugin: myAuthPlugin }
|
|
119
|
+
|
|
120
|
+
// Custom function (decorates fastify.authenticate directly)
|
|
121
|
+
auth: { type: 'authenticator', authenticate: async (req, reply) => { ... } }
|
|
122
|
+
|
|
123
|
+
// Disabled
|
|
124
|
+
auth: false
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Decorates:** `app.authenticate`, `app.optionalAuthenticate`, `app.authorize`
|
|
128
|
+
|
|
129
|
+
## Permissions
|
|
130
|
+
|
|
131
|
+
Function-based. A `PermissionCheck` returns `boolean | { granted, reason?, filters? }`:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import {
|
|
135
|
+
allowPublic, requireAuth, requireRoles, requireOwnership,
|
|
136
|
+
requireOrgMembership, requireOrgRole, requireTeamMembership,
|
|
137
|
+
allOf, anyOf, when, denyAll,
|
|
138
|
+
createDynamicPermissionMatrix,
|
|
139
|
+
} from '@classytic/arc';
|
|
140
|
+
|
|
141
|
+
permissions: {
|
|
142
|
+
list: allowPublic(),
|
|
143
|
+
get: requireAuth(),
|
|
144
|
+
create: requireRoles(['admin', 'editor']),
|
|
145
|
+
update: anyOf(requireOwnership('userId'), requireRoles(['admin'])),
|
|
146
|
+
delete: allOf(requireAuth(), requireRoles(['admin'])),
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Custom permission:**
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
const requirePro = (): PermissionCheck => async (ctx) => {
|
|
154
|
+
if (!ctx.user) return { granted: false, reason: 'Auth required' };
|
|
155
|
+
return { granted: ctx.user.plan === 'pro' };
|
|
156
|
+
};
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Field-level permissions:**
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { fields } from '@classytic/arc';
|
|
163
|
+
|
|
164
|
+
fields: {
|
|
165
|
+
password: fields.hidden(),
|
|
166
|
+
salary: fields.visibleTo(['admin', 'hr']),
|
|
167
|
+
role: fields.writableBy(['admin']),
|
|
168
|
+
email: fields.redactFor(['viewer'], '***'),
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Dynamic ACL (DB-managed):**
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
const acl = createDynamicPermissionMatrix({
|
|
176
|
+
resolveRolePermissions: async (ctx) => aclService.getRoleMatrix(orgId),
|
|
177
|
+
cacheStore: new RedisCacheStore({ client: redis, prefix: 'acl:' }),
|
|
178
|
+
});
|
|
179
|
+
permissions: { list: acl.canAction('product', 'read') }
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Presets
|
|
183
|
+
|
|
184
|
+
| Preset | Routes Added | Controller Interface | Config |
|
|
185
|
+
|--------|-------------|---------------------|--------|
|
|
186
|
+
| `softDelete` | GET /deleted, POST /:id/restore | `ISoftDeleteController` | `{ deletedField }` |
|
|
187
|
+
| `slugLookup` | GET /slug/:slug | `ISlugLookupController` | `{ slugField }` |
|
|
188
|
+
| `tree` | GET /tree, GET /:parent/children | `ITreeController` | `{ parentField }` |
|
|
189
|
+
| `ownedByUser` | none (middleware) | — | `{ ownerField }` |
|
|
190
|
+
| `multiTenant` | none (middleware) | — | `{ tenantField }` |
|
|
191
|
+
| `audited` | none (middleware) | — | — |
|
|
192
|
+
| `bulk` | POST/PATCH/DELETE /bulk | — | `{ operations?, maxCreateItems? }` |
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
presets: ['softDelete', { name: 'multiTenant', tenantField: 'organizationId' }]
|
|
196
|
+
// Bulk: presets: ['bulk'] or bulkPreset({ operations: ['createMany', 'updateMany'] })
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## QueryCache
|
|
200
|
+
|
|
201
|
+
TanStack Query-inspired server cache with stale-while-revalidate and auto-invalidation on mutations.
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
// Enable globally
|
|
205
|
+
const app = await createApp({ arcPlugins: { queryCache: true } });
|
|
206
|
+
|
|
207
|
+
// Per-resource config
|
|
208
|
+
defineResource({
|
|
209
|
+
name: 'product',
|
|
210
|
+
cache: {
|
|
211
|
+
staleTime: 30, // seconds fresh (no revalidation)
|
|
212
|
+
gcTime: 300, // seconds stale data kept (SWR window)
|
|
213
|
+
tags: ['catalog'], // cross-resource grouping
|
|
214
|
+
invalidateOn: { 'category.*': ['catalog'] }, // event pattern → tag targets
|
|
215
|
+
list: { staleTime: 60 }, // per-operation override
|
|
216
|
+
byId: { staleTime: 10 },
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Auto-invalidation:** POST/PATCH/DELETE bumps resource version. Old cached queries expire naturally via TTL.
|
|
222
|
+
|
|
223
|
+
**Runtime modes:** `memory` (default, zero-config) | `distributed` (requires `stores.queryCache: RedisCacheStore`)
|
|
224
|
+
|
|
225
|
+
**Response header:** `x-cache: HIT | STALE | MISS`
|
|
226
|
+
|
|
227
|
+
## BaseController
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { BaseController } from '@classytic/arc';
|
|
231
|
+
import type { IRequestContext, IControllerResponse } from '@classytic/arc';
|
|
232
|
+
|
|
233
|
+
class ProductController extends BaseController<Product> {
|
|
234
|
+
constructor() { super(productRepo); }
|
|
235
|
+
|
|
236
|
+
async getFeatured(req: IRequestContext): Promise<IControllerResponse> {
|
|
237
|
+
const products = await this.repository.getAll({ filters: { isFeatured: true } });
|
|
238
|
+
return { success: true, data: products };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**IRequestContext:** `{ params, query, body, user, headers, context, metadata, server }` — `user` is `Record<string, unknown> | undefined` (guard with `if (req.user)` on public routes)
|
|
244
|
+
|
|
245
|
+
**IControllerResponse:** `{ success, data?, error?, status?, meta?, headers? }`
|
|
246
|
+
|
|
247
|
+
## Adapters (Database-Agnostic)
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// Mongoose
|
|
251
|
+
import { createMongooseAdapter } from '@classytic/arc';
|
|
252
|
+
const adapter = createMongooseAdapter({ model: ProductModel, repository: productRepo });
|
|
253
|
+
|
|
254
|
+
// Custom adapter — implement CrudRepository interface:
|
|
255
|
+
interface CrudRepository<TDoc> {
|
|
256
|
+
getAll(params?): Promise<TDoc[] | PaginatedResult<TDoc>>;
|
|
257
|
+
getById(id: string): Promise<TDoc | null>;
|
|
258
|
+
create(data): Promise<TDoc>;
|
|
259
|
+
update(id: string, data): Promise<TDoc | null>;
|
|
260
|
+
delete(id: string): Promise<boolean>;
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Events
|
|
265
|
+
|
|
266
|
+
The factory auto-registers `eventPlugin` — no manual setup needed:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// createApp() registers eventPlugin automatically (default: MemoryEventTransport)
|
|
270
|
+
const app = await createApp({
|
|
271
|
+
stores: { events: new RedisEventTransport(redis) }, // optional, defaults to memory
|
|
272
|
+
arcPlugins: {
|
|
273
|
+
events: { // event plugin config (default: true, false to disable)
|
|
274
|
+
logEvents: true,
|
|
275
|
+
retry: { maxRetries: 3, backoffMs: 1000 },
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
await app.events.publish('order.created', { orderId: '123' });
|
|
281
|
+
await app.events.subscribe('order.*', async (event) => { ... });
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
CRUD events auto-emit: `{resource}.created`, `{resource}.updated`, `{resource}.deleted`.
|
|
285
|
+
|
|
286
|
+
**Transports:** Memory (default) | Redis Pub/Sub (fire-and-forget) | Redis Streams (durable, at-least-once, consumer groups, DLQ)
|
|
287
|
+
|
|
288
|
+
**Event Outbox** — at-least-once delivery via transactional outbox pattern. Arc ships `OutboxStore` interface + `MemoryOutboxStore` (dev). You implement the store for your DB (Mongoose, Drizzle, Knex, etc.). Cleanup via optional `purge()` contract or native DB tools (TTL index, pg_cron, key expiry).
|
|
289
|
+
|
|
290
|
+
## Factory — createApp()
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
const app = await createApp({
|
|
294
|
+
preset: 'production', // production | development | testing | edge
|
|
295
|
+
runtime: 'memory', // memory (default) | distributed
|
|
296
|
+
auth: { type: 'jwt', jwt: { secret } },
|
|
297
|
+
cors: { origin: ['https://myapp.com'] },
|
|
298
|
+
helmet: true, // false to disable
|
|
299
|
+
rateLimit: { max: 100 }, // false to disable
|
|
300
|
+
ajv: { keywords: ['x-internal'] }, // custom AJV keywords for schema validation
|
|
301
|
+
arcPlugins: {
|
|
302
|
+
events: true, // event plugin (default: true, false to disable)
|
|
303
|
+
emitEvents: true, // CRUD event emission (default: true)
|
|
304
|
+
queryCache: true, // server cache (default: false)
|
|
305
|
+
sse: true, // SSE streaming (default: false)
|
|
306
|
+
caching: true, // ETag + Cache-Control (default: false)
|
|
307
|
+
},
|
|
308
|
+
stores: { // required when runtime: 'distributed'
|
|
309
|
+
events: new RedisEventTransport({ client: redis }),
|
|
310
|
+
queryCache: new RedisCacheStore({ client: redis }),
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Hooks
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { createHookSystem, beforeCreate, afterUpdate } from '@classytic/arc/hooks';
|
|
319
|
+
|
|
320
|
+
const hooks = createHookSystem();
|
|
321
|
+
beforeCreate(hooks, 'product', async (ctx) => { ctx.data.slug = slugify(ctx.data.name); });
|
|
322
|
+
afterUpdate(hooks, 'product', async (ctx) => { await invalidateCache(ctx.result._id); });
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## Pipeline
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
import { guard, transform, intercept } from '@classytic/arc';
|
|
329
|
+
|
|
330
|
+
defineResource({
|
|
331
|
+
pipe: {
|
|
332
|
+
create: [
|
|
333
|
+
guard('verified', async (ctx) => ctx.user?.verified === true),
|
|
334
|
+
transform('inject', async (ctx) => { ctx.body.createdBy = ctx.user._id; }),
|
|
335
|
+
],
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Query Parsing
|
|
341
|
+
|
|
342
|
+
Arc's default parser handles filters, sort, select, populate, and pagination. Swap in MongoKit's `QueryParser` for $lookup joins.
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
GET /products?page=2&limit=20&sort=-createdAt&select=name,price
|
|
346
|
+
GET /products?price[gte]=100&status[in]=active,featured&search=keyword
|
|
347
|
+
GET /products?after=<cursor_id>&limit=20 # keyset pagination
|
|
348
|
+
GET /products?populate=category # ref-based populate
|
|
349
|
+
GET /products?populate[category][select]=name,slug # populate with field select
|
|
350
|
+
GET /products?populate[category][select]=-internal # exclude fields
|
|
351
|
+
GET /products?populate[category][match][isActive]=true # populate with filter
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**Lookup/join (no refs — $lookup via MongoKit QueryParser):**
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
GET /products?lookup[cat][from]=categories&lookup[cat][localField]=categorySlug&lookup[cat][foreignField]=slug&lookup[cat][single]=true
|
|
358
|
+
GET /products?lookup[cat][from]=categories&...&lookup[cat][select]=name,slug
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Operators: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, `like`, `regex`, `exists`
|
|
362
|
+
|
|
363
|
+
**Custom query parser (e.g., MongoKit for $lookup support):**
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
import { QueryParser } from '@classytic/mongokit';
|
|
367
|
+
|
|
368
|
+
defineResource({
|
|
369
|
+
name: 'product',
|
|
370
|
+
adapter: createMongooseAdapter({ model: ProductModel, repository: productRepo }),
|
|
371
|
+
queryParser: new QueryParser(), // enables lookup, advanced populate, keyset pagination
|
|
372
|
+
schemaOptions: {
|
|
373
|
+
query: {
|
|
374
|
+
allowedPopulate: ['category', 'brand'], // whitelist populate paths
|
|
375
|
+
allowedLookups: ['categories', 'brands'], // whitelist lookup collections
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## Error Classes
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
import { ArcError, NotFoundError, ValidationError, UnauthorizedError, ForbiddenError } from '@classytic/arc';
|
|
385
|
+
throw new NotFoundError('Product not found'); // 404
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## Compensating Transaction
|
|
389
|
+
|
|
390
|
+
In-process rollback for multi-step operations. Not a distributed saga — use Temporal/Streamline for that.
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
import { withCompensation } from '@classytic/arc/utils';
|
|
394
|
+
|
|
395
|
+
const result = await withCompensation('checkout', [
|
|
396
|
+
{ name: 'reserve', execute: reserveStock, compensate: releaseStock },
|
|
397
|
+
{ name: 'charge', execute: chargeCard, compensate: refundCard },
|
|
398
|
+
{ name: 'notify', execute: sendEmail, fireAndForget: true }, // non-blocking
|
|
399
|
+
], { orderId }, {
|
|
400
|
+
onStepComplete: (name, res) => fastify.events.publish(`checkout.${name}.done`, res),
|
|
401
|
+
});
|
|
402
|
+
// result: { success, completedSteps, results, failedStep?, error?, compensationErrors? }
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## CLI
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
arc init my-api --mongokit --better-auth --ts
|
|
409
|
+
arc generate resource product # standard resource
|
|
410
|
+
arc generate resource product --mcp # resource + MCP tools file
|
|
411
|
+
arc generate mcp analytics # standalone MCP tools file
|
|
412
|
+
arc docs ./openapi.json --entry ./dist/index.js
|
|
413
|
+
arc introspect --entry ./dist/index.js
|
|
414
|
+
arc doctor
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
Set `"mcp": true` in `.arcrc` to always generate `.mcp.ts` files with resources.
|
|
418
|
+
|
|
419
|
+
## MCP (AI Agent Tools)
|
|
420
|
+
|
|
421
|
+
Expose Arc resources as MCP tools for AI agents. Stateless by default — fresh server per request, zero session overhead.
|
|
422
|
+
|
|
423
|
+
See [mcp reference](references/mcp.md) for full details.
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
import { mcpPlugin } from '@classytic/arc/mcp';
|
|
427
|
+
|
|
428
|
+
// Stateless (default) — production-ready, scalable
|
|
429
|
+
await app.register(mcpPlugin, {
|
|
430
|
+
resources: [productResource, orderResource],
|
|
431
|
+
auth: false, // or: getAuth() | custom function
|
|
432
|
+
exclude: ['credential'],
|
|
433
|
+
overrides: { product: { operations: ['list', 'get'] } },
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// Stateful — when you need server-initiated messages
|
|
437
|
+
await app.register(mcpPlugin, { resources, stateful: true, sessionTtlMs: 600000 });
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Connect Claude CLI: `claude mcp add --transport http my-api http://localhost:3000/mcp`
|
|
441
|
+
|
|
442
|
+
**Auth** — three modes, user chooses: `false` | `getAuth()` (Better Auth OAuth 2.1) | custom function:
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
auth: async (headers) => {
|
|
446
|
+
if (headers['x-api-key'] !== process.env.MCP_KEY) return null;
|
|
447
|
+
return { userId: 'bot', organizationId: 'org-1', roles: ['admin'] };
|
|
448
|
+
},
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
**Guards** for custom tools: `guard(requireAuth, requireOrg, requireRole('admin'), handler)`
|
|
452
|
+
|
|
453
|
+
**Multi-tenancy**: `organizationId` from auth flows into BaseController org-scoping automatically.
|
|
454
|
+
|
|
455
|
+
**Permission filters**: `PermissionResult.filters` from resource permissions flow into MCP tools — same as REST. Define once, works everywhere:
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
permissions: {
|
|
459
|
+
list: (ctx) => ({
|
|
460
|
+
granted: !!ctx.user,
|
|
461
|
+
filters: { orgId: ctx.user?.orgId, branchId: ctx.user?.branchId },
|
|
462
|
+
}),
|
|
463
|
+
}
|
|
464
|
+
// MCP tools automatically scope queries by orgId + branchId
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
**Project structure** — custom MCP tools co-located with resources:
|
|
468
|
+
|
|
469
|
+
```
|
|
470
|
+
src/resources/order/
|
|
471
|
+
order.resource.ts
|
|
472
|
+
order.mcp.ts ← defineTool('fulfill_order', { ... })
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
Generate: `arc generate resource order --mcp` | Wire: `extraTools: [fulfillOrderTool]`
|
|
476
|
+
|
|
477
|
+
## Subpath Imports
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
import { defineResource, BaseController, allowPublic } from '@classytic/arc';
|
|
481
|
+
import { createApp } from '@classytic/arc/factory';
|
|
482
|
+
import { MemoryCacheStore, RedisCacheStore, QueryCache } from '@classytic/arc/cache';
|
|
483
|
+
import { createBetterAuthAdapter, extractBetterAuthOpenApi } from '@classytic/arc/auth';
|
|
484
|
+
import type { ExternalOpenApiPaths } from '@classytic/arc/docs';
|
|
485
|
+
import { eventPlugin } from '@classytic/arc/events';
|
|
486
|
+
import { RedisEventTransport } from '@classytic/arc/events/redis';
|
|
487
|
+
import { healthPlugin, gracefulShutdownPlugin } from '@classytic/arc/plugins';
|
|
488
|
+
import { tracingPlugin } from '@classytic/arc/plugins/tracing';
|
|
489
|
+
import { auditPlugin } from '@classytic/arc/audit';
|
|
490
|
+
import { idempotencyPlugin } from '@classytic/arc/idempotency';
|
|
491
|
+
import { ssePlugin } from '@classytic/arc/plugins';
|
|
492
|
+
import { jobsPlugin } from '@classytic/arc/integrations/jobs';
|
|
493
|
+
import { websocketPlugin } from '@classytic/arc/integrations/websocket';
|
|
494
|
+
import { eventGatewayPlugin } from '@classytic/arc/integrations/event-gateway';
|
|
495
|
+
import { createHookSystem } from '@classytic/arc/hooks';
|
|
496
|
+
import { createTestApp } from '@classytic/arc/testing';
|
|
497
|
+
import { Type, ArcListResponse } from '@classytic/arc/schemas';
|
|
498
|
+
import { createStateMachine, CircuitBreaker, withCompensation, defineCompensation } from '@classytic/arc/utils';
|
|
499
|
+
import { defineMigration } from '@classytic/arc/migrations';
|
|
500
|
+
import { isMember, isElevated, getOrgId, getUserId, getUserRoles } from '@classytic/arc/scope';
|
|
501
|
+
import { createTenantKeyGenerator } from '@classytic/arc/scope';
|
|
502
|
+
import { createRoleHierarchy } from '@classytic/arc/permissions';
|
|
503
|
+
import { createServiceClient } from '@classytic/arc/rpc';
|
|
504
|
+
import { metricsPlugin, versioningPlugin } from '@classytic/arc/plugins';
|
|
505
|
+
import { webhookPlugin } from '@classytic/arc/integrations/webhooks';
|
|
506
|
+
import { mcpPlugin, createMcpServer, defineTool, definePrompt, fieldRulesToZod, resourceToTools } from '@classytic/arc/mcp';
|
|
507
|
+
import { EventOutbox, MemoryOutboxStore } from '@classytic/arc/events';
|
|
508
|
+
import { bulkPreset } from '@classytic/arc/presets';
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
## References (Progressive Disclosure)
|
|
512
|
+
|
|
513
|
+
- **[auth](references/auth.md)** — JWT, Better Auth, API key auth, custom auth, multi-tenant
|
|
514
|
+
- **[events](references/events.md)** — Domain events, transports, retry, outbox pattern, auto-emission
|
|
515
|
+
- **[integrations](references/integrations.md)** — BullMQ jobs, WebSocket, EventGateway, Streamline, Webhooks
|
|
516
|
+
- **[mcp](references/mcp.md)** — MCP tools for AI agents, auto-generation from resources, custom tools, Better Auth OAuth 2.1
|
|
517
|
+
- **[production](references/production.md)** — Health, audit, idempotency, tracing, metrics, versioning, SSE, QueryCache, bulk ops, saga, RPC schema versioning, tenant rate limiting
|
|
518
|
+
- **[testing](references/testing.md)** — Test app, mocks, data factories, in-memory MongoDB
|