@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/dist/types/index.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { a as getTeamId, c as
|
|
2
|
-
|
|
1
|
+
import { a as getTeamId, c as hasOrgAccess, d as isMember, i as getOrgRoles, l as isAuthenticated, n as PUBLIC_SCOPE, r as getOrgId, t as AUTHENTICATED_SCOPE, u as isElevated } from "../types-C6TQjtdi.mjs";
|
|
3
2
|
//#region src/types/index.ts
|
|
4
3
|
/**
|
|
5
4
|
* Extract user ID from a user object (supports both id and _id)
|
|
@@ -9,6 +8,5 @@ function getUserId(user) {
|
|
|
9
8
|
const id = user.id ?? user._id;
|
|
10
9
|
return id ? String(id) : void 0;
|
|
11
10
|
}
|
|
12
|
-
|
|
13
11
|
//#endregion
|
|
14
|
-
export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
|
|
12
|
+
export { AUTHENTICATED_SCOPE, PUBLIC_SCOPE, getOrgId, getOrgRoles, getTeamId, getUserId, hasOrgAccess, isAuthenticated, isElevated, isMember };
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { Lt as ResourceDefinition } from "./interface-DGmPxakH.mjs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
//#region src/integrations/mcp/types.d.ts
|
|
5
|
+
/** Behavioral hints for MCP clients (tool annotations per MCP spec) */
|
|
6
|
+
interface ToolAnnotations {
|
|
7
|
+
/** Tool only reads data, no side effects */
|
|
8
|
+
readOnlyHint?: boolean;
|
|
9
|
+
/** Tool may perform destructive/irreversible actions */
|
|
10
|
+
destructiveHint?: boolean;
|
|
11
|
+
/** Tool can be safely retried with same input */
|
|
12
|
+
idempotentHint?: boolean;
|
|
13
|
+
/** Tool interacts with external systems beyond this server */
|
|
14
|
+
openWorldHint?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** Context passed to tool handlers at invocation time */
|
|
17
|
+
interface ToolContext {
|
|
18
|
+
/** Session identity — null in no-auth mode */
|
|
19
|
+
session: McpAuthResult | null;
|
|
20
|
+
/** Log to MCP client (best-effort, non-blocking) */
|
|
21
|
+
log: (level: "info" | "warning" | "error" | "debug", message: string) => Promise<void>;
|
|
22
|
+
/** Raw MCP SDK extra context (for advanced use) */
|
|
23
|
+
extra: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* MCP CallToolResult — return type from tool handlers.
|
|
27
|
+
*
|
|
28
|
+
* `content` follows the MCP spec: at minimum a text item, optionally other
|
|
29
|
+
* resource/image content types. The fallback union member allows future
|
|
30
|
+
* MCP spec additions without breaking existing handlers.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
35
|
+
* return { content: [{ type: 'text', text: 'Not found' }], isError: true };
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
interface CallToolResult {
|
|
39
|
+
content: Array<{
|
|
40
|
+
type: "text";
|
|
41
|
+
text: string;
|
|
42
|
+
} | {
|
|
43
|
+
type: "resource";
|
|
44
|
+
resource: {
|
|
45
|
+
uri: string;
|
|
46
|
+
mimeType?: string;
|
|
47
|
+
text?: string;
|
|
48
|
+
};
|
|
49
|
+
} | {
|
|
50
|
+
type: string;
|
|
51
|
+
[key: string]: unknown;
|
|
52
|
+
}>;
|
|
53
|
+
isError?: boolean;
|
|
54
|
+
/** Structured output for typed tool results (MCP spec extension) */
|
|
55
|
+
structuredContent?: unknown;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Output of defineTool() — plain data, not yet registered on a server.
|
|
59
|
+
*
|
|
60
|
+
* `inputSchema` is a flat Zod shape `{ name: z.string(), age: z.number() }` —
|
|
61
|
+
* the SDK wraps it in z.object() internally. Do NOT pass z.object() here.
|
|
62
|
+
*/
|
|
63
|
+
interface ToolDefinition {
|
|
64
|
+
name: string;
|
|
65
|
+
description: string;
|
|
66
|
+
title?: string;
|
|
67
|
+
/** Flat Zod shape: `{ field: z.string() }`. NOT z.object(). */
|
|
68
|
+
inputSchema?: Record<string, z.ZodTypeAny>;
|
|
69
|
+
/** Flat Zod shape for structured output validation */
|
|
70
|
+
outputSchema?: Record<string, z.ZodTypeAny>;
|
|
71
|
+
annotations?: ToolAnnotations;
|
|
72
|
+
handler: (input: Record<string, unknown>, ctx: ToolContext) => Promise<CallToolResult>;
|
|
73
|
+
}
|
|
74
|
+
/** Output of definePrompt() — plain data, not yet registered */
|
|
75
|
+
interface PromptDefinition {
|
|
76
|
+
name: string;
|
|
77
|
+
description: string;
|
|
78
|
+
title?: string;
|
|
79
|
+
/** Flat Zod shape for prompt arguments */
|
|
80
|
+
argsSchema?: Record<string, z.ZodTypeAny>;
|
|
81
|
+
handler: (args: Record<string, unknown>) => PromptResult;
|
|
82
|
+
}
|
|
83
|
+
/** Prompt handler return type */
|
|
84
|
+
interface PromptResult {
|
|
85
|
+
messages: Array<{
|
|
86
|
+
role: "user" | "assistant";
|
|
87
|
+
content: {
|
|
88
|
+
type: "text";
|
|
89
|
+
text: string;
|
|
90
|
+
} | {
|
|
91
|
+
type: string;
|
|
92
|
+
[key: string]: unknown;
|
|
93
|
+
};
|
|
94
|
+
}>;
|
|
95
|
+
}
|
|
96
|
+
/** Per-resource MCP configuration overrides */
|
|
97
|
+
interface McpResourceConfig {
|
|
98
|
+
/** Which CRUD operations to expose (default: all enabled on the resource) */
|
|
99
|
+
operations?: CrudOperation[];
|
|
100
|
+
/** Override tool descriptions per operation */
|
|
101
|
+
descriptions?: Partial<Record<CrudOperation, string>>;
|
|
102
|
+
/** Fields to hide from MCP tool schemas (beyond schemaOptions.hiddenFields) */
|
|
103
|
+
hideFields?: string[];
|
|
104
|
+
/** Per-operation tool name overrides: `{ get: 'get_job_by_id' }` */
|
|
105
|
+
names?: Partial<Record<CrudOperation, string>>;
|
|
106
|
+
/** Per-resource tool name prefix (overrides global `toolNamePrefix`): `'db'` → `db_list_jobs` */
|
|
107
|
+
toolNamePrefix?: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Auth resolver function — user provides their own auth logic.
|
|
111
|
+
* Receives request headers, returns identity or null (unauthorized).
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* // API key auth
|
|
116
|
+
* auth: async (headers) => {
|
|
117
|
+
* if (headers['x-api-key'] !== process.env.MCP_API_KEY) return null;
|
|
118
|
+
* return { userId: 'service-account', organizationId: 'org-123' };
|
|
119
|
+
* },
|
|
120
|
+
*
|
|
121
|
+
* // Static org (trusted internal network)
|
|
122
|
+
* auth: async () => ({ userId: 'internal', organizationId: 'org-main' }),
|
|
123
|
+
*
|
|
124
|
+
* // Gateway-validated JWT (token already verified by API gateway)
|
|
125
|
+
* auth: async (headers) => {
|
|
126
|
+
* const userId = headers['x-user-id'];
|
|
127
|
+
* const orgId = headers['x-org-id'];
|
|
128
|
+
* return userId ? { userId, organizationId: orgId } : null;
|
|
129
|
+
* },
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
type McpAuthResolver = (headers: Record<string, string | undefined>) => Promise<McpAuthResult | null> | McpAuthResult | null;
|
|
133
|
+
/**
|
|
134
|
+
* mcpPlugin() options — Fastify plugin config.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* // No auth (dev/testing)
|
|
139
|
+
* await app.register(mcpPlugin, { resources, auth: false });
|
|
140
|
+
*
|
|
141
|
+
* // Better Auth OAuth 2.1
|
|
142
|
+
* await app.register(mcpPlugin, { resources, auth: getAuth() });
|
|
143
|
+
*
|
|
144
|
+
* // Custom auth function (API key, gateway headers, etc.)
|
|
145
|
+
* await app.register(mcpPlugin, {
|
|
146
|
+
* resources,
|
|
147
|
+
* auth: async (headers) => {
|
|
148
|
+
* if (headers['x-api-key'] !== process.env.MCP_KEY) return null;
|
|
149
|
+
* return { userId: 'bot', organizationId: 'org-1' };
|
|
150
|
+
* },
|
|
151
|
+
* });
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
interface McpPluginOptions {
|
|
155
|
+
/** Arc resources to expose as MCP tools */
|
|
156
|
+
resources: ResourceDefinition[];
|
|
157
|
+
/**
|
|
158
|
+
* Auth mode:
|
|
159
|
+
* - `false` — no auth, anonymous access (default)
|
|
160
|
+
* - `BetterAuthHandler` — OAuth 2.1 via Better Auth's mcp() plugin
|
|
161
|
+
* - `McpAuthResolver` — custom function that resolves identity from headers
|
|
162
|
+
*/
|
|
163
|
+
auth?: BetterAuthHandler | McpAuthResolver | false;
|
|
164
|
+
/** MCP endpoint path (default: '/mcp') */
|
|
165
|
+
prefix?: string;
|
|
166
|
+
/** Server identity */
|
|
167
|
+
serverName?: string;
|
|
168
|
+
serverVersion?: string;
|
|
169
|
+
/** Instructions for the LLM — guidance on tool usage, constraints */
|
|
170
|
+
instructions?: string;
|
|
171
|
+
/** Resources to exclude by name (ignored if `include` is set) */
|
|
172
|
+
exclude?: string[];
|
|
173
|
+
/** Resources to include by name — only these get MCP tools. Takes priority over `exclude`. */
|
|
174
|
+
include?: string[];
|
|
175
|
+
/** Tool name prefix: 'crm' → 'crm_list_products' */
|
|
176
|
+
toolNamePrefix?: string;
|
|
177
|
+
/** Per-resource overrides (operations, descriptions, hideFields, names, toolNamePrefix) */
|
|
178
|
+
overrides?: Record<string, McpResourceConfig>;
|
|
179
|
+
/** Hand-written tools added alongside auto-generated ones */
|
|
180
|
+
extraTools?: ToolDefinition[];
|
|
181
|
+
/** Custom prompts */
|
|
182
|
+
extraPrompts?: PromptDefinition[];
|
|
183
|
+
/**
|
|
184
|
+
* Session mode:
|
|
185
|
+
* - `false` (default) — stateless, fresh server per request. Best for production, scaling, serverless.
|
|
186
|
+
* - `true` — stateful, sessions cached with TTL. Use for server-initiated notifications or long-lived connections.
|
|
187
|
+
*/
|
|
188
|
+
stateful?: boolean;
|
|
189
|
+
/** Session TTL in ms (default: 1800000 = 30 min). Only used when stateful: true. */
|
|
190
|
+
sessionTtlMs?: number;
|
|
191
|
+
/** Max concurrent sessions (default: 1000). Only used when stateful: true. */
|
|
192
|
+
maxSessions?: number;
|
|
193
|
+
/**
|
|
194
|
+
* Auth cache TTL in ms for stateless mode (default: 5000 = 5 sec).
|
|
195
|
+
* Caches auth resolver results briefly to avoid redundant DB lookups
|
|
196
|
+
* across initialize → tools/list → tools/call sequences.
|
|
197
|
+
* Set to `0` to disable.
|
|
198
|
+
*/
|
|
199
|
+
authCacheTtlMs?: number;
|
|
200
|
+
}
|
|
201
|
+
/** Minimal Better Auth handler interface for MCP session validation */
|
|
202
|
+
interface BetterAuthHandler {
|
|
203
|
+
api: {
|
|
204
|
+
getMcpSession: (opts: {
|
|
205
|
+
headers: Record<string, string | undefined>;
|
|
206
|
+
}) => Promise<McpSession | null>;
|
|
207
|
+
};
|
|
208
|
+
handler: (request: Request) => Promise<Response>;
|
|
209
|
+
}
|
|
210
|
+
/** Session from Better Auth's getMcpSession() */
|
|
211
|
+
interface McpSession {
|
|
212
|
+
userId: string;
|
|
213
|
+
clientId: string;
|
|
214
|
+
scopes: string;
|
|
215
|
+
activeOrganizationId?: string;
|
|
216
|
+
accessToken: string;
|
|
217
|
+
accessTokenExpiresAt: string;
|
|
218
|
+
refreshToken: string;
|
|
219
|
+
refreshTokenExpiresAt: string;
|
|
220
|
+
}
|
|
221
|
+
/** Resolved auth identity for a single MCP request */
|
|
222
|
+
interface McpAuthResult {
|
|
223
|
+
userId: string;
|
|
224
|
+
organizationId?: string;
|
|
225
|
+
/** User roles (global) — used by guard helpers like requireRole() */
|
|
226
|
+
roles?: string[];
|
|
227
|
+
/** Org-level roles — used by guard helpers */
|
|
228
|
+
orgRoles?: string[];
|
|
229
|
+
/** Any extra metadata from the auth resolver */
|
|
230
|
+
[key: string]: unknown;
|
|
231
|
+
}
|
|
232
|
+
/** Internal session entry */
|
|
233
|
+
interface SessionEntry {
|
|
234
|
+
transport: {
|
|
235
|
+
handleRequest: (req: unknown, res: unknown, body?: unknown) => Promise<void>;
|
|
236
|
+
close: () => void;
|
|
237
|
+
};
|
|
238
|
+
lastAccessed: number;
|
|
239
|
+
organizationId: string;
|
|
240
|
+
auth: McpAuthResult | null;
|
|
241
|
+
/** Mutable ref updated per-request — tool handler closures read from this */
|
|
242
|
+
authRef: {
|
|
243
|
+
current: McpAuthResult | null;
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Configuration for createMcpServer() — Level 2 declarative factory.
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```ts
|
|
251
|
+
* const server = await createMcpServer({
|
|
252
|
+
* name: 'my-api',
|
|
253
|
+
* version: '1.0.0',
|
|
254
|
+
* instructions: 'Use list_users to browse users.',
|
|
255
|
+
* tools: [
|
|
256
|
+
* defineTool('greet', {
|
|
257
|
+
* description: 'Say hello',
|
|
258
|
+
* input: { name: z.string() },
|
|
259
|
+
* handler: async ({ name }) => ({ content: [{ type: 'text', text: `Hello ${name}` }] }),
|
|
260
|
+
* }),
|
|
261
|
+
* ],
|
|
262
|
+
* });
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
interface CreateMcpServerConfig {
|
|
266
|
+
name: string;
|
|
267
|
+
version?: string;
|
|
268
|
+
instructions?: string;
|
|
269
|
+
tools?: ToolDefinition[];
|
|
270
|
+
prompts?: PromptDefinition[];
|
|
271
|
+
}
|
|
272
|
+
/** CRUD operation type */
|
|
273
|
+
type CrudOperation = "list" | "get" | "create" | "update" | "delete";
|
|
274
|
+
//#endregion
|
|
275
|
+
export { McpAuthResolver as a, McpResourceConfig as c, SessionEntry as d, ToolAnnotations as f, CrudOperation as i, PromptDefinition as l, ToolDefinition as m, CallToolResult as n, McpAuthResult as o, ToolContext as p, CreateMcpServerConfig as r, McpPluginOptions as s, BetterAuthHandler as t, PromptResult as u };
|
|
@@ -29,7 +29,7 @@ declare function getUserRoles(user: UserBase | null | undefined): string[];
|
|
|
29
29
|
/**
|
|
30
30
|
* Context passed to permission check functions
|
|
31
31
|
*/
|
|
32
|
-
interface PermissionContext<TDoc =
|
|
32
|
+
interface PermissionContext<TDoc = Record<string, unknown>> {
|
|
33
33
|
/** Authenticated user or null if unauthenticated */
|
|
34
34
|
user: UserBase | null;
|
|
35
35
|
/** Fastify request object */
|
|
@@ -80,7 +80,7 @@ interface PermissionResult {
|
|
|
80
80
|
* };
|
|
81
81
|
* ```
|
|
82
82
|
*/
|
|
83
|
-
type PermissionCheck<TDoc =
|
|
83
|
+
type PermissionCheck<TDoc = Record<string, unknown>> = ((context: PermissionContext<TDoc>) => boolean | PermissionResult | Promise<boolean | PermissionResult>) & PermissionCheckMeta;
|
|
84
84
|
/**
|
|
85
85
|
* Optional metadata attached to permission check functions.
|
|
86
86
|
* Used for OpenAPI docs, introspection, and route-level auth decisions.
|
|
@@ -29,10 +29,38 @@ function getOrgRoles(scope) {
|
|
|
29
29
|
function getTeamId(scope) {
|
|
30
30
|
if (scope.kind === "member") return scope.teamId;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Get userId from scope (available on authenticated, member, elevated).
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { getUserId } from '@classytic/arc/scope';
|
|
38
|
+
* const userId = getUserId(request.scope);
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
function getUserId(scope) {
|
|
42
|
+
if (scope.kind === "public") return void 0;
|
|
43
|
+
return scope.userId;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get global user roles from scope (available on authenticated and member).
|
|
47
|
+
* These are user-level roles (e.g. superadmin, finance-admin) distinct from
|
|
48
|
+
* org-level roles (scope.orgRoles).
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* import { getUserRoles } from '@classytic/arc/scope';
|
|
53
|
+
* const globalRoles = getUserRoles(request.scope);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
function getUserRoles(scope) {
|
|
57
|
+
if (scope.kind === "authenticated") return scope.userRoles ?? [];
|
|
58
|
+
if (scope.kind === "member") return scope.userRoles;
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
32
61
|
/** Default public scope — used as initial decoration value */
|
|
33
62
|
const PUBLIC_SCOPE = Object.freeze({ kind: "public" });
|
|
34
63
|
/** Default authenticated scope — used when user is logged in but no org */
|
|
35
64
|
const AUTHENTICATED_SCOPE = Object.freeze({ kind: "authenticated" });
|
|
36
|
-
|
|
37
65
|
//#endregion
|
|
38
|
-
export { getTeamId as a,
|
|
66
|
+
export { getTeamId as a, hasOrgAccess as c, isMember as d, getOrgRoles as i, isAuthenticated as l, PUBLIC_SCOPE as n, getUserId as o, getOrgId as r, getUserRoles as s, AUTHENTICATED_SCOPE as t, isElevated as u };
|
|
@@ -1,18 +1,26 @@
|
|
|
1
|
-
import { n as ElevationOptions } from "./elevation-
|
|
2
|
-
import { Authenticator } from "./
|
|
3
|
-
import { t as ExternalOpenApiPaths } from "./externalPaths-
|
|
4
|
-
import { i as CacheStore } from "./interface-
|
|
5
|
-
import { r as QueryCachePluginOptions } from "./queryCachePlugin-
|
|
6
|
-
import { i as EventTransport } from "./EventTransport-
|
|
7
|
-
import { t as EventPluginOptions } from "./eventPlugin-
|
|
8
|
-
import {
|
|
9
|
-
import { r as IdempotencyStore } from "./interface-
|
|
1
|
+
import { n as ElevationOptions } from "./elevation-Ca_yveIO.mjs";
|
|
2
|
+
import { h as Authenticator } from "./interface-DGmPxakH.mjs";
|
|
3
|
+
import { t as ExternalOpenApiPaths } from "./externalPaths-DpO-s7r8.mjs";
|
|
4
|
+
import { i as CacheStore } from "./interface-D_BWALyZ.mjs";
|
|
5
|
+
import { r as QueryCachePluginOptions } from "./queryCachePlugin-DcmETvcB.mjs";
|
|
6
|
+
import { i as EventTransport } from "./EventTransport-wc5hSLik.mjs";
|
|
7
|
+
import { t as EventPluginOptions } from "./eventPlugin-iGrSEmwJ.mjs";
|
|
8
|
+
import { c as MetricsOptions, d as SSEOptions, m as CachingOptions, r as VersioningOptions, t as ErrorHandlerOptions } from "./errorHandler-Do4vVQ1f.mjs";
|
|
9
|
+
import { r as IdempotencyStore } from "./interface-B4awm1RJ.mjs";
|
|
10
10
|
import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest, FastifyServerOptions } from "fastify";
|
|
11
|
-
import { FastifyCorsOptions } from "@fastify/cors";
|
|
12
|
-
import { FastifyHelmetOptions } from "@fastify/helmet";
|
|
13
|
-
import { RateLimitOptions } from "@fastify/rate-limit";
|
|
14
11
|
|
|
15
12
|
//#region src/factory/types.d.ts
|
|
13
|
+
type CorsOptions = Record<string, unknown> & {
|
|
14
|
+
origin?: unknown;
|
|
15
|
+
credentials?: boolean;
|
|
16
|
+
methods?: string[];
|
|
17
|
+
allowedHeaders?: string[];
|
|
18
|
+
};
|
|
19
|
+
type HelmetOptions = Record<string, unknown>;
|
|
20
|
+
type RateLimitOpts = Record<string, unknown> & {
|
|
21
|
+
max?: number;
|
|
22
|
+
timeWindow?: string | number;
|
|
23
|
+
};
|
|
16
24
|
/**
|
|
17
25
|
* Arc's built-in JWT auth
|
|
18
26
|
*
|
|
@@ -44,7 +52,7 @@ import { RateLimitOptions } from "@fastify/rate-limit";
|
|
|
44
52
|
* ```
|
|
45
53
|
*/
|
|
46
54
|
interface JwtAuthOption {
|
|
47
|
-
type:
|
|
55
|
+
type: "jwt";
|
|
48
56
|
/**
|
|
49
57
|
* JWT configuration (optional but recommended)
|
|
50
58
|
* If provided, jwt utilities are available in authenticator context
|
|
@@ -82,6 +90,18 @@ interface JwtAuthOption {
|
|
|
82
90
|
* Property name to store user on request (default: 'user')
|
|
83
91
|
*/
|
|
84
92
|
userProperty?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Token revocation check — called after JWT verification.
|
|
95
|
+
* Return `true` to reject the token (fail-closed: errors also reject).
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* isRevoked: async (decoded) => {
|
|
100
|
+
* return revokedTokens.has(decoded.jti as string);
|
|
101
|
+
* },
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
isRevoked?: (decoded: Record<string, unknown>) => boolean | Promise<boolean>;
|
|
85
105
|
}
|
|
86
106
|
/**
|
|
87
107
|
* Better Auth adapter integration
|
|
@@ -100,7 +120,7 @@ interface JwtAuthOption {
|
|
|
100
120
|
* ```
|
|
101
121
|
*/
|
|
102
122
|
interface BetterAuthOption {
|
|
103
|
-
type:
|
|
123
|
+
type: "betterAuth";
|
|
104
124
|
/** Better Auth adapter — pass the result of createBetterAuthAdapter() */
|
|
105
125
|
betterAuth: {
|
|
106
126
|
plugin: FastifyPluginAsync;
|
|
@@ -126,7 +146,7 @@ interface BetterAuthOption {
|
|
|
126
146
|
* ```
|
|
127
147
|
*/
|
|
128
148
|
interface CustomPluginAuthOption {
|
|
129
|
-
type:
|
|
149
|
+
type: "custom";
|
|
130
150
|
/** Custom Fastify plugin that sets up authentication */
|
|
131
151
|
plugin: FastifyPluginAsync;
|
|
132
152
|
}
|
|
@@ -151,7 +171,7 @@ interface CustomPluginAuthOption {
|
|
|
151
171
|
* ```
|
|
152
172
|
*/
|
|
153
173
|
interface CustomAuthenticatorOption {
|
|
154
|
-
type:
|
|
174
|
+
type: "authenticator";
|
|
155
175
|
/** Authenticate function — decorates fastify.authenticate directly */
|
|
156
176
|
authenticate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
|
|
157
177
|
/**
|
|
@@ -215,14 +235,17 @@ type AuthOption = false | JwtAuthOption | BetterAuthOption | CustomPluginAuthOpt
|
|
|
215
235
|
*/
|
|
216
236
|
interface CreateAppOptions {
|
|
217
237
|
/** Environment preset: 'production', 'development', 'testing', or 'edge' */
|
|
218
|
-
preset?:
|
|
238
|
+
preset?: "production" | "development" | "testing" | "edge";
|
|
219
239
|
/**
|
|
220
240
|
* Runtime profile for store backends.
|
|
221
241
|
* - 'memory' (default): Uses in-memory stores. Suitable for single-instance deployments.
|
|
222
|
-
* - 'distributed': Requires
|
|
223
|
-
*
|
|
242
|
+
* - 'distributed': Requires durable adapters for events, and for any enabled
|
|
243
|
+
* shared subsystems such as caching/queryCache/rate limiting.
|
|
244
|
+
* Idempotency remains per-resource opt-in: memory-backed stores are rejected,
|
|
245
|
+
* while a missing idempotency store emits a startup warning because dedupe
|
|
246
|
+
* would be instance-local.
|
|
224
247
|
*/
|
|
225
|
-
runtime?:
|
|
248
|
+
runtime?: "memory" | "distributed";
|
|
226
249
|
/**
|
|
227
250
|
* Store and transport instances for runtime profile validation.
|
|
228
251
|
* When `runtime` is `'distributed'`, Arc validates that these are
|
|
@@ -235,7 +258,7 @@ interface CreateAppOptions {
|
|
|
235
258
|
queryCache?: CacheStore;
|
|
236
259
|
};
|
|
237
260
|
/** Fastify logger configuration */
|
|
238
|
-
logger?: FastifyServerOptions[
|
|
261
|
+
logger?: FastifyServerOptions["logger"];
|
|
239
262
|
/**
|
|
240
263
|
* Enable Arc debug logging.
|
|
241
264
|
*
|
|
@@ -332,11 +355,11 @@ interface CreateAppOptions {
|
|
|
332
355
|
*/
|
|
333
356
|
elevation?: ElevationOptions | false;
|
|
334
357
|
/** Helmet security headers. Set to false to disable. */
|
|
335
|
-
helmet?:
|
|
358
|
+
helmet?: HelmetOptions | false;
|
|
336
359
|
/** CORS configuration. Set to false to disable. */
|
|
337
|
-
cors?:
|
|
360
|
+
cors?: CorsOptions | false;
|
|
338
361
|
/** Rate limiting. Set to false to disable. */
|
|
339
|
-
rateLimit?:
|
|
362
|
+
rateLimit?: RateLimitOpts | false;
|
|
340
363
|
/** Under pressure health monitoring. Set to false to disable. */
|
|
341
364
|
underPressure?: UnderPressureOptions | false;
|
|
342
365
|
/** @fastify/sensible (HTTP helpers). Set to false to disable. */
|
|
@@ -378,7 +401,7 @@ interface CreateAppOptions {
|
|
|
378
401
|
* });
|
|
379
402
|
* ```
|
|
380
403
|
*/
|
|
381
|
-
events?: Omit<EventPluginOptions,
|
|
404
|
+
events?: Omit<EventPluginOptions, "transport"> | boolean;
|
|
382
405
|
/**
|
|
383
406
|
* Caching headers (ETag + Cache-Control). Default: false (opt-in).
|
|
384
407
|
* Set to true for defaults, or pass CachingOptions for fine control.
|
|
@@ -396,6 +419,16 @@ interface CreateAppOptions {
|
|
|
396
419
|
* Requires per-resource `cache` config on defineResource().
|
|
397
420
|
*/
|
|
398
421
|
queryCache?: QueryCachePluginOptions | boolean;
|
|
422
|
+
/**
|
|
423
|
+
* Metrics endpoint (Prometheus-compatible). Default: false (opt-in).
|
|
424
|
+
* Set to true for defaults (/_metrics), or pass MetricsOptions for custom path/prefix.
|
|
425
|
+
*/
|
|
426
|
+
metrics?: MetricsOptions | boolean;
|
|
427
|
+
/**
|
|
428
|
+
* API versioning (header or prefix-based). Default: false (opt-in).
|
|
429
|
+
* Pass VersioningOptions to enable.
|
|
430
|
+
*/
|
|
431
|
+
versioning?: VersioningOptions;
|
|
399
432
|
};
|
|
400
433
|
/**
|
|
401
434
|
* Type provider for schema inference.
|
|
@@ -416,7 +449,7 @@ interface CreateAppOptions {
|
|
|
416
449
|
* // Now route schemas built with Type.* give full TS inference
|
|
417
450
|
* ```
|
|
418
451
|
*/
|
|
419
|
-
typeProvider?:
|
|
452
|
+
typeProvider?: "typebox";
|
|
420
453
|
/**
|
|
421
454
|
* Error handler plugin. Normalizes AJV, Mongoose, and ArcError responses
|
|
422
455
|
* into a consistent JSON envelope. Enabled by default.
|
|
@@ -448,21 +481,29 @@ interface CreateAppOptions {
|
|
|
448
481
|
onClose?: (fastify: FastifyInstance) => void | Promise<void>;
|
|
449
482
|
}
|
|
450
483
|
interface UnderPressureOptions {
|
|
484
|
+
/** Expose `/_status` route for health checks (default: false) */
|
|
451
485
|
exposeStatusRoute?: boolean;
|
|
486
|
+
/** Event loop lag threshold in ms — requests rejected above this (default: 1000) */
|
|
452
487
|
maxEventLoopDelay?: number;
|
|
488
|
+
/** V8 heap usage threshold in bytes — requests rejected above this */
|
|
453
489
|
maxHeapUsedBytes?: number;
|
|
490
|
+
/** RSS memory threshold in bytes — requests rejected above this */
|
|
454
491
|
maxRssBytes?: number;
|
|
455
492
|
}
|
|
456
493
|
interface MultipartOptions {
|
|
457
494
|
limits?: {
|
|
458
|
-
fileSize?: number;
|
|
495
|
+
/** Max file size in bytes (default: Fastify default ~1MB) */fileSize?: number; /** Max number of files per request */
|
|
459
496
|
files?: number;
|
|
460
497
|
};
|
|
461
498
|
}
|
|
462
499
|
interface RawBodyOptions {
|
|
500
|
+
/** Body field name to store raw body on (default: 'rawBody') */
|
|
463
501
|
field?: string;
|
|
502
|
+
/** Apply to all routes globally (default: false) */
|
|
464
503
|
global?: boolean;
|
|
504
|
+
/** Encoding for raw body string (default: 'utf8') */
|
|
465
505
|
encoding?: string;
|
|
506
|
+
/** Parse raw body before other parsers (default: false) */
|
|
466
507
|
runFirst?: boolean;
|
|
467
508
|
}
|
|
468
509
|
//#endregion
|