@classytic/arc 2.4.3 → 2.6.1
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 +22 -6
- package/dist/{BaseController-CkM5dUh_.mjs → BaseController-AbbRx3e0.mjs} +5 -2
- package/dist/adapters/index.d.mts +2 -2
- package/dist/adapters/index.mjs +1 -1
- package/dist/{adapters-DTC4Ug66.mjs → adapters-CTn28N4y.mjs} +72 -11
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +11 -1
- package/dist/audit/mongodb.d.mts +1 -1
- package/dist/auth/index.d.mts +1 -1
- package/dist/auth/index.mjs +2 -2
- package/dist/cli/commands/init.mjs +12 -9
- package/dist/core/index.d.mts +2 -2
- package/dist/core/index.mjs +2 -2
- package/dist/{createApp-CBgVaFyh.mjs → createApp-Bol7DLUf.mjs} +404 -279
- package/dist/{defineResource-B22gcNvn.mjs → defineResource-bVKHjQzE.mjs} +116 -19
- package/dist/discovery/index.mjs +1 -1
- package/dist/docs/index.d.mts +1 -1
- package/dist/dynamic/index.d.mts +1 -1
- package/dist/dynamic/index.mjs +2 -2
- package/dist/{elevation-Ca_yveIO.d.mts → elevation-C_taLQrM.d.mts} +27 -1
- package/dist/{errorHandler-DMbGdzBG.mjs → errorHandler-r2595m8T.mjs} +1 -1
- package/dist/{errors-CPpvPHT0.d.mts → errors-CcVbl1-T.d.mts} +17 -1
- package/dist/{errors-rxhfP7Hf.mjs → errors-NoQKsbAT.mjs} +23 -1
- package/dist/{eventPlugin-iGrSEmwJ.d.mts → eventPlugin-DW45v4V5.d.mts} +30 -2
- package/dist/events/index.d.mts +2 -2
- package/dist/events/index.mjs +40 -10
- package/dist/factory/index.d.mts +44 -23
- package/dist/factory/index.mjs +136 -2
- package/dist/hooks/index.d.mts +1 -1
- package/dist/idempotency/index.d.mts +3 -3
- package/dist/idempotency/mongodb.d.mts +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-yhxyjqNb.d.mts → index-BIsZ_su5.d.mts} +4 -8
- package/dist/{index-BL8CaQih.d.mts → index-Cb3gtbg7.d.mts} +2 -2
- package/dist/{index-Diqcm14c.d.mts → index-NGZksqM5.d.mts} +30 -1
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +8 -7
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +1 -1
- package/dist/integrations/mcp/index.d.mts +4 -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-DGmPxakH.d.mts → interface-DDW43OmS.d.mts} +194 -13
- package/dist/{mongodb-CUpYfxfD.d.mts → mongodb-kltrBPa1.d.mts} +10 -0
- package/dist/{mongodb-bga9AbkD.d.mts → mongodb-pMvOlR5_.d.mts} +1 -1
- package/dist/org/index.d.mts +1 -1
- package/dist/org/index.mjs +1 -1
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +2 -2
- package/dist/{permissions-Jk5x3sxz.mjs → permissions-C8ImI8gC.mjs} +44 -2
- package/dist/plugins/index.d.mts +1 -1
- package/dist/plugins/index.mjs +3 -3
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +1 -1
- package/dist/{presets-OMPaHMTY.mjs → presets-BMfdy34e.mjs} +2 -2
- package/dist/{redis-CQ5YxMC5.d.mts → redis-D0Qc-9EW.d.mts} +1 -1
- package/dist/registry/index.d.mts +1 -1
- package/dist/{resourceToTools-PMFE8HIv.mjs → resourceToTools-DH3c3e-T.mjs} +81 -7
- package/dist/scope/index.d.mts +2 -2
- package/dist/scope/index.mjs +2 -2
- package/dist/{sse-BkViJPlT.mjs → sse-BF7GR7IB.mjs} +1 -1
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +1 -1
- package/dist/types/index.d.mts +3 -3
- package/dist/types/index.mjs +23 -2
- package/dist/{types-C6TQjtdi.mjs → types-BhtYdxZU.mjs} +26 -1
- package/dist/{types-Dt0-AI6E.d.mts → types-D5hJ-k_3.d.mts} +189 -6
- package/dist/{types-BJmgxNbF.d.mts → types-D5rjsS_i.d.mts} +1 -1
- package/dist/utils/index.d.mts +2 -2
- package/dist/utils/index.mjs +1 -1
- package/package.json +6 -5
- package/skills/arc/SKILL.md +104 -4
- package/skills/arc/references/mcp.md +160 -2
- /package/dist/{interface-B4awm1RJ.d.mts → interface-gr-7qo9j.d.mts} +0 -0
|
@@ -12,11 +12,34 @@ npm install @modelcontextprotocol/sdk zod
|
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
14
|
import { mcpPlugin } from '@classytic/arc/mcp';
|
|
15
|
+
import { createApp, loadResources } from '@classytic/arc/factory';
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
// Option A: Explicit resources
|
|
18
|
+
const app = await createApp({
|
|
17
19
|
resources: [productResource, taskResource],
|
|
18
20
|
auth: false,
|
|
19
|
-
|
|
21
|
+
plugins: async (f) => {
|
|
22
|
+
await f.register(mcpPlugin, { resources: [productResource, taskResource], auth: false });
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Option B: Auto-discover from directory
|
|
27
|
+
const resources = await loadResources('./src/resources');
|
|
28
|
+
const app = await createApp({
|
|
29
|
+
resources,
|
|
30
|
+
plugins: async (f) => {
|
|
31
|
+
await f.register(mcpPlugin, { resources, auth: false });
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Per-resource overrides:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
await app.register(mcpPlugin, {
|
|
40
|
+
resources,
|
|
41
|
+
auth: false,
|
|
42
|
+
include: ['product', 'order'], // only these get MCP tools
|
|
20
43
|
overrides: { product: { operations: ['list', 'get'] } },
|
|
21
44
|
});
|
|
22
45
|
```
|
|
@@ -429,3 +452,138 @@ await app.register(mcpPlugin, {
|
|
|
429
452
|
- `DELETE /mcp` — terminates session
|
|
430
453
|
|
|
431
454
|
Sessions: lazily created, TTL-cached, LRU-evicted at max capacity, auto-cleaned on shutdown.
|
|
455
|
+
|
|
456
|
+
## Health Endpoint
|
|
457
|
+
|
|
458
|
+
`GET /mcp/health` — no MCP protocol needed, plain JSON:
|
|
459
|
+
|
|
460
|
+
```json
|
|
461
|
+
{
|
|
462
|
+
"status": "ok",
|
|
463
|
+
"mode": "stateless",
|
|
464
|
+
"tools": 11,
|
|
465
|
+
"resources": 2,
|
|
466
|
+
"toolNames": ["list_products", "get_product", ...],
|
|
467
|
+
"sessions": null
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Use to verify the MCP server is alive before configuring Claude CLI.
|
|
472
|
+
|
|
473
|
+
## DX Helpers (v2.4.4)
|
|
474
|
+
|
|
475
|
+
### ArcRequest — Typed Fastify Request
|
|
476
|
+
|
|
477
|
+
For `wrapHandler: false` routes, use `ArcRequest` instead of `(req as any).user`:
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
import type { ArcRequest } from '@classytic/arc';
|
|
481
|
+
|
|
482
|
+
handler: async (req: ArcRequest, reply) => {
|
|
483
|
+
req.user?.id; // typed
|
|
484
|
+
req.scope.organizationId; // typed (when member)
|
|
485
|
+
req.signal; // AbortSignal (Fastify 5 built-in)
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### envelope() — Response Helper
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
import { envelope } from '@classytic/arc';
|
|
493
|
+
|
|
494
|
+
handler: async (req, reply) => {
|
|
495
|
+
const data = await service.getResults();
|
|
496
|
+
return reply.send(envelope(data));
|
|
497
|
+
// → { success: true, data }
|
|
498
|
+
return reply.send(envelope(data, { total: 100, page: 1 }));
|
|
499
|
+
// → { success: true, data, total: 100, page: 1 }
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### getOrgContext() — Canonical Org Extraction
|
|
504
|
+
|
|
505
|
+
Eliminates duplicated `req.user.organizationId || req.headers['x-organization-id']` patterns:
|
|
506
|
+
|
|
507
|
+
```typescript
|
|
508
|
+
import { getOrgContext } from '@classytic/arc/scope';
|
|
509
|
+
|
|
510
|
+
handler: async (req, reply) => {
|
|
511
|
+
const { userId, organizationId, roles, orgRoles } = getOrgContext(req);
|
|
512
|
+
// Works regardless of auth type (JWT, Better Auth, custom)
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### createDomainError() — Error Factory
|
|
517
|
+
|
|
518
|
+
Eliminates manual `if (err.code) return status` mapping:
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
import { createDomainError } from '@classytic/arc';
|
|
522
|
+
|
|
523
|
+
throw createDomainError('MEMBER_NOT_FOUND', 'Member does not exist', 404);
|
|
524
|
+
throw createDomainError('SELF_REFERRAL', 'Cannot refer yourself', 422);
|
|
525
|
+
throw createDomainError('INSUFFICIENT_BALANCE', 'Not enough credits', 402, { balance: 0 });
|
|
526
|
+
// Arc's error handler auto-maps statusCode to HTTP response
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
### onRegister — Resource Lifecycle Hook
|
|
530
|
+
|
|
531
|
+
Called during plugin registration with the scoped Fastify instance:
|
|
532
|
+
|
|
533
|
+
```typescript
|
|
534
|
+
defineResource({
|
|
535
|
+
name: 'notification',
|
|
536
|
+
onRegister: (fastify) => {
|
|
537
|
+
setSseManager(fastify.sseManager);
|
|
538
|
+
},
|
|
539
|
+
})
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### preAuth — Pre-Auth Handlers for SSE/WebSocket
|
|
543
|
+
|
|
544
|
+
Run before auth middleware. Use for promoting `?token=` to `Authorization` header (EventSource can't set headers):
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
additionalRoutes: [{
|
|
548
|
+
method: 'GET',
|
|
549
|
+
path: '/stream',
|
|
550
|
+
wrapHandler: false,
|
|
551
|
+
permissions: requireAuth(),
|
|
552
|
+
preAuth: [(req) => {
|
|
553
|
+
const token = req.query?.token;
|
|
554
|
+
if (token) req.headers.authorization = `Bearer ${token}`;
|
|
555
|
+
}],
|
|
556
|
+
handler: sseHandler,
|
|
557
|
+
}]
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### streamResponse — SSE Route Flag
|
|
561
|
+
|
|
562
|
+
Auto-sets SSE headers and bypasses Arc's response wrapper:
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
additionalRoutes: [{
|
|
566
|
+
method: 'POST',
|
|
567
|
+
path: '/stream',
|
|
568
|
+
streamResponse: true, // SSE headers + no { success, data } wrapper
|
|
569
|
+
permissions: requireAuth(),
|
|
570
|
+
handler: async (request, reply) => {
|
|
571
|
+
const { stream } = await generateStream({ abortSignal: request.signal });
|
|
572
|
+
return reply.send(stream);
|
|
573
|
+
},
|
|
574
|
+
}]
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
## Test Coverage
|
|
578
|
+
|
|
579
|
+
165 test files, 2439 tests. MCP-specific:
|
|
580
|
+
|
|
581
|
+
| Test File | Tests | Covers |
|
|
582
|
+
|-----------|-------|--------|
|
|
583
|
+
| `mcp-auth-e2e.test.ts` | 16 | All auth modes, multi-tenancy, permission filters, async permissions |
|
|
584
|
+
| `mcp-dx-features.test.ts` | 14 | include, names, prefix, disableDefaultRoutes, mcpHandler, guards, CRUD lifecycle |
|
|
585
|
+
| `resourceToTools.test.ts` | 12 | Tool generation, annotations, field hiding, soft delete |
|
|
586
|
+
| `createMcpServer.test.ts` | 10 | Server creation, tool registration, InMemoryTransport |
|
|
587
|
+
| `guards.test.ts` | 8 | requireAuth, requireOrg, requireRole, customGuard, composition |
|
|
588
|
+
| `dx-features.test.ts` | 17 | envelope, getOrgContext, createDomainError, onRegister, preAuth, streamResponse |
|
|
589
|
+
| Others | 32 | fieldRulesToZod, defineTool, definePrompt, buildRequestContext, sessionCache, authCache |
|
|
File without changes
|